65c02 - processing large amount of text for 20x4 LCD display

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
manhattanmoments
Posts: 7
Joined: 27 Apr 2020

65c02 - processing large amount of text for 20x4 LCD display

Post by manhattanmoments »

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.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by barrym95838 »

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)
BillG
Posts: 710
Joined: 12 Mar 2020
Location: North Tejas

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by BillG »

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

Post by daniMolina »

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!
manhattanmoments
Posts: 7
Joined: 27 Apr 2020

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by manhattanmoments »

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):

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 ...]"

Attachments
65C02.jpg
BillG
Posts: 710
Joined: 12 Mar 2020
Location: North Tejas

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by BillG »

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):
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

Code: Select all

    sec
    sbc
It was not a problem in your case because the code above

Code: Select all

	CPY #4
	BNE ZIS
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.

Anyway...

The code

Code: Select all

	INY
	BNE LP
	INC ZPPTR+1
	JMP LP
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

	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

Post by manhattanmoments »

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

Code: Select all

    sec
    sbc
It was not a problem in your case because the code above

Code: Select all

	CPY #4
	BNE ZIS
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.
Thank you! That is very helpful to understand. I will integrate for now SEC and SBC and comment it.

BillG wrote:
The code

Code: Select all

	INY
	BNE LP
	INC ZPPTR+1
	JMP LP
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

	SEC
	SBC #60
	BCS Same

	DEC ZPPTR+1   ; Go to previous page

Same:
	TAY
Thanks a lot for this information! It solved the problem, everything works fine now!

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!
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by GARTHWILSON »

Just a few tips on efficiency [Edit: see the correction comments further down though]:

What is this part supposed to do?

Code: Select all

   LDY $00
   INY
   STY $00
   CPY #4
   BNE ZIS

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:

Code: Select all

   PLY
   TYA
   SBC #60
   TAY

Why 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?
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by Chromatix »

Hmm, there may be some confusing between load-immediate and load-zeropage in the above analysis. But some of the points remain valid.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by GARTHWILSON »

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?
daniMolina
Posts: 214
Joined: 25 Jan 2019
Location: Madrid, Spain

Re: 65c02 - processing large amount of text for 20x4 LCD dis

Post by daniMolina »

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.
Post Reply