📄 nios_gdb_stub_isr.s
字号:
;
; Assembly language portions of Nios GDB Stub
;
; Stack set up, register clearing, all kinds of
; clever things.
;
.include "nios.s"
.ifdef ETHER_DEBUG
.ifdef na_enet
.equ ethernet_exists, 1
.endif
.endif
; Manual additions .. - AF 9/4/2000
; Eventually these items will be in the SDK.
GEQU na_BreakpointTrap , 3
GEQU na_SingleStepTrap , 4
; End of manual additions.
;
; Word size (32-bit) offsets
; for register storage
;
.equ gdbRegistersGeneral,0
.equ gdbRegistersPC,32
.ifdef __nios32__
.equ gdbRegistersCtl0Ctl1,33
.equ gdbRegistersCtl2Ctl3,34
.equ gdbTrapNumber,35 ; ISR can report trap number here
.else
.equ gdbRegistersCtl0,34
.equ gdbRegistersCtl1,35
.equ gdbRegistersCtl2,36
.equ gdbRegistersCtl3,37
.equ gdbTrapNumber,38
.endif
.text
.global StubBreakpointHandler
.global StubHarmlessHandler
.global StubButtonHandler
.global StubHWBreakpointHandler
.global GDBMain
.ifdef ETHER_DEBUG
.ifdef ethernet_exists
.comm _gdb_stub_stack,8192,4 ; Local stack, statically allocated.
.equ gdbStubStacktop,_gdb_stub_stack+7936
.else
.comm _gdb_stub_stack,1024,4 ; Local stack, statically allocated.
.equ gdbStubStacktop,_gdb_stub_stack+992
.endif
.else
.comm _gdb_stub_stack,1024,4 ; Local stack, statically allocated.
.equ gdbStubStacktop,_gdb_stub_stack+992
.endif
;
; If nios_gdb_install(0) is invoked, the stub is present,
; and linked in, but harmless. This, so that you can "turn off"
; the debugger with minimal change in your code footprint.
;
; This is the harmless breakpoint handler.
StubHarmlessHandler:
TRET %o7 ; pretty darned minimal. Better stuff below.
; StubUart Handler checks to see if we are getting a stop requrest from the
; host. If we are it jumps directly to the breakpoint stub. Otherwise
; it returns after clearing the interrupt
.ifdef nasys_debug_uart
.equ gdbBreakChar,0x3
.global StubUartHandler
StubUartHandler:
;verify Rx interrupt
MOVIA %l0, nasys_debug_uart
LDP %l1, [%l0,np_uartcontrol]
SKP0 %l1, np_uartcontrol_irrdy_bit
BR StubUartRx
NOP
TRET %o7
StubUartRx:
LDP %l1, [%l0,np_uartrxdata] ;clears interrupt bit
CMPI %l1, gdbBreakChar
SKPS cc_nz
BR StubBreakpointHandler
NOP
TRET %o7
.endif
;
; The Hardware Breakpoint needs to do a few additional thing
; before it enters the regular breakpoint handler
.if nasys_debug_core
StubHWBreakpointHandler:
; write to stop register to halt trace
MOVI %l1, 9 ;np_debug_stop register
PFX 3
WRCTL %l1
PFX 4
WRCTL %l1
; now PASS THROUGH to the normal breakpoint handler
; NO BRANCH HERE
; DON'T INSERT CODE BELOW
.endif
;
; When we get here, in response to
; a breakpoint (trap 3 poked into code),
; we need to save the state of all the registers,
; every last one! So we can restore them, you see,
; and then set up to call the debugger. Major
; context switching here! Neat, eh?
;
; We arrive here with CWP down 1 from
; its authentic state (fortunately!)
;
; the %l's and %o's are all ours
; down here. again, fortunately.
;
; We save the current interruptee's
; registers into the register structure
; that the C portion uses.
;
; Then, after popping CWP up one level,
; we reenable interrupts, and jump
; to the debugger's main.
;
; With interrupts enabled, the CWP manager will
; operate normally; if an underflow occurs, registers
; from the debugged program will get stored in
; their own local stack frame, since their own %sp's
; are used for the task. The debugger's will
; go in its own frame.
;
StubBreakpointHandler:
.if nasys_debug_core
; if there is a deubbing peripheral,
; me must stop it on interrupt
; write to stop register to halt trace
MOVI %l1, 9 ;np_debug_stop register
PFX 3
WRCTL %l1
PFX 4
WRCTL %l1
.endif
;
; Save the globals first.
; Then, when we up the CWP, they're
; ours to play with a bit.
;
MOVIA %l0,gdb ; g is the C side's globals. starts with registers.
STP [%l0,0],%g0
STP [%l0,1],%g1
STP [%l0,2],%g2
STP [%l0,3],%g3
STP [%l0,4],%g4
STP [%l0,5],%g5
STP [%l0,6],%g6
STP [%l0,7],%g7
;
; Save the %o registers, which
; appear to us, down here, as
; %i registers
;
STP [%l0,8],%i0
STP [%l0,9],%i1
STP [%l0,10],%i2
STP [%l0,11],%i3
STP [%l0,12],%i4
STP [%l0,13],%i5
STP [%l0,14],%i6
STP [%l0,15],%i7
;
; Read the trap number from CTL0, store in struct
;
RDCTL %g4
LSRI %g4,9
ANDIP %g4,0x3f
PFX gdbTrapNumber
ST [%l0],%g4
;
; Read and pack the control
; registers. Annoyingly, they
; are shorts.
;
; But we never *really* know
; what was in CTL1. In fact,
; we're going to report CTL1
; as zero, and read CTL1 and
; use it for the returned value
; of CTL0, since thats what it was.
; Clear? Good!
PFX 1
RDCTL %g0 ; will pretend to be ctl0 (low) and ctl 1(zeroes) high
.ifdef __nios32__
PFX gdbRegistersCtl0Ctl1
ST [%l0],%g0
.else
PFX gdbRegistersCtl0
ST [%l0],%g0
PFX gdbRegistersCtl1
ST [%l0],%g0
.endif
;
; Silly to save these two, they're fixed, but they're
; in the vars, so ok.
;
PFX 2
RDCTL %g1
.ifdef __nios32__
PFX 3
RDCTL %g0
LSLI %g0, 16
OR %g0, %g1
PFX gdbRegistersCtl2Ctl3
.else
PFX gdbRegistersCtl2
ST [%l0],%g1
PFX 3
RDCTL %g0
PFX gdbRegistersCtl3
.endif
ST [%l0],%g0
;
; Save the %pc register, which
; is now in %o7 cut in half
;
LSLI %o7,1
CMPI %g4,na_SingleStepTrap ; %g4 = trap number we got, now
IFS cc_le
SUBI %o7,2 ; back it up one, to before the breakpoint, if breakpoint or step
PFX gdbRegistersPC
ST [%l0],%o7
;
; Ascend the CWP, and grab
; the last %l's and %i's
;
MOV %g0,%l0
RESTORE
PFX 16 ; save %l0 first, so we can use it for the rest
ST [%g0],%l0
MOV %l0,%g0
STP [%l0,17],%l1
STP [%l0,18],%l2
STP [%l0,19],%l3
STP [%l0,20],%l4
STP [%l0,21],%l5
STP [%l0,22],%l6
STP [%l0,23],%l7
STP [%l0,24],%i0
STP [%l0,25],%i1
STP [%l0,26],%i2
STP [%l0,27],%i3
STP [%l0,28],%i4
STP [%l0,29],%i5
STP [%l0,30],%i6
STP [%l0,31],%i7
PFX 9
WRCTL %g0 ; enable traps (below 3, for cwp underflow action)
NOP
; JMB - Before execute GDBMain, we need to flush the register file to the stack
; for call trace visibility. Do this on the user stack, cuz our stack is minimal
; The global registers are ours, and nothing happens to them on save, so lets use them.
;First get the CWP
RDCTL %g0
LSRI %g0, 4
MOVI %g2, 0x1f
AND %g0, %g2
;Now get the LO_LIMIT
PFX 2
RDCTL %g1
AND %g1, %g2
;Now calculate how many times to save/restore
SUB %g0, %g1
MOV %g1, %g0
GDBSaveLoop:
SAVE %sp, -23
nop
SUBI %g0, 1
SKPS cc_mi
BR GDBSaveLoop
NOP
GDBRestoreLoop:
RESTORE
nop
SUBI %g1, 1
SKPS cc_mi
BR GDBRestoreLoop
NOP
;
; Now, everything is saved.
; If we set ctl0 and ctl1
; from the gdb globals, we
; can restore the registers
; as they were, and use
; a TRET to bump the CWP
; at the same time that we
; jump somewheres.
;
; So what we shall like to
; do now is set up the
; local stack and stuff
; to call into the debugger!
;
MOVIA %sp,gdbStubStacktop
;
; We CALL to our debugger, so
; that we can ensure it balances
; its calling sequence before
; returning here. Once back, we'll
; unwind all the trickery we've
; done, and TRET
;
MOVIA %g0,GDBMain@h
CALL %g0
NOP
;
; Zero'th order, as we say, is to disable interrupts.
;
PFX 8
WRCTL %g0 ; disable interrupts.
;
; We're back. We assume nothing; everything
; may have changed. "Everything" of course
; means the state of the memory, and the
; state of the registers in the GDB globals.
;
; We'll start by instantiating CTL0 and CTL1
; from those globals, bump down a level, tinker
; a bit more, and TRET.
;
MOVIA %g0,gdb ; g is the C side's globals. starts with registers.
.ifdef __nios32__
PFX gdbRegistersCtl0Ctl1
.else
PFX gdbRegistersCtl0
.endif
LD %g1,[%g0]
; CTL0 in the low 16 bits; the high 16 bits are CTL1 which we hate
; And yet, we'll write them into CTL1, so that the TRET
; puts them back for real.
.ifdef __nios32__
EXT16s %g1,0 ; clear the upper 16 bits
.endif
PFX 1
WRCTL %g1
;
; And to start, we shall set CWP to where
; we'll return to, and restore what we can
; the one we're gonna return to
; with interrupts carefully disabled
;
ANDIP %g1,0x00007fff ; mask off TE bit
WRCTL %g1
MOV %l0,%g0 ; %l0 --> C globals now, for restoring registers
; restore %i registers
LDP %i0,[%l0,24]
LDP %i1,[%l0,25]
LDP %i2,[%l0,26]
LDP %i3,[%l0,27]
LDP %i4,[%l0,28]
LDP %i5,[%l0,29]
LDP %i6,[%l0,30]
LDP %i7,[%l0,31]
; restore %l registers
LDP %l7,[%l0,23]
LDP %l6,[%l0,22]
LDP %l5,[%l0,21]
LDP %l4,[%l0,20]
LDP %l3,[%l0,19]
LDP %l2,[%l0,18]
LDP %l1,[%l0,17]
LDP %l0,[%l0,16] ; %l0 kills itself!
;
; Bump CWP down 1, so we have some %l to play with
;
SAVE %sp,0
MOV %l0,%g0
; Restore %o's (visible from down here as %i's)
LDP %i0,[%l0,8]
LDP %i1,[%l0,9]
LDP %i2,[%l0,10]
LDP %i3,[%l0,11]
LDP %i4,[%l0,12]
LDP %i5,[%l0,13]
LDP %i6,[%l0,14]
LDP %i7,[%l0,15]
; restore %g's
LDP %g0,[%l0,0]
LDP %g1,[%l0,1]
LDP %g2,[%l0,2]
LDP %g3,[%l0,3]
LDP %g4,[%l0,4]
LDP %g5,[%l0,5]
LDP %g6,[%l0,6]
LDP %g7,[%l0,7]
;
; Set up local %o7, from PC, for TRET
; (Could use any register, but
; %o7 is ours, and it's traditional.)
;
PFX gdbRegistersPC
LD %o7,[%l0]
LSRI %o7,1
.if nasys_debug_core
; if there is a deubbing peripheral,
; me must start it before returning
; write to stop register to halt trace
MOVI %l1, 8 ;np_debug_start register
PFX 3
WRCTL %l1
PFX 4
WRCTL %l1
.endif
;
;
; I'm so glad we had this time together,
; Just to have a laugh or sing a song.
; Seems we just get started and before you know it
; Comes the time we have to say, "So long."
; Carol Burnett, 1967
;
TRET %o7 ; so long!
; end of file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -