Make room for a screen buffer in C64 Basic
In my previous post in which I moved a box across the screen with a Basic program, I wanted to use a screen buffer. The default screen location starts in memory at $0400
(1024 decimal), and we can move the screen in units of 1024 bytes. The next location would be $0800
(2048 decimal), which is where Basic text lives. Luckily we can move the start of Basic up with a poke
at location 44, but we also have to move the bytes of the Basic text to the new location, or you’d get a jibberish Basic text. The most obvious location is $0c01
(3097 decimal), and it makes sense to do this outside of Basic, with the raw power of the 6510 CPU.
The machine language (M/L) program enablebuffer
does just that. Here’s the source code listing. It has some Basic code to run the M/L code and relocate the start of Basic text. The M/L code is a bit more complicated than it needed to be, but I like some headroom in case I want to include more Basic text in front of the M/L code or put some M/L code in a convenient location, so we can sys
or usr()
to it. The code should be able to copy Basic text in front of the M/L code, no matter how big it would grow.
; enablebuffer.asm
;
; Move the start of basic from $0801 to $0c01
;
; Now both 1024 - 2023 and 2048 - 3047
; can be used as screen memory.
; This makes it possible to use a screen buffer
; in Basic.
PROCESSOR 6502
ORG $0801
; Basic text in front of ML code
; 10 SYSXXXX:POKE44,12:CLR
BASIC1:
HEX 14 08 0a 00 9e
.dc sys_address ; replaces the "XXXX"
BASIC2:
HEX 3a 97 34 34 2c 31 32 3a 9c 00 00 00
sys_address: eqm (start_ML)d
; start of ML code
start_ML:
vect1: eqm $02
vect2: eqm $04
BASstart: eqm $2B
LDA BASstart+1
CMP #$08 ; is start of basic at $0801 ?
BNE exit ; no, then exit
; set up copy process
; copy $0801 to $0C01 until the end of file
; copy start at the end towards the beginning
CLC
LDA #exit
STA vect1+1
ADC #$04 ; move 1024 positions higher in memory
STA vect2+1
LDY #$00
loop1: LDA vect1+1 ; copy in blocks of 256 bytes
CMP #$08 ; less than 256 bytes to copy?
BEQ loop2 ; yes, then loop2 instead
loop1a: LDA (vect1),Y ; fast copy 256 bytes
STA (vect2),Y
DEY
BNE loop1a
DEC vect1 ; next 256 byte
DEC vect2
BNE loop1
DEC vect1+1
DEC vect2+1
BNE loop1
loop2: LDA (vect1),Y ; copy remainder of bytes
STA (vect2),Y ; between 1 and 255
DEC vect1
DEC vect2
BNE loop2b
DEC vect1+1
DEC vect2+1
loop2b: LDA vect1+1
CMP #$07
BNE loop2
exit: RTS
We can load the program as an ordinary Basic program and then run it.
After that we can new
the Basic program and start writing a new Basic program, at location $0C01
instead of the default $0801
! Of course, the M/L code will be overwritten by that new Basic program, but that’s okay, since we no longer need it at that point.