1 /****************************************************************************
2 * tgdisasm.c -- Joseph LoCicero, IV -- 96/5/09
3 Dave Shadoff -- 96/5/09
4 Zeograd -- 99/5/25
5
6 Simple TG Disassembler based on 65C02 opcode listing.
7
8 Updates:
9 --------
10 Dave Shadoff 96/7/19 Place 'new' Hu6280 opcodes/addressing modes in,
11 due to new information available from Japanese
12 'Develo' system asembler.
13 Zeograd 99/5/25 Modifications to be integrated in Hu-Go!
14 for disassemblying on-fly
15
16 ****************************************************************************/
17
18 #include "dis.h"
19
20 /* Way to accedate to the PC Engine memory
21
22 unsigned char Op6502(register unsigned A) { register char __AUX;
23 __asm__ __volatile__ ("
24 movl _Page(,%%eax,4),%%ecx
25 movb (%%edx,%%ecx),%%al"
26 : "=a" (__AUX)
27 : "d" (A) , "a" (A>>13)
28 : "%ebx" , "%ecx" );
29 return __AUX; };
30
31 // disabled 'coz of integration in debug.c
32
33 */
34
35 /* GLOBALS */
36
37 UChar opbuf[OPBUF_SIZE];
38
39 UInt16 init_pos;
40 // Initial adress to disassemble
41
42 UInt16 selected_position;
43 // Adress user points to
44
45 UChar running_mode;
46 // the state we are running the cpu:
47 // 0 -> plain running
48 // 1 -> stepping, going over subroutines
49 // 2 -> tracing, diving into subroutines
50
51 /*****************************************************************************
52
53 Function: forward_one_line
54
55 Description: make the screen scroll down one line
56 Parameters: none
57 Return: none but set init_pos
58
59 *****************************************************************************/
60 void
forward_one_line()61 forward_one_line ()
62 {
63 unsigned char op;
64
65 op = get_8bit_addr(init_pos);
66 if ((op & 0xF) == 0xB)
67 {
68 if (Bp_list[op >> 4].flag == NOT_USED)
69 init_pos++;
70 else
71 op = Bp_list[op >> 4].original_op;
72 }
73
74 init_pos += addr_info_debug[optable_debug[op].addr_mode].size;
75 return;
76 }
77
78
79 /*****************************************************************************
80
81 Function: backward_one_line
82
83 Description: make the screen scroll one line up, al least, try ;)
84 Parameters: none
85 Return: nothing, but set init_pos
86
87 *****************************************************************************/
88 void
backward_one_line()89 backward_one_line ()
90 {
91 char line;
92 unsigned char Try;
93 UInt16 try_pos[MAX_TRY] = { 1, 2, 3, 4, 7 };
94 unsigned short temp_pos;
95 char possible;
96 unsigned char op, size, i;
97
98 for (Try = 0; Try < MAX_TRY; Try++)
99 {
100 if (init_pos >= try_pos[Try])
101 temp_pos = init_pos - try_pos[Try];
102 line = 0;
103 possible = 1;
104
105 while ((line < NB_LINE) && (temp_pos != 0xFFFF))
106 {
107 op = get_8bit_addr (temp_pos);
108
109 if ((op & 0xF) == 0xB)
110 { // It's a breakpoint, we replace it and set the bp_color variable
111 if ((Bp_list[op >> 4].flag == ENABLED) ||
112 (Bp_list[op >> 4].flag == DISABLED))
113 op = Bp_list[op >> 4].original_op;
114 }
115
116 size = addr_info_debug[optable_debug[op].addr_mode].size;
117
118 opbuf[0] = op;
119 temp_pos++;
120 for (i = 1; i < size; i++)
121 opbuf[i] = get_8bit_addr (temp_pos++);
122
123 if (((op & 0xF) == 0xB) || (!strcmp (optable_debug[op].opname, "???")))
124 { // If it's still a breakpoint, it wasn't set and shouldn't be here
125 possible = 0;
126 break;
127 }
128
129 line++;
130 }
131
132 if (possible)
133 {
134 init_pos -= try_pos[Try];
135 return;
136 }
137
138 }
139
140 // We haven't found any good result then ...
141
142 init_pos -= try_pos[1];
143 return;
144 }
145
146
147 /*****************************************************************************
148
149 Function: dis_key
150
151 Description: handle the keyboard in the disassemble function
152 Parameters: none
153 Return: 0 if can go on
154 1 if we must quit the dis function
155 may set a few global variable
156
157 *****************************************************************************/
158 int
dis_key()159 dis_key ()
160 {
161
162 /* TODO: deallegroization needed here */
163 #ifdef ALLEGRO
164 int ch = osd_readkey ();
165 switch (ch >> 8)
166 {
167 case KEY_DOWN:
168 selected_position +=
169 addr_info_debug[optable_debug[Op6502 (selected_position)].addr_mode].size;
170 forward_one_line ();
171 return 0;
172
173 case KEY_UP:
174 backward_one_line ();
175 selected_position = init_pos;
176 return 0;
177
178 case KEY_PGDN:
179 {
180 char dum;
181 for (dum = 1; dum < NB_LINE; dum++)
182 forward_one_line ();
183 // Let one line from the previous display
184 }
185 return 0;
186 case KEY_PGUP:
187 {
188 char dum;
189 for (dum = 1; dum < NB_LINE; dum++)
190 backward_one_line ();
191 }
192 return 0;
193 case KEY_F1: /* F1 */
194 display_debug_help ();
195 return 0;
196 case KEY_F2: /* F2 */
197 toggle_user_breakpoint (selected_position);
198 return 0;
199
200 case KEY_F3: /* F3 */
201 {
202 char *tmp_buf = (char *) alloca (20);
203 UChar index = 0;
204
205 while (osd_keypressed ())
206 osd_readkey ();
207
208 while ((index < 20)
209 && (tmp_buf[index++] = osd_readkey () & 0xFF) != 13);
210
211 tmp_buf[index - 1] = 0;
212
213 // Just in case :
214 if (Bp_list[GIVE_HAND_BP].flag != NOT_USED)
215 {
216 _Wr6502 (Bp_list[GIVE_HAND_BP].position,
217 Bp_list[GIVE_HAND_BP].original_op);
218 Bp_list[GIVE_HAND_BP].flag = NOT_USED;
219 }
220
221 save_background = 0;
222
223 Bp_list[GIVE_HAND_BP].flag = ENABLED;
224 Bp_list[GIVE_HAND_BP].position = cvtnum (tmp_buf);
225 Bp_list[GIVE_HAND_BP].original_op = Op6502 (cvtnum (tmp_buf));
226
227 _Wr6502 (cvtnum (tmp_buf), 0xB + 0x10 * GIVE_HAND_BP);
228 // Put an invalid opcode
229 }
230 return 1;
231
232 case KEY_F4: /* F4 */
233
234 // Just in case :
235 if (Bp_list[GIVE_HAND_BP].flag != NOT_USED)
236 {
237 _Wr6502 (Bp_list[GIVE_HAND_BP].position,
238 Bp_list[GIVE_HAND_BP].original_op);
239 Bp_list[GIVE_HAND_BP].flag = NOT_USED;
240 }
241
242 save_background = 0;
243
244 Bp_list[GIVE_HAND_BP].flag = ENABLED;
245 Bp_list[GIVE_HAND_BP].position = selected_position;
246 Bp_list[GIVE_HAND_BP].original_op = Op6502 (selected_position);
247
248 _Wr6502 (selected_position, 0xB + 0x10 * GIVE_HAND_BP);
249 // Put an invalid opcode
250
251 return 1;
252
253 case KEY_F5: /* F5 */
254 #ifndef KERNEL_DS
255 _PC_ = selected_position;
256 #else
257 reg_pc = selected_position;
258 #endif
259 return 0;
260
261 case KEY_F6: /* F6 */
262 {
263 char dum;
264 unsigned char op = Op6502 (selected_position);
265
266 if ((op & 0xF) == 0xB)
267 op = Bp_list[op >> 4].original_op;
268
269 for (dum = 0; dum < addr_info_debug[optable_debug[op].addr_mode].size; dum++)
270 Wr6502 (selected_position + dum, 0xEA);
271
272 }
273 return 0;
274
275 case KEY_F7: /* F7 */
276 // Just in case :
277 if (Bp_list[GIVE_HAND_BP].flag != NOT_USED)
278 {
279 _Wr6502 (Bp_list[GIVE_HAND_BP].position,
280 Bp_list[GIVE_HAND_BP].original_op);
281 Bp_list[GIVE_HAND_BP].flag = NOT_USED;
282 }
283
284 running_mode = TRACING;
285 #ifndef KERNEL_DS
286 set_bp_following (_PC_, GIVE_HAND_BP);
287 #else
288 set_bp_following (reg_pc, GIVE_HAND_BP);
289 #endif
290
291 save_background = 0;
292
293 return 1;
294
295 case KEY_F8: /* F8 */
296 // Just in case :
297 if (Bp_list[GIVE_HAND_BP].flag != NOT_USED)
298 {
299 _Wr6502 (Bp_list[GIVE_HAND_BP].position,
300 Bp_list[GIVE_HAND_BP].original_op);
301 Bp_list[GIVE_HAND_BP].flag = NOT_USED;
302 }
303
304 running_mode = STEPPING;
305
306 #ifndef KERNEL_DS
307 set_bp_following (_PC_, GIVE_HAND_BP);
308 #else
309 set_bp_following (reg_pc, GIVE_HAND_BP);
310 #endif
311
312 save_background = 0;
313
314 return 1;
315
316 case KEY_R:
317 edit_ram ();
318 return 0;
319
320 case KEY_Z:
321 view_zp ();
322 return 0;
323
324 case KEY_I:
325 view_info ();
326 return 0;
327
328 case KEY_G:
329
330 {
331 char *tmp_buf = (char *) alloca (20);
332 UChar index = 0;
333
334 while (osd_keypressed ())
335 osd_readkey ();
336
337 while ((index < 20)
338 && (tmp_buf[index++] = osd_readkey () & 0xFF) != 13);
339
340 tmp_buf[index - 1] = 0;
341
342 init_pos = cvtnum (tmp_buf);
343
344 }
345 return 0;
346
347 case KEY_ASTERISK: /* dirty trick to avoid dis from going immediately */
348 running_mode = PLAIN_RUN;
349 return (!key_delay);
350
351 case KEY_ESC:
352 case KEY_F12:
353 running_mode = PLAIN_RUN;
354 return 1;
355 }
356
357 #endif
358
359 return 0;
360 }
361
362 /*****************************************************************************
363
364 Function: disassemble
365
366 Description: errr... , disassemble at current PC
367 Parameters: none
368 Return: 0 for now
369
370 *****************************************************************************/
371 int
disassemble()372 disassemble ()
373 {
374
375 #ifdef ALLEGRO
376
377 char linebuf[256];
378 UChar op;
379 int i, size;
380 char line;
381 UInt16 position;
382 char bp_actived, bp_disabled;
383 char *tmp_buf = (char *) alloca (100);
384
385 save_background = 1;
386 #ifndef KERNEL_DS
387 selected_position = init_pos = _PC_;
388 #else
389 selected_position = init_pos = reg_pc;
390 #endif
391 key_delay = 10;
392
393 do
394 {
395 position = init_pos;
396 line = 0;
397
398 clear (screen);
399
400 while (line < NB_LINE)
401 {
402
403 bp_actived = 0;
404 bp_disabled = 0;
405
406 op = Op6502 (position);
407 if ((op & 0xF) == 0xB)
408 { // It's a breakpoint, we replace it and set the bp_* variable
409 if (Bp_list[op >> 4].flag == ENABLED)
410 bp_actived = 1;
411 else if (Bp_list[op >> 4].flag == DISABLED)
412 bp_disabled = 1;
413 else
414 break;
415 op = Bp_list[op >> 4].original_op;
416 }
417
418
419 size = addr_info_debug[optable_debug[op].addr_mode].size;
420
421 //if (size+position>0xFFFF)
422 // size=0xFFFF-position;
423 // Make parsing wraps at the end of the memory
424
425
426 opbuf[0] = op;
427 position++;
428 for (i = 1; i < size; i++)
429 opbuf[i] = Op6502 (position++);
430
431 /* This line is the real 'meat' of the disassembler: */
432
433 (*addr_info_debug[optable_debug[op].addr_mode].func) /* function */
434 (linebuf, position - size, opbuf, optable_debug[op].opname); /* parm's passed */
435 // now, what we got to display is in linebuf
436
437 if (bp_actived)
438 rectfill (screen, blit_x, blit_y + 10 * line - 1, blit_x + WIDTH,
439 blit_y + 10 * (line + 1) - 3, 25);
440 else if (bp_disabled)
441 rectfill (screen, blit_x, blit_y + 10 * line - 1, blit_x + WIDTH,
442 blit_y + 10 * (line + 1) - 3, 26);
443
444 sprintf (tmp_buf, "%04X", position - size);
445 if (position - size == selected_position)
446 {
447 textoutshadow (screen, font, tmp_buf, blit_x,
448 blit_y + 10 * line, -15, 2, 1, 1);
449 textoutshadow (screen, font, linebuf, blit_x + 5 * 8,
450 blit_y + 10 * line, -10, 2, 1, 1);
451 }
452 #ifndef KERNEL_DS
453 else if (position - size != _PC_)
454 #else
455 else if (position - size != reg_pc)
456 #endif
457 {
458 textoutshadow (screen, font, tmp_buf, blit_x,
459 blit_y + 10 * line, -5, 0, 1, 1);
460 textoutshadow (screen, font, linebuf, blit_x + 5 * 8,
461 blit_y + 10 * line, -1, 0, 1, 1);
462 }
463 else
464 {
465 textoutshadow (screen, font, tmp_buf, blit_x,
466 blit_y + 10 * line, 3, 2, 1, 1);
467 textoutshadow (screen, font, linebuf, blit_x + 5 * 8,
468 blit_y + 10 * line, 3, 2, 1, 1);
469 }
470
471 // fprintf(stderr, "%s\n", linebuf);
472
473 line++;
474
475 } /* End of while read loop */
476 }
477 while (!dis_key ());
478
479 #endif
480
481 return (0); /* return value to appease compiler */
482 }
483