URL
https://opencores.org/ocsvn/rf6809/rf6809/trunk
Subversion Repositories rf6809
[/] [rf6809/] [trunk/] [software/] [boot/] [boot_rom.asm] - Rev 21
Compare with Previous | Blame | View Log
; ============================================================================
; __
; \\__/ o\ (C) 2013-2022 Robert Finch, Waterloo
; \ __ / All rights reserved.
; \/_// robfinch<remove>@opencores.org
; ||
;
;
; BSD 3-Clause License
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;
; 1. Redistributions of source code must retain the above copyright notice, this
; list of conditions and the following disclaimer.
;
; 2. Redistributions in binary form must reproduce the above copyright notice,
; this list of conditions and the following disclaimer in the documentation
; and/or other materials provided with the distribution.
;
; 3. Neither the name of the copyright holder nor the names of its
; contributors may be used to endorse or promote products derived from
; this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;
; ============================================================================
;
OPT include "d:\cores2022\rf6809\software\boot\mon_equates.asm"
OPT include "d:\cores2022\rf6809\software\boot\io_equates.asm"
OPC_SWI EQU $03F
ScreenLocation EQU $10
ColorCodeLocation EQU $14
ScreenLocation2 EQU $18
BlkcpySrc EQU $1C
BlkcpyDst EQU $20
Strptr EQU $24
PICptr EQU $28
; Forth Area
; 0x30-0x60
; Task control blocks, room for 256 tasks
TCB_NxtRdy EQU $00 ; next task on ready / timeout list
TCB_PrvRdy EQU $04 ; previous task on ready / timeout list
TCB_NxtTCB EQU $08
TCB_Timeout EQU $0C
TCB_Priority EQU $10
TCB_MSGPTR_D1 EQU $14
TCB_MSGPTR_D2 EQU $18
TCB_hJCB EQU $1C
TCB_Status EQU $1E
TCB_CursorRow EQU $20
TCB_CursorCol EQU $21
TCB_hWaitMbx EQU $22 ; handle of mailbox task is waiting at
TCB_mbq_next EQU $24 ; mailbox queue next
TCB_mbq_prev EQU $28 ; mailbox queue previous
TCB_iof_next EQU $2C
TCB_iof_prev EQU $30
TCB_SPSave EQU $34 ; TCB_SPSave area
TCB_mmu_map EQU $38
KeybdHead EQU $FFFFFC800
KeybdTail EQU $FFFFFC900
KeybdEcho EQU $FFFFFCA00
KeybdBad EQU $FFFFFCB00
KeybdAck EQU $FFFFFCC00
KeybdLocks EQU $FFFFFCD00
KeybdBuffer EQU $FFFFFC000 ; buffer is 16 chars
BIOS_SCREENS EQU $17000000 ; $17000000 to $171FFFFF
; EhBASIC vars:
;
NmiBase EQU $FFC013
IrqBase EQU $FFC014
IOFocusNdx EQU $100
; These variables in global OS storage area
IOFocusList EQU $FFC000 ; to $FF000F
IOFocusID EQU $FFC010
IrqSource EQU $FFC011
IRQFlag EQU $FFC012
RunningID EQU $FFC013
milliseconds EQU $FFC014
; One copy of serial buffer management
; 1 serial buffer for system.
SerHeadRcv EQU $FFC015
SerTailRcv EQU $FFC016
SerHeadXmit EQU $FFC017
SerTailXmit EQU $FFC018
SerRcvXon EQU $FFC019
SerRcvXoff EQU $FFC01A
SerRcvBuf EQU $FFB000 ; 4kB serial recieve buffer
; Top of boot stack is at $FFC0FF
; These variables use direct page access
CursorRow EQU $110
CursorCol EQU $111
CharColor EQU $112
ScreenColor EQU $113
CursorFlash EQU $114
KeyState1 EQU $120
KeyState2 EQU $121
KeyLED EQU $122
KeybdID EQU $124
KeybdBlock EQU $126
kbdHeadRcv EQU $127
kbdTailRcv EQU $128
kbdFifo EQU $40 ; in local RAM
kbdFifoAlias EQU $C00040 ; to $C0007F ; alias for $40 to $7F
SerhZero EQU $130
SertZero EQU $132
farflag EQU $15F
asmbuf EQU $160 ; to $17F
QNdx0 EQU $780
QNdx1 EQU QNdx0+2
QNdx2 EQU QNdx1+2
QNdx3 EQU QNdx2+2
QNdx4 EQU QNdx3+2
FreeTCB EQU QNdx4+2
TimeoutList EQU FreeTCB+2
FreeMbx EQU RunningTCB + 2
nMailbox EQU FreeMbx + 2
FreeMsg EQU nMailbox + 2
nMsgBlk EQU FreeMsg + 2
CharOutVec EQU $800
CharInVec EQU $804
CmdPromptJI EQU $808
MonErrVec EQU $80C
BreakpointFlag EQU $810
NumSetBreakpoints EQU $811 ; to 812
Breakpoints EQU $820 ; to $82F
BreakpointBytes EQU $830 ; to $83F
mon_vectb EQU $880
; Register save area for monitor
mon_DSAVE EQU $900
mon_XSAVE EQU $902
mon_YSAVE EQU $904
mon_USAVE EQU $906
mon_SSAVE EQU $908
mon_PCSAVE EQU $90A
mon_DPRSAVE EQU $90E
mon_CCRSAVE EQU $90F
mon_numwka EQU $910
mon_r1 EQU $920
mon_r2 EQU $924
jmpvec EQU $928
mon_init EQU $92C
mon_retflag EQU $930
; The ORG directive must set an address a multiple of 4 in order for the Verilog
; output to work correctly.
org $FFD0AC
nop
nop
nop
XBLANK
ldb #' '
lbsr OUTCH
rts
org $FFD0D0
nop
nop
CRLF
CRLF1:
ldb #CR
lbsr OUTCH
ldb #LF
lbsr OUTCH
rts
org $FFD0F0
nop
bra CRLF1
org $FFD1DC
ONEKEY
jmp [CharInVec]
org $FFD2C0
nop
LETTER
lbsr OUTCH
rts
org $FFD2CC
nop
nop
HEX2
lbsr DispByteAsHex
rts
HEX4
lbsr DispWordAsHex
rts
org $FFD300
ClearScreenJmp
lbra ClearScreen
org $FFD308
HomeCursorJmp
lbra HomeCursor
org $FFD400
; Local RAM test routine
; Checkerboard testing.
; There is 70kB of local RAM
; Does not use any RAM including no stack
ramtest:
ldy #0
lda #1
sta LEDS
ldd #$AAA555
ramtest1:
std ,y++
cmpy #$8000
blo ramtest1
; now readback values and compare
ldy #0
ramtest3:
ldd ,y++
cmpd #$AAA555
bne ramerr
cmpy #$8000
blo ramtest3
lda #2
sta LEDS
jmp ,u
ramerr:
lda #$80
sta LEDS
ldb COREID
cmpb #$20
beq ramerr1
ldx #TEXTSCR
abx
lda #'F'
sta ,x
sync
ramerr1:
jmp ,u
org $FFE000
FDB Monitor
FDB DumRts ; NEXTCMD
FDB INCH
FDB INCHE
FDB INCHEK
FDB OUTCH
FDB PDATA
FDB PCRLF
FDB PSTRNG
FDB DumRts ; LRA
FDB DumRts
FDB DumRts
FDB DumRts
FDB DumRts ; VINIZ
FDB DisplayChar ; VOUTCH
FDB DumRts ; ACINIZ
FDB DumRts ; AOUTCH
DumRts:
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
start:
lda #$FFF ; all cores can do this
sta VIA+VIA_DDRA
lda #$55 ; see if we can at least set LEDs
sta LEDS
lda #1 ; prime OS semaphore
sta OSSEMA+$1000
sta OUTSEMA+$1000
ldu #st6 ; U = return address
; jmp ramtest ; JMP dont JSR
st6:
lds #$6FFF ; boot up stack area
lda COREID
cmpa #FIRST_CORE
; beq st8
; sync ; halt cores other than 2
st8:
; bne skip_init
; bsr romToRam
; ldd #st7 & $FFFF
; tfr d,x
; jmp ,x ; jump to the BIOS now in local RAM
st7:
bsr Delay3s ; give some time for devices to reset
clr BreakpointFlag
clr NumSetBreakpoints
lda #$AA
sta LEDS
lda COREID
cmpa #$20
beq st11
lda #FIRST_CORE
st11:
sta IOFocusID ; core #2 has focus
sta RunningID
; Clear IO focus list
ldx #0
st9:
clr IOFocusList,x
inx
cmpx #16
blo st9
lda #24
sta IOFocusList+FIRST_CORE
lda #$0CE
sta ScreenColor
sta CharColor
bsr ClearScreen
ldd #DisplayChar
std CharOutVec
ldd #SerialPeekCharDirect
std CharInVec
; swi
; fcb MF_OSCALL
; fcb 24 ; request IO focus
ldb COREID
cmpb #FIRST_CORE
beq init
cmpb #$20 ; CmodA709 core?
beq init2
bra skip_init
bra multi_sieve
st3:
lda #$FF
sta LEDS
bra st3
; initialize interrupt controller
; first, zero out all the vectors
init:
lbsr rtc_read ; get clock values
ldx #kbdHeadRcv
ldb #32 ; number of bytes to zero out
init1:
clr ,x+
decb
bne init1
ldx #128 ; register to start at
st1:
clr PIC,x ; cause code
sta PIC+1,x
stb PIC+2,x
leax 4,x
cmpx #256 ; max reg
blo st1
lda #$C1 ; make irq edge sensitive (bit 7), enable interupt (bit 6), irq (bit 0)
sta PIC+$FD
lda #$41 ; level sensitive, enabled, irq
sta PIC+$D1 ; serial irq is #20
lda #COLS
sta TEXTREG+TEXT_COLS
lda #ROWS
sta TEXTREG+TEXT_ROWS
bsr ClearScreen
bsr HomeCursor
ldx #0
ldd #0
lbsr ShowSprites
lbsr KeybdInit
ldd KeybdID
bsr DispWordAsHex
init2:
lbsr TimerInit
lbsr InitSerial
ldx #128
lda #1 ; set irq(bit0), clear firq (bit1), disable int (bit 6), clear edge sense(bit 7)
ldb #FIRST_CORE ; serving core id
; lda #4 ; make the timer interrupt edge sensitive
; sta PIC+4 ; reg #4 is the edge sensitivity setting
; sta PIC ; reg #0 is interrupt enable
ldb #1
stb OUTSEMA+SEMAABS ; set semaphore to 1 available slot
skip_init:
andcc #$EF ; unmask irq
lda #5
sta LEDS
ldd #msgStartup
bsr DisplayString
st10:
swi
fcb MF_Monitor
bra st10
msgStartup
fcb "rf6809 12-bit System Starting.",CR,LF,0
;------------------------------------------------------------------------------
; The checkpoint register must be cleared within 1 second or a NMI interrupt
; will occur. checkpoint should be called with a JSR so that the global ROM
; routine is called.
;
; Modifies:
; none
;------------------------------------------------------------------------------
checkpoint:
clr $FFFFFFFE1 ; writing any value will do
rts
;------------------------------------------------------------------------------
; Copy the system ROM to local RAM
; Running the code from local RAM is probably an order of magnitude faster
; then running from the global ROM. It also reduces the network traffic to
; run from local RAM.
;
; Modifies:
; d,x,y
;------------------------------------------------------------------------------
romToRam:
ldx #$FFC000
ldy #$00C000
romToRam1:
ldd ,x++
std ,y++
cmpx #0
bne romToRam1
rts
;------------------------------------------------------------------------------
; Multi-core sieve program.
;------------------------------------------------------------------------------
; First fill screen chars with 'P' indicating prime positions
; Each core is responsible for the Nth position where N is the
; core number minus two.
;
multi_sieve:
lda #'P' ; indicate prime
ldb COREID ; find out which core we are
subb #FIRST_CORE
ldx #0 ; start at first char of screen
abx
multi_sieve3:
sta TEXTSCR,x ; store 'P'
leax 8,x ; advance to next position
cmpx #4095
blo multi_sieve3
jsr checkpoint
addb #2 ; start sieve at 2 (core id)
lda #'N' ; flag position value of 'N' for non-prime
multi_sieve2:
ldx #0
abx ; skip the first position - might be prime
multi_sieve1:
abx ; increment
sta TEXTSCR,x
cmpx #4095
blo multi_sieve1
jsr checkpoint
addb #8 ; number of cores working on it
cmpb #4080
blo multi_sieve2
multi_sieve4: ; hang machine
sync
lbra Monitor
;------------------------------------------------------------------------------
; Single core sieve.
;------------------------------------------------------------------------------
sieve:
lda #'P' ; indicate prime
ldx #0 ; start at first char of screen
sieve3:
sta TEXTSCR,x ; store 'P'
inx ; advance to next position
cmpx #4095
blo sieve3
ldb #2 ; start sieve at 2
lda #'N' ; flag position value of 'N' for non-prime
sieve2:
ldx #0
abx ; skip the first position - might be prime
sieve1:
abx ; increment
sta TEXTSCR,x
cmpx #4095
blo multi_sieve1
incb ; number of cores working on it
cmpb #4080
blo sieve2
sieve4: ; hang machine
rts
;------------------------------------------------------------------------------
; Three second delay for user convenience and to allow some devices time to
; reset.
;------------------------------------------------------------------------------
Delay3s:
ldd #9000000
dly3s1:
cmpb #$FF
bne dly3s2
dly3s2:
sta LEDS
subd #1
bne dly3s1
rts
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ShiftLeft5:
aslb
rola
aslb
rola
aslb
rola
aslb
rola
aslb
rola
rts
;------------------------------------------------------------------------------
; Parameters:
; b = core id of core to copy
;------------------------------------------------------------------------------
;
CopyVirtualScreenToScreen:
pshs d,x,y,u
; Compute virtual screen location for core passed in accb.
tfr b,a
asla
asla
asla
asla
ora #$C00
clrb
tfr d,x
pshs d
ldy #TEXTSCR
ldu #COLS*ROWS/2
cv2s1:
ldd ,x++
std ,y++
leau -1,u
cmpu #0
bne cv2s1
; reset the cursor position in the text controller
puls x
ldb CursorRow,x
lda #COLS
mul
tfr d,y
ldb CursorCol,x
tfr y,x
abx
stx TEXTREG+TEXT_CURPOS
puls d,x,y,u,pc
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
CopyScreenToVirtualScreen:
pshs d,x,y,u
bsr GetScreenLocation
tfr d,y
ldx #TEXTSCR
ldu #COLS*ROWS/2
cs2v1:
ldd ,x++
std ,y++
leau -1,u
cmpu #0
bne cs2v1
puls d,x,y,u,pc
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
fcb "TEXTSCR "
fcw TextOpen
fcw TextClose
fcw TextRead
fcw TextWrite
fcw TextSeek
TextOpen:
rts
TextClose:
rts
TextRead:
rts
TextWrite:
rts
TextSeek:
rts
;------------------------------------------------------------------------------
; Clear the screen and the screen color memory
; We clear the screen to give a visual indication that the system
; is working at all.
;
; Modifies:
; none
;------------------------------------------------------------------------------
ClearScreen:
pshs d,x,y,u
ldx #COLS*ROWS
tfr x,u
bsr GetScreenLocation
tfr d,y
ldb #' ' ; space char
cs1:
stb ,y+ ; set text to space
leax -1,x ; decrement x
bne cs1
ldb COREID ; update colors only if we have focus
cmpb IOFocusID
bra cs3
ldy #TEXTSCR+$2000
; lda CharColor
lda #$0CE
tfr u,x ; get back count
cs2:
sta ,y+
dex ; decrement x
bne cs2
cs3:
puls d,x,y,u,pc
;------------------------------------------------------------------------------
; Scroll text on the screen upwards
;
; Modifies:
; none
;------------------------------------------------------------------------------
ScrollUp:
pshs d,x,y,u
ldy #(COLS*ROWS-1)/2 ; y = num chars/2 to move
bsr GetScreenLocation
tfr d,x
tfr d,u
leax COLS,x ; x = index to source row
scrup1:
ldd ,x++ ; move 2 characters
std ,u++
dey
bne scrup1
lda #ROWS-1
bsr BlankLine
puls d,x,y,u,pc
;------------------------------------------------------------------------------
; Blank out a line on the display
;
; Modifies:
; none
; Parameters:
; acca = line number to blank
;------------------------------------------------------------------------------
BlankLine:
pshs d,x
pshs a
bsr GetScreenLocation
tfr d,x
puls a
ldb #COLS ; b = # chars to blank out from video controller
mul ; d = screen index (row# * #cols)
leax d,x
lda #' '
ldb #COLS ; b = # chars to blank out from video controller
blnkln1:
sta ,x+
decb
bne blnkln1
puls d,x,pc
;------------------------------------------------------------------------------
; Get the location of the screen memory. The location
; depends on whether or not the task has the output focus.
;
; Modifies:
; d
; Retuns:
; d = screen location
;------------------------------------------------------------------------------
GetScreenLocation:
lda COREID ; which core are we?
cmpa IOFocusID ; do we have the IO focus
bne gsl1 ; no, go pick virtual screen address
cmpa #$20 ; CmodA709?
beq gsl1
ldd #TEXTSCR ; yes, we update the real screen
rts
gsl1:
ldd #$7800
rts
;------------------------------------------------------------------------------
; HomeCursor
; Set the cursor location to the top left of the screen.
;
; Modifies:
; none
;------------------------------------------------------------------------------
HomeCursor:
pshs d,x
clr CursorRow
clr CursorCol
ldb COREID
cmpb IOFocusID
bne hc1
cmpb #$20
beq hc1
clra
sta TEXTREG+TEXT_CURPOS
hc1:
puls d,x,pc
;------------------------------------------------------------------------------
; Update the cursor position in the text controller based on the
; CursorRow,CursorCol.
;
; Modifies:
; none
;------------------------------------------------------------------------------
;
UpdateCursorPos:
pshs d,x
ldb COREID ; update cursor position in text controller
cmpb IOFocusID ; only for the task with the output focus
bne ucp1
cmpb #$20 ; and not for CmodA709
beq ucp1
lda CursorRow
anda #$3F ; limit of 63 rows
ldb TEXTREG+TEXT_COLS
mul
tfr d,x
ldb CursorCol
abx
stx TEXTREG+TEXT_CURPOS
ucp1:
puls d,x,pc
;------------------------------------------------------------------------------
; Calculate screen memory location from CursorRow,CursorCol.
; Also refreshes the cursor location.
;
; Modifies:
; d
; Returns:
; d = screen location
;------------------------------------------------------------------------------
;
CalcScreenLoc:
pshs x
lda CursorRow
ldb #COLS
mul
tfr d,x
ldb CursorCol
abx
ldb COREID ; update cursor position in text controller
cmpb IOFocusID ; only for the task with the output focus
bne csl1
cmpb #$20
beq csl1
stx TEXTREG+TEXT_CURPOS
csl1:
bsr GetScreenLocation
leax d,x
tfr x,d
puls x,pc
;------------------------------------------------------------------------------
; Display a character on the screen.
; If the task doesn't have the I/O focus then the character is written to
; the virtual screen.
;
; Modifies:
; none
; Parameters:
; accb = char to display
;------------------------------------------------------------------------------
;
DisplayChar:
lbsr SerialPutChar
ScreenDisplayChar:
pshs d,x
cmpb #CR ; carriage return ?
bne dccr
clr CursorCol ; just set cursor column to zero on a CR
bsr UpdateCursorPos
dcx14:
lbra dcx4
dccr:
cmpb #$91 ; cursor right ?
bne dcx6
lda CursorCol
cmpa #COLS
bhs dcx7
inca
sta CursorCol
dcx7:
bsr UpdateCursorPos
puls d,x,pc
dcx6:
cmpb #$90 ; cursor up ?
bne dcx8
lda CursorRow
beq dcx7
deca
sta CursorRow
bra dcx7
dcx8:
cmpb #$93 ; cursor left ?
bne dcx9
lda CursorCol
beq dcx7
deca
sta CursorCol
bra dcx7
dcx9:
cmpb #$92 ; cursor down ?
bne dcx10
lda CursorRow
cmpa #ROWS
beq dcx7
inca
sta CursorRow
bra dcx7
dcx10:
cmpb #$94 ; cursor home ?
bne dcx11
lda CursorCol
beq dcx12
clr CursorCol
bra dcx7
dcx12:
clr CursorRow
bra dcx7
dcx11:
cmpb #$99 ; delete ?
bne dcx13
bsr CalcScreenLoc
tfr d,x
lda CursorCol ; acc = cursor column
bra dcx5
dcx13
cmpb #CTRLH ; backspace ?
bne dcx3
lda CursorCol
beq dcx4
deca
sta CursorCol
bsr CalcScreenLoc
tfr d,x
lda CursorCol
dcx5:
ldb 1,x
stb ,x++
inca
cmpa #COLS
blo dcx5
ldb #' '
dex
stb ,x
bra dcx4
dcx3:
cmpb #LF ; linefeed ?
beq dclf
pshs b
bsr CalcScreenLoc
tfr d,x
puls b
stb ,x
; ToDo character color
; lda CharColor
; sta $2000,x
bsr IncCursorPos
bra dcx4
dclf:
bsr IncCursorRow
dcx4:
puls d,x,pc
;------------------------------------------------------------------------------
; Increment the cursor position, scroll the screen if needed.
;
; Modifies:
; none
;------------------------------------------------------------------------------
IncCursorPos:
pshs d,x
lda CursorCol
inca
sta CursorCol
cmpa #COLS
blo icc1
clr CursorCol ; column = 0
bra icr1
IncCursorRow:
pshs d,x
icr1:
lda CursorRow
inca
sta CursorRow
cmpa #ROWS
blo icc1
deca ; backup the cursor row, we are scrolling up
sta CursorRow
bsr ScrollUp
icc1:
bsr UpdateCursorPos
icc2:
puls d,x,pc
;------------------------------------------------------------------------------
; Display a string on the screen.
;
; Modifies:
; none
; Parameters:
; d = pointer to string
;------------------------------------------------------------------------------
;
DisplayString:
pshs d,x
tfr d,x
lda COREID
cmpa #$20
beq dspj1B
dspj2: ; lock semaphore for access
lda OUTSEMA+1
beq dspj2
dspj1B:
ldb ,x+ ; move string char into acc
beq dsretB ; is it end of string ?
lbsr OUTCH ; display character
bra dspj1B
dsretB:
clr OUTSEMA+1 ; unlock semaphore
puls d,x,pc
DisplayStringCRLF:
pshs d
bsr DisplayString
ldb #CR
lbsr OUTCH
ldb #LF
lbsr OUTCH
puls d,pc
;
; PRINT CR, LF, STRING
;
PSTRNG
BSR PCRLF
BRA PDATA
PCRLF
PSHS X
LDX #CRLFST
BSR PDATA
PULS X
RTS
JSR OUTCH
PDATA
LDB ,X+
CMPB #$04
BNE PRINT
RTS
CRLFST
fcb CR,LF,4
DispDWordAsHex:
bsr DispWordAsHex
exg d,x
bsr DispWordAsHex
exg d,x
rts
DispWordAsHex:
exg a,b
bsr DispByteAsHex
exg a,b
bsr DispByteAsHex
rts
DispByteAsHex:
pshs b
lsrb
lsrb
lsrb
lsrb
lsrb
lsrb
lsrb
lsrb
bsr DispNyb
puls b
pshs b
lsrb
lsrb
lsrb
lsrb
bsr DispNyb
puls b
DispNyb
pshs b
andb #$0F
cmpb #10
blo DispNyb1
addb #'A'-10
lbsr OUTCH
puls b,pc
DispNyb1
addb #'0'
lbsr OUTCH
puls b,pc
;==============================================================================
; Timer
;==============================================================================
OPT INCLUDE "d:\cores2022\rf6809\software\boot\timer.asm"
OPT INCLUDE "d:\cores2022\rf6809\software\boot\i2c.asm"
OPT INCLUDE "d:\cores2022\rf6809\software\boot\rtc_driver.asm"
;==============================================================================
; Keyboard I/O
;==============================================================================
OPT INCLUDE "d:\cores2022\rf6809\software\boot\scancodes.asm"
OPT INCLUDE "d:\cores2022\rf6809\software\boot\keyboard.asm"
fcb "KEYBOARD"
fcw KeybdOpen
fcw KeybdClose
fcw KeybdRead
fcw KeybdWrite
fcw KeybdSeek
; Keyboard Open:
; Initialize the keyboard buffer head and tail indexes
;
KeybdOpen:
rts
; Keyboard Close:
; Nothing to do except maybe clear the keyboard buffer
;
KeybdClose:
rts
;
KeybdRead:
rts
;
KeybdWrite:
rts
KeybdSeek:
rts
;==============================================================================
; Serial I/O
;==============================================================================
OPT INCLUDE "d:\cores2022\rf6809\software\boot\serial.asm"
OPT INCLUDE "d:\cores2022\rf6809\software\boot\S19Loader.asm"
OPT INCLUDE "d:\cores2022\rf6809\software\boot\xmodem.asm"
;------------------------------------------------------------------------------
; Check if there is a keyboard character available. If so return true (<0)
; otherwise return false (0) in accb.
;------------------------------------------------------------------------------
;
KeybdCheckForKeyDirect:
bra DBGCheckForKey
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
INCH:
pshs b
INCH2:
ldb COREID
cmpb IOFocusID ; if we do not have focus, block
bne INCH2
; ldb #$800 ; block if no key available, get scancode directly
; bra GetKey
; jsr [CharInVec] ; vector is being overwritten somehow
lbsr SerialPeekCharDirect
; lbsr SerialGetChar
tsta
bmi INCH1 ; block if no key available
leas 1,s ; get rid of blocking status
rts ; return character
INCH1:
puls b ; check blocking status
tstb
bmi INCH ; if blocking, loop
ldd #-1 ; return -1 if no char available
rts
INCHE:
bsr INCH
bra INCHEK3
INCHEK:
bsr INCH
tst KeybdEcho
beq INCHEK1
INCHEK3:
cmpa #CR
bne INCHEK2
lbsr CRLF
bra INCHEK1
INCHEK2:
lbsr DisplayChar
INCHEK1:
rts
OUTCH:
jmp [CharOutVec]
;------------------------------------------------------------------------------
; r1 0=echo off, non-zero = echo on
;------------------------------------------------------------------------------
;
SetKeyboardEcho:
stb KeybdEcho
rts
;------------------------------------------------------------------------------
; Parameters:
; x,d bitmap of sprites to enable
;------------------------------------------------------------------------------
ShowSprites:
stx SPRITE_CTRL+SPRITE_EN
std SPRITE_CTRL+SPRITE_EN+2
rts
;==============================================================================
; Femtiki Operating System.
;==============================================================================
OSCallTbl:
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw 0
fcw ReleaseIOFocus
fcw 0
fcw RequestIOFocus
NumOSFuncs EQU (*-OSCallTbl)/2
RequestIOFocus:
ldb COREID
ldx #IOFocusList
abx
sta ,x
tst IOFocusID
lbne oscx
stb IOFocusID
lbra oscx
ReleaseIOFocus:
ldb COREID
ldx #IOFocusList
abx
clr ,x ; clear the request indicator
lbsr CopyScreenToVirtualScreen
cmpb IOFocusID ; are we the one with the focus?
lbne oscx
; We had the focus, so now a new core needs the focus.
; Search the focus list for a requestor. If no requester
; is found, give focus to core #1.
lda #15
riof2:
incb
andb #15
abx
tst ,x
bne riof1
deca
bne riof2
; If no focus is requested by anyone, give to core #1
ldb #1
lda #24
sta ,x
riof1:
stb IOFocusID
lbsr CopyVirtualScreenToScreen
lbra oscx
;==============================================================================
;==============================================================================
;------------------------------------------------------------------------------
; Seed the random number generator. All channels are seeded with the same
; value.
;
; Parameters:
; d = 'z' part of seed
; x = 'w' part of seed
; Returns:
; none
;------------------------------------------------------------------------------
mon_srand:
ldy #0
mon_srand1:
sty PRNG+4 ; select channel
clr PRNG+8
clr PRNG+9
std PRNG+10 ; update low half of value
clr PRNG+12
clr PRNG+13
stx PRNG+14 ; update low half of value
iny
cmpy #$400 ; 1k channels
blo mon_srand1
rts
;------------------------------------------------------------------------------
; Get a random number and generate the next one.
;
; Parameters:
; d = channel to use
; Returns:
; x,d = 36 bit random value
;------------------------------------------------------------------------------
mon_rand:
std PRNG+4 ; select channel
ldx PRNG+0
ldd PRNG+2
stb PRNG+3 ; trigger calc of next number
rts
;==============================================================================
; System Monitor
;==============================================================================
; Command Tables
cmdTable1:
fcb '<','>'+$800
fcb 'B','+'+$800
fcb 'B','-'+$800
fcb 'D','R'+$800
fcb 'D'+$800
fcb ':'+$800
fcb "FI",'G'+$800
fcb "FI",'L'+$800
fcb 'F','L'+$800
fcb 'J'+$800
fcb "RAMTES",'T'+$800
fcb "SP",'D'+$800
fcb "TI",'R'+$800
fcb 'U'+$800
fcb "exi",'t'+$800
fcb '?'+$800
fcb "CL",'S'+$800
fcb "C1",'9'+$800
fcb "JD",'4'+$800
fcb "XM",'R'+$800
fcb "XM",'S'+$800
fcb 'R','A'+$800
fcb 'R','B'+$800
fcb "RDP",'R'+$800
fcb 'R','D'+$800
fcb 'R','X'+$800
fcb 'R','Y'+$800
fcb 'R','U'+$800
fcb 'R','S'+$800
fcb "RCC",'R'+$800
fcb "RP",'C'+$800
fcb 'L','B'+$800
fcw 0
cmdTable2:
fcw Redirect
fcw MonArmBreakpoint
fcw MonDisarmBreakpoint
fcw DumpRegs
fcw DumpMemory
fcw EditMemory
fcw $FE0000 ; FIG forth
fcw FillMemory
fcw DumpIOFocusList
fcw jump_to_code
fcw $FFD400
fcw $FF8000 ; sprite demo
fcw rtc_read
fcw $FF8003 ; unassembler
fcw xitMonitor
fcw PromptHelp
fcw PromptClearscreen
fcw S19Loader
fcw $FFD400
fcw xm_ReceiveStart
fcw xm_SendStart
fcw SetRegA
fcw SetRegB
fcw SetRegDPR
fcw SetRegD
fcw SetRegX
fcw SetRegY
fcw SetRegU
fcw SetRegS
fcw SetRegCCR
fcw SetRegPC
fcw ListBreakpoints
CmdPrompt:
lbsr CRLF
ldb #'$'
lbsr OUTCH
lbra OUTCH
msgF09Starting:
fcb "Femtiki F09 Multi-core OS Starting",CR,LF,0
Monitor:
andcc #$EF ; SWI disables interrupts, re-enable them
lda #31 ; Timer is IRQ #31
sta PIC+16 ; register 16 is edge sense reset reg
ldd mon_init ; check special code to see if monitor has been initialized
cmpd #1234567
beq mon1
clr BreakpointFlag
clr NumSetBreakpoints
ldd #123
ldx #654
lbsr mon_srand
ldd #msgF09Starting
lbsr DisplayString
ldd #HelpMsg
lbsr DisplayString
ldd #CmdPrompt
std CmdPromptJI
ldd #DisplayErr
std MonErrVec
ldd #$63FF ; default app stack
std mon_SSAVE
clr mon_DPRSAVE ;
tfr ccr,a
sta mon_CCRSAVE
clr mon_PCSAVE
ldd #Monitor
std mon_PCSAVE+1
clr mon_XSAVE
clr mon_YSAVE
clr mon_USAVE
ldd #1234567
std mon_init
mon1:
leas $6FFF ; reset stack pointer
clrb ; turn off keyboard echo
lbsr SetKeyboardEcho
; Reset IO vectors
ldd #SerialPeekCharDirect
std CharInVec
ldd #DisplayChar
std CharOutVec
ldd #CmdPrompt
std CmdPromptJI
; jsr RequestIOFocus
PromptLn:
jsr [CmdPromptJI]
; Get characters until a CR is keyed
Prompt3:
ldd #-1 ; block until key present
lbsr INCH
tsta ; should not get this with blocking
bmi Prompt3
cmpb #CR ; carriage return?
beq Prompt1
lbsr OUTCH ; spit out the character
bra Prompt3 ; and keep going
; Process the screen line that the CR was keyed on
;
Prompt1:
ldd #$5050
std LEDS
; ldb RunningID
; cmpb #61
; bhi Prompt3
clr CursorCol ; go back to the start of the line
lbsr CalcScreenLoc ; calc screen memory location
tfr d,y
skipDollar:
bsr MonGetNonSpace
cmpb #'$'
beq skipDollar ; skip over '$' prompt character
; Dispatch based on command
;
dey
tfr y,u ; save off input position
clrb
ldx #cmdTable1
parseCmd1:
lda ,y+ ; get input character
tst ,x ; test for end of command
bmi endOfWord ;
cmpa ,x+ ; does input match command?
beq parseCmd1
scanNextWord:
tst ,x+
beq Monitor ; if end of table reached, not a command
bpl scanNextWord
incb
tfr u,y ; reset input pointer
bra parseCmd1 ; try again
endOfWord:
eora ,x
asla
bne scanNextWord
; we found the command in the table
aslb ; b = word index
ldx #cmdTable2
jmp [b,x] ; execute command
Redirect:
bsr MonGetch
cmpb #'s'
bne Prompt2a
ldd #SerialPeekCharDirect
std CharInVec
ldd #SerialPutChar
std CharOutVec
bra Monitor
Prompt2a:
cmpb #'c'
bne Monitor
ldd #GetKey
std CharInVec
ldd #DisplayChar
std CharOutVec
bra Monitor
PromptHelp:
ldd #HelpMsg
lbsr DisplayString
bra Monitor
PromptClearscreen:
lbsr ClearScreen
lbsr HomeCursor
bra Monitor
MonGetch:
ldb ,y
iny
rts
MonGetNonSpace:
bsr MonGetCh
cmpb #' '
beq MonGetNonSpace
rts
MonArmBreakpoint:
lbsr ArmBreakpoint
ldb #$FFF
stb BreakpointFlag
lbra Monitor
MonDisarmBreakpoint:
lbsr DisarmBreakpoint
lbra Monitor
;------------------------------------------------------------------------------
; Ignore blanks in the input
; Y = text pointer
; D destroyed
;------------------------------------------------------------------------------
;
ignBlanks:
ignBlanks1:
bsr MonGetch
cmpb #' '
beq ignBlanks1
dey
rts
;------------------------------------------------------------------------------
; Multiply number in work area by 10.
;------------------------------------------------------------------------------
Times10:
pshs d
ldd mon_numwka ; make a copy of the number
std mon_numwka+8
ldd mon_numwka+2
std mon_numwka+10
bsr shl_numwka ; shift left = *2
bsr shl_numwka ; shift left = *4
ldd mon_numwka+2 ; add in original value
addd mon_numwka+10 ; = *5
ldb mon_numwka+1
adcb mon_numwka+9
stb mon_numwka+1
lda mon_numwka+0
adca mon_numwka+8
sta mon_numwka+0
bsr shl_numwka ; shift left = * 10
puls d,pc
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
GetTwoParams:
bsr ignBlanks
bsr GetNumber ; get start address of dump
ldd mon_numwka
std mon_r1
ldd mon_numwka+2
std mon_r1+2
bsr ignBlanks
bsr GetNumber ; get end address of dump
ldd mon_numwka
std mon_r2
ldd mon_numwka+2
std mon_r2+2
rts
;------------------------------------------------------------------------------
; Get a range, the end must be greater or equal to the start.
;------------------------------------------------------------------------------
GetRange:
bsr GetTwoParams
ldd mon_r2+2
subd mon_r1+2
ldd mon_r2
sbcb mon_r1+1
sbca mon_r1
lbcc grng1
jsr [MonErrVec]
lbra Monitor
grng1:
rts
shl_numwka:
asl mon_numwka+3
rol mon_numwka+2
rol mon_numwka+1
rol mon_numwka
rts
;------------------------------------------------------------------------------
; Get a hexidecimal number. Maximum of twelve digits.
;
; Modifies:
; Y = text pointer (updated)
; D = number of digits
; mon_numwka contains number
;------------------------------------------------------------------------------
;
GetHexNumber:
clrd
std mon_numwka ; zero out work area
std mon_numwka+2
pshs x
ldx #0 ; max 12 eight digits
gthxn2:
bsr MonGetch
bsr AsciiToHexNybble
cmpb #-1
beq gthxn1
bsr shl_numwka
bsr shl_numwka
bsr shl_numwka
bsr shl_numwka
andb #$0f
orb mon_numwka+3
stb mon_numwka+3
inx
cmpx #12
blo gthxn2
gthxn1:
tfr x,d
puls x,pc
GetBinNumber:
clrd
std mon_numwka
std mon_numwka+2
pshs x
ldx #0
gtbin2:
bsr MonGetch
bsr AsciiToBinDigit
tstb
bmi gtbin1
bsr shl_numwka
orb mon_numwka+3
stb mon_numwka+3
inx
cpx #48
blo gtbin2
gtbin1:
tfr x,d
puls x,pc
GetDecNumber:
clrd
std mon_numwka
std mon_numwka+2
pshs x
ldx #0
gtdec2:
bsr MonGetch
bsr AsciiToDecDigit
tstb
bmi gtdec1
bsr Times10
addb mon_numwka+3
stb mon_numwka+3
ldb mon_numwka+2
adcb #0
stb mon_numwka+2
ldb mon_numwka+1
adcb #0
stb mon_numwka+1
ldb mon_numwka+0
adcb #0
stb mon_numwka+0
inx
cpx #15
blo gtdec2
gtdec1:
tfr x,d
puls x,pc
GetNumber:
bsr MonGetch
cmpb #'+'
beq GetDecNumber
cmpb #'%'
beq GetBinNumber
dey
bra GetHexNumber
; phx
; push r4
; push r5
; ldx #0
; ld r4,#10
; ld r5,#10
;gtdcn2:
; jsr MonGetch
; jsr AsciiToDecNybble
; cmp #-1
; beq gtdcn1
; mul r2,r2,r5
; add r2,r1
; dec r4
; bne gtdcn2
;gtdcn1:
; txa
; pop r5
; pop r4
; plx
; rts
;------------------------------------------------------------------------------
; Convert ASCII character in the range '0' to '9', 'a' to 'f' or 'A' to 'F'
; to a hex nybble.
;------------------------------------------------------------------------------
;
AsciiToHexNybble:
cmpb #'0'
blo gthx3
cmpb #'9'
bhi gthx5
subb #'0'
rts
gthx5:
cmpb #'A'
blo gthx3
cmpb #'F'
bhi gthx6
subb #'A'
addb #10
rts
gthx6:
cmpb #'a'
blo gthx3
cmpb #'z'
bhi gthx3
subb #'a'
addb #10
rts
gthx3:
ldb #-1 ; not a hex number
rts
AsciiToDecDigit:
cmpb #'0'
blo gtdc3
cmpb #'9'
bhi gtdc3
subb #'0'
rts
gtdc3:
ldb #-1
rts
AsciiToBinDigit:
cmpb #'0'
bne abd1
clrb
rts
abd1:
cmpb #'1'
bne abd2
ldb #1
rts
abd2:
ldb #-1
rts
DisplayErr:
ldd #msgErr
lbsr DisplayString
jmp Monitor
DisplayStringDX
std Strptr
stx Strptr+2
jsr DisplayString
rts
msgErr:
fcb "**Err",CR,LF,0
HelpMsg:
fcb "? = Display help",CR,LF
fcb "CLS = clear screen",CR,LF
fcb "b+ = set breakpoint",CR,LF
fcb "b- = clear breakpoint",CR,LF
fcb "C19 = run C19 loader",CR,LF
; db "S = Boot from SD Card",CR,LF
fcb ": = Edit memory bytes",CR,LF
; db "L = Load sector",CR,LF
; db "W = Write sector",CR,LF
fcb "DR = Dump registers",CR,LF
fcb "D = Dump memory",CR,LF
fcb "F = Fill memory",CR,LF
fcb "FL = Dump I/O Focus List",CR,LF
; fcb "FIG = start FIG Forth",CR,LF
; db "KILL n = kill task #n",CR,LF
; db "B = start tiny basic",CR,LF
; db "b = start EhBasic 6502",CR,LF
fcb "J = Jump to code",CR,LF
fcb "JD4 = Jump to $FFD400",CR,LF
fcb "R[n] = Set register value",CR,LF
; db "r = random lines - test bitmap",CR,LF
; db "e = ethernet test",CR,LF
fcb "s = serial output test",CR,LF
fcb "SP = sprite demo",CR,LF
; db "T = Dump task list",CR,LF
; db "TO = Dump timeout list",CR,LF
fcb "TI = display date/time",CR,LF
; db "TEMP = display temperature",CR,LF
fcb "U = unassemble",CR,LF
; db "P = Piano",CR,LF
fcb "XM = xmodem transfer",CR,LF
fcb "x = exit monitor",CR,LF
fcb 0
msgRegHeadings
fcb CR,LF," D/AB X Y U S PC DP CCR",CR,LF,0
nHEX4:
jsr HEX4
rts
nXBLANK:
ldb #' '
lbra OUTCH
;------------------------------------------------------------------------------
; Dump Memory
;
; Usage:
; $D FFFC12 FFFC20
;
; Dump formatted to look like:
; :FFFC12 012 012 012 012 555 666 777 888
;
;------------------------------------------------------------------------------
DumpMemory:
bsr GetRange
ldy #0
ldy mon_r1+2
dmpm2:
lbsr CRLF
ldb #':'
lbsr OUTCH
tfr y,d
;addd mon_r1+2 ; output the address
lbsr DispWordAsHex
ldb #' '
lbsr OUTCH
ldx #8 ; number of bytes to display
dmpm1:
; ldb far [mon_r1+1],y
;ldb [mon_r1+2],y
ldb ,y
iny
lbsr DispByteAsHex ; display byte
ldb #' ' ; followed by a space
lbsr OUTCH
clrb
clra
lbsr INCH
cmpb #CTRLC
beq dmpm3
dex
bne dmpm1
; Now output ascii
ldb #' '
lbsr OUTCH
ldx #8 ; 8 chars to output
leay -8,y ; backup pointer
dmpm5:
; ldb far [mon_r1+1],y ; get the char
; ldb [mon_r1+2],y ; get the char
ldb ,y
cmpb #$20 ; is it a control char?
bhs dmpm4
ldb #'.'
dmpm4:
lbsr OUTCH
iny
dex
bne dmpm5
cmpy mon_r2+2
blo dmpm2
dmpm3:
lbsr CRLF
lbra Monitor
;------------------------------------------------------------------------------
; Edit Memory
;
; Usage:
; $$:FFFC12 8 "Hello World!" 0
;
; Dump formatted to look like:
; :FFFC12 012 012 012 012 555 666 777 888
;
;------------------------------------------------------------------------------
EditMemory:
ldu #8 ; set max byte count
lbsr ignBlanks
lbsr GetHexNumber ; get the start address
ldx mon_numwka+2
EditMem2:
lbsr ignBlanks ; skip over blanks
lbsr GetHexNumber ; get the byte value
tstb ; check for valid value
beq EditMem1 ; if invalid, quit
ldb mon_numwka+3 ; get value
stb ,x+ ; update memory at address
leau -1,u ; decremeent byte count
cmpu #0
bne EditMem2 ; go back for annother byte
EditMem1:
lbsr MonGetch ; see if a string is being entered
cmpb #'"'
bne EditMem3 ; no string, we're done
ldu #40 ; string must be less than 40 chars
EditMem4:
lbsr MonGetch ; look for close quote
cmpb #'"'
bne EditMem6 ; end of string?
ldu #8 ; reset the byte count
bra EditMem2
EditMem6:
stb ,x+ ; store the character in memory
leau -1,u ; decrement byte count
cmpu #0
bhi EditMem4 ; max 40 chars
EditMem3:
lbra Monitor
;------------------------------------------------------------------------------
; Fill Memory
;
; Usage:
; $$F FFFC12 FFFC30 89F
;
;------------------------------------------------------------------------------
FillMemory:
lbsr GetRange ; get address range to fill
lbsr ignBlanks
lbsr GetHexNumber ; get target byte to write
ldb mon_numwka+3
ldx mon_r1+2
clra
fillm1: ; Check for a CTRL-C every page of memory
tsta
bne fillm2
clrb ; we want a non-blocking check
clra
lbsr INCH
cmpb #CTRLC
lbeq Monitor
ldb mon_numwka+3 ; reset target byte
fillm2:
stb ,x+
cmpx mon_r2+2
bls fillm1
fillm3:
lbra Monitor
;------------------------------------------------------------------------------
; Dump Registers
;
; Usage:
; $DR
;------------------------------------------------------------------------------
DumpRegs:
ldd #msgRegHeadings
lbsr DisplayString
bsr nXBLANK
ldd mon_DSAVE
bsr nHEX4
bsr nXBLANK
ldd mon_XSAVE
bsr nHEX4
bsr nXBLANK
ldd mon_YSAVE
bsr nHEX4
bsr nXBLANK
ldd mon_USAVE
bsr nHEX4
bsr nXBLANK
ldd mon_SSAVE
bsr nHEX4
bsr nXBLANK
ldb mon_PCSAVE+1
lbsr DispByteAsHex
ldd mon_PCSAVE+2
bsr nHEX4
bsr nXBLANK
ldd mon_DPRSAVE
jsr HEX2
bsr nXBLANK
lda mon_CCRSAVE
lbsr HEX2
bsr nXBLANK
lbra Monitor
;------------------------------------------------------------------------------
; SetRegXXX
;
; Set the value to be loaded into a register.
;------------------------------------------------------------------------------
SetRegA:
lbsr ignBlanks
lbsr GetNumber
lda mon_numwka+3
sta mon_DSAVE
lbra Monitor
SetRegB:
lbsr ignBlanks
lbsr GetNumber
lda mon_numwka+3
sta mon_DSAVE+1
lbra Monitor
SetRegD:
lbsr ignBlanks
lbsr GetNumber
ldd mon_numwka+2
std mon_DSAVE
lbra Monitor
SetRegX:
lbsr ignBlanks
lbsr GetNumber
ldd mon_numwka+2
std mon_XSAVE
lbra Monitor
SetRegY:
lbsr ignBlanks
lbsr GetNumber
ldd mon_numwka+2
std mon_YSAVE
lbra Monitor
SetRegU:
lbsr ignBlanks
lbsr GetNumber
ldd mon_numwka+2
std mon_USAVE
lbra Monitor
SetRegS:
lbsr ignBlanks
lbsr GetNumber
ldd mon_numwka+2
std mon_SSAVE
lbra Monitor
SetRegDPR:
lbsr ignBlanks
lbsr GetNumber
lda mon_numwka+3
sta mon_DPRSAVE
lbra Monitor
SetRegCCR:
lbsr ignBlanks
lbsr GetNumber
lda mon_numwka+3
sta mon_CCRSAVE
lbra Monitor
SetRegPC:
lbsr ignBlanks
lbsr GetNumber
ldd mon_numwka+2
std mon_PCSAVE+2
ldb mon_numwka+1
stb mon_PCSAVE+1
lbra Monitor
;------------------------------------------------------------------------------
; Jump to code
;
; Registers are loaded with values from the monitor register save area before
; the code is jumped to.
;
; J <address>
;------------------------------------------------------------------------------
jump_to_code:
lbsr ignBlanks
lbsr GetNumber
sei
lds mon_SSAVE
ldd #jtc_exit ; setup stack for RTS back to monitor
pshs d
ldb #0
pshs b
ldd mon_USAVE
pshs d
ldd mon_YSAVE
pshs d
ldd mon_XSAVE
pshs d
lda mon_DPRSAVE
pshs a
ldd mon_DSAVE
pshs d
lda mon_CCRSAVE
pshs a
puls far ccr,d,dpr,x,y,u
jmp far [mon_numwka+1]
jtc_exit:
sts >mon_SSAVE ; need to use extended addressing, no direct page setting
leas $6FFF ; reset stack to system area, dont modify flags register!
pshs ccr ; now the stack can be used
pshs a ; save acca register so we can use it
tfr dpr,a ; a = outgoing dpr value
sta >mon_DPRSAVE ; force extended addressing mode usage here dpr is not set
clra ; dpg register must be set to zero before values are
tfr a,dpr ; saved in the monitor register save area.
puls a ; get back acca
std mon_DSAVE ; save regsters, can use direct addressing now
stx mon_XSAVE
sty mon_YSAVE
stu mon_USAVE
puls a ; get back ccr
sta mon_CCRSAVE ; and save it too
; Reset vectors in case they got toasted.
ldd #SerialPeekCharDirect
std CharInVec
ldd #DisplayChar
std CharOutVec
ldd DisplayErr
std MonErrVec
; todo set according to coreid
lbra DumpRegs ; now go do a register dump
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
DumpIOFocusList:
ldx #0
dfl2:
ldb IOFocusList,x
cmpb #24
bne dfl1
tfr x,d
lbsr DispByteAsHex
ldb #' '
lbsr OUTCH
dfl1:
inx
cmpx #16
blo dfl2
lbsr CRLF
lbra Monitor
bootpg:
fcb $000
boot_stack:
fcw $FFC0FF
numBreakpoints:
fcw 8
mon_rom_vectab:
fcw mon_rom_vecs
mon_rom_vecs:
fcw Monitor ; enter monitor program
fcw INCH ; input a character
fcw OUTCH ; output a character
fcw CRLF ; output carriage-return, line feed
fcw DisplayString
fcw DispByteAsHex
fcw DispWordAsHex
fcw ShowSprites
fcw mon_srand
fcw mon_rand
fcw 0 ; operating system call
fcw GetRange
fcw GetNumber
fcw SerialPutChar
NumFuncs EQU (*-mon_rom_vectab)/2
; The following table indicates which routines need to return values in the
; D and possibly X registers.
mon_rettab:
fcb 0 ; monitor
fcb $800 ; INCH
fcb 0 ; OUTCH
fcb 0 ; CRLF
fcb 0 ; DisplayString
fcb 0 ; DisplayByte
fcb 0 ; DisplayWord
fcb 0 ; show sprites
fcb 0 ; srand
fcb $C00 ; rand
fcb $C00 ; OS call
fcb 0 ; GetRange
fcb $800 ; GetNumber
fcb 0 ; SerialPutChar
;------------------------------------------------------------------------------
; SWI routine.
;
; SWI is used to call ROM monitor routines and process breakpoints.
;
; swi
; fcb <desired function>
;------------------------------------------------------------------------------
swi_rout:
ldb bootpg,pcr ; reset direct page
tfr b,dp
swi_rout1:
ldu 11,s ; get program counter (low order 2 bytes)
leau -1,u ; backup a byte
tst BreakpointFlag ; are we in breakpoint mode?
beq swiNotBkpt
ldy #Breakpoints
ldb NumSetBreakpoints
beq swiNotBkpt
swi_rout2:
cmpu ,y++
beq processBreakpoint
decb
bne swi_rout2
swiNotBkpt:
clr BreakpointFlag
pulu d ; get function #, increment PC
cmpb #NumFuncs
lbhi DisplayErr
stu 11,s ; save updated PC on stack
cmpb #MF_OSCALL
beq swiCallOS
aslb ; 2 bytes per vector
ldx mon_rom_vectab,pcr
abx
ldx ,x
stx jmpvec
lsrb
ldx #mon_rettab
abx
ldb ,x
stb mon_retflag
sts mon_SSAVE ; save the stack pointer
ldd 1,s ; get back D
ldx 4,s ; get back X
ldy 6,s ; get back Y
ldu 8,s ; get back U
lds boot_stack,pcr ; and use our own stack
jsr [jmpvec] ; call the routine
swi_rout3:
lds mon_SSAVE ; restore stack
tst mon_retflag
bpl swi_rout4
std 1,s ; return value in D
asl mon_retflag
bpl swi_rout4
stx 4,s ; return value in X
swi_rout4:
rti
;------------------------------------------------------------------------------
; A breakpoint was struck during program execution, process accordingly.
;------------------------------------------------------------------------------
processBreakpoint:
lda ,s
sta mon_CCRSAVE
ldd 1,s
std mon_DSAVE
ldb 3,s
stb mon_DPRSAVE
ldd 4,s
std mon_XSAVE
ldd 6,s
std mon_YSAVE
ldd 8,s
std mon_USAVE
sts mon_SSAVE
ldb 10,s
stb mon_PCSAVE
ldd 11,s
std mon_PCSAVE+1
lds boot_stack,pcr
ldd #swi_rout3 ; setup so monitor can return
pshs d
bsr DisarmAllBreakpoints
lbra DumpRegs
xitMonitor:
bra ArmAllBreakpoints
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
swiCallOS:
leau 1,u ; next byte is func number
ldb ,u+
cmpb #NumOSFuncs ; check for valid range
lbhi DisplayErr
stu 11,s ; save updateed PC on stack
aslb ; compute vector address
ldx #OSCallTbl
tst b,x ; check for non-zero vector
beq swi_rout3
osc1:
; tst OSSEMA+1 ; wait for availability
; beq osc1
jsr [b,x] ; call the OS routine
oscx:
clr OSSEMA+1
bra swi_rout3
;------------------------------------------------------------------------------
; DisarmAllBreakpoints, used when entering the monitor.
;------------------------------------------------------------------------------
DisarmAllBreakpoints:
pshs d,x,y
ldy #0
clrb
ldx #BreakpointBytes ; x = breakpoint byte table address
disarm2:
cmpb #numBreakpoints ; safety check
bhs disarm1
cmpb NumSetBreakpoints
bhs disarm1
lda b,x ; get memory byte
sta [Breakpoints,y] ; and store it back to memory
leay 2,y ; increment for next address
incb ; increment to next byte
bra disarm2 ; loop back
disarm1:
puls d,x,y,pc
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ArmAllBreakpoints:
pshs d,x,y
ldy #0
clrb
ldx #BreakpointBytes ; x = breakpoint byte table address
arm2:
cmpb numBreakpoints ; safety check
bhs arm1
cmpb NumSetBreakpoints
bhs arm1
lda [Breakpoints,y] ; load byte at memory address
sta b,x ; save in table
leay 2,y ; increment for next address
incb ; increment to next byte
bra arm2 ; loop back
arm1:
puls d,x,y,pc
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ArmBreakpoint:
pshs d,x,y
lda NumSetBreakpoints ; check if too many breakpoints set
cmpa numBreakpoints
lbhs DisplayErr
lbsr ignBlanks
lbsr GetHexNumber ; get address parameter
tstb
lbmi DisplayErr
ldb NumSetBreakpoints ; bv= number of set breakpoints
ldy mon_numwka+2 ; get address
lda ,y ; get byte at address
ldx #BreakpointBytes ; and store byte in a table
sta b,x ; record
lda #OPC_SWI ; put a SWI instruction in place
sta ,y
ldx #Breakpoints ; also store the address in a table
aslb ; index for 2 byte values
sty b,x
lsrb ; size back to single byte
incb
stb NumSetBreakpoints
puls d,x,y
lbra Monitor
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
DisarmBreakpoint:
pshs d,x,y,u
lbsr ignBlanks
lbsr GetHexNumber
tstb
lbmi Monitor
clrb
clrb
tfr d,x ; x = zero too
disarm6:
cmpb numBreakpoints ; no more than this many may be set
bhs disarm4
cmpb NumSetBreakpoints ; number actually set
bhs disarm4
ldy Breakpoints,x ; y = breakpoint address
cmpy mon_numwka+2 ; is it the one we want?
bne disarm3 ; if not, go increment to next
ldx mon_numwka+2 ; x = memory address
ldy #BreakpointBytes
lda b,y ; get saved byte from table
sta ,x ; set the byte at the memory address
; compress breakpoint table by removing breakpoint
dec NumSetBreakpoints ; set the new number of set breakpoints
pshs b ; save the position we're removing from
disarm7:
incb ; set index for next byte
lda b,y ; get byte
decb ; and store it back
sta b,y
incb ; move to next position
cmpb numBreakpoints ; hit end of table?
blo disarm7
puls b ; get back position
aslb ; times two for word index
clra
tfr d,y
lsrb ; back to byte index value
disarm8:
ldu 2,y ; get next breakpoint address
stu ,y++ ; store in current pos, increment
incb ; increment count
cmpb numBreakpoints ; hit end of table?
blo disarm8
puls d,x,y,u,pc
disarm3:
leax 2,x
incb
bra disarm6
disarm4:
puls d,x,y,u
lbra Monitor
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
ListBreakpoints:
pshs d,x
swi
fcb MF_CRLF
ldx #0
ldb #0
lbrk1:
cmpb numBreakpoints
bhs lbrk2
cmpb NumSetBreakpoints
bhs lbrk2
ldd Breakpoints,x
leax 2,x
incb
pshs b
swi
fcb MF_DisplayWordAsHex
swi
fcb MF_CRLF
puls b
bra lbrk1
lbrk2:
puls d,x
lbra Monitor
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
swi3_rout:
sei
lda ,s
sta mon_CCRSAVE
ldd 1,s
std mon_DSAVE
ldb 3,s
stb mon_DPRSAVE
ldd 4,s
std mon_XSAVE
ldd 6,s
std mon_YSAVE
ldd 8,s
std mon_USAVE
sts mon_SSAVE
ldd 11,s
std mon_PCSAVE
sts mon_SSAVE
lds #$3FFF
ldd #swi3_exit
pshs d
cli
jmp DumpRegs
swi3_exit:
lds mon_SSAVE
rti
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
firq_rout:
rti
irq_rout:
clra
tfr a,dpr
setdp $000
; lbsr SerialIRQ ; check for recieved character
lbsr TimerIRQ
lda IrqBase ; get the IRQ flag byte
lsra
ora IrqBase
anda #$FE0
sta IrqBase
; inc TEXTSCR+54 ; update IRQ live indicator on screen
; inc TEXTSCR+$2000+54
; flash the cursor
; only bother to flash the cursor for the task with the IO focus.
lda COREID
cmpa IOFocusID
bne tr1a
lda CursorFlash ; test if we want a flashing cursor
beq tr1a
lbsr CalcScreenLoc ; compute cursor location in memory
tfr d,y
inc $2000,y ; get color code $2000 higher in memory
tr1a:
rti
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
nmi_rout:
ldb COREID
lda #'I'
ldx #TEXTSCR+40
sta b,x
rti_insn:
rti
; Special Register Area
org $FFFFE0
; Interrupt vector table
org $FFFFF0
fcw rti_insn ; reserved
fcw swi3_rout ; SWI3
fcw rti_insn ; SWI2
fcw firq_rout ; FIRQ
fcw irq_rout ; IRQ
fcw swi_rout ; SWI
fcw nmi_rout ; NMI
fcw start ; RST