1 //========================================================================
5 // Helper functions for stub, generic to all MIPS processors
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.
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.
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
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.
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.
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.
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####
43 // Author(s): Red Hat, nickg
44 // Contributors: Red Hat, nickg
47 // Description: Helper functions for stub, generic to all MIPS processors
50 //####DESCRIPTIONEND####
52 //========================================================================
56 #include <pkgconf/hal.h>
59 #include <pkgconf/redboot.h>
62 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
64 #include <cyg/hal/hal_stub.h>
66 #define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS
67 #include <cyg/hal/mips-regs.h>
69 #include <cyg/hal/hal_arch.h>
70 #include <cyg/hal/hal_intr.h>
71 #include <cyg/hal/mips_opcode.h>
73 typedef unsigned long t_inst;
75 /*----------------------------------------------------------------------
76 * Asynchronous interrupt support
85 /* Called to asynchronously interrupt a running program.
86 Must be passed address of instruction interrupted.
87 This is typically called in response to a debug port
92 install_async_breakpoint(void *epc)
96 /* This may be called from a separately linked program,
97 so we need to save and restore the incoming gp register
98 and setup our stub local gp register.
99 Alternatively, we could skip this foolishness if we
100 compiled libstub with "-G 0". */
102 __asm__ volatile ( "move %0,$28\n"
107 asyncBuffer.targetAddr = epc;
108 asyncBuffer.savedInstr = *(t_inst *)epc;
109 *(t_inst *)epc = *(t_inst *)_breakinst;
110 __instruction_cache(CACHE_FLUSH);
111 __data_cache(CACHE_FLUSH);
113 __asm__ volatile ( "move $28,%0\n" :: "r"(gp_save) );
116 /*--------------------------------------------------------------------*/
117 /* Given a trap value TRAP, return the corresponding signal. */
119 int __computeSignal (unsigned int trap_number)
124 /* External interrupt */
128 /* Reserved instruction */
130 /* Coprocessor unusable */
135 if (asyncBuffer.targetAddr != NULL)
137 /* BP installed by serial driver to stop running program */
138 *asyncBuffer.targetAddr = asyncBuffer.savedInstr;
139 __instruction_cache(CACHE_FLUSH);
140 __data_cache(CACHE_FLUSH);
141 asyncBuffer.targetAddr = NULL;
147 /* Arithmetic overflow */
151 /* Floating Point Exception */
155 /* Bus error (Ifetch) */
157 /* Bus error (data load or store) */
161 /* TLB modification exception */
163 /* TLB miss (Load or Ifetch) */
165 /* TLB miss (Store) */
167 /* Address error (Load or Ifetch) */
169 /* Address error (Store) */
181 /* Return the trap number corresponding to the last-taken trap. */
183 int __get_trap_number (void)
185 return (get_register (CAUSE) & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT;
188 #if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)
189 int __is_bsp_syscall(void)
191 return __get_trap_number() == EXC_SYS;
195 /* Set the currently-saved pc register value to PC. This also updates NPC
198 void set_pc (target_register_t pc)
200 put_register (PC, pc);
204 /*----------------------------------------------------------------------
205 * Single-step support
208 /* Saved instruction data for single step support. */
217 /* Set things up so that the next user resume will execute one instruction.
218 This may be done by setting breakpoints or setting a single step flag
219 in the saved user registers, for example. */
221 void __single_step (void)
224 t_inst *pc = (t_inst *) get_register (PC);
226 instrBuffer.targetAddr = pc + 1; /* set default */
228 inst.word = *pc; /* read the next instruction */
230 //diag_printf("pc %08x %08x\n",pc,inst.word);
232 switch (inst.RType.op) { /* override default if branch */
234 switch (inst.RType.func) {
237 instrBuffer.targetAddr = (t_inst *) get_register (inst.RType.rs);
243 switch (inst.IType.rt) {
248 if ((int)get_register (inst.IType.rs) < 0 )
249 instrBuffer.targetAddr =
250 (t_inst *)(((signed short)inst.IType.imm<<2)
251 + (get_register (PC) + 4));
253 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
259 if ((int)get_register (inst.IType.rs) >= 0 )
260 instrBuffer.targetAddr =
261 (t_inst *)(((signed short)inst.IType.imm<<2)
262 + (get_register (PC) + 4));
264 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
271 instrBuffer.targetAddr =
272 (t_inst *)((inst.JType.target<<2)
273 + ((get_register (PC) + 4)&0xf0000000));
278 if (get_register (inst.IType.rs) == get_register (inst.IType.rt))
279 instrBuffer.targetAddr =
280 (t_inst *)(((signed short)inst.IType.imm<<2)
281 + (get_register (PC) + 4));
283 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
287 if (get_register (inst.IType.rs) != get_register (inst.IType.rt))
288 instrBuffer.targetAddr =
289 (t_inst *)(((signed short)inst.IType.imm<<2)
290 + (get_register (PC) + 4));
292 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
296 if ((int)get_register (inst.IType.rs) <= 0)
297 instrBuffer.targetAddr =
298 (t_inst *)(((signed short)inst.IType.imm<<2) + (get_register (PC) + 4));
300 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
304 if ((int)get_register (inst.IType.rs) > 0)
305 instrBuffer.targetAddr =
306 (t_inst *)(((signed short)inst.IType.imm<<2) + (get_register (PC) + 4));
308 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
311 #ifdef CYGHWR_HAL_MIPS_FPU
314 if (inst.RType.rs == OP_BC)
315 switch (inst.RType.rt) {
318 if (get_register (FCR31) & FCR31_C)
319 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
321 instrBuffer.targetAddr =
322 (t_inst *)(((signed short)inst.IType.imm<<2)
323 + (get_register (PC) + 4));
327 if (get_register (FCR31) & FCR31_C)
328 instrBuffer.targetAddr =
329 (t_inst *)(((signed short)inst.IType.imm<<2)
330 + (get_register (PC) + 4));
332 instrBuffer.targetAddr = (t_inst *)(get_register (PC) + 8);
342 /* Clear the single-step state. */
344 void __clear_single_step (void)
346 //diag_printf("clear_ss ta %08x\n",instrBuffer.targetAddr);
347 if (instrBuffer.targetAddr != NULL)
349 *instrBuffer.targetAddr = instrBuffer.savedInstr;
350 instrBuffer.targetAddr = NULL;
352 instrBuffer.savedInstr = NOP_INSTR;
356 void __install_breakpoints ()
358 //diag_printf("install_bpt ta %08x\n",instrBuffer.targetAddr);
359 if (instrBuffer.targetAddr != NULL)
361 instrBuffer.savedInstr = *instrBuffer.targetAddr;
362 *instrBuffer.targetAddr = __break_opcode ();
363 //diag_printf("ta %08x si %08x *ta %08x\n",
364 // instrBuffer.targetAddr,instrBuffer.savedInstr,*instrBuffer.targetAddr);
366 /* Ensure that the planted breakpoint makes it out to memory and
367 is subsequently loaded into the instruction cache.
369 __data_cache (CACHE_FLUSH) ;
370 __instruction_cache (CACHE_FLUSH) ;
373 /* Install the breakpoints in the breakpoint list */
374 __install_breakpoint_list();
377 void __clear_breakpoints (void)
379 __clear_breakpoint_list();
383 /* If the breakpoint we hit is in the breakpoint() instruction, return a
387 __is_breakpoint_function ()
389 return get_register (PC) == (target_register_t)(unsigned long)&_breakinst;
393 /* Skip the current instruction. Since this is only called by the
394 stub when the PC points to a breakpoint or trap instruction,
395 we can safely just skip 4. */
397 void __skipinst (void)
399 put_register (PC, get_register (PC) + 4);
402 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS