-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMachine.cpp
More file actions
251 lines (196 loc) · 7.51 KB
/
Machine.cpp
File metadata and controls
251 lines (196 loc) · 7.51 KB
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#include "Machine.h"
#include "Constants.h"
#include <iostream>
Machine::Machine(DRAM& memRef)
: PC(0), R(), bus(memRef)
{
R.setSP(STACK_BOTTOM);
}
uint32_t Machine::stackPop()
{
uint32_t sp = R.readFromRegister(SP_REG);
uint32_t value = bus.loadFromMem(sp, WORD_SIZE_BITS);
R.writeToRegister(SP_REG, sp + WORD_SIZE_BYTES);
return value;
}
void Machine::stackPush(uint32_t value)
{
uint32_t sp = R.readFromRegister(SP_REG);
sp -= WORD_SIZE_BYTES;
bus.storeInMem(sp, WORD_SIZE_BITS, value);
R.writeToRegister(SP_REG, sp);
}
uint32_t Machine::getPC() const
{
return PC;
}
void Machine::loadProgram(const std::string& filename)
{
uint32_t entry_point = elf.loadELF(filename, bus);
PC=entry_point;
std::cout << "PC is: 0x" << std::hex << entry_point << std::dec << "\n";
}
void Machine::setPC(uint32_t value)
{
PC = value;
}
void Machine::dumpMemory(std::ostream& out) {
for (uint32_t addr = 0; addr < MEMORY_SIZE; ++addr) {
uint8_t byte = bus.loadFromMem(addr, 8);
out.put(byte);
}
}
void Machine::fetch() {
std::cout << "Using PC: 0x" << std::hex << PC << std::dec << "\n";
if (PC > MEMORY_SIZE - 4) {
std::cerr << "Segfault: PC out of bounds at 0x" << std::hex << PC << "\n";
exit(1);
}
instr.instr=bus.loadFromMem(PC, WORD_SIZE_BITS); // Already in little endian
PC += 4;
}
void Machine::decode()
{
decodedInstr = decoder.decode(instr.instr);
std::cout << "Opcode is : 0x" << std::hex << static_cast<int>(decodedInstr.opcode) << std::dec << "\n";
}
Decoder::InstrType Machine::getInstrTypeEnum(uint8_t opcode)
{
switch(opcode) {
case 0x33: return Decoder::InstrType::R_TYPE; // R-type (e.g., ADD, SUB)
case 0x13: return Decoder::InstrType::I_TYPE; // I-type (e.g., ADDI, ANDI)
case 0x03: return Decoder::InstrType::I_TYPE; // Load instructions
case 0x67: return Decoder::InstrType::JALR_TYPE; // JALR (I-type but special behavior)
case 0x73: return Decoder::InstrType::ECALL_TYPE; // ECALL
case 0x23: return Decoder::InstrType::S_TYPE; // Store (SB, SH, SW)
case 0x63: return Decoder::InstrType::B_TYPE; // Branch (BEQ, BNE, etc.)
case 0x17: return Decoder::InstrType::U_TYPE; // AUIPC
case 0x37: return Decoder::InstrType::U_TYPE; // LUI
case 0x6F: return Decoder::InstrType::J_TYPE; // JAL
default: return Decoder::InstrType::UNKNOWN_TYPE;
}
}
void Machine::execute()
{
Decoder::InstrType instrType = getInstrTypeEnum(decodedInstr.opcode);
switch (instrType) {
case Decoder::InstrType::B_TYPE: {
uint32_t src1 = R.readFromRegister(decodedInstr.rs1);
uint32_t src2 = R.readFromRegister(decodedInstr.rs2);
bool branch_taken = false;
switch (decodedInstr.funct3) {
case 0x0: branch_taken = (src1 == src2); break; // BEQ
case 0x1: branch_taken = (src1 != src2); break; // BNE
case 0x4: branch_taken = (int32_t(src1) < int32_t(src2)); break; // BLT
case 0x5: branch_taken = (int32_t(src1) >= int32_t(src2)); break; // BGE
case 0x6: branch_taken = (src1 < src2); break; // BLTU
case 0x7: branch_taken = (src1 >= src2); break; // BGEU
default:
std::cerr << "Unknown branch funct3: " << std::hex << int(decodedInstr.funct3) << std::dec << "\n";
break;
}
if (branch_taken) {
PC = PC + decodedInstr.imm - 4;
std::cout << "Branch taken to 0x" << std::hex << PC << std::dec << "\n";
}
else {
std::cout << "Branch not taken\n";
}
// Branch instructions do NOT write registers
break;
}
case Decoder::InstrType::U_TYPE: {
if (decodedInstr.opcode == 0x17) { // AUIPC
uint32_t src1 = PC;
uint32_t src2 = decodedInstr.imm;
uint32_t result = 0;
alu.execute(ALU::AluOp::Add, src1, src2, result);
R.writeToRegister(decodedInstr.rd, result);
}
else if (decodedInstr.opcode == 0x37) { // LUI
R.writeToRegister(decodedInstr.rd, decodedInstr.imm);
}
break;
}
case Decoder::InstrType::J_TYPE: { // JAL
R.writeToRegister(decodedInstr.rd, PC);
PC = (PC - 4) + decodedInstr.imm; // jump target
break;
}
case Decoder::InstrType::JALR_TYPE: { // JALR (I-type, opcode 0x67)
uint32_t target = (R.readFromRegister(decodedInstr.rs1) + decodedInstr.imm) & ~1U;
uint32_t return_addr = PC;
R.writeToRegister(decodedInstr.rd, return_addr);
PC = target;
break;
}
case Decoder::InstrType::S_TYPE: { // Store instructions
uint32_t addr = R.readFromRegister(decodedInstr.rs1) + decodedInstr.imm;
uint32_t val = R.readFromRegister(decodedInstr.rs2);
switch (decodedInstr.funct3) {
case 0x0: // SB
bus.storeInMem(addr, BYTE_SIZE, val & 0xFF); // lowest 8 bits
break;
case 0x1: // SH
bus.storeInMem(addr, HALF_WORD_SIZE_BITS, val & 0xFFFF); // lowest 16 bits
break;
case 0x2: // SW
bus.storeInMem(addr, WORD_SIZE_BITS, val);
break;
default:
std::cerr << "Unknown store funct3: " << std::hex << int(decodedInstr.funct3) << std::dec << "\n";
}
break;
}
case Decoder::InstrType::R_TYPE: {
ALU::AluOp op = alu.getAluOp(decodedInstr);
uint32_t src1 = R.readFromRegister(decodedInstr.rs1);
uint32_t src2 = R.readFromRegister(decodedInstr.rs2);
uint32_t result = 0;
alu.execute(op, src1, src2, result);
R.writeToRegister(decodedInstr.rd, result);
break;
}
case Decoder::InstrType::I_TYPE: {
if (decodedInstr.opcode == 0x03) { // Load instructions
uint32_t base = R.readFromRegister(decodedInstr.rs1);
uint32_t addr = base + decodedInstr.imm;
uint32_t val = 0;
switch (decodedInstr.funct3) {
case 0x0: // LB
val = decoder.signExtend(bus.loadFromMem(addr, BYTE_SIZE), BYTE_SIZE);
break;
case 0x1: // LH
val = decoder.signExtend(bus.loadFromMem(addr, HALF_WORD_SIZE_BITS), HALF_WORD_SIZE_BITS);
break;
case 0x2: // LW
val = bus.loadFromMem(addr, WORD_SIZE_BITS);
break;
case 0x4: // LBU
val = bus.loadFromMem(addr, BYTE_SIZE);
break;
case 0x5: // LHU
val = bus.loadFromMem(addr, HALF_WORD_SIZE_BITS);
break;
default:
std::cerr << "Unknown load funct3: " << std::hex << int(decodedInstr.funct3) << std::dec << "\n";
break;
}
R.writeToRegister(decodedInstr.rd, val);
}
else { // ALU-based I-type instructions
ALU::AluOp op = alu.getAluOp(decodedInstr);
uint32_t src1 = R.readFromRegister(decodedInstr.rs1);
uint32_t src2 = decodedInstr.imm;
uint32_t result = 0;
alu.execute(op, src1, src2, result);
std::cout << "I-type: x" << int(decodedInstr.rd) << " = " << result << "\n";
R.writeToRegister(decodedInstr.rd, result);
}
break;
}
default:
std::cerr << "Unknown instruction type in execute\n";
break;
}
}