This is a reference implementation of a summation unit. The algorithm used is a most straightforward carry-propagation. If necessary, a test driving code could be provided.
Few notes for the reviewers:
- The code does compile and works indeed. Test harness is available on demand.
- I am a steadfast proponent of descriptive names. This is a rare case where one-letter names are descriptive.
N,Z,C,Vwere adopted and blessed by generations of designers. Calling the flagoverflowinstead ofVwould sound like a blasphemy. - Validity of register indices is intentionally not verified. Just pretend that they are always valid.
- For a
Vcalculation, refer to this wonderful explanation
Looking for an Ultimate Review of the Clarity, the Universe and Everything.
#include <vector>
#include <limits>
#include <algorithm>
#include <ostream>
template<typename Int>
struct GPR {
std::vector<bool> bits;
GPR(): bits(std::numeric_limits<Int>::digits, false) {};
~GPR() { delete bits; }
bool sign() const { return bits.back(); }
auto begin() -> decltype(bits.begin()) { return bits.begin(); }
auto end() -> decltype(bits.end()) { return bits.end(); }
auto rbegin() -> decltype(bits.rbegin()) { return bits.rbegin(); }
auto rend() -> decltype(bits.rend()) { return bits.rend(); }
void load(Int value) {
for(auto it = begin(); it != end(); ++it) {
*it = value & 0x01;
value >>= 1;
}
}
void store(Int& value) {
for(auto it = rbegin(); it != rend(); ++it) {
value <<= 1;
value |= *it;
}
}
friend std::ostream& operator<<(std::ostream& os, GPR& reg) {
std::copy(reg.begin(), reg.end(), os);
return os;
}
};
template<typename Int>
class CPU {
struct flags {
bool N;
bool C;
bool Z;
bool V;
flags(): N(false), C(false), Z(false), V(false) {}
friend std::ostream& operator<<(std::ostream& os, flags& f) {
os << f.N << f.C << f.Z << f.V;
return os;
}
};
struct adder {
flags& f;
adder(flags& f): f(f) {}
bool operator()(bool x, bool y) {
bool s = x ^ y ^ f.C;
f.C = x & y | f.C & (x ^ y);
f.Z &= !s;
return s;
}
};
flags flags;
std::vector<GPR<Int> > regfile;
void add_internal(GPR<Int>& r1, GPR<Int>& r2) {
bool s1 = r1.sign();
bool s2 = r2.sign();
flags.Z = true;
std::transform(r1.begin(), r1.end(), r2.begin(), r1.begin(), adder(flags));
flags.N = r1.sign();
flags.V = !(s1 ^ s2) & (s1 ^ r1.sign());
}
public:
CPU(int regs): regfile(regs) {}
void add(unsigned rx1, unsigned rx2) {
flags.C = false;
add_internal(regfile[rx1], regfile[rx2]);
}
void addc(unsigned rx1, unsigned rx2) {
add_internal(regfile[rx1], regfile[rx2]);
}
void load(unsigned rx, Int value) {
regfile[rx].load(value);
}
void store(unsigned rx, Int& x) {
regfile[rx].store(x);
}
};