-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathriscv.cpp
More file actions
355 lines (336 loc) · 9.58 KB
/
riscv.cpp
File metadata and controls
355 lines (336 loc) · 9.58 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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
* riscv.cpp
*
* Instructions: (v1.0)
* add, addi, and, andi, auipc,
* beq, bne, jal, jalr, lb,
* lbu, lw, lui, nop, or,
* ori, sb, slli, slt, sltu,
* srai, srli, sub, sw, xor,
* ecall
*/
//
// Initial values for registers
//
void init() {
pc = 0; ri = 0;
stop_prg = false;
sp = 0x3ffc;
gp = 0x1800;
build_dic();
}
// Imprime conteudo do banco de registradores
//
void dump_breg() {
for (int i=0; i<32; i++) {
printf("BREG[%s] = \t%8d \t\t\t%8x\n", reg_str[i].c_str(), breg[i], breg[i]);
}
}
// Carrega um arquivo binario para a memoria
//
int load_mem(const char *fn, int start) {
FILE *fptr;
int *m_ptr = mem + (start>>2);
int size = 0;
fptr = fopen(fn, "rb");
if (!fptr) {
printf("Arquivo nao encontrado!\n");
return -1;
}
else {
while (!feof(fptr)) {
fread(m_ptr, 4, 1, fptr);
m_ptr++;
size++;
}
fclose(fptr);
}
return size;
}
// Determina o formato da intrucao
//
FORMATS get_i_format(uint32_t opcode, uint32_t func3, uint32_t func7) {
switch(opcode) {
case 0x33 : return RType;
case 0x03: case 0x13: case 0x67: case 0x73:
return IType;
case 0x23 :
return SType;
case 0x63 :
return SBType;
case 0x37: case 0x17:
return UType;
case 0x6F:
return UJType;
case 0x00:
if (func3 == 0 && func7 == 0)
return NOPType;
else
return NullFormat;
default:
cout << "Undefined Format";
return NullFormat;
break;
}
}
// Determina a instrucao a ser executada
INSTRUCTIONS get_instr_code(uint32_t opcode, uint32_t func3, uint32_t func7) {
switch (opcode) {
case LUI: return I_lui;
case AUIPC: return I_auipc;
case BType:
switch (funct3) {
case BEQ3: return I_beq;
case BNE3: return I_bne;
case BGE3: return I_bge;
case BGEU3: return I_bgeu;
case BLT3: return I_blt;
case BLTU3: return I_bltu;
}
break;
case ILType:
switch (funct3) {
case LB3: return I_lb;
case LW3: return I_lw;
case LBU3: return I_lbu;
default: break;
}
break;
case JAL: return I_jal;
case JALR: return I_jalr;
case StoreType:
switch (funct3) {
case SB3: return I_sb;
case SW3: return I_sw;
default: break;
}
break;
case ILAType:
switch (funct3) {
case ADDI3: return I_addi;
case ORI3: return I_ori;
case ANDI3: return I_andi;
case SLLI3: return I_slli;
case SRI3:
switch(funct7){
case SRAI7: return I_srai;
case SRLI7: return I_srli;
default: break;
}
break;
default: break;
}
break;
case RegType:
switch (funct3) {
case ADDSUB3:
if (funct7 == SUB7) return I_sub;
else return I_add;
case SLL3: return I_sll;
case SLT3: return I_slt;
case SLTU3: return I_sltu;
case XOR3: return I_xor;
case OR3: return I_or;
case AND3: return I_and;
case SR3:
if (funct7 == SRA7) return I_sra;
else return I_srl;
default:
break;
}
break;
case ECALL: return I_ecall;
default:
printf("Instrucao Invalida (PC = %08x RI = %08x)\n", pc, ri);
break;
}
return I_nop;
}
// Instrucao decodificada
//
INSTRUCTIONS instruction;
/************************************ FETCH **********************************/
void fetch () {
ri = lw(pc, 0);
pc = pc + 4;
}
/*********************************** DECODE **********************************/
void decode () {
int32_t tmp;
opcode = ri & 0x7F; // codigo da instrucao
rs2 = (ri >> 20) & 0x1F; // segundo operando
rs1 = (ri >> 15) & 0x1F; // primeiro operando
rd = (ri >> 7) & 0x1F; // registrador destino
shamt = (ri >> 20) & 0x1F; // deslocamento
funct3 = (ri >> 12) & 0x7; // auxiliar codigo instrucao
funct7 = (ri >> 25); // auxiliar codigo de instrucao
imm12_i = ((int32_t)ri) >> 20; // imediato 12 bits
tmp = get_field(ri, 7, 0x1f);
imm12_s = set_field(imm12_i, 0, 0x1f, tmp);
imm13 = imm12_s;
imm13 = set_bit(imm13, 11, imm12_s&1);
imm13 = imm13 & ~1;
imm20_u = ri & (~0xFFF);
// mais aborrecido: imediato 21 bits
imm21 = (int32_t)ri >> 11; // estende sinal
tmp = get_field(ri, 12, 0xFF); // le campo 19:12
imm21 = set_field(imm21, 12, 0xFF, tmp); // escreve campo em imm21
tmp = get_bit(ri, 20); // le o bit 11 em ri(20)
imm21 = set_bit(imm21, 11, tmp); // posiciona bit 11
tmp = get_field(ri, 21, 0x3FF);
imm21 = set_field(imm21, 1, 0x3FF, tmp);
imm21 = imm21 & ~1; // zera bit 0
instruction = get_instr_code(opcode, funct3, funct7);
imm32_t = *imediatos[get_i_format(opcode, funct3, funct7)];
}
int i_word = 0;
char *letra;
void execute () {
switch(instruction){
case I_add:
breg[rd] = breg[rs1] + breg[rs2];
break;
case I_addi:
breg[rd] = breg[rs1] + imm32_t;
break;
case I_and:
breg[rd] = breg[rs1]&breg[rs2];
break;
case I_andi:
breg[rd] = breg[rs1]&imm32_t;
break;
case I_auipc:
breg[rd] = pc - 4 + imm32_t;
break;
case I_beq:
if(breg[rs1] == breg[rs2]){
pc = pc - 4 + imm32_t;
}
break;
case I_bge:
if(breg[rs1] >= breg[rs2]){
pc = pc - 4 + imm32_t;
}
break;
case I_bgeu:
if((unsigned)breg[rs1] >= (unsigned)breg[rs2]){
pc = pc - 4 + imm32_t;
}
break;
case I_blt:
if(breg[rs1] < breg[rs2]){
pc = pc - 4 + imm32_t;
}
break;
case I_bltu:
if((unsigned)breg[rs1] < (unsigned)breg[rs2]){
pc = pc - 4 + imm32_t;
}
break;
case I_bne:
if(breg[rs1] != breg[rs2]){
pc = pc - 4 + imm32_t;
}
break;
case I_jal:
breg[rd] = pc;
pc = pc - 4 + imm32_t;
breg[ZERO] = 0;
break;
case I_jalr:
breg[rd] = pc;
pc = imm32_t + breg[rs1];
breg[ZERO] = 0;
break;
case I_nop:
break;
case I_sltu:
if((unsigned)breg[rs1] < (unsigned)breg[rs2]){
breg[rd] = 1;
}
else{
breg[rd] = 0;
}
break;
case I_or:
breg[rd] = breg[rs1] | breg[rs2];
break;
case I_ori:
breg[rd] = breg[rs1] | imm32_t;
break;
case I_slt:
if(breg[rs1] < breg[rs2]){
breg[rd] = 1;
}
else{
breg[rd] = 0;
}
break;
case I_lb:
breg[rd] = lb(breg[rs1], imm32_t);
break;
case I_lbu:
breg[rd] = lbu(breg[rs1], imm32_t);
break;
case I_lw:
breg[rd] = lw(breg[rs1], imm32_t);
break;
case I_lui:
breg[rd] = imm32_t;
break;
case I_sb:
sb(breg[rs1], imm32_t, breg[rs2]);
break;
case I_sw:
sw(breg[rs1], imm32_t, breg[rs2]);
break;
case I_slli:
breg[rd] = breg[rs1] << imm32_t;
break;
case I_srai:
breg[rd] = (signed)breg[rs1] >> imm32_t;
break;
case I_srli:
breg[rd] = (unsigned)breg[rs1] >> imm32_t;
break;
case I_sub:
breg[rd] = breg[rs1] - breg[rs2];
break;
case I_xor:
breg[rd] = breg[rs1] ^ breg[rs2];
break;
case I_ecall:
switch(breg[A7]){
case 1:
printf("%d\n", breg[A0]);
break;
case 4:
letra = (char*)mem + breg[A0];
i_word = 0;
while(*(letra + i_word) != '\0'){
cout << *(letra+i_word);
i_word++;
}
break;
case 10:
stop_prg = 1;
break;
default:
break;
}
break;
default:
cout << "command not found";
break;
}
}
void step() {
fetch();
decode();
execute();
}
void run() {
init();
while ((pc < DATA_SEGMENT_START) && !stop_prg)
step();
}