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