10 REM > Mini65/src
   20 REM Source for Tiny 6502 Single-port Tube Client
   30 REM ============================================
   40 REM This code may be freely reused, with acknowledgements
   50 :
   60 REM Tiny 6502 Tube Client in 512 bytes
   70 REM Implements OSWRCH and OSRDCH via a single I/O port.
   80 :
   90 :
  100 REM Boilerplate
  110 REM ===========
  120 IF HIMEM>&FFFF:SYS "OS_GetEnv"TOA$:IFLEFT$(A$,5)<>"B6502":OSCLI"B6502"+MID$(A$,INSTR(A$," "))
  130 ON ERROR REPORT:PRINT" at line ";ERL:END
  140 DEFFNif(A%):IFA%:z%=-1:=opt% ELSE z%=P%:=opt%
  150 DEFFNendif:IFz%=-1:=opt% ELSE z%=P%-z%:P%=P%-z%:O%=O%-z%:=opt%
  160 DEFFNelse:IFz%=-1:z%=P%:=opt% ELSE z%=P%-z%:P%=P%-z%:O%=O%-z%:z%=-1:=opt%
  170 DIM mcode% &1FF, L% &40
  180 :
  190 :
  200 REM Code to enter after RESET
  210 REM =========================
  220 MAIN=&FFB9:REM Replace with address to jump to
  230 :
  240 :
  250 REM Name and version
  260 REM ================
  270 ver$="0.10":date$=" (11 Nov 2016)"
  280 load%=&FE00:name$="Mini65"
  290 :
  300 :
  310 REM System vectors
  320 REM ==============
  330 USERV=&200:BRKV =&202:IRQ1V=&204:IRQ2V=&206:CLIV =&208:BYTEV=&20A
  340 WORDV=&20C:WRCHV=&20E:RDCHV=&210:FILEV=&212:ARGSV=&214:BGetV=&216
  350 BPutV=&218:GBPBV=&21A:FINDV=&21C:FSCV =&21E:EVNTV=&220
  360 TEXT=&FA:IRQA=&FC:FAULT=&FD:ESCFLG=&FF
  370 :
  380 REM I/O values, these are suitable for a 6850
  390 REM =========================================
  400 TxStatus=&FEF0:TxRDY=2:TxData=&FEF1:TxInit=&13:RxStop=&55:REM &13=Reset ACIA, &55=8N1, clock/16, RTS high
  410 RxStatus=&FEF0:RxRDY=1:RxData=&FEF1:RxInit=&55:RxCont=&15:REM &55=RTS high, &15=RTS low
  420 :
  430 REM Serial Tube system values
  440 REM =========================
  450 esc=&9B
  460 :
  470 :
  480 FOR P=0 TO 1:opt%=P*3+4
  490   P%=load%:O%=mcode%
  500   [OPT opt%
  510   .LF800
  520   JMP RESET
  530   .PrBanner
  540   JSR PrText
  550   .BANNER
  560   EQUB 13:EQUS "Tiny 6502 Kernel ":EQUS ver$
  570   EQUB 32:EQUB 13:EQUB 0
  580   RTS
  590   :
  600   \ Tube Client Startup Code
  610   \ ========================
  620   .RESET
  630   SEI:LDX #&35               :\ Disable interupts
  640   .RESETlp
  650   LDA LFF00,X:STA &0200,X    :\ Copy default vectors
  660   DEX:BPL RESETlp:TXS        :\ Clear stack
  670   LDA #TxInit:STA TxStatus   :\ Initialise I/O port
  680   LDA #RxInit:STA RxStatus
  690   LDA #&00:STA ESCFLG:CLI
  700   JSR PrBanner:JSR OSNEWL
  710   LDA #&01:JMP OSCOLD        :\ Enter main program
  720   :
  730   :
  740   \ Default error handler
  750   \ =====================
  760   .ErrorHandler
  770   JSR OSNEWL
  780   LDX FAULT+0:LDY FAULT+1
  790   INX:BNE P%+3:INY           :\ XY=>error string
  800   JSR PRSTRNG                :\ Print error string
  810   .HALT
  820   JMP HALT                   :\ And stop
  830   :
  840   \ Interrupt handlers
  850   \ ==================
  860   .IRQHandler
  870   STA IRQA:PLA:PHA           :\ Save A, get flags from stack
  880   AND #&10:BNE BRKHandler    :\ If BRK, jump to BRK handler
  890   JMP (IRQ1V)                :\ Continue via IRQ1V handler
  900   .IRQ1Handler
  910   JMP (IRQ2V)                :\ Pass on to IRQ2V
  920   .BRKHandler
  930   TXA:PHA                    :\ Save X
  940   TSX:LDA &0103,X:CLD        :\ Get address from stack
  950   SEC:SBC #&01:STA FAULT+0
  960   LDA &0104,X
  970   SBC #&00:STA FAULT+1       :\ &FD/E=>after BRK opcode
  980   PLA:TAX:LDA IRQA           :\ Restore X, get saved A
  990   CLI:JMP (BRKV)             :\ Restore IRQs, jump to Error Handler
 1000   .IRQ2Handler
 1010   LDA IRQA                   :\ Restore A
 1020   .NMIHandler
 1030   RTI                        :\ Return from interupt
 1040   :
 1050   \ OSRDCH - Wait for character from input stream
 1060   \ =============================================
 1070   \ On exit, A =char, Cy=Escape flag
 1080   .osRDCH
 1090   JSR ReadData:BCC osRDCH    :\ Wait for character
 1100   BNE osRDCH2
 1110   .osRDCH1
 1120   JSR ReadData:BCC osRDCH1   :\ Wait for character
 1130   .osRDCH2
 1140   CMP #27:BEQ osRDCH3        :\ Exit with CS if Escape
 1150   .ReadDataNone
 1160   CLC                        :\ CC if not Escape
 1170   .osRDCH3
 1180   RTS
 1190   :
 1200   \ OSWRCH - Send character to output stream
 1210   \ ========================================
 1220   \ On entry, A =character
 1230   .osWRCH                    :\ WRCH is simply SendByte
 1240   .SendByte
 1250   JSR SendData               :\ Send byte
 1260   CMP #esc:BNE SendByteDone  :\ If not esc, done
 1270   \                          :\ Fall through to send again
 1280   :
 1290   :
 1300   \ *** LOW-LEVEL I/O CODE ***
 1310   \ ==========================
 1320   :
 1330   \ Send a raw byte of data
 1340   \ -----------------------
 1350   .SendData
 1360   PHA
 1370   .SendWait
 1380   LDA TxStatus               :\ Get Status
 1390   AND #TxRDY:BEQ SendWait    :\ Wait until data can be sent
 1400   PLA:STA TxData             :\ Send data
 1410   .SendByteDone
 1420   RTS
 1430   :
 1440   \ Read raw data
 1450   \ -------------
 1460   \ On exit, P =CC, no data
 1470   .ReadData
 1480   LDA RxStatus:AND #RxRDY    :\ Get RxStatus
 1490   BNE ReadDataNone           :\ Exit if no data present
 1500   LDA RxData:CMP #esc:SEC:RTS:\ CS=Data present, EQ/NE=esc
 1510   :
 1520   :
 1530   DEFAULT VECTOR TABLE
 1540   \ ====================
 1550   EQUS STRING$((&FF00-P%)AND255,CHR$255)
 1560   .LFF00
 1570   EQUW NullReturn      :\ &200 - USERV
 1580   EQUW ErrorHandler    :\ &202 - BRKV
 1590   EQUW IRQ1Handler     :\ &204 - IRQ1V
 1600   EQUW IRQ2Handler     :\ &206 - IRQ2V
 1610   EQUW NullReturn      :\ &208 - CLIV
 1620   EQUW NullReturn      :\ &20A - BYTEV
 1630   EQUW NullReturn      :\ &20C - WORDV
 1640   EQUW osWRCH          :\ &20E - WRCHV
 1650   EQUW osRDCH          :\ &210 - RDCHV
 1660   EQUW NullReturn      :\ &212 - FILEV
 1670   EQUW NullReturn      :\ &214 - ARGSV
 1680   EQUW NullReturn      :\ &216 - BGetV
 1690   EQUW NullReturn      :\ &218 - BPutV
 1700   EQUW NullReturn      :\ &21A - GBPBV
 1710   EQUW NullReturn      :\ &21C - FINDV
 1720   EQUW Unsupported     :\ &21E - FSCV
 1730   EQUW NullReturn      :\ &220 - EVNTV
 1740   EQUW Unsupported     :\ &222 - UPTV
 1750   EQUW Unsupported     :\ &224 - NETV
 1760   EQUW Unsupported     :\ &226 - VduV
 1770   EQUW Unsupported     :\ &228 - KEYV
 1780   EQUW Unsupported     :\ &22A - INSV
 1790   EQUW Unsupported     :\ &22C - RemV
 1800   EQUW Unsupported     :\ &22E - CNPV
 1810   EQUW NullReturn      :\ &230 - IND1V
 1820   EQUW NullReturn      :\ &232 - IND2V
 1830   EQUW NullReturn      :\ &234 - IND3V
 1840   :
 1850   .PrHexXY
 1860   TYA:JSR PrHex:TXA
 1870   .PrHex
 1880   PHA:LSR A:LSR A:LSR A:LSR A
 1890   JSR PrNybble:PLA
 1900   .PrNybble
 1910   AND #15:CMP #10:BCC PrDigit:ADC #6
 1920   .PrDigit
 1930   ADC #ASC"0":JMP OSWRCH
 1940   :
 1950   .PrText
 1960   PLA:STA TEXT+0:PLA:STA TEXT+1 :\ TEXT=>embedded string
 1970   JSR PrString2:JMP (TEXT)      :\ Print string and jump back to code
 1980   :
 1990   .PrString
 2000   STX TEXT+0:STY TEXT+1      :\ TEXT=>string at YX
 2010   .PrStringLp
 2020   LDY #&00:LDA (TEXT),Y      :\ Get character
 2030   BEQ PrString2:JSR OSASCI   :\ Print character if not &00
 2040   .PrString2
 2050   INC TEXT+0:BNE LFEA6:INC TEXT+1 :\ Increment address
 2060   .LFEA6
 2070   TYA:BNE PrStringLp         :\ Loop back if not &00
 2080   
 2090   .ScanHex
 2100   .InitError
 2110   .Unsupported
 2120   .NullReturn
 2130   RTS
 2140   :
 2150   \ Standard Tube entry points
 2160   \ ==========================
 2170   EQUS STRING$((&FF95-P%)AND255,CHR$255)
 2180   .LFF95   :JMP NullReturn       :\ &FF95
 2190   .OSCOLD  :JMP OSQUIT           :\ &FF98
 2200   .PRSTRNG :JMP PrString         :\ &FF9B  Print zero-terminated text at YX, returns A=0, Y corrupted
 2210   .LFF9E   :JMP NullReturn       :\ &FF9E
 2220   .SCANHEX :JMP ScanHex          :\ &FFA1  Scan hex string at (&F8), returned in &F0/1
 2230   .DISKACC :JMP NullReturn       :\ &FFA4
 2240   .DISKCCP :JMP NullReturn       :\ &FFA7
 2250   .PRHEX   :JMP PrHex            :\ &FFAA  Print A in hex, A corrupted
 2260   .PR2HEX  :JMP PrHexXY          :\ &FFAD  Print YX in hex, A corrupted
 2270   .USERINT :JMP NullReturn       :\ &FFB0
 2280   .PRTEXT  :JMP PrText           :\ &FFB3  Print zero-terminated inline text, returns A=0, Y corrupted
 2290   .VECDEF  :EQUB &36:EQUW LFF00  :\ &FFB6
 2300   .OSQUIT  :JMP MAIN             :\ &FFB9  Quit current program
 2310   .OSERROR :JMP NullReturn       :\ &FFBC
 2320   .OSINIT  :JMP InitError        :\ &FFBF  Initialise MOS error handler, A corrupted
 2330   .DISKRST :JMP NullReturn       :\ &FFC2
 2340   .LFFC5   :JMP NullReturn       :\ &FFC5
 2350   .NVRDCH  :JMP osRDCH           :\ &FFC8
 2360   .NVWRCH  :JMP osWRCH           :\ &FFCB
 2370   :
 2380   .OSFIND  :JMP (FINDV)          :\ &FFCE
 2390   .OSGBPB  :JMP (GBPBV)          :\ &FFD1
 2400   .OSBPUT  :JMP (BPutV)          :\ &FFD4
 2410   .OSBGET  :JMP (BGetV)          :\ &FFD7
 2420   .OSARGS  :JMP (ARGSV)          :\ &FFDA
 2430   .OSFILE  :JMP (FILEV)          :\ &FFDD
 2440   :
 2450   .OSRDCH  :JMP (RDCHV)          :\ &FFE0
 2460   .OSASCI  :CMP #&0D:BNE OSWRCH  :\ &FFE3
 2470   .OSNEWL  :LDA #&0A:JSR OSWRCH  :\ &FFE7
 2480   .OSWRCR  :LDA #&0D             :\ &FFEC
 2490   .OSWRCH  :JMP (WRCHV)          :\ &FFEE
 2500   .OSWORD  :JMP (WORDV)          :\ &FFF1
 2510   .OSBYTE  :JMP (BYTEV)          :\ &FFF4
 2520   .OS_CLI  :JMP (CLIV)           :\ &FFF7
 2530   :
 2540   .NMIV    :EQUW NMIHandler      :\ &FFFA  NMI Vector
 2550   .RESETV  :EQUW RESET           :\ &FFFC  RESET Vector
 2560   .IRQV    :EQUW IRQHandler      :\ &FFFE  IRQ Vector
 2570 ]:NEXT
 2580 IF O%>L%:PRINT"ERROR: Code overrun"
 2590 PRINT "Saving ";name$;
 2600 OSCLI "Save "+name$+" "+STR$~mcode%+" "+STR$~O%+" "+STR$~load%+" "+STR$~load%
 2610 PRINT