10 REM > Atom65/src
   20 REM Source for Atom/System kernel for 65Tube Tube Emulator
   30 :
   40 IF PAGE>&8000:SYS "OS_GetEnv"TOA$:IFLEFT$(A$,5)<>"B6502":OSCLI"B6502"+MID$(A$,INSTR(A$," "))
   50 ON ERROR REPORT:PRINT" at line ";ERL:END
   60 :
   70 fname$="Kernel65"
   80 load%=&F800:DIM mcode% &900
   90 :
  100 nmiv =&200:brkv =&202:irq1v=&204:cliv =&206
  110 wrchv=&208:rdchv=&20A:loadv=&20C:savev=&20E
  120 rdarv=&210:starv=&212:bgetv=&214:bputv=&216
  130 findv=&218:shutv=&21A:EVNTV=&220
  140 IOADDR=&FEE0
  150 IOTUBE=&FEF8
  160 REM   &0E21 - keypress, b7=1 - nothing pressed, 27=Escape pressed
  170 REM   &B001 - key matrix, b5=0 - Escape pressed
  180 :
  190 ERRBUF=&236:INPBUF=&236
  200 :
  210 REM Memory addresses:
  220 REM &EC/D =>address to enter on MOS startup
  230 REM &EE/F = PROG   - Current program
  240 REM &F0/1 = NUM    - hex accumulator
  250 REM &F2/3 = MEMTOP - top of memory
  260 REM &F4/5 = address of byte transfer address, NMIAddr or ADDR
  270 REM &F6/7 = ADDR   - Data transfer address
  280 REM &F8/9 = String pointer, OSWORD control block
  290 REM &FA/B = CTRL   - OSFILE, OSGBPB control block, PrText string pointer
  300 REM &FC   = IRQ A store
  310 REM &FD/E => last error
  320 REM &FF   = Escape flag
  330 :
  340 REM &0236 = command input buffer
  350 REM &2EE  = OSFILE control block
  360 :
  370 FOR P=0TO1
  380   P%=load%:O%=mcode%
  390   [OPT P*3+4+16
  400   \ &EC/D=>address to enter on MOS startup
  410   \ &EE/F=>current program
  420   \ &F0/1=>membot, if &F0<>0, membot=0000, memtop=0000
  430   \ &F2/3=>command string
  440   \ &F4/5=>memtop
  450   \ &F6/7= readhex accumulator, ";params" pointer
  460   \ &F8/9=>control block
  470   \ &FA/B=>String to print with PrString
  480   \ &FC  = IRQ A store
  490   \ &FD/E=>last error
  500   \ &FF  = escape flag
  510   \ &0236= command input buffer
  520   \ &02EE= OSFILE control block
  530   \ &03xx= bit16-bit23 of Turbo65 (zp),Y addresses
  540   \ &03F3= b16-b23 of (&F2),Y command string pointer
  550   \ &03F5= b16-b23 of (&F4),Y memtop pointer
  560   \ &03F9= b16-b23 of (&F8),Y control block pointer
  570   \ &03FB= b16-b23 of (&FA),Y string pointer
  580   \ &03FE= b16-b23 of (&FD),Y error pointer
  590   
  600   \ Emulator opcodes
  610   \ &03 - OSCLI
  620   \ &13 - OSBYTE
  630   \ &23 - OSWORD
  640   \ &33 - OSWRCH
  650   \ &43 - OSRDCH
  660   \ &53 - OSFILE
  670   \ &63 - OSARGS
  680   \ &73 - OSBGET
  690   \ &83 - OSBPUT
  700   \ &93 - OSGBPB
  710   \ &A3 - OSFIND
  720   \ &B3 - Called by *QUIT
  730   \ &C3 - Called by *BASIC and OSBYTE 142
  740   \ &D3
  750   \ &E3
  760   \ &F3
  770   
  780   \ OSBYTE &A3,&F3
  790   \ Y=4 - RESET, *OS, NMIHandler. Request code to enter
  800   \ Y=6 - RESET occured, request command string to execute
  810   
  820   
  830   \ *OS - Enter command prompt
  840   \ ==========================
  850   .CmdOS
  860   JSR ErrorInit:JSR OSNEWL   :\ Point brkv to ErrorHandler
  870   JSR HelpBanner:JSR OSNEWL  :\ Display Emulator banner
  880   LDY #&04:JSR OSByteA3      :\ Ask host something
  890   TYA:BNE JumpToCode         :\ If Y<>0, enter code at XY
  900   \LDA (&EC),Y               :\ Look for a entry point at &EC/D
  910   \CMP #&20:\BNE CmdOSLoop:\TYA
  920   LDX &EC:LDY &ED:STA &ED
  930   BNE JumpToCode
  940   
  950   .CmdOSLoop
  960   JSR PrText
  970   EQUS "SYSTEM>* ":NOP       :\ Display prompt
  980   LDX #LF84A AND 255
  990   LDY #LF84A DIV 256
 1000   LDA #&00:JSR XOSWORD       :\ Read line to INPBUF
 1010   BCS CmdOSEscape
 1020   LDX #INPBUF AND 255
 1030   LDY #INPBUF DIV 256        :\ Execute command
 1040   JSR XOS_CLI:JMP CmdOSLoop  :\  and loop back for another
 1050   .CmdOSEscape
 1060   LDA #&7E:JSR XOSBYTE       :\ Ack. escape
 1070   BRK:EQUB 17:EQUS "Escape":BRK
 1080   
 1090   \ *BASIC
 1100   \ ======
 1110   .CmdBASIC
 1120   EQUB &C3                      :\ Pass to host
 1130   
 1140   \ NMI Handler
 1150   \ ===========
 1160   .NMIHandler
 1170   LDY #&04:JSR OSByteA3         :\ Ask host something
 1180   TYA:BEQ CmdOS                 :\ If Y=0, enter command prompt
 1190   .JumpToCode
 1200   JMP EnterCodeXY               :\ Y<>0, enter code at XY
 1210   
 1220   .LF84A
 1230   EQUW &0236 :\ Input buffer at &0236
 1240   EQUB &B7   :\ Max. &B7 characters
 1250   EQUB &20   :\ Minimum character
 1260   EQUB &FF   :\ Maximum character
 1270   
 1280   .RESET
 1290   LDX #&FF:TXS                  :\ Clear stack
 1300   JSR LF87F                     :\ Reset vectors and set memory limits
 1310   LDY #&06:JSR OSByteA3         :\ Ask host something
 1320   TYA:BNE OscliXY               :\ If Y<>0, execute command at XY
 1330   \ If Y=0, display startup banner and enter command prompt
 1340   \ If Y<>0, XY=>command to execute
 1350   
 1360   JSR PrText                    :\ Print startup banner
 1370   EQUB 10:EQUS "Acorn Atom/System 65Tube"
 1380   EQUB 10:EQUB 13
 1390   NOP
 1400   JMP CmdOS                     :\ Jump to command prompt
 1410   \ Will then display help banner,
 1420   \ then calls OsByteA3,4 for any entry address
 1430   
 1440   .OscliXY
 1450   JSR ErrorInit                 :\ Set up error handler
 1460   JSR XOS_CLI:JMP CmdQUIT       :\ Execute command then quit
 1470   
 1480   \ Reset vectors and set memory limits
 1490   \ ===================================
 1500   .LF87F
 1510   CLD:LDX #&35
 1520   .LF882
 1530   LDA LFB87,X:STA &0200,X       :\ Copy from default vectors
 1540   DEX:BPL LF882
 1550   STZ &FF:STZ &F0               :\ Clear escape flag
 1560   LDX #&10:STX &F1              :\ Set F0/1=>bottom of memory at &1000
 1570   LDX #&00:LDY #&F8             :\ XY=&F800
 1580   STX &F4:STY &F5               :\ Set F4/5=>top of memory at &F800
 1590   RTS
 1600   
 1610   \ Interupt handler
 1620   \ ================
 1630   .InterruptHandler
 1640   STA &FC:PLA:PHA           :\ Save A, get flags from stack
 1650   AND #&10:BNE BRKHandler   :\ If BRK, jump to BRK handler
 1660   :
 1670   LDA &FC:PHA:JMP (irq1v)   :\ Pass on to IRQ1V
 1680   
 1690   .BRKHandler
 1700   LDA &FC:PLP:PHP:JMP (brkv):\ Restore A and flags, jump to BRK handler
 1710   
 1720   .NullIRQ
 1730   PLA:RTI
 1740   
 1750   
 1760   \ Default error handler
 1770   \ =====================
 1780   \ On Atom/System, adjustment of &FD/E is done in error handler
 1790   \ SP=>flags, ret.lo, ret.hi
 1800   \
 1810   .ErrorHandler
 1820   TXA:PHA                      :\ Save X
 1830   TSX:LDA &0103,X              :\ Get address from stack
 1840   CLD:SEC:SBC #&01:STA &FD
 1850   LDA &0104,X:SBC #&00:STA &FE :\ &FD/E=>after BRK opcode
 1860   LDA #&00:STA &03FE           :\ Error block at (&FD),Y is in block &00
 1870   PLA:TAX:LDA &FC:CLI          :\ Restore X, get saved A
 1880   
 1890   \ Now continue into normal error handler
 1900   LDX #&FF:TXS                 :\ Clear stack
 1910   JSR OSNEWL:LDY #&01
 1920   .LF8D7
 1930   LDA (&FD),Y:BEQ LF8E1        :\ Print error string
 1940   JSR OSWRCH:INY:BNE LF8D7
 1950   .LF8E1
 1960   JSR OSNEWL:JMP CmdOSLoop     :\ Jump to command prompt
 1970   
 1980   \ *QUIT
 1990   \ =====
 2000   .CmdQUIT
 2010   EQUB &B3                     :\ Pass to host
 2020   
 2030   .OSByteA3
 2040   LDA #&A3:LDX #&F3            :\ OSBYTE &A3,&F3
 2050   EQUB &13                     :\ Host OSBYTE
 2060   RTS
 2070   
 2080   \ Scan hex
 2090   \ ========
 2100   .ScanHex
 2110   LDX #&00:STX &F6:STX &F7     :\ Clear hex accumulator
 2120   STX &03F3                    :\ String at (&F2),Y is in block &00
 2130   .LF8F7
 2140   LDA (&F2),Y                  :\ Get current character
 2150   SEC:SBC #&30:BCC LF921       :\ <'0', exit
 2160   CMP #&0A:BCC LF90E           :\ '0'..'9', add into accumator
 2170   AND #&DF:SBC #&07            :\ Ignore case, convert letters
 2180   CMP #&0A:BCC LF921           :\ <'A', exit
 2190   CMP #&10:BCS LF921           :\ >'F', exit
 2200   .LF90E
 2210   ASL A:ASL A:ASL A:ASL A      :\ *16
 2220   LDX #&03
 2230   .LF914
 2240   ASL A:ROL &F6:ROL &F7        :\ Move bits into accumulator
 2250   BCS LF959                    :\ Overflowed, jump to error
 2260   DEX:BPL LF914                :\ Loop for four bits
 2270   INY:BNE LF8F7                :\ Move to next character
 2280   .LF921
 2290   JMP SkipSpaces               :\ Skip past any final spaces and exit
 2300   
 2310   \ Scan hex, error if null string
 2320   .LF924
 2330   JSR ScanHex:PHP              :\ Save <cr> flag
 2340   CPX #&00:BEQ LF959           :\ X=0, nothing read in, 'Bad number' error
 2350   PLP:RTS                      :\ Get <cr> flag back
 2360   
 2370   \ *PAGE - Set PAGE address
 2380   \ ========================
 2390   .CmdPAGE
 2400   JSR SkipSpaces:BEQ LF94A   :\ No parameters, jump to use &1000
 2410   JSR LF924:BNE LF959        :\ Error if more parameters
 2420   LDY &F7:LDX &F6:BNE LF94E  :\ addr<>&xx00, error as must by 256-byte aligned
 2430   CPY #&10:BCC LF94E         :\ addr<&1000, error as too low
 2440   CPY #&80:BCS LF94E         :\ addr>&8000, error as too high
 2450   .LF946
 2460   STY &F1:CLC:RTS            :\ Store PAGE high byte
 2470   .LF94A
 2480   LDY #&10:BRA LF946         :\ Default to &1000
 2490   
 2500   .LF94E
 2510   BRK
 2520   EQUB 252:EQUS "Bad PAGE":BRK    :\ Unusable PAGE value
 2530   .LF959
 2540   BRK
 2550   EQUB 252:EQUS "Bad number":BRK  :\ Bad hex
 2560   .LF966
 2570   SEC:RTS                    :\ SEC=pass command to host
 2580   
 2590   \ *GO - Call machine code
 2600   \ =======================
 2610   .CmdGO
 2620   JSR SkipSpaces:BEQ LF984   :\ If no params, re-enter existing code
 2630   JSR ScanHex                :\ Scan hex parameter
 2640   CPX #&00:BEQ LF966         :\ No hex parameter, pass to host
 2650                              :\ eg *GO HELLO
 2660   CMP #&3B:BEQ LF97C         :\ ';'
 2670   CMP #&0D:BNE LF959         :\ More parameters, error
 2680   .LF97C
 2690   LDX &F6:LDY &F7            :\ Store parameter pointer
 2700                              :\ Enter code at XY
 2710   
 2720   .EnterCodeXY
 2730   STX &F4:STY &F5            :\ Set memtop to entry address
 2740   .LF984
 2750   LDA &EF:PHA:LDA &EE:PHA    :\ Save current program
 2760   JSR EnterCode
 2770   PLA:STA &EE:STA &F4        :\ Restore current program and also set memtop
 2780   PLA:STA &EF:STA &F5
 2790   CLC:RTS                    :\ CLC=command done
 2800   
 2810   \ Check if code to be entered has a ROM header
 2820   .EnterCode
 2830   LDA &F4:STA &EE              :\ Current program starts at memtop
 2840   LDA &F5:STA &EF
 2850   LDX #&00:STX &03F5:STX &03FE :\ Set memtop and errptr are in block &00
 2860   LDY #&07:LDA (&F4),Y         :\ Get copyright offset
 2870   CLD:CLC:ADC &F4:STA &FD
 2880   LDA #&00:ADC &F5:STA &FE     :\ &FD/E=>copyright message
 2890   \ Check for &00,"(C)"
 2900   LDY #&00:LDA (&FD),Y:BNE LF9FC     :\ Check for initial &00
 2910   INY:LDA (&FD),Y:CMP #&28:BNE LF9FC :\ Check for '('
 2920   INY:LDA (&FD),Y:CMP #&43:BNE LF9FC :\ Check for 'C'
 2930   INY:LDA (&FD),Y:CMP #&29:BNE LF9FC :\ Check for ')'
 2940   \ &00,"(C)" exists
 2950   LDY #&06:LDA (&F4),Y         :\ Get ROM type
 2960   AND #&4D:CMP #&40:BCC LFA2A  :\ b6=0, Not a language
 2970   AND #&0D:BEQ LF9E6           :\ code=%x1xx00x0, enter 6502 code
 2980   CMP #&01:BNE LFA0E           :\ code<>%x1xx00x1, not 6502 code
 2990   .LF9E6
 3000   \ romtype=%0000 - A=0 - 6502 BASIC
 3010   \ romtype=%0001 - A=1 - Turbo6502
 3020   \ romtype=%0010 - A=0 - 6502 nonBASIC
 3030   \ romtype=%0011 - A=1 - reserved
 3040   PHA:LDY #&09                 :\ Save entry value &00 or &01
 3050   .LF9E9
 3060   LDA (&F4),Y:BEQ LF9F3        :\ Print ROM title
 3070   JSR OSWRCH:INY:BNE LF9E9
 3080   .LF9F3
 3090   JSR OSNEWL:JSR OSNEWL        :\ Print two NLs
 3100   PLA:BRA LF9FE                :\ Get entry value back
 3110   .LF9FC                       :\ No (C) string, enter as raw code
 3120   LDA #&00                     :\ Set flag=0
 3130   .LF9FE
 3140   STA &F0                      :\ Store flag at &F0
 3150   \ If flag=0, membot=&F0/1, memtop=&F4/5
 3160   \ If flag<>0, membot=010000, memtop=040000
 3170   LDY #&00:TYA
 3180   .LFA03
 3190   STA &0300,Y:DEY:BNE LFA03    :\ All (zp),Y accesses to block &00
 3200   LDA #&01:JMP (&00F4)         :\ Enter code with A=1
 3210   
 3220   .LFA0E
 3230   JSR ErrorInit
 3240   BRK:EQUB 0:EQUS "I cannot run this code":BRK
 3250   .LFA2A
 3260   JSR ErrorInit
 3270   BRK:EQUB 0:EQUS "This is not a language":BRK
 3280   
 3290   .ErrorInit
 3300   LDA #ErrorHandler AND 255:STA brkv+0 :\ Claim brkv
 3310   LDA #ErrorHandler DIV 256:STA brkv+1
 3320   RTS
 3330   
 3340   \ *HELP - Display help
 3350   \ ====================
 3360   .CmdHELP
 3370   JSR SkipSpaces:BNE LFA5C :\ Exit if parameters
 3380   JSR OSNEWL:JSR HelpBanner:\ Display startup banner
 3390   .LFA5C
 3400   SEC:RTS                  :\ Return, SEC to pass to host
 3410   
 3420   .HelpBanner
 3430   JSR PrText
 3440   EQUS "65Tube Atom/System MOS 0.10 (21 Feb 2012)"
 3450   EQUB 10:EQUB 13
 3460   NOP
 3470   RTS
 3480   
 3490   \ OSBYTE Handler
 3500   \ ==============
 3510   .osBYTE               :\ OSBYTE
 3520   PHA
 3530   CMP #&82:BEQ BYTE82 :\ Read memory high word
 3540   CMP #&83:BEQ BYTE83 :\ Read bottom of memory
 3550   CMP #&84:BEQ BYTE84 :\ Read top of memory
 3560   CMP #&85:BEQ BYTE85 :\ Read top of memory for screen mode
 3570   CMP #&8E:BEQ BYTE8E :\ Enter language
 3580   CMP #&A3:BNE BYTEnn :\ Jump if not Application OSBYTE
 3590   CPX #&FE:BCC BYTEnn :\ Jump if X<&FE
 3600   \ OSBYTE &A3,&FE and OSBYTE &A3,FF - return unchanged
 3610   PLA
 3620   RTS
 3630   
 3640   .BYTEnn             :\ Pass OSBYTE to host
 3650   EQUB &13            :\ MOS_BYTE
 3660   PLA:RTS             :\ Return
 3670   
 3680   .BYTE82             :\ Read memory high word
 3690   LDX #&00:LDY #&00   :\ High word=&0000
 3700   PLA:RTS
 3710   
 3720   .BYTE83             :\ Read bottom of memory
 3730   PLA                 :\ Get A back
 3740   LDX &F0:BEQ LFABC   :\ If &F0=0, &F0/F1=>memory bottom
 3750   LDA #&01            :\ Set A=&01
 3760   LDX #&00:LDY #&00   :\ Return memory bottom=&010000
 3770   RTS
 3780   .LFABC
 3790   LDX #&00:LDY &F1    :\ Get memory bottom from &F0/F1
 3800   RTS
 3810   
 3820   .BYTE84             :\ Read top of memory
 3830   PLA                 :\ Get A back
 3840   LDX &F0:BEQ LFACD   :\ If &F0=0, &F4/5=>memory top
 3850   LDA #&04            :\ Set A=&04
 3860   LDX #&00:LDY #&00   :\ Return memory top=&040000
 3870   RTS
 3880   .LFACD
 3890   LDX &F4:LDY &F5     :\ Get memory top from &F4/F5
 3900   RTS
 3910   
 3920   .BYTE85             :\ Read top of memory for screem
 3930   LDX #&00:LDY #&80   :\ Return top of memory=&8000
 3940   PLA:RTS             :\ Restore A and return
 3950   
 3960   .BYTE8E             :\ Enter language
 3970   JMP CmdBASIC        :\ Jump to enter BASIC
 3980   
 3990   \ File and I/O Interface
 4000   \ ======================
 4010   
 4020   \ These low-level calls are the same on the Atom/System and BBC
 4030   \ -------------------------------------------------------------
 4040   .osFIND
 4050   EQUB &A3:RTS        :\ Pass OSFIND to host
 4060   .osGBPB
 4070   EQUB &93:RTS        :\ Pass OSGBPB to host
 4080   .osBPUT:.atomBPUT
 4090   EQUB &83:RTS        :\ Pass OSBPUT to host
 4100   .osBGET:.atomBGET
 4110   EQUB &73:RTS        :\ Pass OSBGET to host
 4120   .osARGS
 4130   EQUB &63:RTS        :\ Padd OSARGS to host
 4140   .osFILE
 4150   EQUB &53:RTS        :\ Pass OSFILE to host
 4160   .osRDCH
 4170   EQUB &43:RTS        :\ Padd OSRDCH to host
 4180   .osWRCH:.atomWRCH
 4190   EQUB &33:RTS        :\ Pass OSWRCH to host
 4200   
 4210   \ A bit of hand-holding for RDCH
 4220   \ ------------------------------
 4230   .atomRDCH
 4240   BIT &FF:BPL doRDCH
 4250   LDA #&7E:JSR XOSBYTE :\ Ack. any Escape
 4260   .doRDCH
 4270   LDA #&FF:STA &0E21   :\ Set 'no key pressed'
 4280   EQUB &43             :\ Pass OSRDCH to host
 4290   PHP
 4300   CMP #8:BEQ SwapRDCH
 4310   CMP #127:BNE RDCHdone
 4320   .SwapRDCH
 4330   EOR #&77             :\ Swap &08 and &7F
 4340   .RDCHdone
 4350   PLP:RTS
 4360   
 4370   \ Atom file interface
 4380   \ -------------------
 4390   
 4400   \ OSLOAD - Load a file
 4410   \ --------------------
 4420   \ On entry,  X=>zero page
 4430   \               X+0/1=>file name
 4440   \               X+2/3=Load address
 4450   \               X+4  =if bit 7=0 use the file's start address
 4460   \           CC=Return immediately
 4470   \           CS=Wait until IRQ/DMA actions completed
 4480   \ On exit,   all preserved
 4490   \
 4500   .atomLOAD
 4510   LDA #&FF:BNE doFILE
 4520   
 4530   \ OSSAVE - Save a file
 4540   \ --------------------
 4550   \ On entry,  X=>zero page
 4560   \               X+0/1=file name
 4570   \               X+2/3=load address
 4580   \               X+4/5=execution address
 4590   \               X+6/7=start address of data to save
 4600   \               X+8/9=(end address)+1 of data to save
 4610   \           CC=Return immediately
 4620   \           CS=Wait until IRQ/DMA actions completed
 4630   \ On exit,   all preserved
 4640   .atomSAVE
 4650   LDA #&00
 4660   .doFILE
 4670   PHA
 4680   TYA:PHA:TXA:PHA
 4690   LDA 0,X:STA &2EE    :\ =>filename
 4700   LDA 1,X:STA &2EF
 4710   LDY #0
 4720   .doFILElp
 4730   LDA 2,X:STA &2F0,Y:INX:INY
 4740   LDA 2,X:STA &2F0,Y:INX:INY
 4750   LDA #0              :\ Expand control block
 4760   STA &2F0,Y:INY
 4770   STA &2F0,Y:INY
 4780   CPY #16:BNE doFILElp
 4790   TSX:LDA &103,X      :\ Get OSFILE action
 4800   CMP #&FF:BNE callFILE
 4810   LDA &2F4:EOR #&FF
 4820   STA &2F4:LDA #&FF
 4830   .callFILE
 4840   LDX #&EE:LDY #&02   :\ Point to control block
 4850   EQUB &53            :\ Pass OSFILE to host
 4860   TSX:STA &103,X      :\ Store return value on stack
 4870   PLA:TAX:PLA:TAY     :\ Restore registers
 4880   PLA:RTS             :\ Get return value and return
 4890   
 4900   \ OSRDAR - Read file's arguments
 4910   \ ------------------------------
 4920   \ On entry,  X=>zero page location
 4930   \            Y=handle
 4940   \            A=0 - read PTR
 4950   \            A=1 - read EXT
 4960   \            A=2 - read allocation
 4970   \ On exit,   X+0-X+3 = returned argument
 4980   \            A,X,Y preserved
 4990   .atomRDAR
 5000   PHA:CLC:BCC doARGS  :\ Jump to do even-numbered OSARGS
 5010   
 5020   \ OSSTAR - Set file's arguments
 5030   \ -----------------------------
 5040   \ On entry,  X=>zero page location
 5050   \            Y=handle
 5060   \            A=0 - write PTR (usually, A=unset)
 5070   \            X+0-X+3 = argument
 5080   \ On exit,   A,X,Y preserved
 5090   .atomSTAR
 5100   PHA:LDA #0:SEC      :\ Do odd-numbered OSARGS
 5110   .doARGS
 5120   ROL A               :\ Convert to OSARGS action
 5130   EQUB &63            :\ Pass OSARGS to host
 5140   PLA:RTS             :\ Restore A and return
 5150   
 5160   \ OSFIND - Open file
 5170   \ ------------------
 5180   \ On entry,  X=>zero page
 5190   \               X+0/1=file name
 5200   \           CS=Open file for input
 5210   \           CC=Open file for output
 5220   \ On exit,   A=file handle, 0 if file not found
 5230   \          X,Y=preserved
 5240   .atomFIND
 5250   PHA                 :\ Space for returned A
 5260   TYA:PHA:TXA:PHA     :\ Save X,Y
 5270   LDA 1,X:TAY         :\ XY=>filename
 5280   LDA 0,X:TAX
 5290                       :\ Create OSFIND action
 5300   LDA #0              :\ A=00, CS  CC
 5310   PHP:ROR A:PLP:ROR A :\       C0  00
 5320   EOR #&80            :\       40  80
 5330   EQUB &A3            :\ Pass OSFIND to host
 5340   TSX:STA &103,X      :\ Store on stack
 5350   PLA:TAX:PLA:TAY     :\ Restore X,Y
 5360   PLA:RTS             :\ Get handle and return
 5370   
 5380   \ OSSHUT - Close a file
 5390   \ ---------------------
 5400   \ On entry,  Y=file handle
 5410   \ On exit,   all preserved
 5420   .atomSHUT
 5430   PHA:LDA #0          :\ OSFIND &00 - Close
 5440   EQUB &A3            :\ Pass OSFIND to host
 5450   PLA:RTS
 5460   
 5470   
 5480   \ OSWORD Handler
 5490   \ ==============
 5500   .osWORD
 5510   CMP #&05:BNE LFB0C   :\ Jump if not Read I/O memory
 5520   :
 5530   \ OSWORD 5 - Read I/O memory
 5540   \ Reads from Tube memory
 5550   STX &F8:STY &F9      :\ &F8/9=>control block
 5560   LDY #&00:STY &03F9   :\ Control block at (&F8),Y in block &00
 5570   LDA (&F8),Y:STA &FA
 5580   INY
 5590   LDA (&F8),Y:STA &FB  :\ &FA/B=address to read
 5600   LDX #&00:LDA (&FA,X) :\ Read from address
 5610   LDY #&04:STA (&F8),Y :\ Store byte read in control block
 5620   LDX &F8:LDY &F9      :\ Restore X, Y
 5630   RTS
 5640   
 5650   .LFB0C
 5660   EQUB &23             :\ Pass OSWORD to host
 5670   RTS
 5680   
 5690   \ OSARGS Handler
 5700   \ ==============
 5710   .osARGS
 5720   CMP #&01:BNE LFB3C   :\ Jump if not command line/PTR=
 5730   CPY #&00:BNE LFB3C   :\ Jump if not command line
 5740   :
 5750   \ OSARGS 1,0 - Read address of command line
 5760   STY &03F3:DEY        :\ String at (&F2),Y is in block &00
 5770   .LFB1A
 5780   INY:LDA (&F2),Y      :\ Get character from command line
 5790   CMP #&20:BCC LFB26   :\ Control character found
 5800   BNE LFB1A            :\ Loop if not space
 5810   JSR SkipSpaces            :\ Skip any more spaces
 5820   .LFB26
 5830   CLC:TYA:ADC &F2:STA &00,X    :\ Add Y to base
 5840   LDA &F3:ADC #&00:STA &01,X   :\ Set returned address
 5850   LDY #&FF:STY &02,X:STY &03,X :\ Set to &FFFFxxxx
 5860   INY:LDA #&01                 :\ Return Y=&00, A=&01
 5870   RTS
 5880   .LFB3C
 5890   EQUB &63             :\ Pass OSARGS to host
 5900   RTS
 5910   
 5920   \ Print embedded string
 5930   \ =====================
 5940   .PrText
 5950   PLA:STA &FA:PLA:STA &FB   :\ &FA/B=>embedded string
 5960   LDY #&00:STY &03FB        :\ String at (&FA),Y is in block &00
 5970   INY
 5980   .LFB4A
 5990   LDA (&FA),Y               :\ Get character
 6000   CMP #&EA:BEQ LFB56        :\ Exit if NOP
 6010   JSR OSWRCH:INY:BNE LFB4A  :\ Print char and loop for next
 6020   .LFB56
 6030   TYA:CLC:ADC &FA
 6040   TAX:LDA #&00:ADC &FB      :\ Update return address
 6050   PHA:TXA:PHA               :\ Points after string
 6060   .NullReturn
 6070   RTS
 6080   
 6090   \ Print string at XY
 6100   \ ------------------
 6110   .PrString
 6120   STX &FA:STY &FB           :\ Store XY in &FA/B
 6130   LDY #&00:STY &03FB        :\ String at (&FA),Y is in block &00
 6140   .LFB6C
 6150   LDA (&FA),Y               :\ Get a character
 6160   CMP #&20:BCC LFB78        :\ Exit at control char
 6170   JSR OSWRCH:INY:BNE LFB6C  :\ Print character
 6180   .LFB78
 6190   RTS
 6200   
 6210   .Unsupported
 6220   BRK
 6230   BRK:EQUS "Unsupported":BRK
 6240   
 6250   \ Default vectors
 6260   .LFB87
 6270   EQUW NMIHandler       :\ &200 - nmiv
 6280   EQUW ErrorHandler     :\ &202 - brkv
 6290   EQUW NullIRQ          :\ &204 - irq1v
 6300   EQUW atomCLI          :\ &206 - cliv
 6310   EQUW atomWRCH         :\ &208 - wrchv
 6320   EQUW atomRDCH         :\ &20A - rdchv
 6330   EQUW atomLOAD         :\ &20C - loadv
 6340   EQUW atomSAVE         :\ &20E - savev
 6350   EQUW atomRDAR         :\ &210 - rdarv
 6360   EQUW atomSTAR         :\ &212 - starv
 6370   EQUW atomBGET         :\ &214 - bgetv
 6380   EQUW atomBPUT         :\ &216 - bputv
 6390   EQUW atomFIND         :\ &218 - findv
 6400   EQUW atomSHUT         :\ &21A - shutv
 6410   EQUW NullReturn       :\ &21C - v21C
 6420   EQUW NullReturn       :\ &21E - v21E
 6430   EQUW NullReturn       :\ &220 - v220
 6440   EQUW NullReturn       :\ &222 - v222
 6450   EQUW NullReturn       :\ &224 - v224
 6460   EQUW NullReturn       :\ &226 - v226
 6470   EQUW NullReturn       :\ &228 - v228
 6480   EQUW NullReturn       :\ &22A - v22A
 6490   EQUW NullReturn       :\ &22C - v22C
 6500   EQUW NullReturn       :\ &22E - v22E
 6510   EQUW NullReturn       :\ &230 - v230
 6520   EQUW NullReturn       :\ &232 - v232
 6530   EQUW NullReturn       :\ &234 - v234
 6540   
 6550   OSCLI - Execute command string
 6560   \ ==============================
 6570   \ Command string is at &100
 6580   \
 6590   .atomCLI
 6600   LDX #&00:LDY #&01        :\ Point XY=>&100, Atom command buffer
 6610   .osCLI
 6620   STX &F2:STY &F3          :\ &F2/3=>command string
 6630   LDY #&00:STY &03F3       :\ String at (&F2),Y is in block &00
 6640   .LFBC6
 6650   LDA (&F2),Y:STA LFC6A,Y  :\ Copy command line to command buffer
 6660   CMP #&0D:BEQ LFBD3       :\ Loop until <cr>
 6670   INY:BNE LFBC6            :\ Loop for up to 256 characters
 6680   .LFBD2
 6690   RTS                      :\ No <cr> found, exit
 6700   .LFBD3
 6710   LDX #LFC6A AND 255
 6720   LDY #LFC6A DIV 256       :\ Point XY to command buffer
 6730   STX &F2:STY &F3          :\ Point &F2/3 to command buffer
 6740   LDX #&00:LDY #&FF
 6750   .LFBDF
 6760   JSR SkipSpaces1          :\ Move past and skip spaces
 6770   CMP #ASC"*":BEQ LFBDF    :\ Skip past '*'s
 6780   CMP #&0D:BEQ LFBD2       :\ Null string, exit
 6790   CMP #ASC"|":BEQ LFBD2    :\ *|, comment, exit
 6800   CLC:TYA:ADC &F2:STA &F2  :\ Adjust &F2/3 to point to start of command
 6810   BCC LFBF8:INC &F3
 6820   .LFBF8
 6830   LDY #&00:LDA (&F2),Y     :\ Get first character
 6840   CMP #ASC".":BEQ LFC45    :\ '*.', jump to pass to host
 6850   .LFC00
 6860   TYA:PHA                  :\ Save command pointer
 6870   JSR SkipSpaces           :\ Skip any more spaces
 6880   .LFC05
 6890   LDA LFF02,X:BMI LFC20    :\ Jump if at end of command table
 6900   EOR (&F2),Y              :\ Compare with command table
 6910   AND #&DF:BNE LFC14       :\ Ignore case, jump if no match
 6920   INX:INY:BRA LFC05        :\ Loop to check next character
 6930   
 6940   .LFC14
 6950   LDA (&F2),Y:INY          :\ Get command character
 6960   CMP #ASC".":BEQ LFC29    :\ Abbreviated, jump to execute
 6970   .LFC1B
 6980   PLA:TAY                  :\ Get command pointer back
 6990   SEC:BRA LFC2B            :\ Step to next entry
 7000   
 7010   .LFC20
 7020   ASL A:BMI LFC29
 7030   LDA (&F2),Y              :\ Get next character
 7040   CMP #ASC"A":BCS LFC1B    :\ Still more letters, try next entry
 7050   .LFC29
 7060   PLA:CLC                  :\ Drop command pointer
 7070   .LFC2B
 7080   DEX
 7090   .LFC2C
 7100   INX:LDA LFF02,X:BPL LFC2C :\ Find end of entry
 7110   BCC LFC3C
 7120   INX:LDA LFF02,X
 7130   BNE LFC00:BEQ LFC45
 7140   
 7150   .LFC3C
 7160   ASL A:AND #&7F            :\ Index into command table
 7170   TAX:JSR LFC4B             :\ Call command routine
 7180   BCC LFC4A                 :\ If CLC, exit with call claimed
 7190   .LFC45
 7200   LDX &F2:LDY &F3           :\ &F2/3=XY
 7210   EQUB &03                  :\ Pass OSCLI to host
 7220                             :\ If host loads code and starts execution,
 7230                             :\ it generates an NMI and returns <>0 from
 7240                             :\ Osbyte 163,&F3
 7250   .LFC4A
 7260   RTS
 7270   
 7280   .LFC4B
 7290   LDA LFC5E+1,X:PHA         :\ Stack address high byte
 7300   LDA LFC5E+0,X:PHA         :\ Stack address low byte
 7310   RTS                       :\ Jump to routine
 7320   
 7330   .SkipSpaces1
 7340   INY
 7350   .SkipSpaces
 7360   LDA (&F2),Y:CMP #&20:BEQ SkipSpaces1
 7370   CMP #&0D:RTS
 7380   
 7390   .Pr2Hex
 7400   TYA:JSR PrHex:TXA
 7410   .PrHex
 7420   PHA:LSR A:LSR A:LSR A:LSR A
 7430   JSR PrNyb:PLA
 7440   .PrNyb
 7450   AND #15:CMP #10:BCC P%+4
 7460   ADC #6:ADC #48:JMP OSWRCH
 7470   
 7480   \ Command addresses
 7490   \ -----------------
 7500   .LFC5E
 7510   EQUW CmdBASIC-1 :\ *BASIC
 7520   EQUW CmdQUIT-1  :\ *QUIT
 7530   EQUW CmdHELP-1  :\ *HELP
 7540   EQUW CmdGO-1    :\ *GO
 7550   EQUW CmdOS-1    :\ *OS
 7560   EQUW CmdPAGE-1  :\ *PAGE
 7570   
 7580   OSCLI command buffer
 7590   \ --------------------
 7600   .LFC6A
 7610   EQUS STRING$(128,CHR$0)
 7620   EQUS STRING$(128,CHR$0)
 7630   
 7640   .LFD6A
 7650   EQUS STRING$(&FE00-P%,CHR$0)
 7660   EQUS STRING$(&FE80-P%,CHR$0)
 7670   EQUS STRING$(&FF00-P%,CHR$0)
 7680   
 7690   \ Command table
 7700   \ =============
 7710   .LFF00
 7720   EQUW LFF17
 7730   .LFF02
 7740   EQUS "GO"   :EQUB &C3
 7750   EQUS "HELP" :EQUB &82
 7760   EQUS "OS"   :EQUB &84
 7770   EQUS "PAGE" :EQUB &C5
 7780   EQUS "QUIT" :EQUB &81
 7790   .LFF17
 7800   EQUS "BASIC":EQUB &80
 7810   EQUB &00
 7820   
 7830   
 7840   \ Copy of BBC MOS API entry block
 7850   \ ===============================
 7860   EQUS STRING$(&FF4E-P%,CHR$0)
 7870   .XOSFIND  :\ &FF4E  :JMP osFIND
 7880   .XOSGBPB  :\ &FF51  :JMP osGBPB
 7890   .XOSBPUT  :\ &FF54  :JMP osBPUT
 7900   .XOSBGET  :\ &FF57  :JMP osBGET
 7910   .XOSARGS  :\ &FF5A  :JMP osARGS
 7920   .XOSFILE  :\ &FF5D  :JMP osFILE
 7930   
 7940   .XOSRDCH  :\ &FF60  :JMP osRDCH
 7950   .XOSASCI  :\ &FF63  :CMP #&0D:BNE XOSWRCH
 7960   .XOSNEWL  :\ &FF67  :LDA #&0A:JSR XOSWRCH
 7970   .XOSPRCR  :\ &FF6C  :LDA #&0D
 7980   .XOSWRCH  :\ &FF6E  :JMP osWRCH
 7990   .XOSWORD  :\ &FF71  :JMP osWORD
 8000   .XOSBYTE  :\ &FF74  :JMP osBYTE
 8010   .XOS_CLI  :\ &FF77  :JMP osCLI
 8020   
 8030   .XNMIV    :\ &FF7A  :EQUW NMIHandler
 8040   .XRESETV  :\ &FF7C  :EQUW RESET
 8050   .XIRQV    :\ &FF7E  :EQUW InterruptHandler
 8060   
 8070   
 8080   \ Main MOS API entry block
 8090   \ ========================
 8100   EQUS STRING$(&FF9E-P%,CHR$0)
 8110   .LFF9E   :\ &FF9E   :JMP NullReturn
 8120   .LFFA1   :\ &FFA1   :JMP NullReturn
 8130   .LFFA4   :\ &FFA4   :JMP NullReturn
 8140   .LFFA7   :\ &FFA7   :JMP NullReturn
 8150   .LFFAA   :\ &FFAA   :JMP PrHex      :\ Print A in hex
 8160   .LFFAD   :\ &FFAD   :JMP Pr2Hex     :\ Print YX in hex
 8170   .LFFB0   :\ &FFB0   :JMP NullReturn :\ IRQ stub
 8180   .LFFB3   :\ &FFB3   :JMP PrText     :\ Print inline text
 8190   .VECDEF  :\ &FFB6   :EQUB &36:EQUW LFB87
 8200   .LFFB9   :\ &FFB9   :JMP Unsupported
 8210   .LFFBC   :\ &FFBC   :JMP Unsupported
 8220   .LFFBF   :\ &FFBF   :JMP LF87F      :\ Reset vectors, etc.
 8230   .LFFC2   :\ &FFC2   :JMP Unsupported
 8240   .LFFC5   :\ &FFC5   :JMP Unsupported
 8250   .LFFC8   :\ &FFC8   :JMP Unsupported
 8260   
 8270   \ Atom/System Entry Block
 8280   \ -----------------------
 8290   .OSSHUT  :\ &FFCB   :JMP (shutv)
 8300   .OSFIND  :\ &FFCE   :JMP (findv)
 8310   .OSBPUT  :\ &FFD1   :JMP (bputv)
 8320   .OSBGET  :\ &FFD4   :JMP (bgetv)
 8330   .OSSTAR  :\ &FFD7   :JMP (starv)
 8340   .OSRDAR  :\ &FFDA   :JMP (rdarv)
 8350   .OSSAVE  :\ &FFDD   :JMP (savev)
 8360   .OSLOAD  :\ &FFE0   :JMP (loadv)
 8370   
 8380   .OSRDCH  :\ &FFE3   :JMP (rdchv)
 8390   .OSECHO  :\ &FFE6   :JSR OSRDCH
 8400   .OSASCI  :\ &FFE9   :CMP #&0D:BNE OSWRCH
 8410   .OSNEWL  :\ &FFED   :LDA #&0A:JSR OSWRCH
 8420   .OSPRCR  :\ &FFF2   :LDA #&0D
 8430   .OSWRCH  :\ &FFF4   :JMP (wrchv)
 8440   .OS_CLI  :\ &FFF7   :JMP (cliv)
 8450   
 8460   \ Hardware vectors
 8470   \ ----------------
 8480   .NMIV    :\ &FFFA  :EQUW NMIHandler
 8490   .RESETV  :\ &FFFC  :EQUW RESET
 8500   .IRQV    :\ &FFFE  :EQUW InterruptHandler
 8510 ]:NEXT
 8520 OSCLI"Save "+fname$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~load%+" "+STR$~load%
 8530 ON ERROR ON ERROR OFF:END
 8540 *Quit