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.