diff --git a/IL.inc b/IL.inc index a7e3c8c..ea9b5a5 100644 --- a/IL.inc +++ b/IL.inc @@ -174,26 +174,12 @@ TSTN macro addr db (addr-*)-1 endm ; -; SAVEP will save the current program to whatever -; storage media is available. -; -SAVEP macro - db 36 - endm -; -; LOADP will load a program from storage. -; It will clear the current program first. -; -LOADP macro - db 37 - endm -; ; FREE returns the amount of free RAM on top of ; the stack. This is the amount of room the user ; program has available. ; FREE macro - db 38 + db 36 endm ; ; RANDOM takes the top item off the stack and @@ -202,14 +188,47 @@ FREE macro ; 42 then RANDOM returns a value from 0 to 41. ; RANDOM macro - db 39 + db 37 endm ; ; ABS will replace the top of stack with the ; absolute value. ; ABS macro + db 38 + endm +; +; OPENREAD opens a file for reading, as in getting +; statements from it. +; +OPENREAD macro + db 39 + endm +; +; OPENWRITE opens a file for writing, as in saving +; the current program to it. +; +OPENWRITE macro db 40 endm - +; +; DCLOSE closes any open disk file. +; +DCLOSE macro + db 41 + endm +; +; DGETLINE gets one line from the disk file and puts it +; into LINBUFF. +; +DGETLINE macro + db 42 + endm +; +; DLIST saves the program to an open disk file. +; +DLIST macro + db 43 + endm +; list diff --git a/basic.il b/basic.il index ba8ce98..491af60 100644 --- a/basic.il +++ b/basic.il @@ -135,7 +135,7 @@ S17A: EXIT S17: - TST UNKNOWN,"REM" ;REMark. Skip rest of line + TST S17B,"REM" ;REMark. Skip rest of line NXT CO JMP STMT ; @@ -143,15 +143,25 @@ S17: ; to/from mass storage. ; S17B: + if XKIM || CTMON65 TST S17C,"SAVE" - SAVEP + OPENWRITE + DLIST + DCLOSE JMP CO S17C: TST UNKNOWN,"LOAD" - LOADP - JMP CO - + OPENREAD +S17CLP: + DGETLINE ;get line from file + TSTL S17EOL ;no line num means EOL + INSERT ;put it into the program + JMP S17CLP ;keep going +S17EOL + DCLOSE ;close disk file + JMP CO ;back to start + endif ; ; Else, unknown command. ; diff --git a/config.inc b/config.inc new file mode 100644 index 0000000..421ed5b --- /dev/null +++ b/config.inc @@ -0,0 +1,50 @@ +;********************************************************* +; FILE: config.inc +; +; General configuration file for the Corsham Technologies +; CTMON65 monitor. +;********************************************************* +; +; Current version and revision +; +VERSION equ 0 +REVISION equ 1 +; +;FALSE equ 0 +;TRUE equ !FALSE +; +; SS-50 bus constants +; +IO_BASE equ $e000 +IO_SIZE equ 16 +; +; Memory usage +; +ZERO_PAGE_START equ $00f0 +ROM_START equ $f000 +RAM_START equ $df00 +; +; If enabled, turn on buffered input code. +; +BUFFERED_INPUT equ FALSE +; +MAX_ARGC equ 5 +; +; If enabled, the debugger will display the flag register +; in ASCII. Nice, but takes more code. +; +FULL_STATUS equ TRUE +; +; Enable EXTENDED_CMDS to allow linking external commands +; to the command handler. +; +EXTENDED_CMDS equ FALSE +; +; Define to enable SD related functions +; +SD_ENABLED equ TRUE +; +; Size of the keyboard buffer +; +BUFFER_SIZE equ 132 + diff --git a/ctmon65.inc b/ctmon65.inc new file mode 100644 index 0000000..956d435 --- /dev/null +++ b/ctmon65.inc @@ -0,0 +1,87 @@ +;********************************************************* +; FILE: ctmon65.inc +; +; Applications wishing to run under CTMON65 should include +; this file, as it defines vectors and other pieces of +; necessary data. +;********************************************************* +; + include "config.inc" +; + bss + org ROM_START +; +;========================================================= +; Jump table to common functions. The entries in this +; table are used by external programs, so nothing can be +; moved or removed from this table. New entries always +; go at the end. Many of these are internal functions +; and I figured they might be handy for others. +; +RESET ds 3 +WARM ds 3 +; +; These are the major and minor revision numbers so that +; code can check to see which CTMON65 version is running. +; +CTMON65ver ds 1 +CTMON65rev ds 1 + ds 1 ;unused +; +; Console related functions +; +cin ds 3 +cout ds 3 +cstatus ds 3 +putsil ds 3 +getline ds 3 +crlf ds 3 +HexA ds 3 +; +; Low-level functions to access the SD card system +; + if SD_ENABLED +xParInit ds 3 +xParSetWrite ds 3 +xParSetRead ds 3 +xParWriteByte ds 3 +xParReadByte ds 3 +; +; Higher level SD card functions +; +DiskPing ds 3 +DiskDir ds 3 +DiskDirNext ds 3 +DiskOpenRead ds 3 +DiskOpenWrite ds 3 +DiskRead ds 3 +DiskWrite ds 3 +DiskClose ds 3 + endif ;SD_ENABLED +; + org RAM_START +; +; The use of memory starting from here will remain +; constant through different versions of CTMON65. +; +IRQvec ds 2 +NMIvec ds 2 +; +; Before a L(oad) command, these are set to $FF. +; After loading, if they are different, jump to +; that address. +; +AutoRun ds 2 +; +; Pointer to the subroutine that gets the next input +; character. Used for doing disk/console input. +; +inputVector ds 2 +; +; Same thing for output. +; +outputVector ds 2 +; +; Buffer for GETLINE +; +buffer ds BUFFER_SIZE diff --git a/mytb.asm b/mytb.asm index ed2a429..1079664 100644 --- a/mytb.asm +++ b/mytb.asm @@ -11,6 +11,16 @@ ; ; 10/07/2017 ; +; This implements a stripped down Tiny BASIC +; interpreter using the Interpretive Language (IL) +; method as described in the first few issues of +; Dr Dobb's Journal. The IL interpreter can be used +; to write various languages simply by changing the +; IL code rather than the interpreter itself. +; +; www.corshamtech.com +; bob@corshamtech.com +; ;===================================================== ; ; Create TRUE and FALSE values for conditionals. @@ -18,13 +28,36 @@ FALSE equ 0 TRUE equ ~FALSE ; +;--------------------------------------------------------- +; One of these must be set to indicate which environment +; Tiny BASIC will be running in. Here are the current +; environments: +; +; KIM - This is a bare KIM-1. You'll need to add a few +; more K of RAM. +; +; XKIM - The Corsham Technologies xKIM extended monitor, +; which enhances, without replacing, the standard KIM +; monitor. It gives access to routines to save/load files +; to a micro SD card. +; +; CTMON65 is a from-scratch monitor written for the +; Corsham Tech SS-50 6502 CPU board, but the monitor can +; easily be ported to other systems. It has support for +; using a micro SD card for file storage/retrieval. +; +KIM equ FALSE ;Basic KIM-1, no extensions +XKIM equ FALSE ;Corsham Tech xKIM monitor +CTMON65 equ TRUE ;Corsham Tech CTMON65 +; ; If ILTRACE is set then dump out the address of every ; IL opcode before executing it. ; ILTRACE equ FALSE ; ; If FIXED is set, put the IL code and the user -; program space at fixed locations in memory. +; program space at fixed locations in memory. This is +; meant only for debugging. ; FIXED equ FALSE ; @@ -54,6 +87,9 @@ ERR_OVER equ 3 ;stack overflow ERR_EXTRA_STUFF equ 4 ;Stuff at end of line ERR_SYNTAX equ 5 ;various syntax errors ERR_DIVIDE_ZERO equ 6 ;divide by zero +ERR_READ_FAIL equ 7 ;error loading file +ERR_WRITE_FAIL equ 8 ;error saving file +ERR_NO_FILENAME equ 9 ; ;===================================================== ; Zero page storage. @@ -104,27 +140,35 @@ cold jmp cold2 ;jump around vectors warm jmp warm2 ; ; These are the user-supplied vectors to I/O routines. +; If you want, you can just patch these in the binary +; file, but it would be better to change the source +; code. ; + if KIM || XKIM OUTCH jmp $1ea0 ;output char in A GETCH jmp $1e5a ;get char in A (blocks) CRLF jmp $1e2f ;print CR/LF OUTHEX jmp $1e3b ;print A as hex MONITOR jmp $1c4f ;return to monitor + if XKIM +AutoRun equ $dff8 + endif + endif + if CTMON65 + include "ctmon65.inc" + code +OUTCH jmp cout +GETCH jmp cin +CRLF jmp crlf +OUTHEX jmp HexA +MONITOR jmp WARM +puts equ putsil + endif ; cold2 jsr puts db CR,LF,CR,LF db "Bob's Tiny BASIC" db CR,LF,0 -; -; This is a TEMPORARY debug aid... put a known pattern -; into the user program space. -; - ldx #0 - lda #$ba -zzxloop sta ProgramStart,x - inx - bne zzxloop - ; lda #IL&$ff sta ILPC @@ -149,7 +193,8 @@ zzxloop sta ProgramStart,x ; ; This is the warm start entry point ; -warm2 jsr CRLF +warm2 jsr SetOutConsole + jsr CRLF lda errGoto sta ILPC lda errGoto+1 @@ -274,11 +319,15 @@ ILTBL dw iXINIT ;0 dw iTSTV ;33 dw iTSTL ;34 dw iTSTN ;35 - dw iSAVEP ;36 - dw iLOADP ;37 - dw iFREE ;38 - dw iRANDOM ;39 - dw iABS ;40 + dw iFREE ;36 + dw iRANDOM ;37 + dw iABS ;38 + dw iOPENREAD + dw iOPENWRITE + dw iDCLOSE ;41 + dw iDGETLINE ;Life, universe, everything + dw iDLIST ;43 + ILTBLend equ * ; ;===================================================== @@ -460,13 +509,13 @@ iXferok jmp NextIL ; ;===================================================== -; +; Save the pointer to the next line to the call stack. ; iSAV jmp ILbad ; ;===================================================== -; +; Pop the next line from the call stack. ; iRSTR jmp ILbad @@ -806,7 +855,8 @@ iIND jsr popR1 ; List the current BASIC program in memory. Uses R0, ; tempIly, and dpl. ; -iLST lda #ProgramStart&$ff +iLST jsr SetOutConsole +iLST2 lda #ProgramStart&$ff sta dpl lda #ProgramStart>>8 sta dpl+1 @@ -831,12 +881,12 @@ iLstNotEnd ldy #0 sty tempIlY jsr PrintDecimal lda #SPACE - jsr OUTCH + jsr VOUTCH ldy tempIlY iLSTl2 lda (dpl),y beq iLST3 ;end of this line sty tempIlY - jsr OUTCH + jsr VOUTCH ldy tempIlY iny bne iLSTl2 ;do next char @@ -853,10 +903,17 @@ iLST3 iny adc #0 sta dpl+1 ; - jsr CRLF +; Have to manually do CR/LF so it uses the vectored +; output function. +; + lda #CR + jsr VOUTCH + lda #LF + jsr VOUTCH jmp iLSTloop ;do next line ; -iLstdone jmp NextIL +iLstdone jsr SetOutConsole + jmp NextIL ; ;===================================================== ; Get a line of text into LINBUF. Terminate with a @@ -1283,24 +1340,13 @@ iABS jsr popR0 inc R0+1 iABS_1 jsr pushR0 jmp NextIL -; -;===================================================== -; Save program to mass storage. -; -iSAVEP - -; -;===================================================== -; Load a program from mass storage. -; -iLOADP - - ; include "support.asm" + include "storage.asm" include "IL.inc" +; if FIXED - org $1000 + org $1000 endif include "basic.il" PROGEND equ * @@ -1316,6 +1362,8 @@ mathStack ds STACKSIZE*2 mathStackPtr ds 1 retStack ds STACKSIZE*2 retStackPtr ds 1 +callStack ds STACKSIZE*2 +callStackPtr ds 1 LINBUF ds 80 getlinx ds 1 printtx ds 1 ;temp X for print funcs @@ -1326,6 +1374,7 @@ MQ ds 2 ;used for some math sign ds 1 ;0 = positive, else negative rtemp1 ds 1 random ds 2 +BOutVec ds 2 ; ; PROGRAMEND is the end of the user's BASIC program. ; More precisely, it is one byte past the end. Or, @@ -1351,6 +1400,12 @@ FreeMem ds 2 ;amount of free memory org $2000 endif ProgramStart equ * - +; + if CTMON65 || XKIM + code + org AutoRun + dw cold + endif +; end diff --git a/mytb.hex b/mytb.hex new file mode 100644 index 0000000..801e95b --- /dev/null +++ b/mytb.hex @@ -0,0 +1,98 @@ +:200200004C15024C53024C0CF04C09F04C18F04C1BF04C03F02012F00D0A0D0A426F6227D9 +:20022000732054696E792042415349430D0A00A9178574A90C8575A9838D7B0EA90E8D7C84 +:200240000EA95A8D760EA99D8D770EA95B8D780E4C6302202F0B200C02AD710E8574AD7290 +:200260000E8575A90085848D1D0EA91D857DA90E857EA47F20F30A847F2024080AC95A903E +:20028000332012F00D0A496C6C6567616C20494C2000203108A000B174200F022012F020D2 +:2002A00061742000A575200F02A574200F02200C024C1202A8B9C2028576B9C30285776C20 +:2002C00076002D03350348036B037403A2067C039D03D603D903DC031E043E044F049B045F +:2002E000B104C704DF0419056205750585051A03E405F0059C061202B506A806AB06C2067F +:20030000D006DC0605072B0745078807910703083D0B6B0BCA0B8A0BC40BA9008D0B0EA97A +:2003200083857D8D7B0EA90E857E8D7C0EA9008DFA0D4C7202A47F20F30AB17DF007A20449 +:20034000A9004C52044C7202A47FA92288D17DD0FBC8847FB17DF010C922F009200602E618 +:200360007FA47FD0EFC8847F4C7202204E0A20C1084C7202A9092006024C7202A584D003DA +:200380004CAB0620AA08A57DCD7B0ED00AA57ECD7C0ED0034C3E042020084C7202204E0AE1 +:2003A000206708A002847FA9FF8584A9258574A90C85754C7202F00F900DAD710E8574ADB4 +:2003C000720E85754C7202A9FF8584A9258574A90C85754C72024C81024C810220610A20B3 +:2003E000740A204E0AA580C582D00AA581C583D004A902D014A580C582A581E5835002495B +:20040000803004A904D002A9010D740E2D730EF0074C7202A904D0F120AA084CA303A57FB5 +:2004200048A57E48A57D48A93F20A409202D0920280A68857D68857E68857F4C7202A90098 +:200440008584AD710E8574AD720E85754C7202202008868085812012F04572726F722000E7 +:2004600020C108A584F01B2012F0206174206C696E652000A000B17D8580C8B17D85812071 +:20048000C108200C02A9008584A9008D0B0EAD710E8574AD720E85754C7202204E0A20615F +:2004A0000A18A58065828580A581658385814C130520610A204E0A38A580E5828580A5819F +:2004C000E58385814C1305204E0AA58049FF8580A58149FF8581E680D002E6814C130520C9 +:2004E0004E0A20610AA5808D730EA5818D740EA90085808581A210068026810E730E2E74ED +:200500000E900D18A58065828580A58165838581CAD0E420280A4C720220610A204E0AA5BB +:20052000820583F03620890AA9008D730E8D740EA210068026812E730E2E740EAD730E386E +:20054000E582A8AD740EE58390088D740E8C730EE680CAD0DD20C40A4C1305A206A9004C75 +:200560005204204E0A20610AA682A5809540A58195414C720220610AA682B5408580B541A1 +:2005800085814C1305202F0BA9838576A90E8577A576CD7B0ED007A577CD7C0EF040A00032 +:2005A000B1768580C8B1768581C8847A20C108A920203A0BA47AB176F00A847A203A0BA4F7 +:2005C0007AC8D0F2C8189865768576A57769008577A90D203A0BA90A203A0B4C9005202FE5 +:2005E0000B4C7202A93E20A409A90085844C7202A000202D0920F30A847B206708D03D203C +:200600000B0A847C38AD7B0EE57C8D7B0EAD7C0EE9008D7C0EA57D8582A57E8583A582CD61 +:200620007B0ED007A583CD7C0EF011A47CB182A0009182E682D0E6E6834C1D06A47BB91DE9 +:200640000EF05620FA09AD7B0E8585AD7C0E8586A000B185A47C9185A585C57DD006A58628 +:20066000C57EF00BA585D002C686C6854C500618A57C6D7B0E8D7B0EAD7C0E69008D7C0E0B +:20068000A000A580917DC8A581917DC8A67BBD1D0E917DF004E8C8D0F54C72022054084CBB +:2006A0007202200C024C7202203A08202008867485754C72022020088680858120280A4C88 +:2006C0007202A900A2009540E8E034D0F94C72022020088E710E8D720E4C7202202408850E +:2006E0007B20160AA47F8476202408F00BA476D17DD00CC88476D0F0A476847F4C72022018 +:200700001F0A4C6807202408857BA47F20F30AB17DC9419053C95BB04F38E9410A8580A911 +:2007200000858120280AE67F4C7202202408857BA47F20F30AB17DC930902DC93AB02920D0 +:200740002D094C7202202408857BA47F20F30AB17DC92DF008C930900FC93AB00B202D094F +:20076000847F20280A4C7202A57B100E1865748574A57569FF85754C72021865748574A571 +:2007800075690085754C720220FC0A20280A4C720220610AAD780E8D760EAD770E0A2E76DA +:2007A0000E0A2E760E186D770E48AD760E6D780E8D780E6869118D770EAD780E69368D781B +:2007C0000EAD770E8580AD780E297F8581A580C582D016A581C583D01038A580E58285808A +:2007E000A581E58385814CCD07A580C582A581E5835002498010E2E680D002E68120280A4D +:200800004C7202204E0AA581101049FF8581A58049FF8580E680D002E68120280A4C7202E9 +:20082000202408AAA000B17408E674D002E6752860A574D002C675C67460AC0B0EA5741830 +:20084000690299FB0D08C8A57528690099FB0DC88C0B0E60AC0B0E88B9FB0D857588B9FB5F +:200860000D85748C0B0E60A983857DA90E857EA57DCD7B0ED00BA57ECD7C0ED004A9011822 +:2008800060A580A000D17DD008C8A581D17DD00160A001B17DC581900BD00788B17DC5801E +:2008A0009002386020AA084C8108A002847FB17DF003C8D0F9C89818657D857D9002E67EBE +:2008C00060A5811017A92D203A0BA58049FF8580A58149FF8581E680D002E681A2008E6F0C +:2008E0000EA000A58038FD25098580A581FD2609102E18A5807D250985808E6E0E98090095 +:20090000D005AD6F0EF0099809308D6F0E203A0BAE6E0EE8E8E008D0C8A58009304C3A0B36 +:200920008581C8D0BE1027E80364000A00A9008580858185768413B17DC92DD002E676B182 +:200940007DC9309036C93AB03238E9304806802681A5808582A5818583068026810680267D +:200960008118A58065828580A581658385816818658085809002E681C8D0C4A5800581F05F +:2009800016A576F012A58049FF8580A58149FF8581E680D002E681A5808510A5818511A584 +:2009A00076851260A21D867DA20E867E4868480900F008200602A920200602A2008E6D0E97 +:2009C00020090248200CF068C90DF00DC908F021AE6D0E9D1D0EE8D0E4A900AE6D0E9D1D52 +:2009E0000E857F200C02A00020F30AB17DF0BE6860AE6D0EF0C7CA4CBD09A200B91D0EF024 +:200A000004C8E8D0F7E8E8E8867C60A002B17DF003C8D0F9C860A5748578A575857960A592 +:200A2000788574A579857560AEFA0DA5809DEA0DE8A5819DEA0DE88EFA0D60AEFA0DA58204 +:200A40009DEA0DE8A5839DEA0DE88EFA0D60AEFA0DCABDEA0D8581CABDEA0D85808EFA0D30 +:200A600060AEFA0DCABDEA0D8583CABDEA0D85828EFA0D60AEFA0DCABDEA0D8D740ECABD98 +:200A8000EA0D8D730E8EFA0D60A9008D750EA5811013EE750E49FF8581A58049FF8580E643 +:200AA00080D002E681A583101A48AD750E49018D750E6849FF8583A58249FF8582E682D0F3 +:200AC00002E68360AD750EF028A580D002C681C680A58049FF8580A58149FF8581A582D0A2 +:200AE00002C683C682A58249FF8582A58349FF858360C8B17DF004C920F0F760A9FF8D7D49 +:200B00000EA9138D7E0E38AD7D0EED7B0E8D810E8580AD7E0EED7C0E8D820E858138AD7BB8 +:200B20000EE9838D7F0EAD7C0EE90E8D800E60A9068D790EA9028D7A0E606C790EA47FB1CE +:200B40007DD007A900A2094C52041898657DA8A57E6900AA2036F09007A207A9004C52040A +:200B6000A9008D8FDF8D8EDF4C7202A47FB17DF0D21898657DA8A57E6900AA2039F09007B4 +:200B8000A900A2084C52044C7202A21D867DA20E867EA2008E6D0E20D00BB016C90DF00DEB +:200BA000C90AF009AE6D0E9D1D0EE8D0E7AE6D0EF0E2AE6D0EA9009D1D0E857FA00020F38D +:200BC0000A4C720220FF0B4C88052042F04C7202AE8FDFEC8EDFD014A984A2DFA00A203C29 +:200BE000F0B0128D8EDFC900F00BA200BD0ADFE88E8FDF1860A9008D8FDF8D8EDF3860A902 +:200C00000A8D790EA90C8D7A0E608D0ADFA901A00AA2DF203FF06016051F1D0C1E172204D4 +:200C2000181D1D0C0020154C455400214E204C3D001C2C0D0113061D0C1D250C2019474F6F +:200C4000002008544F001C2C0D0107202E535542001C2C0D010807202C5052494E540020D6 +:200C60001D22000220062C00041D5F0C20053B001D5F0C0105061D0C1D250C1D290D1C2C4F +:200C80000D031D640C20174946001C2C0D1CB20D1C2C0D20945448454E000A1D250C2018F9 +:200CA000494E5055540021810B1320052C001DA60C01061D0C1D250C200F52455455524E37 +:200CC000000109061D0C1D250C2005454E44000C200A4C4953540001151D1D0C200D5255EF +:200CE0004E00011E1B0100071D250C20084E455700011D170C200645584954001A200A52CD +:200D0000454D00061D0C1D250C200B5341564500282B291D1D0C20114C4F414400272A22E4 +:200D200004181D1E0D291D1D0C0D050020092D001C550D101D3E0D20022B001C550D20098E +:200D40002B001C550D0E1D3E0D20092D001C550D0F1D3E0D191C710D20092A001C710D1178 +:200D60001D580D20EF2F001C710D121D580D1D290D2009465245452829002419200E524E8B +:200D80004428001C710D20A129002519200E41425328001C710D20912900261921021419F6 +:200DA00023011920D728001C2C0D20032900190D050020063D001B02001920163C002006DA +:200DC0003D001B03001920063E001B0500191B010019209A3E0020063D001B060019200612 +:0A0DE0003C001B0100191B04001960 +:02DF0400000219 +:00000001FF diff --git a/mytb.lst b/mytb.lst new file mode 100644 index 0000000..c1d8a43 --- /dev/null +++ b/mytb.lst @@ -0,0 +1,3471 @@ +AS65 Assembler for R6502 [1.42]. Page 1 +---------------------------------- mytb.asm ---------------------------------- + +3052 lines read, no errors in pass 1. + ;===================================================== + ; Bob's Tiny BASIC + ; + ; While working on the Corsham Technologies KIM Clone + ; project, I wanted to include a TINY BASIC since that + ; was a highly desirable feature of early computers. + ; + ; Rather than negotiating copyright issues for + ; existing BASICs, I decided to just write one from + ; scratch. + ; + ; 10/07/2017 + ; + ; This implements a stripped down Tiny BASIC + ; interpreter using the Interpretive Language (IL) + ; method as described in the first few issues of + ; Dr Dobb's Journal. The IL interpreter can be used + ; to write various languages simply by changing the + ; IL code rather than the interpreter itself. + ; + ; www.corshamtech.com + ; bob@corshamtech.com + ; + ;===================================================== + ; + ; Create TRUE and FALSE values for conditionals. + ; +0000 = FALSE equ 0 +ffff = TRUE equ ~FALSE + ; + ;----------------------------------------------------- + ; One of these must be set to indicate which environme + ; Tiny BASIC will be running in. Here are the current + ; environments: + ; + ; KIM - This is a bare KIM-1. You'll need to add a fe + ; more K of RAM. + ; + ; XKIM - The Corsham Technologies xKIM extended monito + ; which enhances, without replacing, the standard KIM + ; monitor. It gives access to routines to save/load f + ; to a micro SD card. + ; + ; CTMON65 is a from-scratch monitor written for the + ; Corsham Tech SS-50 6502 CPU board, but the monitor c + ; easily be ported to other systems. It has support f + ; using a micro SD card for file storage/retrieval. + ; +0000 = KIM equ FALSE ;Basic KIM-1, no extensions +0000 = XKIM equ FALSE ;Corsham Tech xKIM monitor +ffff = CTMON65 equ TRUE ;Corsham Tech CTMON65 + ; + ; If ILTRACE is set then dump out the address of every + ; IL opcode before executing it. + ; +0000 = ILTRACE equ FALSE + ; + ; If FIXED is set, put the IL code and the user + ; program space at fixed locations in memory. This is + ; meant only for debugging. + ; + AS65 Assembler for R6502 [1.42]. Page 2 +---------------------------------- mytb.asm ---------------------------------- + +0000 = FIXED equ FALSE + ; + ; Sets the arithmetic stack depth. This is *TINY* + ; BASIC, so keep this small! + ; +0008 = STACKSIZE equ 8 ;number of entries + ; + ; Common ASCII constants + ; +0007 = BEL equ $07 +0008 = BS equ $08 +0009 = TAB equ $09 +000a = LF equ $0A +000d = CR equ $0D +0022 = QUOTE equ $22 +0020 = SPACE equ ' ' +002c = COMMA equ ',' +003b = SEMICOLON equ ';' + ; + ; These are error codes + ; +0000 = ERR_NONE equ 0 +0001 = ERR_EXPR equ 1 ;expression error +0002 = ERR_UNDER equ 2 ;stack underflow +0003 = ERR_OVER equ 3 ;stack overflow +0004 = ERR_EXTRA_STUFF equ 4 ;Stuff at end of line +0005 = ERR_SYNTAX equ 5 ;various syntax errors +0006 = ERR_DIVIDE_ZERO equ 6 ;divide by zero +0007 = ERR_READ_FAIL equ 7 ;error loading file +0008 = ERR_WRITE_FAIL equ 8 ;error saving file +0009 = ERR_NO_FILENAME equ 9 + ; + ;===================================================== + ; Zero page storage. + ; + bss +0040 = org $0040 +0040 = variables ds 26*2 ;2 bytes, A-Z +0074 = variablesEnd equ * +0074 = ILPC ds 2 ;IL program counter +0076 = dpl ds 2 +0078 = tempIL ds 2 +007a = tempIlY ds 1 +007b = offset ds 1 +007c = lineLength ds 1 + ; + ; CURPTR is a pointer to curent BASIC line being + ; executed. Always points to start of line, CUROFF + ; is the offset to the current character. + ; +007d = CURPTR ds 2 +007f = CUROFF ds 1 + ; + ; R0 and R1 are used for arithmetic operations and + ; general use. + ; +0080 = R0 ds 2 ;arithmetic register 0 +0082 = R1 ds 2 ;arithmetic register 1 + ; + ; This is zero if in immediate mode, or non-zero + ; if currently running a program. Any input from + ; the main loop clears this, and the XFER IL + AS65 Assembler for R6502 [1.42]. Page 3 +---------------------------------- mytb.asm ---------------------------------- + + ; statement will set it. + ; +0084 = RunMode ds 1 + ; + ; Used for line insertion/removal. + ; +0085 = FROM ds 2 + ; + ;===================================================== + ; + code +0200 = org $0200 + ; + ; Cold start is at $0200. Warm start is at $0203. + ; +0200 : 4c1502 cold jmp cold2 ;jump around vectors +0203 : 4c5302 warm jmp warm2 + ; + ; These are the user-supplied vectors to I/O routines. + ; If you want, you can just patch these in the binary + ; file, but it would be better to change the source + ; code. + ; + if KIM || XKIM + OUTCH jmp $1ea0 ;output char in A + GETCH jmp $1e5a ;get char in A (blocks) + CRLF jmp $1e2f ;print CR/LF + OUTHEX jmp $1e3b ;print A as hex + MONITOR jmp $1c4f ;return to monitor + if XKIM + AutoRun equ $dff8 + endif + endif + if CTMON65 + include "ctmon65.inc" + ;***************************************************** + ; FILE: ctmon65.inc + ; + ; Applications wishing to run under CTMON65 should inc + ; this file, as it defines vectors and other pieces of + ; necessary data. + ;***************************************************** + ; + include "config.inc" + ;***************************************************** + ; FILE: config.inc + ; + ; General configuration file for the Corsham Technolog + ; CTMON65 monitor. + ;***************************************************** + ; + ; Current version and revision + ; +0000 = VERSION equ 0 +0001 = REVISION equ 1 + ; + ;FALSE equ 0 + ;TRUE equ !FALSE + ; + ; SS-50 bus constants + ; +e000 = IO_BASE equ $e000 + AS65 Assembler for R6502 [1.42]. Page 4 +---------------------------------- mytb.asm ---------------------------------- + +0010 = IO_SIZE equ 16 + ; + ; Memory usage + ; +00f0 = ZERO_PAGE_START equ $00f0 +f000 = ROM_START equ $f000 +df00 = RAM_START equ $df00 + ; + ; If enabled, turn on buffered input code. + ; +0000 = BUFFERED_INPUT equ FALSE + ; +0005 = MAX_ARGC equ 5 + ; + ; If enabled, the debugger will display the flag regis + ; in ASCII. Nice, but takes more code. + ; +ffff = FULL_STATUS equ TRUE + ; + ; Enable EXTENDED_CMDS to allow linking external comma + ; to the command handler. + ; +0000 = EXTENDED_CMDS equ FALSE + ; + ; Define to enable SD related functions + ; +ffff = SD_ENABLED equ TRUE + ; + ; Size of the keyboard buffer + ; +0084 = BUFFER_SIZE equ 132 + + + ; + bss +f000 = org ROM_START + ; + ;===================================================== + ; Jump table to common functions. The entries in this + ; table are used by external programs, so nothing can + ; moved or removed from this table. New entries alway + ; go at the end. Many of these are internal functions + ; and I figured they might be handy for others. + ; +f000 = RESET ds 3 +f003 = WARM ds 3 + ; + ; These are the major and minor revision numbers so th + ; code can check to see which CTMON65 version is runni + ; +f006 = CTMON65ver ds 1 +f007 = CTMON65rev ds 1 +f008 = ds 1 ;unused + ; + ; Console related functions + ; +f009 = cin ds 3 +f00c = cout ds 3 +f00f = cstatus ds 3 +f012 = putsil ds 3 +f015 = getline ds 3 +f018 = crlf ds 3 + AS65 Assembler for R6502 [1.42]. Page 5 +---------------------------------- mytb.asm ---------------------------------- + +f01b = HexA ds 3 + ; + ; Low-level functions to access the SD card system + ; + if SD_ENABLED +f01e = xParInit ds 3 +f021 = xParSetWrite ds 3 +f024 = xParSetRead ds 3 +f027 = xParWriteByte ds 3 +f02a = xParReadByte ds 3 + ; + ; Higher level SD card functions + ; +f02d = DiskPing ds 3 +f030 = DiskDir ds 3 +f033 = DiskDirNext ds 3 +f036 = DiskOpenRead ds 3 +f039 = DiskOpenWrite ds 3 +f03c = DiskRead ds 3 +f03f = DiskWrite ds 3 +f042 = DiskClose ds 3 + endif ;SD_ENABLED + ; +df00 = org RAM_START + ; + ; The use of memory starting from here will remain + ; constant through different versions of CTMON65. + ; +df00 = IRQvec ds 2 +df02 = NMIvec ds 2 + ; + ; Before a L(oad) command, these are set to $FF. + ; After loading, if they are different, jump to + ; that address. + ; +df04 = AutoRun ds 2 + ; + ; Pointer to the subroutine that gets the next input + ; character. Used for doing disk/console input. + ; +df06 = inputVector ds 2 + ; + ; Same thing for output. + ; +df08 = outputVector ds 2 + ; + ; Buffer for GETLINE + ; +df0a = buffer ds BUFFER_SIZE + + code +0206 : 4c0cf0 OUTCH jmp cout +0209 : 4c09f0 GETCH jmp cin +020c : 4c18f0 CRLF jmp crlf +020f : 4c1bf0 OUTHEX jmp HexA +0212 : 4c03f0 MONITOR jmp WARM +f012 = puts equ putsil + endif + ; +0215 : 2012f0 cold2 jsr puts +0218 : 0d0a0d0a db CR,LF,CR,LF +021c : 426f6227732054.. db "Bob's Tiny BASIC" + AS65 Assembler for R6502 [1.42]. Page 6 +---------------------------------- mytb.asm ---------------------------------- + +022c : 0d0a00 db CR,LF,0 + ; +022f : a917 lda #IL&$ff +0231 : 8574 sta ILPC +0233 : a90c lda #IL>>8 +0235 : 8575 sta ILPC+1 + ; +0237 : a983 lda #ProgramStart&$ff ;user prog +0239 : 8d7b0e sta PROGRAMEND +023c : a90e lda #ProgramStart>>8 +023e : 8d7c0e sta PROGRAMEND+1 + ; + ; Initialize the pseudo-random number sequence... + ; +0241 : a95a lda #$5a +0243 : 8d760e sta rtemp1 +0246 : a99d lda #%10011101 +0248 : 8d770e sta random +024b : a95b lda #%01011011 +024d : 8d780e sta random+1 + ; +0250 : 4c6302 jmp coldtwo + ; + ; This is the warm start entry point + ; +0253 : 202f0b warm2 jsr SetOutConsole +0256 : 200c02 jsr CRLF +0259 : ad710e lda errGoto +025c : 8574 sta ILPC +025e : ad720e lda errGoto+1 +0261 : 8575 sta ILPC+1 + ; + ; And continue with both starts here + ; +0263 : a900 coldtwo lda #0 +0265 : 8584 sta RunMode +0267 : 8d1d0e sta LINBUF +026a : a91d lda #LINBUF&$ff +026c : 857d sta CURPTR +026e : a90e lda #LINBUF>>8 +0270 : 857e sta CURPTR+1 ;fall through... + ; + ;===================================================== + ; This is the top of the IL interpreter. This fetches + ; and executes the instruction currently pointed to + ; by ILPC and adjusts ILPC to point to the next + ; instruction to execute. + ; +0272 : NextIL + if ILTRACE + jsr dbgLine + endif +0272 : a47f ldy CUROFF +0274 : 20f30a jsr SkipSpaces +0277 : 847f sty CUROFF + ; +0279 : 202408 jsr getILByte + ; + ; When the handler is called, these are the conditions + ; of several important items: + ; + ; (ILPC) will point to the byte AFTER the IL + AS65 Assembler for R6502 [1.42]. Page 7 +---------------------------------- mytb.asm ---------------------------------- + + ; opcode being executed. + ; + ; (CURPTR),CUROFF will point to the start of the + ; next word in the input buffer. Ie, the next word + ; in the user program. + ; +027c : 0a asl a +027d : c95a cmp #ILTBLend-ILTBL+2 +027f : 9033 bcc ILgood + ; + ; This handles an illegal IL opcode. This is serious + ; and there's no way to recover. + ; +0281 : 2012f0 ILbad jsr puts +0284 : 0d0a db CR,LF +0286 : 496c6c6567616c.. db "Illegal IL " +0291 : 00 db 0 + ; + ; Well this is awkward, we need to back up the IL + ; by one since it no longer points to the current + ; opcode. + ; +0292 : 203108 jsr decIL + ; +0295 : a000 ldy #0 +0297 : b174 lda (ILPC),y +0299 : 200f02 jsr OUTHEX +029c : 2012f0 jsr puts +029f : 2061742000 db " at ",0 +02a4 : a575 lda ILPC+1 +02a6 : 200f02 jsr OUTHEX +02a9 : a574 lda ILPC +02ab : 200f02 jsr OUTHEX +02ae : 200c02 jsr CRLF +02b1 : 4c1202 jmp MONITOR + ; + ; Just jump to the address (ILPC),y. Have to do + ; some goofy stuff. + ; +02b4 : a8 ILgood tay ;move index into Y +02b5 : b9c202 lda ILTBL,y +02b8 : 8576 sta dpl +02ba : b9c302 lda ILTBL+1,y +02bd : 8577 sta dpl+1 +02bf : 6c7600 jmp (dpl) ;go to handler + ; + ;===================================================== + ; This is the IL jump table. The IL opcode is + ; mulitplied by two, then looked-up in this table. + ; There is absolutely nothing special about the order + ; of entries here... they all decode at exactly the + ; same speed. + ; +02c2 : 2d03 ILTBL dw iXINIT ;0 +02c4 : 3503 dw iDONE ;1 +02c6 : 4803 dw iPRS ;2 +02c8 : 6b03 dw iPRN ;3 +02ca : 7403 dw iSPC ;4 +02cc : a206 dw iNLINE ;5 +02ce : 7c03 dw iNXT ;6 +02d0 : 9d03 dw iXFER ;7 +02d2 : d603 dw iSAV ;8 + AS65 Assembler for R6502 [1.42]. Page 8 +---------------------------------- mytb.asm ---------------------------------- + +02d4 : d903 dw iRSTR ;9 +02d6 : dc03 dw iCMPR ;10 +02d8 : 1e04 dw iINNUM ;11 +02da : 3e04 dw iFIN ;12 +02dc : 4f04 dw iERR ;13 +02de : 9b04 dw iADD ;14 +02e0 : b104 dw iSUB ;15 +02e2 : c704 dw iNEG ;16 +02e4 : df04 dw iMUL ;17 +02e6 : 1905 dw iDIV ;18 +02e8 : 6205 dw iSTORE ;19 +02ea : 7505 dw iIND ;20 +02ec : 8505 dw iLST ;21 +02ee : 1a03 dw iINIT ;22 +02f0 : e405 dw iGETLINE +02f2 : f005 dw iINSRT ;24 +02f4 : 9c06 dw iRTN ;25 +02f6 : 1202 dw MONITOR ;26 +02f8 : b506 dw iLIT ;27 +02fa : a806 dw iCALL ;28 +02fc : ab06 dw iJMP ;29 +02fe : c206 dw iVINIT ;30 +0300 : d006 dw iERRGOTO +0302 : dc06 dw iTST ;32 +0304 : 0507 dw iTSTV ;33 +0306 : 2b07 dw iTSTL ;34 +0308 : 4507 dw iTSTN ;35 +030a : 8807 dw iFREE ;36 +030c : 9107 dw iRANDOM ;37 +030e : 0308 dw iABS ;38 +0310 : 3d0b dw iOPENREAD +0312 : 6b0b dw iOPENWRITE +0314 : ca0b dw iDCLOSE ;41 +0316 : 8a0b dw iDGETLINE ;Life, universe, everything +0318 : c40b dw iDLIST ;43 + +031a = ILTBLend equ * + ; + ;===================================================== + ;===================================================== + ;===================================================== + ; This marks the start of the handlers for IL opcodes. + ;===================================================== + ;===================================================== + ;===================================================== + ; + ; +031a : a900 iINIT lda #0 ;clear IL stack pointer +031c : 8d0b0e sta retStackPtr + ; lda #IL&0xff ;start of IL + ; sta ILPC + ; lda #IL>>8 + ; sta ILPC+1 + ; +031f : a983 lda #ProgramStart&$ff ;user prog +0321 : 857d sta CURPTR +0323 : 8d7b0e sta PROGRAMEND +0326 : a90e lda #ProgramStart>>8 +0328 : 857e sta CURPTR+1 +032a : 8d7c0e sta PROGRAMEND+1 + ; + ; fall into XINIT... + AS65 Assembler for R6502 [1.42]. Page 9 +---------------------------------- mytb.asm ---------------------------------- + + ; + ;===================================================== + ; This initializes for the start of the next line of + ; BASIC text. + ; +032d : a900 iXINIT lda #0 +032f : 8dfa0d sta mathStackPtr ;clear math stack +0332 : 4c7202 goodExit jmp NextIL + ; + ;===================================================== + ; Verify there is nothing else on this input line. + ; If there is, generate an error. + ; +0335 : a47f iDONE ldy CUROFF +0337 : 20f30a jsr SkipSpaces +033a : b17d lda (CURPTR),y +033c : f007 beq doneadv +033e : a204 ldx #ERR_EXTRA_STUFF +0340 : a900 lda #0 +0342 : 4c5204 jmp iErr2 + ; + ; Advance to the next line + ; +0345 : doneadv + ; jsr FindNext2 +0345 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Print the string until a closing quote + ; +0348 : a47f iPRS ldy CUROFF + ; + ; Odd logic here. The main loop skipped any leading + ; whitespace inside the quoted text, so move back to + ; the quote, then move forward again. + ; +034a : a922 lda #'"' ;pre-load with char to find +034c : 88 iPRS3 dey ;move back one +034d : d17d cmp (CURPTR),y ;quote? +034f : d0fb bne iPRS3 +0351 : c8 iny +0352 : 847f sty CUROFF + ; +0354 : b17d iPRS2 lda (CURPTR),y +0356 : f010 beq PRSend2 ;end of line! +0358 : c922 cmp #'"' +035a : f009 beq PRSend +035c : 200602 jsr OUTCH +035f : e67f inc CUROFF +0361 : a47f ldy CUROFF +0363 : d0ef bne iPRS2 +0365 : c8 PRSend iny ;skip closing quote +0366 : 847f sty CUROFF +0368 : 4c7202 PRSend2 jmp NextIL + ; + ;===================================================== + ; Pop the top off the stack and print it as a signed + ; decimal number. + ; +036b : 204e0a iPRN jsr popR0 +036e : 20c108 jsr PrintDecimal +0371 : 4c7202 jmp NextIL + AS65 Assembler for R6502 [1.42]. Page 10 +---------------------------------- mytb.asm ---------------------------------- + + ; + ;===================================================== + ; Space to next zone. Currently the code does not + ; keep track of which column the output is on, so + ; just print a tab. + ; +0374 : a909 iSPC lda #TAB +0376 : 200602 jsr OUTCH +0379 : 4c7202 jmp NextIL + ; + ;===================================================== + ; If in immediate mode, jump to the address following + ; the NXT instruction. Else move to the next line of + ; user code and continue. + ; +037c : a584 iNXT lda RunMode +037e : d003 bne iNxtRun ;in run mode + ; + ; Get address and jump to it. + ; +0380 : 4cab06 jmp iJMP + ; +0383 : 20aa08 iNxtRun jsr FindNextLine + ; + ; Make sure we're not at the end of the program. + ; +0386 : a57d lda CURPTR +0388 : cd7b0e cmp PROGRAMEND +038b : d00a bne iNxtRun2 +038d : a57e lda CURPTR+1 +038f : cd7c0e cmp PROGRAMEND+1 +0392 : d003 bne iNxtRun2 + ; + ; At the end of the program. Pretend an END statement + ; was found. + ; +0394 : 4c3e04 jmp iFIN + ; +0397 : 202008 iNxtRun2 jsr getILWord ;ignore next word + ; jsr FindNextLine +039a : 4c7202 jmp NextIL + ; + ;===================================================== + ; XFER takes the number on top of the stack and looks + ; for that line in the program, or the next line + ; higher. Ie, if it's 1 but there is no line 1, then + ; find the next one after that. + ; +039d : 204e0a iXFER jsr popR0 +03a0 : 206708 jsr findLine +03a3 : a002 iXFER2 ldy #2 ;point to start of text +03a5 : 847f sty CUROFF +03a7 : a9ff lda #$ff +03a9 : 8584 sta RunMode + + ; + ; Transfer IL to STMT. I don't like having this + ; hard-coded; fix it. + ; +03ab : a925 lda #STMT&$ff +03ad : 8574 sta ILPC +03af : a90c lda #STMT>>8 + AS65 Assembler for R6502 [1.42]. Page 11 +---------------------------------- mytb.asm ---------------------------------- + +03b1 : 8575 sta ILPC+1 + +03b3 : 4c7202 jmp NextIL + ; + ; If both Z and C are cleared then there is no + ; program to run. + ; +03b6 : f00f beq iXferok +03b8 : 900d bcc iXferok + ; +03ba : ad710e lda errGoto +03bd : 8574 sta ILPC +03bf : ad720e lda errGoto+1 +03c2 : 8575 sta ILPC+1 +03c4 : 4c7202 jmp NextIL + ; + ; Run + ; +03c7 : iXferok +03c7 : a9ff lda #$ff +03c9 : 8584 sta RunMode ;we're running + ; + ; Need a more elegant way to do this + ; +03cb : a925 lda #STMT&$ff +03cd : 8574 sta ILPC +03cf : a90c lda #STMT>>8 +03d1 : 8575 sta ILPC+1 +03d3 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Save the pointer to the next line to the call stack. + ; +03d6 : iSAV +03d6 : 4c8102 jmp ILbad + ; + ;===================================================== + ; Pop the next line from the call stack. + ; +03d9 : iRSTR +03d9 : 4c8102 jmp ILbad + ; + ;===================================================== + ; Compare items on stack. Okay, so on input there are + ; three things on the stack + ; + ; EXPR2 <- Top of stack + ; OP <- relational operator, next on stack + ; EXPR1 <- last item on stack + ; + ; Comparison is: EXPR1 EXPR2 + ; + ; Operator is one of... + ; + ; 2 is = + ; 1 is < + ; 3 is <= + ; 5 is <> + ; 4 is > + ; 6 is >= + ; + ; Those are bit-mapped: + AS65 Assembler for R6502 [1.42]. Page 12 +---------------------------------- mytb.asm ---------------------------------- + + ; + ; xxxxxGEL + ; + ; G = Greater than + ; E = Equal + ; L = Less than + ; + ; If the comparison is false, do a NXT, ie, move to th + ; next line and continue. If true, continue executing + ; on this line. + ; +0001 = REL_LT equ %001 +0002 = REL_EQUAL equ %010 +0004 = REL_GT equ %100 + ; +03dc : 20610a iCMPR jsr popR1 +03df : 20740a jsr popMQ ;operator in MQ +03e2 : 204e0a jsr popR0 + ; + ; See if they are equal or not + ; +03e5 : a580 lda R0 +03e7 : c582 cmp R1 +03e9 : d00a bne iCMPRnoteq ;try not equal +03eb : a581 lda R0+1 +03ed : c583 cmp R1+1 +03ef : d004 bne iCMPRnoteq + ; + ; Equal, set the flag in MQ+1 + ; +03f1 : a902 lda #REL_EQUAL +03f3 : d014 bne iCMPcom + ; + ; See if EXPR1 (R0) < EXPR2 (R1) + ; See www.6502.org/tutorials/compare_beyond.html + ; +03f5 : a580 iCMPRnoteq lda R0 +03f7 : c582 cmp R1 +03f9 : a581 lda R0+1 +03fb : e583 sbc R1+1 +03fd : 5002 bvc iCMPR_2 +03ff : 4980 eor #$80 +0401 : 3004 iCMPR_2 bmi iCMPlt +0403 : a904 lda #REL_GT +0405 : d002 bne iCMPcom +0407 : a901 iCMPlt lda #REL_LT ;R0 < R1 +0409 : 0d740e iCMPcom ora MQ+1 + ; + ; Now compare the end result with what the caller + ; was looking for. + ; +040c : 2d730e and MQ +040f : f007 beq iCMPno ;no match +0411 : 4c7202 jmp NextIL + ; + ; R0 > R1 + ; +0414 : a904 iCMPgt lda #REL_GT +0416 : d0f1 bne iCMPcom + ; + ; Not a match, so jump to the next line of code. + ; + AS65 Assembler for R6502 [1.42]. Page 13 +---------------------------------- mytb.asm ---------------------------------- + +0418 : 20aa08 iCMPno jsr FindNextLine +041b : 4ca303 jmp iXFER2 + ; + ;===================================================== + ; Get a line of text from the user, convert to a + ; number, leave on top of stack. + ; +041e : a57f iINNUM lda CUROFF ;save state before GetLine +0420 : 48 pha +0421 : a57e lda CURPTR+1 +0423 : 48 pha +0424 : a57d lda CURPTR +0426 : 48 pha + ; +0427 : a93f lda #'?' +0429 : 20a409 jsr GetLine +042c : 202d09 jsr getDecimal +042f : 20280a jsr pushR0 ;put onto stack + ; +0432 : 68 pla +0433 : 857d sta CURPTR +0435 : 68 pla +0436 : 857e sta CURPTR+1 +0438 : 68 pla +0439 : 857f sta CUROFF + ; +043b : 4c7202 jmp NextIL + ; + ;===================================================== + ; Stop the currently running program. Actually very + ; simple to do... clear the RunMode flag, then set the + ; ILPC to the standard handler and continue running. + ; +043e : a900 iFIN lda #0 +0440 : 8584 sta RunMode + ; +0442 : ad710e lda errGoto +0445 : 8574 sta ILPC +0447 : ad720e lda errGoto+1 +044a : 8575 sta ILPC+1 +044c : 4c7202 jmp NextIL + ; + ;===================================================== + ; Handle the ERR opcode. Following the instruction is + ; a 16 bit error number. Print an error message, and + ; if we're in run mode, print the line number. Stop + ; program execution and return to the initial state. + ; +044f : 202008 iERR jsr getILWord ;get err code + ; + ; Enter here with the error code in X (LSB) and A (MSB + ; +0452 : 8680 iErr2 stx R0 +0454 : 8581 sta R0+1 + ; +0456 : 2012f0 jsr puts +0459 : 4572726f722000 db "Error ",0 +0460 : 20c108 jsr PrintDecimal + ; +0463 : a584 lda RunMode ;running? +0465 : f01b beq iERR2 ;nope +0467 : 2012f0 jsr puts + AS65 Assembler for R6502 [1.42]. Page 14 +---------------------------------- mytb.asm ---------------------------------- + +046a : 206174206c696e.. db " at line ",0 +0474 : a000 ldy #0 +0476 : b17d lda (CURPTR),y +0478 : 8580 sta R0 +047a : c8 iny +047b : b17d lda (CURPTR),y +047d : 8581 sta R0+1 +047f : 20c108 jsr PrintDecimal + ; +0482 : 200c02 iERR2 jsr CRLF +0485 : a900 lda #0 +0487 : 8584 sta RunMode ;fall through... + ; + ;===================================================== + ; Reset the IL to be back at the idle loop. Does not + ; clear variables so the user can see what state + ; the program is in. + ; +0489 : a900 ResetIL lda #0 +048b : 8d0b0e sta retStackPtr +048e : ad710e lda errGoto +0491 : 8574 sta ILPC +0493 : ad720e lda errGoto+1 +0496 : 8575 sta ILPC+1 +0498 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Pop two items off stack, add them, then place the + ; result back onto the stack. + ; +049b : 204e0a iADD jsr popR0 +049e : 20610a jsr popR1 +04a1 : 18 clc +04a2 : a580 lda R0 +04a4 : 6582 adc R1 +04a6 : 8580 sta R0 +04a8 : a581 lda R0+1 +04aa : 6583 adc R1+1 +04ac : 8581 sta R0+1 +04ae : 4c1305 jmp pushR0nextIl + ; + ;===================================================== + ; Pop two items off the stack. Subtract the top of + ; stack from the lower entry. + ; +04b1 : 20610a iSUB jsr popR1 +04b4 : 204e0a jsr popR0 +04b7 : 38 sec +04b8 : a580 lda R0 +04ba : e582 sbc R1 +04bc : 8580 sta R0 +04be : a581 lda R0+1 +04c0 : e583 sbc R1+1 +04c2 : 8581 sta R0+1 +04c4 : 4c1305 jmp pushR0nextIl + ; + ;===================================================== + ; Negate the top of stack. + ; +04c7 : 204e0a iNEG jsr popR0 +04ca : a580 lda R0 +04cc : 49ff eor #$ff + AS65 Assembler for R6502 [1.42]. Page 15 +---------------------------------- mytb.asm ---------------------------------- + +04ce : 8580 sta R0 +04d0 : a581 lda R0+1 +04d2 : 49ff eor #$ff +04d4 : 8581 sta R0+1 +04d6 : e680 inc R0 +04d8 : d002 bne iNEG2 +04da : e681 inc R0+1 +04dc : 4c1305 iNEG2 jmp pushR0nextIl + ; + ;===================================================== + ; Multiply top two items on the stack, put the results + ; on top. This uses the algorithm documented on page + ; 115 of "Microprocessor Programming for Computer + ; Hobbyists" by Neill Graham. + ; +04df : 204e0a iMUL jsr popR0 ;AC +04e2 : 20610a jsr popR1 ;OP + ; +04e5 : a580 lda R0 +04e7 : 8d730e sta MQ +04ea : a581 lda R0+1 +04ec : 8d740e sta MQ+1 +04ef : a900 lda #0 ;clear result +04f1 : 8580 sta R0 +04f3 : 8581 sta R0+1 + ; +04f5 : a210 ldx #16 ;number of bits in value +04f7 : 0680 multloop asl R0 +04f9 : 2681 rol R0+1 +04fb : 0e730e asl MQ +04fe : 2e740e rol MQ+1 +0501 : 900d bcc multno ;skip add if no carry + ; + ; Add R1 back into R0 + ; +0503 : 18 clc +0504 : a580 lda R0 +0506 : 6582 adc R1 +0508 : 8580 sta R0 +050a : a581 lda R0+1 +050c : 6583 adc R1+1 +050e : 8581 sta R0+1 + ; +0510 : ca multno dex ;did all bits yet? +0511 : d0e4 bne multloop + ; +0513 : 20280a pushR0nextIl jsr pushR0 ;OP +0516 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Divide the top of stack into the next to top item. + ; Leave results on stack. Taken from: + ; http://codebase64.org/doku.php?id=base:16bit_divisio + ; + ; MQ = R0 / R1 + ; Remainder is in R0 + ; +0519 : 20610a iDIV jsr popR1 +051c : 204e0a jsr popR0 + ; + ; Check for divide by zero + ; + AS65 Assembler for R6502 [1.42]. Page 16 +---------------------------------- mytb.asm ---------------------------------- + +051f : a582 lda R1 +0521 : 0583 ora R1+1 +0523 : f036 beq divby0 + ; +0525 : 20890a jsr SaveSigns +0528 : a900 lda #0 ;preset remainder to 0 +052a : 8d730e sta MQ +052d : 8d740e sta MQ+1 +0530 : a210 ldx #16 ;repeat for each bit: ... + +0532 : 0680 divloop asl R0 ;dividend lb & hb*2, msb -> Carry +0534 : 2681 rol R0+1 +0536 : 2e730e rol MQ ;remainder lb & hb * 2 + msb from carry +0539 : 2e740e rol MQ+1 +053c : ad730e lda MQ +053f : 38 sec +0540 : e582 sbc R1 ;substract divisor to see if it fits in +0542 : a8 tay ;lb result -> Y, for we may need it late +0543 : ad740e lda MQ+1 +0546 : e583 sbc R1+1 +0548 : 9008 bcc skip ;if carry=0 then divisor didn't fit in yet + +054a : 8d740e sta MQ+1 ;else save substraction result as new remai +054d : 8c730e sty MQ +0550 : e680 inc R0 ;and INCrement result cause divisor fit in 1 + +0552 : ca skip dex +0553 : d0dd bne divloop +0555 : 20c40a jsr RestoreSigns +0558 : 4c1305 jmp pushR0nextIl + ; + ; Indicate divide-by-zero error + ; +055b : a206 divby0 ldx #ERR_DIVIDE_ZERO +055d : a900 lda #0 +055f : 4c5204 jmp iErr2 + ; + ;===================================================== + ; This pops the top two items off the stack. The top + ; item is a data value and the other is an index into + ; the variable table. Save the value into that entry. + ; +0562 : 204e0a iSTORE jsr popR0 ;data +0565 : 20610a jsr popR1 ;index +0568 : a682 ldx R1 ;get index +056a : a580 lda R0 +056c : 9540 sta variables,x +056e : a581 lda R0+1 +0570 : 9541 sta variables+1,x +0572 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Replaces the top of stack with the variable whose + ; index it represents. + ; +0575 : 20610a iIND jsr popR1 +0578 : a682 ldx R1 ;get index +057a : b540 lda variables,x +057c : 8580 sta R0 +057e : b541 lda variables+1,x +0580 : 8581 sta R0+1 +0582 : 4c1305 jmp pushR0nextIl + AS65 Assembler for R6502 [1.42]. Page 17 +---------------------------------- mytb.asm ---------------------------------- + + ; + ;===================================================== + ; List the current BASIC program in memory. Uses R0, + ; tempIly, and dpl. + ; +0585 : 202f0b iLST jsr SetOutConsole +0588 : a983 iLST2 lda #ProgramStart&$ff +058a : 8576 sta dpl +058c : a90e lda #ProgramStart>>8 +058e : 8577 sta dpl+1 + ; + ; dpl/dph point to the current line. See if we're at + ; the end of the program. + ; +0590 : a576 iLSTloop lda dpl +0592 : cd7b0e cmp PROGRAMEND +0595 : d007 bne iLstNotEnd +0597 : a577 lda dpl+1 +0599 : cd7c0e cmp PROGRAMEND+1 +059c : f040 beq iLstdone + ; +059e : a000 iLstNotEnd ldy #0 +05a0 : b176 lda (dpl),y ;line number LSB +05a2 : 8580 sta R0 +05a4 : c8 iny +05a5 : b176 lda (dpl),y ;line number MSB +05a7 : 8581 sta R0+1 +05a9 : c8 iny +05aa : 847a sty tempIlY +05ac : 20c108 jsr PrintDecimal +05af : a920 lda #SPACE +05b1 : 203a0b jsr VOUTCH +05b4 : a47a ldy tempIlY +05b6 : b176 iLSTl2 lda (dpl),y +05b8 : f00a beq iLST3 ;end of this line +05ba : 847a sty tempIlY +05bc : 203a0b jsr VOUTCH +05bf : a47a ldy tempIlY +05c1 : c8 iny +05c2 : d0f2 bne iLSTl2 ;do next char + ; + ; End of this line. Print CR/LF, then move to the + ; next line. + ; +05c4 : c8 iLST3 iny +05c5 : 18 clc +05c6 : 98 tya +05c7 : 6576 adc dpl +05c9 : 8576 sta dpl +05cb : a577 lda dpl+1 +05cd : 6900 adc #0 +05cf : 8577 sta dpl+1 + ; + ; Have to manually do CR/LF so it uses the vectored + ; output function. + ; +05d1 : a90d lda #CR +05d3 : 203a0b jsr VOUTCH +05d6 : a90a lda #LF +05d8 : 203a0b jsr VOUTCH +05db : 4c9005 jmp iLSTloop ;do next line + ; + AS65 Assembler for R6502 [1.42]. Page 18 +---------------------------------- mytb.asm ---------------------------------- + +05de : 202f0b iLstdone jsr SetOutConsole +05e1 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Get a line of text into LINBUF. Terminate with a + ; null byte. + ; +05e4 : a93e iGETLINE lda #'>' ;prompt character +05e6 : 20a409 jsr GetLine + ; +05e9 : a900 lda #0 +05eb : 8584 sta RunMode +05ed : 4c7202 jmp NextIL + ; + ;===================================================== + ; This is called when the input buffer contains a line + ; typed in by the user that starts with a line number. + ; Insert the line into the program or delete the line + ; if there is nothing after the line number, + ; +05f0 : a000 iINSRT ldy #0 +05f2 : 202d09 jsr getDecimal ;convert line # +05f5 : 20f30a jsr SkipSpaces +05f8 : 847b sty offset ;save for now + ; + ; Now find the line OR the next higher line OR the + ; end of the program. + ; +05fa : 206708 jsr findLine + ; + ; If the line exists, it needs to be removed. + ; +05fd : d03d bne insert2 ;jump if not found + ; + ; Get length of line to be removed + ; +05ff : 200b0a jsr getCURPTRLength ;results in Y +0602 : 847c sty lineLength + ; + ; Compute the new end of the program first. + ; +0604 : 38 sec +0605 : ad7b0e lda PROGRAMEND +0608 : e57c sbc lineLength +060a : 8d7b0e sta PROGRAMEND +060d : ad7c0e lda PROGRAMEND+1 +0610 : e900 sbc #0 +0612 : 8d7c0e sta PROGRAMEND+1 + ; + ; Copy CURPTR into R1 for working + ; +0615 : a57d lda CURPTR +0617 : 8582 sta R1 +0619 : a57e lda CURPTR+1 +061b : 8583 sta R1+1 + ; + ; See if we're at the end. + ; +061d : a582 InsDelChk lda R1 +061f : cd7b0e cmp PROGRAMEND +0622 : d007 bne InsDelLoop +0624 : a583 lda R1+1 + AS65 Assembler for R6502 [1.42]. Page 19 +---------------------------------- mytb.asm ---------------------------------- + +0626 : cd7c0e cmp PROGRAMEND+1 +0629 : f011 beq insert2 + ; + ; Move one byte, move to next location. + ; +062b : a47c InsDelLoop ldy lineLength +062d : b182 lda (R1),y +062f : a000 ldy #0 +0631 : 9182 sta (R1),y +0633 : e682 inc R1 +0635 : d0e6 bne InsDelChk +0637 : e683 inc R1+1 +0639 : 4c1d06 jmp InsDelChk + ; + ; Deletion is done. + ; If the new line is empty we're done. + ; +063c : a47b insert2 ldy offset ;get back ptr +063e : b91d0e lda LINBUF,y ;next byte +0641 : f056 beq mvUpFini ;empty line + ; + ; CURPTR points to where the line will be inserted. + ; +0643 : 20fa09 jsr getLineLength ;get bytes needed + ; +0646 : ad7b0e lda PROGRAMEND +0649 : 8585 sta FROM +064b : ad7c0e lda PROGRAMEND+1 +064e : 8586 sta FROM+1 + ; +0650 : a000 mvup1 ldy #0 +0652 : b185 lda (FROM),y +0654 : a47c ldy lineLength +0656 : 9185 sta (FROM),y + ; +0658 : a585 lda FROM +065a : c57d cmp CURPTR +065c : d006 bne mvUpMore +065e : a586 lda FROM+1 +0660 : c57e cmp CURPTR+1 +0662 : f00b beq mvUpDone + ; + ; Not done yet + ; +0664 : a585 mvUpMore lda FROM ;decrement FROM +0666 : d002 bne mvUpMore2 +0668 : c686 dec FROM+1 +066a : c685 mvUpMore2 dec FROM +066c : 4c5006 jmp mvup1 + ; + ; All done with copy. + ; +066f : 18 mvUpDone clc +0670 : a57c lda lineLength +0672 : 6d7b0e adc PROGRAMEND +0675 : 8d7b0e sta PROGRAMEND +0678 : ad7c0e lda PROGRAMEND+1 +067b : 6900 adc #0 +067d : 8d7c0e sta PROGRAMEND+1 + ; +0680 : a000 ldy #0 ;copy line number first +0682 : a580 lda R0 + AS65 Assembler for R6502 [1.42]. Page 20 +---------------------------------- mytb.asm ---------------------------------- + +0684 : 917d sta (CURPTR),y +0686 : c8 iny +0687 : a581 lda R0+1 +0689 : 917d sta (CURPTR),y +068b : c8 iny + ; +068c : a67b ldx offset +068e : bd1d0e mvUpLoop2 lda LINBUF,x +0691 : 917d sta (CURPTR),y +0693 : f004 beq mvUpFini +0695 : e8 inx +0696 : c8 iny +0697 : d0f5 bne mvUpLoop2 + ; +0699 : 4c7202 mvUpFini jmp NextIL + ; + ;===================================================== + ; Pops the top value of the ILPC stack and stores it + ; in ILPC. Ie, return from an IL subroutine. + ; +069c : 205408 iRTN jsr popILPC +069f : 4c7202 jmp NextIL + ; + ;===================================================== + ; NLINE + ; +06a2 : 200c02 iNLINE jsr CRLF ;user supplied sub +06a5 : 4c7202 jmp NextIL + ; + ;===================================================== + ; This saves the current ILPC value on the stack, then + ; jumps to the address specified by the next two bytes + ; +06a8 : 203a08 iCALL jsr pushILPC ;save ILPC + ; + ; Jmp to a specific location in the IL code. The new + ; address immediately follows the opcode. + ; +06ab : 202008 iJMP jsr getILWord +06ae : 8674 stx ILPC +06b0 : 8575 sta ILPC+1 +06b2 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Push the next two bytes onto the arithmetic stack. + ; +06b5 : 202008 iLIT jsr getILWord +06b8 : 8680 stx R0 +06ba : 8581 sta R0+1 +06bc : 20280a jsr pushR0 +06bf : 4c7202 jmp NextIL + ; + ;===================================================== + ; Initialize all variables. Ie, set to zero. + ; +06c2 : a900 iVINIT lda #0 +06c4 : a200 ldx #0 +06c6 : 9540 Vinit2 sta variables,x +06c8 : e8 inx +06c9 : e034 cpx #variablesEnd-variables +06cb : d0f9 bne Vinit2 +06cd : 4c7202 jmp NextIL + AS65 Assembler for R6502 [1.42]. Page 21 +---------------------------------- mytb.asm ---------------------------------- + + ; + ;===================================================== + ; Set the address of the error handler. After any + ; error, set to the ILPC to the specified location. + ; +06d0 : 202008 iERRGOTO jsr getILWord +06d3 : 8e710e stx errGoto +06d6 : 8d720e sta errGoto+1 +06d9 : 4c7202 jmp NextIL + ; + ;===================================================== + ; TST is followed by an 8 bit signed offset, then a + ; null terminated string. Compare the string against + ; the string starting at (CURPTR),CUROFF. If the + ; strings match, continue executing the next IL + ; opcode. Else, add the offset to ILPC. + ; +06dc : 202408 iTST jsr getILByte +06df : 857b sta offset + ; +06e1 : 20160a jsr saveIL ;in case of failure +06e4 : a47f ldy CUROFF +06e6 : 8476 sty dpl ;save for later + ; +06e8 : 202408 iTSTloop jsr getILByte ;get next char +06eb : f00b beq iTSTm ;match! +06ed : a476 ldy dpl +06ef : d17d cmp (CURPTR),y +06f1 : d00c bne iTSTfail ;mismatch +06f3 : c8 iny +06f4 : 8476 sty dpl +06f6 : d0f0 bne iTSTloop + ; + ; It's a match! Clean up a bit. + ; +06f8 : a476 iTSTm ldy dpl +06fa : 847f sty CUROFF +06fc : 4c7202 jmp NextIL + ; + ; Not a match, reset ILPC and then move to the + ; offset. + ; +06ff : 201f0a iTSTfail jsr restoreIL +0702 : 4c6807 jmp tstBranch + ; + ;===================================================== + ; TSTV is followed by an 8 bit signed offset. If the + ; value at (CURPTR),CUROFF appears to be a variable + ; name, move to the next IL statement. Else, add the + ; offset to ILPC. + ; +0705 : 202408 iTSTV jsr getILByte ;offset +0708 : 857b sta offset + ; +070a : a47f ldy CUROFF +070c : 20f30a jsr SkipSpaces +070f : b17d lda (CURPTR),y + ; +0711 : c941 cmp #'A' +0713 : 9053 bcc tstBranch +0715 : c95b cmp #'Z'+1 +0717 : b04f bcs tstBranch + AS65 Assembler for R6502 [1.42]. Page 22 +---------------------------------- mytb.asm ---------------------------------- + + ; + ; The condition is true, so convert to an index, push + ; it onto the stack and continue running. + ; +0719 : 38 sec +071a : e941 sbc #'A' ;index is zero based +071c : 0a asl a ;multiply by two +071d : 8580 sta R0 +071f : a900 lda #0 +0721 : 8581 sta R0+1 +0723 : 20280a jsr pushR0 ;put index onto stack +0726 : e67f inc CUROFF ;move to next input char +0728 : 4c7202 jmp NextIL + ; + ;===================================================== + ; TSTL seems basically the same as TSTN, but leave the + ; value in R0 instead of pushing onto stack. + ; +072b : 202408 iTSTL jsr getILByte +072e : 857b sta offset + ; +0730 : a47f ldy CUROFF +0732 : 20f30a jsr SkipSpaces +0735 : b17d lda (CURPTR),y + ; +0737 : c930 cmp #'0' +0739 : 902d bcc tstBranch +073b : c93a cmp #'9'+1 +073d : b029 bcs tstBranch + ; + ; It's a digit, so convert to a number. + ; +073f : 202d09 jsr getDecimal +0742 : 4c7202 jmp NextIL + ; + ;===================================================== + ; TSTN checks for a number. This is very simplistic; + ; if the character is a digit, assume it's a number. + ; Convert to a number and push it onto the stack. + ; +0745 : 202408 iTSTN jsr getILByte +0748 : 857b sta offset + ; +074a : a47f ldy CUROFF +074c : 20f30a jsr SkipSpaces +074f : b17d lda (CURPTR),y + ; +0751 : c92d cmp #'-' ;negative? +0753 : f008 beq iTSTN_1 +0755 : c930 cmp #'0' +0757 : 900f bcc tstBranch +0759 : c93a cmp #'9'+1 +075b : b00b bcs tstBranch + ; + ; It's a digit, so convert to a number. + ; +075d : 202d09 iTSTN_1 jsr getDecimal +0760 : 847f sty CUROFF +0762 : 20280a jsr pushR0 ;save onto stack +0765 : 4c7202 jmp NextIL + ; + ; Common jump point for all TSTx instructions that + AS65 Assembler for R6502 [1.42]. Page 23 +---------------------------------- mytb.asm ---------------------------------- + + ; fail to meet the requirements. This takes the + ; offset and adds/subtracts to/from ILPC. + ; +0768 : a57b tstBranch lda offset ;get signed offset +076a : 100e bpl tstPositive + ; + ; Do negative branch. Do sign extension. + ; +076c : 18 clc +076d : 6574 adc ILPC +076f : 8574 sta ILPC +0771 : a575 lda ILPC+1 +0773 : 69ff adc #$ff +0775 : 8575 sta ILPC+1 +0777 : 4c7202 jmp NextIL ;keep going + ; +077a : 18 tstPositive clc +077b : 6574 adc ILPC +077d : 8574 sta ILPC +077f : a575 lda ILPC+1 +0781 : 6900 adc #0 +0783 : 8575 sta ILPC+1 +0785 : 4c7202 jmp NextIL + ; + ;===================================================== + ; This places the number of free bytes on top of the + ; stack. + ; +0788 : 20fc0a iFREE jsr GetSizes +078b : 20280a jsr pushR0 +078e : 4c7202 jmp NextIL + ; + ;===================================================== + ; Generate a random number from 0-FFFF and then MOD + ; it with the value on top of stack. Leaves number on + ; stack + ; +0791 : 20610a iRANDOM jsr popR1 ;mod value +0794 : ad780e lda random+1 +0797 : 8d760e sta rtemp1 +079a : ad770e lda random +079d : 0a asl a +079e : 2e760e rol rtemp1 +07a1 : 0a asl a +07a2 : 2e760e rol rtemp1 +07a5 : 18 clc +07a6 : 6d770e adc random +07a9 : 48 pha +07aa : ad760e lda rtemp1 +07ad : 6d780e adc random+1 +07b0 : 8d780e sta random+1 +07b3 : 68 pla +07b4 : 6911 adc #$11 +07b6 : 8d770e sta random +07b9 : ad780e lda random+1 +07bc : 6936 adc #$36 +07be : 8d780e sta random+1 + +07c1 : ad770e lda random +07c4 : 8580 sta R0 +07c6 : ad780e lda random+1 +07c9 : 297f and #$7f ;make positive + AS65 Assembler for R6502 [1.42]. Page 24 +---------------------------------- mytb.asm ---------------------------------- + +07cb : 8581 sta R0+1 + ; + ; R0 contains the number and R1 contains the max value + ; +07cd : a580 iRANDOM_2 lda R0 +07cf : c582 cmp R1 +07d1 : d016 bne iRANDOM_1 +07d3 : a581 lda R0+1 +07d5 : c583 cmp R1+1 +07d7 : d010 bne iRANDOM_1 ;need to subtract + ; + ; Subtract R1 from R0 + ; +07d9 : 38 iRANDOM_sub sec +07da : a580 lda R0 +07dc : e582 sbc R1 +07de : 8580 sta R0 +07e0 : a581 lda R0+1 +07e2 : e583 sbc R1+1 +07e4 : 8581 sta R0+1 +07e6 : 4ccd07 jmp iRANDOM_2 + ; + ; See if R1 > R0. If so, branch to subtract. + ; +07e9 : a580 iRANDOM_1 lda R0 +07eb : c582 cmp R1 +07ed : a581 lda R0+1 +07ef : e583 sbc R1+1 +07f1 : 5002 bvc iRANDOM_4 +07f3 : 4980 eor #$80 +07f5 : 10e2 iRANDOM_4 bpl iRANDOM_sub + ; + ; All done. Almost. Add one, then push the result. + ; +07f7 : e680 inc R0 +07f9 : d002 bne iRANDOM_3 +07fb : e681 inc R0+1 +07fd : 20280a iRANDOM_3 jsr pushR0 ;return value +0800 : 4c7202 jmp NextIL + ; + ;===================================================== + ; Replace TOS with its absolute value. + ; +0803 : 204e0a iABS jsr popR0 +0806 : a581 lda R0+1 +0808 : 1010 bpl iABS_1 ;already positive +080a : 49ff eor #$ff +080c : 8581 sta R0+1 +080e : a580 lda R0 +0810 : 49ff eor #$ff +0812 : 8580 sta R0 +0814 : e680 inc R0 +0816 : d002 bne iABS_1 +0818 : e681 inc R0+1 +081a : 20280a iABS_1 jsr pushR0 +081d : 4c7202 jmp NextIL + ; + include "support.asm" + ; + ;===================================================== + ;===================================================== + ;===================================================== + AS65 Assembler for R6502 [1.42]. Page 25 +---------------------------------- mytb.asm ---------------------------------- + + ; This marks the start of support functions used by + ; the IL opcodes. These are support functions, NOT + ; the IL code. + ;===================================================== + ;===================================================== + ;===================================================== + ; This gets the next two bytes pointed to by ILPC and + ; returns them; X contains LSB, A contains MSB. ILPC + ; is advanced by two, and Y contains 0 on return. + ; +0820 : 202408 getILWord jsr getILByte ;LSB +0823 : aa tax + ; + ;===================================================== + ; This gets the next byte pointed to by ILPC and + ; returns it in A. On return, X is unchanged but Y + ; contains 0. + ; +0824 : a000 getILByte ldy #0 +0826 : b174 lda (ILPC),y ;get byte +0828 : 08 php ;save status +0829 : e674 inc ILPC ;inc LSB +082b : d002 bne getILb2 ;branch if no overflow +082d : e675 inc ILPC+1 ;inc MSB +082f : 28 getILb2 plp ;restore status +0830 : 60 rts + ; + ;===================================================== + ; Decrement ILPC by one. + ; +0831 : a574 decIL lda ILPC +0833 : d002 bne decIL2 +0835 : c675 dec ILPC+1 +0837 : c674 decIL2 dec ILPC +0839 : 60 rts + ; + ;===================================================== + ; Push the ILPC onto the return stack. Actually, this + ; pushes the address of ILPC+2 since that's the next + ; address to execute. + ; +083a : ac0b0e pushILPC ldy retStackPtr +083d : a574 lda ILPC +083f : 18 clc +0840 : 6902 adc #2 +0842 : 99fb0d sta retStack,y +0845 : 08 php ;save C bit +0846 : c8 iny +0847 : a575 lda ILPC+1 +0849 : 28 plp ;restore C +084a : 6900 adc #0 +084c : 99fb0d sta retStack,y +084f : c8 iny +0850 : 8c0b0e sty retStackPtr +0853 : 60 rts + ; + ;===================================================== + ; Pull the top entry from return stack and put into + ; ILPC. + ; +0854 : ac0b0e popILPC ldy retStackPtr +0857 : 88 dey + AS65 Assembler for R6502 [1.42]. Page 26 +---------------------------------- mytb.asm ---------------------------------- + +0858 : b9fb0d lda retStack,y +085b : 8575 sta ILPC+1 +085d : 88 dey +085e : b9fb0d lda retStack,y +0861 : 8574 sta ILPC +0863 : 8c0b0e sty retStackPtr +0866 : 60 rts + ; + ;===================================================== + ; This searches for a specific line number that is in + ; R0. There are three possible return conditions: + ; + ; Exact match was found: + ; * Z set + ; * CURPTR points to two-byte line number for that + ; line. + ; + ; Next highest line found: + ; * Z cleared + ; * C set + ; * CURPTR points to two-byte line number for that + ; line. + ; + ; End of program reached: + ; * Z cleared + ; * C cleared + ; * CURPTR points to first free byte at end of + ; program. Ie, it has save value as PROGRAMEND. + ; + ; A, X, and Y are all undefined on return. + ; +0867 : a983 findLine lda #ProgramStart&$ff +0869 : 857d sta CURPTR +086b : a90e lda #ProgramStart>>8 +086d : 857e sta CURPTR+1 + ; + ; At end of code? + ; +086f : a57d iXFER1 lda CURPTR +0871 : cd7b0e cmp PROGRAMEND +0874 : d00b bne xfer2 ;not end +0876 : a57e lda CURPTR+1 +0878 : cd7c0e cmp PROGRAMEND+1 +087b : d004 bne xfer2 + ; + ; Line not found and the end of the program was + ; reached. Return Z and C both clear. + ; +087d : a901 lda #1 ;clear Z +087f : 18 clc ;clear C +0880 : 60 rts + ; + ; Check for an exact match first + ; +0881 : a580 xfer2 lda R0 +0883 : a000 ldy #0 +0885 : d17d cmp (CURPTR),y +0887 : d008 bne xfernotit +0889 : c8 iny +088a : a581 lda R0+1 +088c : d17d cmp (CURPTR),y +088e : d001 bne xfernotit + AS65 Assembler for R6502 [1.42]. Page 27 +---------------------------------- mytb.asm ---------------------------------- + + ; + ; This is exactly the line we want. + ; +0890 : 60 rts + ; + ; See if this line is greater than the one we're + ; searching for. + ; +0891 : a001 xfernotit ldy #1 +0893 : b17d lda (CURPTR),y ;compare MSB first +0895 : c581 cmp R0+1 +0897 : 900b bcc xfer3 +0899 : d007 bne xfer4 +089b : 88 dey +089c : b17d lda (CURPTR),y ;compare LSB +089e : c580 cmp R0 +08a0 : 9002 bcc xfer3 + ; + ; This line is greater than the one we want, so + ; return Z clear and C set. + ; +08a2 : 38 xfer4: sec +08a3 : 60 rts ;both conditions set + ; + ; Not the line (or droid) we're looking for. Move to + ; the next line. + ; +08a4 : 20aa08 xfer3 jsr FindNextLine +08a7 : 4c8108 jmp xfer2 + ; + ;===================================================== + ; This advances CURPTR to the next line. If there + ; are no more lines, this leaves CURPTR equal to + ; ProgramEnd. Returns CUROFF set to 2. This assumes + ; CURPTR is pointing to a valid line on entry. This + ; pointer points to the two-byte line number. + ; +08aa : a002 FindNextLine ldy #2 ;skip line number +08ac : 847f sty CUROFF ;this is the new offset + ; +08ae : b17d FindNext2 lda (CURPTR),y +08b0 : f003 beq FindNext3 ;found end +08b2 : c8 iny +08b3 : d0f9 bne FindNext2 +08b5 : c8 FindNext3 iny ;skip null byte +08b6 : 98 tya +08b7 : 18 clc +08b8 : 657d adc CURPTR +08ba : 857d sta CURPTR +08bc : 9002 bcc FindNext4 ;exit +08be : e67e inc CURPTR+1 +08c0 : 60 FindNext4 rts + ; + ;===================================================== + ; Print the contents of R0 as a signed decimal number. + ; Does leading zero suppression. + ; +08c1 : a581 PrintDecimal lda R0+1 ;MSB has sign +08c3 : 1017 bpl pplus ;it's a positive number + ; + ; Negative numbers need more work. Invert all the bit + ; then add one. + AS65 Assembler for R6502 [1.42]. Page 28 +---------------------------------- mytb.asm ---------------------------------- + + ; +08c5 : a92d lda #'-' +08c7 : 203a0b jsr VOUTCH ;print the negative sign + ; +08ca : a580 lda R0 ;invert bits +08cc : 49ff eor #$ff +08ce : 8580 sta R0 +08d0 : a581 lda R0+1 +08d2 : 49ff eor #$ff +08d4 : 8581 sta R0+1 +08d6 : e680 inc R0 ;add one +08d8 : d002 bne pplus +08da : e681 inc R0+1 + ; + ; Print the value in R0 as a positive number. + ; +08dc : a200 pplus ldx #0 ;start of subtraction table +08de : 8e6f0e stx diddigit ;no digits yet +08e1 : a000 pploop ldy #0 ;result of division +08e3 : a580 pploop2 lda R0 ;LSB +08e5 : 38 sec +08e6 : fd2509 sbc dectable,x +08e9 : 8580 sta R0 +08eb : a581 lda R0+1 +08ed : fd2609 sbc dectable+1,x +08f0 : 102e bpl pplusok ;no underflow + ; + ; Else, underflow. Add back in the LSB of the + ; table to R0. + ; +08f2 : 18 clc +08f3 : a580 lda R0 +08f5 : 7d2509 adc dectable,x +08f8 : 8580 sta R0 + ; + ; Print the value in Y. Actually, see if Y is zero an + ; whether any digit has been printed yet. If Y isn't + ; zero or we've printed a digit, go ahead and print. + ; +08fa : 8e6e0e stx printtx +08fd : 98 tya +08fe : 0900 ora #0 ;set flags +0900 : d005 bne pprintit ;non-zero, print + ; +0902 : ad6f0e lda diddigit +0905 : f009 beq pprintno ;don't print + ; +0907 : 98 pprintit tya +0908 : 0930 ora #'0' +090a : 8d6f0e sta diddigit +090d : 203a0b jsr VOUTCH +0910 : ae6e0e pprintno ldx printtx + ; + ; Move to the next table entry + ; +0913 : e8 inx +0914 : e8 inx +0915 : e008 cpx #dectableend-dectable +0917 : d0c8 bne pploop ;not at end + ; + ; At the end. R0 contains the final value + ; to print. + AS65 Assembler for R6502 [1.42]. Page 29 +---------------------------------- mytb.asm ---------------------------------- + + ; +0919 : a580 lda R0 +091b : 0930 ora #'0' +091d : 4c3a0b jmp VOUTCH + ; + ; Finish doing the subtraction. + ; +0920 : 8581 pplusok sta R0+1 +0922 : c8 iny +0923 : d0be bne pploop2 + ; + ; Table of powers-of-ten + ; +0925 : 1027 dectable dw 10000 +0927 : e803 dw 1000 +0929 : 6400 dw 100 +092b : 0a00 dw 10 +092d = dectableend equ * + ; + ;===================================================== + ; Convert an ASCII string to a number. On input, + ; (CURPTR),Y points to the first digit. This gets + ; digit-by-digit until finding a non-number. Returns + ; Y pointing to the non-digit, and R0 contains the + ; number. This does NOT check for valid ranges, so + ; a value like "123456789" will produce something, + ; but not what you had expected. + ; +092d : a900 getDecimal lda #0 +092f : 8580 sta R0 +0931 : 8581 sta R0+1 +0933 : 8576 sta dpl ;temporary negative flag + ; + ; See if it's negative... + ; +0935 : 8413 sty $0013 +0937 : b17d lda (CURPTR),y +0939 : c92d cmp #'-' +093b : d002 bne getDecLoop +093d : e676 inc dpl ;it's negative + ; +093f : b17d getDecLoop lda (CURPTR),y +0941 : c930 cmp #'0' +0943 : 9036 bcc getDdone +0945 : c93a cmp #'9'+1 +0947 : b032 bcs getDdone +0949 : 38 sec +094a : e930 sbc #'0' ;convert to binary +094c : 48 pha + ; + ; Now multiply R0 by 10. Remember that + ; 2*N + 8*N = 10*N. + ; +094d : 0680 asl R0 +094f : 2681 rol R0+1 ;*2 +0951 : a580 lda R0 +0953 : 8582 sta R1 +0955 : a581 lda R0+1 +0957 : 8583 sta R1+1 +0959 : 0680 asl R0 +095b : 2681 rol R0+1 ;*4 +095d : 0680 asl R0 + AS65 Assembler for R6502 [1.42]. Page 30 +---------------------------------- mytb.asm ---------------------------------- + +095f : 2681 rol R0+1 ;*8 +0961 : 18 clc ;now add the partial sums... +0962 : a580 lda R0 ;...to get *10 +0964 : 6582 adc R1 +0966 : 8580 sta R0 +0968 : a581 lda R0+1 +096a : 6583 adc R1+1 +096c : 8581 sta R0+1 + ; + ; Add in the new digit + ; +096e : 68 pla +096f : 18 clc +0970 : 6580 adc R0 +0972 : 8580 sta R0 +0974 : 9002 bcc getD2 +0976 : e681 inc R0+1 + ; + ; Move to next character + ; +0978 : c8 getD2 iny +0979 : d0c4 bne getDecLoop + ; + ; All done with digits, so now deal with it being + ; negative. If zero, then don't check for negative + ; flag. Ie, -0 is stored as 0. + ; +097b : a580 getDdone lda R0 +097d : 0581 ora R0+1 +097f : f016 beq getDone2 ;zero +0981 : a576 lda dpl +0983 : f012 beq getDone2 ;positive + ; + ; Invert all the bits, then add one. + ; +0985 : a580 lda R0 +0987 : 49ff eor #$ff +0989 : 8580 sta R0 +098b : a581 lda R0+1 +098d : 49ff eor #$ff +098f : 8581 sta R0+1 + ; +0991 : e680 inc R0 +0993 : d002 bne getDone2 +0995 : e681 inc R0+1 +0997 : getDone2 +0997 : a580 lda R0 +0999 : 8510 sta $0010 +099b : a581 lda R0+1 +099d : 8511 sta $0011 +099f : a576 lda dpl +09a1 : 8512 sta $012 + +09a3 : 60 rts + ; + ;===================================================== + ; Print the string that immediately follows the JSR to + ; this function. Stops when a null byte is found, + ; then returns to the instruction immediately + ; following the null. + ; + ; Thanks to Ross Archer for this code. + AS65 Assembler for R6502 [1.42]. Page 31 +---------------------------------- mytb.asm ---------------------------------- + + ; http://www.6502.org/source/io/primm.htm + ; + if KIM + puts sty putsy + pla ;low part of "return" address + ;(data start address) + sta dpl + pla + sta dpl+1 ;high part of "return" address + ;(data start address) + ;Note: we're pointing one short + psinb ldy #1 + lda (dpl),y ;Get next string character + inc dpl ;update the pointer + bne psinc ;if not, we're pntng to next char + inc dpl+1 ;account for page crossing + psinc ora #0 ;Set flags according to contents of + ; Accumulator + beq psix1 ;don't print the final NULL + jsr OUTCH ;write it out + jmp psinb ;back around + psix1 inc dpl + bne psix2 + inc dpl+1 ;account for page crossing + psix2 ldy putsy + jmp (dpl) ;return to byte following NULL + endif + ; + ;===================================================== + ; Gets a line of input into LINBUF. + ; + ; On entry: + ; A contains the prompt character, or 0 if none. + ; + ; On exit: + ; CURPTR points to LINBUF + ; LINBUF contains the line with 0 at the end. + ; Y has offset to first non-space character + ; CURROFF has the same as Y. + ; +09a4 : a21d GetLine ldx #LINBUF&$ff +09a6 : 867d stx CURPTR +09a8 : a20e ldx #LINBUF>>8 +09aa : 867e stx CURPTR+1 + ; + ; Prompt + ; +09ac : 48 pha ;save for retries +09ad : 68 GetLinePr pla ;restore +09ae : 48 pha ;save again +09af : 0900 ora #0 ;any prompt? +09b1 : f008 beq getlinenp +09b3 : 200602 jsr OUTCH +09b6 : a920 lda #' ' +09b8 : 200602 jsr OUTCH ;space after prompt + ; +09bb : a200 getlinenp ldx #0 ;offset into LINBUF +09bd : 8e6d0e getline1 stx getlinx +09c0 : 200902 jsr GETCH + if CTMON65 +09c3 : 48 pha +09c4 : 200cf0 jsr cout + AS65 Assembler for R6502 [1.42]. Page 32 +---------------------------------- mytb.asm ---------------------------------- + +09c7 : 68 pla + endif +09c8 : c90d cmp #CR +09ca : f00d beq getlind ;end of line +09cc : c908 cmp #BS ;backspace? +09ce : f021 beq getlinebs +09d0 : ae6d0e ldx getlinx +09d3 : 9d1d0e sta LINBUF,x +09d6 : e8 inx +09d7 : d0e4 bne getline1 + ; + ; CR was hit + ; +09d9 : a900 getlind lda #0 +09db : ae6d0e ldx getlinx +09de : 9d1d0e sta LINBUF,x +09e1 : 857f sta CUROFF + ; + ; Output a CR/LF + ; +09e3 : 200c02 jsr CRLF + ; + ; If a blank line, prompt again. + ; +09e6 : a000 ldy #0 +09e8 : 20f30a jsr SkipSpaces +09eb : b17d lda (CURPTR),y +09ed : f0be beq GetLinePr ;empty line +09ef : 68 pla ;get rid of prompt char +09f0 : 60 rts + ; + ; Backspace was hit + ; +09f1 : ae6d0e getlinebs ldx getlinx +09f4 : f0c7 beq getline1 ;at start of line +09f6 : ca dex +09f7 : 4cbd09 jmp getline1 + ; + ;===================================================== + ; Count the length of the line currently in LINBUF + ; starting at offset Y. Returns the length in X. The + ; starting offset in Y should point past the ASCII + ; line number. Also counts the trailing NULL and two + ; extra bytes for where the line number will be. + ; +09fa : a200 getLineLength ldx #0 ;size +09fc : b91d0e getLineL2 lda LINBUF,y +09ff : f004 beq getLineL3 +0a01 : c8 iny +0a02 : e8 inx +0a03 : d0f7 bne getLineL2 +0a05 : e8 getLineL3 inx ;count null at end +0a06 : e8 inx ;line number LSB +0a07 : e8 inx ;MSB +0a08 : 867c stx lineLength +0a0a : 60 rts + ; + ;===================================================== + ; Count the length of the line pointed to by CURPTR. + ; This also counts the line number and the terminating + ; null. Ie, this string returns 8: + ; + AS65 Assembler for R6502 [1.42]. Page 33 +---------------------------------- mytb.asm ---------------------------------- + + ; Hello + ; + ; Another way of looking at it: add the return value + ; to the CURPTR and it'll point to the next line's + ; line number. Returns the value in Y. + ; +0a0b : a002 getCURPTRLength ldy #2 ;skip line number +0a0d : b17d getCLineL2 lda (CURPTR),y +0a0f : f003 beq getCLineL3 +0a11 : c8 iny +0a12 : d0f9 bne getCLineL2 +0a14 : c8 getCLineL3 iny ;count null at end +0a15 : 60 rts + ; + ;===================================================== + ; This saves ILPC. This saves to a single save area, + ; so it can't be called more than once. + ; +0a16 : a574 saveIL lda ILPC +0a18 : 8578 sta tempIL +0a1a : a575 lda ILPC+1 +0a1c : 8579 sta tempIL+1 +0a1e : 60 rts + ; + ;===================================================== + ; This restores ILPC. + ; +0a1f : a578 restoreIL lda tempIL +0a21 : 8574 sta ILPC +0a23 : a579 lda tempIL+1 +0a25 : 8575 sta ILPC+1 +0a27 : 60 rts + ; + ;===================================================== + ; This pushes R0 onto the stack. + ; +0a28 : aefa0d pushR0 ldx mathStackPtr +0a2b : a580 lda R0 +0a2d : 9dea0d sta mathStack,x +0a30 : e8 inx +0a31 : a581 lda R0+1 +0a33 : 9dea0d sta mathStack,x +0a36 : e8 inx +0a37 : 8efa0d stx mathStackPtr +0a3a : 60 rts + ; + ;===================================================== + ; This pushes R1 onto the stack + ; +0a3b : aefa0d pushR1 ldx mathStackPtr +0a3e : a582 lda R1 +0a40 : 9dea0d sta mathStack,x +0a43 : e8 inx +0a44 : a583 lda R1+1 +0a46 : 9dea0d sta mathStack,x +0a49 : e8 inx +0a4a : 8efa0d stx mathStackPtr +0a4d : 60 rts + ; + ;===================================================== + ; This pops TOS and places it in R0. + ; + AS65 Assembler for R6502 [1.42]. Page 34 +---------------------------------- mytb.asm ---------------------------------- + +0a4e : aefa0d popR0 ldx mathStackPtr +0a51 : ca dex +0a52 : bdea0d lda mathStack,x +0a55 : 8581 sta R0+1 +0a57 : ca dex +0a58 : bdea0d lda mathStack,x +0a5b : 8580 sta R0 +0a5d : 8efa0d stx mathStackPtr +0a60 : 60 rts + ; + ;===================================================== + ; This pops TOS and places it in R1. + ; +0a61 : aefa0d popR1 ldx mathStackPtr +0a64 : ca dex +0a65 : bdea0d lda mathStack,x +0a68 : 8583 sta R1+1 +0a6a : ca dex +0a6b : bdea0d lda mathStack,x +0a6e : 8582 sta R1 +0a70 : 8efa0d stx mathStackPtr +0a73 : 60 rts + ; + ;===================================================== + ; This pops TOS and places it in MQ. + ; +0a74 : aefa0d popMQ ldx mathStackPtr +0a77 : ca dex +0a78 : bdea0d lda mathStack,x +0a7b : 8d740e sta MQ+1 +0a7e : ca dex +0a7f : bdea0d lda mathStack,x +0a82 : 8d730e sta MQ +0a85 : 8efa0d stx mathStackPtr +0a88 : 60 rts + ; + ;===================================================== + ; This assists with multiplication and division by + ; looking at R0 and R1 and saving a flag as to what + ; sign the result will be. Math is always done on + ; positive numbers, so this converts negative numbers + ; into positives. On exit, R0 and R1 are both + ; positive. If the signs were different then 'signs' + ; will be non-zero. + ; +0a89 : a900 SaveSigns lda #0 +0a8b : 8d750e sta sign ;assume positive +0a8e : a581 lda R0+1 ;MSB +0a90 : 1013 bpl SaveSigns1 +0a92 : ee750e inc sign ;it's negative +0a95 : 49ff eor #$ff ;flip bits +0a97 : 8581 sta R0+1 +0a99 : a580 lda R0 +0a9b : 49ff eor #$ff +0a9d : 8580 sta R0 +0a9f : e680 inc R0 +0aa1 : d002 bne SaveSigns1 +0aa3 : e681 inc R0+1 +0aa5 : a583 SaveSigns1 lda R1+1 +0aa7 : 101a bpl SaveSigns2 +0aa9 : 48 pha +0aaa : ad750e lda sign + AS65 Assembler for R6502 [1.42]. Page 35 +---------------------------------- mytb.asm ---------------------------------- + +0aad : 4901 eor #1 +0aaf : 8d750e sta sign +0ab2 : 68 pla +0ab3 : 49ff eor #$ff ;flip bits +0ab5 : 8583 sta R1+1 +0ab7 : a582 lda R1 +0ab9 : 49ff eor #$ff +0abb : 8582 sta R1 +0abd : e682 inc R1 +0abf : d002 bne SaveSigns2 +0ac1 : e683 inc R1+1 +0ac3 : 60 SaveSigns2 rts + ; + ;===================================================== + ; This looks at the value of 'signs' and will convert + ; both R0 and R1 to negative if set. + ; +0ac4 : ad750e RestoreSigns lda sign +0ac7 : f028 beq restoresigns2 + ; +0ac9 : a580 lda R0 +0acb : d002 bne restoresigns3 +0acd : c681 dec R0+1 +0acf : c680 restoresigns3 dec R0 +0ad1 : a580 lda R0 +0ad3 : 49ff eor #$ff +0ad5 : 8580 sta R0 +0ad7 : a581 lda R0+1 +0ad9 : 49ff eor #$ff +0adb : 8581 sta R0+1 + ; +0add : a582 lda R1 +0adf : d002 bne restoresigns4 +0ae1 : c683 dec R1+1 +0ae3 : c682 restoresigns4 dec R1 +0ae5 : a582 lda R1 +0ae7 : 49ff eor #$ff +0ae9 : 8582 sta R1 +0aeb : a583 lda R1+1 +0aed : 49ff eor #$ff +0aef : 8583 sta R1+1 + ; +0af1 : 60 restoresigns2 rts + ; + ;===================================================== + ; Skip over spaces. Returns Y with the offset to + ; either the last character in the line, or the first + ; non-space character. + ; +0af2 : c8 skipsp2 iny +0af3 : b17d SkipSpaces lda (CURPTR),y +0af5 : f004 beq Skip3 ;end of line +0af7 : c920 cmp #SPACE +0af9 : f0f7 beq skipsp2 +0afb : 60 Skip3 rts + ; + ;===================================================== + ; This is some debug logic which displays the current + ; value of the ILPC and the line buffer. + ; + if ILTRACE + dbgLine jsr puts + AS65 Assembler for R6502 [1.42]. Page 36 +---------------------------------- mytb.asm ---------------------------------- + + db "ILPC: ",0 + lda ILPC+1 + jsr OUTHEX + lda ILPC + jsr OUTHEX + lda #SPACE + jsr OUTCH + ldy #0 + lda (ILPC),y + jsr OUTHEX + ; + ; Display the CURPTR value and offset + ; + jsr puts + db ", CURPTR: ",0 + lda CURPTR+1 + jsr OUTHEX + lda CURPTR + jsr OUTHEX + lda #'+' + jsr OUTCH + lda CUROFF + jsr OUTHEX + ; + jmp CRLF + endif + ; + ;===================================================== + ; This function might go away eventually, but was + ; added to provide data for other pieces of code. + ; It has some ties to the operating environment that + ; will need to be customized for the target system. + ; +0afc : GetSizes + ; + ; Here is machine specific code to get the highest + ; memory location that can be used by BASIC. + ; + if ProgramStart < $2000 +0afc : a9ff lda #$ff +0afe : 8d7d0e sta HighMem ;$13ff for KIM-1 +0b01 : a913 lda #$13 +0b03 : 8d7e0e sta HighMem+1 + else + lda #$ff + sta HighMem ;$CFFF otherwise + lda #$cf + sta HighMem+1 + endif + ; + ; This computes the available memory remaining. + ; +0b06 : 38 sec +0b07 : ad7d0e lda HighMem +0b0a : ed7b0e sbc PROGRAMEND +0b0d : 8d810e sta FreeMem +0b10 : 8580 sta R0 +0b12 : ad7e0e lda HighMem+1 +0b15 : ed7c0e sbc PROGRAMEND+1 +0b18 : 8d820e sta FreeMem+1 +0b1b : 8581 sta R0+1 + ; + AS65 Assembler for R6502 [1.42]. Page 37 +---------------------------------- mytb.asm ---------------------------------- + + ; This computes the size of the current user program. + ; +0b1d : 38 sec +0b1e : ad7b0e lda PROGRAMEND +0b21 : e983 sbc #ProgramStart&$ff +0b23 : 8d7f0e sta UsedMem +0b26 : ad7c0e lda PROGRAMEND+1 +0b29 : e90e sbc #ProgramStart>>8 +0b2b : 8d800e sta UsedMem+1 + ; +0b2e : 60 rts + ; + ;===================================================== + ; Set output vector to the console output function + ; +0b2f : a906 SetOutConsole lda #OUTCH&$ff +0b31 : 8d790e sta BOutVec +0b34 : a902 lda #OUTCH/256 +0b36 : 8d7a0e sta BOutVec+1 +0b39 : 60 rts + ; + ;===================================================== + ; Jump to the output function in BOutVec + ; +0b3a : 6c790e VOUTCH jmp (BOutVec) + + + include "storage.asm" + ; + ;===================================================== + ;===================================================== + ;===================================================== + ; This file contains the functions for saving and + ; restoring programs from some sort of mass storage + ; device. This particular version is for using the + ; Corsham Tech SD Card System. + ;===================================================== + ;===================================================== + ;===================================================== + + bss +df8e = diskBufLength ds 1 +df8f = diskBufOffset ds 1 + code + + ; + ;===================================================== + ; Open a file for reading as a program. The next + ; thing on the line should be the filename. + ; +0b3d : iOPENREAD + if XKIM || CTMON65 +0b3d : a47f ldy CUROFF +0b3f : b17d lda (CURPTR),y +0b41 : d007 bne iOPENfn ;might be filename + ; + ; No filename supplied. + ; +0b43 : a900 iOPENnofn lda #0 +0b45 : a209 ldx #ERR_NO_FILENAME +0b47 : 4c5204 jmp iErr2 + ; + AS65 Assembler for R6502 [1.42]. Page 38 +---------------------------------- mytb.asm ---------------------------------- + + ; Add the offset into the buffer start + ; +0b4a : 18 iOPENfn clc +0b4b : 98 tya +0b4c : 657d adc CURPTR +0b4e : a8 tay ;LSB +0b4f : a57e lda CURPTR+1 +0b51 : 6900 adc #0 +0b53 : aa tax +0b54 : 2036f0 jsr DiskOpenRead ;attempt to open file +0b57 : 9007 bcc Ropenok ;branch if opened ok + ; + ; Open failed + ; +0b59 : a207 Rdfail ldx #ERR_READ_FAIL +0b5b : a900 Rdfail2 lda #0 +0b5d : 4c5204 jmp iErr2 + ; + ; Clear counts and offsets so the next read will + ; cause the file to be read. + ; +0b60 : a900 Ropenok lda #0 +0b62 : 8d8fdf sta diskBufOffset +0b65 : 8d8edf sta diskBufLength +0b68 : 4c7202 jmp NextIL + endif + ; + ;===================================================== +0b6b : iOPENWRITE + if XKIM || CTMON65 +0b6b : a47f ldy CUROFF +0b6d : b17d lda (CURPTR),y +0b6f : f0d2 beq iOPENnofn + ; +0b71 : 18 clc +0b72 : 98 tya +0b73 : 657d adc CURPTR +0b75 : a8 tay ;LSB +0b76 : a57e lda CURPTR+1 +0b78 : 6900 adc #0 +0b7a : aa tax +0b7b : 2039f0 jsr DiskOpenWrite ;attempt to open file +0b7e : 9007 bcc Wopenok ;branch if opened ok + ; + ; Open failed + ; +0b80 : a900 Wdfail lda #0 +0b82 : a208 ldx #ERR_WRITE_FAIL +0b84 : 4c5204 jmp iErr2 + ; +0b87 : 4c7202 Wopenok jmp NextIL + endif + ; + ;===================================================== + ; Gets a line of input from the disk file and puts it + ; into LINBUF. + ; + ; On exit: + ; CURPTR points to LINBUF + ; LINBUF contains the line with 0 at the end. + ; Y has offset to first non-space character + ; CURROFF has the same as Y. + AS65 Assembler for R6502 [1.42]. Page 39 +---------------------------------- mytb.asm ---------------------------------- + + ; +0b8a : iDGETLINE + if XKIM || CTMON65 +0b8a : a21d ldx #LINBUF&$ff +0b8c : 867d stx CURPTR +0b8e : a20e ldx #LINBUF>>8 +0b90 : 867e stx CURPTR+1 + ; +0b92 : a200 ldx #0 ;offset +0b94 : 8e6d0e iDgetLoop stx getlinx +0b97 : 20d00b jsr getNextFileByte +0b9a : b016 bcs iGetEOF +0b9c : c90d cmp #CR +0b9e : f00d beq iGetEOL +0ba0 : c90a cmp #LF +0ba2 : f009 beq iGetEOL +0ba4 : ae6d0e ldx getlinx +0ba7 : 9d1d0e sta LINBUF,x +0baa : e8 inx +0bab : d0e7 bne iDgetLoop + ; + ; Handle end of line. If the line has nothing, loop + ; back and get another line. + ; +0bad : ae6d0e iGetEOL ldx getlinx ;blank line? +0bb0 : f0e2 beq iDgetLoop ;yes, ignore it + ; + ; This can fall through when there is a line, or + ; called directly when EOF is encountered. + ; +0bb2 : ae6d0e iGetEOF ldx getlinx +0bb5 : a900 lda #0 +0bb7 : 9d1d0e sta LINBUF,x +0bba : 857f sta CUROFF +0bbc : a000 ldy #0 +0bbe : 20f30a jsr SkipSpaces +0bc1 : 4c7202 jmp NextIL + endif + ; + ;===================================================== + ; Does a LIST to a file file. + ; +0bc4 : iDLIST + if XKIM || CTMON65 +0bc4 : 20ff0b jsr SetOutDisk +0bc7 : 4c8805 jmp iLST2 + endif + ; + ;===================================================== + ; Closes any pending disk file. Okay to call if there + ; is no open file. + ; +0bca : iDCLOSE + if XKIM || CTMON65 +0bca : 2042f0 jsr DiskClose +0bcd : 4c7202 jmp NextIL + endif + ; + ;===================================================== + ; This gets the next byte from an open disk file. If + ; there are no more bytes left, this returns C set. + ; Else, C is clear and A contains the character. + AS65 Assembler for R6502 [1.42]. Page 40 +---------------------------------- mytb.asm ---------------------------------- + + ; +0bd0 : getNextFileByte + if XKIM || CTMON65 +0bd0 : ae8fdf ldx diskBufOffset +0bd3 : ec8edf cpx diskBufLength +0bd6 : d014 bne hasdata ;branch if still data + ; + ; There is no data left in the buffer, so read a + ; block from the SD system. + ; +0bd8 : a984 lda #BUFFER_SIZE +0bda : a2df ldx #buffer>>8 +0bdc : a00a ldy #buffer&$ff +0bde : 203cf0 jsr DiskRead +0be1 : b012 bcs getNextEof + ; + ; A contains the number of bytes actually read. + ; +0be3 : 8d8edf sta diskBufLength ;save length +0be6 : c900 cmp #0 ;shouldn't happen +0be8 : f00b beq getNextEof + ; +0bea : a200 ldx #0 +0bec : bd0adf hasdata lda buffer,x +0bef : e8 inx +0bf0 : 8e8fdf stx diskBufOffset +0bf3 : 18 clc +0bf4 : 60 rts + ; +0bf5 : a900 getNextEof lda #0 +0bf7 : 8d8fdf sta diskBufOffset +0bfa : 8d8edf sta diskBufLength +0bfd : 38 sec +0bfe : 60 rts + ; + ;===================================================== + ; Set output vector to the disk output function + ; +0bff : a90a SetOutDisk lda #DOUT&$ff +0c01 : 8d790e sta BOutVec +0c04 : a90c lda #DOUT/256 +0c06 : 8d7a0e sta BOutVec+1 +0c09 : 60 rts + ; + ;===================================================== + +0c0a : 8d0adf DOUT sta buffer +0c0d : a901 lda #1 +0c0f : a00a ldy #buffer&$ff +0c11 : a2df ldx #buffer/256 +0c13 : 203ff0 jsr DiskWrite + ; + ; need error checking here + ; +0c16 : 60 rts + endif + + + + include "IL.inc" + nolist + + AS65 Assembler for R6502 [1.42]. Page 41 +---------------------------------- mytb.asm ---------------------------------- + + ; + if FIXED + org $1000 + endif + include "basic.il" + ; + ;===================================================== + ;===================================================== + ;===================================================== + ; This is the IL of the BASIC (or whatever) language. + ; Because of the way macros are implemented by as65, + ; labels can't be on the same line as a macro + ; invocation, so that's why labels are on separate + ; lines. + ; +0c17 = IL equ * + + ;THE IL CONTROL SECTION + +0c17 : START: + INIT ;INITIALIZE +0c17 : 16 > db 22 + + NLINE ;WRITE CRLF +0c18 : 05 > db 5 + + ERRGOTO CO ;where to go after an error +0c19 : 1f > db 31 +0c1a : 1d0c > dw CO + + VINIT ;clear all variables +0c1c : 1e > db 30 + + ; + ; This is where we jump to get a line of commands or + ; a program from the user. + ; +0c1d : CO: + GETLINE ;WRITE PROMPT AND GET LINE +0c1d : 17 > db 23 + + TSTL XEC ;TEST FOR LINE NUMBER +0c1e : 22 > db 34 +0c1f : 04 > db (XEC -*)-1 + + INSERT ;INSERT IT (MAY BE DELETE) +0c20 : 18 > db 24 + + JMP CO +0c21 : 1d > db 29 +0c22 : 1d0c > dw CO + +0c24 : XEC: + XINIT ;INITIALIZE +0c24 : 00 > db 0 + + + ;STATEMENT EXECUTOR + +0c25 : STMT: + TST S1,"LET" ;IS STATEMENT A LET +0c25 : 20 > db 32 + AS65 Assembler for R6502 [1.42]. Page 42 +---------------------------------- mytb.asm ---------------------------------- + +0c26 : 15 > db (S1-*)-1 +0c27 : 4c455400 > db "LET" ,0 + + TSTV ERRVEC ;YES, PLACE VAR ADDRESS ON AESTK +0c2b : 21 > db 33 +0c2c : 4e > db (ERRVEC -*)-1 + + TST ERRVEC,"=" ;(This line originally omitted) +0c2d : 20 > db 32 +0c2e : 4c > db (ERRVEC-*)-1 +0c2f : 3d00 > db "=" ,0 + + CALL EXPR ;PLACE EXPR VALUE ON AESTK +0c31 : 1c > db 28 +0c32 : 2c0d > dw EXPR + + DONE ;REPORT ERROR IF NOT NEXT +0c34 : 01 > db 1 + + STORE ;STORE RESULT +0c35 : 13 > db 19 + + NXT CO ;AND SEQUENCE TO NEXT +0c36 : 06 > db 6 +0c37 : 1d0c > dw CO + + JMP STMT +0c39 : 1d > db 29 +0c3a : 250c > dw STMT + +0c3c : S1: + TST S3,"GO" ;GOTO OT GOSUB? +0c3c : 20 > db 32 +0c3d : 19 > db (S3-*)-1 +0c3e : 474f00 > db "GO" ,0 + + TST S2,"TO" ;YES...TO, OR...SUB +0c41 : 20 > db 32 +0c42 : 08 > db (S2-*)-1 +0c43 : 544f00 > db "TO" ,0 + + CALL EXPR ;GET LABEL +0c46 : 1c > db 28 +0c47 : 2c0d > dw EXPR + + DONE ;ERROR IF CR NOT NEXT +0c49 : 01 > db 1 + + XFER ;SET UP AND JUMP +0c4a : 07 > db 7 + +0c4b : S2: + TST ERRVEC,"SUB" ;ERROR IF NO MATCH +0c4b : 20 > db 32 +0c4c : 2e > db (ERRVEC-*)-1 +0c4d : 53554200 > db "SUB" ,0 + + CALL EXPR ;GET DESTINATION +0c51 : 1c > db 28 +0c52 : 2c0d > dw EXPR + + DONE ;ERROR IF CR NOT NEXT + AS65 Assembler for R6502 [1.42]. Page 43 +---------------------------------- mytb.asm ---------------------------------- + +0c54 : 01 > db 1 + + SAV ;SAVE RETURN LINE +0c55 : 08 > db 8 + + XFER ;AND JUMP +0c56 : 07 > db 7 + +0c57 : S3: + TST S8,"PRINT" ;PRINT +0c57 : 20 > db 32 +0c58 : 2c > db (S8-*)-1 +0c59 : 5052494e5400 > db "PRINT" ,0 + +0c5f : S4: + TST S7,QUOTE ;TEST FOR QUOTE +0c5f : 20 > db 32 +0c60 : 1d > db (S7-*)-1 +0c61 : 2200 > db QUOTE ,0 + + PRS ;PRINT STRING +0c63 : 02 > db 2 + +0c64 : S5: + TST S6A,COMMA ;IS THERE MORE? +0c64 : 20 > db 32 +0c65 : 06 > db (S6A-*)-1 +0c66 : 2c00 > db COMMA ,0 + + SPC ;SPACE TO NEXT ZONE +0c68 : 04 > db 4 + + JMP S4 ;YES JUMP BACK +0c69 : 1d > db 29 +0c6a : 5f0c > dw S4 + + ; + ; If a semicolon, don't do anything. + ; +0c6c : S6A: + TST S6,SEMICOLON +0c6c : 20 > db 32 +0c6d : 05 > db (S6-*)-1 +0c6e : 3b00 > db SEMICOLON,0 + + JMP S4 +0c70 : 1d > db 29 +0c71 : 5f0c > dw S4 + +0c73 : S6: + DONE ;ERROR IF CR NOT NEXT +0c73 : 01 > db 1 + + NLINE +0c74 : 05 > db 5 + + NXT CO +0c75 : 06 > db 6 +0c76 : 1d0c > dw CO + + JMP STMT +0c78 : 1d > db 29 + AS65 Assembler for R6502 [1.42]. Page 44 +---------------------------------- mytb.asm ---------------------------------- + +0c79 : 250c > dw STMT + + ; + ; A jump for code too far away for relative branch + ; +0c7b : ERRVEC: + JMP UNKNOWN +0c7b : 1d > db 29 +0c7c : 290d > dw UNKNOWN + + ; +0c7e : S7: + CALL EXPR +0c7e : 1c > db 28 +0c7f : 2c0d > dw EXPR + + PRN ;PRINT IT +0c81 : 03 > db 3 + + JMP S5 ;IS THERE MORE? +0c82 : 1d > db 29 +0c83 : 640c > dw S5 + +0c85 : S8: + TST S9,"IF" ;IF STATEMENT +0c85 : 20 > db 32 +0c86 : 17 > db (S9-*)-1 +0c87 : 494600 > db "IF" ,0 + + CALL EXPR ;GET EXPRESSION +0c8a : 1c > db 28 +0c8b : 2c0d > dw EXPR + + CALL RELOP ;DETERMINE OPR AND PUT ON STK +0c8d : 1c > db 28 +0c8e : b20d > dw RELOP + + CALL EXPR ;GET EXPRESSION +0c90 : 1c > db 28 +0c91 : 2c0d > dw EXPR + + TST UNKNOWN,"THEN" ;(This line originally omitted) +0c93 : 20 > db 32 +0c94 : 94 > db (UNKNOWN-*)-1 +0c95 : 5448454e00 > db "THEN" ,0 + + CMPR ;PERFORM COMPARISON -- PERFORMS NXT IF FALSE +0c9a : 0a > db 10 + + JMP STMT +0c9b : 1d > db 29 +0c9c : 250c > dw STMT + +0c9e : S9: + TST S12,"INPUT" ;INPUT STATEMENT +0c9e : 20 > db 32 +0c9f : 18 > db (S12-*)-1 +0ca0 : 494e50555400 > db "INPUT" ,0 + +0ca6 : S10: + TSTV UNKNOWN ;GET VAR ADDRESS (Originally CALL VAR = +0ca6 : 21 > db 33 + AS65 Assembler for R6502 [1.42]. Page 45 +---------------------------------- mytb.asm ---------------------------------- + +0ca7 : 81 > db (UNKNOWN -*)-1 + + INNUM ;MOVE NUMBER FROM TTY TO AESTK +0ca8 : 0b > db 11 + + STORE ;STORE IT +0ca9 : 13 > db 19 + + TST S11,COMMA ;IS THERE MORE? +0caa : 20 > db 32 +0cab : 05 > db (S11-*)-1 +0cac : 2c00 > db COMMA ,0 + + JMP S10 ;YES +0cae : 1d > db 29 +0caf : a60c > dw S10 + + +0cb1 : S11: + DONE ;MUST BE CR +0cb1 : 01 > db 1 + + NXT CO ;SEQUENCE TO NEXT +0cb2 : 06 > db 6 +0cb3 : 1d0c > dw CO + + JMP STMT +0cb5 : 1d > db 29 +0cb6 : 250c > dw STMT + +0cb8 : S12: + TST S13,"RETURN" ;RETURN STATEMENT +0cb8 : 20 > db 32 +0cb9 : 0f > db (S13-*)-1 +0cba : 52455455524e00 > db "RETURN" ,0 + + DONE ;MUST BE CR +0cc1 : 01 > db 1 + + RSTR ;RESTORE LINE NUMBER OF CALL +0cc2 : 09 > db 9 + + NXT CO ;SEQUENCE TO NEXT STATEMENT +0cc3 : 06 > db 6 +0cc4 : 1d0c > dw CO + + JMP STMT +0cc6 : 1d > db 29 +0cc7 : 250c > dw STMT + +0cc9 : S13: + TST S14,"END" +0cc9 : 20 > db 32 +0cca : 05 > db (S14-*)-1 +0ccb : 454e4400 > db "END",0 + + FIN +0ccf : 0c > db 12 + +0cd0 : S14: + TST S15,"LIST" ;LIST COMMAND +0cd0 : 20 > db 32 + AS65 Assembler for R6502 [1.42]. Page 46 +---------------------------------- mytb.asm ---------------------------------- + +0cd1 : 0a > db (S15-*)-1 +0cd2 : 4c49535400 > db "LIST" ,0 + + DONE +0cd7 : 01 > db 1 + + LST +0cd8 : 15 > db 21 + + JMP CO +0cd9 : 1d > db 29 +0cda : 1d0c > dw CO + +0cdc : S15: + TST S16,"RUN" ;RUN COMMAND +0cdc : 20 > db 32 +0cdd : 0d > db (S16-*)-1 +0cde : 52554e00 > db "RUN" ,0 + + DONE +0ce2 : 01 > db 1 + + VINIT ;clear variables +0ce3 : 1e > db 30 + + LIT 1 ;GOTO line 1 +0ce4 : 1b > db 27 +0ce5 : 0100 > dw 1 + + XFER ;Bob's addition +0ce7 : 07 > db 7 + + ; EXIT + JMP STMT ;and run! +0ce8 : 1d > db 29 +0ce9 : 250c > dw STMT + +0ceb : S16: + TST S17A,"NEW" ;clear program +0ceb : 20 > db 32 +0cec : 08 > db (S17A-*)-1 +0ced : 4e455700 > db "NEW" ,0 + + DONE +0cf1 : 01 > db 1 + + JMP START +0cf2 : 1d > db 29 +0cf3 : 170c > dw START + + +0cf5 : S17A: + TST S17,"EXIT" ;allow them to exit BASIC +0cf5 : 20 > db 32 +0cf6 : 06 > db (S17-*)-1 +0cf7 : 4558495400 > db "EXIT" ,0 + + EXIT +0cfc : 1a > db 26 + + +0cfd : S17: + AS65 Assembler for R6502 [1.42]. Page 47 +---------------------------------- mytb.asm ---------------------------------- + + TST S17B,"REM" ;REMark. Skip rest of line +0cfd : 20 > db 32 +0cfe : 0a > db (S17B-*)-1 +0cff : 52454d00 > db "REM" ,0 + + NXT CO +0d03 : 06 > db 6 +0d04 : 1d0c > dw CO + + JMP STMT +0d06 : 1d > db 29 +0d07 : 250c > dw STMT + + ; + ; Commands related to saving/restoring programs + ; to/from mass storage. + ; +0d09 : S17B: + if XKIM || CTMON65 + TST S17C,"SAVE" +0d09 : 20 > db 32 +0d0a : 0b > db (S17C-*)-1 +0d0b : 5341564500 > db "SAVE",0 + + OPENWRITE +0d10 : 28 > db 40 + + DLIST +0d11 : 2b > db 43 + + DCLOSE +0d12 : 29 > db 41 + + JMP CO +0d13 : 1d > db 29 +0d14 : 1d0c > dw CO + + +0d16 : S17C: + TST UNKNOWN,"LOAD" +0d16 : 20 > db 32 +0d17 : 11 > db (UNKNOWN-*)-1 +0d18 : 4c4f414400 > db "LOAD",0 + + OPENREAD +0d1d : 27 > db 39 + +0d1e : S17CLP: + DGETLINE ;get line from file +0d1e : 2a > db 42 + + TSTL S17EOL ;no line num means EOL +0d1f : 22 > db 34 +0d20 : 04 > db (S17EOL -*)-1 + + INSERT ;put it into the program +0d21 : 18 > db 24 + + JMP S17CLP ;keep going +0d22 : 1d > db 29 +0d23 : 1e0d > dw S17CLP + + AS65 Assembler for R6502 [1.42]. Page 48 +---------------------------------- mytb.asm ---------------------------------- + +0d25 : S17EOL + DCLOSE ;close disk file +0d25 : 29 > db 41 + + JMP CO ;back to start +0d26 : 1d > db 29 +0d27 : 1d0c > dw CO + + endif + ; + ; Else, unknown command. + ; +0d29 : UNKNOWN: + ERR ERR_SYNTAX ;SYNTAX ERROR +0d29 : 0d > db 13 +0d2a : 0500 > dw ERR_SYNTAX + + + ;----------------------------------------------------- +0d2c : EXPR: + TST E0,"-" +0d2c : 20 > db 32 +0d2d : 09 > db (E0-*)-1 +0d2e : 2d00 > db "-",0 + + CALL TERM ;TEST FOR UNARY -. +0d30 : 1c > db 28 +0d31 : 550d > dw TERM + + NEG ;GET VALUE +0d33 : 10 > db 16 + + JMP E1 ;NEGATE IT +0d34 : 1d > db 29 +0d35 : 3e0d > dw E1 + +0d37 : E0: + TST E1A,"+" ;LOOK FOR MORE +0d37 : 20 > db 32 +0d38 : 02 > db (E1A-*)-1 +0d39 : 2b00 > db "+" ,0 + +0d3b : E1A: + CALL TERM ;TEST FOR UNARY + +0d3b : 1c > db 28 +0d3c : 550d > dw TERM + +0d3e : E1: + TST E2,"+" ;LEADING TERM +0d3e : 20 > db 32 +0d3f : 09 > db (E2-*)-1 +0d40 : 2b00 > db "+" ,0 + + CALL TERM +0d42 : 1c > db 28 +0d43 : 550d > dw TERM + + ADD +0d45 : 0e > db 14 + + JMP E1 +0d46 : 1d > db 29 + AS65 Assembler for R6502 [1.42]. Page 49 +---------------------------------- mytb.asm ---------------------------------- + +0d47 : 3e0d > dw E1 + +0d49 : E2: + TST E3,"-" ;ANY MORE? +0d49 : 20 > db 32 +0d4a : 09 > db (E3-*)-1 +0d4b : 2d00 > db "-" ,0 + + CALL TERM ;DIFFERENCE TERM +0d4d : 1c > db 28 +0d4e : 550d > dw TERM + + SUB +0d50 : 0f > db 15 + + JMP E1 +0d51 : 1d > db 29 +0d52 : 3e0d > dw E1 + +0d54 : E3: +0d54 : T2: + RTN ;ANY MORE? +0d54 : 19 > db 25 + +0d55 : TERM: + CALL FACT +0d55 : 1c > db 28 +0d56 : 710d > dw FACT + +0d58 : T0: + TST T1,"*" +0d58 : 20 > db 32 +0d59 : 09 > db (T1-*)-1 +0d5a : 2a00 > db "*",0 + + CALL FACT ;PRODUCT FACTOR. +0d5c : 1c > db 28 +0d5d : 710d > dw FACT + + MUL +0d5f : 11 > db 17 + + JMP T0 +0d60 : 1d > db 29 +0d61 : 580d > dw T0 + +0d63 : T1: + TST T2,"/" +0d63 : 20 > db 32 +0d64 : ef > db (T2-*)-1 +0d65 : 2f00 > db "/",0 + + CALL FACT ;QUOTIENT FACTOR. +0d67 : 1c > db 28 +0d68 : 710d > dw FACT + + DIV +0d6a : 12 > db 18 + + JMP T0 +0d6b : 1d > db 29 +0d6c : 580d > dw T0 + AS65 Assembler for R6502 [1.42]. Page 50 +---------------------------------- mytb.asm ---------------------------------- + + + +0d6e : UNKNOWNVEC: + JMP UNKNOWN +0d6e : 1d > db 29 +0d6f : 290d > dw UNKNOWN + + + + + ; + ; Factor an expression. Always test for functions + ; first or else they'll be confused for variables. + ; +0d71 : FACT: + TST F2A,"FREE()" +0d71 : 20 > db 32 +0d72 : 09 > db (F2A-*)-1 +0d73 : 46524545282900 > db "FREE()",0 + + FREE +0d7a : 24 > db 36 + + RTN +0d7b : 19 > db 25 + + +0d7c : F2A: + TST F2B,"RND(" +0d7c : 20 > db 32 +0d7d : 0e > db (F2B-*)-1 +0d7e : 524e442800 > db "RND(",0 + + CALL FACT ;GET RANGE +0d83 : 1c > db 28 +0d84 : 710d > dw FACT + + TST UNKNOWN,")" +0d86 : 20 > db 32 +0d87 : a1 > db (UNKNOWN-*)-1 +0d88 : 2900 > db ")",0 + + RANDOM +0d8a : 25 > db 37 + + RTN +0d8b : 19 > db 25 + + +0d8c : F2B: + TST F2C,"ABS(" +0d8c : 20 > db 32 +0d8d : 0e > db (F2C-*)-1 +0d8e : 4142532800 > db "ABS(",0 + + CALL FACT ;get value +0d93 : 1c > db 28 +0d94 : 710d > dw FACT + + TST UNKNOWN,")" +0d96 : 20 > db 32 +0d97 : 91 > db (UNKNOWN-*)-1 + AS65 Assembler for R6502 [1.42]. Page 51 +---------------------------------- mytb.asm ---------------------------------- + +0d98 : 2900 > db ")",0 + + ABS +0d9a : 26 > db 38 + + RTN +0d9b : 19 > db 25 + + +0d9c : F2C: + TSTV F0 +0d9c : 21 > db 33 +0d9d : 02 > db (F0-*)-1 + + IND ;YES, GET THE VALUE. +0d9e : 14 > db 20 + + RTN +0d9f : 19 > db 25 + +0da0 : F0: + TSTN F1 ;NUMBER, GET ITS VALUE. +0da0 : 23 > db 35 +0da1 : 01 > db (F1 -*)-1 + + RTN +0da2 : 19 > db 25 + +0da3 : F1: + TST F2A,"(" ;PARENTHESIZED EXPR. +0da3 : 20 > db 32 +0da4 : d7 > db (F2A-*)-1 +0da5 : 2800 > db "(" ,0 + + CALL EXPR +0da7 : 1c > db 28 +0da8 : 2c0d > dw EXPR + + TST F2,")" +0daa : 20 > db 32 +0dab : 03 > db (F2-*)-1 +0dac : 2900 > db ")",0 + + RTN +0dae : 19 > db 25 + + +0daf : F2: + ERR ERR_SYNTAX ;ERROR. +0daf : 0d > db 13 +0db0 : 0500 > dw ERR_SYNTAX + + +0db2 : RELOP: + TST iR0,"=" +0db2 : 20 > db 32 +0db3 : 06 > db (iR0-*)-1 +0db4 : 3d00 > db "=",0 + + LIT 2 ;= +0db6 : 1b > db 27 +0db7 : 0200 > dw 2 + AS65 Assembler for R6502 [1.42]. Page 52 +---------------------------------- mytb.asm ---------------------------------- + + + RTN +0db9 : 19 > db 25 + +0dba : iR0: + TST R4,"<" +0dba : 20 > db 32 +0dbb : 16 > db (R4-*)-1 +0dbc : 3c00 > db "<",0 + + TST iR1,"=" +0dbe : 20 > db 32 +0dbf : 06 > db (iR1-*)-1 +0dc0 : 3d00 > db "=",0 + + LIT 3 ;<= +0dc2 : 1b > db 27 +0dc3 : 0300 > dw 3 + + RTN +0dc5 : 19 > db 25 + +0dc6 : iR1: + TST R3,">" +0dc6 : 20 > db 32 +0dc7 : 06 > db (R3-*)-1 +0dc8 : 3e00 > db ">",0 + + LIT 5 ;<> +0dca : 1b > db 27 +0dcb : 0500 > dw 5 + + RTN +0dcd : 19 > db 25 + +0dce : R3: + LIT 1 ;< +0dce : 1b > db 27 +0dcf : 0100 > dw 1 + + RTN +0dd1 : 19 > db 25 + +0dd2 : R4: + TST UNKNOWNVEC,">" +0dd2 : 20 > db 32 +0dd3 : 9a > db (UNKNOWNVEC-*)-1 +0dd4 : 3e00 > db ">",0 + + TST R5,"=" +0dd6 : 20 > db 32 +0dd7 : 06 > db (R5-*)-1 +0dd8 : 3d00 > db "=",0 + + LIT 6 ;>= +0dda : 1b > db 27 +0ddb : 0600 > dw 6 + + RTN +0ddd : 19 > db 25 + +0dde : R5: + AS65 Assembler for R6502 [1.42]. Page 53 +---------------------------------- mytb.asm ---------------------------------- + + TST R6,"<" +0dde : 20 > db 32 +0ddf : 06 > db (R6-*)-1 +0de0 : 3c00 > db "<",0 + + LIT 1 +0de2 : 1b > db 27 +0de3 : 0100 > dw 1 + + RTN ;(This line originally omitted) +0de5 : 19 > db 25 + +0de6 : R6: + LIT 4 ;>??? +0de6 : 1b > db 27 +0de7 : 0400 > dw 4 + + RTN +0de9 : 19 > db 25 + + +0dea = ILEND equ * + +0dea = PROGEND equ * + + ;===================================================== + ;===================================================== + ;===================================================== + ; These are storage items not in page zero. + ; + bss +0dea = org PROGEND +0dea = mathStack ds STACKSIZE*2 +0dfa = mathStackPtr ds 1 +0dfb = retStack ds STACKSIZE*2 +0e0b = retStackPtr ds 1 +0e0c = callStack ds STACKSIZE*2 +0e1c = callStackPtr ds 1 +0e1d = LINBUF ds 80 +0e6d = getlinx ds 1 +0e6e = printtx ds 1 ;temp X for print funcs +0e6f = diddigit ds 1 ;for leading zero suppression +0e70 = putsy ds 1 +0e71 = errGoto ds 2 ;where to set ILPC on err +0e73 = MQ ds 2 ;used for some math +0e75 = sign ds 1 ;0 = positive, else negative +0e76 = rtemp1 ds 1 +0e77 = random ds 2 +0e79 = BOutVec ds 2 + ; + ; PROGRAMEND is the end of the user's BASIC program. + ; More precisely, it is one byte past the end. Or, + ; it's where the next line added to the end will be + ; placed. + ; +0e7b = PROGRAMEND ds 2 +0e7d = HighMem ds 2 ;highest location +0e7f = UsedMem ds 2 ;size of user program +0e81 = FreeMem ds 2 ;amount of free memory + ; + ;===================================================== + ; This is the start of the user's BASIC program space. + AS65 Assembler for R6502 [1.42]. Page 54 +---------------------------------- mytb.asm ---------------------------------- + + ; + ; PERSONAL GOAL: This should be no larger than $0DFF. + ; 0200-05FF = 1K + ; 0200-09FF = 2K + ; 0200-0DFF = 3K + ; 0200-11FF = 4K + ; 0200-13FF = 4.5K + ; + if FIXED + org $2000 + endif +0e83 = ProgramStart equ * + ; + if CTMON65 || XKIM + code +df04 = org AutoRun +df04 : 0002 dw cold + endif + ; + end + + +No errors in pass 2. diff --git a/storage.asm b/storage.asm new file mode 100644 index 0000000..14b93e6 --- /dev/null +++ b/storage.asm @@ -0,0 +1,216 @@ +; +;===================================================== +;===================================================== +;===================================================== +; This file contains the functions for saving and +; restoring programs from some sort of mass storage +; device. This particular version is for using the +; Corsham Tech SD Card System. +;===================================================== +;===================================================== +;===================================================== + + bss +diskBufLength ds 1 +diskBufOffset ds 1 + code + +; +;===================================================== +; Open a file for reading as a program. The next +; thing on the line should be the filename. +; +iOPENREAD + if XKIM || CTMON65 + ldy CUROFF + lda (CURPTR),y + bne iOPENfn ;might be filename +; +; No filename supplied. +; +iOPENnofn lda #0 + ldx #ERR_NO_FILENAME + jmp iErr2 +; +; Add the offset into the buffer start +; +iOPENfn clc + tya + adc CURPTR + tay ;LSB + lda CURPTR+1 + adc #0 + tax + jsr DiskOpenRead ;attempt to open file + bcc Ropenok ;branch if opened ok +; +; Open failed +; +Rdfail ldx #ERR_READ_FAIL +Rdfail2 lda #0 + jmp iErr2 +; +; Clear counts and offsets so the next read will +; cause the file to be read. +; +Ropenok lda #0 + sta diskBufOffset + sta diskBufLength + jmp NextIL + endif +; +;===================================================== +iOPENWRITE + if XKIM || CTMON65 + ldy CUROFF + lda (CURPTR),y + beq iOPENnofn +; + clc + tya + adc CURPTR + tay ;LSB + lda CURPTR+1 + adc #0 + tax + jsr DiskOpenWrite ;attempt to open file + bcc Wopenok ;branch if opened ok +; +; Open failed +; +Wdfail lda #0 + ldx #ERR_WRITE_FAIL + jmp iErr2 +; +Wopenok jmp NextIL + endif +; +;===================================================== +; Gets a line of input from the disk file and puts it +; into LINBUF. +; +; On exit: +; CURPTR points to LINBUF +; LINBUF contains the line with 0 at the end. +; Y has offset to first non-space character +; CURROFF has the same as Y. +; +iDGETLINE + if XKIM || CTMON65 + ldx #LINBUF&$ff + stx CURPTR + ldx #LINBUF>>8 + stx CURPTR+1 +; + ldx #0 ;offset +iDgetLoop stx getlinx + jsr getNextFileByte + bcs iGetEOF + cmp #CR + beq iGetEOL + cmp #LF + beq iGetEOL + ldx getlinx + sta LINBUF,x + inx + bne iDgetLoop +; +; Handle end of line. If the line has nothing, loop +; back and get another line. +; +iGetEOL ldx getlinx ;blank line? + beq iDgetLoop ;yes, ignore it +; +; This can fall through when there is a line, or +; called directly when EOF is encountered. +; +iGetEOF ldx getlinx + lda #0 + sta LINBUF,x + sta CUROFF + ldy #0 + jsr SkipSpaces + jmp NextIL + endif +; +;===================================================== +; Does a LIST to a file file. +; +iDLIST + if XKIM || CTMON65 + jsr SetOutDisk + jmp iLST2 + endif +; +;===================================================== +; Closes any pending disk file. Okay to call if there +; is no open file. +; +iDCLOSE + if XKIM || CTMON65 + jsr DiskClose + jmp NextIL + endif +; +;===================================================== +; This gets the next byte from an open disk file. If +; there are no more bytes left, this returns C set. +; Else, C is clear and A contains the character. +; +getNextFileByte + if XKIM || CTMON65 + ldx diskBufOffset + cpx diskBufLength + bne hasdata ;branch if still data +; +; There is no data left in the buffer, so read a +; block from the SD system. +; + lda #BUFFER_SIZE + ldx #buffer>>8 + ldy #buffer&$ff + jsr DiskRead + bcs getNextEof +; +; A contains the number of bytes actually read. +; + sta diskBufLength ;save length + cmp #0 ;shouldn't happen + beq getNextEof +; + ldx #0 +hasdata lda buffer,x + inx + stx diskBufOffset + clc + rts +; +getNextEof lda #0 + sta diskBufOffset + sta diskBufLength + sec + rts +; +;===================================================== +; Set output vector to the disk output function +; +SetOutDisk lda #DOUT&$ff + sta BOutVec + lda #DOUT/256 + sta BOutVec+1 + rts +; +;===================================================== + +DOUT sta buffer + lda #1 + ldy #buffer&$ff + ldx #buffer/256 + jsr DiskWrite +; +; need error checking here +; + rts + endif + + diff --git a/support.asm b/support.asm index cc0d2aa..c6ce45e 100644 --- a/support.asm +++ b/support.asm @@ -190,7 +190,7 @@ PrintDecimal lda R0+1 ;MSB has sign ; then add one. ; lda #'-' - jsr OUTCH ;print the negative sign + jsr VOUTCH ;print the negative sign ; lda R0 ;invert bits eor #$ff @@ -238,7 +238,7 @@ pploop2 lda R0 ;LSB pprintit tya ora #'0' sta diddigit - jsr OUTCH + jsr VOUTCH pprintno ldx printtx ; ; Move to the next table entry @@ -253,7 +253,7 @@ pprintno ldx printtx ; lda R0 ora #'0' - jmp OUTCH + jmp VOUTCH ; ; Finish doing the subtraction. ; @@ -376,6 +376,7 @@ getDone2 ; Thanks to Ross Archer for this code. ; http://www.6502.org/source/io/primm.htm ; + if KIM puts sty putsy pla ;low part of "return" address ;(data start address) @@ -399,6 +400,7 @@ psix1 inc dpl inc dpl+1 ;account for page crossing psix2 ldy putsy jmp (dpl) ;return to byte following NULL + endif ; ;===================================================== ; Gets a line of input into LINBUF. @@ -431,6 +433,11 @@ GetLinePr pla ;restore getlinenp ldx #0 ;offset into LINBUF getline1 stx getlinx jsr GETCH + if CTMON65 + pha + jsr cout + pla + endif cmp #CR beq getlind ;end of line cmp #BS ;backspace? @@ -750,3 +757,18 @@ GetSizes sta UsedMem+1 ; rts +; +;===================================================== +; Set output vector to the console output function +; +SetOutConsole lda #OUTCH&$ff + sta BOutVec + lda #OUTCH/256 + sta BOutVec+1 + rts +; +;===================================================== +; Jump to the output function in BOutVec +; +VOUTCH jmp (BOutVec) +