Addressing into screen memory, how?

Basic and Machine Language

Moderator: Moderators

MartinC
Vic 20 Drifter
Posts: 33
Joined: Tue Oct 25, 2022 12:18 pm
Website: https://winterfam.co.uk
Location: Kent,uk
Occupation: Author

Addressing into screen memory, how?

Post by MartinC »

in another thread, chysn wrote:[...]
Thanks for the reply. I'm using the CMB PRG Studio environment's assembler. I'm just starting out learning the language and trying to figure out how to load the screen map I exported and display it. Using "Top-Down Assembly Language for your C64 and Vic20" as a guide, I'm trying to cobble together a routine to do this. But, I'm stuck :-)....

I've written a routine that I want to read through the screen map and put each character in the x and y position I track through the X and Y registers. But when I need to read the character from the map using indirect addressing something like

LDY #0
LDA (SCMAPL),Y

I have overwritten Y and lost track of which row of the screen I am on. Why do I need the Y value anyway in the LDA call? Thought I might be able to push Y onto the stack and pop it off again, but that doesn't seem to be a thing without going through A first??? Which then means I lose by character value...

I'm probably making this harder than it needs to be, any pointers (pardon the pun) gratefully received.

Cheers

Martin
User avatar
srowe
Vic 20 Scientist
Posts: 1340
Joined: Mon Jun 16, 2014 3:19 pm

Re: Addressing into screen memory, how?

Post by srowe »

MartinC wrote: Sun Nov 06, 2022 8:07 am Why do I need the Y value anyway in the LDA call?
Because there are two addressing modes that give you indirection through a zero page pointer but they both also use an index register. If you can spare using .X then you can always clear it and use

Code: Select all

LDA (SCMAPL,X)
Juggling registers on the 6502 can be frustrating, you often need to store them in memory (preferably zero page).
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Addressing into screen memory, how?

Post by chysn »

MartinC wrote: Sun Nov 06, 2022 8:07 am I've written a routine that I want to read through the screen map and put each character in the x and y position I track through the X and Y registers.
I realize that it's dangerous to make sweeping statements, but in general, you'll be happier if you don't try to use the 6502 registers as part of an application data structure. They're used for so many things that trying to use X and Y registers to correspond to X and Y screen position will drive you mad except in the most trivial programs. Instead, allocate memory locations to data structures of any kind.
MartinC
Vic 20 Drifter
Posts: 33
Joined: Tue Oct 25, 2022 12:18 pm
Website: https://winterfam.co.uk
Location: Kent,uk
Occupation: Author

Re: Addressing into screen memory, how?

Post by MartinC »

Thanks for the tip
MartinC
Vic 20 Drifter
Posts: 33
Joined: Tue Oct 25, 2022 12:18 pm
Website: https://winterfam.co.uk
Location: Kent,uk
Occupation: Author

Re: Addressing into screen memory, how?

Post by MartinC »

I'll have a rethink and try an approach without x and y registers
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Addressing into screen memory, how?

Post by Mike »

MartinC wrote:I'll have a rethink and try an approach without x and y registers
You might have misunderstood chysn's remark. Trying to do the task at hand (addressing into screen), or pretty much anything non-trivial in 65xx assembly involves informed use of the accumulator, and the X, Y index-registers as scratch pads. All relevant data processing uses the accumulator; address indexing and counting are done using the X and Y registers.

What does not work is treating any of them as 'variables' to hold values for any prolonged time. You will be using memory for that, preferably in the zero page if pointers into memory are involved. A similar question was posed some time ago, where the poster asked for a non-existent address mode to express his program ideas.

That being said, taking X and Y out of the tool set for a solution inevitably leads to self-modifying code. That type of code has its own pitfalls, bad maintainability being one of them. And not necessary here, either.

You find examples how to address into screen memory in the thread 'A sample programming session in VICMON':
  • "BALLPING" uses co-ordinate addressing and derives the screen address of the ball from tables, while the ball co-ordinate values are held in zero page memory,
  • "KILLER COMET" keeps running addresses for meteor and rocket into screen memory, and updates these addresses as the objects are moved. +/- 1 moves an object horizontally, +/- 22 moves an object vertically (given the standard screen width of 22 characters/line).
Both methods can be combined in case of need. What you shouldn't do is, just store the running screen address, and then trying to calculate x- and y-co-ordinates from that (for whatever reason) - this needs a division which is very expensive on the 65xx.

Finally, if you are going to initialise the screen from some other buffer in memory, you do not need to consider a co-ordinate system "in the background". Rather, you use the indexed address modes of the 6502 as follows:

Code: Select all

 LDX #0
.loop
 LDA buffer,X
 STA screen,X
 LDA buffer+256,X
 STA screen+256,X
 INX
 BNE loop
buffer and screen are symbols supposed to be defined somewhere else in the source. This is a simple two-fold unrolled loop that copies 512 bytes from the buffer to the screen. Counting over whole 256 byte pages keeps this code short and simple, and in most cases it should not matter that the 6 bytes immediately after the visible screen are also being written to.
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Addressing into screen memory, how?

Post by chysn »

While it seems like you're mostly interested in copying a block of memory, and Mike's 512-byte copy routine will do that, you might find this helpful as well.

I didn't mean to say that you shouldn't use X and Y registers. I meant that you should use memory for data structures, like the x and y position of something. For example, let's say that the x position will be in memory location $00, and the y position will be in $01. You can then use registers to pass data to a routine, like the KERNAL's PLOT routine:

Code: Select all

ldy $00     ; Get x position (yes, PLOT uses the Y register as its x position)
ldx $01     ; Get y position (yes, vice versa)
clc         ; Clear carry flag indicates to PLOT that it should set cursor position
jsr $fff0   ; Call PLOT to place cursor at x,y (0,0 being the upper-left corner)

lda #"*"    ; Call CHROUT to place an asterisk at the cursor position
jsr $ffd2   ; ,,
Now you can manipulate $00 and $01 with INC or DEC (or any other math) to move your asterisk around. Outside your placement routine, or outside PLOT, you can use X and Y registers for other stuff, knowing that your object's x and y positions are safe in $00 and $01.

Hopefully that clarifies what I meant to say.
MartinC
Vic 20 Drifter
Posts: 33
Joined: Tue Oct 25, 2022 12:18 pm
Website: https://winterfam.co.uk
Location: Kent,uk
Occupation: Author

Re: Addressing into screen memory, how?

Post by MartinC »

Thank you both for your replies. I'm using CBM PRG Studio v4's assembler and tools. I have generated a customer char set and screen in the designers and saved them off to binary files in the project folder.

Then I have the following code, cobbled together from watching YouTube and reading (I am a total newb at assembly).

Code: Select all

; 10 SYS (5120)

*=$1001

        BYTE    $0E, $10, $0A, $00, $9E, $20, $28,  $35, $31, $32, $30, $29, $00, $00, $00


*=$1400

                jsr defchr         
                jsr drawmap
                rts
                 


defchr         ; redefine char memory
                lda #255
                sta $9005
                rts

drawmap
                lda SCRL
                sta $fb
                lda SCRH
                sta $fc
                lda MAPL
                sta $fd
                lda MAPH
                sta $fe
        
                ldx #2
main_lp         ldy #$00
loop1           lda ($fd),y
                sta ($fb),y
                iny
                bne loop1
                inc $fc
                inc $fe
                dex
                bne main_lp
                rts

MAPH            byte >SCRMAP
MAPL            byte <SCRMAP
SCRN=7680
SCRL            byte <SCRN
SCRH            byte >SCRN

SCRMAP
incbin         dksyscreen.bin


*=$1c00
incbin          dskychars.bin       
I *think* I am loading the new character set because I see some of my custom chars - but the screen is corrupting so I guess I have garbage. So question 1 is, is there a better way to do this?

Then I *think* I am looping through the 506 bytes of the screen design loaded from the binary and outputting that to the screen using the technique you kindly described above. Question 2 then is why am I only getting some of the screen displayed rather than the whole thing. I have padded the binary file to 505 bytes and exported blank rows and trailing spaces in the export options.

Thanks again guys, any help gratefully received.

Martin
User avatar
thegg
Vic 20 Amateur
Posts: 69
Joined: Mon Aug 30, 2021 4:49 am
Location: England
Occupation: retired

Re: Addressing into screen memory, how?

Post by thegg »

I think your main problem is that you are not loading the zero page pointers with the addresses you think you are. Try changing your code to:
Lda #<scrn
Sta $fb
Lda #>scrn
Sta $fc
Lda #<scrmap
Sta $fd
Lda #>scrmap
Sta $fe

The construct you trying does not work in CBM Prg.

Alternatively, you could use the loop Mike suggests, but I guess you are trying to learn how to use zero page addressing.

By the way, if you are using CBM Prg you can look at the Assembly Dump to check your code is assembling as you think it is.

Check back if you need any clarification.
MartinC
Vic 20 Drifter
Posts: 33
Joined: Tue Oct 25, 2022 12:18 pm
Website: https://winterfam.co.uk
Location: Kent,uk
Occupation: Author

Re: Addressing into screen memory, how?

Post by MartinC »

Thanks Thegg - what's the difference with the code sample you gave me? Tried it and same results.

Setting the redefined char set aside and commenting that out, I get the result below. The top row looks as expected, it all goes wrong after that.

Screenshot 2022-11-20 151323.png

I'll look again at Mike's loop and try something like that.
Last edited by Mike on Mon Jan 09, 2023 5:29 pm, edited 1 time in total.
Reason: attachment/screenshot repaired
User avatar
vicist
Vic 20 Afficionado
Posts: 352
Joined: Tue Oct 09, 2012 5:26 am
Location: Sheffield, UK

Re: Addressing into screen memory, how?

Post by vicist »

Try it like this:-

Code: Select all

; 10 SYS (5120)

*=$1001

        BYTE    $0E, $10, $0A, $00, $9E, $20, $28,  $35, $31, $32, $30, $29, $00, $00, $00
        
        
MAP   =   [start of map data]
SCRN  =   7680


*=$1400

                jsr defchr         
                jsr drawmap
                rts
                 


defchr         ; redefine char memory
                lda #255
                sta $9005
                rts

drawmap
                lda #<SCRN
                sta $fb
                lda #>SCRN
                sta $fc
                lda #<MAP
                sta $fd
                lda #>MAP
                sta $fe
        
                ldx #2
main_lp         ldy #$00
loop1           lda ($fd),y
                sta ($fb),y
                iny
                bne loop1
                inc $fc
                inc $fe
                dex
                bne main_lp
                rts


incbin         dksyscreen.bin
incbin         dskychars.bin       
If you declare all your variables at or near the start, you'll be able to find them should you need to change anything.
You don't need to declare the start of your charset if you save them with a start address.

PS. are these names correct or are they supposed to be the same?
dksyscreen.bin
dskychars.bin
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Addressing into screen memory, how?

Post by chysn »

Make sure that color memory gets set, too. Alternately, change the screen color so that white characters can be seen.
User avatar
thegg
Vic 20 Amateur
Posts: 69
Joined: Mon Aug 30, 2021 4:49 am
Location: England
Occupation: retired

Re: Addressing into screen memory, how?

Post by thegg »

Your code is loading the address from a memory location ie $1436, $1437,$1435,$1434 whereas my suggestion is loading the immediate low and high values of the screen map and video matrix. In actual fact I was wrong to say your code will not work. Looking closer it will, it is just less clear what is going on.

I think the reason you are not getting the results you expect might be in the binary files you are including. I am guessing you have exported your binary files from CBM Prg's character and screen editor tools.

The screen editor exports its raw data with a load address in the first 2 bytes. If you want to include it in an assembly, you need to instruct the assembler to skip the first 2 bytes, eg incbin "file.bin",2.

The character editor export to a file contains fields to control how many characters you export. If you make a file with more than 64 characters and load it at $1c00 it will run into your screen data at $1e00. I don't think this is happening here, but it is something to be aware of. Personally, I include the character cst file rather than the binary. Look at CBM Prg help under Directives for details.

A final thing to note is that you are not setting the colour data for your screen. The screen editor can export colour data as well as character data. I think that if you add colour in your loop you will get a different result. The address to load for video matrix at $1e00 is $9600. So :
ldy #0
lda #colour
loop sta $9600,y
sta $9700,y
iny
bne loop

should suffice.

Hope that helps. I do recommend looking at the CBM Prg help for the editors and directives for more detail.
MartinC
Vic 20 Drifter
Posts: 33
Joined: Tue Oct 25, 2022 12:18 pm
Website: https://winterfam.co.uk
Location: Kent,uk
Occupation: Author

Re: Addressing into screen memory, how?

Post by MartinC »

Hey all,

Thanks for the kind replies.

I've taken on board what was suggested and ended up with:

Code: Select all

; 10 SYS (5120)

*=$1001

        BYTE    $0E, $10, $0A, $00, $9E, $20, $28,  $35, $31, $32, $30, $29, $00, $00, $00

SCRN=$1e00
COLOUR=$9600
CMAP=$1010
SMAP=$120A

SCRMAP
incbin         "DSKY1.sdd",1,1

*=$1400

                jsr defchr 
                jsr docolour
                jsr drawmap
                rts
                 


defchr         ; redefine char memory
                lda #255
                sta $9005
                rts

drawmap
                lda #<SCRN
                sta $fb
                lda #>SCRN
                sta $fc
                lda #<SMAP
                sta $fd
                lda #>SMAP
                sta $fe
        
                ldx #2
main_lp         ldy #$00
loop1           lda ($fd),y
                sta ($fb),y
                iny
                bne loop1
                inc $fc
                inc $fe
                dex
                bne main_lp
                rts

docolour        lda #<COLOUR
                sta $fb
                lda #>COLOUR
                sta $fc
                lda #<CMAP
                sta $fd
                lda #>CMAP
                sta $fe
                ldx #2
cmain_lp         ldy #$00
cloop1           lda ($fd),y
                sta ($fb),y
                iny
                bne cloop1
                inc $fc
                inc $fe
                dex
                bne cmain_lp
                rts
        


*=$1c00
incbin          "DSKY1.cst",0,64       
Still no joy...
Screenshot 2022-11-21 182222.png

Where am I going wrong now?
Last edited by Mike on Mon Jan 09, 2023 5:30 pm, edited 1 time in total.
Reason: attachment/screenshot repaired
User avatar
thegg
Vic 20 Amateur
Posts: 69
Joined: Mon Aug 30, 2021 4:49 am
Location: England
Occupation: retired

Re: Addressing into screen memory, how?

Post by thegg »

A couple of small points.
There is not enough room between the end of your Basic stub and the start of your code for the screen and colour data. So your code will be assembled on top of the last few bytes of your screen data.

You are including 65 character definitions (0-64) so the last definition is corrupted when you write to row 0 of the screen.

That said, as far as I can see, you should see the screen you designed providing your screen is using characters 0-63 in the character set you are loading.

If you can upload your complete project, I'll happily look at your character and screen definitions.

What version of CBM Prg Studio are you using? I think there were some issues with the screen editor in early versions. I'm using the newly released Version 4 which fixes some of the issues.
Post Reply