* AUXMEM.MISC.S * (c) Bobbi 2021 GPLv3 * * Misc functions and API entry block * 02-Sep-2021 Written GSINIT/GSREAD * OSBYTE $80 - ADVAL ************************************ * Read input device or buffer status BYTE80 LDY #$00 ; Prepare return=&00xx TXA ; X<0 - info about buffers BMI ADVALBUF ; X>=0 - read input devices CPX #$7F BNE ADVALNONE ADVALWAIT JSR KBDREAD BCS ADVALWAIT TAX BPL ADVALOK1 ; &00xx for normal keys INY ; &01xx for function/edit keys ADVALOK1 RTS ADVALNONE LDX #$00 ; Input, just return 0 RTS ADVALBUF INX BEQ :ADVALKBD ; Fake keyboard buffer INX BEQ :ADVALOK ; Serial input, return 0 LDX #$01 ; For outputs, return 1 char free RTS :ADVALKBD BIT $C000 ; Test keyboard data/strobe BPL :ADVALOK ; No Strobe, return 0 INX ; Strobe, return 1 :ADVALOK RTS ****************** * Helper functions ****************** * Beep * * Sound measurement shows the tone formula is: * 1.230 MHz * ------------- = cycles * 8 * frequency * * cycles = BEEPX*5+10 * * So: * BEEPX = (cycles-10)/5 * So: * BEEPX = ( 1.230 MHz ) * (------------- - 10 ) / 5 * (8 * frequency ) * BEEPX EQU #57 ; note=C5 BEEPX EQU #116 ; note=C4 BEEP PHA PHX PHY LDY #$00 ; duration :L1 LDX #BEEPX ; 2cy pitch 2cy *------------------------------------------------------ :L2 DEX ; 2cy BEEPX * 2cy BNE :L2 ; 3cy/2cy (BEEPX-1) * 3cy + 1 * 2cy *------------------------------------------------------ * BEEPX*5-1cy LDA $C030 ; 4cy BEEPX*5+5 DEY ; 2cy BEEPX*5+7 BNE :L1 ; 3cy/2cy BEEPX*5+10 PLY ; PLX PLA 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 OSTEXT+0 ; String in A,Y STY OSTEXT+1 :L1 LDA (OSTEXT) ; Ptr to string in ZP3 BEQ PRSTROK JSR OSASCI INC OSTEXT BNE :L1 INC OSTEXT+1 BRA :L1 PRSTROK RTS * Print NL if not already at column 0 FORCENL LDA #$86 JSR OSBYTE TXA BEQ PRSTROK JMP OSNEWL * 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 * Print hex nibble in A PRNIB CMP #$0A BCC :S1 CLC ; >= $0A ADC #'A'-$0A JSR OSWRCH RTS :S1 ADC #'0' ; < $0A JMP OSWRCH * Print 16 bit value in XY in decimal * beebwiki.mdfs.net/Number_output_in_6502_machine_code PRDECXY STX :NUM+0 STY :NUM+1 LDA #' ' STA :PAD :PRDEC16 LDY #$08 ; Five digits :LP1 LDX #$FF SEC :LP2 LDA :NUM+0 SBC :TENS+0,Y STA :NUM+0 LDA :NUM+1 SBC :TENS+1,Y STA :NUM+1 INX BCS :LP2 LDA :NUM+0 ADC :TENS+0,Y STA :NUM+0 LDA :NUM+1 ADC :TENS+1,Y STA :NUM+1 TXA BNE :DIGIT LDA :PAD BNE :PRINT BEQ :NEXT :DIGIT LDX #'0' STX :PAD ORA #'0' :PRINT JSR OSWRCH :NEXT DEY DEY BPL :LP1 RTS :PAD DB $00 :NUM DW $0000 :TENS DW 1 DW 10 DW 100 DW 1000 DW 10000 * GSINIT - Initialise for GSTRANS string parsing ************************************************ * On entry, * (OSLPTR),Y=>start of string (spaces will be skipped) * CLC = filename style parsing * SEC = *KEY style parsing * On exit, * X = preserved * Y = prepared for future calls to GSREAD * EQ = end of line (nb: not "" null string) * NE = not end of line * * Very difficult to write this without it being a direct clone * from the BBC MOS. ;) * GSINTGO ROR GSFLAG ; CY initially into bit 7 JSR SKIPSPC ; Skip any spaces INY ; Step past in case it's a quote CMP #$22 ; Is it a quote? BEQ GSINTGO1 DEY ; Wasn't a quote, step back CLC ; Prepare CC=no leading quote GSINTGO1 ROR GSFLAG ; Rotate 'leading-quote' into flags CMP #$0D RTS ; Return EQ if end of line * GSFLAG set to: * bit7: leading quote found * bit6: CC=filename CS=*KEY * GSREAD - Read a character from a GSTRANS parsed string ******************************************************** * On entry, * (OSLPTR),Y=>current string pointer * On exit, * A = parsed character * X = preserved * CS = end of string (space or or ") * Y =updated to start of next word or end of line * EQ=end of line after this string * NE=not end of line, more words follow * CC = not end of string * Y =updated for future calls to GSREAD * VS=control character, <$20 * VC=not control character >$1F * * No string present is checked for with: * JSR GSINIT:BEQ missingstring * * A null string is checked for with: * JSR GSINIT:JSR GSREAD:BCS nullstring * * A string is skipped with: * JSR GSINIT * loop * JSR GSREAD:BCC loop * * A string is copied with: * JSR GSINIT * LDX #0 * loop * JSR GSREAD:BCS done * STA data,X * INX:BNE loop * done * GSRDGO LDA #$00 ; Prepare to clear accumulator GSREADLP STA GSCHAR ; Update accumulator LDA (OSLPTR),Y ; Get current character CMP #$0D ; End of line? BNE GSREAD2 ; No, check character BIT GSFLAG BPL GSREADEND ; We aren't waiting for a closing quote * ; End of line before closing quote ERRBADSTR BRK DB $FD ASC 'Bad string' BRK GSREAD2 CMP #' ' BCC ERRBADSTR ; Embedded control char BNE GSREAD3 ; Not a space, process it BIT GSFLAG ; Can space terminate string? BMI GSREADCHAR ; We're waiting for a terminating quote * ; so return the space character BVC GSREADEND ; Space is a terminator, finish GSREAD3 CMP #$22 ; Is it a quote? BNE GSREADESC ; Not quote, check for escapes BIT GSFLAG ; Was there an opening quote? BPL GSREADCHAR ; Not waiting for a closing quote INY ; Waiting for quote, check next character LDA (OSLPTR),Y CMP #$22 ; Is it another quote? BEQ GSREADCHAR ; Quote-Quote, expand to single quote * End of string * Either closing quote, or a space seperator, or end of line GSREADEND JSR SKIPSPC ; Skip any spaces to next word SEC ; SEC=end of string RTS ; and (OSLPTR),Y=>next word or end of line * CS=end of string * EQ=end of line * NE=not end of line, more words follow GSREADESC CMP #$7C ; Is is '|' escape character BNE GSREADCHAR ; No, return as character INY ; Step to next character LDA (OSLPTR),Y CMP #$7C BEQ GSREADCHAR ; bar-bar expands to bar CMP #$22 BEQ GSREADCHAR ; bar-quote expands to quote CMP #'!' ; Is it bar-pling? BNE GSREAD5 ; No, check for bar-letter INY ; Step past it LDA #$80 ; Set bit 7 in accumulator BNE GSREADLP ; Loop back to check next character(s) GSREAD5 CMP #'?' ; Check for '?' BCC ERRBADSTR ; <'?', bad character BEQ GSREADDEL ; bar-query -> DEL AND #$1F ; Convert bar-letter to control code BIT SETV ; SEV=control character BVS GSREADOK GSREADDEL LDA #$7F GSREADCHAR CLV ; CLV=not control character GSREADOK INY ; Step to next character ORA GSCHAR ; Add in any bit 7 from |! prefix CLC ; CLC=not end of string RTS * CC=not end of string * VS=control character * VC=not control character * Read a byte from sideways ROM RDROM LDX #$0F ; Returns X=current ROM, Y=0, A=byte LDY #$00 ; We haven't really got any ROMs LDA ($F6),Y ; so just read directly RTS EVENT LDA #OSEVENM JMP PRSTR OSEVENM ASC 'OSEVEN.' DB $00 ********************************************************** * Interrupt Handlers, MOS redirection vectors etc. ********************************************************** * Invoked from GSBRK in main memory. On IIgs only. GSBRKAUX >>> IENTAUX ; IENTAUX does not do CLI * Continue into IRQBRKHDLR * TO DO: Check, IENTAUX modifies X * IRQ/BRK handler IRQBRKHDLR PHA * Mustn't enable IRQs within the IRQ handler * Do not use WRTMAIN/WRTAUX macros STA $C004 ; Write to main memory STA $45 ; $45=A for ProDOS IRQ handlers STA $C005 ; Write to aux memory TXA PHA CLD TSX LDA $103,X ; Get PSW from stack AND #$10 BEQ :IRQ ; 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 :IRQ >>> XF2MAIN,A2IRQ ; Bounce to Apple IRQ handler IRQBRKRET >>> IENTAUX ; IENTAUX does not do CLI PLA ; TODO: 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 JSR PRSTR JSR PRERR JSR OSNEWL JSR OSNEWL STOP JMP STOP ; Cannot return from a BRK MSGBRK DB $0D ASC "ERROR: " 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 FSCHND ; $21E FSCV ENDVEC * * Acorn MOS entry points at the top of RAM * Copied from loaded code to high memory * * Base of API entries here in loaded code MOSVEC * Real base of API entries in real memory MOSAPI EQU $FFB6 ORG MOSAPI * OPTIONAL ENTRIES * ---------------- *OSSERV JMP SERVICE ; FF95 OSSERV *OSCOLD JMP NULLRTS ; FF98 OSCOLD *OSPRSTR JMP OUTSTR ; FF9B OSPRSTR *OSFF9E JMP NULLRTS ; FF9E *OSSCANHEX JMP RDHEX ; FFA1 SCANHX *OSFFA4 JMP NULLRTS ; FFA4 *OSFFA7 JMP NULLRTS ; FFA7 *PRHEX JMP OUTHEX ; FFAA PRHEX *PR2HEX JMP OUT2HEX ; FFAD PR2HEX *OSFFB0 JMP NULLRTS ; FFB0 *OSWRRM JMP NULLRTS ; FFB3 OSWRRM * 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 ASC '**ENDOFCODE**' DS $200-13