Page 1 of 1

6502 Arithmetic

Posted: Tue Jun 27, 2006 12:10 am
by nineTENdo
Hello again,
Im working on the Sound test Demo by Snow Bro. I came across some thing that i could have passed up but couldnt until i completly understood it. heres the Code:

Code: Select all

end_text:	

lda     #$20		
sta     ADDR_HI
lda     #$C0
sta     ADDR_LO
ldy     #$20            
-
lda     ADDR_HI
sta     $2006
lda     ADDR_LO
sta     $2006
lda     #$12    ; "R"
sta     $2007
lda     #$05    ; "E"
sta     $2007
lda     #$07    ; "G"
sta     $2007
lda     #$00    ; " "
sta     $2007
sty     $2007
lda     #$2A    ; ":"
sta     $2007

lda     ADDR_LO
clc
adc     #$40	
sta     ADDR_LO
bcc     +
inc     ADDR_HI         ;<-- This is what is nagging at my brain.
+
iny			
cpy     #$24		
bne     -
rts
After reading this i came to find out that it setsup "REG :" at locations #$20C0,2100,2140,2180. Each time the code loops it adds with a carry #$40 to low byte of 20CO until it stops at #$24.

What my Question is what is the INC ADDR_HI doing after the first loop? Because adding #$80 (Second loop adds #$40 again, i think) to C0 would generate a carry not branching it and incrementing ADDR_HI (20) making 21 i think.

How can you increment to 21 while there still is a carry and a value of a 100 in the low byte. Wouldnt that just add 21 + 100. What happens to the low byte after not branching???

Thanks in Advance,
EL

Posted: Tue Jun 27, 2006 6:35 am
by Quietust
During the first loop, ADDR_LO gets incremented from $C0 to $00 (and gets stored), triggering a carry and incrementing ADDR_HI. During the subsequent loops, ADDR_LO gets incremented from $00 to $40, then $40 to $80, then $80 to $C0; none of these trigger carry (since carry only happens when crossing from $FF to $00), so the "INC ADDR_HI" gets skipped entirely.

Carry is only determined based on the immediate previous action, not the cumulative changes to the register - it doesn't care that it started at $C0 during all 4 additions, just the first addition.

On a side note, you really ought to understand this sort of stuff by now, given the amount of time you've been dealing with 6502 assembly. At the very least, you should be able to get this sort of information from formal documentation instead of relying on the rest of us here.

Posted: Tue Jun 27, 2006 8:56 am
by nineTENdo
Well 6502 is not exacly childs play. And the documentation is not exacly all shits and giggles. All though i dont know where i would be if it wasnt there. trust me ive gotten everybook i could get my hands on. And there are still somethings i dont understand, like what the hell these ASL's do:

Code: Select all

rast_init:	LDX #$05	
ri1:		TXA
		ASL A
		ASL A
		ASL A
		STA rbars,x
		DEX
		BPL ri1
Yeah i know they divide but what exactly is going on here. Ive never seen this stuff in the documentation. If i had started with GBA development by now i would have had a bunch of demos. Cause C is easier. But im stupid and love a challenge. The biggest challenge right. now for me though is not filling up your Newbie Forum:) All the way aleast.

Thanks anyways,
EL

Posted: Tue Jun 27, 2006 9:09 am
by Disch
nineTENdo wrote:Yeah i know they divide
Not exactly. ASL and LSR perform bitshifts.

ASL shifts left, LSR shifts right. The first time those ASLs in that code you pasted are run, it looks like A=$05

So:

Code: Select all

%00000101 = $05   <--  A initially
%00001010 = $0A   <--  A after first ASL
%00010100 = $14   <--  A after second ASL
%00101000 = $28   <--  A after third ASL
As you can see left shifting does what the name implies, it shifts bits to the left. This works out so that each left shift is kind of like a multiply by 2. Therefore ASLing 3 times in a row like that code was doing is multiplying by 2*2*2 --- or multiplying by 8

LSR does the opposite (shifts right). Which sort of works out like a divide-by-two.


And C isn't really any easier. Programming fundamentals are pretty much the same with any language.