Applecorn/applecorn.s
Bobbi Webber-Manners 43b97430fb Initial version.
2021-07-15 22:16:22 -04:00

1410 lines
39 KiB
ArmAsm

* Load Acorn BBC Micro ROM into aux memory
* Provide an environment where it can run
* Bobbi 2021
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
GTIMECMD EQU $82
CREATCMD EQU $C0
ONLNCMD EQU $C5
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
* Address is aux memory where the MOS entrypoints are
AUXVEC EQU $FFB9 ; 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
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 ; 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 ; 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
: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 GPFXPL
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
* Reset handler
* XFER to AUXMOS1 in aux, AuxZP on
RESET TSX
STX $0100
LDA #<AUXMOS1
STA STRTL
LDA #>AUXMOS1
STA STRTH
SEC
BIT $FF58
JMP XFER
RTS
* ProDOS file handling for MOS OSFILE LOAD call
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 :NOTFOUND
:L1 LDA OPENPL+5 ; File ref number
STA READPL+1
JSR RDBLK
BCS :EOF
LDA #<RDBUF
STA A1L
LDA #>RDBUF
STA A1H
LDA #<RDBUFEND
STA A2L
LDA #>RDBUFEND
STA A2H
LDA FBEXEC
STA A4L
LDA FBEXEC+1
LDX BLOCKS
:L2 CPX #$00
BEQ :S1
INC
INC
DEX
BRA :L2
:S1 STA A4H
SEC ; Main -> AUX
JSR AUXMOVE
INC BLOCKS
BRA :L1
:NOTFOUND
JSR BELL
JSR BELL
LDA #$00 ; Nothing found
:EOF
LDA #$01 ; File found
PHA
LDA OPENPL+1 ; File ref num
STA CLSPL+5
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
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
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 :NORMALEND ; TODO: ERROR HANDLING
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
JSR BELL
LDA #$00 ; Nothing found
BRA :EXIT
:NORMALEND
LDA OPENPL+1 ; File ref num
STA CLSPL+5
JSR CLSFILE
LDA #$01 ; File found
: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
* 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
GPFXPL HEX 01 ; Number of parameters
DW $300 ; Buffer
* Buffer for Acorn MOS filename
MOSFILE DS 20 ; 20 bytes ought to be enough
* 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
*********************************************************
ZP1 EQU $90 ; $90-$9f are Econet space
; so safe to use
ZP2 EQU $92
ROW EQU $94
COL EQU $95
FAULT EQU $FD
ESCFLAG EQU $FF
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
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
*
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 #<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 #<AUXVEC
STA A4L
LDA #>AUXVEC
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
:S8 STA $C00D ; 80 col on
STA $C003 ; Alt charset off
STA $C055 ; PAGE2
STZ ROW
STZ COL
JSR CLEAR
STZ ESCFLAG
LDA #<DEFBRKHDLR
STA BRKV
LDA #>DEFBRKHDLR
STA BRKV+1
LDA #<OSCLI ; Initialize MOS vectors
STA CLIV
LDA #>OSCLI
STA CLIV+1
LDA #<OSBYTE
STA BYTEV
LDA #>OSBYTE
STA BYTEV+1
LDA #<OSWORD
STA WORDV
LDA #>OSWORD
STA WORDV+1
LDA #<OSWRCH
STA WRCHV
LDA #>OSWRCH
STA WRCHV+1
LDA #<OSRDCH
STA RDCHV
LDA #>OSRDCH
STA RDCHV+1
LDA #<OSFILE
STA FILEV
LDA #>OSFILE
STA FILEV+1
LDA #<OSARGS
STA ARGSV
LDA #>OSARGS
STA ARGSV+1
LDA #<OSBGET
STA BGETV
LDA #>OSBGET
STA BGETV+1
LDA #<OSBPUT
STA BPUTV
LDA #>OSBPUT
STA BPUTV+1
LDA #<OSGBPB
STA GBPBV
LDA #>OSGBPB
STA GBPBV+1
LDA #<OSFIND
STA FINDV
LDA #>OSFIND
STA FINDV+1
LDA #<HELLO2
LDY #>HELLO2
JSR PRSTR
LDA #$01
JMP AUXADDR ; Start Acorn ROM
* No return
HELLO2 ASC 'AppleMOS v0.01'
DB $0D,$0A
ASC '=============='
DB $0D,$0A,$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 A,Y to the screen
PRSTR STA ZP2 ; String in A,Y
STY ZP2+1
:L1 LDA (ZP2) ; Ptr to string in ZP1
BEQ :S1
JSR $FFEE ; OSWRCH
INC ZP2
BNE :L1
INC ZP2+1
BRA :L1
:S1 RTS
* Print hex byte in A
PRHEX PHA
LSR
LSR
LSR
LSR
AND #$0F
JSR PRNIB
PLA
AND #$0F
JSR PRNIB
RTS
* Print hex nibble in A
PRNIB CMP #$0A
BCC :S1
CLC ; >= $0A
ADC #'A'-$0A
JSR $FFEE ; OSWRCH
RTS
:S1 ADC #'0' ; < $0A
JSR $FFEE ; OSWRCH
RTS
OSRDRM LDA #<OSRDRMM
LDY #>OSRDRMM
JSR PRSTR
RTS
OSRDRMM ASC 'OSRDDRM.'
DB $00
OSEVEN LDA #<OSEVENM
LDY #>OSEVENM
JSR PRSTR
RTS
OSEVENM ASC 'OSEVEN.'
DB $00
OSINIT LDA #<OSINITM
LDY #>OSINITM
JSR PRSTR
RTS
OSINITM ASC 'OSINITM.'
DB $00
OSREAD LDA #<OSREADM
LDY #>OSREADM
JSR PRSTR
RTS
OSREADM ASC 'OSREAD.'
DB $00
OSFIND LDA #<OSFINDM
LDY #>OSFINDM
JSR PRSTR
RTS
OSFINDM ASC 'OSFIND.'
DB $00
OSGBPB LDA #<OSGBPBM
LDY #>OSGBPBM
JSR PRSTR
RTS
OSGBPBM ASC 'OSGBPB.'
DB $00
OSBPUT LDA #<OSBPUTM
LDY #>OSBPUTM
JSR PRSTR
RTS
OSBPUTM ASC 'OSBPUT.'
DB $00
OSBGET LDA #<OSBGETM
LDY #>OSBGETM
JSR PRSTR
RTS
OSBGETM ASC 'OSBGET.'
DB $00
OSARGS LDA #<OSARGSM
LDY #>OSARGSM
JSR PRSTR
RTS
OSARGSM ASC 'OSARGS.'
DB $00
OSFILE 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 #$0D ; Carriage return
BNE :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
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 PRHEX
LDA #<OSFILEM2
LDY #>OSFILEM2
JSR PRSTR
PLA
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 ; Discard other copy of A
PLY
PLX
LDA #$00 ; File not found
RTS
OSFILEM ASC 'OSFILE($'
DB $00
OSFILEM2 ASC ')'
DB $00
TEMP1 DB $00
TEMP2 DB $00
OSRDCH 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
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 PHA
PHX
PHY
CMP #$00 ; NULL
BNE :T1
BRA :DONE
:T1 CMP #$07 ; BELL
BNE :T2
JSR BEEP
BRA :DONE
: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
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 PLY
PLX
PLA
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 STX ZP1 ; ZP1 points to control block
STY ZP1+1
CMP #$00 ; OSWORD 0 read a line
BNE :S1
LDA (ZP1) ; Addr of buf -> ZP2
STA ZP2
LDY #$01
LDA (ZP1),Y
STA ZP2+1
LDY #$00
:L1 JSR OSRDCH
STA (ZP2),Y
INY
CMP #$0D ; Carriage return
BEQ :DONE
CMP #27 ; Escape
BEQ :CANCEL
CMP #$7F ; Delete
BEQ :DELETE
JSR OSWRCH ; Echo
BRA :L1
:DONE JSR OSWRCH
LDA #$0A
JSR OSWRCH
CLC
RTS
:CANCEL SEC
RTS
:DELETE DEY
BEQ :L1 ; Nothing to delete
JSR OSWRCH ; Echo
DEY
BRA :L1
:S1 PHA
LDA #<OSWORDM ; Unimplemented, print msg
LDY #>OSWORDM
JSR PRSTR
PLA
JSR PRHEX
LDA #<OSWORDM2
LDY #>OSWORDM2
JSR PRSTR
RTS
OSWORDM STR 'OSWORD('
DB $00
OSWORDM2 STR ')'
DB $00
OSBYTE PHX
PHY
:S1 CMP #$7E ; $7E = ack detection of ESC
BNE :S2
PLY
PLX
LDX #$FF ; Means ESC condition cleared
RTS
:S2 CMP #$81 ; $81 = Read key with time lim
BNE :S3
PLY
PLX
JMP GETKEY
:S3 CMP #$82 ; $82 = read high order address
BNE :S4
PLY
PLX
LDY #$FF ; $FFFF for I/O processor
LDX #$FF
RTS
:S4 CMP #$83 ; $83 = read bottom of user mem
BNE :S5
PLY
PLX
LDY #$0E ; $0E00
LDX #$00
RTS
:S5 CMP #$84 ; $84 = read top of user mem
BNE :S6
PLY
PLX
LDY #$80
LDX #$00
RTS
:S6 CMP #$85 ; $85 = top user mem for mode
BNE :S7
PLY
PLX
LDY #$80
LDX #$00
RTS
:S7 CMP #$86 ; $86 = read cursor pos
BNE :S8
PLY
PLX
LDY ROW
LDX COL
RTS
:S8 CMP #$DA ; $DA = clear VDU queue
BNE :S9
PLY
PLX
RTS
:S9 PHA
LDA #<OSBYTEM
LDY #>OSBYTEM
JSR PRSTR
PLA
PHA
JSR PRHEX
LDA #<OSBM2
LDY #>OSBM2
JSR PRSTR
PLA
PLY
PLX
RTS
OSBYTEM ASC 'OSBYTE($'
DB $00
OSBM2 ASC ').'
DB $00
OSCLI LDA #<OSCLIM
LDY #>OSCLIM
JSR PRSTR
RTS
OSCLIM ASC 'OSCLI.'
DB $00
* Performs OSBYTE $81 INKEY$ function
* X,Y has time limit
GETKEY
: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 LDY #27 ; Escape
SEC
RTS
* Beep
BEEP PHA
PHX
LDX #$00
:L1 LDA $C030
JSR DELAY
INX
CPX #$00
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
* Break handler
BRKHDLR 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)
:S1 ; No Apple IRQs to handle
PLA
TAX
PLA
RTS
DEFBRKHDLR
LDA #<BRKM
LDY #>BRKM
JSR PRSTR
PLA
PLX
PLY
PHY
PHX
PHA
TYA
JSR PRHEX
TXA
JSR PRHEX
LDA #<BRKM2
LDY #>BRKM2
JSR PRSTR
RTI
BRKM ASC "BRK($"
DB $00
BRKM2 ASC ")."
DB $00
*
* Acorn MOS entry points at the top of RAM
*
MOSVEC
JMP OSRDRM ; FFB9
NOP ; FFBC
NOP ; FFBD
NOP ; FFBE
JMP OSEVEN ; FFBF
JMP OSINIT ; FFC2
JMP OSREAD ; FFC5
JMP OSWRCH ; FFC8 NVWRCH Non vectored
JMP OSRDCH ; FFCB NVRDCH Non vectored
JMP (FINDV) ; FFCE OSFIND
JMP (GBPBV) ; FFD1 OSGBPB
JMP (BPUTV) ; FFD4 OSBPUT
JMP (BGETV) ; FFD7 OSBGET
JMP (ARGSV) ; FFDA OSARGS
JMP (FILEV) ; FFDD OSFILE
JMP (RDCHV) ; FFE0 OSRDCH
CMP #$0D ; FFE3 OSASCI
BNE :S1
LDA #$0A ; FFE7 OSNEWL
JSR OSWRCH
LDA #$0D
:S1 JMP (WRCHV) ; FFEE OSWRCH
JMP (WORDV) ; FFF1 OSWORD
JMP (BYTEV) ; FFF4 OSBYTE
JMP (CLIV) ; FFF7 OSCLI
NOP ; FFFA
NOP ; FFFB
NOP ; FFFC
NOP ; FFFD
DW BRKHDLR ; FFFE
MOSVEND