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
Mats wrote:
I would say that the task simply is not appropriately formulated in the first place!
Strange; I understood the problem as written perfectly.
Quote:

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
Mats wrote:
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.
Quote:
Sorry for that!
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