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 $03FScreenLocation EQU $10ColorCodeLocation EQU $14ScreenLocation2 EQU $18BlkcpySrc EQU $1CBlkcpyDst EQU $20Strptr EQU $24PICptr EQU $28; Forth Area; 0x30-0x60; Task control blocks, room for 256 tasksTCB_NxtRdy EQU $00 ; next task on ready / timeout listTCB_PrvRdy EQU $04 ; previous task on ready / timeout listTCB_NxtTCB EQU $08TCB_Timeout EQU $0CTCB_Priority EQU $10TCB_MSGPTR_D1 EQU $14TCB_MSGPTR_D2 EQU $18TCB_hJCB EQU $1CTCB_Status EQU $1ETCB_CursorRow EQU $20TCB_CursorCol EQU $21TCB_hWaitMbx EQU $22 ; handle of mailbox task is waiting atTCB_mbq_next EQU $24 ; mailbox queue nextTCB_mbq_prev EQU $28 ; mailbox queue previousTCB_iof_next EQU $2CTCB_iof_prev EQU $30TCB_SPSave EQU $34 ; TCB_SPSave areaTCB_mmu_map EQU $38KeybdHead EQU $FFFFFC800KeybdTail EQU $FFFFFC900KeybdEcho EQU $FFFFFCA00KeybdBad EQU $FFFFFCB00KeybdAck EQU $FFFFFCC00KeybdLocks EQU $FFFFFCD00KeybdBuffer EQU $FFFFFC000 ; buffer is 16 charsBIOS_SCREENS EQU $17000000 ; $17000000 to $171FFFFF; EhBASIC vars:;NmiBase EQU $FFC013IrqBase EQU $FFC014IOFocusNdx EQU $100; These variables in global OS storage areaIOFocusList EQU $FFC000 ; to $FF000FIOFocusID EQU $FFC010IrqSource EQU $FFC011IRQFlag EQU $FFC012RunningID EQU $FFC013milliseconds EQU $FFC014; One copy of serial buffer management; 1 serial buffer for system.SerHeadRcv EQU $FFC015SerTailRcv EQU $FFC016SerHeadXmit EQU $FFC017SerTailXmit EQU $FFC018SerRcvXon EQU $FFC019SerRcvXoff EQU $FFC01ASerRcvBuf EQU $FFB000 ; 4kB serial recieve buffer; Top of boot stack is at $FFC0FF; These variables use direct page accessCursorRow EQU $110CursorCol EQU $111CharColor EQU $112ScreenColor EQU $113CursorFlash EQU $114KeyState1 EQU $120KeyState2 EQU $121KeyLED EQU $122KeybdID EQU $124KeybdBlock EQU $126kbdHeadRcv EQU $127kbdTailRcv EQU $128kbdFifo EQU $40 ; in local RAMkbdFifoAlias EQU $C00040 ; to $C0007F ; alias for $40 to $7FSerhZero EQU $130SertZero EQU $132farflag EQU $15Fasmbuf EQU $160 ; to $17FQNdx0 EQU $780QNdx1 EQU QNdx0+2QNdx2 EQU QNdx1+2QNdx3 EQU QNdx2+2QNdx4 EQU QNdx3+2FreeTCB EQU QNdx4+2TimeoutList EQU FreeTCB+2FreeMbx EQU RunningTCB + 2nMailbox EQU FreeMbx + 2FreeMsg EQU nMailbox + 2nMsgBlk EQU FreeMsg + 2CharOutVec EQU $800CharInVec EQU $804CmdPromptJI EQU $808MonErrVec EQU $80CBreakpointFlag EQU $810NumSetBreakpoints EQU $811 ; to 812Breakpoints EQU $820 ; to $82FBreakpointBytes EQU $830 ; to $83Fmon_vectb EQU $880; Register save area for monitormon_DSAVE EQU $900mon_XSAVE EQU $902mon_YSAVE EQU $904mon_USAVE EQU $906mon_SSAVE EQU $908mon_PCSAVE EQU $90Amon_DPRSAVE EQU $90Emon_CCRSAVE EQU $90Fmon_numwka EQU $910mon_r1 EQU $920mon_r2 EQU $924jmpvec EQU $928mon_init EQU $92Cmon_retflag EQU $930; The ORG directive must set an address a multiple of 4 in order for the Verilog; output to work correctly.org $FFD0ACnopnopnopXBLANKldb #' 'lbsr OUTCHrtsorg $FFD0D0nopnopCRLFCRLF1:ldb #CRlbsr OUTCHldb #LFlbsr OUTCHrtsorg $FFD0F0nopbra CRLF1org $FFD1DCONEKEYjmp [CharInVec]org $FFD2C0nopLETTERlbsr OUTCHrtsorg $FFD2CCnopnopHEX2lbsr DispByteAsHexrtsHEX4lbsr DispWordAsHexrtsorg $FFD300ClearScreenJmplbra ClearScreenorg $FFD308HomeCursorJmplbra HomeCursororg $FFD400; Local RAM test routine; Checkerboard testing.; There is 70kB of local RAM; Does not use any RAM including no stackramtest:ldy #0lda #1sta LEDSldd #$AAA555ramtest1:std ,y++cmpy #$8000blo ramtest1; now readback values and compareldy #0ramtest3:ldd ,y++cmpd #$AAA555bne ramerrcmpy #$8000blo ramtest3lda #2sta LEDSjmp ,uramerr:lda #$80sta LEDSldb COREIDcmpb #$20beq ramerr1ldx #TEXTSCRabxlda #'F'sta ,xsyncramerr1:jmp ,uorg $FFE000FDB MonitorFDB DumRts ; NEXTCMDFDB INCHFDB INCHEFDB INCHEKFDB OUTCHFDB PDATAFDB PCRLFFDB PSTRNGFDB DumRts ; LRAFDB DumRtsFDB DumRtsFDB DumRtsFDB DumRts ; VINIZFDB DisplayChar ; VOUTCHFDB DumRts ; ACINIZFDB DumRts ; AOUTCHDumRts:rts;------------------------------------------------------------------------------;------------------------------------------------------------------------------start:lda #$FFF ; all cores can do thissta VIA+VIA_DDRAlda #$55 ; see if we can at least set LEDssta LEDSlda #1 ; prime OS semaphoresta OSSEMA+$1000sta OUTSEMA+$1000ldu #st6 ; U = return address; jmp ramtest ; JMP dont JSRst6:lds #$6FFF ; boot up stack arealda COREIDcmpa #FIRST_CORE; beq st8; sync ; halt cores other than 2st8:; bne skip_init; bsr romToRam; ldd #st7 & $FFFF; tfr d,x; jmp ,x ; jump to the BIOS now in local RAMst7:bsr Delay3s ; give some time for devices to resetclr BreakpointFlagclr NumSetBreakpointslda #$AAsta LEDSlda COREIDcmpa #$20beq st11lda #FIRST_COREst11:sta IOFocusID ; core #2 has focussta RunningID; Clear IO focus listldx #0st9:clr IOFocusList,xinxcmpx #16blo st9lda #24sta IOFocusList+FIRST_CORElda #$0CEsta ScreenColorsta CharColorbsr ClearScreenldd #DisplayCharstd CharOutVecldd #SerialPeekCharDirectstd CharInVec; swi; fcb MF_OSCALL; fcb 24 ; request IO focusldb COREIDcmpb #FIRST_COREbeq initcmpb #$20 ; CmodA709 core?beq init2bra skip_initbra multi_sievest3:lda #$FFsta LEDSbra st3; initialize interrupt controller; first, zero out all the vectorsinit:lbsr rtc_read ; get clock valuesldx #kbdHeadRcvldb #32 ; number of bytes to zero outinit1:clr ,x+decbbne init1ldx #128 ; register to start atst1:clr PIC,x ; cause codesta PIC+1,xstb PIC+2,xleax 4,xcmpx #256 ; max regblo st1lda #$C1 ; make irq edge sensitive (bit 7), enable interupt (bit 6), irq (bit 0)sta PIC+$FDlda #$41 ; level sensitive, enabled, irqsta PIC+$D1 ; serial irq is #20lda #COLSsta TEXTREG+TEXT_COLSlda #ROWSsta TEXTREG+TEXT_ROWSbsr ClearScreenbsr HomeCursorldx #0ldd #0lbsr ShowSpriteslbsr KeybdInitldd KeybdIDbsr DispWordAsHexinit2:lbsr TimerInitlbsr InitSerialldx #128lda #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 enableldb #1stb OUTSEMA+SEMAABS ; set semaphore to 1 available slotskip_init:andcc #$EF ; unmask irqlda #5sta LEDSldd #msgStartupbsr DisplayStringst10:swifcb MF_Monitorbra st10msgStartupfcb "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 dorts;------------------------------------------------------------------------------; 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 #$FFC000ldy #$00C000romToRam1:ldd ,x++std ,y++cmpx #0bne romToRam1rts;------------------------------------------------------------------------------; 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 primeldb COREID ; find out which core we aresubb #FIRST_COREldx #0 ; start at first char of screenabxmulti_sieve3:sta TEXTSCR,x ; store 'P'leax 8,x ; advance to next positioncmpx #4095blo multi_sieve3jsr checkpointaddb #2 ; start sieve at 2 (core id)lda #'N' ; flag position value of 'N' for non-primemulti_sieve2:ldx #0abx ; skip the first position - might be primemulti_sieve1:abx ; incrementsta TEXTSCR,xcmpx #4095blo multi_sieve1jsr checkpointaddb #8 ; number of cores working on itcmpb #4080blo multi_sieve2multi_sieve4: ; hang machinesynclbra Monitor;------------------------------------------------------------------------------; Single core sieve.;------------------------------------------------------------------------------sieve:lda #'P' ; indicate primeldx #0 ; start at first char of screensieve3:sta TEXTSCR,x ; store 'P'inx ; advance to next positioncmpx #4095blo sieve3ldb #2 ; start sieve at 2lda #'N' ; flag position value of 'N' for non-primesieve2:ldx #0abx ; skip the first position - might be primesieve1:abx ; incrementsta TEXTSCR,xcmpx #4095blo multi_sieve1incb ; number of cores working on itcmpb #4080blo sieve2sieve4: ; hang machinerts;------------------------------------------------------------------------------; Three second delay for user convenience and to allow some devices time to; reset.;------------------------------------------------------------------------------Delay3s:ldd #9000000dly3s1:cmpb #$FFbne dly3s2dly3s2:sta LEDSsubd #1bne dly3s1rts;------------------------------------------------------------------------------;------------------------------------------------------------------------------ShiftLeft5:aslbrolaaslbrolaaslbrolaaslbrolaaslbrolarts;------------------------------------------------------------------------------; 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,aaslaaslaaslaaslaora #$C00clrbtfr d,xpshs dldy #TEXTSCRldu #COLS*ROWS/2cv2s1:ldd ,x++std ,y++leau -1,ucmpu #0bne cv2s1; reset the cursor position in the text controllerpuls xldb CursorRow,xlda #COLSmultfr d,yldb CursorCol,xtfr y,xabxstx TEXTREG+TEXT_CURPOSpuls d,x,y,u,pc;------------------------------------------------------------------------------;------------------------------------------------------------------------------;CopyScreenToVirtualScreen:pshs d,x,y,ubsr GetScreenLocationtfr d,yldx #TEXTSCRldu #COLS*ROWS/2cs2v1:ldd ,x++std ,y++leau -1,ucmpu #0bne cs2v1puls d,x,y,u,pc;------------------------------------------------------------------------------;------------------------------------------------------------------------------fcb "TEXTSCR "fcw TextOpenfcw TextClosefcw TextReadfcw TextWritefcw TextSeekTextOpen:rtsTextClose:rtsTextRead:rtsTextWrite:rtsTextSeek: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,uldx #COLS*ROWStfr x,ubsr GetScreenLocationtfr d,yldb #' ' ; space charcs1:stb ,y+ ; set text to spaceleax -1,x ; decrement xbne cs1ldb COREID ; update colors only if we have focuscmpb IOFocusIDbra cs3ldy #TEXTSCR+$2000; lda CharColorlda #$0CEtfr u,x ; get back countcs2:sta ,y+dex ; decrement xbne cs2cs3:puls d,x,y,u,pc;------------------------------------------------------------------------------; Scroll text on the screen upwards;; Modifies:; none;------------------------------------------------------------------------------ScrollUp:pshs d,x,y,uldy #(COLS*ROWS-1)/2 ; y = num chars/2 to movebsr GetScreenLocationtfr d,xtfr d,uleax COLS,x ; x = index to source rowscrup1:ldd ,x++ ; move 2 charactersstd ,u++deybne scrup1lda #ROWS-1bsr BlankLinepuls d,x,y,u,pc;------------------------------------------------------------------------------; Blank out a line on the display;; Modifies:; none; Parameters:; acca = line number to blank;------------------------------------------------------------------------------BlankLine:pshs d,xpshs absr GetScreenLocationtfr d,xpuls aldb #COLS ; b = # chars to blank out from video controllermul ; d = screen index (row# * #cols)leax d,xlda #' 'ldb #COLS ; b = # chars to blank out from video controllerblnkln1:sta ,x+decbbne blnkln1puls 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 focusbne gsl1 ; no, go pick virtual screen addresscmpa #$20 ; CmodA709?beq gsl1ldd #TEXTSCR ; yes, we update the real screenrtsgsl1:ldd #$7800rts;------------------------------------------------------------------------------; HomeCursor; Set the cursor location to the top left of the screen.;; Modifies:; none;------------------------------------------------------------------------------HomeCursor:pshs d,xclr CursorRowclr CursorColldb COREIDcmpb IOFocusIDbne hc1cmpb #$20beq hc1clrasta TEXTREG+TEXT_CURPOShc1:puls d,x,pc;------------------------------------------------------------------------------; Update the cursor position in the text controller based on the; CursorRow,CursorCol.;; Modifies:; none;------------------------------------------------------------------------------;UpdateCursorPos:pshs d,xldb COREID ; update cursor position in text controllercmpb IOFocusID ; only for the task with the output focusbne ucp1cmpb #$20 ; and not for CmodA709beq ucp1lda CursorRowanda #$3F ; limit of 63 rowsldb TEXTREG+TEXT_COLSmultfr d,xldb CursorColabxstx TEXTREG+TEXT_CURPOSucp1:puls d,x,pc;------------------------------------------------------------------------------; Calculate screen memory location from CursorRow,CursorCol.; Also refreshes the cursor location.;; Modifies:; d; Returns:; d = screen location;------------------------------------------------------------------------------;CalcScreenLoc:pshs xlda CursorRowldb #COLSmultfr d,xldb CursorColabxldb COREID ; update cursor position in text controllercmpb IOFocusID ; only for the task with the output focusbne csl1cmpb #$20beq csl1stx TEXTREG+TEXT_CURPOScsl1:bsr GetScreenLocationleax d,xtfr x,dpuls 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 SerialPutCharScreenDisplayChar:pshs d,xcmpb #CR ; carriage return ?bne dccrclr CursorCol ; just set cursor column to zero on a CRbsr UpdateCursorPosdcx14:lbra dcx4dccr:cmpb #$91 ; cursor right ?bne dcx6lda CursorColcmpa #COLSbhs dcx7incasta CursorColdcx7:bsr UpdateCursorPospuls d,x,pcdcx6:cmpb #$90 ; cursor up ?bne dcx8lda CursorRowbeq dcx7decasta CursorRowbra dcx7dcx8:cmpb #$93 ; cursor left ?bne dcx9lda CursorColbeq dcx7decasta CursorColbra dcx7dcx9:cmpb #$92 ; cursor down ?bne dcx10lda CursorRowcmpa #ROWSbeq dcx7incasta CursorRowbra dcx7dcx10:cmpb #$94 ; cursor home ?bne dcx11lda CursorColbeq dcx12clr CursorColbra dcx7dcx12:clr CursorRowbra dcx7dcx11:cmpb #$99 ; delete ?bne dcx13bsr CalcScreenLoctfr d,xlda CursorCol ; acc = cursor columnbra dcx5dcx13cmpb #CTRLH ; backspace ?bne dcx3lda CursorColbeq dcx4decasta CursorColbsr CalcScreenLoctfr d,xlda CursorColdcx5:ldb 1,xstb ,x++incacmpa #COLSblo dcx5ldb #' 'dexstb ,xbra dcx4dcx3:cmpb #LF ; linefeed ?beq dclfpshs bbsr CalcScreenLoctfr d,xpuls bstb ,x; ToDo character color; lda CharColor; sta $2000,xbsr IncCursorPosbra dcx4dclf:bsr IncCursorRowdcx4:puls d,x,pc;------------------------------------------------------------------------------; Increment the cursor position, scroll the screen if needed.;; Modifies:; none;------------------------------------------------------------------------------IncCursorPos:pshs d,xlda CursorColincasta CursorColcmpa #COLSblo icc1clr CursorCol ; column = 0bra icr1IncCursorRow:pshs d,xicr1:lda CursorRowincasta CursorRowcmpa #ROWSblo icc1deca ; backup the cursor row, we are scrolling upsta CursorRowbsr ScrollUpicc1:bsr UpdateCursorPosicc2:puls d,x,pc;------------------------------------------------------------------------------; Display a string on the screen.;; Modifies:; none; Parameters:; d = pointer to string;------------------------------------------------------------------------------;DisplayString:pshs d,xtfr d,xlda COREIDcmpa #$20beq dspj1Bdspj2: ; lock semaphore for accesslda OUTSEMA+1beq dspj2dspj1B:ldb ,x+ ; move string char into accbeq dsretB ; is it end of string ?lbsr OUTCH ; display characterbra dspj1BdsretB:clr OUTSEMA+1 ; unlock semaphorepuls d,x,pcDisplayStringCRLF:pshs dbsr DisplayStringldb #CRlbsr OUTCHldb #LFlbsr OUTCHpuls d,pc;; PRINT CR, LF, STRING;PSTRNGBSR PCRLFBRA PDATAPCRLFPSHS XLDX #CRLFSTBSR PDATAPULS XRTSJSR OUTCHPDATALDB ,X+CMPB #$04BNE PRINTRTSCRLFSTfcb CR,LF,4DispDWordAsHex:bsr DispWordAsHexexg d,xbsr DispWordAsHexexg d,xrtsDispWordAsHex:exg a,bbsr DispByteAsHexexg a,bbsr DispByteAsHexrtsDispByteAsHex:pshs blsrblsrblsrblsrblsrblsrblsrblsrbbsr DispNybpuls bpshs blsrblsrblsrblsrbbsr DispNybpuls bDispNybpshs bandb #$0Fcmpb #10blo DispNyb1addb #'A'-10lbsr OUTCHpuls b,pcDispNyb1addb #'0'lbsr OUTCHpuls 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 KeybdOpenfcw KeybdClosefcw KeybdReadfcw KeybdWritefcw 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:rtsKeybdSeek: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 bINCH2:ldb COREIDcmpb IOFocusID ; if we do not have focus, blockbne INCH2; ldb #$800 ; block if no key available, get scancode directly; bra GetKey; jsr [CharInVec] ; vector is being overwritten somehowlbsr SerialPeekCharDirect; lbsr SerialGetChartstabmi INCH1 ; block if no key availableleas 1,s ; get rid of blocking statusrts ; return characterINCH1:puls b ; check blocking statuststbbmi INCH ; if blocking, loopldd #-1 ; return -1 if no char availablertsINCHE:bsr INCHbra INCHEK3INCHEK:bsr INCHtst KeybdEchobeq INCHEK1INCHEK3:cmpa #CRbne INCHEK2lbsr CRLFbra INCHEK1INCHEK2:lbsr DisplayCharINCHEK1:rtsOUTCH:jmp [CharOutVec];------------------------------------------------------------------------------; r1 0=echo off, non-zero = echo on;------------------------------------------------------------------------------;SetKeyboardEcho:stb KeybdEchorts;------------------------------------------------------------------------------; Parameters:; x,d bitmap of sprites to enable;------------------------------------------------------------------------------ShowSprites:stx SPRITE_CTRL+SPRITE_ENstd SPRITE_CTRL+SPRITE_EN+2rts;==============================================================================; Femtiki Operating System.;==============================================================================OSCallTbl:fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw 0fcw ReleaseIOFocusfcw 0fcw RequestIOFocusNumOSFuncs EQU (*-OSCallTbl)/2RequestIOFocus:ldb COREIDldx #IOFocusListabxsta ,xtst IOFocusIDlbne oscxstb IOFocusIDlbra oscxReleaseIOFocus:ldb COREIDldx #IOFocusListabxclr ,x ; clear the request indicatorlbsr CopyScreenToVirtualScreencmpb 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 #15riof2:incbandb #15abxtst ,xbne riof1decabne riof2; If no focus is requested by anyone, give to core #1ldb #1lda #24sta ,xriof1:stb IOFocusIDlbsr CopyVirtualScreenToScreenlbra 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 #0mon_srand1:sty PRNG+4 ; select channelclr PRNG+8clr PRNG+9std PRNG+10 ; update low half of valueclr PRNG+12clr PRNG+13stx PRNG+14 ; update low half of valueinycmpy #$400 ; 1k channelsblo mon_srand1rts;------------------------------------------------------------------------------; 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 channelldx PRNG+0ldd PRNG+2stb PRNG+3 ; trigger calc of next numberrts;==============================================================================; System Monitor;==============================================================================; Command TablescmdTable1:fcb '<','>'+$800fcb 'B','+'+$800fcb 'B','-'+$800fcb 'D','R'+$800fcb 'D'+$800fcb ':'+$800fcb "FI",'G'+$800fcb "FI",'L'+$800fcb 'F','L'+$800fcb 'J'+$800fcb "RAMTES",'T'+$800fcb "SP",'D'+$800fcb "TI",'R'+$800fcb 'U'+$800fcb "exi",'t'+$800fcb '?'+$800fcb "CL",'S'+$800fcb "C1",'9'+$800fcb "JD",'4'+$800fcb "XM",'R'+$800fcb "XM",'S'+$800fcb 'R','A'+$800fcb 'R','B'+$800fcb "RDP",'R'+$800fcb 'R','D'+$800fcb 'R','X'+$800fcb 'R','Y'+$800fcb 'R','U'+$800fcb 'R','S'+$800fcb "RCC",'R'+$800fcb "RP",'C'+$800fcb 'L','B'+$800fcw 0cmdTable2:fcw Redirectfcw MonArmBreakpointfcw MonDisarmBreakpointfcw DumpRegsfcw DumpMemoryfcw EditMemoryfcw $FE0000 ; FIG forthfcw FillMemoryfcw DumpIOFocusListfcw jump_to_codefcw $FFD400fcw $FF8000 ; sprite demofcw rtc_readfcw $FF8003 ; unassemblerfcw xitMonitorfcw PromptHelpfcw PromptClearscreenfcw S19Loaderfcw $FFD400fcw xm_ReceiveStartfcw xm_SendStartfcw SetRegAfcw SetRegBfcw SetRegDPRfcw SetRegDfcw SetRegXfcw SetRegYfcw SetRegUfcw SetRegSfcw SetRegCCRfcw SetRegPCfcw ListBreakpointsCmdPrompt:lbsr CRLFldb #'$'lbsr OUTCHlbra OUTCHmsgF09Starting:fcb "Femtiki F09 Multi-core OS Starting",CR,LF,0Monitor:andcc #$EF ; SWI disables interrupts, re-enable themlda #31 ; Timer is IRQ #31sta PIC+16 ; register 16 is edge sense reset regldd mon_init ; check special code to see if monitor has been initializedcmpd #1234567beq mon1clr BreakpointFlagclr NumSetBreakpointsldd #123ldx #654lbsr mon_srandldd #msgF09Startinglbsr DisplayStringldd #HelpMsglbsr DisplayStringldd #CmdPromptstd CmdPromptJIldd #DisplayErrstd MonErrVecldd #$63FF ; default app stackstd mon_SSAVEclr mon_DPRSAVE ;tfr ccr,asta mon_CCRSAVEclr mon_PCSAVEldd #Monitorstd mon_PCSAVE+1clr mon_XSAVEclr mon_YSAVEclr mon_USAVEldd #1234567std mon_initmon1:leas $6FFF ; reset stack pointerclrb ; turn off keyboard echolbsr SetKeyboardEcho; Reset IO vectorsldd #SerialPeekCharDirectstd CharInVecldd #DisplayCharstd CharOutVecldd #CmdPromptstd CmdPromptJI; jsr RequestIOFocusPromptLn:jsr [CmdPromptJI]; Get characters until a CR is keyedPrompt3:ldd #-1 ; block until key presentlbsr INCHtsta ; should not get this with blockingbmi Prompt3cmpb #CR ; carriage return?beq Prompt1lbsr OUTCH ; spit out the characterbra Prompt3 ; and keep going; Process the screen line that the CR was keyed on;Prompt1:ldd #$5050std LEDS; ldb RunningID; cmpb #61; bhi Prompt3clr CursorCol ; go back to the start of the linelbsr CalcScreenLoc ; calc screen memory locationtfr d,yskipDollar:bsr MonGetNonSpacecmpb #'$'beq skipDollar ; skip over '$' prompt character; Dispatch based on command;deytfr y,u ; save off input positionclrbldx #cmdTable1parseCmd1:lda ,y+ ; get input charactertst ,x ; test for end of commandbmi endOfWord ;cmpa ,x+ ; does input match command?beq parseCmd1scanNextWord:tst ,x+beq Monitor ; if end of table reached, not a commandbpl scanNextWordincbtfr u,y ; reset input pointerbra parseCmd1 ; try againendOfWord:eora ,xaslabne scanNextWord; we found the command in the tableaslb ; b = word indexldx #cmdTable2jmp [b,x] ; execute commandRedirect:bsr MonGetchcmpb #'s'bne Prompt2aldd #SerialPeekCharDirectstd CharInVecldd #SerialPutCharstd CharOutVecbra MonitorPrompt2a:cmpb #'c'bne Monitorldd #GetKeystd CharInVecldd #DisplayCharstd CharOutVecbra MonitorPromptHelp:ldd #HelpMsglbsr DisplayStringbra MonitorPromptClearscreen:lbsr ClearScreenlbsr HomeCursorbra MonitorMonGetch:ldb ,yinyrtsMonGetNonSpace:bsr MonGetChcmpb #' 'beq MonGetNonSpacertsMonArmBreakpoint:lbsr ArmBreakpointldb #$FFFstb BreakpointFlaglbra MonitorMonDisarmBreakpoint:lbsr DisarmBreakpointlbra Monitor;------------------------------------------------------------------------------; Ignore blanks in the input; Y = text pointer; D destroyed;------------------------------------------------------------------------------;ignBlanks:ignBlanks1:bsr MonGetchcmpb #' 'beq ignBlanks1deyrts;------------------------------------------------------------------------------; Multiply number in work area by 10.;------------------------------------------------------------------------------Times10:pshs dldd mon_numwka ; make a copy of the numberstd mon_numwka+8ldd mon_numwka+2std mon_numwka+10bsr shl_numwka ; shift left = *2bsr shl_numwka ; shift left = *4ldd mon_numwka+2 ; add in original valueaddd mon_numwka+10 ; = *5ldb mon_numwka+1adcb mon_numwka+9stb mon_numwka+1lda mon_numwka+0adca mon_numwka+8sta mon_numwka+0bsr shl_numwka ; shift left = * 10puls d,pc;------------------------------------------------------------------------------;------------------------------------------------------------------------------GetTwoParams:bsr ignBlanksbsr GetNumber ; get start address of dumpldd mon_numwkastd mon_r1ldd mon_numwka+2std mon_r1+2bsr ignBlanksbsr GetNumber ; get end address of dumpldd mon_numwkastd mon_r2ldd mon_numwka+2std mon_r2+2rts;------------------------------------------------------------------------------; Get a range, the end must be greater or equal to the start.;------------------------------------------------------------------------------GetRange:bsr GetTwoParamsldd mon_r2+2subd mon_r1+2ldd mon_r2sbcb mon_r1+1sbca mon_r1lbcc grng1jsr [MonErrVec]lbra Monitorgrng1:rtsshl_numwka:asl mon_numwka+3rol mon_numwka+2rol mon_numwka+1rol mon_numwkarts;------------------------------------------------------------------------------; Get a hexidecimal number. Maximum of twelve digits.;; Modifies:; Y = text pointer (updated); D = number of digits; mon_numwka contains number;------------------------------------------------------------------------------;GetHexNumber:clrdstd mon_numwka ; zero out work areastd mon_numwka+2pshs xldx #0 ; max 12 eight digitsgthxn2:bsr MonGetchbsr AsciiToHexNybblecmpb #-1beq gthxn1bsr shl_numwkabsr shl_numwkabsr shl_numwkabsr shl_numwkaandb #$0forb mon_numwka+3stb mon_numwka+3inxcmpx #12blo gthxn2gthxn1:tfr x,dpuls x,pcGetBinNumber:clrdstd mon_numwkastd mon_numwka+2pshs xldx #0gtbin2:bsr MonGetchbsr AsciiToBinDigittstbbmi gtbin1bsr shl_numwkaorb mon_numwka+3stb mon_numwka+3inxcpx #48blo gtbin2gtbin1:tfr x,dpuls x,pcGetDecNumber:clrdstd mon_numwkastd mon_numwka+2pshs xldx #0gtdec2:bsr MonGetchbsr AsciiToDecDigittstbbmi gtdec1bsr Times10addb mon_numwka+3stb mon_numwka+3ldb mon_numwka+2adcb #0stb mon_numwka+2ldb mon_numwka+1adcb #0stb mon_numwka+1ldb mon_numwka+0adcb #0stb mon_numwka+0inxcpx #15blo gtdec2gtdec1:tfr x,dpuls x,pcGetNumber:bsr MonGetchcmpb #'+'beq GetDecNumbercmpb #'%'beq GetBinNumberdeybra 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 gthx3cmpb #'9'bhi gthx5subb #'0'rtsgthx5:cmpb #'A'blo gthx3cmpb #'F'bhi gthx6subb #'A'addb #10rtsgthx6:cmpb #'a'blo gthx3cmpb #'z'bhi gthx3subb #'a'addb #10rtsgthx3:ldb #-1 ; not a hex numberrtsAsciiToDecDigit:cmpb #'0'blo gtdc3cmpb #'9'bhi gtdc3subb #'0'rtsgtdc3:ldb #-1rtsAsciiToBinDigit:cmpb #'0'bne abd1clrbrtsabd1:cmpb #'1'bne abd2ldb #1rtsabd2:ldb #-1rtsDisplayErr:ldd #msgErrlbsr DisplayStringjmp MonitorDisplayStringDXstd Strptrstx Strptr+2jsr DisplayStringrtsmsgErr:fcb "**Err",CR,LF,0HelpMsg:fcb "? = Display help",CR,LFfcb "CLS = clear screen",CR,LFfcb "b+ = set breakpoint",CR,LFfcb "b- = clear breakpoint",CR,LFfcb "C19 = run C19 loader",CR,LF; db "S = Boot from SD Card",CR,LFfcb ": = Edit memory bytes",CR,LF; db "L = Load sector",CR,LF; db "W = Write sector",CR,LFfcb "DR = Dump registers",CR,LFfcb "D = Dump memory",CR,LFfcb "F = Fill memory",CR,LFfcb "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,LFfcb "J = Jump to code",CR,LFfcb "JD4 = Jump to $FFD400",CR,LFfcb "R[n] = Set register value",CR,LF; db "r = random lines - test bitmap",CR,LF; db "e = ethernet test",CR,LFfcb "s = serial output test",CR,LFfcb "SP = sprite demo",CR,LF; db "T = Dump task list",CR,LF; db "TO = Dump timeout list",CR,LFfcb "TI = display date/time",CR,LF; db "TEMP = display temperature",CR,LFfcb "U = unassemble",CR,LF; db "P = Piano",CR,LFfcb "XM = xmodem transfer",CR,LFfcb "x = exit monitor",CR,LFfcb 0msgRegHeadingsfcb CR,LF," D/AB X Y U S PC DP CCR",CR,LF,0nHEX4:jsr HEX4rtsnXBLANK: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 GetRangeldy #0ldy mon_r1+2dmpm2:lbsr CRLFldb #':'lbsr OUTCHtfr y,d;addd mon_r1+2 ; output the addresslbsr DispWordAsHexldb #' 'lbsr OUTCHldx #8 ; number of bytes to displaydmpm1:; ldb far [mon_r1+1],y;ldb [mon_r1+2],yldb ,yinylbsr DispByteAsHex ; display byteldb #' ' ; followed by a spacelbsr OUTCHclrbclralbsr INCHcmpb #CTRLCbeq dmpm3dexbne dmpm1; Now output asciildb #' 'lbsr OUTCHldx #8 ; 8 chars to outputleay -8,y ; backup pointerdmpm5:; ldb far [mon_r1+1],y ; get the char; ldb [mon_r1+2],y ; get the charldb ,ycmpb #$20 ; is it a control char?bhs dmpm4ldb #'.'dmpm4:lbsr OUTCHinydexbne dmpm5cmpy mon_r2+2blo dmpm2dmpm3:lbsr CRLFlbra 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 countlbsr ignBlankslbsr GetHexNumber ; get the start addressldx mon_numwka+2EditMem2:lbsr ignBlanks ; skip over blankslbsr GetHexNumber ; get the byte valuetstb ; check for valid valuebeq EditMem1 ; if invalid, quitldb mon_numwka+3 ; get valuestb ,x+ ; update memory at addressleau -1,u ; decremeent byte countcmpu #0bne EditMem2 ; go back for annother byteEditMem1:lbsr MonGetch ; see if a string is being enteredcmpb #'"'bne EditMem3 ; no string, we're doneldu #40 ; string must be less than 40 charsEditMem4:lbsr MonGetch ; look for close quotecmpb #'"'bne EditMem6 ; end of string?ldu #8 ; reset the byte countbra EditMem2EditMem6:stb ,x+ ; store the character in memoryleau -1,u ; decrement byte countcmpu #0bhi EditMem4 ; max 40 charsEditMem3:lbra Monitor;------------------------------------------------------------------------------; Fill Memory;; Usage:; $$F FFFC12 FFFC30 89F;;------------------------------------------------------------------------------FillMemory:lbsr GetRange ; get address range to filllbsr ignBlankslbsr GetHexNumber ; get target byte to writeldb mon_numwka+3ldx mon_r1+2clrafillm1: ; Check for a CTRL-C every page of memorytstabne fillm2clrb ; we want a non-blocking checkclralbsr INCHcmpb #CTRLClbeq Monitorldb mon_numwka+3 ; reset target bytefillm2:stb ,x+cmpx mon_r2+2bls fillm1fillm3:lbra Monitor;------------------------------------------------------------------------------; Dump Registers;; Usage:; $DR;------------------------------------------------------------------------------DumpRegs:ldd #msgRegHeadingslbsr DisplayStringbsr nXBLANKldd mon_DSAVEbsr nHEX4bsr nXBLANKldd mon_XSAVEbsr nHEX4bsr nXBLANKldd mon_YSAVEbsr nHEX4bsr nXBLANKldd mon_USAVEbsr nHEX4bsr nXBLANKldd mon_SSAVEbsr nHEX4bsr nXBLANKldb mon_PCSAVE+1lbsr DispByteAsHexldd mon_PCSAVE+2bsr nHEX4bsr nXBLANKldd mon_DPRSAVEjsr HEX2bsr nXBLANKlda mon_CCRSAVElbsr HEX2bsr nXBLANKlbra Monitor;------------------------------------------------------------------------------; SetRegXXX;; Set the value to be loaded into a register.;------------------------------------------------------------------------------SetRegA:lbsr ignBlankslbsr GetNumberlda mon_numwka+3sta mon_DSAVElbra MonitorSetRegB:lbsr ignBlankslbsr GetNumberlda mon_numwka+3sta mon_DSAVE+1lbra MonitorSetRegD:lbsr ignBlankslbsr GetNumberldd mon_numwka+2std mon_DSAVElbra MonitorSetRegX:lbsr ignBlankslbsr GetNumberldd mon_numwka+2std mon_XSAVElbra MonitorSetRegY:lbsr ignBlankslbsr GetNumberldd mon_numwka+2std mon_YSAVElbra MonitorSetRegU:lbsr ignBlankslbsr GetNumberldd mon_numwka+2std mon_USAVElbra MonitorSetRegS:lbsr ignBlankslbsr GetNumberldd mon_numwka+2std mon_SSAVElbra MonitorSetRegDPR:lbsr ignBlankslbsr GetNumberlda mon_numwka+3sta mon_DPRSAVElbra MonitorSetRegCCR:lbsr ignBlankslbsr GetNumberlda mon_numwka+3sta mon_CCRSAVElbra MonitorSetRegPC:lbsr ignBlankslbsr GetNumberldd mon_numwka+2std mon_PCSAVE+2ldb mon_numwka+1stb mon_PCSAVE+1lbra 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 ignBlankslbsr GetNumberseilds mon_SSAVEldd #jtc_exit ; setup stack for RTS back to monitorpshs dldb #0pshs bldd mon_USAVEpshs dldd mon_YSAVEpshs dldd mon_XSAVEpshs dlda mon_DPRSAVEpshs aldd mon_DSAVEpshs dlda mon_CCRSAVEpshs apuls far ccr,d,dpr,x,y,ujmp far [mon_numwka+1]jtc_exit:sts >mon_SSAVE ; need to use extended addressing, no direct page settingleas $6FFF ; reset stack to system area, dont modify flags register!pshs ccr ; now the stack can be usedpshs a ; save acca register so we can use ittfr dpr,a ; a = outgoing dpr valuesta >mon_DPRSAVE ; force extended addressing mode usage here dpr is not setclra ; dpg register must be set to zero before values aretfr a,dpr ; saved in the monitor register save area.puls a ; get back accastd mon_DSAVE ; save regsters, can use direct addressing nowstx mon_XSAVEsty mon_YSAVEstu mon_USAVEpuls a ; get back ccrsta mon_CCRSAVE ; and save it too; Reset vectors in case they got toasted.ldd #SerialPeekCharDirectstd CharInVecldd #DisplayCharstd CharOutVecldd DisplayErrstd MonErrVec; todo set according to coreidlbra DumpRegs ; now go do a register dump;------------------------------------------------------------------------------;------------------------------------------------------------------------------DumpIOFocusList:ldx #0dfl2:ldb IOFocusList,xcmpb #24bne dfl1tfr x,dlbsr DispByteAsHexldb #' 'lbsr OUTCHdfl1:inxcmpx #16blo dfl2lbsr CRLFlbra Monitorbootpg:fcb $000boot_stack:fcw $FFC0FFnumBreakpoints:fcw 8mon_rom_vectab:fcw mon_rom_vecsmon_rom_vecs:fcw Monitor ; enter monitor programfcw INCH ; input a characterfcw OUTCH ; output a characterfcw CRLF ; output carriage-return, line feedfcw DisplayStringfcw DispByteAsHexfcw DispWordAsHexfcw ShowSpritesfcw mon_srandfcw mon_randfcw 0 ; operating system callfcw GetRangefcw GetNumberfcw SerialPutCharNumFuncs 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 ; monitorfcb $800 ; INCHfcb 0 ; OUTCHfcb 0 ; CRLFfcb 0 ; DisplayStringfcb 0 ; DisplayBytefcb 0 ; DisplayWordfcb 0 ; show spritesfcb 0 ; srandfcb $C00 ; randfcb $C00 ; OS callfcb 0 ; GetRangefcb $800 ; GetNumberfcb 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 pagetfr b,dpswi_rout1:ldu 11,s ; get program counter (low order 2 bytes)leau -1,u ; backup a bytetst BreakpointFlag ; are we in breakpoint mode?beq swiNotBkptldy #Breakpointsldb NumSetBreakpointsbeq swiNotBkptswi_rout2:cmpu ,y++beq processBreakpointdecbbne swi_rout2swiNotBkpt:clr BreakpointFlagpulu d ; get function #, increment PCcmpb #NumFuncslbhi DisplayErrstu 11,s ; save updated PC on stackcmpb #MF_OSCALLbeq swiCallOSaslb ; 2 bytes per vectorldx mon_rom_vectab,pcrabxldx ,xstx jmpveclsrbldx #mon_rettababxldb ,xstb mon_retflagsts mon_SSAVE ; save the stack pointerldd 1,s ; get back Dldx 4,s ; get back Xldy 6,s ; get back Yldu 8,s ; get back Ulds boot_stack,pcr ; and use our own stackjsr [jmpvec] ; call the routineswi_rout3:lds mon_SSAVE ; restore stacktst mon_retflagbpl swi_rout4std 1,s ; return value in Dasl mon_retflagbpl swi_rout4stx 4,s ; return value in Xswi_rout4:rti;------------------------------------------------------------------------------; A breakpoint was struck during program execution, process accordingly.;------------------------------------------------------------------------------processBreakpoint:lda ,ssta mon_CCRSAVEldd 1,sstd mon_DSAVEldb 3,sstb mon_DPRSAVEldd 4,sstd mon_XSAVEldd 6,sstd mon_YSAVEldd 8,sstd mon_USAVEsts mon_SSAVEldb 10,sstb mon_PCSAVEldd 11,sstd mon_PCSAVE+1lds boot_stack,pcrldd #swi_rout3 ; setup so monitor can returnpshs dbsr DisarmAllBreakpointslbra DumpRegsxitMonitor:bra ArmAllBreakpoints;------------------------------------------------------------------------------;------------------------------------------------------------------------------swiCallOS:leau 1,u ; next byte is func numberldb ,u+cmpb #NumOSFuncs ; check for valid rangelbhi DisplayErrstu 11,s ; save updateed PC on stackaslb ; compute vector addressldx #OSCallTbltst b,x ; check for non-zero vectorbeq swi_rout3osc1:; tst OSSEMA+1 ; wait for availability; beq osc1jsr [b,x] ; call the OS routineoscx:clr OSSEMA+1bra swi_rout3;------------------------------------------------------------------------------; DisarmAllBreakpoints, used when entering the monitor.;------------------------------------------------------------------------------DisarmAllBreakpoints:pshs d,x,yldy #0clrbldx #BreakpointBytes ; x = breakpoint byte table addressdisarm2:cmpb #numBreakpoints ; safety checkbhs disarm1cmpb NumSetBreakpointsbhs disarm1lda b,x ; get memory bytesta [Breakpoints,y] ; and store it back to memoryleay 2,y ; increment for next addressincb ; increment to next bytebra disarm2 ; loop backdisarm1:puls d,x,y,pc;------------------------------------------------------------------------------;------------------------------------------------------------------------------ArmAllBreakpoints:pshs d,x,yldy #0clrbldx #BreakpointBytes ; x = breakpoint byte table addressarm2:cmpb numBreakpoints ; safety checkbhs arm1cmpb NumSetBreakpointsbhs arm1lda [Breakpoints,y] ; load byte at memory addresssta b,x ; save in tableleay 2,y ; increment for next addressincb ; increment to next bytebra arm2 ; loop backarm1:puls d,x,y,pc;------------------------------------------------------------------------------;------------------------------------------------------------------------------ArmBreakpoint:pshs d,x,ylda NumSetBreakpoints ; check if too many breakpoints setcmpa numBreakpointslbhs DisplayErrlbsr ignBlankslbsr GetHexNumber ; get address parametertstblbmi DisplayErrldb NumSetBreakpoints ; bv= number of set breakpointsldy mon_numwka+2 ; get addresslda ,y ; get byte at addressldx #BreakpointBytes ; and store byte in a tablesta b,x ; recordlda #OPC_SWI ; put a SWI instruction in placesta ,yldx #Breakpoints ; also store the address in a tableaslb ; index for 2 byte valuessty b,xlsrb ; size back to single byteincbstb NumSetBreakpointspuls d,x,ylbra Monitor;------------------------------------------------------------------------------;------------------------------------------------------------------------------DisarmBreakpoint:pshs d,x,y,ulbsr ignBlankslbsr GetHexNumbertstblbmi Monitorclrbclrbtfr d,x ; x = zero toodisarm6:cmpb numBreakpoints ; no more than this many may be setbhs disarm4cmpb NumSetBreakpoints ; number actually setbhs disarm4ldy Breakpoints,x ; y = breakpoint addresscmpy mon_numwka+2 ; is it the one we want?bne disarm3 ; if not, go increment to nextldx mon_numwka+2 ; x = memory addressldy #BreakpointByteslda b,y ; get saved byte from tablesta ,x ; set the byte at the memory address; compress breakpoint table by removing breakpointdec NumSetBreakpoints ; set the new number of set breakpointspshs b ; save the position we're removing fromdisarm7:incb ; set index for next bytelda b,y ; get bytedecb ; and store it backsta b,yincb ; move to next positioncmpb numBreakpoints ; hit end of table?blo disarm7puls b ; get back positionaslb ; times two for word indexclratfr d,ylsrb ; back to byte index valuedisarm8:ldu 2,y ; get next breakpoint addressstu ,y++ ; store in current pos, incrementincb ; increment countcmpb numBreakpoints ; hit end of table?blo disarm8puls d,x,y,u,pcdisarm3:leax 2,xincbbra disarm6disarm4:puls d,x,y,ulbra Monitor;------------------------------------------------------------------------------;------------------------------------------------------------------------------ListBreakpoints:pshs d,xswifcb MF_CRLFldx #0ldb #0lbrk1:cmpb numBreakpointsbhs lbrk2cmpb NumSetBreakpointsbhs lbrk2ldd Breakpoints,xleax 2,xincbpshs bswifcb MF_DisplayWordAsHexswifcb MF_CRLFpuls bbra lbrk1lbrk2:puls d,xlbra Monitor;------------------------------------------------------------------------------;------------------------------------------------------------------------------swi3_rout:seilda ,ssta mon_CCRSAVEldd 1,sstd mon_DSAVEldb 3,sstb mon_DPRSAVEldd 4,sstd mon_XSAVEldd 6,sstd mon_YSAVEldd 8,sstd mon_USAVEsts mon_SSAVEldd 11,sstd mon_PCSAVEsts mon_SSAVElds #$3FFFldd #swi3_exitpshs dclijmp DumpRegsswi3_exit:lds mon_SSAVErti;------------------------------------------------------------------------------;------------------------------------------------------------------------------firq_rout:rtiirq_rout:clratfr a,dprsetdp $000; lbsr SerialIRQ ; check for recieved characterlbsr TimerIRQlda IrqBase ; get the IRQ flag bytelsraora IrqBaseanda #$FE0sta 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 COREIDcmpa IOFocusIDbne tr1alda CursorFlash ; test if we want a flashing cursorbeq tr1albsr CalcScreenLoc ; compute cursor location in memorytfr d,yinc $2000,y ; get color code $2000 higher in memorytr1a:rti;------------------------------------------------------------------------------;------------------------------------------------------------------------------nmi_rout:ldb COREIDlda #'I'ldx #TEXTSCR+40sta b,xrti_insn:rti; Special Register Areaorg $FFFFE0; Interrupt vector tableorg $FFFFF0fcw rti_insn ; reservedfcw swi3_rout ; SWI3fcw rti_insn ; SWI2fcw firq_rout ; FIRQfcw irq_rout ; IRQfcw swi_rout ; SWIfcw nmi_rout ; NMIfcw start ; RST
