|
1
2
3
4
5
6
7
|
//
// Created by imanol on 12/26/16.
//
#include <malloc.h>
#include <string.h>
#include "debug.h"
|
|
8
|
#include <signal.h>
|
|
9
|
|
|
10
|
uint32_t cycle_count = 0;
|
|
11
12
13
14
|
uint8_t breakpoint = 1;
uint16_t breakpoints[0xFF];
uint16_t nbpoints = 0;
char lastchoice = 0;
|
|
15
|
uint8_t terminate = 0;
|
|
16
|
uint8_t break_on_next = 0;
|
|
17
18
19
20
21
|
void to_debugger(int signal)
{
if(signal == SIGINT)
{
|
|
22
|
fprintf(stderr,"CTRL+C hit. Falling to debugger (Press enter if in the middle of input)\n");
|
|
23
24
25
26
27
|
breakpoint = 1;
return;
}
core_dump();
}
|
|
28
|
|
|
29
|
void load_state(char *filename)
|
|
30
|
{
|
|
31
32
33
34
|
FILE *state = fopen(filename,"r");
uint16_t regsdump[NUM_REGISTERS+1];
uint16_t memdump[MEMSIZE];
uint16_t *stackdump;
|
|
35
36
|
uint32_t stacksize;
long stackpos;
|
|
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
fread(regsdump,sizeof(uint16_t),NUM_REGISTERS+1,state);
fread(memdump,sizeof(uint16_t),MEMSIZE,state);
stackpos = ftell(state);
fseek(state,0,SEEK_END);
stacksize = (ftell(state) - stackpos)/sizeof(uint16_t);
stackdump = calloc(stacksize,sizeof(uint16_t));
fseek(state,stackpos,SEEK_SET);
fread(stackdump,sizeof(uint16_t),stacksize,state);
fclose(state);
load_regs(regsdump);
load_memory(memdump);
stack_load(stackdump,stacksize);
free(stackdump);
|
|
53
54
|
}
|
|
55
|
void save_state(char *filename)
|
|
56
|
{
|
|
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
FILE *state = fopen(filename,"w");
uint16_t regsdump[NUM_REGISTERS+1];
uint16_t memdump[MEMSIZE];
uint16_t *stackdump;
uint32_t stacksize;
dump_regs(regsdump);
dump_memory(memdump);
stacksize = stack_dump(&stackdump);
fwrite(regsdump,sizeof(uint16_t),NUM_REGISTERS+1,state);
fwrite(memdump,sizeof(uint16_t),MEMSIZE,state);
fwrite(stackdump,sizeof(uint16_t),stacksize,state);
fclose(state);
free(stackdump);
|
|
72
73
74
75
76
|
}
void query()
{
uint8_t end = 0;
|
|
77
78
|
uint16_t bpoint;
uint16_t mempos;
|
|
79
80
|
char input[100] = {0};
char filename[32];
|
|
81
82
|
uint8_t reg;
uint16_t value;
|
|
83
84
85
|
while(!end)
{
printf("\n> ");
|
|
86
87
88
|
char command = 0;
fgets(input,100,stdin);
command = input[0];
|
|
89
|
//FIXME: Input is not validated in any way. Crashes *will* occur on misuse. Have fun!
|
|
90
91
92
93
94
95
96
97
98
99
100
|
if (command != '\n')
{
lastchoice = command;
}
else
{
command = lastchoice;
}
switch (command)
{
case 'b':
|
|
101
102
|
sscanf(input,"b %hx\n",&bpoint);
fprintf(stderr,"Set breakpoint %hu to %hx",nbpoints,bpoint);
|
|
103
|
breakpoints[nbpoints] = bpoint;
|
|
104
|
nbpoints = (uint16_t)(nbpoints + 1 % 0xFF);
|
|
105
106
|
break;
case 'd':
|
|
107
108
|
sscanf(input,"d %hu\n",&bpoint);
fprintf(stderr,"Deleted breakpoint %hu",bpoint);
|
|
109
|
breakpoints[bpoint] = 0;
|
|
110
111
112
113
114
115
|
break;
case 'c':
breakpoint = 0;
end = 1;
break;
case 'n':
|
|
116
|
break_on_next = 1;
|
|
117
118
119
120
121
122
|
end = 1;
break;
case 'r':
print_regs();
break;
case 'm':
|
|
123
|
sscanf(input,"m %hX\n",&mempos);
|
|
124
|
fprintf(stderr,"%02X: %02x\n",mempos,mem[mempos]);
|
|
125
|
break;
|
|
126
127
|
case 't':
sscanf(input,"t %s\n",filename);
|
|
128
129
130
|
save_state(filename);
fprintf(stderr,"Saved state as %s",filename);
break;
|
|
131
132
133
|
case 's':
end = 1;
break;
|
|
134
135
136
137
138
139
|
case 'l':
sscanf(input,"l %s\n",filename);
load_state(filename);
fprintf(stderr,"Loaded state as %s",filename);
break;
case 'w':
|
|
140
141
|
sscanf(input,"w r%hhu %hu\n",®,&value);
fprintf(stderr,"Setting r%hhu = %02X",reg,value);
|
|
142
143
|
regs[reg] = value;
break;
|
|
144
145
146
147
|
case 'q':
terminate = 1;
end = 1;
break;
|
|
148
149
150
|
case 'h':
//print_debug_commands();
break;
|
|
151
152
153
154
155
156
|
default:
break;
}
}
}
|
|
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
uint8_t in_breakpoint(uint16_t pc)
{
uint8_t i;
for(i = 0; i < nbpoints; i++)
{
if(breakpoints[i] == pc)
{
return 1;
}
}
return 0;
}
uint16_t fetch_debug()
{
uint16_t value = mem[pc++];
return value;
}
|
|
176
|
void translate_args(uint16_t a1, uint16_t a2, uint16_t a3, char *arg1, char *arg2, char *arg3)
|
|
177
|
{
|
|
178
179
180
181
182
183
|
if(a1 > MAX_INT)
{
sprintf(arg1,"r%d",a1-(MAX_INT+1));
}
else
{
|
|
184
|
sprintf(arg1,"%02X",a1);
|
|
185
186
187
188
189
190
191
192
|
}
if(a2 > MAX_INT)
{
sprintf(arg2,"r%d",a2-(MAX_INT+1));
}
else
{
|
|
193
|
sprintf(arg2,"%02X",a2);
|
|
194
195
196
197
198
199
200
201
|
}
if(a3 > MAX_INT)
{
sprintf(arg3,"r%d",a3-(MAX_INT+1));
}
else
{
|
|
202
|
sprintf(arg3,"%02X",a3);
|
|
203
204
205
206
207
208
209
210
211
212
|
}
}
void print_instruction(uint16_t opcode, uint16_t a1, uint16_t a2, uint16_t a3)
{
char arg1[10];
char arg2[10];
char arg3[10];
translate_args(a1,a2,a3,arg1,arg2,arg3);
|
|
213
214
215
|
switch(opcode)
{
case HALT:
|
|
216
|
fprintf(stderr, "HALT\n");
|
|
217
218
|
break;
case MOV:
|
|
219
|
fprintf(stderr, "MOV %s %s\n", arg1, arg2);
|
|
220
221
|
break;
case PUSH:
|
|
222
|
fprintf(stderr, "PUSH %s\n", arg1);
|
|
223
224
|
break;
case POP:
|
|
225
|
fprintf(stderr, "POP %s\n", arg1);
|
|
226
227
|
break;
case TEQ:
|
|
228
|
fprintf(stderr, "TEQ %s %s %s\n", arg1, arg2, arg3);
|
|
229
230
|
break;
case TGT:
|
|
231
|
fprintf(stderr, "TGT %s %s %s\n", arg1, arg2, arg3);
|
|
232
233
|
break;
case JMP:
|
|
234
|
fprintf(stderr, "JMP %s\n", arg1);
|
|
235
236
|
break;
case JNZ:
|
|
237
|
fprintf(stderr, "JNZ %s %s\n", arg1, arg2);
|
|
238
239
|
break;
case JZ:
|
|
240
|
fprintf(stderr, "JZ %s %s\n", arg1, arg2);
|
|
241
242
|
break;
case ADD:
|
|
243
|
fprintf(stderr, "ADD %s %s %s\n", arg1, arg2, arg3);
|
|
244
245
|
break;
case MUL:
|
|
246
|
fprintf(stderr, "MUL %s %s %s\n", arg1, arg2, arg3);
|
|
247
248
|
break;
case MOD:
|
|
249
|
fprintf(stderr, "MOD %s %s %s\n", arg1, arg2, arg3);
|
|
250
251
|
break;
case AND:
|
|
252
|
fprintf(stderr, "AND %s %s %s\n", arg1, arg2, arg3);
|
|
253
254
|
break;
case OR:
|
|
255
|
fprintf(stderr, "OR %s %s %s\n", arg1, arg2, arg3);
|
|
256
257
|
break;
case NOT:
|
|
258
|
fprintf(stderr, "NOT %s %s\n", arg1, arg2);
|
|
259
260
|
break;
case LOAD:
|
|
261
|
fprintf(stderr, "LOAD %s %s\n", arg1, arg2);
|
|
262
263
|
break;
case STOR:
|
|
264
|
fprintf(stderr, "STOR %s %s\n", arg1, arg2);
|
|
265
266
|
break;
case CALL:
|
|
267
|
fprintf(stderr, "CALL %s\n", arg1);
|
|
268
269
|
break;
case RET:
|
|
270
|
fprintf(stderr, "RET\n");
|
|
271
272
|
break;
case OUT:
|
|
273
274
275
276
277
278
279
280
|
if (a1 <= MAX_INT)
{
fprintf(stderr, "OUT '%c'\n",a1);
}
else
{
fprintf(stderr, "OUT %s\n", arg1);
}
|
|
281
282
|
break;
case IN:
|
|
283
|
fprintf(stderr,"IN %s\n",arg1);
|
|
284
285
|
break;
case NOP:
|
|
286
|
fprintf(stderr,"NOP\n");
|
|
287
288
|
break;
default:
|
|
289
|
fprintf(stderr,"UNK %02X\n", opcode);
|
|
290
291
292
293
294
|
break;
}
}
|
|
295
296
|
void debug_program()
{
|
|
297
|
signal(SIGINT, to_debugger);
|
|
298
299
300
301
302
303
|
memset(breakpoints,0x00,0xFF);
uint16_t arg1;
uint16_t arg2;
uint16_t arg3;
for(;;)
{
|
|
304
|
cycle_count++;
|
|
305
306
307
|
if(in_breakpoint(pc))
{
breakpoint = 1;
|
|
308
|
fprintf(stderr,"Breakpoint hit @ pc=%X\n",pc);
|
|
309
|
}
|
|
310
|
if(breakpoint)
|
|
311
|
{
|
|
312
|
break_on_next = 0;
|
|
313
|
fprintf(stderr, "cycle: %d\n", cycle_count);
|
|
314
|
fprintf(stderr, "%02X: ", pc);
|
|
315
|
print_instruction(mem[pc], mem[pc+1], mem[pc+2], mem[pc+3]);
|
|
316
317
318
319
|
if(stdin_length())
{
read_input();
}
|
|
320
|
query();
|
|
321
322
323
324
|
if(terminate)
{
return;
}
|
|
325
326
|
}
uint16_t opcode = fetch_debug();
|
|
327
328
329
330
331
332
333
334
335
336
337
338
339
|
if(opcode == CALL && break_on_next != 0)
{
breakpoint = 0;
break_on_next++;
}
else if(opcode == RET && break_on_next != 0)
{
if(--break_on_next == 1)
{
breakpoint = 1;
break_on_next = 0;
}
}
|
|
340
341
|
decode_instruction(opcode, &arg1, &arg2, &arg3);
if (execute_instruction(opcode, arg1, arg2, arg3))
|
|
342
|
{
|
|
343
|
return;
|
|
344
345
346
|
}
}
}
|