*
* Custom kernal routines, from Blahtune. (Ignore the ENTs)
*
*-------------------------------
*
* My own little kernal routines -- useful utility
* routines.
*
* INPUT -- Read string
* KERPLOP
* PLOPXY
* PLOP -- Fast screen (text) plotting routines
* CHAROUT -- PLOPs a character to the screen
* PRINT -- Prints a string using CHROUT
* STROUT -- Prints a string immediately following call
* PRINPLOP -- Like PRINT but uses PLOP
* PLOPSTR -- PLOPs a string immediately following call
* MULT16 -- 16-bit integer multiply routine
* DIV16 -- 16-bit divide
* ASCTONUM -- Convert string to 16-bit number
* PLOPNUM -- PLOPs 16-bit number to screen
* PHBYTE -- PLOP two digit hex byte
* BLMOVE -- Block memory move
*
SCREENP = $FB
READST = $FFB7
SETLFS = $FFBA
SETNAM = $FFBD
OPEN = $FFC0
CLOSE = $FFC3
CHKIN = $FFC6
CHKOUT = $FFC9
CLRCHN = $FFCC
CHRIN = $FFCF
CHROUT = $FFD2
LOAD = $FFD5
SAVE = $FFD8
STOP = $FFE1
GETIN = $FFE4
CLALL = $FFE7
FAQ2 = $69
ACC = FAQ2
AUX = ACC+2
EXT = AUX+2
BLNSW = $CC
BLNON = $CF
BLNCT = $CD
*
* INPUT inputs a string of data into STRBUF. The maximum
* number of chars to be read are passed in X. On output,
* zero set means the input was aborted with R/S or is
* empty. .A (and STRLEN) contains the string length.
*
STRBUF EQU $0200
STRLEN ENT
DFB 00
MAXLEN DFB 00
INPUT ENT
STX MAXLEN
LDA #00
STA STRLEN
STA STRBUF
LDA $0286 ;Set blink color to
STA $0287 ;current color.
:LOOP LDA #00
STA BLNSW ;Blink
:WAIT JSR STOP
BEQ :RTS
JSR GETIN
BEQ :WAIT
LDY #1
STY BLNCT
:WAIT2 LDY BLNON
BNE :WAIT2
INC BLNSW
CMP #160 ;Alphanumeric characters
BCS :NORMAL
CMP #128
BCS :LOOP
CMP #13
BEQ :DONE
CMP #20
BEQ :DEL
CMP #32
BCC :LOOP
:NORMAL
LDY STRLEN
CPY MAXLEN
BCS :LOOP
STA STRBUF,Y
JSR CHROUT
INC STRLEN
BNE :LOOP
:DEL LDY STRLEN
BEQ :LOOP
JSR CHROUT
DEC STRLEN
BPL :LOOP
:DONE LDY STRLEN
LDA #00
STA STRBUF,Y
TYA ;Z set if string empty
:RTS RTS
*
* PLOP
* Stores the value in A to the screen at the point
* (ROW,COLUMN) and the color in COLOR to the
* colormap. If entered at PLOPXY, ROW is set to X and
* column is set to Y. If entered at KERPLOP, char
* is stored to the kerrent screen pointer.
* On exit, A X and Y are preserved; carry set indicates
* an error, i.e. row/col out of range.
*
ROW ENT
DFB 0 ;Current row,column
COLUMN ENT
DFB 0
COLOR ENT
DFB 0
PLOPXY ENT ;Set Y=column, X=row
CPX #25
BCS PLOPRTS
CPY #40
BCS PLOPRTS
STY COLUMN
STX ROW
PLOP ENT
PHA
LDA ROW ;We need 40*ROW
ASL
ASL
ADC ROW ;5*ROW
STA SCREENP
LDA #00 ;A=high byte
ASL SCREENP ;Mult by 8
ROL
ASL SCREENP
ROL
ASL SCREENP
ROL
ADC #$04 ;Add 1024
STA SCREENP+1 ;SCREENP now points to screen
PLA
PLOPRTS RTS
KTEMP DS 1
STAXY ENT
JSR PLOPXY ;plop to X,Y
KERPLOP ENT ;PLOP to kerrent screen loc.
STY KTEMP
LDY COLUMN
STA (SCREENP),Y
LDA SCREENP+1
CLC
ADC #$D4 ;Color mem at $D800
STA SCREENP+1
LDA COLOR
STA (SCREENP),Y
LDA SCREENP+1 ;Restore SCREENP to point to
SEC ;screen
SBC #$D4
STA SCREENP+1
CLC ;Signal all is well.
LDA (SCREENP),Y ;restore A
LDY KTEMP
RTS
*
* CHAROUT
* Sticks a CHR$ character to the screen at the current
* row,column and advances the column.
* All registers are preserved.
*
CHAROUT ENT
EOR #$E0 ;Convert to screen char
CLC
ADC #32
BPL :CONT
ADC #64
BPL :CONT
EOR #$A0
:CONT JSR KERPLOP
INC COLUMN
RTS
*
* PRINT
* As the name suggests, this prints a string to the
* screen, where the address of the string is
* contained in (.X,.A) = (lo,hi). The string is
* assumed to be null-terminated.
*
* On exit, the location of the last character read
* (the null-terminator hopefully) is returned in
* (.X,.A) = (lo,hi). Y is preserved.
*
PRINT ENT
STA :LOOP+2
:LOOP LDA $A000,X
BEQ :DONE
JSR CHROUT
INX
BNE :LOOP
INC :LOOP+2
BNE :LOOP
:DONE
LDA :LOOP+2
RTS
*
* STROUT
* Like PRINT, but the string immediately follows the
* subroutine call; execution resumes right after the
* null-termination byte.
*
* On exit, A and X are thoroughly hosed.
*
STROUT ENT
PLA
TAX ;Lo byte
PLA
INX
BNE :CONT
CLC
ADC #01
:CONT JSR PRINT
PHA ;lo byte
TXA
PHA ;hi byte
RTS
*
* Like PRINT, but uses PLOP.
*
PRINPLOP ENT
STA :LOOP+2
:LOOP LDA $A000,X
BEQ :DONE
JSR CHAROUT
INX
BNE :LOOP
INC :LOOP+2
BNE :LOOP
:DONE
LDA :LOOP+2
RTS
*
* PLOPSTR
* Like STROUT, but uses PLOP
*
TEMPA DFB 00
TEMPX DFB 00
PLOPSTR ENT
STA TEMPA
STX TEMPX
PLA
TAX ;Lo byte
PLA
INX
BNE :CONT
CLC
ADC #01
:CONT JSR PRINPLOP
PHA ;lo byte
TXA
PHA ;hi byte
LDX TEMPX
LDA TEMPA
RTS
*-------------------------------------
* 16 bit multiply and divide routines.
* Three 16 bit (two-byte) locations
* ACC, AUX and EXT must be set up,
* preferably on zero page.
*-------------------------------------
* MULTIPLY ROUTINE
* ACC*AUX -> [ACC,EXT] (low,hi) 32 bit result
MULT16 ENT
LDA #0
STA EXT+1
LDY #$11
]LOOP LSR EXT+1
ROR
ROR ACC+1
ROR ACC
BCC MUL2
CLC
ADC AUX
PHA
LDA AUX+1
ADC EXT+1
STA EXT+1
PLA
MUL2 DEY
BNE ]LOOP
STA EXT
RTS
* DIVIDE ROUTINE
* ACC/AUX -> ACC, remainder in EXT
DIV16 ENT
LDA #0
STA EXT+1
LDY #$10
]LOOP ASL ACC
ROL ACC+1
ROL
ROL EXT+1
PHA
CMP AUX
LDA EXT+1
SBC AUX+1
BCC DIV2
STA EXT+1
PLA
SBC AUX
PHA
INC ACC
DIV2 PLA
DEY
BNE ]LOOP
STA EXT
RTS
*
* ASCTONUM
* Converts a string to a 16-bit number. The address
* of the string is passed in in (A,X) = (lo,hi), and
* the base of the number is contained in Y. Valid
* bases are 0-16. The string is assumed to be
* null-terminated.
*
* On exit, carry set denotes an error, either an
* invalid base, an invalid string, or a number
* overflow. The number is contained in ACC, as
* used in MULT16. The last char read is contained
* in (A,X)=(lo,hi). Y is toast.
*
ASCTONUM ENT
CPY #17
BCS :EXIT
STY AUX ;AUX=number base
LDY #00
STY AUX+1
STY ACC
STY ACC+1
STX :LOOP+2
TAX ;X=lo byte string
:LOOP LDA $A000,X ;Valid chars are $30-$39, $41-$46
BEQ :EXIT
EOR #$30
CMP #10
BCC :CONT
EOR #$70 ;Should use SBC #$70-9
ADC #8 ;Now A-F = 10-16
:CONT CMP AUX ;Compare with number base
BCS :EXIT
PHA
JSR MULT16 ;Multiply number times base
PLA
LDY EXT ;Did multiplication exceed 16 bits?
BNE :ERROR
CLC
ADC ACC
STA ACC
LDA ACC+1
ADC #00
STA ACC+1
INX
BNE :LOOP
INC :LOOP+2
BNE :LOOP
:ERROR SEC
:EXIT TXA
LDX :LOOP+2
RTS
*
* PRINTNUM
* Prints the 16-bit number in (A,X) = (lo,hi)
* to the screen, i.e. prints using CHROUT.
* The number base is contained in Y.
*
PRINTNUM ENT
STA ACC
STX ACC+1
STY AUX ;Base
LDX #00
STX AUX+1
* ACC/AUX -> ACC, remainder in EXT
:LOOP JSR DIV16
INX
LDA EXT
PHA
LDA ACC
ORA ACC+1
BNE :LOOP ;Divide until result=0
:POOP PLA
ORA #$30 ;Convert to chr$
CMP #$3A
BCC :PLOP
ADC #$06 ;$3A->A $3B->B etc.
:PLOP JSR CHROUT
DEX
BNE :POOP
RTS
*
* PLOPNUM
* Plops the 16-bit number in (A,X) = (lo,hi)
* to the screen, i.e. prints using PLOP routine.
* The number base is contained in Y.
*
PLOPNUM ENT
STA ACC
STX ACC+1
STY AUX ;Base
LDX #00
STX AUX+1
* ACC/AUX -> ACC, remainder in EXT
:LOOP JSR DIV16
INX
LDA EXT
PHA
LDA ACC
ORA ACC+1
BNE :LOOP ;Divide until result=0
:POOP PLA
ORA #$30 ;Convert to chr$
CMP #$3A
BCC :PLOP
ADC #$06 ;$3A->A $3B->B etc.
:PLOP JSR CHAROUT
DEX
BNE :POOP
RTS
*
* PHBYTE
* Print a hex byte in .A, including trailing zeros
*
PHBYTE ENT
PHA
LSR
LSR
LSR
LSR
JSR :PRINT
PLA
AND #$0F
:PRINT ORA #$30
CMP #$3A
BCC :PLOP
ADC #$06
:PLOP JMP CHAROUT
*
* BLMOVE
* Moves a block of memory to another location.
* Set BLSTART to the beginning of the block of
* memory, BLEND to the last byte of the block,
* and BLDEST to the destination byte (2-bytes
* each, in lo,hi format).
*
* The routine is smart, and can tell the difference
* between forwards and backwards moves, etc.
*
* AUX and EXT are used, from mult routine.
*
BLSTART ENT
DA 0
BLEND ENT
DA 0
BLDEST ENT
DA 0
BLMOVE ENT
LDA BLEND ;Number of bytes to move
SEC
SBC BLSTART
TAX
LDA BLEND+1
SBC BLSTART+1
BCC :DONE
STA AUX ;(.X,AUX) = (LO,HI)
LDA BLSTART
SEC
SBC BLDEST
LDA BLSTART+1
SBC BLDEST+1
BCC :FORWARD
LDA BLSTART
STA :BSRC+1
LDA BLSTART+1
STA :BSRC+2
LDA BLDEST
STA :BDEST+1
LDA BLDEST+1
STA :BDEST+2
INC AUX
INX
LDY #00
:LOOP
:BSRC LDA $1000,Y
:BDEST STA $1000,Y
INY
BNE :C1
INC :BSRC+2
INC :BDEST+2
:C1 DEX
BNE :LOOP
DEC AUX
BNE :LOOP
:DONE RTS
:FORWARD ;Move block forwards
TXA
ADC BLDEST ;Copy to end of blocks
STA :FDEST+1
LDA AUX
ADC BLDEST+1
STA :FDEST+2
LDA BLEND
STA :FSRC+1
LDA BLEND+1
STA :FSRC+2
INC AUX
INX
LDY #00
:FLOOP
:FSRC LDA $1000,Y
:FDEST STA $1000,Y
DEY
CPY #$FF
BNE :C2
DEC :FSRC+2
DEC :FDEST+2
:C2 DEX
BNE :FLOOP
DEC AUX
BNE :FLOOP
RTS