2 Copyright (c) 1999 by William A. Gatliff
3 All rights reserved. bgat@open-widgets.com
5 See the file COPYING for details.
7 This file is provided "as-is", and without any express
8 or implied warranties, including, without limitation,
9 the implied warranties of merchantability and fitness
10 for a particular purpose.
12 The author welcomes feedback regarding this file.
14 Mostly rewritten from sh2-704x.c by Petr Ledvina,
15 ledvinap@kae.zcu.cz, 2001/10
17 BTW: Can't imagine houw could sh2 stub work ...
18 It would be probably good idea to compare it with this file
23 /* $Id: h8s-2633.c,v 1.5 2001/11/05 06:10:08 ledvinap Exp $ */
25 #include "h8s-2633-defs.h"
26 #include "common_def.h"
27 #include "h8s-2633-rmap.h"
29 #include "h8s-2633-sci.h"
32 /* trapa #3, the code is <5><3><trapno><0> */
33 #define STEP_OPCODE 0x5730
35 /* TODO 8bit ccr and exr */
45 } gdb_register_file_T;
47 gdb_register_file_T gdb_register_file
48 /*__attribute__((section(".regfile")))*/;
51 /* stack for gdb, switch to this stack on start */
52 /* stack must containg RX and TX buffers */
53 #define GDB_STACK_SIZE 1024
54 unsigned short gdb_stack[GDB_STACK_SIZE] /*__attribute__ ((section (".stack")))*/;
55 /* flag that we are in gdb stub, ignore exceptions (bit 7, for TAS)*/
56 unsigned char gdb_in_gdb=0x80;
59 Retrieves a register value from gdb_register_file.
60 Returns the size of the register, in bytes,
61 or zero if an invalid id is specified (which *will*
62 happen--- gdb.c uses this functionality to tell
63 how many registers we actually have).
65 short gdb_peek_register_file ( short id, long *val )
67 /* all our registers are longs */
68 short retval = sizeof( long );
73 case 0: case 1: case 2: case 3:
74 case 4: case 5: case 6: case 7:
75 *val = gdb_register_file.r[id];
79 *val = gdb_register_file.ccr;
82 *val = gdb_register_file.pc;
85 *val = gdb_register_file.exr;
89 *val = gdb_register_file.mach;
92 *val = gdb_register_file.macl;
102 Stuffs a register value into gdb_register_file.
103 Returns the size of the register, in bytes,
104 or zero if an invalid id is specified.
106 short gdb_poke_register_file ( short id, long val )
108 /* all our registers are longs */
109 short retval = sizeof( long );
114 case 0: case 1: case 2: case 3:
115 case 4: case 5: case 6: case 7:
116 gdb_register_file.r[id] = val;
120 gdb_register_file.ccr = val;
123 gdb_register_file.pc = val;
125 case 10: /* cycles */
126 gdb_register_file.exr = val;
130 gdb_register_file.mach = val;
133 gdb_register_file.macl = val;
143 table to clasify instruction according to first byte
144 Only first 128 entries, rest is always 4
163 unsigned char const opcode_0_to_length[128] =
168 2, D_LD, 2, 2, 2, 2, 2, 2,
169 2, 2, 2, 2, 2, 2, 2, 2,
171 2, 2, 2, 2, 2, 2, 2, 2,
172 2, 2, 2, 2, 2, 2, 2, 2,
174 2, 2, 2, 2, 2, 2, 2, 2,
175 2, 2, 2, 2, 2, 2, 2, 2,
177 2, 2, 2, 2, 2, 2, 2, 2,
178 2, 2, 2, 2, 2, 2, 2, 2,
180 D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,
181 D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,D_BCC2,
183 2, 2, 2, 2, D_RTS,D_BSR2, D_RTE, 2,
184 D_BCC4,D_JMPR,D_JMPA,D_JMPI,D_BSR4,D_JSRR,D_JSRA,D_JSRI,
186 2, 2, 2, 2, 2, 2, 2, 2,
187 2, 2, D_MV, D_MV, 2, 2, 4, 4,
189 2, 2, 2, 2, 2, 2, 2, 2,
190 8, 4, 6, 4, 4, 4, 4, 4
193 /* test global ccr state, return if given condition is true */
194 int test_bcc(int op) {
195 register char ccr=gdb_register_file.ccr;
203 case 0x2: return !(ccr&(C|Z));
204 case 0x3: return ccr&(C|Z);
205 case 0x4: return !(ccr&C);
206 case 0x5: return ccr&C;
207 case 0x6: return !(ccr&Z);
208 case 0x7: return ccr&Z;
209 case 0x8: return !(ccr&V);
210 case 0x9: return ccr&V;
211 case 0xa: return !(ccr&N);
212 case 0xb: return ccr&N;
213 case 0xc: return (ccr&N)? (ccr&V):!(ccr&V);
214 case 0xd: return (ccr&N)?!(ccr&V):(ccr&V);
215 case 0xe: return !(ccr&Z) && (ccr&N)? (ccr&V):!(ccr&V);
216 case 0xf: return (ccr&Z) || (ccr&N)?!(ccr&V): (ccr&V);
226 Analyzes the next instruction, to see where the program
227 will go to when it runs. Returns the destination address.
229 Maybe some code opcodes may be used to automagicaly
231 (There are some magic opcodes in gdb's opcodes, so don't forget
234 Instruction length is decoded using hardwired tests+table
235 The table contains operation necesary for given prefix
236 Length of non-jump instruction must be computed to gen next instr
238 This code is partialy tested, the table was generated form /opcodes
239 Probably some more intensive testing is neccesary
242 long gdb_get_stepi_dest ( void )
244 unsigned char op = ((unsigned char*)gdb_register_file.pc)[0];
246 long addr = gdb_register_file.pc;
248 /* test if opcode > 0x80 -> 2b */
252 /* fetch length from opcode table, dispatch results */
253 op_t=opcode_0_to_length[op];
255 case D_LD: // prefix 01, ld and similar
256 op=((unsigned char*)gdb_register_file.pc)[1];
260 op=((unsigned char*)gdb_register_file.pc)[2];
262 case 0x6b: return addr+((((unsigned char*)gdb_register_file.pc)[3]&2)?8:6);
263 case 0x6f: return addr+6;
264 case 0x78: return addr+10;
265 default: return addr+4;
271 /* some invalid opcodes here, but ignore it ... */
275 if(test_bcc(op&0x0f))
276 return addr+2+((signed char*)gdb_register_file.pc)[1];
279 if(test_bcc(((unsigned char*)gdb_register_file.pc)[1]>>4))
280 return addr+4+((signed short*)gdb_register_file.pc)[1];
284 return gdb_register_file.r[((unsigned char*)gdb_register_file.pc)[1]>>4];
287 return ((unsigned long*)gdb_register_file.pc)[0]&0x00ffffff;
291 ((unsigned long*)(0))
292 [((unsigned char*)gdb_register_file.pc)[1]]&0x00ffffff;
294 return addr+2+((signed char*)gdb_register_file.pc)[1];
296 return addr+4+((signed short*)gdb_register_file.pc)[1];
298 switch(((unsigned char*)gdb_register_file.pc)[1]>>4) {
301 case 0xa: return addr+6;
302 case 0x3: return addr+8;
303 default: return addr+4;
306 return ((unsigned long*)gdb_register_file.r[7])[0]&0x00ffffff;
309 return ((unsigned long*)(gdb_register_file.r[7]+2))[0]&0x00ffffff;
311 return ((unsigned long*)(gdb_register_file.r[7]+0))[0]&0x00ffffff;
318 /* Write back data caches, and invalidates instruction caches */
319 /* NOTE: only used on SH4 for now */
320 void gdb_flush_cache(void *start UNUSED, void *end UNUSED)
326 Uses a TRAP to generate an exception
327 after we execute the next instruction.
330 short gdb_stepped_opcode=STEP_OPCODE;
331 unsigned long gdb_step_pc;
333 void gdb_step ( char *hargs )
338 /* parse address, if any */
339 while( *hargs != '#' )
340 addr = ( addr << 4 ) + hex_to_long( *hargs++ );
342 /* if we're stepping from an address, adjust pc (untested!) */
343 /* TODO: test gdb_step when PC is supplied */
344 if( addr ) gdb_register_file.pc = addr;
346 /* determine where the target instruction will send us to */
347 addr = gdb_get_stepi_dest();
350 gdb_stepped_opcode = *(short*)addr;
352 *(short*)addr = STEP_OPCODE; /* FIXME: Use HW break if PC is in flash */
354 /* we're all done now */
355 gdb_return_from_exception();
361 pc could be bad when stepping trapa #3 ( gdb breakpoint )
362 or when other exception occurs in stepi
363 so remember address of replaced instruction separately
365 void gdb_undo_step ( void ) /* FIXME: If using HW steps, undo hw steps. */
367 /* quite bad idea to use 0 here, 0 is NOP */
368 /* STEP_OPCODE should be ok */
369 if( gdb_stepped_opcode != STEP_OPCODE) {
370 *(short*)gdb_step_pc = gdb_stepped_opcode;
371 gdb_stepped_opcode = 0;
378 Continue program execution at addr,
379 or at the current pc if addr == 0.
381 void gdb_continue ( char *hargs )
386 /* parse address, if any */
387 while( *hargs != '#' )
388 addr = ( addr << 4 ) + hex_to_long( *hargs++ );
391 gdb_register_file.pc = addr;
393 gdb_return_from_exception();
398 /* breakpoint support
399 If we would like to support hw breakpoints, we needt suport
400 SW breakpoints to. Another solution would be to patch GDB
408 signed char type; /* BP type, -1 when free pos */
409 unsigned short oldval; /* replaced opcode for sw, channel for HW */
410 } breakpoints[MAX_BREAKPOINTS];
412 #if USE_HW_BREAKPOINTS
413 signed char pbc_use[2]; /* breakpoint idx for given channel or -1 */
416 /* function to insert/remove brekpoints */
417 void gdb_breakpoint_1(int on, char* hargs) {
427 /* packet could be Z1,ADDR# or Z?,ADDR,LEN# */
431 while( *hargs != ',' && *hargs!='#')
432 addr = ( addr << 4 ) + hex_to_long( *hargs++ );
436 while( *hargs != '#' )
437 len = ( len << 4 ) + hex_to_long( *hargs++ );
439 /* length for FETCH */
442 /* find breakpoint entry or free space */
444 f_idx=-1; /* free entry */
445 for(i=0;i<MAX_BREAKPOINTS;i++) {
446 if(breakpoints[i].type==type
447 && breakpoints[i].addr==addr
448 && breakpoints[i].len==len) {
452 if(f_idx<0 && breakpoints[i].type<0)
455 if(b_idx>=0) { /* we found existing breakpoint */
456 if(on) { /* already inserted */
458 } else { /* remove breakpoint */
459 if(type==0) { /* remove sw breakpoint */
460 *(unsigned short*)(addr)=breakpoints[b_idx].oldval;
461 } else { /* remove HW breakpoint/watchpoint */
462 #if USE_HW_BREAKPOINTS
463 /* just disable interrupt for given register */
464 PBC_BCRX(breakpoints[b_idx].oldval)&=~BIT(0);
465 /* and mark it free */
466 pbc_use[breakpoints[b_idx].oldval]=-1;
472 breakpoints[b_idx].type=-1;
474 } else { /* breakpoint not found */
475 if(on) { /* insert new breakpoint */
476 if(f_idx<0) { /* we run out of breakpoints */
480 breakpoints[f_idx].type=type;
481 breakpoints[f_idx].addr=addr;
482 breakpoints[f_idx].len=len;
483 if(type==0) { /* insert software breakpoint */
484 breakpoints[f_idx].oldval=*(unsigned short*)(addr);
485 *(unsigned short*)(addr)=STEP_OPCODE;
486 } else { /* insert HW breakpoint */
487 #if USE_HW_BREAKPOINTS
488 /* find free channel */
489 if(pbc_use[0]<0) i=0; /* FIXME: Add support for HW stepping. */
490 else if(pbc_use[1]<0) i=1;
492 /* no channel free */
496 /* build control byte */
497 val=BIT(0); /* enabled (FIXME this could be problem for watchpoints
498 Better enable them just before leaving into code */
500 if (len<=1<<0) val|=0<<3; /* nop */
501 else if((addr&0x0001)+len<=1<<1) val|=1<<3;
502 else if((addr&0x0003)+len<=1<<2) val|=2<<3;
503 else if((addr&0x0007)+len<=1<<3) val|=3<<3;
504 else if((addr&0x000f)+len<=1<<4) val|=4<<3;
505 else if((addr&0x00ff)+len<=1<<8) val|=5<<3;
506 else if((addr&0x0fff)+len<=1<<12) val|=6<<3;
507 else if((addr&0xffff)+len<=1L<<16) val|=7<<3;
509 /* cant insert this watchpoint */
515 case 1: val|=0<<1; break;
516 case 2: val|=2<<1; break;
517 case 3: val|=1<<1; break;
518 case 4: val|=3<<1; break;
523 (volatile void)PBC_BCRX(i); /* read hit flag to clear it in next instruction */
526 breakpoints[f_idx].oldval=i;
533 } else { /* gdb is trying to delete nonexisting breakpoint */
538 gdb_putmsg(0, "OK", 2);
541 tx_buf[0]=lnibble_to_hex(err>>4);
542 tx_buf[1]=lnibble_to_hex(err&0xff);
543 gdb_putmsg('E',tx_buf, 2);
546 void gdb_insert_breakpoint( char *hargs ) {
547 gdb_breakpoint_1(1, hargs);
550 void gdb_remove_breakpoint( char *hargs ) {
551 gdb_breakpoint_1(0, hargs);
554 /* initialize breakpoints table */
556 void gdb_breakpoint_init(void) {
558 for(i=0;i<MAX_BREAKPOINTS;i++) {
559 breakpoints[i].type=-1;
561 #if USE_HW_BREAKPOINTS
562 MSTPCRC&=~BIT(4); /* enable PBC */
570 #endif /* USE_BREAKPOINTS */
572 Kills the current application.
573 Simulates a reset by jumping to
574 the address taken from the reset
577 void gdb_kill ( void )
579 /* return control to monitor */
580 /* skip this for now, HDI hates this ;-) */
581 /* asm( "jmp @@0"); */
584 #if defined(HW_INDEPENDENT)&&HW_INDEPENDENT
586 #include "system_def.h"
587 /* #include "h8s2638h.h" */
589 /* extern void *excptvec_get(int vectnum); */
590 /* extern void *excptvec_set(int vectnum,void *vect); */
591 /* extern int excptvec_initfill(void *fill_vect, int force_all); */
592 #endif /* HW_INDEPENDENT */
594 /* initialize this target */
595 void gdb_platform_init() {
596 #if defined(HW_INDEPENDENT)&&HW_INDEPENDENT
597 static const int sci_vect_tab[]=
598 {EXCPTVEC_ERI0,EXCPTVEC_ERI1,EXCPTVEC_ERI2};
599 int sci_vect=sci_vect_tab[GDB_SCI_PORT];
601 excptvec_initfill(gdb_unhandled_isr,0);
603 excptvec_set(sci_vect,gdb_scirxerr_isr); /* ERIx */
604 excptvec_set(sci_vect+1,gdb_scirx_isr); /* RXIx */
605 excptvec_set(sci_vect+2,gdb_unhandled_isr); /* TXIx */
606 excptvec_set(sci_vect+3,gdb_unhandled_isr); /* TEIx */
608 excptvec_set(EXCPTVEC_NMI,gdb_nmi_isr); /* NMI */
609 excptvec_set(EXCPTVEC_TRAP2,gdb_trapa2_isr); /* TRAPA2 */
610 excptvec_set(EXCPTVEC_TRAP3,gdb_trapa3_isr); /* TRAPA3 */
611 excptvec_set(EXCPTVEC_PBC,gdb_pbc_isr); /* PCB */
614 #endif /* HW_INDEPENDENT */
616 gdb_sci_init(SCI_BAUD(GDB_SCI_SPEED), SCI_8N1);
618 gdb_breakpoint_init();
623 /* initialize this target */
624 int gdb_platform_enable(int en) {
625 int olden=!gdb_in_gdb;
635 /* assembly function moved into separate file */