Page 1 of 1
Is this code okay?
Posted: Wed Oct 18, 2006 5:18 pm
by oxymoron
I've been messing around with the 6502 simulator and tried making a program that counts up from $00 to $1F and stores the numbers in memory in as few steps as possible. Could this code be made shorter somehow?
Code: Select all
.ORG $8000
LDA #$20
sta $8088
LDX #$00
loop:
TXA
CMP $8088
beq end
sta $8040,x
INX
jmp loop
end:
Posted: Wed Oct 18, 2006 6:15 pm
by Memblers
Code: Select all
.org $8000
ldx #0
loop:
txa
sta $8040,x
inx
cpx #$20
bne loop
Originally 20 bytes, now 11 bytes.
Posted: Wed Oct 18, 2006 7:59 pm
by dvdmth
If you use zero page memory and count down from $1F to $00, you can make the code even shorter:
Code: Select all
LDX #$1F
loop:
TXA
STA <$40, X
DEX
BPL loop
Posted: Wed Oct 18, 2006 10:25 pm
by oxymoron
thanks memblers... I forgot about cpx.

I was hoping to make it so you could dynamically change the value of the counter from within the program though. Can it be made shorter if that was a consideration?
(btw it's just a brain excersize)
thanks too dvdmth. I thought about that but I wanted it to be able to store the numbers anywhere in memory.
Posted: Thu Oct 19, 2006 1:31 am
by blargg
It's still shorter (two bytes) and faster (2 clocks per iteration) to count down than up, due to DEX doing an implicit CMP #0 after decrementing X. Replace <$40 with $8040 and you have the same result as your code. Note that this will only work for counting down from $80 or less, since greater values would cause the loop to terminate after the first iteration.
Posted: Thu Oct 19, 2006 2:34 am
by Bregalad
To count up to number greather than $80, you'll have to trick a bit :
Code: Select all
ldx #$ff
- txa
sta Somewhere,X
dex
bne -
stx Somewhere
Posted: Thu Oct 19, 2006 12:21 pm
by Memblers
If you wanted to be evil, you could do self-modifying code in RAM (going from dvdmth's code).
Code: Select all
loop_value = label+1
lda #$40-1 ;(do 64)
sta loop_value
.org somewhere_in_RAM
label:
LDX #$1F
loop:
TXA
STA <$40, X
DEX
BPL loop
Or the easier way, put an RTS at the end and do an LDX then JSR to the loop label. But JSR/RTS together costs something like 12 cycles, JMP is only 3, so the self-modifying code is good if speed really counts.
Posted: Thu Oct 19, 2006 1:15 pm
by tokumaru
Easy guys, or you'll confuse the poor guy. This battle for speed/size is eventually important, but for now, as long as the code does what it's supposed to, it's OK.
Oxymoron, it doesn't really matter if there is a better/shorter way to do some task when you're learning 6502 assembly. Because, you know, there always is a faster way to do things. What is important now is that you understand how each instruction behaves and affects the CPU, and that you can successfully code a program that will do what you expect it to.
I say that because sometimes, when you look at clever, tight code, it isn't always clear what it's supposed to do, 'cause often there are "tricks" involved. And learning through tricks is not a good way to start.
In the future, when you start thinking the same way as the processor works, these kind of improvemnts/shortcuts will also start to appear clearly in your head. Don't worry about that too much right now.
Posted: Thu Oct 19, 2006 1:33 pm
by Bregalad
This battle for speed/size is eventually important, but for now, as long as the code does what it's supposed to, it's OK.
Well, it's important in up to a certain point, but Memblers tend to be a bit too "evil" usually, and well, my opinion is that you should always with code that is understandable and easily modifiable/fixable, even if you do a minimun of tricks to gain ROM space.
If you really need trick, it is recommanded to comment them very well and/or to have a commented "untricked" version of the code in order to have yourself understand what you was doing when you look at code you wrote 6 months ago.
Posted: Thu Oct 19, 2006 4:13 pm
by Memblers
Well he did say it was just a brain exercise, rather than some project code. So I figure anything goes, I didn't post my fastest methods though since the goal was size.

Just some (partially or fully) unrolled loops anyways.
But I definitely agree though that code should be kept easy to read and understand. Except inside of loops that run several times per frame, then you definitely should use little tricks like the one dvdmth posted wherever possible. Ditching that compare when copying 32 bytes saves 64 cpu cycles (over half a scanline), the 2 less ROM bytes only matter if you're writing a 1024 byte game or something.
Also nothing wrong with writing code that works, then coming back later and optimizing if needed. Like when I first wrote Roadkill (while still learning how to code), most of the frame was taken up by hit detection code. When I optimized it some years later, the results were the same but the code was something like 300% faster. When handling 62 sprites, that's a tremendously, ridiculously huge difference.
Posted: Thu Oct 19, 2006 7:40 pm
by oxymoron
I appreciate the tips guys. I don't know what the < in "<$40" means? But otherwise those examples mostly make sense. Although like I said, I didn't want to make the code do something different (ie count down instead of up, although I didn't think about DEX setting the Z flag - is that what you mean when you say "implicit CMP #0" blargg?) or make it incporporate "tricks", I just wanted to know if I had missed something obvious that would have reduced the number of steps. I can't even think of a reason to actually use this routine off the top of my head, I had just written a bunch of things in the simulator and decided to try cutting them down to make them as small as possible as an excersize.
Posted: Thu Oct 19, 2006 8:17 pm
by tepples
oxymoron wrote:I appreciate the tips guys. I don't know what the < in "<$40" means?
In 65xx assembly language, < means bits 7-0, > means bits 15-8 ("page"), and | means bits 23-16 ("bank", generally 65816 only). If you know C, I can explain a lot of 65xx concepts in terms of C.
Posted: Thu Oct 19, 2006 8:33 pm
by tokumaru
He probably did that to make sure that the instruction would be assembled to the zero-page addressing version (where the high byte of the address is implied, $00). Otherwise, it could be assembled to the equivalent of "STA $0040, X", which would be wasteful (both in space and time) in this case. I wouldn't usually do that, and assume that the assembler is smart enough to use the appropriate instruction.
Posted: Thu Oct 19, 2006 9:43 pm
by Memblers
NESASM is the only assembler I'm aware of that requires you to force it to use zero-page. Actually though when making my NSF player I ran across a few games that never use zero-page, always stuff like STA $0000 (whoops!).
But for a practical example of using < and >, you'll very often see stuff like this:
Code: Select all
filething = $C032
lda #>filething ; $C0
sta addr_hi
lda #<filething ; $32
sta addr_lo
Posted: Fri Oct 20, 2006 8:43 am
by Bregalad
WLA-DX almost forces you to either default to zero page and force to non-zero page or the other way arround (like NESASM does).
In NESASM (and ONLY in NESASM) :
lda <Label
means like
would in WLA-DX
In WLA-DX it is use to just say
for zero page and to have
for non-zero page instruction.
This is isn't all that bad because it forces the programmer to know wich varaiables aren't in zero page, and you can use "sta $2000" without mention "sta $2000.w", so it is just for variables and not for registers you have to do the .w trick.