10 REM > AtomCP/src
   20 REM Source for Atom/System kernel for 6502 CoProcessor
   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$="KernelCP"
   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   .RESET
  410   LDX #&00
  420   .LF802
  430   LDA &FF00,X:STA &FF00,X    :\ Copy entry block to RAM
  440   DEX:BNE LF802
  450   LDX #&36
  460   .LF80D
  470   LDA VECTABLE,X:STA &200,X  :\ Set up default vectors
  480   DEX:BPL LF80D
  490   TXS                        :\ Clear stack
  500   LDX #IOADDR AND 255
  510   .LF819
  520   LDA &FDFF,X:STA &FDFF,X    :\ Copy &FE00-&FEEF to RAM, avoiding
  530   DEX:BNE LF819              :\  Tube registers at &FEFx
  540   LDY #RESET AND 255:STY &F8 :\ Point to start of ROM
  550   LDA #RESET DIV 256:STA &F9
  560   .LF82A                     :\ Copy rest of ROM to RAM
  570   LDA (&F8),Y:STA (&F8),Y    :\ Copy a page to RAM
  580   INY:BNE LF82A              :\ Loop for 256 bytes
  590   INC &F9:LDA &F9            :\ Inc. address high byte
  600   CMP #&FE:BNE LF82A         :\ Loop from &F800 to &FDFF
  610   LDX #&10
  620   .LF83B
  630   LDA LF859,X:STA &0100,X    :\ Copy jump code to &100
  640   DEX:BPL LF83B
  650   LDA &EE:STA &F6            :\ Copy &EE/F to &F6/7
  660   LDA &EF:STA &F7
  670   LDA #&00:STA &FF           :\ Clear Escape flag
  680   STA &F2:LDA #&F8:STA &F3   :\ Set memtop to start of ROM at &F800
  690   JMP &0100                  :\ Jump via low memory to page ROM out
  700   
  710   \ Executed in low memory to page ROM out
  720   \ --------------------------------------
  730   .LF859
  740   LDA TubeS1:CLI             :\ Check Tube R1 status to page ROM out
  750   .LF85D
  760   JMP LF860                  :\ Jump to initilise I/O with banner
  770   
  780   .LF860
  790   JSR PrText                 :\ Display startup banner
  800   EQUB 10:EQUS "Acorn Atom/System Tube"
  810   EQUB 10:EQUB 10:EQUB 13:EQUB 0
  820   NOP
  830   LDA #CmdOSLoop AND 255     :\ Next time RESET is soft entered,
  840   STA LF85D+1                :\ banner not printed
  850   LDA #CmdOSLoop DIV 256
  860   STA LF85D+2
  870   LDA #&00                   :\ Look for a entry point at &EC/D
  880   LDX &EC:LDY &ED:STA &ED
  890   BNE JumpToCode
  900   JSR WaitByte               :\ Wait for Acknowledge
  910   CMP #&80:BEQ EnterCode     :\ If &80, jump to enter code
  920                              :\ Otherwise, enter command prompt loop
  930   
  940   \ Minimal Command prompt
  950   \ ======================
  960   .CmdOSLoop
  970   JSR PrText
  980   EQUS "SYSTEM>* ":NOP       :\ Display prompt
  990   LDX #LF95D AND 255
 1000   LDY #LF95D DIV 256
 1010   LDA #&00:JSR XOSWORD       :\ Read line to INPBUF
 1020   BCS CmdOSEscape
 1030   LDX #INPBUF AND 255
 1040   LDY #INPBUF DIV 256        :\ Execute command
 1050   JSR XOS_CLI:JMP CmdOSLoop  :\  and loop back for another
 1060   .CmdOSEscape
 1070   LDA #&7E:JSR XOSBYTE       :\ Acknowledge Escape state
 1080   BRK:EQUB 17:EQUS "Escape":BRK
 1090   
 1100   
 1110   \ Enter Code pointer to by &F6/7
 1120   \ ==============================
 1130   \ Checks to see if code has a ROM header, and verifies
 1140   \ it if it has
 1150   .JumpToCode
 1160   STX &F6:STY &F7            :\ Enter code at XY
 1170   .EnterCode
 1180   LDA &F6:STA &EE:STA &F2    :\ Set current program and memtop
 1190   LDA &F7:STA &EF:STA &F3    :\  to address beng entered
 1200   .z%
 1210   LDY #&07:LDA (&EE),Y       :\ Get copyright offset
 1220   CLD:CLC:ADC &EE:STA &FD
 1230   LDA #&00:ADC &EF:STA &FE   :\ &FD/E=>copyright message
 1240   \
 1250   \ Now check for &00,"(C)"
 1260   LDY #&00:LDA (&FD),Y:BNE LF8FA     :\ Jump if no initial &00
 1270   INY:LDA (&FD),Y:CMP #&28:BNE LF8FA :\ Jump if no '('
 1280   INY:LDA (&FD),Y:CMP #&43:BNE LF8FA :\ Jump if no 'C'
 1290   INY:LDA (&FD),Y:CMP #&29:BNE LF8FA :\ Jump if no ')'
 1300   \
 1310   \ &00,"(C)" exists
 1320   LDY #&06:LDA (&EE),Y               :\ Get ROM type
 1330   AND #&4F:CMP #&40:BCC NotLanguage  :\ b6=0, not a language
 1340   AND #&0D:BNE Not6502Code           :\ type<>0 and <>2, not 6502 code
 1350   ]:z%=P%-z%:P%=P%-z%:O%=O%-z%:[OPT P*3+4
 1360   .LF8FA
 1370   LDA #&01:JMP (&00F2)               :\ Enter code with A=1
 1380   \
 1390   .z%
 1400   \ Any existing error handler will probably have been overwritten
 1410   \ Set up new error handler before generating an error
 1420   .NotLanguage
 1430   LDA #ErrorHandler AND 255:STA brkv+0 :\ Claim error handler
 1440   LDA #ErrorHandler DIV 256:STA brkv+1
 1450   BRK:EQUB 0:EQUS "This is not a language":EQUB 0
 1460   
 1470   .Not6502Code
 1480   LDA #ErrorHandler AND 255:STA brkv+0 :\ Claim error handler
 1490   LDA #ErrorHandler DIV 256:STA brkv+1
 1500   BRK:EQUB 0:EQUS "I cannot run this code":EQUB 0
 1510   ]:z%=P%-z%:P%=P%-z%:O%=O%-z%:[OPT P*3+4
 1520   
 1530   \ Default error handler
 1540   \ =====================
 1550   \ On Atom/System, adjustment of &FD/E is done in error handler
 1560   \ SP=>flags, ret.lo, ret.hi
 1570   \
 1580   .ErrorHandler
 1590   TXA:PHA                      :\ Save X
 1600   TSX:LDA &0103,X              :\ Get address from stack
 1610   CLD:SEC:SBC #&01:STA &FD
 1620   LDA &0104,X:SBC #&00:STA &FE :\ &FD/E=>after BRK opcode
 1630   PLA:TAX:LDA &FC:CLI          :\ Restore X, get saved A
 1640   
 1650   \ Now continue into normal error handler
 1660   LDX #&FF:TXS               :\ Clear stack
 1670   JSR OSNEWL:LDY #&01
 1680   .LF94D
 1690   LDA (&FD),Y:BEQ LF957      :\ Print error string
 1700   JSR OSWRCH:INY:BNE LF94D
 1710   .LF957
 1720   JSR OSNEWL:JMP CmdOSLoop   :\ Jump to command prompt
 1730   
 1740   \ Control block for command prompt input
 1750   \ --------------------------------------
 1760   .LF95D
 1770   EQUW INPBUF                :\ Input text to INPBUF at &236
 1780   EQUB &B7                   :\ Up to &CA characters
 1790   EQUB &20:EQUB &FF          :\ Min=&20, Max=&FF
 1800   
 1810   
 1820   \ MOS INTERFACE
 1830   \ =============
 1840   \
 1850   \
 1860   \ OSWRCH - Send character to output stream
 1870   \ ========================================
 1880   \ On entry, A =character
 1890   \ On exit,  A =preserved
 1900   \
 1910   \ Tube data  character  --
 1920   \
 1930   .osWRCH:.atomWRCH
 1940   BIT TubeS1                 :\ Read Tube R1 status
 1950   NOP:BVC osWRCH             :\ Loop until b6 set
 1960   STA TubeR1:RTS             :\ Send character to Tube R1
 1970   
 1980   
 1990   \ A bit of hand-holding for RDCH
 2000   \ ------------------------------
 2010   .atomRDCH
 2020   LDA &FF:BPL doRDCH
 2030   LDA #&7E:JSR XOSBYTE :\ Ack. any Escape
 2040   .doRDCH
 2050   LDA #&FF:STA &0E21   :\ Set 'no key pressed'
 2060                        :\ Continue into osRDCH
 2070   
 2080   
 2090   \ OSRDCH - Wait for character from input stream
 2100   \ =============================================
 2110   \ On exit, A =char, Cy=Escape flag
 2120   \
 2130   \ Tube data  &00  --  Carry Char
 2140   \
 2150   .osRDCH
 2160   LDA #&00:JSR SendCommand   :\ Send command &00 - OSRDCH
 2170   .WaitCarryChar             :\ Wait for Carry and A
 2180   JSR WaitByte:ASL A         :\ Wait for carry
 2190   .WaitByte
 2200   BIT TubeS2:BPL WaitByte    :\ Loop until Tube R2 has data
 2210   LDA TubeR2                 :\ Fetch character
 2220   .NullReturn
 2230   RTS
 2240   
 2250   
 2260   \ Skip Spaces
 2270   \ ===========
 2280   .SkipSpaces1
 2290   INY
 2300   .SkipSpaces
 2310   LDA (&F8),Y:CMP #&20:BEQ SkipSpaces1
 2320   RTS
 2330   
 2340   
 2350   \ Scan hex
 2360   \ ========
 2370   .ScanHex
 2380   LDX #&00:STX &F0:STX &F1   :\ Clear hex accumulator
 2390   .LF98C
 2400   LDA (&F8),Y                :\ Get current character
 2410   CMP #&30:BCC LF9B1         :\ <'0', exit
 2420   CMP #&3A:BCC LF9A0         :\ '0'..'9', add to accumulator
 2430   AND #&DF:SBC #&07:BCC LF9B1:\ Convert letter, if <'A', exit
 2440   CMP #&40:BCS LF9B1         :\ >'F', exit
 2450   .LF9A0
 2460   ASL A:ASL A:ASL A:ASL A    :\ *16
 2470   LDX #&03                   :\ Prepare to move 3+1 bits
 2480   .LF9A6
 2490   ASL A:ROL &F0:ROL &F1      :\ Move bits into accumulator
 2500   DEX:BPL LF9A6              :\ Loop for four bits, no overflow check
 2510   INY:BNE LF98C              :\ Move to next character
 2520   .LF9B1
 2530   RTS
 2540   
 2550   
 2560   \ Send string to Tube R2
 2570   \ ======================
 2580   .SendString
 2590   STX &F8:STY &F9            :\ Set &F8/9=>string
 2600   .SendStringF8
 2610   LDY #&00
 2620   .LF9B8
 2630   BIT TubeS2:BVC LF9B8       :\ Wait for Tube R2 free
 2640   LDA (&F8),Y:STA TubeR2     :\ Send character to Tube R2
 2650   INY:CMP #&0D:BNE LF9B8     :\ Loop until <cr> sent
 2660   LDY &F9:RTS                :\ Restore Y from &F9 and return
 2670   
 2680   
 2690   OSCLI - Execute command
 2700   \ =======================
 2710   \ Command string is at &100
 2720   \
 2730   .atomCLI
 2740   LDX #&00:LDY #&01        :\ Point XY=>&100, Atom command buffer
 2750   
 2760   \ On entry, XY=>command string
 2770   \ On exit,  XY= preserved
 2780   \
 2790   .osCLI
 2800   PHA:STX &F8:STY &F9        :\ Save A, &F8/9=>command string
 2810   LDY #&00
 2820   .LF9D1
 2830   JSR SkipSpaces:INY
 2840   CMP #ASC"*":BEQ LF9D1      :\ Skip spaces and stars
 2850   AND #&DF:TAX               :\ Ignore case, and save in X
 2860   LDA (&F8),Y                :\ Get next character
 2870   CPX #ASC"G":BEQ CmdGO      :\ Jump to check '*GO'
 2880   CPX #ASC"H":BNE osCLI_IO   :\ Not "H---", jump to pass to Tube
 2890   CMP #ASC".":BEQ CmdHELP    :\ "H.", jump to do *HELP
 2900   AND #&DF                   :\ Ignore case
 2910   CMP #ASC"E":BNE osCLI_IO   :\ Not "HE---", jump to pass to Tube
 2920   INY:LDA (&F8),Y            :\ Get next character
 2930   CMP #ASC".":BEQ CmdHELP    :\ "HE.", jump to do *HELP
 2940   AND #&DF                   :\ Ignore case
 2950   CMP #ASC"L":BNE osCLI_IO   :\ Not "HEL---", jump to pass to Tube
 2960   INY:LDA (&F8),Y            :\ Get next character
 2970   CMP #ASC".":BEQ CmdHELP    :\ "HEL.", jump to do *HELP
 2980   AND #&DF                   :\ Ignore case
 2990   CMP #ASC"P":BNE osCLI_IO   :\ Not "HELP---", jump to pass to Tube
 3000   INY:LDA (&F8),Y            :\ Get next character
 3010   AND #&DF                   :\ Ignore case
 3020   CMP #ASC"A":BCC CmdHELP    :\ "HELP" terminated by non-letter, do *HELP
 3030   CMP #ASC"[":BCC osCLI_IO   :\ "HELP" followed by letter, pass to Tube
 3040   
 3050   \ *Help - Display help information
 3060   \ --------------------------------
 3070   .CmdHELP
 3080   JSR PrText                 :\ Print help message
 3090   EQUB 10:EQUB 13:EQUS "65C102 Tube Atom/System MOS 0.10 (21 Feb 2012)"
 3100   EQUB 10:EQUB 13
 3110   NOP                        :\ Continue to pass '*HELP' command to Tube
 3120   
 3130   
 3140   OSCLI - Send command line to host
 3150   \ =================================
 3160   \ On entry, &F8/9=>command string
 3170   \
 3180   \ Tube data  &02 string &0D  --  &7F or &80
 3190   \
 3200   .osCLI_IO
 3210   LDA #&02:JSR SendCommand   :\ Send command &02 - OSCLI
 3220   JSR SendStringF8           :\ Send command string at &F8/9
 3230   .osCLI_Ack
 3240   JSR WaitByte               :\ Wait for acknowledgement
 3250   CMP #&80:BEQ LFA5C         :\ Jump if code to be entered
 3260   PLA:RTS                    :\ Restore A and return
 3270   
 3280   
 3290   \ *GO - call machine code
 3300   \ -----------------------
 3310   .CmdGO
 3320   AND #&DF                   :\ Ignore case
 3330   CMP #ASC"O":BNE osCLI_IO   :\ Not '*GO', jump to pass to Tube
 3340   JSR SkipSpaces1            :\ Move past any spaces
 3350   JSR ScanHex:JSR SkipSpaces :\ Read hex value and move past spaces
 3360   CMP #&0D:BNE osCLI_IO      :\ More parameters, pass to Tube to deal with
 3370   TXA:BEQ LFA5C              :\ If no address given, jump to current program
 3380   LDA &F0:STA &F6            :\ Set program start to address read
 3390   LDA &F1:STA &F7
 3400   
 3410   .LFA5C
 3420   LDA &EF:PHA:LDA &EE:PHA    :\ Save current program
 3430   JSR EnterCode
 3440   PLA:STA &EE:STA &F2        :\ Restore current program and
 3450   PLA:STA &EF:STA &F3        :\  set address top of memory to it
 3460   PLA:RTS
 3470   
 3480   .CheckAck
 3490   BEQ osCLI_Ack
 3500   
 3510   
 3520   \ OSBYTE - Byte MOS functions
 3530   \ ===========================
 3540   \ On entry, A, X, Y=OSBYTE parameters
 3550   \ On exit,  A  preserved
 3560   \           If A<&80, X=returned value
 3570   \           If A>&7F, X, Y, Carry=returned values
 3580   \
 3590   .osBYTE
 3600   CMP #&80:BCS ByteHigh      :\ Jump for long OSBYTEs
 3610   \
 3620   \ Tube data  &04 X A    --  X
 3630   \
 3640   PHA:LDA #&04
 3650   .LFA7A
 3660   BIT TubeS2:BVC LFA7A       :\ Wait for Tube R2 free
 3670   STA TubeR2                 :\ Send command &04 - OSBYTELO
 3680   .LFA82
 3690   BIT TubeS2:BVC LFA82       :\ Wait for Tube R2 free
 3700   STX TubeR2:PLA             :\ Send single parameter
 3710   .LFA8B
 3720   BIT TubeS2:BVC LFA8B       :\ Wait for Tube R2 free
 3730   STA TubeR2                 :\ Send function
 3740   .LFA93
 3750   BIT TubeS2:BPL LFA93       :\ Wait for Tube R2 data present
 3760   LDX TubeR2:RTS             :\ Get return value
 3770   
 3780   .ByteHigh
 3790   CMP #&82:BEQ Byte82        :\ Read memory high word
 3800   CMP #&83:BEQ Byte83        :\ Read bottom of memory
 3810   CMP #&84:BEQ Byte84        :\ Read top of memory
 3820   \
 3830   \ Tube data  &06 X Y A  --  Cy Y X
 3840   \
 3850   PHA:LDA #&06
 3860   .LFAAB
 3870   BIT TubeS2:BVC LFAAB       :\ Wait for Tube R2 free
 3880   STA TubeR2                 :\ Send command &06 - OSBYTEHI
 3890   .LFAB3
 3900   BIT TubeS2:BVC LFAB3       :\ Wait for Tube R2 free
 3910   STX TubeR2                 :\ Send parameter 1
 3920   .LFABB
 3930   BIT TubeS2:BVC LFABB       :\ Wait for Tube R2 free
 3940   STY TubeR2                 :\ Send parameter 2
 3950   PLA
 3960   .LFAC4
 3970   BIT TubeS2:BVC LFAC4       :\ Wait for Tube R2 free
 3980   STA TubeR2                 :\ Send function
 3990   CMP #&8E:BEQ CheckAck      :\ If select language, check to enter code
 4000   CMP #&9D:BEQ LFAEF         :\ Fast return with Fast BPUT
 4010   PHA                        :\ Save function
 4020   .LFAD5
 4030   BIT TubeS2:BPL LFAD5       :\ Wait for Tube R2 data present
 4040   LDA TubeR2:ASL A:PLA       :\ Get Carry
 4050   .LFADF
 4060   BIT TubeS2:BPL LFADF       :\ Wait for Tube R2 data present
 4070   LDY TubeR2                 :\ Get return high byte
 4080   .LFAE7
 4090   BIT TubeS2:BPL LFAE7       :\ Wait for Tube R2 data present
 4100   LDX TubeR2                 :\ Get return low byte
 4110   .LFAEF
 4120   RTS
 4130   
 4140   .Byte84:LDX &F2:LDY &F3:RTS   :\ Read top of memory from &F2/3
 4150   .Byte83:LDX #&00:LDY #&10:RTS :\ Read bottom of memory
 4160   .Byte82:LDX #&00:LDY #&00:RTS :\ Return &0000 as memory high word
 4170   
 4180   
 4190   \ OSWORD - Various functions
 4200   \ ==========================
 4210   \ On entry, A =function
 4220   \           XY=>control block
 4230   \
 4240   .osWORD
 4250   STX &F8:STY &F9            :\ &F8/9=>control block
 4260   TAY:BEQ RDLINE             :\ OSWORD 0, jump to read line
 4270   PHA:LDY #&08
 4280   .LFB09
 4290   BIT TubeS2:BVC LFB09       :\ Loop until Tube R2 free
 4300   STY TubeR2                 :\ Send command &08 - OSWORD
 4310   .LFB11
 4320   BIT TubeS2:BVC LFB11       :\ Loop until Tube R2 free
 4330   STA TubeR2                 :\ Send function
 4340   TAX:BPL WordSendLow        :\ Jump with functions<&80
 4350   LDY #&00:LDA (&F8),Y       :\ Get send block length from control block
 4360   TAY:JMP WordSend           :\ Jump to send control block
 4370   
 4380   .WordSendLow
 4390   LDY WordLengthsLo-1,X      :\ Get send block length from table
 4400   CPX #&15:BCC WordSend      :\ Use this length for OSWORD 1 to &14
 4410   LDY #&10                   :\ Send 16 bytes for OSWORD &15 to &7F
 4420   .WordSend
 4430   BIT TubeS2:BVC WordSend    :\ Wait until Tube R2 free
 4440   STY TubeR2                 :\ Send send block length
 4450   DEY:BMI LFB45              :\ Zero or &81..&FF length, nothing to send
 4460   .LFB38
 4470   BIT TubeS2:BVC LFB38       :\ Wait for Tube R2 free
 4480   LDA (&F8),Y:STA TubeR2     :\ Send byte from control block
 4490   DEY:BPL LFB38              :\ Loop for number to be sent
 4500   .LFB45
 4510   TXA:BPL WordRecvLow        :\ Jump with functions<&80
 4520   LDY #&01:LDA (&F8),Y       :\ Get receive block length from control block
 4530   TAY:JMP WordRecv           :\ Jump to receive control block
 4540   
 4550   .WordRecvLow
 4560   LDY WordLengthsHi-1,X      :\ Get receive length from table
 4570   CPX #&15:BCC WordRecv      :\ Use this length for OSWORD 1 to &14
 4580   LDY #&10                   :\ Receive 16 bytes for OSWORD &15 to &7F
 4590   .WordRecv
 4600   BIT TubeS2:BVC WordRecv    :\ Wait for Tube R2 free
 4610   STY TubeR2                 :\ Send receive block length
 4620   DEY:BMI LFB71              :\ Zero of &81..&FF length, nothing to receive
 4630   .LFB64
 4640   BIT TubeS2:BPL LFB64       :\ Wait for Tube R2 data present
 4650   LDA TubeR2:STA (&F8),Y     :\ Get byte to control block
 4660   DEY:BPL LFB64              :\ Loop for number to receive
 4670   .LFB71
 4680   LDY &F9:LDX &F8:PLA        :\ Restore registers
 4690   RTS
 4700   
 4710   
 4720   \ RDLINE - Read a line of text
 4730   \ ============================
 4740   \ On entry, A =0
 4750   \           XY=>control block
 4760   \ On exit,  A =undefined
 4770   \           Y =length of returned string
 4780   \           Cy=0 ok, Cy=1 Escape
 4790   \
 4800   \ Tube data  &0A block  --  &FF or &7F string &0D
 4810   \
 4820   .RDLINE
 4830   LDA #&0A:JSR SendCommand   :\ Send command &0A - RDLINE
 4840   LDY #&04
 4850   .LFB7E
 4860   BIT TubeS2:BVC LFB7E       :\ Wait for Tube R2 free
 4870   LDA (&F8),Y:STA TubeR2     :\ Send control block
 4880   DEY:CPY #&01:BNE LFB7E     :\ Loop for 4, 3, 2
 4890   LDA #&07:JSR SendByte      :\ Send &07 as address high byte
 4900   LDA (&F8),Y:PHA            :\ Get text buffer address high byte
 4910   DEY
 4920   .LFB96
 4930   BIT TubeS2:BVC LFB96       :\ Wait for Tube R2 free
 4940   STY TubeR2                 :\ Send &00 as address low byte
 4950   LDA (&F8),Y:PHA            :\ Get text buffer address low byte
 4960   LDX #&FF:JSR WaitByte      :\ Wait for response
 4970   CMP #&80:BCS RdLineEscape  :\ Jump if Escape returned
 4980   PLA:STA &F8:PLA:STA &F9    :\ Set &F8/9=>text buffer
 4990   LDY #&00
 5000   .RdLineLp
 5010   BIT TubeS2:BPL RdLineLp    :\ Wait for Tube R2 data present
 5020   LDA TubeR2:STA (&F8),Y     :\ Store returned character
 5030   INY:CMP #&0D:BNE RdLineLp  :\ Loop until <cr>
 5040   LDA #&00:DEY:CLC:INX       :\ Return A=0, Y=len, X=00, Cy=0
 5050   RTS
 5060   :
 5070   .RdLineEscape
 5080   PLA:PLA:LDA #&00           :\ Return A=0, Y=len, X=FF, Cy=1
 5090   RTS
 5100   
 5110   
 5120   \ OSARGS - Read info on open file
 5130   \ ===============================
 5140   \ On entry, A =function
 5150   \           X =>data word in zero page
 5160   \           Y =handle
 5170   \ On exit,  A =returned value
 5180   \           X  preserved
 5190   \           Y  preserved
 5200   \
 5210   \ Tube data  &0C handle block function  --  result block
 5220   \
 5230   .osARGS
 5240   PHA:LDA #&0C:JSR SendCommand :\ Send command &0C - OSARGS
 5250   .LFBD2
 5260   BIT TubeS2:BVC LFBD2       :\ Loop until Tube R2 free
 5270   STY TubeR2                 :\ Send handle
 5280   LDA &03,X:JSR SendByte     :\ Send data word
 5290   LDA &02,X:JSR SendByte
 5300   LDA &01,X:JSR SendByte
 5310   LDA &00,X:JSR SendByte
 5320   PLA:JSR SendByte           :\ Send function
 5330   JSR WaitByte:PHA           :\ Get and save result
 5340   JSR WaitByte:STA &03,X     :\ Receive data word
 5350   JSR WaitByte:STA &02,X
 5360   JSR WaitByte:STA &01,X
 5370   JSR WaitByte:STA &00,X
 5380   PLA:RTS                    :\ Get result back and return
 5390   
 5400   
 5410   \ OSFIND - Open file
 5420   \ ------------------
 5430   \ On entry,  X=>zero page
 5440   \               X+0/1=file name
 5450   \           CS=Open file for input
 5460   \           CC=Open file for output
 5470   \ On exit,   A=file handle, 0 if file not found
 5480   \          X,Y=preserved
 5490   .atomFIND
 5500   PHA                 :\ Space for returned A
 5510   TYA:PHA:TXA:PHA     :\ Save X,Y
 5520   LDA 1,X:TAY         :\ XY=>filename
 5530   LDA 0,X:TAX
 5540                       :\ Create OSFIND action
 5550   LDA #0              :\ A=00, CS  CC
 5560   PHP:ROR A:PLP:ROR A :\       C0  00
 5570   EOR #&80            :\       40  80
 5580   JSR osFIND          :\ Pass OSFIND to host
 5590   TSX:STA &103,X      :\ Store on stack
 5600   PLA:TAX:PLA:TAY     :\ Restore X,Y
 5610   PLA:RTS             :\ Get handle and return
 5620   
 5630   \ OSSHUT - Close a file
 5640   \ ---------------------
 5650   \ On entry,  Y=file handle
 5660   \ On exit,   all preserved
 5670   .atomSHUT
 5680   PHA:LDA #0          :\ OSFIND &00 - Close
 5690   JSR osFIND          :\ Pass OSFIND to host
 5700   PLA:RTS
 5710   
 5720   
 5730   \ OSFIND - Open of Close a file
 5740   \ =============================
 5750   \ On entry, A =function
 5760   \           Y =handle or XY=>filename
 5770   \ On exit,  A =zero or handle
 5780   \
 5790   \ Tube data  &12 function string &0D  --  handle
 5800   \            &12 &00 handle  --  &7F
 5810   \
 5820   .osFIND
 5830   PHA:LDA #&12:JSR SendCommand :\ Send command &12 - OSFIND
 5840   PLA:JSR SendByte             :\ Send function
 5850   CMP #&00:BNE OPEN            :\ If <>0, jump to do OPEN
 5860   PHA:TYA:JSR SendByte         :\ Send handle
 5870   JSR WaitByte:PLA:RTS         :\ Wait for acknowledge, restore regs and return
 5880   .OPEN
 5890   JSR SendString               :\ Send pathname
 5900   JMP WaitByte                 :\ Wait for and return handle
 5910   
 5920   
 5930   \ OSBGET - Get a byte from open file
 5940   \ ==================================
 5950   \ On entry, Y =handle
 5960   \ On exit,  A =byte Read
 5970   \           Y =preserved
 5980   \           Cy set if EOF
 5990   \
 6000   \ Tube data  &0E handle --  Carry byte
 6010   \
 6020   .osBGET:.atomBGET
 6030   LDA #&0E:JSR SendCommand   :\ Send command &0E - OSBGET
 6040   TYA:JSR SendByte           :\ Send handle
 6050   JMP WaitCarryChar          :\ Jump to wait for Carry and byte
 6060   
 6070   
 6080   \ OSBPUT - Put a byte to an open file
 6090   \ ===================================
 6100   \ On entry, A =byte to write
 6110   \           Y =handle
 6120   \ On exit,  A =preserved
 6130   \           Y =preserved
 6140   \
 6150   \ Tube data  &10 handle byte  --  &7F
 6160   \
 6170   .osBPUT:.atomBPUT
 6180   PHA:LDA #&10:JSR SendCommand :\ Send command &10 - OSBPUT
 6190   TYA:JSR SendByte             :\ Send handle
 6200   PLA:JSR SendByte             :\ Send byte
 6210   PHA:JSR WaitByte:PLA:RTS     :\ Wait for acknowledge and return
 6220   
 6230   
 6240   \ Send a byte to Tube R2
 6250   \ ======================
 6260   .SendCommand
 6270   .SendByte
 6280   BIT TubeS2:BVC SendByte    :\ Wait for Tube R2 free
 6290   STA TubeR2:RTS             :\ Send byte to Tube R2
 6300   
 6310   
 6320   \ OSLOAD - Load a file
 6330   \ --------------------
 6340   \ On entry,  X=>zero page
 6350   \               X+0/1=>file name
 6360   \               X+2/3=Load address
 6370   \               X+4  =if bit 7=0 use the file's start address
 6380   \           CC=Return immediately
 6390   \           CS=Wait until IRQ/DMA actions completed
 6400   \ On exit,   all preserved
 6410   \
 6420   .atomLOAD
 6430   LDA #&FF:BNE doFILE
 6440   
 6450   \ OSSAVE - Save a file
 6460   \ --------------------
 6470   \ On entry,  X=>zero page
 6480   \               X+0/1=file name
 6490   \               X+2/3=load address
 6500   \               X+4/5=execution address
 6510   \               X+6/7=start address of data to save
 6520   \               X+8/9=(end address)+1 of data to save
 6530   \           CC=Return immediately
 6540   \           CS=Wait until IRQ/DMA actions completed
 6550   \ On exit,   all preserved
 6560   .atomSAVE
 6570   LDA #&00
 6580   .doFILE
 6590   PHA
 6600   TYA:PHA:TXA:PHA
 6610   LDA 0,X:STA &2EE    :\ =>filename
 6620   LDA 1,X:STA &2EF
 6630   LDY #0
 6640   .doFILElp
 6650   LDA 2,X:STA &2F0,Y:INX:INY
 6660   LDA 2,X:STA &2F0,Y:INX:INY
 6670   LDA #0              :\ Expand control block
 6680   STA &2F0,Y:INY
 6690   STA &2F0,Y:INY
 6700   CPY #16:BNE doFILElp
 6710   TSX:LDA &103,X      :\ Get OSFILE action
 6720   CMP #&FF:BNE callFILE
 6730   LDA &2F4:EOR #&FF
 6740   STA &2F4:LDA #&FF
 6750   .callFILE
 6760   LDX #&EE:LDY #&02   :\ Point to control block
 6770   JSR osFILE          :\ Pass OSFILE to host
 6780   TSX:STA &103,X      :\ Store return value on stack
 6790   PLA:TAX:PLA:TAY     :\ Restore registers
 6800   PLA:RTS             :\ Get return value and return
 6810   
 6820   
 6830   \ OSFILE - Operate on whole files
 6840   \ ===============================
 6850   \ On entry, A =function
 6860   \           XY=>control block
 6870   \ On exit,  A =result
 6880   \           control block updated
 6890   \
 6900   \ Tube data  &14 block string <cr> function  --  result block
 6910   \
 6920   .osFILE
 6930   STY &FB:STX &FA              :\ &FA/B=>control block
 6940   PHA:LDA #&14:JSR SendCommand :\ Send command &14 - OSFILE
 6950   LDY #&11
 6960   .LFC5F
 6970   LDA (&FA),Y:JSR SendByte   :\ Send control block
 6980   DEY:CPY #&01:BNE LFC5F     :\ Loop for &11..&02
 6990   DEY:LDA (&FA),Y:TAX
 7000   INY:LDA (&FA),Y:TAY        :\ Get pathname address to XY
 7010   JSR SendString             :\ Send pathname
 7020   PLA:JSR SendByte           :\ Send function
 7030   JSR WaitByte:PHA           :\ Wait for result
 7040   LDY #&11
 7050   .LFC7E
 7060   JSR WaitByte:STA (&FA),Y   :\ Get control block back
 7070   DEY:CPY #&01:BNE LFC7E     :\ Loop for &11..&02
 7080   LDY &FB:LDX &FA            :\ Restore registers
 7090   PLA:RTS                    :\ Get result and return
 7100   
 7110   
 7120   \ OSGBPB - Multiple byte Read and write
 7130   \ =====================================
 7140   \ On entry, A =function
 7150   \           XY=>control block
 7160   \ On exit,  A =returned value
 7170   \              control block updated
 7180   \
 7190   \ Tube data  &16 block function  --   block Carry result
 7200   \
 7210   .osGBPB
 7220   STY &FB:STX &FA              :\ &FA/B=>control block
 7230   PHA:LDA #&16:JSR SendCommand :\ Send command &16 - OSGBPB
 7240   LDY #&0C
 7250   .LFC9A
 7260   LDA (&FA),Y:JSR SendByte   :\ Send control block
 7270   DEY:BPL LFC9A              :\ Loop for &0C..&00
 7280   PLA:JSR SendByte           :\ Send function
 7290   LDY #&0C
 7300   .LFCA8
 7310   JSR WaitByte:STA (&FA),Y   :\ Get control block back
 7320   DEY:BPL LFCA8              :\ Loop for &0C..&00
 7330   LDY &FB:LDX &FA            :\ Restore registers
 7340   JMP WaitCarryChar          :\ Jump to get Carry and result
 7350   
 7360   
 7370   \ OSWORD control block lengths
 7380   \ ============================
 7390   .WordLengthsLo
 7400   EQUB &00:EQUB &05:EQUB &00:EQUB &05
 7410   EQUB &04:EQUB &05:EQUB &08:EQUB &0E :\ ** Different, 6502 TUBE sends only 2 bytes for =IO
 7420   EQUB &04:EQUB &01:EQUB &01:EQUB &05
 7430   EQUB &00:EQUB &01:EQUB &20:EQUB &10
 7440   EQUB &0D:EQUB &00:EQUB &04:EQUB &80
 7450   .WordLengthsHi
 7460   EQUB &05:EQUB &00:EQUB &05:EQUB &00
 7470   EQUB &05:EQUB &00:EQUB &00:EQUB &00
 7480   EQUB &05:EQUB &09:EQUB &05:EQUB &00
 7490   EQUB &08:EQUB &18:EQUB &00:EQUB &01
 7500   EQUB &0D:EQUB &80:EQUB &04:EQUB &80
 7510   
 7520   
 7530   \ Interrupt Handler
 7540   \ =================
 7550   .InterruptHandler
 7560   STA &FC:PLA:PHA            :\ Save A, get flags from stack
 7570   AND #&10:BNE BRKHandler    :\ If BRK, jump to BRK handler
 7580   :
 7590   BIT TubeS4:BMI LFD3F       :\ If data in Tube R4, jump to process errors and transferes
 7600   BIT TubeS1:BMI LFD18       :\ If data in Tube R1, jump to process Escape and Events
 7610   LDA &FC:PHA:JMP (irq1v)    :\ Pass on to IRQ1V
 7620   
 7630   .BRKHandler
 7640   LDA &FC:PLP:PHP:JMP (brkv) :\ Restore A and flags, jump to BRK handler
 7650   
 7660   
 7670   \ Interrupt generated by data in Tube R1
 7680   \ --------------------------------------
 7690   .LFD18
 7700   LDA TubeR1:BMI LFD39       :\ b7=1, jump to set Escape state
 7710   TYA:PHA:TXA:PHA            :\ Save registers
 7720   JSR LFE80:TAY              :\ Get Y parameter from Tube R1
 7730   JSR LFE80:TAX              :\ Get X parameter from Tube R1
 7740   JSR LFE80                  :\ Get event number from Tube R1
 7750   JSR LFD36:PLA:TAX:PLA:TAY  :\ Dispatch event, restore registers
 7760   LDA &FC:RTI                :\ Restore A, return from interrupt
 7770   .LFD36
 7780   JMP (EVNTV)
 7790   .LFD39
 7800   ASL A:STA &FF              :\ Set Escape flag from b6
 7810   LDA &FC:RTI                :\ Restore A, return from interrupt
 7820   
 7830   
 7840   \ Interrupt generated by data in Tube R4
 7850   \ --------------------------------------
 7860   .LFD3F
 7870   LDA TubeR4:BPL LFD65       :\ b7=0, jump for data transfer
 7880   CLI
 7890   .LFD45
 7900   BIT TubeS2:BPL LFD45       :\ Wait for data in Tube R2
 7910   LDA TubeR2
 7920   LDA #&00:STA ERRBUF:TAY    :\ Store BRK opcode in error buffer
 7930   JSR WaitByte:STA ERRBUF+1  :\ Get error number
 7940   .LFD59
 7950   INY:JSR WaitByte           :\ Store bytes fetched from Tube R2
 7960   STA ERRBUF+1,Y:BNE LFD59   :\ Loop until final zero
 7970   JMP ERRBUF                 :\ Jump to error block to generate error
 7980   
 7990   \ Data transfer initiated by IRQ via Tube R4
 8000   \ ------------------------------------------
 8010   .LFD65
 8020   STA NMIV+0:TYA:PHA         :\ Save transfer type, save Y
 8030   LDY NMIV+0                 :\ Get transfer type back
 8040   LDA LFE70,Y:STA NMIV+0     :\ get NMI routine address from table
 8050   LDA LFE78,Y:STA NMIV+1     :\ and point NMIV to it
 8060   LDA LFE60,Y:STA &F4        :\ Point &F4/5 to transfer address field
 8070   LDA LFE68,Y:STA &F5
 8080   .LFD83
 8090   BIT TubeS4:BPL LFD83       :\ Wait until Tube R4 data present
 8100   LDA TubeR4                 :\ Get called ID from Tube R4
 8110   CPY #&05:BEQ LFDE7         :\ If 'TubeRelease', jump to exit
 8120   TYA:PHA:LDY #&01           :\ Save transfer type
 8130   .LFD93
 8140   BIT TubeS4:BPL LFD93       :\ Wait for Tube R4 data present
 8150   LDA TubeR4                 :\ Fetch and disgard address byte 4
 8160   .LFD9B
 8170   BIT TubeS4:BPL LFD9B       :\ Wait for Tube R4 data present
 8180   LDA TubeR4                 :\ Fetch and disgard address byte 3
 8190   .LFDA3
 8200   BIT TubeS4:BPL LFDA3       :\ Wait for Tube R4 data present
 8210   LDA TubeR4:STA (&F4),Y:DEY :\ Fetch address byte 2, store in address
 8220   .LFDAE
 8230   BIT TubeS4:BPL LFDAE       :\ Wait for Tube R4 data present
 8240   LDA TubeR4:STA (&F4),Y     :\ Fetch address byte 1, store in address
 8250   BIT TubeR3:BIT TubeR3      :\ Read from Tube R3 twice
 8260   .LFDBE
 8270   BIT TubeS4:BPL LFDBE       :\ Wait for Tube R4 data present
 8280   LDA TubeR4:PLA             :\ Get sync byte from Tube R4
 8290   CMP #&06:BCC LFDE7         :\ Exit if not 256-byte transfers
 8300   BNE LFDEC                  :\ Jump with 256-byte read
 8310   
 8320   \ Send 256 bytes to Tube via R3
 8330   \ -----------------------------
 8340   LDY #&00
 8350   .LFDCF
 8360   LDA TubeS3:AND #&80:BPL LFDCF:\ Wait for Tube R3 free
 8370   .NMI6Addr
 8380   LDA &FFFF,Y:STA TubeR3     :\ Fetch byte and send to Tube R3
 8390   INY:BNE LFDCF              :\ Loop for 256 bytes
 8400   .LFDDF
 8410   BIT TubeS3:BPL LFDDF       :\ Wait for Tube R3 free
 8420   STA TubeR3                 :\ Send final sync byte
 8430   .LFDE7
 8440   PLA:TAY:LDA &FC:RTI        :\ Restore registers and return
 8450   
 8460   \ Read 256 bytes from Tube via R3
 8470   \ -------------------------------
 8480   .LFDEC
 8490   LDY #&00
 8500   .LFDEE
 8510   LDA TubeS3:AND #&80:BPL LFDEE:\ Wait for Tube R3 data present
 8520   LDA TubeR3                 :\ Fetch byte from Tube R3
 8530   .NMI7Addr
 8540   STA &FFFF,Y:INY:BNE LFDEE  :\ Store byte and loop for 256 bytes
 8550   BEQ LFDE7                  :\ Jump to restore registers and return
 8560   
 8570   \ Transfer 0 - Transfer single byte to Tube
 8580   \ -----------------------------------------
 8590   .NMI0
 8600   PHA                        :\ Save A
 8610   .NMI0Addr
 8620   LDA &FFFF:STA TubeR3       :\ Get byte and send to Tube R3
 8630   INC NMI0Addr+1:BNE LFE0F   :\ Increment transfer address
 8640   INC NMI0Addr+2
 8650   .LFE0F
 8660   .NullIRQ
 8670   PLA:RTI                    :\ Restore A and return
 8680   
 8690   \ Transfer 1 - Transfer single byte from Tube
 8700   \ -------------------------------------------
 8710   .NMI1
 8720   PHA:LDA TubeR3             :\ Save A, get byte from Tube R3
 8730   .NMI1Addr
 8740   STA &FFFF                  :\ Store byte
 8750   INC NMI1Addr+1:BNE LFE20   :\ Increment transfer address
 8760   INC NMI1Addr+2
 8770   .LFE20
 8780   PLA:RTI                    :\ Restore A and return
 8790   
 8800   \ Transfer 2 - Transfer two bytes to Tube
 8810   \ ---------------------------------------
 8820   .NMI2
 8830   PHA:TYA:PHA:LDY #&00       :\ Save registers
 8840   LDA (&F6),Y:STA TubeR3     :\ Get byte and send to Tube R3
 8850   INC &F6:BNE LFE32:INC &F7  :\ Increment transfer address
 8860   .LFE32
 8870   LDA (&F6),Y:STA TubeR3     :\ Get byte and send to Tube R3
 8880   INC &F6:BNE LFE3D:INC &F7  :\ Increment transfer address
 8890   .LFE3D
 8900   PLA:TAY:PLA:RTI            :\ Restore registers and return
 8910   
 8920   \ Transfer 3 - Transfer two bytes from Tube
 8930   \ -----------------------------------------
 8940   .NMI3
 8950   PHA:TYA:PHA:LDY #&00       :\ Save registers
 8960   LDA TubeR3:STA (&F6),Y     :\ Get byte from Tube R3 and store
 8970   INC &F6:BNE LFE51:INC &F7  :\ Increment transfer address
 8980   .LFE51
 8990   LDA TubeR3:STA (&F6),Y     :\ Get byte from Tube R3 and store
 9000   INC &F6:BNE LFE5C:INC &F7  :\ Increment transfer address
 9010   .LFE5C
 9020   PLA:TAY:PLA:RTI            :\ Restore registers and return
 9030   
 9040   \ Data transfer address pointers
 9050   \ ------------------------------
 9060   .LFE60
 9070   EQUB (NMI0Addr+1) AND 255:EQUB (NMI1Addr+1) AND 255
 9080   EQUB &00F6 AND 255       :EQUB &00F6 AND 255
 9090   EQUB &00F6 AND 255       :EQUB &00F6 AND 255
 9100   EQUB (NMI6Addr+1) AND 255:EQUB (NMI7Addr+1) AND 255
 9110   .LFE68
 9120   EQUB (NMI0Addr+1) DIV 256:EQUB (NMI1Addr+1) DIV 256
 9130   EQUB &00F6 DIV 256       :EQUB &00F6 DIV 256
 9140   EQUB &00F6 DIV 256       :EQUB &00F6 DIV 256
 9150   EQUB (NMI6Addr+1) DIV 256:EQUB (NMI7Addr+1) DIV 256
 9160   
 9170   \ Data transfer routine addresses
 9180   \ -------------------------------
 9190   .LFE70
 9200   EQUB NMI0 AND 255   :EQUB NMI1 AND 255
 9210   EQUB NMI2 AND 255   :EQUB NMI3 AND 255
 9220   EQUB NMI_Ack AND 255:EQUB NMI_Ack AND 255
 9230   EQUB NMI_Ack AND 255:EQUB NMI_Ack AND 255
 9240   .LFE78
 9250   EQUB NMI0 DIV 256   :EQUB NMI1 DIV 256
 9260   EQUB NMI2 DIV 256   :EQUB NMI3 DIV 256
 9270   EQUB NMI_Ack DIV 256:EQUB NMI_Ack DIV 256
 9280   EQUB NMI_Ack DIV 256:EQUB NMI_Ack DIV 256
 9290   
 9300   
 9310   \ Wait for byte in Tube R1 while allowing requests via Tube R4
 9320   \ ============================================================
 9330   .LFE80
 9340   BIT TubeS1:BMI LFE94       :\ If data in Tube R1, jump to fetch it
 9350   .LFE85
 9360   BIT TubeS4                 :\ Check if data present in Tube R4
 9370   BPL LFE80                  :\ If nothing there, jump back to check Tube R1
 9380   LDA &FC                    :\ Save IRQ's A store in A register
 9390   PHP:CLI:PLP                :\ Allow an IRQ through to process R4 request
 9400   STA &FC:JMP LFE80          :\ Restore IRQ's A store and jump back to check R1
 9410   .LFE94
 9420   LDA TubeR1:RTS             :\ Fetch byte from Tube R1 and return
 9430   
 9440   
 9450   \ Spare space
 9460   \ ===========
 9470   EQUS STRING$(IOADDR-P%,CHR$255)
 9480   
 9490   
 9500   \ I/O Space
 9510   \ =========
 9520   EQUS STRING$(IOTUBE-P%,CHR$0)
 9530   
 9540   \ Tube I/O Registers
 9550   \ ==================
 9560   .TubeS1 :\ &FEF8 :EQUB 0
 9570   .TubeR1 :\ &FEF9 :EQUB 0
 9580   .TubeS2 :\ &FEFA :EQUB 0
 9590   .TubeR2 :\ &FEFB :EQUB 0
 9600   .TubeS3 :\ &FEFC :EQUB 0
 9610   .TubeR3 :\ &FEFD :EQUB 0
 9620   .TubeS4 :\ &FEFE :EQUB 0
 9630   .TubeR4 :\ &FEFF :EQUB 0
 9640   
 9650   .LFF00
 9660   \ Print embedded string
 9670   \ =====================
 9680   .PrText
 9690   PLA:STA &FA:PLA:STA &FB    :\ &FA/B=>embedded string
 9700   LDY #&00
 9710   .LFEA0
 9720   INC &FA:BNE LFEA6:INC &FB  :\ Increment address
 9730   .LFEA6
 9740   LDA (&FA),Y:BMI LFEB0      :\ Get character, exit if >&7F
 9750   JSR OSWRCH:JMP LFEA0       :\ Print character and loop back for more
 9760   .LFEB0
 9770   JMP (&00FA)                :\ Jump back to code after string
 9780   
 9790   \ Print hex
 9800   \ =========
 9810   .Pr2Hex
 9820   TYA:JSR PrHex:TXA
 9830   .PrHex
 9840   PHA:LSR A:LSR A:LSR A:LSR A
 9850   JSR PrNyb:PLA
 9860   .PrNyb
 9870   AND #15:CMP #10:BCC P%+4
 9880   ADC #6:ADC #48:JMP OSWRCH
 9890   
 9900   \ OSRDAR - Read file's arguments
 9910   \ ------------------------------
 9920   \ On entry,  X=>zero page location
 9930   \            Y=handle
 9940   \            A=0 - read PTR
 9950   \            A=1 - read EXT
 9960   \            A=2 - read allocation
 9970   \ On exit,   X+0-X+3 = returned argument
 9980   \            A,X,Y preserved
 9990   .atomRDAR
10000   PHA:CLC:BCC doARGS  :\ Jump to do even-numbered OSARGS
10010   
10020   \ OSSTAR - Set file's arguments
10030   \ -----------------------------
10040   \ On entry,  X=>zero page location
10050   \            Y=handle
10060   \            A=0 - write PTR (usually, A=unset)
10070   \            X+0-X+3 = argument
10080   \ On exit,   A,X,Y preserved
10090   .atomSTAR
10100   PHA:LDA #0:SEC      :\ Do odd-numbered OSARGS
10110   .doARGS
10120   ROL A:JSR osARGS    :\ Convert to OSARGS action
10130   PLA:RTS
10140   
10150   \ Null NMI code
10160   \ -------------
10170   .NMI_Ack
10180   STA TubeR3:RTI             :\ Store to TubeR3 to acknowlege NMI
10190   
10200   .Unsupported
10210   BRK:EQUB 255:EQUS "Bad":EQUB 0
10220   
10230   
10240   \ Copy of BBC MOS API entry block
10250   \ ===============================
10260   EQUS STRING$(&FF4E-P%,CHR$0)
10270   .XOSFIND  :\ &FF4E  :JMP osFIND
10280   .XOSGBPB  :\ &FF51  :JMP osGBPB
10290   .XOSBPUT  :\ &FF54  :JMP osBPUT
10300   .XOSBGET  :\ &FF57  :JMP osBGET
10310   .XOSARGS  :\ &FF5A  :JMP osARGS
10320   .XOSFILE  :\ &FF5D  :JMP osFILE
10330   
10340   .XOSRDCH  :\ &FF60  :JMP osRDCH
10350   .XOSASCI  :\ &FF63  :CMP #&0D:BNE XOSWRCH
10360   .XOSNEWL  :\ &FF67  :LDA #&0A:JSR XOSWRCH
10370   .XOSPRCR  :\ &FF6C  :LDA #&0D
10380   .XOSWRCH  :\ &FF6E  :JMP osWRCH
10390   .XOSWORD  :\ &FF71  :JMP osWORD
10400   .XOSBYTE  :\ &FF74  :JMP osBYTE
10410   .XOS_CLI  :\ &FF77  :JMP osCLI
10420   
10430   .XNMIV    :\ &FF7A  :EQUW NMI0
10440   .XRESETV  :\ &FF7C  :EQUW RESET
10450   .XIRQV    :\ &FF7E  :EQUW InterruptHandler
10460   
10470   
10480   DEFAULT VECTOR TABLE
10490   \ ====================
10500   .VECTABLE
10510   EQUW NullIRQ          :\ &200 - nmiv
10520   EQUW ErrorHandler     :\ &202 - brkv
10530   EQUW NullIRQ          :\ &204 - irq1v
10540   EQUW atomCLI          :\ &206 - cliv
10550   EQUW atomWRCH         :\ &208 - wrchv
10560   EQUW atomRDCH         :\ &20A - rdchv
10570   EQUW atomLOAD         :\ &20C - loadv
10580   EQUW atomSAVE         :\ &20E - savev
10590   EQUW atomRDAR         :\ &210 - rdarv
10600   EQUW atomSTAR         :\ &212 - starv
10610   EQUW atomBGET         :\ &214 - bgetv
10620   EQUW atomBPUT         :\ &216 - bputv
10630   EQUW atomFIND         :\ &218 - findv
10640   EQUW atomSHUT         :\ &21A - shutv
10650   EQUW NullReturn       :\ &21C - v21C
10660   EQUW NullReturn       :\ &21E - v21E
10670   EQUW NullReturn       :\ &220 - EVNTV
10680   EQUW Unsupported      :\ &222 - v222
10690   EQUW Unsupported      :\ &224 - v224
10700   EQUW Unsupported      :\ &226 - v226
10710   EQUW Unsupported      :\ &228 - v228
10720   
10730   
10740   \ Main MOS API entry block
10750   \ ========================
10760   EQUS STRING$(&FFA1-P%,CHR$255)
10770   .LFFAA   :\ &FFAA   :JMP PrHex      :\ Print A in hex
10780   .LFFAD   :\ &FFAD   :JMP Pr2Hex     :\ Print XY in hex
10790   .LFFB0   :\ &FFB0   :JMP NullReturn :\ IRQ stub
10800   .LFFB3   :\ &FFB3   :JMP PrText     :\ Print inline text
10810   .VECDEF  :\ &FFB6   :EQUB &2A:EQUW VECTABLE
10820   .LFFB9   :\ &FFB9   :JMP Unsupported
10830   .LFFBC   :\ &FFBC   :JMP Unsupported
10840   .LFFBF   :\ &FFBF   :JMP NullReturn :\ Reset vectors, etc.
10850   .LFFC2   :\ &FFC2   :JMP Unsupported
10860   .LFFC5   :\ &FFC5   :JMP Unsupported
10870   .LFFC8   :\ &FFC8   :JMP Unsupported
10880   
10890   \ Atom/System Entry Block
10900   \ -----------------------
10910   .OSSHUT  :\ &FFCB   :JMP (shutv)
10920   .OSFIND  :\ &FFCE   :JMP (findv)
10930   .OSBPUT  :\ &FFD1   :JMP (bputv)
10940   .OSBGET  :\ &FFD4   :JMP (bgetv)
10950   .OSSTAR  :\ &FFD7   :JMP (starv)
10960   .OSRDAR  :\ &FFDA   :JMP (rdarv)
10970   .OSSAVE  :\ &FFDD   :JMP (savev)
10980   .OSLOAD  :\ &FFE0   :JMP (loadv)
10990   
11000   .OSRDCH  :\ &FFE3   :JMP (rdchv)
11010   .OSECHO  :\ &FFE6   :JSR OSRDCH
11020   .OSASCI  :\ &FFE9   :CMP #&0D:BNE OSWRCH
11030   .OSNEWL  :\ &FFED   :LDA #&0A:JSR OSWRCH
11040   .OSPRCR  :\ &FFF2   :LDA #&0D
11050   .OSWRCH  :\ &FFF4   :JMP (wrchv)
11060   .OS_CLI  :\ &FFF7   :JMP (cliv)
11070   
11080   \ Hardware vectors
11090   \ ----------------
11100   .NMIV    :\ &FFFA :EQUW NMI0             :\ NMI Vector
11110   .RESETV  :\ &FFFC :EQUW RESET            :\ RESET Vector
11120   .IRQV    :\ &FFFE :EQUW InterruptHandler :\ IRQ Vector
11130 ]:NEXT
11140 OSCLI"Save "+fname$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~load%+" "+STR$~load%
11150 ON ERROR ON ERROR OFF:END
11160 *Quit