diff --git a/applecorn.po b/applecorn.po new file mode 100644 index 0000000..a07b784 Binary files /dev/null and b/applecorn.po differ diff --git a/applecorn.s b/applecorn.s new file mode 100644 index 0000000..4732a9f --- /dev/null +++ b/applecorn.s @@ -0,0 +1,1409 @@ +* 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+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 # A1L,A1H + STA A1L + LDA #>RDBUF + STA A1H + + LDA # A2L,A2H + STA A2L + LDA #>RDBUFEND + STA A2H + + LDA # 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 + STA A1H + + LDA #MOSSHIM+$1000 + STA A2H + + LDA #AUXMOS1 + STA A4H + + SEC ; Main->aux + JSR AUXMOVE + + LDA #RESET + STA RSTV + LDA #>RESET + STA RSTV+1 + EOR #$A5 ; Checksum + STA RSTV+2 + + TSX + STX $0100 ; Store SP at $0100 + 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 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+2 + JSR OPENFILE + BCS :NOTFOUND + +:L1 LDA OPENPL+5 ; File ref number + STA READPL+1 + JSR RDBLK + BCS :EOF + + LDA #RDBUF + STA A1H + + 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 + 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+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 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 + 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 + STA A1H + LDA #EAUXMOS1 + STA A2H + 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 A1H + LDA #MOSVEND-MOSINIT+AUXMOS1 + STA A2H + 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+1 + + LDA #OSCLI + STA CLIV+1 + LDA #OSBYTE + STA BYTEV+1 + LDA #OSWORD + STA WORDV+1 + LDA #OSWRCH + STA WRCHV+1 + LDA #OSRDCH + STA RDCHV+1 + LDA #OSFILE + STA FILEV+1 + LDA #OSARGS + STA ARGSV+1 + LDA #OSBGET + STA BGETV+1 + LDA #OSBPUT + STA BPUTV+1 + LDA #OSGBPB + STA GBPBV+1 + LDA #OSFIND + STA FINDV+1 + + LDA #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 + JSR PRSTR + RTS +OSRDRMM ASC 'OSRDDRM.' + DB $00 + +OSEVEN LDA #OSEVENM + JSR PRSTR + RTS +OSEVENM ASC 'OSEVEN.' + DB $00 + +OSINIT LDA #OSINITM + JSR PRSTR + RTS +OSINITM ASC 'OSINITM.' + DB $00 + +OSREAD LDA #OSREADM + JSR PRSTR + RTS +OSREADM ASC 'OSREAD.' + DB $00 + +OSFIND LDA #OSFINDM + JSR PRSTR + RTS +OSFINDM ASC 'OSFIND.' + DB $00 + +OSGBPB LDA #OSGBPBM + JSR PRSTR + RTS +OSGBPBM ASC 'OSGBPB.' + DB $00 + +OSBPUT LDA #OSBPUTM + JSR PRSTR + RTS +OSBPUTM ASC 'OSBPUT.' + DB $00 + +OSBGET LDA #OSBGETM + JSR PRSTR + RTS +OSBGETM ASC 'OSBGET.' + DB $00 + +OSARGS LDA #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+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+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 + JSR PRSTR + PLA + PHA + JSR PRHEX + LDA #OSFILEM2 + JSR PRSTR + PLA + PLY + PLX + RTS + +:S1 LDA #SAVEFILE + STA STRTH + BRA :S3 +:S2 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 + JSR PRSTR + PLA + JSR PRHEX + LDA #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 + JSR PRSTR + PLA + PHA + JSR PRHEX + LDA #OSBM2 + JSR PRSTR + PLA + PLY + PLX + RTS +OSBYTEM ASC 'OSBYTE($' + DB $00 +OSBM2 ASC ').' + DB $00 + +OSCLI LDA #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 + JSR PRSTR + PLA + PLX + PLY + PHY + PHX + PHA + TYA + JSR PRHEX + TXA + JSR PRHEX + LDA #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 +