2's complement in assembly?

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can anyone suggest the correct way to calculate the two's complement from a 16-bit number stored in the ALU?

com r24
com r25
adiw r24, 1

Is one way, but that takes 4 cycles to complete, and uses adiw, which is not available in all devices.

I saw somewhere that it is possible to use

com r25
neg r24

I thought this can't be true... And it wasn't. Can anyone suggest another algorithm which would complete in 3 cycles, or take less space?

Thanks,
axos88

axos88

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you kept an 0x00 and an 0x01 in a register pair, you could use a register to register add as the increment instead of the add immediate.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That would fix the compatibility issue, but it wouldn't produce faster nor smaller code... (+1 words)

axos88

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
this generated the following that uses COM;NEG
plus a SBCI, so back to 3 instructions it seems. But only 3 cycles instead of 4.

HA? what happened to cliff's post???

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm sorry, I don't quite follow... what generated what?

axos88

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
HA? what happened to cliff's post???

Something happened here. It looks likes several posts have gone missing.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, last time i wanted to open the topic it said it didn't exist...

axos88

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
what generated what?
Cliff had some compiled C code which has disappeared.
From memory:

com r25
neg r24
sbci r25,0xff

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

right, thanks... that seems to be the best way to do it... and that can be generalized for n words (well uh.. bytes) as well.

axos88

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry to dredge up an old thread.

 

I'm assuming this works because NEG creates a carry unless the result is zero?

 

So for a three-byte number r25:r23 (big endian):

 

com r25
com r24
neg r23
sbci r24,0xff
sbci r25,0xff

I think it works on paper, but am I completely up the creek?

 

It's me again...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, from this old thread, I noticed they compiled something to see how the compiler did it.

 

So, I compiled this:

 

int main() {
	uint32_t test = PORTB;
	uint32_t temp = -test;
	return temp + (temp >> 16);
}

and the output is (I separated the relevant code for clarity):

 

0000007a <main>:
  7a:   85 b1           in      r24, 0x05       ; 5
  7c:   90 e0           ldi     r25, 0x00       ; 0
  7e:   b0 e0           ldi     r27, 0x00       ; 0
  80:   a0 e0           ldi     r26, 0x00       ; 0
  
  82:   b0 95           com     r27
  84:   a0 95           com     r26
  86:   90 95           com     r25
  88:   81 95           neg     r24
  8a:   9f 4f           sbci    r25, 0xFF       ; 255
  8c:   af 4f           sbci    r26, 0xFF       ; 255
  8e:   bf 4f           sbci    r27, 0xFF       ; 255
 
  90:   ad 01           movw    r20, r26
  92:   66 27           eor     r22, r22
  94:   77 27           eor     r23, r23
  96:   84 0f           add     r24, r20
  98:   95 1f           adc     r25, r21
  9a:   08 95           ret

 

Therefore, if this is the code for 32 bit, I'm pretty sure for 24 bits it's the code you wrote.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 It really hurt my eyes to use uint32_t for signed calculations ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:

Well, from this old thread, I noticed they compiled something to see how the compiler did it.

 

So, I compiled this:

 

....

 

Therefore, if this is the code for 32 bit, I'm pretty sure for 24 bits it's the code you wrote.

 

Many thanks, much appreciated.

 

No excuse not to move on to the next hard bit now...

It's me again...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

big endian

Why?  The AVR is arguably a little-endian machine.  Are you writing some kind of cross compiler?  Or an interchange library à la Google's protobuf?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Tue. Aug 29, 2017 - 04:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:

big endian

Why?  The AVR is arguably a little-endian machine.  Are you writing some kind of cross compiler?  Or an interchange library à la Google's protobuf?

 

Calm down, just meant to type little... :-)

It's me again...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Stub_Mandrel wrote:
Calm down,
In what way was Joey's reply not "calm" ? I think you may be the one over-reacting here.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

clawson wrote:

Stub_Mandrel wrote:

Calm down,

 

In what way was Joey's reply not "calm" ? I think you may be the one over-reacting here.

 

I assume you responded before I added the smiley...?

It's me again...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-gcc uses

 

neg HI

neg LO

sbc HI, __zero_reg__

 

as the compiler maintains a register that is known to be 0.  When such a reg is not available, you can constrain to the upper 16 regs using

 

com HI

neg LO

sbci HI,-1

 

(which is what older compiler versions used to use).

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB wrote:

avr-gcc uses

 

neg HI

neg LO

sbc HI, __zero_reg__

 

as the compiler maintains a register that is known to be 0.  When such a reg is not available, you can constrain to the upper 16 regs using

 

com HI

neg LO

sbci HI,-1

 

(which is what older compiler versions used to use).

 

Interesting, thanks.

It's me again...