Page 1 of 2
How to clear the whole display?
Posted: Sat Aug 03, 2024 6:31 am
by Nabir14
I am new to 6502 programming. I wanted to make a game using this assembly language. My first program fills the whole display with white pixels.
Code:
Code: Select all
ldx #$ff
lda #$01
drawPixel:
dex
cpx #$00
sta $0200,x
sta $0300,x
sta $0400,x
sta $0500,x
bne drawPixel
brk
However it is not doing it correctly. It stops before the last pixel so it doesn't fill some pixels. How do I make it fill every single pixel?
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 7:06 am
by John West
Can you see why your code doesn't work? It's worth spending a little time walking through it yourself instruction by instruction to see exactly what it's doing, and think about how that differs from what you expected.
Spoilers below:
I assume you have a 32x32 display, with each pixel being represented by one byte in the range $0200 - $05FF. To clear it, you want to write to every byte in this range. You're counting down to 0, which is an idiomatic thing to do on the 6502 as many instructions automatically set the Z flag. So you want the first bytes to be written at $02FF, $03FF, $04FF, and $05FF.
Your code loads X with $FF, which you'd think would be right. But the first thing it does is decrement it, so the first time through the loop it's actually writing to $02FE, $03FE, $04FE, and $05FE. What you want is for X to be $FF
after that first decrement. Loading it with $00 will do that.
I said before that many 6502 instructions automatically set the Z flag. DEX is one of them, so you don't need the CPX #$00 after it. It's not wrong to leave it in, but idiomatic 6502 code will omit it. It's worth noting that STA doesn't change the flags, so although separating the branch from the instruction that sets the flag makes me nervous, there's nothing wrong with it.
This code should work:
Code: Select all
ldx #$ff
lda #$00 ; changed $ff to $00 so the first writes are to $xxff
drawPixel:
dex
; removed cpx #$00 as it is redundant
sta $0200,x
sta $0300,x
sta $0400,x
sta $0500,x
bne drawPixel
brk
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 8:25 am
by fachat
An additional comment:
You do an operation that sets the flags, then do some other operations, and only then check the flag.
When you further work with the code, it is easy to forget about that and insert other operations that change the flags. For example, if you want to change the loop to invert the screen, suddenly you have flag changing operations between the dex and the check with beq.
Therefore I recommend keeping the flag change and the check closer together.
Also, John's version already uses the fact that the index registers are 8 bits and overflow after $ff (or underflow to $ff when you decrement them from $00).
Here's my version that uses that fact the other way:
Code: Select all
LDX #$00
TXA ; reuse the value from XR and copy it to AC to clear - saves a byte
L1 STA $0200,X
STA $0300,X
STA $0400,X
STA $0500,X
INX ; count from 0 to $ff and overflow to 0 again
BNE L1 ; loop as long as 0 is not yet reached again
BRK
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 8:32 am
by GARTHWILSON
To the preceding excellent replies, I will add that if you have a 65c02 (ie, CMOS, not NMOS), you can omit the LDA #0 and use STZ $0200,X (STZ being "STore Zero") in place of STA $0200,X (and $300,X, $400,X, and $500,X).
And, to expand, an automatic compare-to-zero instruction is built into the following 65c02 instructions: LDA, LDX, LDY, INC, INX, INY, DEC, DEX, DEY, INA, DEA, AND, ORA, EOR, ASL, LSR, ROL, ROR, PLA, PLX, PLY, SBC, ADC, TAX, TXA, TAY, TYA, and TSX, reflecting the result of the operation.
The 6502 Primer's programming-tips page has more of this kind of stuff.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:18 am
by Nabir14
Can you see why your code doesn't work? It's worth spending a little time walking through it yourself instruction by instruction to see exactly what it's doing, and think about how that differs from what you expected.
Spoilers below:
I assume you have a 32x32 display, with each pixel being represented by one byte in the range $0200 - $05FF. To clear it, you want to write to every byte in this range. You're counting down to 0, which is an idiomatic thing to do on the 6502 as many instructions automatically set the Z flag. So you want the first bytes to be written at $02FF, $03FF, $04FF, and $05FF.
Your code loads X with $FF, which you'd think would be right. But the first thing it does is decrement it, so the first time through the loop it's actually writing to $02FE, $03FE, $04FE, and $05FE. What you want is for X to be $FF
after that first decrement. Loading it with $00 will do that.
I said before that many 6502 instructions automatically set the Z flag. DEX is one of them, so you don't need the CPX #$00 after it. It's not wrong to leave it in, but idiomatic 6502 code will omit it. It's worth noting that STA doesn't change the flags, so although separating the branch from the instruction that sets the flag makes me nervous, there's nothing wrong with it.
This code should work:
Code: Select all
ldx #$ff
lda #$00 ; changed $ff to $00 so the first writes are to $xxff
drawPixel:
dex
; removed cpx #$00 as it is redundant
sta $0200,x
sta $0300,x
sta $0400,x
sta $0500,x
bne drawPixel
brk
Well first I did check multiple times what happened its just the same result everytime. I did notice that the DEX decrements it and makes it 2FE 3FE... But shifting the position of DEX makes it end before a pixel. Using your code the same result happened it still started after a pixel.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:35 am
by fachat
I think John's code has an issue in that he changed the value of A to $00 instead of X - this should have been changed to $00.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:40 am
by Nabir14
Can you see why your code doesn't work? It's worth spending a little time walking through it yourself instruction by instruction to see exactly what it's doing, and think about how that differs from what you expected.
Spoilers below:
I assume you have a 32x32 display, with each pixel being represented by one byte in the range $0200 - $05FF. To clear it, you want to write to every byte in this range. You're counting down to 0, which is an idiomatic thing to do on the 6502 as many instructions automatically set the Z flag. So you want the first bytes to be written at $02FF, $03FF, $04FF, and $05FF.
Your code loads X with $FF, which you'd think would be right. But the first thing it does is decrement it, so the first time through the loop it's actually writing to $02FE, $03FE, $04FE, and $05FE. What you want is for X to be $FF
after that first decrement. Loading it with $00 will do that.
I said before that many 6502 instructions automatically set the Z flag. DEX is one of them, so you don't need the CPX #$00 after it. It's not wrong to leave it in, but idiomatic 6502 code will omit it. It's worth noting that STA doesn't change the flags, so although separating the branch from the instruction that sets the flag makes me nervous, there's nothing wrong with it.
This code should work:
Code: Select all
ldx #$ff
lda #$00 ; changed $ff to $00 so the first writes are to $xxff
drawPixel:
dex
; removed cpx #$00 as it is redundant
sta $0200,x
sta $0300,x
sta $0400,x
sta $0500,x
bne drawPixel
brk
Ok I fixed somethings and it's now fixed. Basically your code is almost correct but the problem is that your setting the LDA to $00 instead of LDX I mean the LDA is used for setting the pixel color and setting it to $00 dosent change anything because the position (LDX) is still $ff. I did a idiotic thing trying to count down from $ff so now I fixed it and it now counts from $00. Thank you for your code it works

.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:41 am
by Nabir14
I think John's code has an issue in that he changed the value of A to $00 instead of X - this should have been changed to $00.
Yes you are correct thanks for telling. I almost forgot that LDX is used for position.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:43 am
by Nabir14
An additional comment:
You do an operation that sets the flags, then do some other operations, and only then check the flag.
When you further work with the code, it is easy to forget about that and insert other operations that change the flags. For example, if you want to change the loop to invert the screen, suddenly you have flag changing operations between the dex and the check with beq.
Therefore I recommend keeping the flag change and the check closer together.
Also, John's version already uses the fact that the index registers are 8 bits and overflow after $ff (or underflow to $ff when you decrement them from $00).
Here's my version that uses that fact the other way:
Code: Select all
LDX #$00
TXA ; reuse the value from XR and copy it to AC to clear - saves a byte
L1 STA $0200,X
STA $0300,X
STA $0400,X
STA $0500,X
INX ; count from 0 to $ff and overflow to 0 again
BNE L1 ; loop as long as 0 is not yet reached again
BRK
This code has a problem see it is transferring the X value to A. A is used for color so setting the A to 0 (value of X) makes it black and you can't change the color at all. I replaced it with LDA #$01 to make it white and make it so that I can change the color.
But Thank you for your reply it helped and I fixed the code.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:45 am
by fachat
Great you managed to fix it! First steps into a new world!
What you haven't told us (or I missed it), what system are you working on/for?
André
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 9:52 am
by Nabir14
Great you managed to fix it! First steps into a new world!
What you haven't told us (or I missed it), what system are you working on/for?
André
I am learning assembly languages and I wanted to use an assembly language where accessing the display is very easy so I can draw graphics on it. To make games too. I am working on Linux.
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 11:06 am
by fachat
Sorry I meant to ask what 6502 system you are developing for.
I am unaware of a real 6502 that has its screen at $0200.
It would be a pity if you develop a game and it only runs on a PC in a simulator.
Obviously you are using a simulator or emulator, which one is this?
André
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 11:48 am
by BigEd
Welcome, Nabir14!
I wouldn't be surprised to learn that you're using easy6502 by Nick Morgan:
https://skilldrick.github.io/easy6502/#first-program
Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 6:16 pm
by Nabir14
I am absolutely

Re: How to clear the whole display?
Posted: Sat Aug 03, 2024 6:17 pm
by Nabir14
Sorry I meant to ask what 6502 system you are developing for.
I am unaware of a real 6502 that has its screen at $0200.
It would be a pity if you develop a game and it only runs on a PC in a simulator.
Obviously you are using a simulator or emulator, which one is this?
André
No I am not even close to make games. I want to make games for the NES. For now I am learning 6502 and I am following the Nick Morgans Easy6502 tutorial.