Need help with an incrementing 16-bit pointer

Building your first 6502-based project? We'll help you get started here.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Need help with an incrementing 16-bit pointer

Post by BigEd »

Indeed - that's my point perhaps better made - it's a personal choice, not a must-have.
EvilSandwich
Posts: 36
Joined: 13 Oct 2019
Location: Pennsylvania, USA

Re: Need help with an incrementing 16-bit pointer

Post by EvilSandwich »

Using a combo of BigEd's idea and floobydust's I whittled it all down to 23 bytes. I'm going to try to insert it into my program now! :)

Code: Select all

LDA #$01
LDX #$01
LDY #$00
STX $02
STY $01

main:
STA ($01),y
INY
BNE main
INC $02
LDX $02
CPX #$06
BNE main
Less branching and it only runs three lines of code the majority of the time.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Need help with an incrementing 16-bit pointer

Post by barrym95838 »

EvilSandwich wrote:
Using a combo of BigEd's idea and floobydust's I whittled it all down to 23 bytes. I'm going to try to insert it into my program now! :)

Code: Select all

LDA #$01
LDX #$01
LDY #$00
STX $02
STY $01

main:
STA ($01),y
INY
BNE main
INC $02
LDX $02
CPX #$06
BNE main
Less branching and it only runs three lines of code the majority of the time.
That looks quite nice, but you should replace the LDX #$01 with LDX #$02 to avoid smashing your stack, and you should be able to save one byte and a few cycles by replacing the LDX $02 with INX.
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Need help with an incrementing 16-bit pointer

Post by BigEd »

One unexpected thing for me on this code snippet, as it has developed: my first thought was that the use of X to load and compare a value was not idiomatic - it rather looked like the writer was using all the registers just because they are distinct 'variables' and that's how you'd write something in a high level language. But as it turned out on second reading is that X is used well: Y must be used to index because that's the only addressing mode which fits the bill, and therefore A must be used for the constant value to be written, and therefore X is the right register to use as a working register for the comparison.

Using the right register at the right time is one of the marks of the well-crafted 6502 code... another being good use of the persistence of the flag values.
hoglet
Posts: 367
Joined: 29 Jun 2014

Re: Need help with an incrementing 16-bit pointer

Post by hoglet »

You can shave off one more byte, and a few cycles:

Code: Select all

LDA #$01
LDX #$02   ;; corrected
LDY #$00
STX $02
STY $01

LDX #$04  ;; number of pages to copy
main:
STA ($01),y
INY
BNE main
INC $02
DEX
BNE main
I make that 22 bytes.

Dave
EvilSandwich
Posts: 36
Joined: 13 Oct 2019
Location: Pennsylvania, USA

Re: Need help with an incrementing 16-bit pointer

Post by EvilSandwich »

barrym95838 wrote:
That looks quite nice, but you should replace the LDX #$01 with LDX #$02 to avoid smashing your stack, and you should be able to save one byte and a few cycles by replacing the LDX $02 with INX.
It never even occurred to me that X and $02 would have the exact same values.

It seems screamingly obvious in hindsight, but I'm just so used to only thinking about the values in the Zero Page and kinda got stuck thinking of the Registers as just middle men to be used and forgotten once the bytes are in the right locations.
BigEd wrote:
One unexpected thing for me on this code snippet, as it has developed: my first thought was that the use of X to load and compare a value was not idiomatic - it rather looked like the writer was using all the registers just because they are distinct 'variables' and that's how you'd write something in a high level language. But as it turned out on second reading is that X is used well: Y must be used to index because that's the only addressing mode which fits the bill, and therefore A must be used for the constant value to be written, and therefore X is the right register to use as a working register for the comparison.

Using the right register at the right time is one of the marks of the well-crafted 6502 code... another being good use of the persistence of the flag values.
Honestly, I keep catching myself with the exact opposite problem. I have an annoying habit of thinking of the Zero Page and the Flags so much, that tend to forget that there are still values in the Register that I can still technically use until something changes them.

I often think of registers as "Robot Arms" that grab packets of data and place them in the right memory "Bucket". I often forget that the "Arm" will continue to grip what you asked it to grab until you ask it to grab something else.

I work in a factory as my day job, so it helps me to think of code in assembly line terms. lol

EDIT:
hoglet wrote:
You can shave off one more byte, and a few cycles:

Code: Select all

LDA #$01
LDX #$02   ;; corrected
LDY #$00
STX $02
STY $01

LDX #$04  ;; number of pages to copy
main:
STA ($01),y
INY
BNE main
INC $02
DEX
BNE main
I make that 22 bytes.

Dave
Oh, that's a cool idea. It lets me eliminate the Compare command completely! As well as the need to load the high byte into X (like how Barry suggested swapping LDX $02 with simply INX.)

Now I can cut out the LDX and the CPX!
Martin A
Posts: 197
Joined: 02 Jan 2016

Re: Need help with an incrementing 16-bit pointer

Post by Martin A »

Here's my 2c worth

Code: Select all

lda #$01
ldy #$00
ldx #$02

sty $01
loop2:
stx $02

loop:
sta ($01),y
iny
bne loop
inx
cpx #$06
bne loop2
Down to 20 bytes by re-using the initial STX in the outer loop.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Need help with an incrementing 16-bit pointer

Post by BigEd »

EvilSandwich wrote:
Honestly, I keep catching myself with the exact opposite problem. I have an annoying habit of thinking of the Zero Page and the Flags so much, that tend to forget that there are still values in the Register that I can still technically use until something changes them.
Interesting insight!

And I see Dave/hoglet has now shown that the normally-idiomatic use of X as a down counter turns out to be another small improvement. And then Martin shows another improvement going the opposite way!
EvilSandwich
Posts: 36
Joined: 13 Oct 2019
Location: Pennsylvania, USA

Re: Need help with an incrementing 16-bit pointer

Post by EvilSandwich »

BigEd wrote:
EvilSandwich wrote:
Honestly, I keep catching myself with the exact opposite problem. I have an annoying habit of thinking of the Zero Page and the Flags so much, that tend to forget that there are still values in the Register that I can still technically use until something changes them.
Interesting insight!

And I see Dave/hoglet has now shown that the normally-idiomatic use of X as a down counter turns out to be another small improvement. And then Martin shows another improvement going the opposite way!
What was it someone said on the first page of this thread?

Ask a dozen programmers to solve a problem and you'll get a baker's dozen solutions? haha

And now the age old question. Do I go with Dave to optimize for less clock cycles? Or Martin and optimize for a smaller size?

Both are equally attractive options (and for a mere 20+ byte program is completely meaningless from the point of view of the end user. lol)
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Need help with an incrementing 16-bit pointer

Post by BigEd »

There can be no best solution - but this journey has been very informative, I think.

(Edit: I mean to say, it feels like a good thread to be found by future learners getting to grips with the 6502)
Last edited by BigEd on Tue Oct 29, 2019 9:13 am, edited 1 time in total.
EvilSandwich
Posts: 36
Joined: 13 Oct 2019
Location: Pennsylvania, USA

Re: Need help with an incrementing 16-bit pointer

Post by EvilSandwich »

If nothing else, this thread helped explain something that was REALLY bugging me about branching. Why are there branching opcodes for all the flags except the Zero Flag?

Then you guys told me that was basically what BNE/BEQ was.

That changed a lot.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Need help with an incrementing 16-bit pointer

Post by Chromatix »

floobydust wrote:
BigEd wrote:
That's the spirit! The 65C02's extra opcodes are handy if you have them, but by no means necessary - and of course if you use only the originals, your code will run on either flavour.
A very true statement, however, I decided to use nothing but the CMOS version decades ago. I still have the pair of Rockwell R65C02P2 processors I purchased back in the 80's and the original datasheet. One of those chips is still in my original Vic-20 and the other in my original 1541 diskette drive. I haven't written any NMOS specific code since then. Now that you can still get Rockwell CMOS chips at fairly cheap prices (for older hardware replacements) and new WDC chips, I can't see any reason to use the older NMOS chips. That's just my personal view of course, so all of my code since then requires the CMOS processor.
In my case, I have one project which by its nature has to be able to run on an NMOS CPU - the 6502 Fake Finder. I have an NMOS chip on hand for when it comes time to test that. I think nearly everything else I write will be for 65C02 or 65C816.
EvilSandwich
Posts: 36
Joined: 13 Oct 2019
Location: Pennsylvania, USA

Re: Need help with an incrementing 16-bit pointer

Post by EvilSandwich »

I used dave's idea and used it to streamline the confetti draw subroutine as well as the screen fill subroutine.

I am however keeping Martin's version handy in case I need to make it smaller someday. For now, I'll optimize for speed.

Once again, this program is designed to run in Nick Morgan's Easy6502 virtual machine:
http://skilldrick.github.io/easy6502/

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Waiting for input                 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Press W to Pop Confetti Forever!  ;
; Press O to Pop Confetti Just Once ;
; Press Q to End Program            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

idle:
	
LDA $ff		;reading last keystroke
CMP #$71	;If Q, End Program
BEQ end
CMP #$6f	;If O, Just Once
BEQ poponce
CMP #$77 	;If W, Pop Confetti!  Yay! :D
BEQ poprepeat
BNE idle 	;If no input, continue idle

poponce:
LDA #$00 ;clearing last keystroke
STA $ff
poprepeat:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
;clearing screen for new confetti ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LDA #$00
LDX #$02   
LDY #$00
STX $02
STY $01

LDX #$04  
sweep:
STA ($01),y
INY
BNE sweep
INC $02
DEX
BNE sweep

;;;;;;;;;;;;;;;;;;;;;
;Yay! Party Time! ;
;;;;;;;;;;;;;;;;;;;;;

LDX #$01
STX $02

loop2:
INC $02
LDX $02
CPX #$06
BEQ idle
LDX #$20

loop:
LDA $fe
LDY $fe
STA ($01),y
DEX
BNE loop

BEQ loop2

end:
I think this is as streamlined I can make the program now.

I also removed the code that initialized Y for the confetti subroutine, since Y will just be set in the main inner loop. I also removed the command to "Pause" the Confetti loop. The Pop Once function does mostly the same thing, so Pause was just redundant.

67 bytes for the whole thing!

I think I should just call this thing complete for now and move on to the next project.

I need to learn how to use the stack effectively. So I'll play around with programs that use the stack next. :)
EvilSandwich
Posts: 36
Joined: 13 Oct 2019
Location: Pennsylvania, USA

Re: Need help with an incrementing 16-bit pointer

Post by EvilSandwich »

Okay, I lied. That confetti draw subroutine was bugging me and I had to streamline it.

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Waiting for input                 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Press W to Pop Confetti Forever!  ;
; Press O to Pop Confetti Just Once ;
; Press Q to End Program            ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

idle:
	
LDA $ff		;reading last keystroke
CMP #$71	;If Q, End Program
BEQ end
CMP #$6f	;If O, Just Once
BEQ poponce
CMP #$77 	;If W, Pop Confetti!  Yay! :D
BEQ poprepeat
BNE idle 	;If no input, continue idle

poponce:
LDA #$00 ;clearing last keystroke
STA $ff
poprepeat:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
;clearing screen for new confetti ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LDY #$00
LDX #$02

LDA #$00

STY $01
sweep2:
STX $02

sweep:
STA ($01),y
INY
BNE sweep
INX
CPX #$06
BNE sweep2

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Yay! Party Time! :D :D :D ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;


LDX #$80    ;set draw limit

loop:           ;confetti draw loop
LDA $fe     ;Load random byte
AND #$03     ;And with %00000011 to mask out all but the last two bits 
CLC
ADC #$02     ;Add 2 to the 1-3 result
STA $02      ;Store into high byte of pointer

LDA $fe      ;Load random color
LDY $fe      ;Load random low byte offset
STA ($01),y  ;Draw pixel

DEX          ;Decrement draw limit counter

BNE loop     ;If counter no zero, loop again
BEQ idle     ;Else, Return to Idle Loop

end:
I stole Nick Morgan's idea to use an AND function to mask out all but the two smallest bits and adding 2 to the result so I could get a random number between 2 and 5 for the high byte of the pointer, instead of just incrementing the high byte every time the low byte was randomized 32 times.

Saves me the need to load the draw limit into X three more times.

Also I really need to practice bitwise functions more. I'm still stuck in thinking of operands just as Hex numbers and that's limiting me so much.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Need help with an incrementing 16-bit pointer

Post by BigEd »

At least Hex is a good starting point! If you work in decimal, the bit patterns are very obscure indeed (other than even/odd or huge/tiny or positive/negative) - whereas in hex, you just need to get a feel for the 16 bit-patterns that you deal with, and that comes soon enough.
Post Reply