Last active
November 10, 2018 17:07
-
-
Save ofx/7cd54cdf27419cbdf803a121711b2d40 to your computer and use it in GitHub Desktop.
16-bits ALU
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <bitset> | |
#include <iostream> | |
#include <limits> | |
#include <random> | |
#define ALU_ADD 0 | |
#define ALU_SUB 1 | |
#define ALU_AND 2 | |
#define ALU_OR 3 | |
#define ALU_XOR 4 | |
constexpr inline unsigned char adder(const bool a, const bool b, const bool cin, | |
bool &cout) { | |
cout = (a & b) | (cin & (a ^ b)); | |
return cin ^ (a ^ b); | |
} | |
constexpr inline bool parity(short x) { | |
x ^= x >> 8; | |
x ^= x >> 4; | |
x ^= x >> 2; | |
x ^= x >> 1; | |
return (~x) & 1; | |
} | |
constexpr short alu(const unsigned char control, short a, short b, bool &zf, | |
bool &cf, bool &of, bool &sf, bool &pf, bool &af) { | |
short r = 0; | |
auto a_ = std::bitset<16>(a); | |
auto b_ = std::bitset<16>(b); | |
auto r_ = std::bitset<16>(); | |
switch (control) { | |
case ALU_SUB: | |
case ALU_ADD: { | |
cf = control; | |
r_.set(0, adder(a_[0], b_[0] ^ control, cf, cf)); | |
r_.set(1, adder(a_[1], b_[1] ^ control, cf, cf)); | |
r_.set(2, adder(a_[2], b_[2] ^ control, cf, cf)); | |
r_.set(3, adder(a_[3], b_[3] ^ control, cf, cf)); | |
af = cf; | |
r_.set(4, adder(a_[4], b_[4] ^ control, cf, cf)); | |
r_.set(5, adder(a_[5], b_[5] ^ control, cf, cf)); | |
r_.set(6, adder(a_[6], b_[6] ^ control, cf, cf)); | |
r_.set(7, adder(a_[7], b_[7] ^ control, cf, cf)); | |
r_.set(8, adder(a_[8], b_[8] ^ control, cf, cf)); | |
r_.set(9, adder(a_[9], b_[9] ^ control, cf, cf)); | |
r_.set(10, adder(a_[10], b_[10] ^ control, cf, cf)); | |
r_.set(11, adder(a_[11], b_[11] ^ control, cf, cf)); | |
r_.set(12, adder(a_[12], b_[12] ^ control, cf, cf)); | |
r_.set(13, adder(a_[13], b_[13] ^ control, cf, cf)); | |
r_.set(14, adder(a_[14], b_[14] ^ control, cf, cf)); | |
r_.set(15, adder(a_[15], b_[15] ^ control, cf, cf)); | |
r = (short)r_.to_ulong(); | |
sf = r_[15]; | |
of = (a_[15] & b_[15] & ~sf) | (~a_[15] & ~b_[15] & sf); | |
zf = ~r_[15] & ~r_[14] & ~r_[13] & ~r_[12] & ~r_[11] & ~r_[10] & ~r_[9] & | |
~r_[8] & ~r_[7] & ~r_[6] & ~r_[5] & ~r_[4] & ~r_[3] & ~r_[2] & ~r_[1] & | |
~r_[0]; | |
pf = parity(r); | |
assert(pf == (r_.count() % 2 == 0)); | |
assert(zf == (r == 0)); | |
assert(sf == (r < 0)); | |
assert(of == ((a >= 0 && b >= 0 && r < 0) || (a < 0 && b < 0 && r >= 0))); | |
break; | |
} | |
case ALU_AND: | |
r = a & b; | |
break; | |
case ALU_OR: | |
r = a | b; | |
break; | |
case ALU_XOR: | |
r = a ^ b; | |
break; | |
} | |
return r; | |
} | |
constexpr short add(short a, short b, bool &zf, bool &cf, bool &of, bool &sf, | |
bool &pf, bool &af) { | |
return alu(ALU_ADD, a, b, zf, cf, of, sf, pf, af); | |
} | |
constexpr short sub(short a, short b, bool &zf, bool &cf, bool &of, bool &sf, | |
bool &pf, bool &af) { | |
return alu(ALU_SUB, a, b, zf, cf, of, sf, pf, af); | |
} | |
int main() { | |
std::random_device rseed; | |
std::mt19937 generator(rseed()); | |
std::uniform_int_distribution<short> dist(std::numeric_limits<short>::min(), | |
std::numeric_limits<short>::max()); | |
for (int i = 0; i < 100000; ++i) { | |
bool zf, cf, of, sf, pf, af; | |
const auto a = dist(generator); | |
const auto b = dist(generator); | |
const auto alu_result = add(a, b, zf, cf, of, sf, pf, af); | |
const auto cpp_result = short(a + b); | |
std::cout << a << "+" << b << ": " << alu_result << " == " << cpp_result | |
<< std::endl; | |
if (alu_result != cpp_result) { | |
std::cout << "Failed" << std::endl; | |
return 1; | |
} | |
} | |
for (int i = 0; i < 100000; ++i) { | |
bool zf, cf, of, sf, pf, af; | |
const auto a = dist(generator); | |
const auto b = dist(generator); | |
const auto alu_result = sub(a, b, zf, cf, of, sf, pf, af); | |
const auto cpp_result = short(a - b); | |
std::cout << a << "-" << b << ": " << alu_result << " == " << cpp_result | |
<< std::endl; | |
if (alu_result != cpp_result) { | |
std::cout << "Failed" << std::endl; | |
return 1; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment