How to clear the whole display?

Building your first 6502-based project? We'll help you get started here.
Nabir14
Posts: 8
Joined: 03 Aug 2024

How to clear the whole display?

Post 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?
Attachments
Result
Result
IMG_20240803_122709.jpg (8.51 KiB) Viewed 5309 times
John West
Posts: 383
Joined: 03 Sep 2002

Re: How to clear the whole display?

Post 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
fachat
Posts: 1123
Joined: 05 Jul 2005
Location: near Heidelberg, Germany
Contact:

Re: How to clear the whole display?

Post 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
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: How to clear the whole display?

Post 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.
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?
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

John West wrote:
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.
Attachments
New result
New result
IMG_20240803_151423.jpg (10.28 KiB) Viewed 5285 times
fachat
Posts: 1123
Joined: 05 Jul 2005
Location: near Heidelberg, Germany
Contact:

Re: How to clear the whole display?

Post 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.
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

John West wrote:
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 :D .
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

fachat wrote:
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.
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

fachat wrote:
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.
Last edited by Nabir14 on Sat Aug 03, 2024 9:47 am, edited 1 time in total.
fachat
Posts: 1123
Joined: 05 Jul 2005
Location: near Heidelberg, Germany
Contact:

Re: How to clear the whole display?

Post 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é
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

fachat wrote:
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.
fachat
Posts: 1123
Joined: 05 Jul 2005
Location: near Heidelberg, Germany
Contact:

Re: How to clear the whole display?

Post 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é
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: How to clear the whole display?

Post 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
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

BigEd wrote:
Welcome, Nabir14!

I wouldn't be surprised to learn that you're using easy6502 by Nick Morgan:
https://skilldrick.github.io/easy6502/#first-program
I am absolutely :)
Nabir14
Posts: 8
Joined: 03 Aug 2024

Re: How to clear the whole display?

Post by Nabir14 »

fachat wrote:
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.
Post Reply