📄 nios_germs_monitor.s
字号:
; --------------------------
; File: nios_germs_monitor.s
;
; Contents: a Nios monitor,
; this one with S-Record, I-Hex
; records, and Flash Programming
; for the Nios development board.
;
;
; GermsMon is build-time configurable to
; support various Nios configurations.
; The following variables control
; how it's built:
;
; GM_UARTBase -- base of the uart for output, presumed
; to be Nios compatible registers
;
; GM_FlashBase,
; GM_FlashTop --
; The flash to support, unless FlashTop is zero,
; which means "no flash". The flash is presumed
; to be AMD 29LV800, as on the Nios reference design.
; Other AMD flashes might be compatible.
;
; GM_FlashExec --
; The address in flash to check for the Nios
; signature "Ni". Reference design uses
; 0x14000c. If the signature is found, execution
; is transferred to GM_FlashExec - 0x0c. If
; GM_FlashExec is zero, the feature is disabled.
; GM_PIO --
; The pio to check bit zero of before executing
; from flash.
;
; GM_VectorTable --
; Interrupt vector table base
;
; GM_Clear1Base,GM_Clear1Register,
; GM_Clear2Base,GM_Clear2Register,
; GM_Clear3Base,GM_Clear3Register --
; Up to three addresses which are cleared
; when GermsMon starts up. These can be
; used to disable interrupts on peripherals,
; and such.
;
; To set a variable, include the directive
;
; --defsym GM_whatever=value
;
; on the assembler's command line. With nios-build, include
; the directive
;
; -as "--defsym GM_whatever=value"
;
;
.include "nios.s"
.ifndef GM_UARTBase
.ifdef nasys_printf_uart
.equ GM_UARTBase,nasys_printf_uart
.else
#
# If there's no UART defined, we'll compile
# as IF the uart address is 0x0000.
# This, of course, won't be a functioning
# monitor, but, hey, there's no UART. What
# were you expecting?
# At least it puts some bytes in your
# ROM, and you can see what code looks like.
#
#.equ GM_UARTBase,0
# !!!
# The above comment is obsolete, but is preserved here
# for future generations to look upon, and marvel.
# See the bottom of this file for the code that's generated
# when no UART exists.
# !!!
.endif
.endif
.ifndef GM_FlashBase
.ifdef nasys_main_flash
.equ GM_FlashBase,nasys_main_flash
.endif
.endif
.ifdef GM_FlashBase
.ifndef GM_FlashTop
.ifdef nasys_main_flash_end
.equ GM_FlashTop,nasys_main_flash_end
.else
.equ GM_FlashTop,GM_FlashBase+0x100000
.endif
.endif
.ifndef GM_FlashExec
.equ GM_FlashExec,GM_FlashBase+0x4000C
.endif
.endif
.ifndef GM_StackTop
.equ GM_StackTop,nasys_stack_top
.endif
.ifndef GM_VectorTable
.equ GM_VectorTable,nasys_vector_table
.endif
.ifndef GM_PIO
.ifdef na_button_pio
.equ GM_PIO,na_button_pio
.endif
.endif
.ifndef GM_WIDTHS
.equ GM_WIDTHS,1
.endif
;-----------------------------------------
; A simple macro that stores a 16 bit
; word on either the nios32 or nios16
; It uses %g0 (%r0), no foolin!
.macro G_ST16 rDst,rSrc
.ifdef __nios32__
FILL16 %r0,\rSrc
ST16d [\rDst],%r0
.else
ST [\rDst],\rSrc
.endif
.endm
;
; Mostly, this is one big goto-tangle.
;
; No RAM used
;
; Global Register Usage:
;
; %l0: UART Base Address
; %g5: the value 0x0000000F
; %g6: the value 0x00000003 for masking addresses
; %g7: residual byte for writing to Flash in words
; %g0,%g1: Any routine's scratch
; %g3 : number of bytes read by getHex routine
; %l1-%l2: Any routine's scratch
; %o5: stashed return address
;
; %l3: Upper bytes (or segment) for I-Hex records
;
; %l4: Force-to address for S-Records/I-Hex records
; This gets set by an F command
;
; %l5: Address to read next from <CR>
; %i3: How many words to display on CR
;
; --------------
; During S-Record read
; %i0 record type
; %i1 record length in bytes
; %i2 address we're reading bytes into
;
;
; -------------------------------
; Commands:
; G<address> Go at address
; E<address> Erase flash at address
; R<address>-<address> Relocate S-Records from-to
; M<address> Display at address
; M<address>-<address> Display range
; M<address>:val val... Write at attress
; M<address>-<address> Display range
; S... S-record, no error checking
; :... Intel-Hex record, no error checking
.text
.global _start
_start:
PFX 8
WRCTL %g0
.ifdef GM_UARTBase
; (previous germs monitors cleared the vector table
; here, but it's more useful to be able to still
; see it after you finish. Also, every byte is
; precious, to keep it under 1k bytes! so its gone.)
;
; Reset UART, SwitchPIO, and Timers
;
MOVIP %l0,GM_UARTBase ; we'll keep this...
MOVI %g0,0
STP [%l0,np_uartcontrol],%g0 ; control all 0's: no irq's
;
; Clear some registers (presumably
; to disable interrupts)
;
.ifdef GM_Clear1Base
MOVIP %l1,GM_Clear1Base
STP [%l1,GM_Clear1Register],%g0
.endif
.ifdef GM_Clear2Base
MOVIP %l1,GM_Clear2Base
STP [%l1,GM_Clear2Register],%g0
.endif
.ifdef GM_Clear3Base
MOVIP %l1,GM_Clear3Base
STP [%l1,GM_Clear3Register],%g0
.endif
.ifdef GM_PIO
MOVIP %l1,GM_PIO
STP [%l1,np_piointerruptmask],%g0
.endif
;
; Set CWP to top, and IRQ to bottom
;
PFX 2
RDCTL %g0
LSRI %g0,1 ; HI_LIMIT in correct bit position
; Also, the topmost bit IS zero now, after LSR
ORIP %g0,0x7e0f ; I_PRI set to 63, NZVC all true (why not)
WRCTL %g0
;
; Set the stack pointer
;
.ifdef GM_StackTop
MOVIP %sp,GM_StackTop
.endif
;
; Look for Signature in flash, & jump there.
;
.ifdef GM_PIO
LDP %g0,[%l1,np_piodata] ; Unless the button is pressed
IF0 %g0,0
BR postFlash_start
.endif
.ifdef GM_FlashTop
MOVIP %l2,GM_FlashExec ; 2nd quadrant of four, in flash, + 0xC
LD %g0,[%l2]
.ifdef __nios32__
EXT16d %g0,%l2
.endif
CMPIP %g0,'N'+(256*'i')
IFS cc_ne
BR postFlash_start
SUBI %l2,0x000c
LSRI %l2,1
CALL %l2 ; (if it wants to return, no problem!)
.endif
postFlash_start:
NOP ; clears out possible delay-slot PFX's
;; We end up here upon exit of a user-program run with the 'G'
;; command. User-programs can do -anything-, including exitng
;; with interrupts left running. This is inconvenient when
;; using the monitor. Disable CPU interrupts as a defensive measure.
PFX 8
WRCTL %g0
;
; Registers which need certain
; values for the rest of the monitor
; to work.
; (Other registers are used as
; needed, although their reservations
; for certain uses must be respected
; while running.)
MOVIP %l0,GM_UARTBase
MOVI %g5,0x0f
MOVI %g6,0x03
BSR PutHash ; but up here, so delay slot is used.
; Initial safe values
MOVI %l3,0
MOVI %l4,0
MOVI %l5,0 ; # address to show on <CR>
MOVIP %i3,32 ; # words to show on <CR>
.ifndef __timeStamp__
.equ __timeStamp__,0
.endif
MOVIP %o1,__timeStamp__
BSR PutHex
NOP
PFX 6
RDCTL %o1
BSR PutHex
NOP
BSR PutChar
MOVI %o0,13
#
# Print the system name GM_SystemName, if defined
#
BR pastSystemNameString
NOP
systemNameString:
nm_monitor_string ; include monitor name string
.align 1 ; align by 2^n
pastSystemNameString:
MOVIA %i2,systemNameString
printSystemNameLoop:
LD %o0,[%i2]
EXT8d %o0,%i2
IFRz %o0
BR donePrintSystemNameLoop
NOP
BSR PutChar
ADDI %i2,1
BR printSystemNameLoop
NOP
donePrintSystemNameLoop:
BSR PutChar
MOVI %o0,13
ReceiveCommand:
MOVIP %o0,'+'
BSR PutChar
NOP
BSR GetChar
NOP
CMPIP %o0,0x0060 ; character from [60,7f]
IFS cc_ge ; mapped down to [40,5f]
ANDNIP %o0,0x0020
SUBIP %o0,13
IFRz %o0
BR doCR
SUBIP %o0,'#'-13 ; '#' (hash) is for comments: ignore to EOL
IFRz %o0
BR happyWaitForEOL
SUBIP %o0,':'-'#'
IFRz %o0
BR doColon
SUBIP %o0,'E'-':'
IFRz %o0
BR doE
SUBIP %o0,'G'-'E'
IFRz %o0
BR doG
SUBIP %o0,'M'-'G'
IFRz %o0
BR doM
SUBIP %o0,'R'-'M'
IFRz %o0
BR doR
SUBIP %o0,'S'-'R'
IFRz %o0
BR doS
NOP
errorWaitForEOL:
BSR WaitForEOL
NOP
MOVIP %o0,'?' ; Unknown Command
BSR PutChar
NOP
BSR PutChar
MOVI %o0,13
BR ReceiveCommand
NOP
doColon:
; First 2 chars: record length, for data only
BSR GetHexBytes
MOVI %o3,1 ; (delay slot) Fetch record length
MOV %i1,%o1 ; record length stashed
;
; Next 4 chars: address offset
;
BSR GetHexBytes
MOVI %o3,2 ; (delay slot) we want 2 byte/4 chars of hex)
MOV %i2,%l3 ; Get most recent upper-bytes address
OR %i2,%o1 ; construct full address into %i2
; Get record type
;
BSR GetHexBytes
MOVI %o3,1 ; (delay slot) 1 byte/2 chars for record type
IFRz %o1
BR doSReadData ; same code as reading S-Record data
CMPI %o1,4 ; I-Hex 4 sets upper bits of destination address
IFS cc_ne
BR doColonNot4
NOP
BSR GetHexBytes
MOVI %o3,2 ; (delay slot) upper 16 bits is 2 bytes worth
LSLI %o1,16
MOV %l3,%o1 ; and save the upper bits there...
doColonNot4:
BR happyWaitForEOL
NOP
;------------------------
; M Command
; M<addr> show 16 bytes
; M<addr>-<addr> show range
; M<addr>:val val val write values to addr
; M<addr>-<addr>:val fill range
;
doM:
MOVIP %o2,':'
BSR GetHexUntil
NOP
;
; Write operation?
;
CMPIP %o0,':'
IFS cc_eq
BR doMWrite
NOP
;
; If showing range, compute it...
;
IFRnz %o4
BR doMShowRange
NOP
;
; Show %i3 words... bytes
;
MOV %l5,%o1
BR doCR
;
; Show Range
; Show from %o4 to %o1, inclusive
;
doMShowRange:
MOV %o3,%o1
SUB %o3,%o4
LSRI %o3,1 ; o3 = # words
MOV %i3,%o3 ; if they hit return, they get this many, again
MOV %l5,%o4 ; use %l5 to walk the addresses
doCR:
MOV %o3,%i3 ; <CR> shows %i3 words from %l5
doMShowRangeLine:
;
; Come here with %o3 = #words to show, %l5 = address to show
;
MOVI %l6,8 ; countdown for this line
; Print #addr:
BSR PutHash ; (watch out for delay slot)
;
; print the address
;
.ifdef __nios32__
; nios32? Show upper 16 bits of address first.
MOV %o1,%l5
LSRI %o1,16
SKPRz %o1
BSR PutHex
NOP
.endif
MOV %o1,%l5
BSR PutHex
NOP
MOVIP %o0,':'
BSR PutChar
NOP
BSR PutChar
BGEN %o0,5 ; (delay slot) hex 0x20 = space
doMShowRangeLoop:
LD %o1,[%l5]
BSR PutHex
.ifdef __nios32__
EXT16d %o1,%l5 ; (delay slot)
.else
NOP ; (delay slot)
.endif
MOVIP %o0,' '
BSR PutChar
;
; Bump address and decrement to-show count
;
ADDI %l5,2
SUBI %o3,1
IFS cc_le
BR doneMCR
; See if it's time for a newline
SUBI %l6,1
IFRnz %l6
BR doMShowRangeLoop
NOP
BSR PutChar
MOVI %o0,13 ; (delay slot)
BR doMShowRangeLine
NOP
doneMCR:
BSR PutChar
MOVI %o0,13 ; (delay slot)
BR ReceiveCommand
NOP
doMWrite:
IFRnz %o4
BR doMFill
MOV %l5,%o1 ; (delay slot, sometimes) start for next <CR> show
;
; Write space-separated values until CR
;
MOV %i2,%o1
doMWriteLoop:
MOVIP %o2,' '
BSR GetHexUntil
MOVI %g3,0 ; (GetHexUntil needs this to count bytes)
MOV %l7,%o0 ; save the break-character...
.if GM_WIDTHS
; decide which kind of write to do: 8, 16, or 32
CMPI %g3,2
IFS cc_eq
BR doMWrite16
NOP
.ifdef __nios32__
IFS cc_lt
BR doMWrite8
NOP
BR doMWrite_did
ST [%i2],%o1
.endif
doMWrite8:
BSR StashByte
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -