Need help with a loop that has 16 bit counter
Need help with a loop that has 16 bit counter
So, I'm trying to make a loop that counts to 960 (decimal), but I have never used 16 bit numbers so far, so I have no idea how to do it. What the loop is supposed to do is that it loads data from different location with indexed X addressing mode and stores it to $2007 (which automatically stores the data to pre-defined location and stores the next data to the next slot). Here is example (8 bit tough):
LDA $2002 ; Reset High/Low latch
LDA #$20 ; Defines high and low bytes
STA $2006
LDA #$00
STA $2006
LDX #$00 ; Load 0 to X for loop
DrawBackground: ; Loop for drawing background
LDA background, x
STA $2007
INX
CPX #$FF
BNE DrawBackground ; Branch to DrawBackground if X is less than $FF
LDA $2002 ; Reset High/Low latch
LDA #$20 ; Defines high and low bytes
STA $2006
LDA #$00
STA $2006
LDX #$00 ; Load 0 to X for loop
DrawBackground: ; Loop for drawing background
LDA background, x
STA $2007
INX
CPX #$FF
BNE DrawBackground ; Branch to DrawBackground if X is less than $FF
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Need help with a loop that has 16 bit counter
Here's one way to do it:
I didn't test it. Hopefully I don't have mistakes.
Code: Select all
LDA $2002 ; (Instead of a number, it's better to give addresses meaningful names.)
LDA $20
STA $2006
STZ $2006 ; 65c02 STZ allows you to skip the LDA #0.
LDA #<background ; One way to do it is to put the address of "background" into a pair of ZP bytes
STA BG_ind ; to use for indirect addressing, then increment it, instead of indexing by X
LDA #>background ; (since X doesn't have enough bits). Remember it's low-byte-first order.
STA BG_ind + 1
DrawBackground:
LDA (BG_ind) ; Do the transfer. (If you use an NMOS 6502, you'll have to use LDA (BG_ind),Y or
STA $2007 ; LDA (BG_ind,X), with Y or X zeroed. 65c02 allows the indirect without the X or Y.
INC BG_ind ; Now increment and test your indirect number.
BNE db1
INC BG_ind + 1
db1: LDA BG_ind ; After the incr, compare to target value, starting with low byte.
CMP #<{background + $3C0} ; $3C0 is the hex value of 960. "<" is for low byte.
BNE DrawBackground
LDA BG_ind + 1 ; Now compare high byte (hence the "+1").
CMP #>{background + $3C0} ; The ">" in many assemblers puts the high byte in the operand.
BNE DrawBackground
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Need help with a loop that has 16 bit counter
You can easily loop 960 times by nesting loops. If the y register is available, you could just do 15 outer loops with y and 64 inner loops with x (15 * 64 == 960).
What about your background data? Is it repetitive in a Flintstones kind of way? If not, then you need to construct a 16-bit address pointer into your background data using the (dp),y addressing mode, and increment the high-byte of the pointer address when y wraps around.
Mike
[Edit: Darn! I see that Garth scooped me by a few minutes! My version is about 5 bytes longer, but works on any 6502, and is a tiny bit faster than Garth's version.]
What about your background data? Is it repetitive in a Flintstones kind of way? If not, then you need to construct a 16-bit address pointer into your background data using the (dp),y addressing mode, and increment the high-byte of the pointer address when y wraps around.
Code: Select all
...
DrawBackground:
lda #<background ; init background pointer
sta zppointer
lda #>background
sta zppointer+1
ldy #0
DrawLoop: ; transfer 3 full pages of data
lda (zppointer),y
sta $2007
iny
bne DrawLoop
inc zppointer+1 ; point to next page
lda zppointer+1
cmp #>background+3 ; last page of data?
bne Drawloop ; No. transfer another full page
Drawloop2: ; Yes. transfer final (partial) page
lda (zppointer),y
sta $2007
iny
cpy #960-768 ; done?
bne Drawloop2
...
[Edit: Darn! I see that Garth scooped me by a few minutes! My version is about 5 bytes longer, but works on any 6502, and is a tiny bit faster than Garth's version.]
Re: Need help with a loop that has 16 bit counter
GARTHWILSON wrote:
One way to do it is to put the address of "background" into a pair of ZP bytes
The way I learned to load the background is doing this (not sure if this is how everybody does it):
Code: Select all
background:
.db $2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F ; Row 0 1/2 - Writes
.db $2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F ; Row 0 2/2 - 'HELLO!
.db $2F,$11,$0E,$15,$15,$18,$27,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F ; Row 1 1/2 - THIS IS A TEST
.db $2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F ; Row 1 2/2 - FOR DRAWING
.db $2F,$1D,$11,$12,$1C,$2F,$12,$1C,$2F,$0A,$2F,$1D,$0E,$1C,$1D,$2F ; Row 2 1/2 - BACKGROUND.'
.db $2F,$0F,$18,$1B,$2F,$0D,$1B,$0A,$20,$12,$17,$10,$2F,$2F,$2F,$2F ; Row 2 2/2 - on screen
.db $2F,$0B,$0A,$0C,$14,$10,$1B,$18,$1E,$17,$0D,$24,$2F,$2F,$2F,$2F ; Row 3 1/2
.db $2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F,$2F ; Row 3 2/2- BitWise
- In Memoriam
- Posts: 996
- Joined: 02 Mar 2004
- Location: Berkshire, UK
- Contact:
Re: Need help with a loop that has 16 bit counter
You can squeeze a few cycles (and one byte!) using X to count the pages
It shouldn't matter where the data for the background is. The assembler will work out the actual address and use it in the <background and >background expressions used to initialise the pointer.
Code: Select all
DrawBackground:
lda #<background ; init background pointer
sta zppointer
lda #>background
sta zppointer+1
ldx #>960
ldy #0
DrawLoop: ; transfer 3 full pages of data
lda (zppointer),y
sta $2007
iny
bne DrawLoop
inc zppointer+1 ; point to next page
dex ; last page of data?
bne Drawloop ; No. transfer another full page
Drawloop2: ; Yes. transfer final (partial) page
lda (zppointer),y
sta $2007
iny
cpy #<960 ; done?
bne Drawloop2
...
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
Re: Need help with a loop that has 16 bit counter
BitWise wrote:
You can squeeze a few cycles (and one byte!) using X to count the pages
It shouldn't matter where the data for the background is. The assembler will work out the actual address and use it in the <background and >background expressions used to initialise the pointer.
It shouldn't matter where the data for the background is. The assembler will work out the actual address and use it in the <background and >background expressions used to initialise the pointer.
Re: Need help with a loop that has 16 bit counter
Baka94 wrote:
So, using the < and > with a label tells the assembler to get the start and end point of the .db?
I like the 16 bit value in the zero page. It's nice and clear and leaves X and Y free.
Re: Need help with a loop that has 16 bit counter
Okay. I tried this code (I of course edited the pointer names and labels to fit in my program), but I got few syntax errors (marked red in the code)
barrym95838 wrote:
...
DrawBackground:
lda #<background ; init background pointer
sta zppointer
lda #>background
sta zppointer+1
ldy #0
DrawLoop: ; transfer 3 full pages of data
lda (zppointer),y
sta $2007
iny
bne DrawLoop
inc zppointer+1 ; point to next page
lda zppointer+1
cmp #>background+3 ; last page of data?
bne Drawloop ; No. transfer another full page
Drawloop2: ; Yes. transfer final (partial) page
lda (zppointer),y
sta $2007
iny
cpy #960-768 ; done?
bne Drawloop2
...
DrawBackground:
lda #<background ; init background pointer
sta zppointer
lda #>background
sta zppointer+1
ldy #0
DrawLoop: ; transfer 3 full pages of data
lda (zppointer),y
sta $2007
iny
bne DrawLoop
inc zppointer+1 ; point to next page
lda zppointer+1
cmp #>background+3 ; last page of data?
bne Drawloop ; No. transfer another full page
Drawloop2: ; Yes. transfer final (partial) page
lda (zppointer),y
sta $2007
iny
cpy #960-768 ; done?
bne Drawloop2
...
-
teamtempest
- Posts: 443
- Joined: 08 Nov 2009
- Location: Minnesota
- Contact:
Re: Need help with a loop that has 16 bit counter
Quote:
So, using the < and > with a label tells the assembler to get the start and end point of the .db?
So if, for example, the value of "label" is $1234, then "<label" has a value of $34 and "">label" has a value of $12.
-
teamtempest
- Posts: 443
- Joined: 08 Nov 2009
- Location: Minnesota
- Contact:
Re: Need help with a loop that has 16 bit counter
Quote:
but I got few syntax errors
Re: Need help with a loop that has 16 bit counter
teamtempest wrote:
That suggests the assembler you're using doesn't like/understand standard 6502 syntax. What assembler are you using?
EIDT: Also there is some weird issue that I forgot to mention that started around the time I started doing the 16 Bit counter stuff. It happens whenever I start up or reset
https://www.youtube.com/watch?v=HiNY6d4 ... e=youtu.be
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Need help with a loop that has 16 bit counter
BitWise wrote:
You can squeeze a few cycles (and one byte!) using X to count the pages
Code: Select all
...
DrawBackground:
lda #<(background-64) ; init background pointer with offset
sta zppointer
lda #>(background-64)
sta zppointer+1
ldx #4
ldy #64 ; first page transfer is only 192 bytes
DrawLoop: ; transfer 3.75 pages of data (960 bytes)
lda (zppointer),y
sta $2007
iny
bne DrawLoop
inc zppointer+1 ; point to next page
dex ; are we done?
bne Drawloop ; No. transfer another full page
...
[Edit: added parentheses around initial address operands for safety. NESASM3 must have a way to select the upper and lower halves of a 16-bit value, but I'm not familiar with it.]
Re: Need help with a loop that has 16 bit counter
I almost got it working. This is what I used:
Now the problem is that the 'H' ($11) on the word 'Hello!' is replaced with a blank tile ($2F).
Here is the background tile address list:
http://pastebin.com/2MBdrRSN
Here is a list of the tiles in the .chr and their hex values:
http://pastebin.com/ssmABx7F
Hopefully with these someone can find what's going wrong.
Code: Select all
DrawBackground: ; Loop for drawing background
LDA #$B3
STA pointerLo
LDA #$80
STA pointerHi
LDA #$00
STA counterLo
LDA #$04
STA counterHi
BgLoop:
LDA [pointerLo], y
STA $2007
LDA pointerLo
CLC
ADC #$01
STA pointerLo
LDA pointerHi
ADC #$00
STA pointerHi
LDA counterLo
SEC
SBC #$01
STA counterLo
LDA counterHi
SBC #$00
STA counterHi
LDA counterLo
CMP #$00
BNE BgLoop
LDA counterHi
CMP #$00
BNE BgLoopHere is the background tile address list:
http://pastebin.com/2MBdrRSN
Here is a list of the tiles in the .chr and their hex values:
http://pastebin.com/ssmABx7F
Hopefully with these someone can find what's going wrong.
Re: Need help with a loop that has 16 bit counter
You can directly INC or DEC a memory location without using a register.
Replace:
with:
But anyway, here is a suggested way of doing things that is simple.. if you make sure your data is a multiple of 4 bytes (4 bytes of data, 8 bytes of data, 12 bytes, etc..)
If you are writing the entire nametable it will work, otherwise you are going to have to decide on a terminating value and bail out of the loop.
Untested! .. barrym95838's code should work too, this code may be a touch faster to execute, but is slightly more bytes of code.
Replace:
Code: Select all
LDA pointerLo
CLC
ADC #$01
STA pointerLo
Code: Select all
INC pointerlo
If you are writing the entire nametable it will work, otherwise you are going to have to decide on a terminating value and bail out of the loop.
Code: Select all
; replace symbol names with your names..
; PPU_NAMETABLEADDRESS - where you want to write
; p - your pointer
; myData - data you want to write
; PPU_ADDRESS ; $2006
; PPU_DATA ; $2007
; set PPU address
lda #>PPU_NAMETABLEADDRESS
sta PPU_ADDRESS ; $2006
lda #<PPU_NAMETABLEADDRESS
sta PPU_ADDRESS
; nametable is 32 x 30 = 960
; this loop is 240 x 4 = 960
lda #<mydata
sta p
lda #>mydata
sta p+1
ldy #0
ldx #240
loop:
lda (p), y
sta PPU_DATA
iny
lda (p), y
sta PPU_DATA
iny
lda (p), y
sta PPU_DATA
iny
lda (p), y
sta PPU_DATA
iny
bne loop
inc p+1
dex
bne loop
; here you could set your attributes
Re: Need help with a loop that has 16 bit counter
Movax12 wrote:
You can directly INC or DEC a memory location without using a register.
Replace:
with:
But anyway, here is a suggested way of doing things that is simple.. if you make sure your data is a multiple of 4 bytes (4 bytes of data, 8 bytes of data, 12 bytes, etc..)
If you are writing the entire nametable it will work, otherwise you are going to have to decide on a terminating value and bail out of the loop.
Untested! .. barrym95838's code should work too, this code may be a touch faster to execute, but is slightly more bytes of code.
Replace:
Code: Select all
LDA pointerLo
CLC
ADC #$01
STA pointerLo
Code: Select all
INC pointerlo
If you are writing the entire nametable it will work, otherwise you are going to have to decide on a terminating value and bail out of the loop.
Code: Select all
; replace symbol names with your names..
; PPU_NAMETABLEADDRESS - where you want to write
; p - your pointer
; myData - data you want to write
; PPU_ADDRESS ; $2006
; PPU_DATA ; $2007
; set PPU address
lda #>PPU_NAMETABLEADDRESS
sta PPU_ADDRESS ; $2006
lda #<PPU_NAMETABLEADDRESS
sta PPU_ADDRESS
; nametable is 32 x 30 = 960
; this loop is 240 x 4 = 960
lda #<mydata
sta p
lda #>mydata
sta p+1
ldy #0
ldx #240
loop:
lda (p), y
sta PPU_DATA
iny
lda (p), y
sta PPU_DATA
iny
lda (p), y
sta PPU_DATA
iny
lda (p), y
sta PPU_DATA
iny
bne loop
inc p+1
dex
bne loop
; here you could set your attributes