forked from jborza/emuriscv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.c
279 lines (247 loc) · 6.7 KB
/
test.c
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
#include <stdio.h>
#include "config.h"
#include "cpu.h"
#include <memory.h>
#include "test.h"
#include "decode.h"
#include "memory.h"
#include "exit_codes.h"
#ifdef RUN_TESTS
int last_exit_code = 0;
int bin_file_size = 0;
const int SUCCESS = 42;
const int FAIL = 0;
const int test_ram_size = 1 * 1024 * 1024;
void set_last_exit_code(int code) {
last_exit_code = code;
}
void check_test_exit_code(State* state) {
if (last_exit_code == FAIL) {
printf("TEST FAILED! gp=0x%08x\n",state->x[3]);
exit(EXIT_TEST_FAILED);
}
}
void clear_state(State* state) {
//clear the registers
for (int i = 0; i < REGISTERS; i++)
state->x[i] = 0;
state->pc = 0;
state->status = RUNNING;
//clear the memory
const int memory_size = 1024 * 1024;
state->memory_map = phys_mem_map_init();
cpu_register_ram(state->memory_map, 0, test_ram_size);
set_last_exit_code(0);
}
void print_registers(State* state) {
for (int i = 0; i < 32; i++) {
printf("x%d %08X\t", i, state->x[i]);
if ((i + 1) % 4 == 0)
printf("\n");
}
}
//void test_beq_1() {
// int program[] = {
// 0x00000463, //beq x0,x0,0x4
// 0x00900093, //addi x1, x0, 0x9
// 0x00000013, //nop / addi x0,x0,0
// };
// State state;
// clear_state(&state);
// memcpy(state.memory, program, sizeof(program));
// emulate_op(&state);
// print_registers(&state);
// emulate_op(&state);
// if (state.x[1] != 0x0) {
// printf("Assertion failed, x1 should be 0!");
// exit(1);
// }
//}
//
//void test_addi() {
// int program[] = {
// 0x800000b7, //lui x1, 0x00080000
// 0xfff08093, //addi x1, x1, 0xffffffff
// 0x00108f13, //addi x30, x1, 0x001
// };
// State state;
// clear_state(&state);
// memcpy(state.memory, program, sizeof(program));
// for (int i = 0; i < 3; i++)
// {
// emulate_op(&state);
// print_registers(&state);
// }
// if (state.x[30] != 0x80000000)
// printf("Assertion failed!");
//}
void assert_shamt(word instruction, int expected_shamt) {
int actual_shamt = shamt(instruction);
if (actual_shamt != expected_shamt) {
printf("Unexpected shamt value: %d, expected %d", actual_shamt, expected_shamt);
exit(EXIT_TEST_FAILED);
return;
}
}
//void test_shamt() {
// word instr = 0x00009f13; //slli x30, x1, 0
// assert_shamt(0x00009f13 /*slli x30, x1, 0*/, 0);
// assert_shamt(0x00109f13 /*slli x30, x1, 1*/, 1);
// assert_shamt(0x00709f13 /*slli x30, x1, 7*/, 7);
// assert_shamt(0x00e09f13 /*slli x30, x1, 14*/, 14);
// assert_shamt(0x01f09f13 /*slli x30, x1, 31*/, 31);
//}
void assert_b_imm(word instruction, int expected_imm) {
int actual = get_b_imm(instruction);
if (actual != expected_imm) {
printf("Unexpected B-imm value: %d, expected %d", actual, expected_imm);
exit(EXIT_TEST_FAILED);
return;
}
}
//void test_b_imm() {
// assert_b_imm(0xfe000ee3 /* beq x0, x0, 0xfffffffe */, 0xfffffffc/*0xfffffffe * 2*/);
// assert_b_imm(0x00108a63 /* beq x1, x1, 0x0000000a */, 0x0000000a * 2);
// assert_b_imm(0x08108263 /* beq x1, x1, 0x00000042 */, 0x00000042 * 2);
// assert_b_imm(0x16108663 /* beq x1, x1, 0x000000b6 */, 0x000000b6 * 2);
// assert_b_imm(0x1a108e63 /* beq x1, x1, 0x000000de */, 0x000000de * 2);
// assert_b_imm(0x1e108e63 /* beq x1, x1, 0x000000fe */, 0x000000fe * 2);
// assert_b_imm(0x24108463 /* beq x1, x1, 0x00000124 */, 0x00000124 * 2);
//}
//
//void test_addi_2() {
// int program[] = {
// 0x80000eb7, //lui x29, 0xfff80000
// 0x00008093 //addi x29,x29,0x0
// };
// State state;
// clear_state(&state);
// memcpy(state.memory, program, sizeof(program));
// for (int i = 0; i < 2; i++)
// {
// emulate_op(&state);
// print_registers(&state);
// }
// if (state.x[29] != 0x80000000)
// printf("Assertion failed!");
//}
//
//void test_slli() {
// int program[] = {
// 0x00033537, //lui a0,0x33
// 0xbfb50513, //addi a0,a0,-1029
// 0x00e51513, //slli a0,a0,0xe
// 0xabe50513 //addi a0,a0,-1346
// };
// State state;
// clear_state(&state);
// memcpy(state.memory, program, sizeof(program));
// for (int i = 0; i < 4; i++)
// {
// emulate_op(&state);
// print_registers(&state);
// }
// if (state.x[10] != 0xcafebabe)
// printf("Assertion failed!");
//}
void test_bin(char* name) {
printf("Starting test for: %s\n", name);
byte* buffer = read_bin(name, &bin_file_size);
if (buffer == NULL) {
return;
}
State *state = mallocz(sizeof(State));
clear_state(state);
//load test binary
memcpy(state->memory_map[0].phys_mem_range->phys_mem_ptr, buffer, bin_file_size);
for (;;) {
MemoryTarget next_op_target;
int read_status = get_memory_target(state, state->pc, FETCH, &next_op_target);
word* instruction = next_op_target.ptr;
//word* address = state.memory + state.pc;
printf("%08x: %08x \n", state->pc, *instruction);
emulate_op(state);
//print_registers(&state);
if (state->status == EXIT_TERMINATION) {
check_test_exit_code(state);
break;
}
}
printf("Test %s passed\n", name);
}
void test_memory() {
//TODO assume the compact configuration - .text at 0x0000, .data at 0x2000
//TODO generalize test_simple_bin
}
void test_ecall_callback(State* state) {
//tests use a7 = EXIT (93)
if (state->x[SYSCALL_REG] == EXIT) {
set_last_exit_code(state->x[SYSCALL_ARG0]);
state->status = EXIT_TERMINATION;
}
}
void run_tests() {
//test_addi_2();
//test_shamt();
//test_b_imm();
//test_beq_1();
test_bin("test/simple.bin");
test_bin("test/slli.bin");
//integer register-register
test_bin("test/add.bin");
test_bin("test/slt.bin");
test_bin("test/sltu.bin");
test_bin("test/sub.bin");
//register-immediate special
test_bin("test/lui.bin");
test_bin("test/auipc.bin");
//register-register logical
test_bin("test/and.bin");
test_bin("test/or.bin");
test_bin("test/xor.bin");
//register-register shifts
test_bin("test/sll.bin");
test_bin("test/srl.bin");
test_bin("test/sra.bin");
//immediate shifts
test_bin("test/slli.bin");
test_bin("test/srli.bin");
test_bin("test/srai.bin");
//register-register immediate logical
test_bin("test/andi.bin");
test_bin("test/ori.bin");
test_bin("test/xori.bin");
//register-register immediates
test_bin("test/addi.bin");
test_bin("test/slti.bin");
test_bin("test/sltiu.bin");
//conditional branches
test_bin("test/beq_bne_loop.bin");
test_bin("test/beq.bin");
test_bin("test/bltu.bin");
test_bin("test/blt.bin");
test_bin("test/bge.bin");
test_bin("test/bgeu.bin");
//load/save
test_bin("test/lw_sw_offset.bin");
test_bin("test/lh_sh.bin");
test_bin("test/lb_sb.bin");
test_bin("test/memory.bin");
//jumps
test_bin("test/jal_long.bin");
test_bin("test/jal_simple.bin");
test_bin("test/jalr.bin");
//atomics
test_bin("test/amoadd.w.bin");
}
int run_test_suite() {
set_ecall_callback(&test_ecall_callback);
run_tests();
printf("--------------------------\n");
printf("ALL TESTS PASSED\n");
printf("--------------------------\n");
}
int main() {
run_test_suite();
}
#endif