-
Notifications
You must be signed in to change notification settings - Fork 0
/
controller.cc
198 lines (151 loc) · 4.53 KB
/
controller.cc
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
#include "controller.h"
#include <iomanip>
using namespace std;
/*
TO DO: instruction queue made need to throw an exception when empyt for the pipeline to work properly
figure out how to pop instruction from running_inst<> after it is done commiting
ISSUES that could arise: Pipeline control has not been exhaustively tested because operation
depends on finished functionality of each instruction - this needs to be fully tested later on
*/
InstructionMemory::InstructionMemory(unsigned size){
inst_memory = new unsigned char[size];
fill_n(inst_memory, size, 0xFF);
}
unsigned char * InstructionMemory::get_mem_ptr(){
return inst_memory;
}
InstructionMemory::~InstructionMemory(){
delete[] inst_memory;
}
Instruction* InstructionMemory::fetch(unsigned addrPtr, Pipeline * pl){
//make instruction here
int bit_inst = 0;
for (int i = 0; i<4; i++){
bit_inst = bit_inst | (inst_memory[addrPtr + i] << (3 - i) * 8);
}
if (bit_inst == UNDEFINED) throw HardwareException("Inst Mem");
opcode_t opcode = OPCODE(bit_inst);
return Instruction_Factory::Get()->Create_Instruction(opcode, bit_inst, pl);
}
void InstructionMemory::print(unsigned start_address, unsigned end_address){
cout << "inst_memory[0x" << hex << setw(8) << setfill('0') << start_address << ":0x" << hex << setw(8) << setfill('0') << end_address << "]" << endl;
unsigned i;
for (i = start_address; i<end_address; i++){
if (i % 4 == 0) cout << "0x" << hex << setw(8) << setfill('0') << i << ": ";
cout << hex << setw(2) << setfill('0') << int(inst_memory[i]) << " ";
if (i % 4 == 3) cout << endl;
}
}
InstructionQueue::InstructionQueue(unsigned QueueSize){
maxSize = QueueSize;
}
void InstructionQueue::push(Instruction * inst){
if (q.size() <= maxSize) q.push(inst);
else throw HardwareException("Inst Queue");
}
void InstructionQueue::clear(){
queue<Instruction *> empty;
swap(q, empty);
}
void InstructionQueue::pop(){
q.pop();
}
Instruction * InstructionQueue::fetch(){
if (q.empty()) throw HardwareException("IQ empty");
return q.front();
}
bool InstructionQueue::isFull(){
return (q.size() == maxSize);
}
Controller::Controller(unsigned inst_queue_size, Pipeline * pl, unsigned max_issue) {
this->pl = pl;
this->max_issue = max_issue;
inst_executed = 0;
inst_memory = new InstructionMemory((unsigned)256);
inst_queue = new InstructionQueue(inst_queue_size);//same size as ROB
}
void Controller::execute(){
Instruction * instruction;
bool issueSuccess;
try{
while (true){ //fill inst queue whenever it starts to empty
instruction = inst_memory->fetch(pl->pc.get(), pl);
inst_queue->push(instruction);
pl->pc.pulse();
}
}
catch (exception &e){}
try{
instruction = inst_queue->fetch();
}
catch (HardwareException &he){
instruction = NULL;
cerr << he.what();
}
//put on running_inst stack, then run through that stack and assess() every instruction in it
//if issue() fails, do not pop another instruction
//have to do commit stage before issue
for (unsigned i = 0; i < running_inst.size(); i++){
try{
if (running_inst[i]->getStage() == COMMIT){
running_inst[i]->assess();
}
}
catch (EndOfProgram &eop){
throw EndOfProgram();
}
catch (InstructionEmpty& ie){
// cout << "deleted" << endl;
running_inst.erase(running_inst.begin() + i);
inst_executed++;
i--;
}
catch (BranchException &be){
running_inst.clear();
inst_queue->clear();
inst_executed++;
return;
}
}
try{
if (instruction != NULL){
instruction->issue();
//is if issue successful:
inst_queue->pop();
issueSuccess = true;
}
}
catch (exception &e){
issueSuccess = false;
cerr << e.what();
}
for (int i = 0; i < running_inst.size(); i++){ //run in issue order
// cout << "Instruction being assessed: ";
// running_inst[i]->print();
running_inst[i]->assess();
}
if (issueSuccess){ //this is here because it must take place next clock cycle
//setInInstStageOrder(running_inst);
running_inst.push_back(instruction);
if (instruction != NULL)
instruction->setStage(EXECUTE);
}
}
unsigned char * Controller::inst_mem_base(){
return inst_memory->get_mem_ptr();
}
void Controller::setInInstStageOrder(vector<Instruction *> & running_inst){
Instruction * temp;
for (unsigned i = 0; i < running_inst.size(); i++){
for (unsigned j = i; j > running_inst.size(); j++){
if (running_inst[i]->getStage() < running_inst[j]->getStage()){
temp = running_inst[i];
running_inst[i] = running_inst[j];
running_inst[j] = temp;
}
}
}
}
unsigned Controller::getInstExecuted(){
return inst_executed;
}