Virtual CPU - Electronics - Adder

IF YOU HAVE JUST ARRIVED HERE, PLEASE SEE: http://megalomaniacbore.blogspot.co.uk/2014/04/virtual-cpu-in-c-4001-cpu.html

This code contains the logical implementation for a Binary Adder in C++, for unsigned bytes.

--- Electronics.h ---

#ifndef ELECTRONICS_HEADER
#define ELECTRONICS_HEADER

// We only include memory for the type "byte" to be known
#include "Memory.h"

namespace CPU_4001
{
class Electronics
{

private:


// The function is static so we can just call it without
// needing to instantiate a copy of "Electronics"
static void Adder (
const bool& A, // Bit from top of sum
const bool& B, // bit from bottom of sum
const bool& Cin, // Carry from previous column
bool& Cout, // Carry out
bool& Sum, // Sum of binary addition
const bool& p_Debug = false);


public:

// We're going to add both bytes 
// inside their own memory, hence
// they're passed in by reference
static void AddTwoBytes (
byte& p_Register0,
byte& p_Register1,
bool& p_Overflow,
const bool& p_Debug = false);

// We saw the adder trace table, 
// this function lets us put it
// to the test!
static void TestAdder();

// Test routine for the adding of bytes
static void TestAddTwoBytes();
};
}

#endif


--- Electronics.cpp ---
#include "Electronics.h"

#include <iostream>
#include <bitset>

namespace CPU_4001
{

// The trace table for the adder:
// A  B  Cin  |  Cout  Sum
// 0  0  0    |  0     0
// 0  0  1    |  0     1
// 0  1  0    |  0     1
// 0  1  1    |  1     0
// 1  0  0    |  0     1
// 1  0  1    |  1     0
// 1  1  0    |  1     0
// 1  1  1    |  1     1
void Electronics::Adder(
const bool& A,
const bool& B,
const bool& Cin,
bool& Cout,
bool& Sum,
const bool& p_Debug)
{
// The logic here you can follow,
// but it comes from an electronic
// diagram of an adder :)
Sum = Cin ^ (A ^ B);
Cout = (A & B) | (Cin & (A ^ B));

if ( p_Debug )
{
std::cout << "Adder: " << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << std::endl;
}
}

// Tests the adder
void Electronics::TestAdder()
{
using namespace std;

bool Cout = false;
bool Sum = false;

// 0 0 0
bool A = false;
bool B = false;
bool Cin = false;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 0 0 1
A = false;
B = false;
Cin = true;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 0 1 0
A = false;
B = true;
Cin = false;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 0 1 1
A = false;
B = true;
Cin = true;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 1 0 0
A = true;
B = false;
Cin = false;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 1 0 1
A = true;
B = false;
Cin = true;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 1 1 0
A = true;
B = true;
Cin = false;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

// 1 1 1
A = true;
B = true;
Cin = true;
Adder (A, B, Cin, Cout, Sum);
cout << A << " " << B << " " << Cin << " | " << Cout << " " << Sum << endl;

cout << endl;
}

void Electronics::AddTwoBytes (
byte& p_Register0,
byte& p_Register1,
bool& p_Overflow,
const bool& p_Debug)
{
bool l_CarryIn = false;
bool l_CarryOut = false;
bool l_Sum = false;

// For each bit we need to mask the
// right most bit out of the register
// meaning, we start at 00000001 and
// for each loop move the register
// so the bit we're interested is over
// the 8th position.


// Our mask never changes
byte l_mask = 0x01;

// For each bit we run the masking 
// then adder and handle switching
// the result into the register.
// You can find more efficient ways!
for (int i = 0; i < 8; ++i) // 8 bits in a byte
{
if ( p_Debug )
{
std::cout << "Cycle: " << i << std::endl;
std::bitset<8> msk { l_mask };
std::cout << "Mask: " << msk << std::endl;
std::bitset<8> reg0 { p_Register0 };
std::bitset<8> reg1 { p_Register1 };
std::cout << "Register 0 [" << reg0 << "]" << std::endl;
std::cout << "Register 1 [" << reg1 << "]" << std::endl;
}

// Get the A & B bits by shift & masking
// the register
bool A = ( ( ( p_Register0 >> i ) & l_mask) == 1);
bool B = ( ( ( p_Register1 >> i ) & l_mask) == 1);

// We have the carry in and the A & B now, so
// we can call the adder
Adder(A, B, l_CarryIn, l_CarryOut, l_Sum, p_Debug);

if ( p_Debug )
{
// This should be a value from our Adder trace table!
std::cout << "Adding: " << A << " " << B << " " << l_CarryIn << " | " << l_CarryOut << " " << l_Sum << std::endl;
}

// The carry out simply becomes the carry in
// I'm sure you can see one way to optimise this already!
l_CarryIn = l_CarryOut;

// Now the register change based on sum, but
// we also output the binary
if ( p_Debug )
{
std::bitset<8> regBefore { p_Register0 };
std::cout << "Register Change: " << regBefore << " -> ";
}

// Now the logic
if ( l_Sum )
{
// Mask is shifted, and always 1 in the i position
// so we always add a 1 back into the target
// register in the right location
p_Register0 = p_Register0 | ( l_mask << i);
}
else
{
// We know the mask is ON, so inversing it and moving it
// will give us an always off...
p_Register0 = p_Register0 & ~(l_mask << i);
}

// The register changed, so finish the debug statements
if ( p_Debug )
{
std::bitset<8> regAfter { p_Register0 };
std::cout << regAfter << std::endl;
}
}

// The final carry out becomes our
// over flow
p_Overflow = l_CarryOut;
}

void Electronics::TestAddTwoBytes ()
{
using namespace std;

byte A = 0;
byte B = 0;
bool Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 0;
B = 1;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 60;
B = 14;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 42;
B = 42;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 128;
B = 16;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 200;
B = 50;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 250;
B = 60;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;

A = 255;
B = 255;
Overflow = false;

cout << (int)A << "\t+\t" << (int)B << "\t=";
AddTwoBytes(A, B, Overflow);
cout<< (int)A;
if ( Overflow )
{
cout << " it over flowed!";
}
cout << std::endl;
}

}

No comments:

Post a Comment