patterncppMinor
Summator simulation
Viewed 0 times
simulationsummatorstackoverflow
Problem
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:
Looking for an Ultimate Review of the Clarity, the Universe and Everything.
```
#include
#include
#include
#include
template
struct GPR {
std::vector bits;
GPR(): bits(std::numeric_limits::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
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 > regfile;
void add_internal(GPR& r1, GPR& 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
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
#include
#include
#include
template
struct GPR {
std::vector bits;
GPR(): bits(std::numeric_limits::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
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 > regfile;
void add_internal(GPR& r1, GPR& 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
Solution
First of all I would like to dispute your assertion that the one letter names are descriptive. The only people how will find them descriptive are those who are used to them but readers that have no understanding of the topic are at a total loss here (not having any comments on the variables reinforces this).
But this is only my opinion.
On to more substantial problems:
Using
I see that you are using the dreaded
However, fact that
Why are you deleting a non pointer in GPR's destructor:
I am nearly certain that this should be a compiler error (although my compiler only warns about it)
C++11
Why didn't you use a range based for in
Using boost's reversed range adaptor you could also do this in store.
Compiler warnings about operator order
Compiling your code gave me warnings about recommended parentheses on:
and
Output order of the bits of reg
You output the bits in reg with the least significant coming first and the sign last. Is this intended?
Or should it be
And while we are at it you surely mean
Flag Output
The output for the flags is only understandable when you read the code and see the order. At the very least I would output the flag "descriptor" instead of 0 or 1 to better indicate which flags are set.
You could use the case to identify the flag or simply leave out those that are not set.
Extract non template members
Neither
If you insist on making them private members than you should put them in a non templated base class for
Naming
But this is only my opinion.
On to more substantial problems:
Using
vector considered harmful?I see that you are using the dreaded
vector. I also see that you don't change its size after initialization and that the size is known at compiletime. Together with the fact that you are doing bit manipulations this calls for a std::bitset.However, fact that
vector offers these nice iterators that you can use with the standard algorithms might be enough of a reason to use it nonetheless.delete std::vector()?Why are you deleting a non pointer in GPR's destructor:
std::vector bits;
//...
~GPR() { delete bits; }I am nearly certain that this should be a compiler error (although my compiler only warns about it)
C++11
Why didn't you use a range based for in
GPR::load?for(auto ¤tBit: bits) {
currentBit = value & 0x01;
value >>= 1;
}Using boost's reversed range adaptor you could also do this in store.
Compiler warnings about operator order
Compiling your code gave me warnings about recommended parentheses on:
f.C = x & y | f.C & (x ^ y);and
flags.V = !(s1 ^ s2) & (s1 ^ r1.sign());Output order of the bits of reg
You output the bits in reg with the least significant coming first and the sign last. Is this intended?
std::copy(reg.begin(), reg.end(), os);Or should it be
std::copy(reg.rbegin(), reg.rend(), os);And while we are at it you surely mean
std::ostream_iterator(os) instead of os. Flag Output
The output for the flags is only understandable when you read the code and see the order. At the very least I would output the flag "descriptor" instead of 0 or 1 to better indicate which flags are set.
You could use the case to identify the flag or simply leave out those that are not set.
Extract non template members
Neither
flags nor adder depend on the template parameter of CPU so you should take it out of the that class to avoid code bloat due to unnecessary multiple instantiations.If you insist on making them private members than you should put them in a non templated base class for
CPU.Naming
- the member variable
CPU::flagsshadows the member structCPU::flags
adder->BitAdder(orbit_adderbut I would choose the former to distinguish class and function names)
regfile->registers(although the former might be more domain specific)
Code Snippets
std::vector<bool> bits;
//...
~GPR() { delete bits; }for(auto ¤tBit: bits) {
currentBit = value & 0x01;
value >>= 1;
}f.C = x & y | f.C & (x ^ y);flags.V = !(s1 ^ s2) & (s1 ^ r1.sign());std::copy(reg.begin(), reg.end(), os);Context
StackExchange Code Review Q#61924, answer score: 6
Revisions (0)
No revisions yet.