Hi,
I've implemented, pretty much exactly what you're looking for,
on my first SBC. You can find the current firmware
here although it's a very preliminary version.
This is what I've done. I've assigned a nice chunk of RAM ($7000-$7FFF) as "screen memory". I then use two bytes in ZP as a pointer to the beggining of the portion I want to show on the display. On startup, $10.$11 points to the beggining of my screen:
Code: Select all
// Top left corner of screen at startup
.const SCREEN_BASE = $7000
// 10 11. Pointer to top left on Screen
.const SCREEN_POINTER = $10
lda #<SCREEN_BASE
sta SCREEN_POINTER
sta SCREEN_CURSOR_POINTER
lda #>SCREEN_BASE
sta SCREEN_POINTER+1 // Set up base window
sta SCREEN_CURSOR_POINTER+1
I have a routine that moves the LCD cursor to the first location, then sends the first 80 characters (starting at (SCREEN_POINTER) to the LCD. Keep in mind the lines are "out of order" on the LCD (First, then third, second, and fourth"
Code: Select all
scrRefresh:
// Moves screen window to LCD
pha
phy
lda #$80
jsr lcdInstr
lda #$00
jsr lcdInstr // Set cursor to 0x0
ldy #$00
dl1: lda ($10),y
jsr lcdChar
iny
cpy #$14
bne dl1
ldy #$28
dl3: lda ($10),y
jsr lcdChar
iny
cpy #$3C
bne dl3
ldy #$14
dl2: lda ($10),y
jsr lcdChar
iny
cpy #$28
bne dl2
ldy #$3C
dl4: lda ($10),Y
jsr lcdChar
iny
cpy #$50
bne dl4
ply
pla
rts
This routine is called by my interrupt service routine. Given the slow refresh rate of the LCD display, 5 times per second is more than enough. BTW, lcdChar is a routing that sends the character on A to the LCD.
Finally, to move the window, I have two routines to scroll up or down a line. This is simply done by adding/substracting 20 from the current SCREEN_POINTER. Some additional code is needed to check for the boundaries of my screen memory.
Code: Select all
scrScrollUp:
pha
lda SCREEN_POINTER
sec
sbc #$14 // Substract 20 from screen_pointer
sta SCREEN_POINTER
bcs scrScrollUpEnd // Carry Clear, no overflow
// overflow
dec SCREEN_POINTER+1 // DEC HI BYTE
lda SCREEN_POINTER+1
cmp #$6f
bne scrScrollUpEnd // Not at screen end, so end routine
lda #<SCREEN_BASE
sta SCREEN_POINTER
lda #>SCREEN_BASE
sta SCREEN_POINTER+1 // Reset screen_pointer to $7000
scrScrollUpEnd:
pla
rts
scrScrollDown:
pha
clc
lda SCREEN_POINTER
adc #$14 // Add 20 to screen pointer
sta SCREEN_POINTER
bcc scrScrollDownEnd // Carry Clear, so overflow
// overflow
inc SCREEN_POINTER+1 // INC HI BYTE
lda SCREEN_POINTER+1
cmp #$7f
bne scrScrollDownEnd // Not at the screen bottom, end
lda #$EC
sta SCREEN_POINTER
lda #$7E
sta SCREEN_POINTER+1
scrScrollDownEnd:
pla
rts
As I said, is very preliminary, and it is been a very long time since I did anything in assembler... there is a big potential for improvements for sure. But I can say it does work.
Hope it helps.
Cheers!