]> rtime.felk.cvut.cz Git - sysless.git/blob - arch/h8300/generic/libs/gdbstub/h8s-2633.c
983866f725342fd545a5d63c0e8ef4e2a3ea1b80
[sysless.git] / arch / h8300 / generic / libs / gdbstub / h8s-2633.c
1 /*
2   Copyright (c) 1999 by      William A. Gatliff
3   All rights reserved.     bgat@open-widgets.com
4
5   See the file COPYING for details.
6
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.
11
12   The author welcomes feedback regarding this file.
13
14   Mostly rewritten from sh2-704x.c by Petr Ledvina, 
15   ledvinap@kae.zcu.cz, 2001/10
16   
17   BTW: Can't imagine houw could sh2 stub work ... 
18     It would be probably good idea to compare it with this file
19     and fix bugs
20   
21 */
22
23 /* $Id: h8s-2633.c,v 1.5 2001/11/05 06:10:08 ledvinap Exp $ */
24
25 #include "h8s-2633-defs.h"
26 #include "common_def.h"
27 #include "h8s-2633-rmap.h"
28 #include "gdb-stub.h"
29 #include "h8s-2633-sci.h"
30 #include "h8s-2633.h"
31
32 /* trapa #3, the code is <5><3><trapno><0> */
33 #define STEP_OPCODE 0x5730
34
35 /* TODO 8bit ccr and exr */
36 typedef struct {
37   unsigned long  r[8];
38   unsigned long  pc;
39   unsigned long  ccr;
40   unsigned long  exr;
41 #if USE_MAC
42   unsigned long  mach;
43   unsigned long  macl;
44 #endif
45 } gdb_register_file_T;
46
47 gdb_register_file_T gdb_register_file
48 /*__attribute__((section(".regfile")))*/;
49
50
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;  
57
58 /*
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).
64 */
65 short gdb_peek_register_file ( short id, long *val )
66 {
67   /* all our registers are longs */
68   short retval = sizeof( long );
69
70
71   switch( id ) {
72
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];
76     break;
77
78   case 8:
79     *val = gdb_register_file.ccr;
80     break;
81   case 9:
82     *val = gdb_register_file.pc;
83     break;
84   case 10:
85     *val = gdb_register_file.exr;
86     break;
87 #if USE_MAC
88   case 11:
89     *val = gdb_register_file.mach;
90     break;
91   case 12:
92     *val = gdb_register_file.macl;
93     break;
94 #endif
95   default:
96     retval = 0;
97   }
98   return retval;
99 }
100
101 /*
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.
105  */
106 short gdb_poke_register_file ( short id, long val )
107 {
108   /* all our registers are longs */
109   short retval = sizeof( long );
110
111
112   switch( id ) {
113
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;
117     break;
118
119   case 8:   /* ccr */
120     gdb_register_file.ccr = val;
121     break;
122   case 9:   /* pc */
123     gdb_register_file.pc = val;
124     break;
125   case 10:  /* cycles */
126     gdb_register_file.exr = val;
127     break;
128 #if USE_MAC
129   case 11:
130     gdb_register_file.mach = val;
131     break;
132   case 12:
133     gdb_register_file.macl = val;
134     break;
135 #endif
136   default:
137     retval = 0;
138   }
139   return retval;
140 }
141
142 /* 
143    table to clasify instruction according to first byte 
144    Only first 128 entries, rest is always 4 
145 */
146
147 #define D_FIRST 11
148 #define D_LD   11
149 #define D_BCC2 12 
150 #define D_BCC4 13
151 #define D_JMPR 14
152 #define D_JMPA 15
153 #define D_JMPI 16
154 #define D_BSR2 17
155 #define D_BSR4 18
156 #define D_JSRR 19
157 #define D_JSRA 20
158 #define D_JSRI 21
159 #define D_MV   22
160 #define D_RTS  23
161 #define D_RTE  24
162
163 unsigned char const opcode_0_to_length[128] = 
164     { 
165 /*       0      1      2      3      4      5      6      7  
166          8      9      a      b      c      d      e      f */
167 /* 0x */
168          2,  D_LD,     2,     2,     2,     2,     2,     2,   
169          2,     2,     2,     2,     2,     2,     2,     2, 
170 /* 1x */
171          2,     2,     2,     2,     2,     2,     2,     2,   
172          2,     2,     2,     2,     2,     2,     2,     2, 
173 /* 2x */
174          2,     2,     2,     2,     2,     2,     2,     2,   
175          2,     2,     2,     2,     2,     2,     2,     2, 
176 /* 3x */
177          2,     2,     2,     2,     2,     2,     2,     2,   
178          2,     2,     2,     2,     2,     2,     2,     2, 
179 /* 4x */
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, 
182 /* 5x */
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, 
185 /* 6x */
186          2,     2,     2,     2,     2,     2,     2,     2,   
187          2,     2,  D_MV,  D_MV,     2,     2,     4,     4, 
188 /* 7x */
189          2,     2,     2,     2,     2,     2,     2,     2,  
190          8,     4,     6,     4,     4,     4,     4,     4 
191     };  
192
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;
196 #define C 0x01
197 #define V 0x02
198 #define Z 0x04
199 #define N 0x08
200   switch(op) {
201   case 0x0: return 1;
202   case 0x1: return 0;
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);
217   }
218 #undef C
219 #undef V
220 #undef N
221 #undef Z
222   return 0;
223 }
224
225 /*
226   Analyzes the next instruction, to see where the program
227   will go to when it runs.  Returns the destination address.
228   
229   Maybe some code opcodes may be used to automagicaly
230   generate this ... 
231   (There are some magic opcodes in gdb's opcodes, so don't forget
232     to filter them )
233
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
237   
238   This code is partialy tested, the table was generated form /opcodes
239   Probably some more intensive testing is neccesary
240 */
241
242 long gdb_get_stepi_dest ( void )
243 {
244   unsigned char op = ((unsigned char*)gdb_register_file.pc)[0];
245   unsigned char op_t;
246   long addr = gdb_register_file.pc;
247   
248   /* test if opcode > 0x80 -> 2b */ 
249   if(op>=0x80) 
250     return addr+2;
251   
252   /* fetch length from opcode table, dispatch results */
253   op_t=opcode_0_to_length[op];
254   switch(op_t) {
255   case D_LD:   // prefix 01, ld and similar
256     op=((unsigned char*)gdb_register_file.pc)[1];
257     switch(op>>4) {
258     case 0x0:
259     case 0x4:
260       op=((unsigned char*)gdb_register_file.pc)[2];
261       switch(op) {
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;  
266       }
267     case 0x8:
268     case 0xa:
269       return addr+2;
270     default:
271       /* some invalid opcodes here, but ignore it ... */
272       return addr+4;
273     }
274   case D_BCC2:
275     if(test_bcc(op&0x0f))
276       return addr+2+((signed char*)gdb_register_file.pc)[1];
277     else return addr+2;
278   case D_BCC4:
279     if(test_bcc(((unsigned char*)gdb_register_file.pc)[1]>>4))
280       return addr+4+((signed short*)gdb_register_file.pc)[1];
281     else return addr+4;
282   case D_JMPR:
283   case D_JSRR:
284     return gdb_register_file.r[((unsigned char*)gdb_register_file.pc)[1]>>4];
285   case D_JMPA:
286   case D_JSRA:
287     return ((unsigned long*)gdb_register_file.pc)[0]&0x00ffffff;
288   case D_JMPI:
289   case D_JSRI:
290     return 
291       ((unsigned long*)(0))
292       [((unsigned char*)gdb_register_file.pc)[1]]&0x00ffffff;
293   case D_BSR2:
294     return addr+2+((signed char*)gdb_register_file.pc)[1];
295   case D_BSR4:
296     return addr+4+((signed short*)gdb_register_file.pc)[1];
297   case D_MV:
298     switch(((unsigned char*)gdb_register_file.pc)[1]>>4) {
299     case 0x1:
300     case 0x2: 
301     case 0xa: return addr+6;
302     case 0x3: return addr+8;
303     default:  return addr+4;
304     }
305   case D_RTS:
306     return ((unsigned long*)gdb_register_file.r[7])[0]&0x00ffffff;
307   case D_RTE:
308 #if USE_EXR
309     return ((unsigned long*)(gdb_register_file.r[7]+2))[0]&0x00ffffff;
310 #else
311     return ((unsigned long*)(gdb_register_file.r[7]+0))[0]&0x00ffffff;
312 #endif
313   default:
314     return addr+op_t;
315   }
316 }
317
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)
321 {
322 }
323
324
325 /*
326   Uses a TRAP to generate an exception
327   after we execute the next instruction.
328 */
329
330 short gdb_stepped_opcode=STEP_OPCODE;
331 unsigned long  gdb_step_pc;
332
333 void gdb_step ( char *hargs )
334 {
335   long addr = 0;
336
337
338   /* parse address, if any */
339   while( *hargs != '#' )
340     addr = ( addr << 4 ) + hex_to_long( *hargs++ );
341
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;
345
346   /* determine where the target instruction will send us to */
347   addr = gdb_get_stepi_dest();
348
349   /* replace it */
350   gdb_stepped_opcode = *(short*)addr;
351   gdb_step_pc = addr;
352   *(short*)addr = STEP_OPCODE;  /* FIXME: Use HW break if PC is in flash */
353   
354   /* we're all done now */
355   gdb_return_from_exception();
356
357   return;
358 }
359
360 /* 
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
364 */
365 void gdb_undo_step ( void )     /* FIXME: If using HW steps, undo hw steps. */
366 {
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;
372   }
373   return;
374 }
375
376
377 /*
378   Continue program execution at addr,
379   or at the current pc if addr == 0.
380 */
381 void gdb_continue ( char *hargs )
382 {
383   long addr = 0;
384
385
386   /* parse address, if any */
387   while( *hargs != '#' )
388     addr = ( addr << 4 ) + hex_to_long( *hargs++ );
389
390   if( addr )
391     gdb_register_file.pc = addr;
392
393   gdb_return_from_exception();
394
395   return;
396 }
397
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
401 */
402
403 #if USE_BREAKPOINTS
404
405 struct breakpoint {
406   long addr;
407   unsigned char len;
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];
411
412 #if USE_HW_BREAKPOINTS
413 signed char pbc_use[2];     /* breakpoint idx for given channel or -1 */
414 #endif
415
416 /* function to insert/remove brekpoints */
417 void gdb_breakpoint_1(int on, char* hargs) {
418   char type;
419   long addr=0;
420   short len=0;
421   short b_idx, f_idx;
422   short i;
423   unsigned char err;
424   char tx_buf[2];
425   unsigned char val;
426
427   /* packet could be Z1,ADDR# or Z?,ADDR,LEN# */
428   type=(*hargs++)-'0';
429   /* skip , */
430   hargs++;
431   while( *hargs != ',' && *hargs!='#')
432     addr = ( addr << 4 ) + hex_to_long( *hargs++ );
433   if(*hargs==',') { 
434     /* skip , */
435     hargs++;
436     while( *hargs != '#' )
437       len = ( len << 4 ) + hex_to_long( *hargs++ );
438   } else {
439     /* length for FETCH */
440     len=2;
441   }
442   /* find breakpoint entry or free space */
443   b_idx=-1; 
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) {
449       b_idx=i;
450       break;
451     }
452     if(f_idx<0 && breakpoints[i].type<0)
453       f_idx=i;
454   }
455   if(b_idx>=0) {  /* we found existing breakpoint */
456     if(on) {  /* already inserted */
457       ; // no op
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;
467 #else
468         err=1;
469         goto ret_err;
470 #endif
471       }
472       breakpoints[b_idx].type=-1;
473     }
474   } else {  /* breakpoint not found */
475     if(on) { /* insert new breakpoint */
476       if(f_idx<0) { /* we run out of breakpoints */
477         err=2;
478         goto ret_err;
479       }
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;
491         else {
492           /* no channel free */
493           err=4;
494           goto ret_err;  
495         }
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 */
499         /* add size bits */
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;
508         else { 
509           /* cant insert this watchpoint */
510           err=5;
511           goto ret_err;
512         }
513         /* add type bits */
514         switch(type) {
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;
519         default:
520           err=5;
521           goto ret_err;
522         }
523         (volatile void)PBC_BCRX(i);   /* read hit flag to clear it in next instruction */
524         PBC_BCRX(i)=val;
525         PBC_BARX(i)=addr;
526         breakpoints[f_idx].oldval=i;
527         pbc_use[i]=f_idx;
528 #else
529         err=2;
530         goto ret_err;
531 #endif
532       }
533     } else {  /* gdb is trying to delete nonexisting breakpoint */
534       err=3;
535       goto ret_err;
536     }
537   }
538   gdb_putmsg(0, "OK", 2);
539   return;
540  ret_err:
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);
544 }
545
546 void gdb_insert_breakpoint( char *hargs ) {
547   gdb_breakpoint_1(1, hargs);
548 }
549
550 void gdb_remove_breakpoint( char *hargs ) {
551   gdb_breakpoint_1(0, hargs);
552 }
553
554 /* initialize breakpoints table */
555 /* wake PBC */
556 void gdb_breakpoint_init(void) {
557   short i;
558   for(i=0;i<MAX_BREAKPOINTS;i++) {
559     breakpoints[i].type=-1;
560   }
561 #if USE_HW_BREAKPOINTS
562   MSTPCRC&=~BIT(4);     /* enable PBC */
563   pbc_use[0]=-1;
564   pbc_use[1]=-1;
565   PBC_BCRA=0;
566   PBC_BCRB=0;
567 #endif
568 }
569
570 #endif /* USE_BREAKPOINTS */
571 /*
572   Kills the current application.
573   Simulates a reset by jumping to
574   the address taken from the reset
575   vector at address 0.
576  */
577 void gdb_kill ( void )
578 {
579   /* return control to monitor */
580   /* skip this for now, HDI hates this ;-) */
581   /* asm( "jmp @@0"); */
582 }
583
584 #if defined(HW_INDEPENDENT)&&HW_INDEPENDENT
585 #include "cpu_def.h"
586 #include "system_def.h"
587 #include "h8s2633h.h"
588
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 */
593
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,EXCPTVEC_ERI3,EXCPTVEC_ERI4};
599   int sci_vect=sci_vect_tab[GDB_SCI_PORT];
600   
601   excptvec_initfill(gdb_unhandled_isr,0);
602
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 */
607
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 */
612   
613   
614 #endif /* HW_INDEPENDENT */
615
616   gdb_sci_init(SCI_BAUD(GDB_SCI_SPEED), SCI_8N1);
617 #if USE_BREAKPOINTS
618   gdb_breakpoint_init();
619 #endif
620
621 }
622
623 /* initialize this target */
624 int gdb_platform_enable(int en) {
625   int olden=!gdb_in_gdb;
626   if(en) {
627     SCI_SCR|=1<<6;
628     gdb_in_gdb=0;
629   }else{
630     gdb_in_gdb=0x80;
631   }
632   return olden;
633 }
634
635 /* assembly function moved into separate file */
636