Page 1 of 2
Addressing into screen memory, how?
Posted: Sun Nov 06, 2022 8:07 am
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
Re: Addressing into screen memory, how?
Posted: Sun Nov 06, 2022 8:32 am
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
Juggling registers on the 6502 can be frustrating, you often need to store them in memory (preferably zero page).
Re: Addressing into screen memory, how?
Posted: Sun Nov 06, 2022 8:26 pm
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.
Re: Addressing into screen memory, how?
Posted: Sun Nov 13, 2022 5:13 am
by MartinC
Thanks for the tip
Re: Addressing into screen memory, how?
Posted: Sun Nov 13, 2022 5:17 am
by MartinC
I'll have a rethink and try an approach without x and y registers
Re: Addressing into screen memory, how?
Posted: Mon Nov 14, 2022 1:23 am
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.
Re: Addressing into screen memory, how?
Posted: Mon Nov 14, 2022 8:25 am
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.
Re: Addressing into screen memory, how?
Posted: Sat Nov 19, 2022 7:14 am
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
Re: Addressing into screen memory, how?
Posted: Sat Nov 19, 2022 10:07 am
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.
Re: Addressing into screen memory, how?
Posted: Sun Nov 20, 2022 9:16 am
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.
I'll look again at Mike's loop and try something like that.
Re: Addressing into screen memory, how?
Posted: Sun Nov 20, 2022 12:16 pm
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
Re: Addressing into screen memory, how?
Posted: Sun Nov 20, 2022 2:09 pm
by chysn
Make sure that color memory gets set, too. Alternately, change the screen color so that white characters can be seen.
Re: Addressing into screen memory, how?
Posted: Sun Nov 20, 2022 2:25 pm
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.
Re: Addressing into screen memory, how?
Posted: Mon Nov 21, 2022 12:23 pm
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...
Where am I going wrong now?
Re: Addressing into screen memory, how?
Posted: Mon Nov 21, 2022 3:47 pm
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.