URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 206 to Rev 207
- ↔ Reverse comparison
Rev 206 → Rev 207
/trunk/insight/gdb/config/or1k/tm-or1k.h
28,6 → 28,17
#include "defs.h" |
#include <inttypes.h> /* CZ */ |
|
/* CZ 11/09/01 -- Cause GDB to expect actual PC value to appear |
in breakpoint exception vector instead of being in PC itself */ |
|
#define NEW_PC_HANDLING |
|
#ifdef NEW_PC_HANDLING |
#define TARGET_READ_PC(pid) or1k_target_read_pc(pid) |
#define TARGET_WRITE_PC(pc,pid) or1k_target_write_pc(pc,pid) |
#endif |
|
|
struct value; |
|
struct struct_or1k_implementation |
144,6 → 155,21
#define PS_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 1) |
#define CCR_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 2) |
|
/*******************************************/ |
/* Added by CZ on 12/09/01 Used for new style breakpoints */ |
/* These really aren't designed to be seen by the user */ |
#define EPC_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 3) |
#define EAR_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 4) |
#define ESR_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 5) |
|
#define EPC_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP,32+cid) |
#define EAR_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP,48+cid) |
#define ESR_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP,64+cid) |
|
#define MAX_EXTRA_NUM_REGS 6 |
|
/******** END OF ADDITIONS BY CZ ************/ |
|
extern int or1k_regnum_to_sprnum PARAMS ((int regno)); |
#define REGNUM_TO_SPRNUM(regno) (or1k_regnum_to_sprnum(regno)) |
|
151,6 → 177,8
#define DMR1_ST (0x00400000) |
|
/* Changed by CZ 21/06/01 */ |
#define DRR_SS (0x00004000) |
#define DRR_TE (0x00002000) |
#define DRR_BE (0x00001000) |
#define DRR_SCE (0x00000800) |
#define DRR_RE (0x00000400) |
177,9 → 205,12
#define NUM_VF_REGS (or1k_implementation.num_vfpr_regs) |
#define MAX_VF_REGS (32) |
|
/*******************************/ |
/* Paramterized by CZ 11/09/01 */ |
/*******************************/ |
/* gdb mapping of registers */ |
#ifndef NUM_REGS |
#define NUM_REGS (MAX_GPR_REGS+MAX_VF_REGS+3) |
#define NUM_REGS (MAX_GPR_REGS+MAX_VF_REGS+MAX_EXTRA_NUM_REGS) |
#endif |
|
/* Can act like a little or big endian. */ |
270,11 → 301,23
/* Amount PC must be decremented by after a breakpoint. |
This is often the number of bytes in BREAKPOINT |
but not always. */ |
#define DECR_PC_AFTER_BREAK 0 |
|
/* Amount PC must be decremented by after a breakpoint. |
This is often the number of bytes in BREAKPOINT |
but not always. */ |
/* Note: several attempts have been made to account for |
differences between hardware and software breakpoints |
and still allow hardware breakpoints to advance the |
PC beyond the offending instruction. However, short |
of rewriting gdb, none of them seem to work. Thus, |
for now, we assume that a hardware breakpoint will |
always give control to the breakpoint vector BEFORE |
it executes the instruction, thus, when the breakpoint |
vector returns, it will return to the same instruction |
that caused the exception (and thus hit the exception |
again if it hasn't been cleared) Note that if it actually |
executes this instruction, things fail bandly inside of |
gdb. This should not be an issue for now, as the or1200 |
implementation will not implement hardware breakpoints |
at all.. */ |
|
#define DECR_PC_AFTER_BREAK 0 |
|
extern int or1k_insert_breakpoint (CORE_ADDR addr, char *contents_cache); |
319,7 → 362,7
/* Given a name (SIGHUP, etc.), return its signal. */ |
extern enum target_signal or1k_signal_from_name PARAMS ((char *)); |
|
#define NUM_OR1K_SIGNALS (10) |
#define NUM_OR1K_SIGNALS (14) |
|
/* Extract from an array REGBUF containing the (raw) register state |
a function return value of type TYPE, and copy that, in virtual format, |
357,6 → 400,7
#define SKIP_PROLOGUE(pc) (or1k_skip_prologue (pc)) |
|
/* FRAMES */ |
|
#define FRAME_ARGS_ADDRESS(fi) (fi)->frame |
|
#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame |
411,7 → 455,7
/* Is floating/vector unit present. */ |
#define OR1K_VF_PRESENT (or1k_implementation.vf_present) |
|
#define INIT_FRAME_PC /* Not necessary */ |
/* #define INIT_FRAME_PC */ /* Not necessary */ |
|
/* Stack grows downward. */ |
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs)) |
/trunk/insight/gdb/remote-or1k.c
164,6 → 164,15
unsigned int dsr = 0; |
unsigned int drr = 0; |
|
static void (*old_sigint) (); /* Old signal-handler for sigint */ |
static int interrupt_requested = 0; /* Interrupted flag */ |
static void or1k_request_int () |
{ |
/* restore original signalhandler */ |
signal (SIGINT, old_sigint); |
interrupt_requested = 1; |
} |
|
/* Current matchpoints. */ |
unsigned int dvr[MAX_MATCHPOINTS]; |
struct dcr_struct dcr[MAX_MATCHPOINTS]; |
299,6 → 308,60
return or1k_read_reg (regno + REG_SPACE); |
} |
|
/* CZ 15/09/01 -- This is hacked in right now. This should |
probably NOT be called directly, but at the moment I don't |
have the time to figure out how to do it right. The problem |
is the following, in order to write the PC, I may need to |
step the processor...(long story, but trust me, I need to |
do this)...I need to do this sometimes even when I have |
not started or even loaded a program, thus I can not |
use the default routines gdb provides for this purpose. |
|
I do not wish to embed targets directly into or1k-tdep, |
but I need a simple function there that will cause the |
processor to continue 1 instruction and not pay attention |
to gdb's state machine. I know this could conceivably break |
things if we stop connecting via jtag and start doing |
something else, so anyone who wants to figure out how to do |
this right is welcome. Drop me an email if you want to |
correct it. I'll try to help you understand the issue. */ |
|
/* The processor should already be in single step mode or |
this will continue indefinitely! */ |
void or1k_do_1_processor_step() |
{ |
unsigned long drr = 0; |
unsigned long val; |
|
/* Run the processor */ |
or1k_set_chain (SC_REGISTER); |
val = or1k_read_reg (JTAG_RISCOP); |
or1k_write_reg (JTAG_RISCOP, val & ~1); |
|
/* Wait for the DEBUG_REASON_REGISTER to be non zero */ |
while(!(drr = or1k_read_spr_reg (DRR_SPRNUM))) |
usleep (10); |
|
/* OK..we're done */ |
} |
|
static int saved_stall_state = 0; |
void or1k_save_stall_state() |
{ |
or1k_set_chain (SC_REGISTER); |
saved_stall_state = or1k_read_reg (JTAG_RISCOP) & 0x01; |
} |
void or1k_restore_stall_state() |
{ |
int val; |
|
or1k_set_chain (SC_REGISTER); |
val = or1k_read_reg (JTAG_RISCOP); |
val |= saved_stall_state; |
or1k_write_reg (JTAG_RISCOP, val); |
saved_stall_state = 0; |
} |
|
/* Stalls the CPU. */ |
|
static void |
322,6 → 385,7
{ |
unsigned int val; |
|
|
or1k_set_chain (SC_REGISTER); |
val = or1k_read_reg (JTAG_RISCOP); |
or1k_write_reg (JTAG_RISCOP, val & ~1); |
645,6 → 709,26
|
or1k_commit_debug_registers (); |
/* Run the target. */ |
#ifdef NEW_PC_HANDLING |
|
/* In the new style PC handling mode, we should always |
keep stepping the target until we get out of the |
breakpoint exception vector assuming that "step" |
has been specified. Otherwise, this isn't |
particularly useful, as we'll keep hitting the |
same breakpoint that put us here in the first |
place. By stepping out of this vector we guarantee |
to step over the instruction that caused the |
breakpoint, so when they are reinserted we are |
already past that location. */ |
if(step) |
{ |
while((or1k_read_spr_reg(PC_SPRNUM) & 0xFFFFFF00) == 0xD00) |
or1k_do_1_processor_step(); |
} |
#endif |
|
/* We can now continue normally, independent of step */ |
or1k_unstall (); |
or1k_status = TARGET_RUNNING; |
} |
674,13 → 758,25
or1k_error ("Remote failure: %s", or1k_err_name (err)); |
|
/* Wait for or1k DRR register to be nonzero. */ |
interrupt_requested = 0; |
old_sigint = signal (SIGINT, or1k_request_int); |
do |
{ |
if(interrupt_requested) |
{ |
or1k_stall(); |
status->kind = TARGET_WAITKIND_STOPPED; |
status->value.sig = TARGET_SIGNAL_INT; |
or1k_status = TARGET_STOPPED; |
or1k_read_trace(); |
return 0; |
} |
drr = or1k_read_spr_reg (DRR_SPRNUM); |
usleep (10); |
} |
while (drr == 0); |
|
signal (SIGINT, old_sigint); |
status->kind = TARGET_WAITKIND_STOPPED; |
or1k_flush_pipeline (); |
|
710,6 → 806,10
status->value.sig = TARGET_SIGNAL_REALTIME_40; |
else if (drr & DRR_BE) |
status->value.sig = TARGET_SIGNAL_TRAP; |
else if (drr & DRR_TE) |
status->value.sig = TARGET_SIGNAL_REALTIME_41; |
else if (drr & DRR_SS) /* CZ 16/09/01 */ |
status->value.sig = TARGET_SIGNAL_TRAP; |
else |
{ |
status->value.sig = TARGET_SIGNAL_UNKNOWN; |
739,6 → 839,8
} |
hit_watchpoint = !breakpoint; |
|
|
#ifndef NEW_PC_HANDLING |
/* Cause the trap/breakpoint exception to be ignored. This is |
the behavior of the simulator when the PC value is changed |
by a write command. All pending exceptions are cleared and |
750,6 → 852,24
{ |
or1k_write_spr_reg(PC_SPRNUM,value); |
} |
#endif |
|
#ifdef NEW_PC_HANDLING |
|
/* If we're a software breakpoint and we're currently located |
in the breakpoint vector, then we need to reset the pc |
back 4 bytes. This will ensure that the instruction gets |
executed. If we don't do this, gdb will skip this instruction, |
even if we set DECR_PC_AFTER_BREAK, which seems to have no |
effect other than to calculate the correct breakpoint |
address. */ |
|
if((b_insn == or1k_read_spr_reg(((pc-4) >> 2) + MEM_SPACE)) && |
or1k_read_spr_reg(PC_SPRNUM) == 0xD00) |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID),pc-4); |
|
#endif |
|
} |
else |
hit_watchpoint = 0; |
1061,9 → 1181,13
void |
or1k_flush_pipeline () |
{ |
/* CZ 15/09/01 -- Damjan has made it perfectly clear |
that the DIR will not be implemented on any chip |
as the entire concept is poorly conceived. This |
section has therefore been removed. */ |
/* or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); */ |
} |
|
/* Print info on this target. */ |
/trunk/insight/gdb/or1k-tdep.c
112,12 → 112,13
"R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", |
"R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31", |
|
/* Modified by CZ 12/09/01 */ |
/* vector/floating point registers */ |
"VFA0", "VFA1", "VFA2", "VFA3", "VFA4", "VFA5", "VFRV ", "VFR7", |
"VFR8", "VFR9", "VFR10", "VFR11", "VFR12", "VFR13", "VFR14", "VFR15", |
"VFR16", "VFR17", "VFR18", "VFR19", "VFR20", "VFR21", "VFR22", "VFR23", |
"VFR24", "VFR25", "VFR26", "VFR27", "VFR28", "VFR29", "VFR30", "VFR31", |
"PC", "SR", "EPCR" |
"PC", "SR", "EPCR", "ExPC", "ExEAR", "ExSR" |
}; |
|
static char *or1k_group_names[] = { |
133,15 → 134,19
} or1k_signals [NUM_OR1K_SIGNALS + 1] = |
{ |
{"RSTE", "Reset Exception"}, |
{"BUSE", "Bus Error" }, |
{"DFPE", "Data Page Fault Exception"}, |
{"IFPE", "Instruction Page Fault Exception"}, |
{"LPINTE", "Low Priority Interrupt Exception"}, |
{"AE", "Alignment Exception"}, |
{"ILINSE" "Illegal Instruction" }, |
{"HPINTE", "High Priority Interrupt Exception"}, |
{"DME", "DTLB Miss Exception"}, |
{"IME", "ITLB Miss Exception"}, |
{"RE", "Range Exception"}, |
{"SCE", "SCE Exception"}, |
{"BRKPTE", "Breakpoint Exception"}, |
{"TRAPE", "Trap Exception"}, |
{NULL, NULL} |
}; |
|
190,24 → 195,169
static int prev_length = 10; |
static int prev_from = 0; |
|
/* Define NEW_PC_HANDLING if you want to use the new style routines |
where control is given to the debug interface AFTER the exception |
has already been taken. */ |
|
#ifdef NEW_PC_HANDLING |
|
/* Specialized read_pc routine. Looks at returned value. If value |
is detected inside the breakpoint exception vector, the actual |
value stored in EPC is returned instead. The breakpoint exception |
vector should consist of nothing more than an RTE and a NOP. Note |
that this mechanism prohibits the use of GDB in an environment |
where this restriction is not met, however this is not expected |
to cause a significant problem. Anyone wishing to use GDB can |
easily store the appropriate instructions at the vector, and if |
they're not using GDB, why the hell are they inserting breakpoint |
exceptions?... |
*/ |
|
CORE_ADDR or1k_target_read_pc(int pid) |
{ |
#if defined(PC_REGNUM) && defined(EPC_REGNUM) |
if(PC_REGNUM >= 0) |
{ |
unsigned long pc_val = or1k_read_spr_reg(PC_SPRNUM); |
|
/* If we're currently at the breakpoint exception, get the logical PC |
from the exception register instead. */ |
if(pc_val == 0xD00) |
{ |
unsigned long sr_val = or1k_read_spr_reg(ESR_SPRNUM(CURRENT_CID)); |
|
pc_val = or1k_read_spr_reg(EPC_SPRNUM(CURRENT_CID)); |
#if 0 |
if(!(sr_val & 0x2000)) /* If ESR[DSX] is not set */ |
pc_val += 4; |
#endif |
} |
return pc_val; |
} |
#endif |
internal_error ("or1k_target_read_pc"); |
return 0; |
} |
|
void or1k_target_write_pc(CORE_ADDR pc,int pid) |
{ |
#if defined(PC_REGNUM) && defined(EPC_REGNUM) |
if(PC_REGNUM >= 0) |
{ |
unsigned long pc_val = or1k_read_spr_reg(PC_SPRNUM); |
if(pc_val == 0xD00) |
{ |
unsigned long sr_val = or1k_read_spr_reg(ESR_SPRNUM(CURRENT_CID)); |
|
if(or1k_read_spr_reg(EPC_SPRNUM(CURRENT_CID)) != pc) |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc); |
} |
else |
{ |
unsigned char break_bytes[4] = BRK_INSTR_STRUCT; |
unsigned long b_insn = ntohl(*((unsigned long*)break_bytes)); |
unsigned long saved_insn = or1k_read_spr_reg((pc_val >> 2) + MEM_SPACE); |
unsigned long saved_sr = or1k_read_spr_reg(SR_SPRNUM); |
unsigned long saved_dmr1 = or1k_read_spr_reg(DMR1_SPRNUM); |
unsigned long working_sr = saved_sr; |
unsigned long working_dmr1 = saved_dmr1; |
unsigned long new_pc_val = pc_val; |
|
or1k_save_stall_state(); |
/* Install a breakpoint */ |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE,b_insn); |
|
/* Make sure exceptions are enabled and interrupts |
are disabled */ |
working_sr |= 0x02; /* Exceptions enabled */ |
working_sr &= ~0x04; /* Interrupts disabled */ |
or1k_write_spr_reg(SR_SPRNUM,working_sr); |
|
/* Make sure we are in hardware single step... */ |
dmr1 |= DMR1_ST; |
or1k_write_spr_reg(DMR1_SPRNUM, dmr1); |
|
or1k_do_1_processor_step(); |
while((new_pc_val = or1k_read_spr_reg(PC_SPRNUM)) != 0xD00) |
{ |
/* We still haven't managed to get into the exception. |
Perhaps there was an exception pending already and |
it jumped somewhere else? Let's try it again. */ |
|
/* Restore the old instruction */ |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE, saved_insn); |
pc_val = new_pc_val; |
|
/* Install a new breakpoint */ |
saved_insn = or1k_read_spr_reg(( pc_val >> 2) + MEM_SPACE); |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE,b_insn); |
|
/* Again, make sure exceptions are enabled */ |
working_sr = or1k_read_spr_reg(SR_SPRNUM); |
working_sr |= 0x02; /* Exceptions enabled */ |
working_sr &= ~0x04; /* Interrupts disabled */ |
or1k_write_spr_reg(SR_SPRNUM,working_sr); |
|
or1k_do_1_processor_step(); |
} |
|
/* Restore the state of everything */ |
#if 0 |
if(saved_sr & 0x2000) |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc); |
else |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc-4); |
#endif |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc); |
or1k_write_spr_reg(ESR_SPRNUM(CURRENT_CID), saved_sr); |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE, saved_insn); |
|
/* Step the processor twice to finish through the |
breakpoint instruction */ |
or1k_do_1_processor_step(); |
or1k_do_1_processor_step(); |
|
or1k_restore_stall_state(); |
|
/* Reset the single step mode */ |
or1k_write_spr_reg(DMR1_SPRNUM,saved_dmr1); |
} |
return; |
} |
#endif |
internal_error ("or1k_target_write_pc"); |
return; |
} |
|
#endif /* NEW_PC_HANDLING */ |
|
/* Converts regno to sprno. or1k debug unit has GPRs mapped to SPRs, |
which are not compact, so we are mapping them for GDB. */ |
|
/* Rewritten by CZ 12/09/01 */ |
int |
or1k_regnum_to_sprnum (int regno) |
{ |
if (regno < MAX_GPR_REGS) |
if(regno < MAX_GPR_REGS) |
return SPR_REG(SPR_SYSTEM_GROUP, regno + CURRENT_CID * MAX_GPR_REGS + SPR_GPR_START); |
|
if (regno < MAX_GPR_REGS + MAX_VF_REGS) |
return SPR_REG(SPR_SYSTEM_GROUP, regno - MAX_GPR_REGS |
+ CURRENT_CID * MAX_GPR_REGS + SPR_VFPR_START); |
if (regno == PS_REGNUM) |
return SR_SPRNUM; |
if (regno == PC_REGNUM) |
return PC_SPRNUM; |
if (regno == CCR_REGNUM) |
return CCR_SPRNUM(CURRENT_CID); |
error ("Invalid register number!"); |
|
switch(regno) |
{ |
case PS_REGNUM: return SR_SPRNUM; |
case PC_REGNUM: return PC_SPRNUM; |
case CCR_REGNUM: return CCR_SPRNUM(CURRENT_CID); |
case EPC_REGNUM: return EPC_SPRNUM(CURRENT_CID); |
case EAR_REGNUM: return EAR_SPRNUM(CURRENT_CID); |
case ESR_REGNUM: return ESR_SPRNUM(CURRENT_CID); |
default: |
error("Invalid register number!"); |
break; |
} |
|
return 0; |
} |
|
/* Builds and returns register name. */ |
634,58 → 784,153
memcpy (valbuf, ®buf[REGISTER_BYTE (RV_REGNUM)], TYPE_LENGTH (valtype)); |
} |
|
/* The or1k cc defines the following |
prologue: |
00000000 <_proc1>: |
0: d7 e1 17 e4 l.sw 0xffffffe4(r1),r2 |
4: 9c 41 00 00 l.addi r2,r1,0x0 |
8: 9c 21 ff e8 l.addi r1,r1,0xffffffe8 |
c: d7 e2 1f f8 l.sw 0xfffffff8(r2),r3 |
10: d7 e2 27 f4 l.sw 0xfffffff4(r2),r4 |
14: 84 82 ff f8 l.lwz r4,0xfffffff8(r2) |
18: 9d 24 00 00 l.addi r9,r4,0x0 |
1c: 00 00 00 02 l.j 0x2 |
20: 15 00 00 00 l.nop |
/* CZ -- 25/09/01 -- The prologue handling code has been rewritten |
to bring it inline with the new C compiler and various changes |
that have been made. The code below expects to see various |
instructions that are identified by states. States are ordered |
and should flow from one to the next. If a state is encountered |
out of order, it is assumed to be function code and not |
prologue, so the prologue parsing is terminated. I've tried |
several real world tests from the C compiler, and this seems |
to recognize the transition from prologue to code even under |
a worst case (21 instructions) scenario. */ |
|
00000024 <_L2>: |
24: 84 41 ff fc l.lwz r2,0xfffffffc(r1) |
28: 48 00 58 00 l.jalr r11 |
2c: 9c 21 00 18 l.addi r1,r1,0x18 */ |
typedef enum { |
PrologueStateMachineStart, |
PrologueStateMachineFrameInitialized, |
PrologueStateMachineFrameSaved, |
PrologueStateMachineFrameAdjusted, |
PrologueStateMachineRegisterSaved, |
PrologueStateMachineParameterSaved, |
PrologueStateMachineInvalid, |
} FunctionPrologueStates; |
|
CORE_ADDR |
or1k_skip_prologue (CORE_ADDR pc) |
/* Parse the insn and save the arguments */ |
static FunctionPrologueStates getPrologueInsnType(unsigned long insn, |
int* arg1,int* arg2) |
{ |
unsigned long inst; |
CORE_ADDR skip_pc; |
CORE_ADDR func_addr, func_end; |
struct symtab_and_line sal; |
int i; |
int offset = 0; |
int code = insn >> 26; |
int state = PrologueStateMachineInvalid; |
int op1,op2; |
short offset; |
|
switch(code) |
{ |
case 0x27: /* l.addi */ |
op1 = (insn & 0x03E00000) >> 21; |
op2 = (insn & 0x001F0000) >> 16; |
if(op1 == 1 && op2 == 1) |
{ |
offset = insn & 0xFFFF; |
state = PrologueStateMachineFrameInitialized; |
} |
else if(op1 == 2 && op2 == 1) |
{ |
offset = insn & 0xFFFF; |
state = PrologueStateMachineFrameAdjusted; |
} |
*arg1 = op1; |
*arg2 = offset; |
break; |
case 0x35: /* l.sw */ |
op1 = (insn & 0x001F0000) >> 16; |
op2 = (insn & 0x0000F800) >> 11; |
offset = (insn & 0x000007FF) | |
((insn & 0x03E00000) >> 10); |
|
if(op1 == 1) |
state = (op2 == 2) ? PrologueStateMachineFrameSaved : |
PrologueStateMachineRegisterSaved; |
else if(op1 == 2) |
state = PrologueStateMachineParameterSaved; |
*arg1 = op2; |
*arg2 = offset; |
break; |
default: /* unknown */ |
break; |
} |
|
return state; |
} |
|
CORE_ADDR or1k_skip_prologue (CORE_ADDR pc) |
{ |
int frame_size = 0,i; |
FunctionPrologueStates state = PrologueStateMachineStart; |
CORE_ADDR t_pc; |
|
/* |
Maximum prologue: save even reg's 10-30 (11 insns) |
save params passed in regs (6 insns) |
adjust stack (1 insn), adjust frame (1 insn), |
save old frame pointer (1 insn), |
save old link register (1 insn) |
*/ |
static const int MAX_PROLOGUE_LENGTH = 21; |
|
for (i = 0; i < MAX_GPR_REGS; i++) |
or1k_saved_reg_addr[i] = -1; |
|
/* Is there a prologue? */ |
inst = or1k_fetch_instruction (pc); |
if (inst & 0xfc1ff800 != 0xd4011000) return pc; /* l.sw I(r1),r2 */ |
or1k_saved_reg_addr[2] = offset++; |
inst = or1k_fetch_instruction (pc + OR1K_INSTLEN); |
if (inst & 0xFFFF0000 != 0x9c410000) return pc; /* l.addi r2,r1,I */ |
pc += 2 * OR1K_INSTLEN; |
inst = or1k_fetch_instruction (pc); |
if (inst & 0xFFFF0000 != 0x9c210000) return pc; /* l.addi r1,r1,I */ |
pc += OR1K_INSTLEN; |
for(t_pc=pc; t_pc < (pc + MAX_PROLOGUE_LENGTH) && |
state != PrologueStateMachineInvalid; t_pc += OR1K_INSTLEN) |
{ |
unsigned long insn = or1k_fetch_instruction(t_pc); |
int reg; |
int offset; |
FunctionPrologueStates new_state = getPrologueInsnType(insn,®,&offset); |
|
/* Skip stored registers. */ |
inst = or1k_fetch_instruction (pc); |
while (inst & 0xfc1ff800 != 0xd4020000) /* l.sw 0x0(r2),rx */ |
{ |
/* get saved reg. */ |
or1k_saved_reg_addr[(inst >> 11) & 0x1f] = offset++; |
pc += OR1K_INSTLEN; |
inst = or1k_fetch_instruction (pc); |
switch(state) |
{ |
case PrologueStateMachineStart: |
if(new_state == PrologueStateMachineFrameInitialized) |
{ |
frame_size = -offset; |
or1k_saved_reg_addr[1] = frame_size; |
} |
else |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineFrameInitialized: |
if(new_state == PrologueStateMachineFrameSaved) |
or1k_saved_reg_addr[reg] = frame_size - offset; |
else if(new_state == PrologueStateMachineRegisterSaved) |
{ |
/* Ooops...we have a frameless function. |
Not sure what this might mean, but |
let's try and continue. */ |
or1k_saved_reg_addr[reg] = frame_size - offset; |
} |
else |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineFrameSaved: |
if(new_state != PrologueStateMachineFrameAdjusted && |
offset != frame_size) |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineFrameAdjusted: |
case PrologueStateMachineRegisterSaved: |
if(new_state == PrologueStateMachineRegisterSaved) |
or1k_saved_reg_addr[reg] = frame_size - offset; |
else if(new_state == PrologueStateMachineParameterSaved) |
or1k_saved_reg_addr[reg] = -offset; |
else |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineParameterSaved: |
if(new_state == PrologueStateMachineParameterSaved) |
or1k_saved_reg_addr[reg] = -offset; |
else |
new_state = PrologueStateMachineInvalid; |
break; |
default: |
new_state = PrologueStateMachineInvalid; |
} |
|
state = new_state; |
} |
return pc; |
|
return t_pc; |
} |
|
/* Determines whether this function has frame. */ |
732,8 → 977,50
frame pointer. */ |
fp = FRAME_FP (frame); |
else |
fp = read_memory_integer (frame->frame, 4); |
{ |
unsigned long func_pc = get_pc_function_start(frame->pc); |
unsigned long insn = read_memory_integer(func_pc,4); |
int i; |
int offset = 0; |
|
/* The first instruction should be the number of bytes |
in our frame. If it isn't we're in trouble because |
the function is without a prologue... */ |
if(((insn & 0xFC000000) == 0x9C000000) && |
((insn & 0x03E00000) == 0x00200000) && |
((insn & 0x001F0000) == 0x00010000)) |
{ |
short off = insn & 0xFFFF; |
|
/* Look for the storage of the frame pointer in the |
function prologue.. */ |
for(i=1;i<20;i++) |
{ |
unsigned long insn = read_memory_integer(func_pc+4*i,4); |
|
/* If bits are 31 - 26 are %110101, |
and bits 20 - 16 are %00001, |
and bits 15 - 11 are %00010, |
then our frame pointer lies at the offset specified |
by bits [25-21][10-0]. */ |
|
int code = insn >> 26; |
int r1 = (insn & 0x001F0000) >> 16; |
int r2 = (insn & 0x0000F800) >> 11; |
int idx_h = (insn & 0x03E00000) >> 10; |
int idx = (insn & 0x000007FF) | idx_h; |
|
if(code == 0x35 && r1 == 1 && r2 == 2) |
{ |
offset = off + idx; |
break; |
} |
} |
} |
|
fp = read_memory_integer (frame->frame + offset, 4); |
} |
|
if (USE_GENERIC_DUMMY_FRAMES) |
{ |
CORE_ADDR fpp, lr; |
758,17 → 1045,44
{ |
int i; |
CORE_ADDR frame_addr; |
CORE_ADDR func_pc = get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET; |
int frame_size; |
int pc_found = 0; |
|
frame_saved_regs_zalloc (fi); |
|
/* Skip prologue sets or1k_saved_reg_addr[], we will use it later. */ |
or1k_skip_prologue (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); |
or1k_skip_prologue (func_pc); |
|
frame_size = or1k_saved_reg_addr[1]; |
or1k_saved_reg_addr[1] = -1; |
|
/* If the frame_size is less than 0, we have hit an assembly |
routine which we can't traverse beyond. Let's give up here, |
because attempting to continue will only lead to trouble. */ |
if(frame_size < 0) |
{ |
printf("Found a function without a prologue at 0x%08x\n",func_pc); |
printf("Frame pc was at 0x%08x\n",fi->pc); |
return; |
} |
|
for (i = 0; i < NUM_GPR_REGS + NUM_VF_REGS; i++) |
if (or1k_saved_reg_addr[i] >= 0) |
fi->saved_regs[i] = fi->frame + or1k_saved_reg_addr[i]; |
fi->saved_regs[i] = fi->frame - or1k_saved_reg_addr[i]; |
|
/* We want to make sure we fill in the PC with the value of the |
r9 register from the NEXT frame, and that the value of r1 is |
the correct value of r1 for the next frame, which can be |
calculated by adding the frame_size to the frame pointer. */ |
fi->saved_regs[1] = fi->frame - frame_size; |
|
if(fi->saved_regs[LR_REGNUM]) |
fi->saved_regs[PC_REGNUM] = read_memory_integer(fi->saved_regs[LR_REGNUM],4); |
else |
fi->saved_regs[PC_REGNUM] = read_register(LR_REGNUM); |
} |
|
|
static CORE_ADDR |
read_next_frame_reg (fi, regno) |
struct frame_info *fi; |
785,7 → 1099,12
if (fi->saved_regs == NULL) |
or1k_init_saved_regs (fi); |
if (fi->saved_regs[regno]) |
return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE); |
{ |
if(regno == SP_REGNUM || regno == PC_REGNUM) |
return fi->saved_regs[regno]; |
else |
return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE); |
} |
} |
} |
return read_register (regno); |
2176,9 → 2495,10
add_com ("spr", class_support, spr_command, "Set specified SPR register."); |
|
/* hwatch command. */ |
add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watchpoint.\n\ |
Example: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_var)&&($SDATA >= 50).\n\ |
See OR1k Architecture document for more info."); |
add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watch" |
"point.\nExample: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_" |
"var)&&($SDATA >= 50).\nSee OR1k Architecture document for more" |
" info."); |
|
/* htrace commands. */ |
add_prefix_cmd ("htrace", class_breakpoint, htrace_command, |
/trunk/gdb-5.0/gdb/remote-or1k.c
164,6 → 164,15
unsigned int dsr = 0; |
unsigned int drr = 0; |
|
static void (*old_sigint) (); /* Old signal-handler for sigint */ |
static int interrupt_requested = 0; /* Interrupted flag */ |
static void or1k_request_int () |
{ |
/* restore original signalhandler */ |
signal (SIGINT, old_sigint); |
interrupt_requested = 1; |
} |
|
/* Current matchpoints. */ |
unsigned int dvr[MAX_MATCHPOINTS]; |
struct dcr_struct dcr[MAX_MATCHPOINTS]; |
299,6 → 308,60
return or1k_read_reg (regno + REG_SPACE); |
} |
|
/* CZ 15/09/01 -- This is hacked in right now. This should |
probably NOT be called directly, but at the moment I don't |
have the time to figure out how to do it right. The problem |
is the following, in order to write the PC, I may need to |
step the processor...(long story, but trust me, I need to |
do this)...I need to do this sometimes even when I have |
not started or even loaded a program, thus I can not |
use the default routines gdb provides for this purpose. |
|
I do not wish to embed targets directly into or1k-tdep, |
but I need a simple function there that will cause the |
processor to continue 1 instruction and not pay attention |
to gdb's state machine. I know this could conceivably break |
things if we stop connecting via jtag and start doing |
something else, so anyone who wants to figure out how to do |
this right is welcome. Drop me an email if you want to |
correct it. I'll try to help you understand the issue. */ |
|
/* The processor should already be in single step mode or |
this will continue indefinitely! */ |
void or1k_do_1_processor_step() |
{ |
unsigned long drr = 0; |
unsigned long val; |
|
/* Run the processor */ |
or1k_set_chain (SC_REGISTER); |
val = or1k_read_reg (JTAG_RISCOP); |
or1k_write_reg (JTAG_RISCOP, val & ~1); |
|
/* Wait for the DEBUG_REASON_REGISTER to be non zero */ |
while(!(drr = or1k_read_spr_reg (DRR_SPRNUM))) |
usleep (10); |
|
/* OK..we're done */ |
} |
|
static int saved_stall_state = 0; |
void or1k_save_stall_state() |
{ |
or1k_set_chain (SC_REGISTER); |
saved_stall_state = or1k_read_reg (JTAG_RISCOP) & 0x01; |
} |
void or1k_restore_stall_state() |
{ |
int val; |
|
or1k_set_chain (SC_REGISTER); |
val = or1k_read_reg (JTAG_RISCOP); |
val |= saved_stall_state; |
or1k_write_reg (JTAG_RISCOP, val); |
saved_stall_state = 0; |
} |
|
/* Stalls the CPU. */ |
|
static void |
322,6 → 385,7
{ |
unsigned int val; |
|
|
or1k_set_chain (SC_REGISTER); |
val = or1k_read_reg (JTAG_RISCOP); |
or1k_write_reg (JTAG_RISCOP, val & ~1); |
645,6 → 709,26
|
or1k_commit_debug_registers (); |
/* Run the target. */ |
#ifdef NEW_PC_HANDLING |
|
/* In the new style PC handling mode, we should always |
keep stepping the target until we get out of the |
breakpoint exception vector assuming that "step" |
has been specified. Otherwise, this isn't |
particularly useful, as we'll keep hitting the |
same breakpoint that put us here in the first |
place. By stepping out of this vector we guarantee |
to step over the instruction that caused the |
breakpoint, so when they are reinserted we are |
already past that location. */ |
if(step) |
{ |
while((or1k_read_spr_reg(PC_SPRNUM) & 0xFFFFFF00) == 0xD00) |
or1k_do_1_processor_step(); |
} |
#endif |
|
/* We can now continue normally, independent of step */ |
or1k_unstall (); |
or1k_status = TARGET_RUNNING; |
} |
674,13 → 758,25
or1k_error ("Remote failure: %s", or1k_err_name (err)); |
|
/* Wait for or1k DRR register to be nonzero. */ |
interrupt_requested = 0; |
old_sigint = signal (SIGINT, or1k_request_int); |
do |
{ |
if(interrupt_requested) |
{ |
or1k_stall(); |
status->kind = TARGET_WAITKIND_STOPPED; |
status->value.sig = TARGET_SIGNAL_INT; |
or1k_status = TARGET_STOPPED; |
or1k_read_trace(); |
return 0; |
} |
drr = or1k_read_spr_reg (DRR_SPRNUM); |
usleep (10); |
} |
while (drr == 0); |
|
signal (SIGINT, old_sigint); |
status->kind = TARGET_WAITKIND_STOPPED; |
or1k_flush_pipeline (); |
|
710,6 → 806,10
status->value.sig = TARGET_SIGNAL_REALTIME_40; |
else if (drr & DRR_BE) |
status->value.sig = TARGET_SIGNAL_TRAP; |
else if (drr & DRR_TE) |
status->value.sig = TARGET_SIGNAL_REALTIME_41; |
else if (drr & DRR_SS) /* CZ 16/09/01 */ |
status->value.sig = TARGET_SIGNAL_TRAP; |
else |
{ |
status->value.sig = TARGET_SIGNAL_UNKNOWN; |
739,6 → 839,8
} |
hit_watchpoint = !breakpoint; |
|
|
#ifndef NEW_PC_HANDLING |
/* Cause the trap/breakpoint exception to be ignored. This is |
the behavior of the simulator when the PC value is changed |
by a write command. All pending exceptions are cleared and |
750,6 → 852,24
{ |
or1k_write_spr_reg(PC_SPRNUM,value); |
} |
#endif |
|
#ifdef NEW_PC_HANDLING |
|
/* If we're a software breakpoint and we're currently located |
in the breakpoint vector, then we need to reset the pc |
back 4 bytes. This will ensure that the instruction gets |
executed. If we don't do this, gdb will skip this instruction, |
even if we set DECR_PC_AFTER_BREAK, which seems to have no |
effect other than to calculate the correct breakpoint |
address. */ |
|
if((b_insn == or1k_read_spr_reg(((pc-4) >> 2) + MEM_SPACE)) && |
or1k_read_spr_reg(PC_SPRNUM) == 0xD00) |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID),pc-4); |
|
#endif |
|
} |
else |
hit_watchpoint = 0; |
1061,9 → 1181,13
void |
or1k_flush_pipeline () |
{ |
/* CZ 15/09/01 -- Damjan has made it perfectly clear |
that the DIR will not be implemented on any chip |
as the entire concept is poorly conceived. This |
section has therefore been removed. */ |
/* or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); |
or1k_write_spr_reg (DIR_SPRNUM, NOP_INSTR); */ |
} |
|
/* Print info on this target. */ |
/trunk/gdb-5.0/gdb/or1k-tdep.c
112,12 → 112,13
"R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", |
"R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31", |
|
/* Modified by CZ 12/09/01 */ |
/* vector/floating point registers */ |
"VFA0", "VFA1", "VFA2", "VFA3", "VFA4", "VFA5", "VFRV ", "VFR7", |
"VFR8", "VFR9", "VFR10", "VFR11", "VFR12", "VFR13", "VFR14", "VFR15", |
"VFR16", "VFR17", "VFR18", "VFR19", "VFR20", "VFR21", "VFR22", "VFR23", |
"VFR24", "VFR25", "VFR26", "VFR27", "VFR28", "VFR29", "VFR30", "VFR31", |
"PC", "SR", "EPCR" |
"PC", "SR", "EPCR", "ExPC", "ExEAR", "ExSR" |
}; |
|
static char *or1k_group_names[] = { |
133,15 → 134,19
} or1k_signals [NUM_OR1K_SIGNALS + 1] = |
{ |
{"RSTE", "Reset Exception"}, |
{"BUSE", "Bus Error" }, |
{"DFPE", "Data Page Fault Exception"}, |
{"IFPE", "Instruction Page Fault Exception"}, |
{"LPINTE", "Low Priority Interrupt Exception"}, |
{"AE", "Alignment Exception"}, |
{"ILINSE" "Illegal Instruction" }, |
{"HPINTE", "High Priority Interrupt Exception"}, |
{"DME", "DTLB Miss Exception"}, |
{"IME", "ITLB Miss Exception"}, |
{"RE", "Range Exception"}, |
{"SCE", "SCE Exception"}, |
{"BRKPTE", "Breakpoint Exception"}, |
{"TRAPE", "Trap Exception"}, |
{NULL, NULL} |
}; |
|
190,24 → 195,169
static int prev_length = 10; |
static int prev_from = 0; |
|
/* Define NEW_PC_HANDLING if you want to use the new style routines |
where control is given to the debug interface AFTER the exception |
has already been taken. */ |
|
#ifdef NEW_PC_HANDLING |
|
/* Specialized read_pc routine. Looks at returned value. If value |
is detected inside the breakpoint exception vector, the actual |
value stored in EPC is returned instead. The breakpoint exception |
vector should consist of nothing more than an RTE and a NOP. Note |
that this mechanism prohibits the use of GDB in an environment |
where this restriction is not met, however this is not expected |
to cause a significant problem. Anyone wishing to use GDB can |
easily store the appropriate instructions at the vector, and if |
they're not using GDB, why the hell are they inserting breakpoint |
exceptions?... |
*/ |
|
CORE_ADDR or1k_target_read_pc(int pid) |
{ |
#if defined(PC_REGNUM) && defined(EPC_REGNUM) |
if(PC_REGNUM >= 0) |
{ |
unsigned long pc_val = or1k_read_spr_reg(PC_SPRNUM); |
|
/* If we're currently at the breakpoint exception, get the logical PC |
from the exception register instead. */ |
if(pc_val == 0xD00) |
{ |
unsigned long sr_val = or1k_read_spr_reg(ESR_SPRNUM(CURRENT_CID)); |
|
pc_val = or1k_read_spr_reg(EPC_SPRNUM(CURRENT_CID)); |
#if 0 |
if(!(sr_val & 0x2000)) /* If ESR[DSX] is not set */ |
pc_val += 4; |
#endif |
} |
return pc_val; |
} |
#endif |
internal_error ("or1k_target_read_pc"); |
return 0; |
} |
|
void or1k_target_write_pc(CORE_ADDR pc,int pid) |
{ |
#if defined(PC_REGNUM) && defined(EPC_REGNUM) |
if(PC_REGNUM >= 0) |
{ |
unsigned long pc_val = or1k_read_spr_reg(PC_SPRNUM); |
if(pc_val == 0xD00) |
{ |
unsigned long sr_val = or1k_read_spr_reg(ESR_SPRNUM(CURRENT_CID)); |
|
if(or1k_read_spr_reg(EPC_SPRNUM(CURRENT_CID)) != pc) |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc); |
} |
else |
{ |
unsigned char break_bytes[4] = BRK_INSTR_STRUCT; |
unsigned long b_insn = ntohl(*((unsigned long*)break_bytes)); |
unsigned long saved_insn = or1k_read_spr_reg((pc_val >> 2) + MEM_SPACE); |
unsigned long saved_sr = or1k_read_spr_reg(SR_SPRNUM); |
unsigned long saved_dmr1 = or1k_read_spr_reg(DMR1_SPRNUM); |
unsigned long working_sr = saved_sr; |
unsigned long working_dmr1 = saved_dmr1; |
unsigned long new_pc_val = pc_val; |
|
or1k_save_stall_state(); |
/* Install a breakpoint */ |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE,b_insn); |
|
/* Make sure exceptions are enabled and interrupts |
are disabled */ |
working_sr |= 0x02; /* Exceptions enabled */ |
working_sr &= ~0x04; /* Interrupts disabled */ |
or1k_write_spr_reg(SR_SPRNUM,working_sr); |
|
/* Make sure we are in hardware single step... */ |
dmr1 |= DMR1_ST; |
or1k_write_spr_reg(DMR1_SPRNUM, dmr1); |
|
or1k_do_1_processor_step(); |
while((new_pc_val = or1k_read_spr_reg(PC_SPRNUM)) != 0xD00) |
{ |
/* We still haven't managed to get into the exception. |
Perhaps there was an exception pending already and |
it jumped somewhere else? Let's try it again. */ |
|
/* Restore the old instruction */ |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE, saved_insn); |
pc_val = new_pc_val; |
|
/* Install a new breakpoint */ |
saved_insn = or1k_read_spr_reg(( pc_val >> 2) + MEM_SPACE); |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE,b_insn); |
|
/* Again, make sure exceptions are enabled */ |
working_sr = or1k_read_spr_reg(SR_SPRNUM); |
working_sr |= 0x02; /* Exceptions enabled */ |
working_sr &= ~0x04; /* Interrupts disabled */ |
or1k_write_spr_reg(SR_SPRNUM,working_sr); |
|
or1k_do_1_processor_step(); |
} |
|
/* Restore the state of everything */ |
#if 0 |
if(saved_sr & 0x2000) |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc); |
else |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc-4); |
#endif |
or1k_write_spr_reg(EPC_SPRNUM(CURRENT_CID), pc); |
or1k_write_spr_reg(ESR_SPRNUM(CURRENT_CID), saved_sr); |
or1k_write_spr_reg((pc_val >> 2) + MEM_SPACE, saved_insn); |
|
/* Step the processor twice to finish through the |
breakpoint instruction */ |
or1k_do_1_processor_step(); |
or1k_do_1_processor_step(); |
|
or1k_restore_stall_state(); |
|
/* Reset the single step mode */ |
or1k_write_spr_reg(DMR1_SPRNUM,saved_dmr1); |
} |
return; |
} |
#endif |
internal_error ("or1k_target_write_pc"); |
return; |
} |
|
#endif /* NEW_PC_HANDLING */ |
|
/* Converts regno to sprno. or1k debug unit has GPRs mapped to SPRs, |
which are not compact, so we are mapping them for GDB. */ |
|
/* Rewritten by CZ 12/09/01 */ |
int |
or1k_regnum_to_sprnum (int regno) |
{ |
if (regno < MAX_GPR_REGS) |
if(regno < MAX_GPR_REGS) |
return SPR_REG(SPR_SYSTEM_GROUP, regno + CURRENT_CID * MAX_GPR_REGS + SPR_GPR_START); |
|
if (regno < MAX_GPR_REGS + MAX_VF_REGS) |
return SPR_REG(SPR_SYSTEM_GROUP, regno - MAX_GPR_REGS |
+ CURRENT_CID * MAX_GPR_REGS + SPR_VFPR_START); |
if (regno == PS_REGNUM) |
return SR_SPRNUM; |
if (regno == PC_REGNUM) |
return PC_SPRNUM; |
if (regno == CCR_REGNUM) |
return CCR_SPRNUM(CURRENT_CID); |
error ("Invalid register number!"); |
|
switch(regno) |
{ |
case PS_REGNUM: return SR_SPRNUM; |
case PC_REGNUM: return PC_SPRNUM; |
case CCR_REGNUM: return CCR_SPRNUM(CURRENT_CID); |
case EPC_REGNUM: return EPC_SPRNUM(CURRENT_CID); |
case EAR_REGNUM: return EAR_SPRNUM(CURRENT_CID); |
case ESR_REGNUM: return ESR_SPRNUM(CURRENT_CID); |
default: |
error("Invalid register number!"); |
break; |
} |
|
return 0; |
} |
|
/* Builds and returns register name. */ |
634,58 → 784,153
memcpy (valbuf, ®buf[REGISTER_BYTE (RV_REGNUM)], TYPE_LENGTH (valtype)); |
} |
|
/* The or1k cc defines the following |
prologue: |
00000000 <_proc1>: |
0: d7 e1 17 e4 l.sw 0xffffffe4(r1),r2 |
4: 9c 41 00 00 l.addi r2,r1,0x0 |
8: 9c 21 ff e8 l.addi r1,r1,0xffffffe8 |
c: d7 e2 1f f8 l.sw 0xfffffff8(r2),r3 |
10: d7 e2 27 f4 l.sw 0xfffffff4(r2),r4 |
14: 84 82 ff f8 l.lwz r4,0xfffffff8(r2) |
18: 9d 24 00 00 l.addi r9,r4,0x0 |
1c: 00 00 00 02 l.j 0x2 |
20: 15 00 00 00 l.nop |
/* CZ -- 25/09/01 -- The prologue handling code has been rewritten |
to bring it inline with the new C compiler and various changes |
that have been made. The code below expects to see various |
instructions that are identified by states. States are ordered |
and should flow from one to the next. If a state is encountered |
out of order, it is assumed to be function code and not |
prologue, so the prologue parsing is terminated. I've tried |
several real world tests from the C compiler, and this seems |
to recognize the transition from prologue to code even under |
a worst case (21 instructions) scenario. */ |
|
00000024 <_L2>: |
24: 84 41 ff fc l.lwz r2,0xfffffffc(r1) |
28: 48 00 58 00 l.jalr r11 |
2c: 9c 21 00 18 l.addi r1,r1,0x18 */ |
typedef enum { |
PrologueStateMachineStart, |
PrologueStateMachineFrameInitialized, |
PrologueStateMachineFrameSaved, |
PrologueStateMachineFrameAdjusted, |
PrologueStateMachineRegisterSaved, |
PrologueStateMachineParameterSaved, |
PrologueStateMachineInvalid, |
} FunctionPrologueStates; |
|
CORE_ADDR |
or1k_skip_prologue (CORE_ADDR pc) |
/* Parse the insn and save the arguments */ |
static FunctionPrologueStates getPrologueInsnType(unsigned long insn, |
int* arg1,int* arg2) |
{ |
unsigned long inst; |
CORE_ADDR skip_pc; |
CORE_ADDR func_addr, func_end; |
struct symtab_and_line sal; |
int i; |
int offset = 0; |
int code = insn >> 26; |
int state = PrologueStateMachineInvalid; |
int op1,op2; |
short offset; |
|
switch(code) |
{ |
case 0x27: /* l.addi */ |
op1 = (insn & 0x03E00000) >> 21; |
op2 = (insn & 0x001F0000) >> 16; |
if(op1 == 1 && op2 == 1) |
{ |
offset = insn & 0xFFFF; |
state = PrologueStateMachineFrameInitialized; |
} |
else if(op1 == 2 && op2 == 1) |
{ |
offset = insn & 0xFFFF; |
state = PrologueStateMachineFrameAdjusted; |
} |
*arg1 = op1; |
*arg2 = offset; |
break; |
case 0x35: /* l.sw */ |
op1 = (insn & 0x001F0000) >> 16; |
op2 = (insn & 0x0000F800) >> 11; |
offset = (insn & 0x000007FF) | |
((insn & 0x03E00000) >> 10); |
|
if(op1 == 1) |
state = (op2 == 2) ? PrologueStateMachineFrameSaved : |
PrologueStateMachineRegisterSaved; |
else if(op1 == 2) |
state = PrologueStateMachineParameterSaved; |
*arg1 = op2; |
*arg2 = offset; |
break; |
default: /* unknown */ |
break; |
} |
|
return state; |
} |
|
CORE_ADDR or1k_skip_prologue (CORE_ADDR pc) |
{ |
int frame_size = 0,i; |
FunctionPrologueStates state = PrologueStateMachineStart; |
CORE_ADDR t_pc; |
|
/* |
Maximum prologue: save even reg's 10-30 (11 insns) |
save params passed in regs (6 insns) |
adjust stack (1 insn), adjust frame (1 insn), |
save old frame pointer (1 insn), |
save old link register (1 insn) |
*/ |
static const int MAX_PROLOGUE_LENGTH = 21; |
|
for (i = 0; i < MAX_GPR_REGS; i++) |
or1k_saved_reg_addr[i] = -1; |
|
/* Is there a prologue? */ |
inst = or1k_fetch_instruction (pc); |
if (inst & 0xfc1ff800 != 0xd4011000) return pc; /* l.sw I(r1),r2 */ |
or1k_saved_reg_addr[2] = offset++; |
inst = or1k_fetch_instruction (pc + OR1K_INSTLEN); |
if (inst & 0xFFFF0000 != 0x9c410000) return pc; /* l.addi r2,r1,I */ |
pc += 2 * OR1K_INSTLEN; |
inst = or1k_fetch_instruction (pc); |
if (inst & 0xFFFF0000 != 0x9c210000) return pc; /* l.addi r1,r1,I */ |
pc += OR1K_INSTLEN; |
for(t_pc=pc; t_pc < (pc + MAX_PROLOGUE_LENGTH) && |
state != PrologueStateMachineInvalid; t_pc += OR1K_INSTLEN) |
{ |
unsigned long insn = or1k_fetch_instruction(t_pc); |
int reg; |
int offset; |
FunctionPrologueStates new_state = getPrologueInsnType(insn,®,&offset); |
|
/* Skip stored registers. */ |
inst = or1k_fetch_instruction (pc); |
while (inst & 0xfc1ff800 != 0xd4020000) /* l.sw 0x0(r2),rx */ |
{ |
/* get saved reg. */ |
or1k_saved_reg_addr[(inst >> 11) & 0x1f] = offset++; |
pc += OR1K_INSTLEN; |
inst = or1k_fetch_instruction (pc); |
switch(state) |
{ |
case PrologueStateMachineStart: |
if(new_state == PrologueStateMachineFrameInitialized) |
{ |
frame_size = -offset; |
or1k_saved_reg_addr[1] = frame_size; |
} |
else |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineFrameInitialized: |
if(new_state == PrologueStateMachineFrameSaved) |
or1k_saved_reg_addr[reg] = frame_size - offset; |
else if(new_state == PrologueStateMachineRegisterSaved) |
{ |
/* Ooops...we have a frameless function. |
Not sure what this might mean, but |
let's try and continue. */ |
or1k_saved_reg_addr[reg] = frame_size - offset; |
} |
else |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineFrameSaved: |
if(new_state != PrologueStateMachineFrameAdjusted && |
offset != frame_size) |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineFrameAdjusted: |
case PrologueStateMachineRegisterSaved: |
if(new_state == PrologueStateMachineRegisterSaved) |
or1k_saved_reg_addr[reg] = frame_size - offset; |
else if(new_state == PrologueStateMachineParameterSaved) |
or1k_saved_reg_addr[reg] = -offset; |
else |
new_state = PrologueStateMachineInvalid; |
break; |
case PrologueStateMachineParameterSaved: |
if(new_state == PrologueStateMachineParameterSaved) |
or1k_saved_reg_addr[reg] = -offset; |
else |
new_state = PrologueStateMachineInvalid; |
break; |
default: |
new_state = PrologueStateMachineInvalid; |
} |
|
state = new_state; |
} |
return pc; |
|
return t_pc; |
} |
|
/* Determines whether this function has frame. */ |
732,8 → 977,50
frame pointer. */ |
fp = FRAME_FP (frame); |
else |
fp = read_memory_integer (frame->frame, 4); |
{ |
unsigned long func_pc = get_pc_function_start(frame->pc); |
unsigned long insn = read_memory_integer(func_pc,4); |
int i; |
int offset = 0; |
|
/* The first instruction should be the number of bytes |
in our frame. If it isn't we're in trouble because |
the function is without a prologue... */ |
if(((insn & 0xFC000000) == 0x9C000000) && |
((insn & 0x03E00000) == 0x00200000) && |
((insn & 0x001F0000) == 0x00010000)) |
{ |
short off = insn & 0xFFFF; |
|
/* Look for the storage of the frame pointer in the |
function prologue.. */ |
for(i=1;i<20;i++) |
{ |
unsigned long insn = read_memory_integer(func_pc+4*i,4); |
|
/* If bits are 31 - 26 are %110101, |
and bits 20 - 16 are %00001, |
and bits 15 - 11 are %00010, |
then our frame pointer lies at the offset specified |
by bits [25-21][10-0]. */ |
|
int code = insn >> 26; |
int r1 = (insn & 0x001F0000) >> 16; |
int r2 = (insn & 0x0000F800) >> 11; |
int idx_h = (insn & 0x03E00000) >> 10; |
int idx = (insn & 0x000007FF) | idx_h; |
|
if(code == 0x35 && r1 == 1 && r2 == 2) |
{ |
offset = off + idx; |
break; |
} |
} |
} |
|
fp = read_memory_integer (frame->frame + offset, 4); |
} |
|
if (USE_GENERIC_DUMMY_FRAMES) |
{ |
CORE_ADDR fpp, lr; |
758,17 → 1045,44
{ |
int i; |
CORE_ADDR frame_addr; |
CORE_ADDR func_pc = get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET; |
int frame_size; |
int pc_found = 0; |
|
frame_saved_regs_zalloc (fi); |
|
/* Skip prologue sets or1k_saved_reg_addr[], we will use it later. */ |
or1k_skip_prologue (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); |
or1k_skip_prologue (func_pc); |
|
frame_size = or1k_saved_reg_addr[1]; |
or1k_saved_reg_addr[1] = -1; |
|
/* If the frame_size is less than 0, we have hit an assembly |
routine which we can't traverse beyond. Let's give up here, |
because attempting to continue will only lead to trouble. */ |
if(frame_size < 0) |
{ |
printf("Found a function without a prologue at 0x%08x\n",func_pc); |
printf("Frame pc was at 0x%08x\n",fi->pc); |
return; |
} |
|
for (i = 0; i < NUM_GPR_REGS + NUM_VF_REGS; i++) |
if (or1k_saved_reg_addr[i] >= 0) |
fi->saved_regs[i] = fi->frame + or1k_saved_reg_addr[i]; |
fi->saved_regs[i] = fi->frame - or1k_saved_reg_addr[i]; |
|
/* We want to make sure we fill in the PC with the value of the |
r9 register from the NEXT frame, and that the value of r1 is |
the correct value of r1 for the next frame, which can be |
calculated by adding the frame_size to the frame pointer. */ |
fi->saved_regs[1] = fi->frame - frame_size; |
|
if(fi->saved_regs[LR_REGNUM]) |
fi->saved_regs[PC_REGNUM] = read_memory_integer(fi->saved_regs[LR_REGNUM],4); |
else |
fi->saved_regs[PC_REGNUM] = read_register(LR_REGNUM); |
} |
|
|
static CORE_ADDR |
read_next_frame_reg (fi, regno) |
struct frame_info *fi; |
785,7 → 1099,12
if (fi->saved_regs == NULL) |
or1k_init_saved_regs (fi); |
if (fi->saved_regs[regno]) |
return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE); |
{ |
if(regno == SP_REGNUM || regno == PC_REGNUM) |
return fi->saved_regs[regno]; |
else |
return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE); |
} |
} |
} |
return read_register (regno); |
2176,9 → 2495,10
add_com ("spr", class_support, spr_command, "Set specified SPR register."); |
|
/* hwatch command. */ |
add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watchpoint.\n\ |
Example: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_var)&&($SDATA >= 50).\n\ |
See OR1k Architecture document for more info."); |
add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watch" |
"point.\nExample: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_" |
"var)&&($SDATA >= 50).\nSee OR1k Architecture document for more" |
" info."); |
|
/* htrace commands. */ |
add_prefix_cmd ("htrace", class_breakpoint, htrace_command, |
/trunk/gdb-5.0/gdb/config/or1k/tm-or1k.h
28,6 → 28,17
#include "defs.h" |
#include <inttypes.h> /* CZ */ |
|
/* CZ 11/09/01 -- Cause GDB to expect actual PC value to appear |
in breakpoint exception vector instead of being in PC itself */ |
|
#define NEW_PC_HANDLING |
|
#ifdef NEW_PC_HANDLING |
#define TARGET_READ_PC(pid) or1k_target_read_pc(pid) |
#define TARGET_WRITE_PC(pc,pid) or1k_target_write_pc(pc,pid) |
#endif |
|
|
struct value; |
|
struct struct_or1k_implementation |
144,6 → 155,21
#define PS_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 1) |
#define CCR_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 2) |
|
/*******************************************/ |
/* Added by CZ on 12/09/01 Used for new style breakpoints */ |
/* These really aren't designed to be seen by the user */ |
#define EPC_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 3) |
#define EAR_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 4) |
#define ESR_REGNUM (MAX_GPR_REGS + MAX_VF_REGS + 5) |
|
#define EPC_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP,32+cid) |
#define EAR_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP,48+cid) |
#define ESR_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP,64+cid) |
|
#define MAX_EXTRA_NUM_REGS 6 |
|
/******** END OF ADDITIONS BY CZ ************/ |
|
extern int or1k_regnum_to_sprnum PARAMS ((int regno)); |
#define REGNUM_TO_SPRNUM(regno) (or1k_regnum_to_sprnum(regno)) |
|
151,6 → 177,8
#define DMR1_ST (0x00400000) |
|
/* Changed by CZ 21/06/01 */ |
#define DRR_SS (0x00004000) |
#define DRR_TE (0x00002000) |
#define DRR_BE (0x00001000) |
#define DRR_SCE (0x00000800) |
#define DRR_RE (0x00000400) |
177,9 → 205,12
#define NUM_VF_REGS (or1k_implementation.num_vfpr_regs) |
#define MAX_VF_REGS (32) |
|
/*******************************/ |
/* Paramterized by CZ 11/09/01 */ |
/*******************************/ |
/* gdb mapping of registers */ |
#ifndef NUM_REGS |
#define NUM_REGS (MAX_GPR_REGS+MAX_VF_REGS+3) |
#define NUM_REGS (MAX_GPR_REGS+MAX_VF_REGS+MAX_EXTRA_NUM_REGS) |
#endif |
|
/* Can act like a little or big endian. */ |
270,11 → 301,23
/* Amount PC must be decremented by after a breakpoint. |
This is often the number of bytes in BREAKPOINT |
but not always. */ |
#define DECR_PC_AFTER_BREAK 0 |
|
/* Amount PC must be decremented by after a breakpoint. |
This is often the number of bytes in BREAKPOINT |
but not always. */ |
/* Note: several attempts have been made to account for |
differences between hardware and software breakpoints |
and still allow hardware breakpoints to advance the |
PC beyond the offending instruction. However, short |
of rewriting gdb, none of them seem to work. Thus, |
for now, we assume that a hardware breakpoint will |
always give control to the breakpoint vector BEFORE |
it executes the instruction, thus, when the breakpoint |
vector returns, it will return to the same instruction |
that caused the exception (and thus hit the exception |
again if it hasn't been cleared) Note that if it actually |
executes this instruction, things fail bandly inside of |
gdb. This should not be an issue for now, as the or1200 |
implementation will not implement hardware breakpoints |
at all.. */ |
|
#define DECR_PC_AFTER_BREAK 0 |
|
extern int or1k_insert_breakpoint (CORE_ADDR addr, char *contents_cache); |
319,7 → 362,7
/* Given a name (SIGHUP, etc.), return its signal. */ |
extern enum target_signal or1k_signal_from_name PARAMS ((char *)); |
|
#define NUM_OR1K_SIGNALS (10) |
#define NUM_OR1K_SIGNALS (14) |
|
/* Extract from an array REGBUF containing the (raw) register state |
a function return value of type TYPE, and copy that, in virtual format, |
357,6 → 400,7
#define SKIP_PROLOGUE(pc) (or1k_skip_prologue (pc)) |
|
/* FRAMES */ |
|
#define FRAME_ARGS_ADDRESS(fi) (fi)->frame |
|
#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame |
411,7 → 455,7
/* Is floating/vector unit present. */ |
#define OR1K_VF_PRESENT (or1k_implementation.vf_present) |
|
#define INIT_FRAME_PC /* Not necessary */ |
/* #define INIT_FRAME_PC */ /* Not necessary */ |
|
/* Stack grows downward. */ |
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs)) |