Page 1 of 1
Sign extension question
Posted: Sat Apr 29, 2006 12:16 pm
by Kallikak
Hi,
I need to add a signed 8 bit number (in zero page location TEMP1) to a stored 16 bit number (in zero page locations LVALL,H). Below is my current method. I was wondering if anyone had any suggestions or improvements.
Code: Select all
ADD16X
LDX #$00
LDA TEMP1 ; signed 8 bit number
CMP #$00
BPL .CONT
DEX ; bit 7 was set, so it's a negative
.CONT STX TEMP2
CLC
ADC LVALL
STA LVALL ; update the stored number low byte
LDA LVALH
ADC TEMP2
STA LVALH ; update the stored number high byte
RTS
Thanks,
Ken
Posted: Sat Apr 29, 2006 2:37 pm
by leeeeee
This should work ..
Code: Select all
ADD16X
LDA TEMP1 ; signed 8 bit number
BPL .CONT ; skip high byte decrement if +ve
DEC LVALH ; number is -ve so decrement stored number high byte
.CONT
CLC ; clear carry for add
ADC LVALL ; add to 16 bit low byte
STA LVALL ; update the stored number low byte
BCC .EXIT ; exit if no carry
INC LVALH ; add the carry to the stored number high byte
.EXIT
RTS
Lee.
Posted: Sun Apr 30, 2006 1:36 am
by Kallikak
Nice - thanks. Not only short and clear, but also avoids using X, so you've saved me quite a few bytes there.
Ken
Posted: Mon May 01, 2006 4:33 pm
by Mats
I would say that the task simply is not appropriately formulated in the first place!
If the two byte value should be the sum of many one byte "signed" values you should consider it as a signed value too. If you for some reason know from the start that the sum is positive you kind of miss the most significant bit, i.e. you only have 15 bits fo the end sum. But what do you otherwise do if some "partial sum" should be negative? With absolutely standard signed arithmetic you then have
Code: Select all
CLC
LDA TEMP1
ADC LVALL
STA LVALL
LDA #00
ADC LVALH
STA LVALH
BVS ERROR
RTS
If now the final sum in LVALL,LVALH stays positive at all times, fine! If not, also fine!
This is the straight-forward approach in the spirit of the chip design! Rock solid! No "tricks" needed!
Posted: Mon May 01, 2006 4:46 pm
by kc5tja
I would say that the task simply is not appropriately formulated in the first place!
Strange; I understood the problem as written perfectly.
Code: Select all
CLC
LDA TEMP1
ADC LVALL
STA LVALL
LDA #00
ADC LVALH
STA LVALH
BVS ERROR
RTS
If now the final sum in LVALL,LVALH stays positive at all times, fine! If not, also fine! This is the straight-forward approach in the spirit of the chip design! Rock solid! No "tricks" needed!
The poster of the question is adding a signed 8-bit value to a signed 16-bit quantity. This
mandates that the 8-bit value be
sign-extended first. The code above works if and only if the signed value is guaranteed to be positive at all times.
I'm not a fan of unnecessary tricks except where performance counts (see my thread on arithmetic shifts). I would start off by writing this instead:
Code: Select all
clc
lda TEMP1
bmi isNeg
adc LVALL
sta LVALL
lda #0
adc LVALH
sta LVALH
back:
...etc...
isNeg:
adc LVALL
sta LVALL
lda #$FF
adc LVALH
sta LVALH
jmp back
That would be my initial solution. It takes more memory, and MAY even take more time to execute, but it'll work. Then, from there, I'd optimize as required.
update -- I did a preliminary timing analysis of my code versus lee's with the assumption that everything is stored in zero-page, and it looks like mine is only 3 cycles slower than his in the case of a negative number. Not bad at all, I'd say.
Posted: Mon May 01, 2006 10:31 pm
by Mats
You are perfectly right. But "basically" I think I was right that the straightforward way to do this absolutely standard task is to
Step 1:
Extend the signed one byte variable to a build a signed 2 byte variable by "prolonging" the sign bit, i.e. (for example)
80 => FF80
7F => 007F
Then do 2 byte signed arithmetic!
This is exactly what you (correctly) did! I wrote my thing a bit to quickly! Sorry for that!
This could also be seen as 8 "ASR" (division by 256) of 8000 and 7F00 , respectively, where "ASR" would be the non-existing operation "Arithmetic Shift Right" copying the value of the sign bit to the second most significant bit, i.e division with 2
Posted: Tue May 02, 2006 1:48 am
by kc5tja
You are perfectly right. But "basically" I think I was right that the straightforward way to do this absolutely standard task is to
Yes -- provided performance or tight memory size isn't an issue. Lee's approach is 'straight forward' in the sense that it exploits the logic of 2's compliment math, but it does require a bit of algebra to see how it works.
The "trick" is that, should you have a negative number N, you can break it up such that N = $FF00 + N', where N' is between $80 and $FF inclusive.
Thus, LVAL + $FF00 + N' is what's being computed, and since addition is commutative, and since $FF is -1, and therefore $FF00 is -256, the initial DEC instruction on the high byte is precisely correct to compute (LVAL+$FF00) + N'. The middle code computes the final sum, with the BCS/INC easily handling any carry that may need to be propegated.
Not a problem; without a clearly written message it was kind of hard to get, but everyone does it. I do too.
Re: Sign extension question
Posted: Sun May 21, 2006 4:25 pm
by TMorita
Code: Select all
LDX #$00
LDA TEMP1 ; signed 8 bit number
CMP #$00
BPL .CONT
DEX ; bit 7 was set, so it's a negative
.CONT CLC
ADC LVALL
STA LVALL ; update the stored number low byte
TXA
ADC LVALH
STA LVALH ; update the stored number high byte
RTS