Applecorn/applecorn.s
jgharston fd8e5ba0c6 Add files via upload
Corrected and updated MOS API entry block
Created default vector table
Vectors initialised from default vector table
Corrected OSFILE error numbers
PRSTR prints via OSASCI
Laid out zero page workspace
Added OUT2HEX, optimised OUTHEX
Added WRCH wrapper to OUTCHAR
OSRDLINE recognises BS for delete
RDCH sets ESCFLAG if Escape returned, lets REPEAT PRINT GET:UNTIL 0 to stop
2021-07-26 10:10:41 +01:00

2127 lines
60 KiB
ArmAsm

* Load Acorn BBC Micro ROM into aux memory
* Provide an environment where it can run
* Bobbi 2021
* Assembled with the Merlin 8 assembler with:
* Merlin -V . applecorn.s
XC ; 65c02
ORG $2000 ; Load addr of loader in main memory
* Monitor routines
BELL EQU $FBDD
PRBYTE EQU $FDDA
COUT1 EQU $FDED
CROUT EQU $FD8E
AUXMOVE EQU $C311
XFER EQU $C314
* Monitor ZP locations
A1L EQU $3C
A1H EQU $3D
A2L EQU $3E
A2H EQU $3F
A4L EQU $42
A4H EQU $43
* Used by XFER
STRTL EQU $3ED
STRTH EQU $3EE
* Reset vector (2 bytes + 1 byte checksum)
RSTV EQU $3F2
* MLI entry point
MLI EQU $BF00
* ProDOS MLI command numbers
QUITCMD EQU $65
GTIMECMD EQU $82
CREATCMD EQU $C0
ONLNCMD EQU $C5
SPFXCMD EQU $C6
GPFXCMD EQU $C7
OPENCMD EQU $C8
READCMD EQU $CA
WRITECMD EQU $CB
CLSCMD EQU $CC
* IO Buffer for reading file (512 bytes)
IOBUF EQU $4000
* File will be read 512 bytes at a time into this buffer
RDBUF EQU $5000
RDBUFEND EQU $5200
* Address in aux memory where ROM will be loaded
AUXADDR EQU $8000
* Address in aux memory where the MOS shim is located
AUXMOS1 EQU $2000 ; Temp staging area in Aux
EAUXMOS1 EQU $3000 ; End of staging area
AUXMOS EQU $D000 ; Final location in aux LC
START STZ BLOCKS
LDX #$00
:L1 LDA HELLO,X ; Signon message
BEQ :S1
JSR COUT1
INX
BRA :L1
:S1 JSR CROUT
JSR SETPRFX
JSR DISCONN
STA $C009 ; Alt ZP on
STZ $9F ; WARMSTRT - set cold!
STA $C008 ; Alt ZP off
LDA #<ROMFILE
STA OPENPL+1
LDA #>ROMFILE
STA OPENPL+2
JSR OPENFILE ; Open ROM file
BCC :S2
LDX #$00
:L2 LDA CANTOPEN,X
BEQ :ER1
JSR COUT1
INX
BRA :L2
BRA :S2
:ER1 JSR CROUT
JSR BELL
RTS
:S2 LDA OPENPL+5 ; File reference number
STA READPL+1
:L3 LDA #'.'+$80 ; Read file block by block
JSR COUT1
JSR RDBLK
BCS :S3 ; EOF (0 bytes left) or some error
LDA #<RDBUF ; Source start addr -> A1L,A1H
STA A1L
LDA #>RDBUF
STA A1H
LDA #<RDBUFEND ; Source end addr -> A2L,A2H
STA A2L
LDA #>RDBUFEND
STA A2H
LDA #<AUXADDR ; Dest in aux -> A4L, A4H
STA A4L
LDA #>AUXADDR
LDX BLOCKS
:L4 CPX #$00
BEQ :S25
INC
INC
DEX
BRA :L4
:S25 STA A4H
SEC ; Copy Main -> Aux
JSR AUXMOVE
INC BLOCKS
BRA :L3
:S3 LDA OPENPL+5 ; File reference number
STA CLSPL+1
JSR CLSFILE
LDA #<MOSSHIM ; Start address of MOS shim
STA A1L
LDA #>MOSSHIM
STA A1H
LDA #<MOSSHIM+$1000 ; End address of MOS shim
STA A2L
LDA #>MOSSHIM+$1000
STA A2H
LDA #<AUXMOS1 ; To AUXMOS1 in aux memory
STA A4L
LDA #>AUXMOS1
STA A4H
SEC ; Copy MOS from Main->Aux
JSR AUXMOVE
LDA #<RESET ; Set reset vector->RESET
STA RSTV
LDA #>RESET
STA RSTV+1
EOR #$A5 ; Checksum
STA RSTV+2
TSX
STX $0100 ; Store SP at $0100
LDA #<AUXMOS1 ; Start address in aux, for XFER
STA STRTL
LDA #>AUXMOS1
STA STRTH
SEC ; Main -> Aux
BIT $FF58 ; Set V; Use page zero and stack in aux
JMP XFER ; Jump to copied MOS code in Aux
;:DONE JSR CROUT
; JSR BELL
; RTS
BLOCKS DB 0 ; Counter for blocks read
* Set prefix if not already set
SETPRFX LDA #GPFXCMD
STA :OPC7 ; Initialize cmd byte to $C7
:L1 JSR MLI
:OPC7 DB $00
DW GSPFXPL
LDX $0300
BNE :S1
LDA $BF30
STA ONLPL+1 ; Device number
JSR MLI
DB ONLNCMD
DW ONLPL
LDA $0301
AND #$0F
TAX
INX
STX $0300
LDA #$2F
STA $0301
DEC :OPC7
BNE :L1
:S1 RTS
* Disconnect /RAM
* Stolen from Beagle Bros Extra K
DISCONN LDA $BF98
AND #$30
CMP #$30
BNE :S1
LDA $BF26
CMP $BF10
BNE :S2
LDA $BF27
CMP $BF11
BEQ :S1
:S2 LDY $BF31
:L1 LDA $BF32,Y
AND #$F3
CMP #$B3
BEQ :S3
DEY
BPL :L1
BMI :S1
:S3 LDA $BF32,Y
STA $0302
:L2 LDA $BF33,Y
STA $BF32,Y
BEQ :S4
INY
BNE :L2
:S4 LDA $BF26
STA $0300
LDA $BF27
STA $0301
LDA $BF10
STA $BF26
LDA $BF11
STA $BF27
DEC $BF31
:S1 RTS
* Reset handler
* XFER to AUXMOS ($C000) in aux, AuxZP on, LC on
RESET TSX
STX $0100
LDA $C08B ; Rd/Wt LC, bank one
LDA $C08B
LDA #<AUXMOS
STA STRTL
LDA #>AUXMOS
STA STRTH
SEC
BIT $FF58
JMP XFER
RTS
* Copy 512 bytes from RDBUF to AUXBLK in aux LC
COPYAUXBLK
LDA $C08B ; R/W LC RAM, bank 1
LDA $C08B
STA $C009 ; Alt ZP (and Alt LC) on
LDY #$00
:L1 LDA RDBUF,Y
STA $C005 ; Write aux mem
STA AUXBLK,Y
STA $C004 ; Write main mem
CPY #$FF
BEQ :S1
INY
BRA :L1
:S1 LDY #$00
:L2 LDA RDBUF+$100,Y
STA $C005 ; Write aux mem
STA AUXBLK+$100,Y
STA $C004 ; Write main mem
CPY #$FF
BEQ :S2
INY
BRA :L2
:S2 STA $C008 ; Alt ZP off
LDA $C081 ; Bank the ROM back in
LDA $C081
RTS
* ProDOS file handling for MOS OSFILE LOAD call
* Return A=0 if successful
* A=1 if file not found
* A=2 if read error
LOADFILE LDX $0100 ; Recover SP
TXS
LDA $C081 ; Gimme the ROM!
LDA $C081
STZ BLOCKS
LDA #<MOSFILE
STA OPENPL+1
LDA #>MOSFILE
STA OPENPL+2
JSR OPENFILE
BCS :NOTFND ; File not found
:L1 LDA OPENPL+5 ; File ref number
STA READPL+1
JSR RDBLK
BCC :S1
CMP #$4C ; EOF
BEQ :EOF
BRA :READERR
:S1 LDA #<RDBUF
STA A1L
LDA #>RDBUF
STA A1H
LDA #<RDBUFEND
STA A2L
LDA #>RDBUFEND
STA A2H
LDA FBLOAD
STA A4L
LDA FBLOAD+1
LDX BLOCKS
:L2 CPX #$00
BEQ :S2
INC
INC
DEX
BRA :L2
:S2 STA A4H
SEC ; Main -> AUX
JSR AUXMOVE
INC BLOCKS
BRA :L1
:NOTFND LDA #$01 ; Nothing found
PHA
BRA :EXIT
:READERR LDA #$02 ; Read error
PHA
BRA :EOF2
:EOF LDA #$00 ; Success
PHA
:EOF2 LDA OPENPL+5 ; File ref num
STA CLSPL+1
JSR CLSFILE
:EXIT LDA $C08B ; R/W RAM, bank 1
LDA $C08B
LDA #<OSFILERET ; Return to caller in aux
STA STRTL
LDA #>OSFILERET
STA STRTH
PLA
SEC
BIT $FF58
JMP XFER
* ProDOS file handling for MOS OSFILE SAVE call
* Return A=0 if successful
* A=1 if unable to create/open
* A=2 if error during save
SAVEFILE LDX $0100 ; Recover SP
TXS
LDA $C081 ; Gimme the ROM!
LDA $C081
STZ BLOCKS
LDA #<MOSFILE
STA CREATEPL+1
STA OPENPL+1
LDA #>MOSFILE
STA CREATEPL+2
STA OPENPL+2
LDA #$C3 ; Access unlocked
STA CREATEPL+3
LDA #$06 ; Filetype BIN
STA CREATEPL+4
LDA FBSTRT ; Auxtype = save address
STA CREATEPL+5
LDA FBSTRT+1
STA CREATEPL+6
LDA #$01 ; Storage type - file
STA CREATEPL+7
LDA $BF90 ; Current date
STA CREATEPL+8
LDA $BF91
STA CREATEPL+9
LDA $BF92 ; Current time
STA CREATEPL+10
LDA $BF93
STA CREATEPL+11
JSR CRTFILE
JSR OPENFILE
BCS :FWD1 ; :CANTOPEN error
SEC ; Compute file length
LDA FBEND
SBC FBSTRT
STA :LEN
LDA FBEND+1
SBC FBSTRT+1
STA :LEN+1
:L1 LDA FBSTRT ; Setup for first block
STA A1L
STA A2L
LDA FBSTRT+1
STA A1H
STA A2H
INC A2H ; $200 = 512 bytes
INC A2H
LDA #$00 ; 512 byte request count
STA WRITEPL+4
LDA #$02
STA WRITEPL+5
LDX BLOCKS
:L2 CPX #$00 ; Adjust for subsequent blks
BEQ :S1
INC A1H
INC A1H
INC A2H
INC A2H
DEX
BRA :L2
:FWD1 BRA :CANTOPEN ; Forwarding call from above
:S1 LDA :LEN+1 ; MSB of length remaining
CMP #$02
BCS :S2 ; MSB of len >= 2 (not last)
CMP #$00 ; If no bytes left ...
BNE :S3
LDA :LEN
BNE :S3
BRA :NORMALEND
:S3 LDA FBEND ; Adjust for last block
STA A2L
LDA FBEND+1
STA A2H
LDA :LEN
STA WRITEPL+4 ; Remaining bytes to write
LDA :LEN+1
STA WRITEPL+5
:S2 LDA #<RDBUF
STA A4L
LDA #>RDBUF
STA A4H
CLC ; Aux -> Main
JSR AUXMOVE
LDA OPENPL+5 ; File ref number
STA WRITEPL+1
JSR WRTBLK
BCS :WRITEERR
BRA :UPDLEN
:ENDLOOP INC BLOCKS
BRA :L1
:UPDLEN
SEC ; Update length remaining
LDA :LEN
SBC WRITEPL+4
STA :LEN
LDA :LEN+1
SBC WRITEPL+5
STA :LEN+1
BRA :ENDLOOP
:CANTOPEN
LDA #$01 ; Can't open/create
BRA :EXIT
:WRITEERR
LDA OPENPL+5 ; File ref num
STA CLSPL+1
JSR CLSFILE
LDA #$02 ; Write error
BRA :EXIT
:NORMALEND
LDA OPENPL+5 ; File ref num
STA CLSPL+1
JSR CLSFILE
LDA #$00 ; Success!
BCC :EXIT ; If close OK
LDA #$02 ; Write error
:EXIT PHA
LDA $C08B ; R/W RAM, bank 1
LDA $C08B
LDA #<OSFILERET ; Return to caller in aux
STA STRTL
LDA #>OSFILERET
STA STRTH
PLA
SEC
BIT $FF58
JMP XFER
:LEN DW $0000
* Quit to ProDOS
QUIT INC $3F4 ; Invalidate powerup byte
STA $C054 ; PAGE2 off
JSR MLI
DB QUITCMD
DW QUITPL
RTS
* Obtain catalog of current PREFIX dir
CATALOG LDX $0100 ; Recover SP
TXS
LDA $C081 ; Select ROM
LDA $C081
JSR MLI ; Fetch prefix into RDBUF
DB GPFXCMD
DW GPFXPL
BNE CATEXIT ; If prefix not set
LDA #<RDBUF
STA OPENPL+1
LDA #>RDBUF
STA OPENPL+2
JSR OPENFILE
BCS CATEXIT ; Can't open dir
CATREENTRY
LDA OPENPL+5 ; File ref num
STA READPL+1
JSR RDBLK
BCC :S1
CMP #$4C ; EOF
BEQ :EOF
BRA :READERR
:S1 JSR COPYAUXBLK
LDA $C08B ; R/W RAM, bank 1
LDA $C08B
LDA #<PRONEBLK
STA STRTL
LDA #>PRONEBLK
STA STRTH
SEC
BIT $FF58
JMP XFER
:READERR
:EOF LDA OPENPL+5 ; File ref num
STA CLSPL+1
JSR CLSFILE
CATEXIT LDA $C08B ; R/W LC RAM, bank 1
LDA $C08B
LDA #<STARCATRET
STA STRTL
LDA #>STARCATRET
STA STRTH
PLA
SEC
BIT $FF58
JMP XFER
* PRONEBLK call returns here ...
CATALOGRET
LDX #0100 ; Recover SP
TXS
LDA $C081 ; ROM please
LDA $C081
BRA CATREENTRY
* Set the prefix
SETPFX LDX $0100 ; Recover SP
TXS
LDA $C081 ; ROM, ta!
LDA $C081
JSR MLI
DB SPFXCMD
DW SPFXPL
BCC :S1
JSR BELL ; Beep on error
:S1 LDA $C08B ; R/W LC RAM, bank 1
LDA $C08B
LDA #<STARDIRRET
STA STRTL
LDA #>STARDIRRET
STA STRTH
SEC
BIT $FF58
JMP XFER
* Create disk file
CRTFILE JSR MLI
DB CREATCMD
DW CREATEPL
RTS
* Open disk file
OPENFILE JSR MLI
DB OPENCMD
DW OPENPL
RTS
* Close disk file
CLSFILE JSR MLI
DB CLSCMD
DW CLSPL
RTS
* Read 512 bytes into RDBUF
RDBLK JSR MLI
DB READCMD
DW READPL
RTS
* Write 512 bytes from RDBUF
WRTBLK JSR MLI
DB WRITECMD
DW WRITEPL
RTS
HELLO ASC "Applecorn - (c) Bobbi 2021 GPLv3"
HEX 00
CANTOPEN ASC "Unable to open BASIC.ROM"
HEX 00
ROMFILE STR "BASIC.ROM"
* ProDOS Parameter lists for MLI calls
OPENPL HEX 03 ; Number of parameters
DW $0000 ; Pointer to filename
DW IOBUF ; Pointer to IO buffer
DB $00 ; Reference number returned
CREATEPL HEX 07 ; Number of parameters
DW $0000 ; Pointer to filename
DB $00 ; Access
DB $00 ; File type
DW $0000 ; Aux type
DB $00 ; Storage type
DW $0000 ; Create date
DW $0000 ; Create time
READPL HEX 04 ; Number of parameters
DB $00 ; Reference number
DW RDBUF ; Pointer to data buffer
DW 512 ; Request count
DW $0000 ; Trans count
WRITEPL HEX 04 ; Number of parameters
DB $01 ; Reference number
DW RDBUF ; Pointer to data buffer
DW $00 ; Request count
DW $0000 ; Trans count
CLSPL HEX 01 ; Number of parameters
DB $00 ; Reference number
ONLPL HEX 02 ; Number of parameters
DB $00 ; Unit num
DW $301 ; Buffer
GSPFXPL HEX 01 ; Number of parameters
DW $300 ; Buffer
GPFXPL HEX 01 ; Number of parameters
DW RDBUF ; Buffer
SPFXPL HEX 01 ; Number of parameters
DW MOSFILE ; Buffer
QUITPL HEX 04 ; Number of parameters
DB $00
DW $0000
DB $00
DW $0000
* Buffer for Acorn MOS filename
MOSFILE DS 64 ; 64 bytes max prefix/file len
* Acorn MOS format OSFILE param list
FILEBLK
FBPTR DW $0000 ; Pointer to name (in aux)
FBLOAD DW $0000 ; Load address
DW $0000
FBEXEC DW $0000 ; Exec address
DW $0000
FBSTRT DW $0000 ; Start address for SAVE
DW $0000
FBEND DW $0000 ; End address for SAVE
DW $0000
**********************************************************
* Everything below here is the BBC Micro 'virtual machine'
* in Apple //e Auxiliary memory
**********************************************************
ZP1 EQU $90 ; $90-$9f are Econet space
; so safe to use
ZP2 EQU $92
ZP3 EQU $94
ROW EQU $96 ; Cursor row
COL EQU $97 ; Cursor column
WARMSTRT EQU $9F ; Cold or warm start
* $00-$8F Language workspace
* $90-$9F Network workspace
* $A0-$A7 NMI workspace
* $A8-$AF Non-MOS *command workspace
* $B0-$BF Temporary filing system workspace
* $C0-$CF Persistant filing system workspace
* $D0-$DF VDU driver workspace
* $E0-$EE Internal MOS workspace
* $EF-$FF MOS API workspace
OSAREG EQU $EF
OSXREG EQU $F0
OSYREG EQU $F1
OSCTRL EQU OSXREG
OSLPTR EQU $F2
FAULT EQU $FD ; Error message pointer
ESCFLAG EQU $FF ; Escape status
BRKV EQU $202 ; BRK vector
CLIV EQU $208 ; OSCLI vector
BYTEV EQU $20A ; OSBYTE vector
WORDV EQU $20C ; OSWORD vector
WRCHV EQU $20E ; OSWRCH vector
RDCHV EQU $210 ; OSRDCH vector
FILEV EQU $212 ; OSFILE vector
ARGSV EQU $214 ; OSARGS vector
BGETV EQU $216 ; OSBGET vector
BPUTV EQU $218 ; OSBPUT vector
GBPBV EQU $21A ; OSGBPB vector
FINDV EQU $21C ; OSFIND vector
MAGIC EQU $BC ; Arbitrary value
MOSSHIM
ORG AUXMOS ; MOS shim implementation
*
* Shim code to service Acorn MOS entry points using
* Apple II monitor routines
* This code is initially loaded into aux mem at AUXMOS1
* Then relocated into aux LC at AUXMOS by MOSINIT
*
* Initially executing at $3000 until copied to $D000
MOSINIT
STA $C005 ; Make sure we are writing aux
STA $C000 ; Make sure 80STORE is off
LDA $C08B ; LC RAM Rd/Wt, 1st 4K bank
LDA $C08B
LDA WARMSTRT ; Don't relocate on restart
CMP #MAGIC
BEQ :NORELOC
LDA #<AUXMOS1 ; Relocate MOS shim
STA A1L
LDA #>AUXMOS1
STA A1H
LDA #<EAUXMOS1
STA A2L
LDA #>EAUXMOS1
STA A2H
LDA #<AUXMOS
STA A4L
LDA #>AUXMOS
STA A4H
:L1 LDA (A1L)
STA (A4L)
LDA A1H
CMP A2H
BNE :S1
LDA A1L
CMP A2L
BNE :S1
BRA :S4
:S1 INC A1L
BNE :S2
INC A1H
:S2 INC A4L
BNE :S3
INC A4H
:S3 BRA :L1
:S4 LDA #<MOSVEC-MOSINIT+AUXMOS1
STA A1L
LDA #>MOSVEC-MOSINIT+AUXMOS1
STA A1H
LDA #<MOSVEND-MOSINIT+AUXMOS1
STA A2L
LDA #>MOSVEND-MOSINIT+AUXMOS1
STA A2H
LDA #<MOSAPI
STA A4L
LDA #>MOSAPI
STA A4H
:L2 LDA (A1L)
STA (A4L)
LDA A1H
CMP A2H
BNE :S5
LDA A1L
CMP A2L
BNE :S5
BRA :S8
:S5 INC A1L
BNE :S6
INC A1H
:S6 INC A4L
BNE :S7
INC A4H
:S7 BRA :L2
:NORELOC
:S8 STA $C00D ; 80 col on
STA $C003 ; Alt charset off
STA $C055 ; PAGE2
STZ ROW
STZ COL
JSR CLEAR
STZ ESCFLAG
LDX #$35
INITPG2 LDA DEFVEC,X
STA $200,X
DEX
BPL INITPG2
; LDA #<MOSBRKHDLR
; STA BRKV
; LDA #>MOSBRKHDLR
; STA BRKV+1
; LDA #<CLIHND ; Initialize MOS vectors
; STA CLIV
; LDA #>CLIHND
; STA CLIV+1
; LDA #<BYTEHND
; STA BYTEV
; LDA #>BYTEHND
; STA BYTEV+1
; LDA #<WORDHND
; STA WORDV
; LDA #>WORDHND
; STA WORDV+1
; LDA #<WRCHHND
; STA WRCHV
; LDA #>WRCHHND
; STA WRCHV+1
; LDA #<RDCHHND
; STA RDCHV
; LDA #>RDCHHND
; STA RDCHV+1
; LDA #<FILEHND
; STA FILEV
; LDA #>FILEHND
; STA FILEV+1
; LDA #<ARGSHND
; STA ARGSV
; LDA #>ARGSHND
; STA ARGSV+1
; LDA #<BGETHND
; STA BGETV
; LDA #>BGETHND
; STA BGETV+1
; LDA #<BPUTHND
; STA BPUTV
; LDA #>BPUTHND
; STA BPUTV+1
; LDA #<GBPBHND
; STA GBPBV
; LDA #>GBPBHND
; STA GBPBV+1
; LDA #<FINDHND
; STA FINDV
; LDA #>FINDHND
; STA FINDV+1
LDA #<:HELLO
LDY #>:HELLO
JSR PRSTR
LDA #$09 ; Print language name at $8009
LDY #$80
JSR PRSTR
JSR OSNEWL
JSR OSNEWL
LDA WARMSTRT
CMP #MAGIC
BNE :S9
LDA #<:OLDM
LDY #>:OLDM
JSR PRSTR
:S9 LDA #MAGIC ; So we do not reloc again
STA WARMSTRT
CLC ; CLC=Entered from RESET
LDA #$01 ; $01=Entering application code
JMP AUXADDR ; Start Acorn ROM
* No return
:HELLO ASC 'Applecorn MOS v0.01'
DB $0D,$0D,$00
:OLDM ASC '(Use OLD to recover any program)'
DB $0D,$0D,$00
* Clear to EOL
CLREOL LDA ROW
ASL
TAX
LDA SCNTAB,X ; LSB of row
STA ZP1
LDA SCNTAB+1,X ; MSB of row
STA ZP1+1
LDA COL
PHA
:L1 LDA COL
LSR
TAY
BCC :S1
STA $C004 ; Write main mem
:S1 LDA #" "
STA (ZP1),Y
STA $C005 ; Write aux mem
LDA COL
CMP #79
BEQ :S2
INC COL
BRA :L1
:S2 PLA
STA COL
RTS
* Clear the screen
CLEAR STZ ROW
STZ COL
:L1 JSR CLREOL
:S2 LDA ROW
CMP #23
BEQ :S3
INC ROW
BRA :L1
:S3 STZ ROW
STZ COL
RTS
* Print string pointed to by X,Y to the screen
OUTSTR TXA
* Print string pointed to by A,Y to the screen
PRSTR STA ZP3+0 ; String in A,Y
STY ZP3+1
:L1 LDA (ZP3) ; Ptr to string in ZP3
BEQ :S1
JSR OSASCI
INC ZP3
BNE :L1
INC ZP3+1
BRA :L1
:S1 RTS
* Print XY in hex
OUT2HEX TYA
JSR OUTHEX
TAX ; Continue into OUTHEX
* Print hex byte in A
OUTHEX PHA
LSR
LSR
LSR
LSR
AND #$0F
JSR PRNIB
PLA
AND #$0F ; Continue into PRNIB
; JSR PRNIB
; RTS
* Print hex nibble in A
PRNIB CMP #$0A
BCC :S1
CLC ; >= $0A
ADC #'A'-$0A
JSR OSWRCH
RTS
:S1 ADC #'0' ; < $0A
JMP OSWRCH
RDROM LDA #<OSRDRMM
LDY #>OSRDRMM
JMP PRSTR
OSRDRMM ASC 'OSRDDRM.'
DB $00
EVENT LDA #<OSEVENM
LDY #>OSEVENM
JMP PRSTR
OSEVENM ASC 'OSEVEN.'
DB $00
GSINTGO LDA #<OSINITM
LDY #>OSINITM
JMP PRSTR
OSINITM ASC 'GSINITM.'
DB $00
GSRDGO LDA #<OSREADM
LDY #>OSREADM
JMP PRSTR
OSREADM ASC 'GSREAD.'
DB $00
FINDHND LDA #<OSFINDM
LDY #>OSFINDM
JMP PRSTR
OSFINDM ASC 'OSFIND.'
DB $00
GBPBHND LDA #<OSGBPBM
LDY #>OSGBPBM
JMP PRSTR
OSGBPBM ASC 'OSGBPB.'
DB $00
BPUTHND LDA #<OSBPUTM
LDY #>OSBPUTM
JMP PRSTR
OSBPUTM ASC 'OSBPUT.'
DB $00
BGETHND LDA #<OSBGETM
LDY #>OSBGETM
JMP PRSTR
OSBGETM ASC 'OSBGET.'
DB $00
ARGSHND LDA #<OSARGSM
LDY #>OSARGSM
JMP PRSTR
OSARGSM ASC 'OSARGS.'
DB $00
* MOS OSFILE HANDLER
* On entry, A=action
* XY=>control block
* On exit, A=preserved if unimplemented
* A=0 object not found (not load/save)
* A=1 file found
* A=2 directory found
* XY preserved
* control block updated
FILEHND PHX
PHY
PHA
STX ZP1 ; LSB of parameter block
STY ZP1+1 ; MSB of parameter block
LDA #<FILEBLK
STA ZP2
LDA #>FILEBLK
STA ZP2+1
LDY #$00 ; Copy to FILEBLK in main mem
:L1 LDA (ZP1),Y
STA $C004 ; Write main
STA (ZP2),Y
STA $C005 ; Write aux
INY
CPY #$12
BNE :L1
LDA (ZP1) ; Pointer to filename->ZP2
STA ZP2
LDY #$01
LDA (ZP1),Y
STA ZP2+1
LDA #<MOSFILE+1
STA ZP1
LDA #>MOSFILE+1
STA ZP1+1
LDY #$00
:L2 LDA (ZP2),Y
STA $C004 ; Write main
STA (ZP1),Y
STA $C005 ; Write aux
INY
CMP #$21 ; Space or Carriage return
BCS :L2
DEY
STA $C004 ; Write main
STY MOSFILE ; Length (Pascal string)
STA $C005 ; Write aux
LDA STRTL ; Backup STRTL/STRTH
STA TEMP1
LDA STRTH
STA TEMP2
TSX
STX $0101 ; Store alt SP in $0101
PLA ; Get action back
PHA
BEQ :S1 ; A=00 -> SAVE
CMP #$FF
BEQ :S2 ; A=FF -> LOAD
LDA #<OSFILEM ; If not implemented, print msg
LDY #>OSFILEM
JSR PRSTR
PLA
PHA
JSR OUTHEX
LDA #<OSFILEM2
LDY #>OSFILEM2
JSR PRSTR
PLA ; Not implemented, return unchanged
PLY
PLX
RTS
:S1 LDA #<SAVEFILE
STA STRTL
LDA #>SAVEFILE
STA STRTH
BRA :S3
:S2 LDA #<LOADFILE
STA STRTL
LDA #>LOADFILE
STA STRTH
:S3 CLC ; Use main memory
CLV ; Use main ZP and LC
JMP XFER
OSFILERET
LDX $0101 ; Recover alt SP from $0101
TXS
PHA ; Return value
LDA TEMP1 ; Restore STRTL/STRTH
STA STRTL
LDA TEMP2
STA STRTH
PLA ; Return value
PLY ; Value of A on entry
CPY #$FF ; LOAD
BNE :S4 ; Deal with return from SAVE
CMP #$01 ; No file found
BNE :SL1
BRK
DB $D6 ; $D6 = Object not found
ASC 'File not found'
BRK
:SL1 CMP #$02 ; Read error
BNE :SL2
BRK
DB $CA ; $CA = Premature end, 'Data lost'
ASC 'Read error'
BRK
:SL2 LDA #$01 ; Return code - file found
BRA :EXIT
:S4 CPY #$00 ; Return from SAVE
BNE :S6
CMP #$01 ; Unable to create or open
BNE :SS1
BRK
DB $C0 ; $C0 = Can't create file to save
ASC 'Can'
DB $27
ASC 't save file'
BRK
:SS1 CMP #$02 ; Unable to write
BNE :S6
BRK
DB $CA ; $CA = Premature end, 'Data lost'
ASC 'Write error'
BRK
:S6 LDA #$00
:EXIT PLY
PLX
RTS
OSFILEM ASC 'OSFILE($'
DB $00
OSFILEM2 ASC ')'
DB $00
TEMP1 DB $00
TEMP2 DB $00
RDCHHND PHX
PHY
JSR GETCHRC
STA OLDCHAR
:L1 LDA CURS+1 ; Skip unless CURS=$8000
CMP #$80
BNE :S1
LDA CURS
BNE :S1
STZ CURS
STZ CURS+1
LDA CSTATE
ROR
BCS :S2
LDA #'_'
BRA :S3
:S2 LDA OLDCHAR
:S3 JSR PRCHRC
INC CSTATE
:S1 INC CURS
BNE :S4
INC CURS+1
:S4 LDA $C000 ; Keyboard data/strobe
AND #$80
BEQ :L1
LDA OLDCHAR ; Erase cursor
JSR PRCHRC
LDA $C000
AND #$7F
STA $C010 ; Clear strobe
PLY
PLX
CMP #$1B ; Escape pressed?
BNE :S5
ROR $FF ; Set ESCFLG
SEC ; Return CS
RTS
:S5 CLC
RTS
CURS DW $0000 ; Counter
CSTATE DB $00 ; Cursor on or off
OLDCHAR DB $00 ; Char under cursor
* Print char in A at ROW,COL
PRCHRC PHA
LDA ROW
ASL
TAX
LDA SCNTAB,X ; LSB of row address
STA ZP1
LDA SCNTAB+1,X ; MSB of row address
STA ZP1+1
LDA COL
LSR
TAY
BCC :S1
STA $C004 ; Write main memory
:S1 PLA
ORA #$80
STA (ZP1),Y ; Screen address
STA $C005 ; Write aux mem again
RTS
* Return char at ROW,COL in A
GETCHRC LDA ROW
ASL
TAX
LDA SCNTAB,X
STA ZP1
LDA SCNTAB+1,X
STA ZP1+1
LDA COL
LSR
TAY
BCC :S1
STA $C002 ; Read main memory
:S1 LDA (ZP1),Y
STX $C003 ; Read aux mem again
RTS
* Perform backspace & delete operation
BACKSPC LDA COL
BEQ :S1
DEC COL
BRA :S2
:S1 LDA ROW
BEQ :S3
DEC ROW
STZ COL
:S2 LDA #' '
JSR PRCHRC
:S3 RTS
* Perform backspace/cursor left operation
NDBSPC LDA COL
BEQ :S1
DEC COL
BRA :S3
:S1 LDA ROW
BEQ :S3
DEC ROW
STZ COL
:S3 RTS
* Perform cursor right operation
CURSRT LDA COL
CMP #78
BCS :S1
INC COL
RTS
:S1 LDA ROW
CMP #22
BCS :S2
INC ROW
STZ COL
:S2 RTS
* OSWRCH handler
* All registers preserved
WRCHHND PHA
PHX
PHY
; Check any output redirections
; Check any spool output
JSR OUTCHAR
; Check any printer output
PLY
PLX
PLA
RTS
* Output character to VDU driver
* All registers trashable
OUTCHAR CMP #$00 ; NULL
BNE :T1
BRA :IDONE
:T1 CMP #$07 ; BELL
BNE :T2
JSR BEEP
BRA :IDONE
:T2 CMP #$08 ; Backspace
BNE :T3
JSR NDBSPC
BRA :DONE
:T3 CMP #$09 ; Cursor right
BNE :T4
JSR CURSRT
BRA :DONE
:T4 CMP #$0A ; Linefeed
BNE :T5
LDA ROW
CMP #23
BEQ :SCROLL
INC ROW
JSR CLREOL
:IDONE BRA :DONE
:T5 CMP #$0B ; Cursor up
BNE :T6
LDA ROW
BEQ :DONE
DEC ROW
BRA :DONE
:T6 CMP #$0D ; Carriage return
BNE :T7
JSR CLREOL
STZ COL
BRA :DONE
:T7 CMP #$0C ; Ctrl-L
BNE :T8
JSR CLEAR
BRA :DONE
:T8 CMP #$1E ; Home
BNE :T9
STZ ROW
STZ COL
BRA :DONE
:T9 CMP #$7F ; Delete
BNE :T10
JSR BACKSPC
BRA :DONE
:T10 JSR PRCHRC
LDA COL
CMP #79
BNE :S2
STZ COL
LDA ROW
CMP #23
BEQ :SCROLL
INC ROW
BRA :DONE
:S2 INC COL
BRA :DONE
:SCROLL JSR SCROLL
STZ COL
JSR CLREOL
:DONE RTS
* Scroll whole screen one line
SCROLL LDA #$00
:L1 PHA
JSR SCR1LINE
PLA
INC
CMP #23
BNE :L1
RTS
* Copy line A+1 to line A
SCR1LINE ASL ; Dest addr->ZP1
TAX
LDA SCNTAB,X
STA ZP1
LDA SCNTAB+1,X
STA ZP1+1
INX ; Source addr->ZP2
INX
LDA SCNTAB,X
STA ZP2
LDA SCNTAB+1,X
STA ZP2+1
LDY #$00
:L1 LDA (ZP2),Y
STA (ZP1),Y
STA $C002 ; Read main mem
STA $C004 ; Write main
LDA (ZP2),Y
STA (ZP1),Y
STA $C003 ; Read aux mem
STA $C005 ; Write aux mem
INY
CPY #40
BNE :L1
RTS
* Addresses of screen rows in PAGE2
SCNTAB DW $800,$880,$900,$980,$A00,$A80,$B00,$B80
DW $828,$8A8,$928,$9A8,$A28,$AA8,$B28,$BA8
DW $850,$8D0,$950,$9D0,$A50,$AD0,$B50,$BD0
* OSWORD HANDLER
* On entry, A=action
* XY=>control block
* On exit, All preserved (except OSWORD 0)
* control block updated
WORDHND STX OSCTRL+0 ; Point to control block
STY OSCTRL+1
CMP #$00 ; OSWORD 0 read a line
BNE :UNSUPP
* OSRDLINE - Read a line of input
* On entry, (OSCTRL)=>control block
* On exit, Y=length of line, offset to <cr>
* CC = Ok, CS = Escape
*
LDY #$04
:RDLNLP1 LDA (OSCTRL),Y ; Copy MAXLEN, MINCH, MAXCH to workspace
STA :MAXLEN-2,Y
DEY
CPY #$02
BCS :RDLNLP1
:RDLNLP2 LDA (OSCTRL),Y ; (ZP2)=>line buffer
STA ZP2,Y
DEY
BPL :RDLNLP2
INY
BRA :L1
:BELL LDA #$07 ; BELL
:R1 DEY
:R2 INY ; Step to next character
:R3 JSR OSWRCH ; Output character
:L1 JSR OSRDCH
BCS :EXIT
CMP #$08 ; Backspace
BEQ :RDDEL
CMP #$7F ; Delete
BEQ :RDDEL
CMP #$15 ; Ctrl-U
BNE :S2
INY ; Balance first DEY
:RDCTRLU DEY ; Back up one character
BEQ :L1 ; Beginning of line
LDA #$7F ; Delete
JSR OSWRCH
JMP :RDCTRLU
:RDDEL TYA
BEQ :L1 ; Beginning of line
DEY ; Back up one character
LDA #$7F ; Delete
BNE :R3 ; Jump back to delete
:S2 STA (ZP2),Y
CMP #$0D ; CR
BEQ :S3
CPY :MAXLEN
BCS :BELL ; Too long, beep
CMP :MINCH
BCC :R1 ; <MINCHAR, don't step to next
CMP :MAXCH
BEQ :R2 ; =MAXCHAR, step to next
BCC :R2 ; <MAXCHAR, step to next
BCS :R1 ; >MAXCHAR, don't step to next
:S3 JSR OSNEWL
:EXIT LDA ESCFLAG
ROL
RTS
:UNSUPP PHA
LDA #<:OSWORDM ; Unimplemented, print msg
LDY #>:OSWORDM
JSR PRSTR
PLA
PHA
JSR OUTHEX
LDA #<:OSWRDM2
LDY #>:OSWRDM2
JSR PRSTR
PLA
RTS
:MAXLEN DB $00
:MINCH DB $00
:MAXCH DB $00
:OSWORDM ASC 'OSWORD('
DB $00
:OSWRDM2 ASC ')'
DB $00
* OSBYTE HANDLER
* On entry, A=action
* X=first parameter
* Y=second parameter if A>$7F
* On exit, A=preserved
* X=first returned result
* Y=second returned result if A>$7F
* Cy=any returned status if A>$7F
BYTEHND PHA
JSR BYTECALLER
PLA
RTS
BYTECALLER
; PHA
; JSR OUTHEX
; JSR OUT2HEX
; JSR OSNEWL
; PLA
CMP #$00
BNE :S1
LDX #$0A
RTS
:S1 CMP #$7C ; $7C = clear escape condition
BNE :S2
LDA ESCFLAG
AND #$7F ; Clear MSB
STA ESCFLAG
RTS
:S2 CMP #$7D ; $7D = set escape condition
BNE :S3
ROR ESCFLAG
RTS
:S3 CMP #$7E ; $7E = ack detection of ESC
BNE :S4
LDA ESCFLAG
AND #$7F ; Clear MSB
STA ESCFLAG
LDX #$FF ; Means ESC condition cleared
RTS
:S4 CMP #$81 ; $81 = Read key with time lim
BNE :S5
JSR GETKEY
RTS
:S5 CMP #$82 ; $82 = read high order address
BNE :S6
LDY #$FF ; $FFFF for I/O processor
LDX #$FF
RTS
:S6 CMP #$83 ; $83 = read bottom of user mem
BNE :S7
LDY #$0E ; $0E00
LDX #$00
RTS
:S7 CMP #$84 ; $84 = read top of user mem
BNE :S8
LDY #$80
LDX #$00
RTS
:S8 CMP #$85 ; $85 = top user mem for mode
BNE :S9
LDY #$80
LDX #$00
RTS
:S9 CMP #$86 ; $86 = read cursor pos
BNE :S10
LDY ROW
LDX COL
RTS
:S10 CMP #$DA ; $DA = clear VDU queue
BNE :S11
RTS
:S11 PHX
PHY
LDA #<OSBYTEM
LDY #>OSBYTEM
JSR PRSTR
TSX
LDA $103,X
JSR OUTHEX
LDA #<OSBM2
LDY #>OSBM2
JSR PRSTR
PLY
PLX
RTS
OSBYTEM ASC 'OSBYTE($'
DB $00
OSBM2 ASC ').'
DB $00
* OSCLI HANDLER
* On entry, XY=>command string
CLIHND PHX
PHY
STX ZP1+0 ; Pointer to CLI
STY ZP1+1
; TO DO: needs to skip leading '*'s and ' 's
; TO DO: exit early with <cr>
; TO DO: exit early with | as comment
LDA #<:QUIT
STA ZP2
LDA #>:QUIT
STA ZP2+1
JSR STRCMP
BCS :S1
JSR STARQUIT
BRA :EXIT
:S1 LDA #<:CAT
STA ZP2
LDA #>:CAT
STA ZP2+1
JSR STRCMP
BCS :S2
JSR STARCAT
BRA :EXIT
:S2 LDA #<:CAT2
STA ZP2
LDA #>:CAT2
STA ZP2+1
JSR STRCMP
BCS :S3
JSR STARCAT
BRA :EXIT
:S3 LDA #<:DIR
STA ZP2
LDA #>:DIR
STA ZP2+1
JSR STRCMP
BCS :S4
JSR STARDIR
BRA :EXIT
:S4 LDA #<:HELP
STA ZP2
LDA #>:HELP
STA ZP2+1
JSR STRCMP
BCS :UNSUPP
JSR STARHELP
BRA :EXIT
:UNSUPP LDA #<:OSCLIM
LDY #>:OSCLIM
JSR PRSTR
:EXIT PLY
PLX
RTS
:QUIT ASC '*QUIT'
DB $00
:CAT ASC '*CAT'
DB $00
:CAT2 ASC '*.'
DB $00
:DIR ASC '*DIR'
DB $00
:HELP ASC '*HELP'
DB $00
:OSCLIM ASC 'OSCLI.'
DB $00
* String comparison for OSCLI
* Compares str in ZP1 with null-terminated str in ZP2
* Clear carry if match, set carry otherwise
* Leaves (ZP1),Y pointing to char after verb
STRCMP LDY #$00
:L1 LDA (ZP2),Y
BEQ :PMATCH
CMP (ZP1),Y
BNE :MISMTCH
INY
BRA :L1
:PMATCH LDA (ZP1),Y
CMP #$0D
BEQ :MATCH
CMP #' '
BEQ :MATCH
BRA :MISMTCH
:MATCH CLC
RTS
:MISMTCH SEC
RTS
* Print *HELP test
STARHELP LDA #<:MSG
LDY #>:MSG
JSR PRSTR
LDA #$09 ; Language name
LDY #$80
JSR PRSTR
LDA #<:MSG2
LDY #>:MSG2
JSR PRSTR
RTS
:MSG DB $0D
ASC 'Applecorn MOS v0.01'
DB $0D,$0D,$00
:MSG2 DB $0D,$00
STARQUIT LDA #<QUIT
STA STRTL
LDA #>QUIT
STA STRTH
CLC ; Main memory
CLV ; Main ZP & LC
JMP XFER
STARCAT LDA STRTL
STA TEMP1
LDA STRTH
STA TEMP2
TSX
STX $0101 ; Stash alt SP
LDA #<CATALOG
STA STRTL
LDA #>CATALOG
STA STRTH
CLC ; Main memory
CLV ; Main ZP & LC
JMP XFER
STARCATRET
LDX $0101 ; Recover alt SP
TXS
LDA TEMP1
STA STRTL
LDA TEMP2
STA STRTH
RTS
* Print one block of a catalog. Called by CATALOG
* Block is in AUXBLK
PRONEBLK LDX $0101 ; Recover alt SP
TXS
LDA AUXBLK+4 ; Get storage type
AND #$E0 ; Mask 3 MSBs
CMP #$E0
BNE :NOTKEY ; Not a key block
LDA #<:DIRM
LDY #>:DIRM
JSR PRSTR
:NOTKEY LDA #$00
:L1 PHA
JSR PRONEENT
PLA
INC
CMP #13 ; Number of dirents in block
BNE :L1
BRA :END
:END LDA STRTL
STA TEMP1
LDA STRTH
STA TEMP2
LDA #<CATALOGRET
STA STRTL
LDA #>CATALOGRET
STA STRTH
CLC ; Main memory
CLV ; Main ZP & LC
JMP XFER
:DIRM ASC 'Directory: '
DB $00
* Print a single directory entry
* On entry: A = dirent index in AUXBLK
PRONEENT TAX
LDA #<AUXBLK+4 ; Skip pointers
STA ZP3
LDA #>AUXBLK+4
STA ZP3+1
:L1 CPX #$00
BEQ :S1
CLC
LDA #$27 ; Size of dirent
ADC ZP3
STA ZP3
LDA #$00
ADC ZP3+1
STA ZP3+1
DEX
BRA :L1
:S1 LDY #$00
LDA (ZP3),Y
BEQ :EXIT ; Inactive entry
AND #$0F ; Len of filename
TAX
LDY #$01
:L2 CPX #$00
BEQ :S2
LDA (ZP3),Y
JSR OSWRCH
DEX
INY
BRA :L2
:S2 JSR OSNEWL
:EXIT RTS
* On entry, command line is in ZP1
STARDIR LDA ZP1 ; Move ZP1->ZP3 (OSWRCH uses ZP1)
STA ZP3
LDA ZP1+1
STA ZP3+1
LDX #$01
LDY #$00
:L1 LDA (ZP3),Y
CMP #' '
BEQ :L2
CMP #$0D ; Carriage return
BEQ :S2 ; No space in cmdline
INY
BRA :L1
:S2 RTS ; No argument
:L2 LDA (ZP3),Y
CMP #$0D
BEQ :S2 ; Hit EOL before arg
CMP #' '
BNE :L3
INY
BRA :L2
:L3 LDA (ZP3),Y
CMP #$0D
BEQ :S3
STA $C004 ; Write main
STA MOSFILE,X
STA $C005 ; Write aux
INY
INX
BRA :L3
:S3 DEX
STA $C004 ; Write main
STX MOSFILE ; Length byte
STA $C005 ; Write aux
LDA STRTL
STA TEMP1
LDA STRTH
STA TEMP2
TSX
STX $0101 ; Stash alt SP
LDA #<SETPFX
STA STRTL
LDA #>SETPFX
STA STRTH
CLC ; Main memory
CLV ; Main ZP & LC
JMP XFER
STARDIRRET
LDX $0101 ; Recover Alt SP
TXS
LDA TEMP1
STA STRTL
LDA TEMP2
STA STRTH
RTS
* Performs OSBYTE $81 INKEY$ function
* X,Y has time limit
* On exit, CC, Y=$00, X=key - key pressed
* CS, Y=$FF - timeout
* CS, Y=$1B - escape
GETKEY TYA
BMI NEGKEY ; Negative INKEY
:L1 CPX #$00
BEQ :S1
LDA $C000 ; Keyb data/strobe
AND #$80
BNE :GOTKEY
JSR DELAY ; 1/100 sec
DEX
BRA :L1
:S1 CPY #$00
BEQ :S2
DEY
LDX #$FF
BRA :L1
:S2 LDA $C000 ; Keyb data/strobe
AND #$80
BNE :GOTKEY
LDY #$FF ; No key, time expired
SEC
RTS
:GOTKEY LDA $C000 ; Fetch char
AND #$7F
STA $C010 ; Clear strobe
CMP #27 ; Escape
BEQ :ESC
TAX
LDY #$00
CLC
RTS
:ESC ROR ESCFLAG
LDY #27 ; Escape
SEC
RTS
NEGKEY LDX #$00 ; Unimplemented
LDY #$00
RTS
* Beep
BEEP PHA
PHX
LDX #$80
:L1 LDA $C030
JSR DELAY
INX
BNE :L1
PLX
PLA
RTS
* Delay approx 1/100 sec
DELAY PHX
PHY
LDX #$00
:L1 INX ; 2
LDY #$00 ; 2
:L2 INY ; 2
CPY #$00 ; 2
BNE :L2 ; 3 (taken)
CPX #$05 ; 2
BNE :L1 ; 3 (taken)
PLY
PLX
RTS
* IRQ/BRK handler
IRQBRKHDLR PHA
TXA
PHA
CLD
TSX
LDA $103,X ; Get PSW from stack
AND #$10
BEQ :S1 ; IRQ
SEC
LDA $0104,X
SBC #$01
STA FAULT
LDA $0105,X
SBC #$00
STA FAULT+1
PLA
TAX
PLA
CLI
JMP (BRKV) ; Pass on to BRK handler
:S1 ; No Apple IRQs to handle
PLA ; TO DO: pass on to IRQ1V
TAX
PLA
NULLRTI RTI
PRERR LDY #$01
PRERRLP LDA (FAULT),Y
BEQ PRERR1
JSR OSWRCH
INY
BNE PRERRLP
NULLRTS
PRERR1 RTS
MOSBRKHDLR LDA #<MSGBRK
LDY #>MSGBRK
JSR PRSTR
JSR PRERR
JSR OSNEWL
JSR OSNEWL
STOP JMP STOP ; Cannot return from a BRK
MSGBRK DB $0D
ASC "ERROR: "
DB $00
;DEFBRKHDLR
; LDA #<BRKM
; LDY #>BRKM
; JSR PRSTR
; PLA
; PLX
; PLY
; PHY
; PHX
; PHA
; JSR OUT2HEX
; LDA #<BRKM2
; LDY #>BRKM2
; JSR PRSTR
; RTI
;BRKM ASC "BRK($"
; DB $00
;BRKM2 ASC ")."
; DB $00
* Default page 2 contents
DEFVEC DW NULLRTS ; $200 USERV
DW MOSBRKHDLR ; $202 BRKV
DW NULLRTI ; $204 IRQ1V
DW NULLRTI ; $206 IRQ2V
DW CLIHND ; $208 CLIV
DW BYTEHND ; $20A BYTEV
DW WORDHND ; $20C WORDV
DW WRCHHND ; $20E WRCHV
DW RDCHHND ; $210 RDCHV
DW FILEHND ; $212 FILEV
DW ARGSHND ; $214 ARGSV
DW BGETHND ; $216 BGETV
DW BPUTHND ; $218 BPUTV
DW GBPBHND ; $21A GBPBV
DW FINDHND ; $21C FINDV
DW NULLRTS ; $21E FSCV
ENDVEC
*
* Acorn MOS entry points at the top of RAM
* Copied from loaded code to high memory
*
MOSVEC ; Base of API entries here in loaded code
MOSAPI EQU $FFB6 ; Real base of API entries in real memory
ORG MOSAPI
; OPTIONAL ENTRIES
; ----------------
;OSSERV JMP NULLRTS ; FF95 OSSERV
;OSCOLD JMP NULLRTS ; FF98 OSCOLD
;OSPRSTR JMP OUTSTR ; FF9B PRSTRG Print zero-terminated text at XY
;OSFF9E JMP NULLRTS ; FF9E
;OSSCANHEX JMP RDHEX ; FFA1 SCANHX Scan hex string
;OSFFA4 JMP NULLRTS ; FFA4
;OSFFA7 JMP NULLRTS ; FFA7
;PRHEX JMP OUTHEX ; FFAA PRHEX Print A in hex, A corrupted
;PR2HEX JMP OUT2HEX ; FFAD PR2HEX Print YX in hex, A corrupted
;OSFFB0 JMP NULLRTS ; FFB0
;OSWRRM JMP NULLRTS ; FFB3 OSWRRM Write byte to paged RAM
; COMPULSARY ENTRIES
; ------------------
VECSIZE DB ENDVEC-DEFVEC ; FFB6 VECSIZE Size of vectors
VECBASE DW DEFVEC ; FFB7 VECBASE Base of default vectors
OSRDRM JMP RDROM ; FFB9 OSRDRM Read byte from paged ROM
OSCHROUT JMP OUTCHAR ; FFBC CHROUT Send char to VDU driver
OSEVEN JMP EVENT ; FFBF OSEVEN Signal an event
GSINIT JMP GSINTGO ; FFC2 GSINIT Init string reading
GSREAD JMP GSRDGO ; FFC5 GSREAD Parse general string
NVWRCH JMP WRCHHND ; FFC8 NVWRCH Nonvectored WRCH
NVRDCH JMP RDCHHND ; FFCB NVRDCH Nonvectored RDCH
OSFIND JMP (FINDV) ; FFCE OSFIND
OSGBPB JMP (GBPBV) ; FFD1 OSGBPB
OSBPUT JMP (BPUTV) ; FFD4 OSBPUT
OSBGET JMP (BGETV) ; FFD7 OSBGET
OSARGS JMP (ARGSV) ; FFDA OSARGS
OSFILE JMP (FILEV) ; FFDD OSFILE
OSRDCH JMP (RDCHV) ; FFE0 OSRDCH
OSASCI CMP #$0D ; FFE3 OSASCI
BNE OSWRCH
OSNEWL LDA #$0A ; FFE7 OSNEWL
JSR OSWRCH
OSWRCR LDA #$0D ; FFEC OSWRCR
OSWRCH JMP (WRCHV) ; FFEE OSWRCH
OSWORD JMP (WORDV) ; FFF1 OSWORD
OSBYTE JMP (BYTEV) ; FFF4 OSBYTE
OSCLI JMP (CLIV) ; FFF7 OSCLI
NMIVEC DW NULLRTI ; FFFA NMIVEC
RSTVEC DW STOP ; FFFC RSTVEC
IRQVEC
* Assembler doesn't like running up to $FFFF, so we bodge a bit
MOSEND
ORG MOSEND-MOSAPI+MOSVEC
DW IRQBRKHDLR ; FFFE IRQVEC
MOSVEND
* Buffer for one 512 byte disk block in aux mem
AUXBLK DS $200