-
Notifications
You must be signed in to change notification settings - Fork 3
/
ScottyCPU.hpp
200 lines (163 loc) · 5.42 KB
/
ScottyCPU.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#ifndef SCOTTYCPU_HPP
#define SCOTTYCPU_HPP
#include "CPUComponents/ALUnit.hpp"
#include "CPUComponents/ControlUnit.hpp"
#include "CPUComponents/Memory.hpp"
#include "CPUComponents/Clock.hpp"
#include "CPUComponents/MemoryCell.hpp"
#include "utils.hpp"
namespace CPUComponents {
/**
* \brief **ScottyCPU** : The class containing all components for the ScottyCPU.
*
* * Currently limited to bit_width of 16 (8, 16, 24, 32 ... should be possible).
* * Currently only support staticly loading 1 program from address 0 in RAM.
*
* \tparam bit_width
* This template argument specifies the width of the internal bitset state.
* \tparam mem_size
* This template argument specifies the size of the internal memory (amount).
* \tparam reg_size
* This template argument specifies the size of the internal registers (amount).
*/
template <size_t bit_width, size_t mem_size, size_t reg_size>
class ScottyCPU {
private:
/**
* \brief The ALUnit for the Scotty CPU.
*/
ALUnit<bit_width> *_ALU;
/**
* \brief The Memory for the Scotty CPU.
*/
Memory<bit_width, mem_size> *_RAM;
/**
* \brief The ControlUnit for the Scotty CPU.
*/
ControlUnit<bit_width, mem_size, reg_size> *_CU;
/**
* \brief The Clock for the Scotty CPU.
*/
Clock<bit_width> _clk;
/**
* \brief The common bus for the Scotty CPU.
*/
MemoryCell<bit_width> _BUS;
/**
* \brief A buffer register for the ALU.
*/
MemoryCell<bit_width> _ALU_BUFFER;
public:
/** \brief Default constructor
*
* \param clk_freq
* The Clock frequency for the CPU.
* \exception Exceptions::Exception
* Throws Exception if the bit_width is not 16-bits.
* Currently the ScottyCPU is fixed to a 16-bit architecure.
*/
ScottyCPU(float clk_freq)
: _ALU(SysUtils::allocVar<ALUnit<bit_width>>()),
_RAM(SysUtils::allocVar<Memory<bit_width, mem_size>>()),
// _CU(SysUtils::allocVar<ControlUnit<bit_width, mem_size, reg_size>(_ALU, _RAM, &_BUS, &_ALU_BUFFER)>()),
_CU(new ControlUnit<bit_width, mem_size, reg_size>(_ALU, _RAM, &_BUS, &_ALU_BUFFER)),
_clk(clk_freq)
{
#ifdef THROW_EXCEPTIONS
if (bit_width != 16u)
throw Exceptions::Exception("ScottyCPU is currently locked with a bit_width of 16!");
#endif
this->_clk.addOutput(*this->_CU);
this->_ALU->addInput(this->_BUS);
this->_ALU->addInput(this->_ALU_BUFFER);
this->_ALU->connectInternal();
}
/**
* \brief Default destructor
*/
~ScottyCPU() {
SysUtils::deallocVar(this->_ALU);
SysUtils::deallocVar(this->_CU);
SysUtils::deallocVar(this->_RAM);
}
/** \brief Returns the ALU of the CPU.
*/
const ALUnit<bit_width>* getALU(void) const {
return this->_ALU;
}
/** \brief Returns the CU of the CPU.
*/
const ControlUnit<bit_width, mem_size, reg_size>* getControlUnit(void) const {
return this->_CU;
}
/** \brief Returns the Memory of the CPU.
*/
Memory<bit_width, mem_size>& getRAM(void) const {
return *this->_RAM;
}
/** \brief Returns the Clock of the CPU.
*/
Clock<bit_width>& getClock(void) /* const */ {
return this->_clk;
}
/** \brief Staticly loads a program into RAM (from address 0).
*
* \param *buffer
* A vector with buffer->size() bytes containing a program in raw binary.
*
* \throws Exceptions::OutOfBoundsException
* Throws Exception if program is longer than the available Memory.
*/
void staticLoader(const std::vector<char> *buffer) {
// split into bit_width segments when pushing into RAM
try {
std::bitset<bit_width> data;
size_t bytes_per_instruction = bit_width / 8;
int i;
for (size_t pos = 0, address = 0; pos < buffer->size(); ++address) {
data = 0;
i = bytes_per_instruction;
while(i--) {
data <<= 8;
data |= 0xFF & buffer->at(pos++);
}
this->_RAM->setData(std::bitset<bit_width>(address), data);
}
} catch (Exceptions::OutOfBoundsException const& e) {
throw Exceptions::Exception(e.getMessage() + "\n[ScottyCPU::staticLoader] : \n\tProgram to be loaded is longer than the available Memory!");
}
}
/**
* \brief Starts the execution of the ScottyCPU by threading the Clock.
*/
void start(void) {
// Thread cannot access bitset output?
//std::thread clk(_clk);
//clk.join();
this->_clk();
//this->_clk.startThread();
}
/**
* \brief Steps the execution of the ScottyCPU by one tick().
* Also dumps the contents of its RAM and Registers respectively
* to RAMdump.txt and REGdump.txt.
*/
void step(void) {
std::bitset<bit_width> *range = this->getRAM().getDataRange(0, this->getRAM().getMaxAddress());
std::stringstream ss;
for (size_t i = 0; i < this->getRAM().getMaxAddress().to_ulong(); ++i)
ss << range[i].to_string() << std::endl;
SysUtils::writeStringToFile("RAMdump.txt", ss.str());
SysUtils::deallocArray(range);
range = nullptr;
range = this->getControlUnit()->getRegisters().getDataRange(0, this->getControlUnit()->getRegisters().getMaxAddress());
std::stringstream st;
for (size_t i = 0; i < this->getControlUnit()->getRegisterSize(); ++i)
st << range[i].to_string() << std::endl;
SysUtils::writeStringToFile("REGdump.txt", st.str());
SysUtils::deallocArray(range);
this->getClock().tick();
}
};
}
#endif // SCOTTYCPU_HPP