Skip to content

Instantly share code, notes, and snippets.

@ofx
Last active November 10, 2018 17:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ofx/7cd54cdf27419cbdf803a121711b2d40 to your computer and use it in GitHub Desktop.
Save ofx/7cd54cdf27419cbdf803a121711b2d40 to your computer and use it in GitHub Desktop.
16-bits ALU
#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