65c02 - processing large amount of text for 20x4 LCD display
-
manhattanmoments
- Posts: 7
- Joined: 27 Apr 2020
65c02 - processing large amount of text for 20x4 LCD display
Hello,
how can I read out vast amount of texts (hundreds of lines) and display them on a 20x4 display?
What I did so far is reading up to 256 characters from the space indicated with .BYTE or .ASCIIZ and displaying it, even with scrolling the lines from bottom to top on the 20x4.
Now I want to address much more text and I fear, I miss even how to ask the right questions regarding how to do it. Because reading from .BYTE is easy to do with just counting until 255 and handing the characters over to the display. But how to proceed for much more text stored in the program? How can i read this out properly?
Thank you for some suggestions.
how can I read out vast amount of texts (hundreds of lines) and display them on a 20x4 display?
What I did so far is reading up to 256 characters from the space indicated with .BYTE or .ASCIIZ and displaying it, even with scrolling the lines from bottom to top on the 20x4.
Now I want to address much more text and I fear, I miss even how to ask the right questions regarding how to do it. Because reading from .BYTE is easy to do with just counting until 255 and handing the characters over to the display. But how to proceed for much more text stored in the program? How can i read this out properly?
Thank you for some suggestions.
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: 65c02 - processing large amount of text for 20x4 LCD dis
You're going to want to come up with a plan to allow the user to interactively pause and/or scroll the display up and down. To access the text, I would use indirect addressing with a zero-page pointer, but I don't have time to provide a specific example ... my broken down house desperately needs my help right now ...
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!
Mike B. (about me) (learning how to github)
Mike B. (about me) (learning how to github)
Re: 65c02 - processing large amount of text for 20x4 LCD dis
It is fairly easy to handle more than 256 characters from a buffer. Consider:
Code: Select all
lda #<Buffer
sta ZPPtr
lda #>Buffer
sta ZPPtr+1
ldy #0
Loop:
lda (ZPPtr),Y
beq Done
jsr Output
iny
bne Loop
inc ZPPtr+1
jmp Loop
Done:
-
daniMolina
- Posts: 214
- Joined: 25 Jan 2019
- Location: Madrid, Spain
Re: 65c02 - processing large amount of text for 20x4 LCD dis
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:
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"
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.
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!
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+1Code: 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
rtsFinally, 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
rtsHope it helps.
Cheers!
-
manhattanmoments
- Posts: 7
- Joined: 27 Apr 2020
Re: 65c02 - processing large amount of text for 20x4 LCD dis
Thank you all so much so far! Since I'm really new in programming in general and in assembly language especially, I tried to take any hint very serious.
Thanks to @barrm95838, I started to read quite a bit on all addressing modes for the 65C02 and especially on indirect addressing, memory structure and so on.
Thanks to you, @BillG, I was then able to apply your code and learn with it. I made it to read out from the data saved in the ROM for more than 255 characters and in my case to store them in the RAM at a certain address.
I am following an approach to enter a routine to display four lines (4x20 characters) at once and then to store the "next" 4 lines (which are the previous ones minus 60 characters) at that buffer in the RAM.
You can imagine now, where i failed: Exactly at that point where the 255 counter needs to subtract the "60 characters" from the pinter (right term here?) when i reached already 255 lines (and the ZPPtr+1 needs to be subtracted as well and so on).
@daniMolina: Thank you for your post! I will try your code as well. I have some questions: Do you store the long text you are displaying at the address starting with $7000? Where is the text located first? Because I burn all the text first in the EEPROM and then try to shift it to an address in the RAM from where I read it in for the display. Where in your code is this transfer from ROM to RAM (starting with $7000, I assume)? I'm pretty sure I am missing something. Thanks for some more hints!
Here is my code example. What works perfectly is displaying the first 255 characters, each 4 lines are perfectly scrolling ... until I reach the 255 threshold and it doesn't to subtract properly (see below in the print "ROWS" routine: SBC #60 and so on):
Thanks to @barrm95838, I started to read quite a bit on all addressing modes for the 65C02 and especially on indirect addressing, memory structure and so on.
Thanks to you, @BillG, I was then able to apply your code and learn with it. I made it to read out from the data saved in the ROM for more than 255 characters and in my case to store them in the RAM at a certain address.
I am following an approach to enter a routine to display four lines (4x20 characters) at once and then to store the "next" 4 lines (which are the previous ones minus 60 characters) at that buffer in the RAM.
You can imagine now, where i failed: Exactly at that point where the 255 counter needs to subtract the "60 characters" from the pinter (right term here?) when i reached already 255 lines (and the ZPPtr+1 needs to be subtracted as well and so on).
@daniMolina: Thank you for your post! I will try your code as well. I have some questions: Do you store the long text you are displaying at the address starting with $7000? Where is the text located first? Because I burn all the text first in the EEPROM and then try to shift it to an address in the RAM from where I read it in for the display. Where in your code is this transfer from ROM to RAM (starting with $7000, I assume)? I'm pretty sure I am missing something. Thanks for some more hints!
Here is my code example. What works perfectly is displaying the first 255 characters, each 4 lines are perfectly scrolling ... until I reach the 255 threshold and it doesn't to subtract properly (see below in the print "ROWS" routine: SBC #60 and so on):
Code: Select all
ZPPTR = $02
.ORG $8000
; SED ; not sure if I need some of these Codes, tried, but didn't change much
; SEC
[ Here is the initialization routine for the display ]
LDA #<TEXT
STA ZPPTR
LDA #>TEXT
STA ZPPTR+1
LDY #0
LP:
LDA (ZPPTR),Y
BEQ DONE
JSR MEM
INY
BNE LP
INC ZPPTR+1
JMP LP
MEM:
STA $0100, X ; storing 80 characters from location $0100 on
INX
CPX #80
BEQ ROWS
RTS
DONE:
LDA #$01 ; clear display
JSR IS
DONE1:
JMP DONE1
; --- SUBROUTINE FOR DISPLAYING 80 CHARACTERS ---
ROWS:
PHY
LDX #0
LDY #0
STY $00
ZIS:
LDY $00
LDA LCD, Y
JSR INSTRUCTION
LDY #0
ZPR:
LDA $0100, X
JSR PRINT
INX
INY
CPY #20
BNE ZPR
LDY $00
INY
STY $00
CPY #4
BNE ZIS
LDX #0
PLY
TYA
SBC #60
TAY
RTS
INSTRUCTION:
[Here is a subroutine for LCD instructions]
PRINT:
[Here is a subroutine for LCD printing characters]
LCD:.BYTE $80, $C0, $94, $D4 ; Starting addresses for the 4 LCD Display lines
TEXT:
.BYTE "[...very long text ...]"
Re: 65c02 - processing large amount of text for 20x4 LCD dis
manhattanmoments wrote:
Here is my code example. What works perfectly is displaying the first 255 characters, each 4 lines are perfectly scrolling ... until I reach the 255 threshold and it doesn't to subtract properly (see below in the print "ROWS" routine: SBC #60 and so on):
The SBC instruction uses the carry flag to indicate whether there is a borrow from a previous subtraction; carry set means no borrow.
Usually, you will see the sequence
Code: Select all
sec
sbc
Code: Select all
CPY #4
BNE ZIS
Anyway...
The code
Code: Select all
INY
BNE LP
INC ZPPTR+1
JMP LP
When you are trying to step back by subtracting three lines from Y, you are not reversing the process when you hit the beginning of a page.
Code: Select all
SEC
SBC #60
BCS Same
DEC ZPPTR+1 ; Go to previous page
Same:
TAY
-
manhattanmoments
- Posts: 7
- Joined: 27 Apr 2020
Re: 65c02 - processing large amount of text for 20x4 LCD dis
BillG wrote:
First, a comment, then I will get to the cause of your problem.
The SBC instruction uses the carry flag to indicate whether there is a borrow from a previous subtraction; carry set means no borrow.
Usually, you will see the sequence
It was not a problem in your case because the code above
was leaving carry set. Advanced programmers sometimes take advantage of these opportunities to save bytes and cycles, but document them well because the code is not as obvious.
The SBC instruction uses the carry flag to indicate whether there is a borrow from a previous subtraction; carry set means no borrow.
Usually, you will see the sequence
Code: Select all
sec
sbc
Code: Select all
CPY #4
BNE ZIS
BillG wrote:
The code
steps from one 256-byte page of text to the next.
When you are trying to step back by subtracting three lines from Y, you are not reversing the process when you hit the beginning of a page.
Code: Select all
INY
BNE LP
INC ZPPTR+1
JMP LP
When you are trying to step back by subtracting three lines from Y, you are not reversing the process when you hit the beginning of a page.
Code: Select all
SEC
SBC #60
BCS Same
DEC ZPPTR+1 ; Go to previous page
Same:
TAY
So the carry flag is set, when after the subtraction of 60 the counter does not need to cross the 255 border again. Correct?
Made my day!
- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: 65c02 - processing large amount of text for 20x4 LCD dis
Just a few tips on efficiency [Edit: see the correction comments further down though]:
What is this part supposed to do?
It loads Y with 0, then immediately increments it to 1; so why not just load 1 into Y in the first place and skip the increment. Next, it is being compared to 4, and of course it will never match (because it's always 1 at that point).
Also this:
Why not just PLA, SBC; and then if you want the value in Y you can do the TAY.
Then there's this:
When it arrives at the STY, both X and Y have 0 in them, and Y gets loaded with 0 again right below; so why not just do STX instead, and skip the first LDY #0. In the JSR INSTRUCTION right after that, does "INSTRUCTION" modify Y? If not, the LDY #0 immediately following the JSR is redundant.
There are more programming tips in that section of the 6502 primer, at http://wilsonminesco.com/6502primer/PgmTips.html .
What is this part supposed to do?
Code: Select all
LDY $00
INY
STY $00
CPY #4
BNE ZISIt loads Y with 0, then immediately increments it to 1; so why not just load 1 into Y in the first place and skip the increment. Next, it is being compared to 4, and of course it will never match (because it's always 1 at that point).
Also this:
Code: Select all
PLY
TYA
SBC #60
TAYWhy not just PLA, SBC; and then if you want the value in Y you can do the TAY.
Then there's this:
Code: Select all
ROWS:
PHY
LDX #0
LDY #0
STY $00
ZIS:
LDY $00 When it arrives at the STY, both X and Y have 0 in them, and Y gets loaded with 0 again right below; so why not just do STX instead, and skip the first LDY #0. In the JSR INSTRUCTION right after that, does "INSTRUCTION" modify Y? If not, the LDY #0 immediately following the JSR is redundant.
There are more programming tips in that section of the 6502 primer, at http://wilsonminesco.com/6502primer/PgmTips.html .
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: 65c02 - processing large amount of text for 20x4 LCD dis
Hmm, there may be some confusing between load-immediate and load-zeropage in the above analysis. But some of the points remain valid.
- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: 65c02 - processing large amount of text for 20x4 LCD dis
Chromatix wrote:
Hmm, there may be some confusing between load-immediate and load-zeropage in the above analysis. But some of the points remain valid.
Oops. You're right. My mistake comes because numbers as operands should virtually never be addresses! Addresses need to be given descriptive names. Besides the readability factor, if you ever need to change it, you only change it in one place, and then every place the assembler sees the name, it substitutes-in the right address.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
-
daniMolina
- Posts: 214
- Joined: 25 Jan 2019
- Location: Madrid, Spain
Re: 65c02 - processing large amount of text for 20x4 LCD dis
manhattanmoments wrote:
@daniMolina: Thank you for your post! I will try your code as well. I have some questions: Do you store the long text you are displaying at the address starting with $7000? Where is the text located first? Because I burn all the text first in the EEPROM and then try to shift it to an address in the RAM from where I read it in for the display. Where in your code is this transfer from ROM to RAM (starting with $7000, I assume)? I'm pretty sure I am missing something. Thanks for some more hints!
It's stored nowhere. I have a "charPrint" routine that moves a character to (SCREEN_CURSOR_POINTER) which is $7000 on startup. After each char is printed, it increases the pointer by 1. On top of this I've built a "stringPrint", "decPrint", and "hexPrint" routines.
My idea was not to display a long text, but to have the hability to print to screen, and then scrollback to see what's been going on, so there's no initial big text stored anywhere.