]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/h8300/arch/v2_0/src/h8300_stub.c
Initial revision
[karo-tx-redboot.git] / packages / hal / h8300 / arch / v2_0 / src / h8300_stub.c
1 //========================================================================
2 //
3 //      h8300_stub.c
4 //
5 //      Helper functions for H8/300H stub
6 //
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):     Red Hat, jskov
44 // Contributors:  Red Hat, jskov
45 // Date:          1998-11-06
46 // Purpose:       
47 // Description:   Helper functions for H8/300H stub
48 // Usage:         
49 //
50 //####DESCRIPTIONEND####
51 //
52 //========================================================================
53
54 #include <stddef.h>
55
56 #include <pkgconf/hal.h>
57
58 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
59
60 #include <cyg/hal/hal_stub.h>
61 #include <cyg/hal/hal_arch.h>
62 #include <cyg/hal/hal_intr.h>
63
64 #ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
65 #include <cyg/hal/dbg-threads-api.h>    // dbg_currthread_id
66 #endif
67
68 /*----------------------------------------------------------------------
69  * Asynchronous interrupt support
70  */
71
72 typedef unsigned short t_inst;
73
74 static struct
75 {
76   t_inst *targetAddr;
77   t_inst savedInstr;
78 } asyncBuffer;
79
80 /* Called to asynchronously interrupt a running program.
81    Must be passed address of instruction interrupted.
82    This is typically called in response to a debug port
83    receive interrupt.
84 */
85
86 void
87 install_async_breakpoint(void *pc)
88 {
89   asyncBuffer.targetAddr = pc;
90   asyncBuffer.savedInstr = *(t_inst *)pc;
91   *(t_inst *)pc = (t_inst)HAL_BREAKINST;
92   __instruction_cache(CACHE_FLUSH);
93   __data_cache(CACHE_FLUSH);
94 }
95
96 /*--------------------------------------------------------------------*/
97 /* Given a trap value TRAP, return the corresponding signal. */
98
99 int __computeSignal (unsigned int trap_number)
100 {
101     switch (trap_number) {
102     case 11:
103         return SIGTRAP;
104     default:
105         return SIGINT;
106     }
107 }
108
109 /*--------------------------------------------------------------------*/
110 /* Return the trap number corresponding to the last-taken trap. */
111
112 int __get_trap_number (void)
113 {
114     extern int CYG_LABEL_NAME(_intvector);
115     // The vector is not not part of the GDB register set so get it
116     // directly from the save context.
117     return CYG_LABEL_NAME(_intvector);
118 }
119
120 /*--------------------------------------------------------------------*/
121 /* Set the currently-saved pc register value to PC. This also updates NPC
122    as needed. */
123
124 void set_pc (target_register_t pc)
125 {
126     put_register (PC, pc);
127 }
128
129
130 /*----------------------------------------------------------------------
131  * Single-step support. Lifted from CygMon.
132  */
133
134 #define NUM_SS_BPTS 2
135 static target_register_t break_mem [NUM_SS_BPTS] = {0, 0};
136 static unsigned char break_mem_data [NUM_SS_BPTS];
137
138 /* Set a single-step breakpoint at ADDR.  Up to two such breakpoints
139    can be set; WHICH specifies which one to set (0 or 1).  */
140
141 static void
142 set_single_bp (int which, unsigned char *addr)
143 {
144     if (break_mem[which] == 0) {
145         break_mem[which] = (target_register_t) addr;
146         break_mem_data[which] = *(unsigned short *)addr;
147         *(unsigned short *)addr = HAL_BREAKINST;
148     }
149 }
150
151 /* Clear any single-step breakpoint(s) that may have been set.  */
152
153 void __clear_single_step (void)
154 {
155   int x;
156   for (x = 0; x < NUM_SS_BPTS; x++)
157     {
158         unsigned char* addr = (unsigned char*) break_mem[x];
159         if (addr) {
160             *addr = break_mem_data[x];
161             break_mem[x] = 0;
162         }
163     }
164 }
165
166 /* Set breakpoint(s) to simulate a single step from the current PC.  */
167
168 const static unsigned char opcode_length0[]={
169   0x04,0x02,0x04,0x02,0x04,0x02,0x04,0x02,  /* 0x58 */
170   0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,  /* 0x60 */
171   0x02,0x02,0x11,0x11,0x02,0x02,0x04,0x04,  /* 0x68 */
172   0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,  /* 0x70 */
173   0x08,0x04,0x06,0x04,0x04,0x04,0x04,0x04   /* 0x78 */
174 };
175
176 const static unsigned char opcode_length1[]={
177   0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
178   0x02,0x00,0x00,0x00,0x04,0x04,0x00,0x04
179 };
180
181 static int insn_length(unsigned char *pc)
182 {
183   if (*pc != 0x01 && (*pc < 0x58 || *pc>=0x80)) 
184     return 2;
185   else
186     switch (*pc) {
187       case 0x01:
188         switch (*(pc+1) & 0xf0) {
189         case 0x00:
190           if (*(pc+2)== 0x78) {
191             return 10;
192           } else if (*(pc+2)== 0x6b) {
193             return (*(pc+3) & 0x20)?8:6;
194           } else {
195             return (*(pc+2) & 0x02)?6:4;
196           }
197         case 0x40:
198           return (*(pc+2) & 0x02)?8:6;
199         default:
200           return opcode_length1[*(pc+1)>>4];
201         }
202       case 0x6a:
203       case 0x6b:
204         return (*(pc+1) & 0x20)?6:4;
205       default:
206         return opcode_length0[*pc-0x58];
207     }
208 }
209
210 void __single_step (void)
211 {
212   unsigned int pc = get_register (PC);
213   unsigned int next;
214   unsigned int opcode;
215
216   opcode = *(unsigned short *)pc;
217   next = pc + insn_length((unsigned char *)pc);
218   if (opcode == 0x5470) {
219     /* rts */ 
220     unsigned long *sp;
221     sp = (unsigned long *)get_register(SP);
222     next = *sp & 0x00ffffff;
223   } else if ((opcode & 0xfb00) != 0x5800) {
224     /* jmp / jsr */
225     int regs;
226     const short reg_tbl[]={ER0,ER1,ER2,ER3,ER4,ER5,ER6,SP};
227     switch(opcode & 0xfb00) {
228     case 0x5900:
229       regs = (opcode & 0x0070) >> 8;
230       next = get_register(reg_tbl[regs]);
231       break;
232     case 0x5a00:
233       next = *(unsigned long *)(pc+2) & 0x00ffffff;
234       break;
235     case 0x5b00:
236       next = *(unsigned long *)(opcode & 0xff);
237       break;
238     }
239   } else if (((opcode & 0xf000) == 0x4000) || ((opcode & 0xff00) == 0x5500)) { 
240     /* b**:8 */
241     unsigned long dsp;
242     dsp = (long)(opcode && 0xff)+pc+2;
243     set_single_bp(1,(unsigned char *)dsp);
244   } else if (((opcode & 0xff00) == 0x5800) || ((opcode & 0xff00) == 0x5c00)) { 
245     /* b**:16 */
246     unsigned long dsp;
247     dsp = *(unsigned short *)(pc+2)+pc+4;
248     set_single_bp(1,(unsigned char *)dsp);
249   }
250   set_single_bp(0,(unsigned char *)next);
251 }
252
253 void __install_breakpoints (void)
254 {
255     /* NOP since single-step HW exceptions are used instead of
256        breakpoints. */
257 }
258
259 void __clear_breakpoints (void)
260 {
261
262 }
263
264
265 /* If the breakpoint we hit is in the breakpoint() instruction, return a
266    non-zero value. */
267
268 externC void CYG_LABEL_NAME(breakinst)(void);
269 int
270 __is_breakpoint_function ()
271 {
272     return get_register (PC) == (target_register_t)&CYG_LABEL_NAME(breakinst);
273 }
274
275
276 /* Skip the current instruction. */
277
278 void __skipinst (void)
279 {
280     unsigned long pc = get_register (PC);
281
282     pc+=insn_length((unsigned char *)pc);
283     put_register (PC, (target_register_t) pc);
284 }
285
286 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS