Hallo allen,

Voor een project met een atmega64 heb ik 2 acht-bits registers die samen een 16-bitsregister vormen. Bij dit register moeten een 8-bits constante worden opgeteld (in dit geval 14). De code die ik hiervoor bedacht had, staat bij een appnote van atmel bekend als addi16.
De code:


	subi	Packet_Length_L, -14
	sbci	Packet_Length_H, -0

Als ik dit doe, en Packet_Length staat eerst op 0x3C (d'60'), dan komt er als uitkomst 0xFF4A. Als ik niet -0, maar -255 of -256 doe, werkt het wel goed. Waarom niet met -0? Dat lijkt me toch een heel stuk logischer, ook omdat er geen enkele opmerking over dit bij de appnote van atmel staat.

Alvast bedankt,
Wouter

Denk dat -0 niet kan alleen 0.

subi	Packet_Length_L, -14
sbci	Packet_Length_H, 0

[Bericht gewijzigd door RES op ]

-0 is waarschijnlijk gewoon 0. En dat is niet de juiste waarde voor wat je wil. Je wilt -14 optellen, wat 0xFFF2 is als 16-bit signed waarde. De laagste 8-bits zijn 0xF2, wat inderdaad -14 is als byte. De subi klopt dus. Maar de hoogste 8-bits zijn 0xFF, oftewel -1. En dat is niet -0. Waarom -255 en -256 wel werken weet ik niet, +255 zou wel moeten werken omdat dat binair gelijk is aan -1.

Je hebt ook niet de appnote letterlijk overgenomen, er staat:

subi add1l, low(-addi2)
sbci add1h, high(-addi2)

In jouw geval is dat:

subi add1l, low(-14)
sbci add1h, high(-14)

En dat is gelijk aan:

subi add1l, -14
sbci add1h, -1 

Wat jij doet is -low(14) en -high(14), maar het min-teken moet juist binnen de low en high zitten. Eerst de negatieve waarde bepalen en dan pas low en high byte nemen. De high byte zal dan 0xFF (= -1 = 255) zijn, niet 0 of -0.

Bedankt, geweldig antwoord! Ik hoopte al dat ik ergens een of ander foutje maakte, het onthoud een stuk makkelijker zo. Met high(-14) en low(-14) werkt het gelukkig wel goed!

Okee, een aanverwand probleem:
Ik heb 4 registers, die samen een 32-bits getal vormen. Hier moeten 2 registers die samen een 16-bits getal worden bij opgeteld worden.
De code die ik hiervoor bedacht had:


	add	Reg32_3, Reg16_1	;Tel lage bytes bij elkaar op
	adc	Reg32_2, Reg16, 0	;Tel hoge bytes + carry bij elkaar op
	sbci	Reg32_1, High(-1)	;reken carry door
	sbci	Reg32_0, High(-1)

reg32_0 - reg32_3 = 32 bits getal, 0 = MSB
reg16_0 - reg16_1 = 16 bits getal, 0 = MSB

Maar dat gaat helaas mis... Ik denk dat het komt omdat ik eerst een add en dan een sub gebruik, en dat de carry dan precies verkeerd staat. Hoe wordt zoiets normaal gesproken gedaan?

Op 2 augustus 2006 20:58:15 schreef Wouter Sijm:
Okee, een aanverwand probleem:
Ik heb 4 registers, die samen een 32-bits getal vormen. Hier moeten 2 registers die samen een 16-bits getal worden bij opgeteld worden.
De code die ik hiervoor bedacht had:


	add	Reg32_3, Reg16_1	;Tel lage bytes bij elkaar op
	adc	Reg32_2, Reg16, 0	;Tel hoge bytes + carry bij elkaar op
	sbci	Reg32_1, High(-1)	;reken carry door
	sbci	Reg32_0, High(-1)

reg32_0 - reg32_3 = 32 bits getal, 0 = MSB
reg16_0 - reg16_1 = 16 bits getal, 0 = MSB

Maar dat gaat helaas mis... Ik denk dat het komt omdat ik eerst een add en dan een sub gebruik, en dat de carry dan precies verkeerd staat. Hoe wordt zoiets normaal gesproken gedaan?

In dit geval moet je de carry optellen bij de 2 hoogste bytes, in het eerdere geval moest je de carry juist aftrekken (met sbci). Hier moet je dan ook adc gebruiken, en dan 0 optellen. Een eventuele carry wordt er dan bij gerekend. Je hebt dan wel een register nodig wat 0 is, zeg rTemp bijvoorbeeld:


    add Reg32_3, Reg16_1   ;Tel lage bytes bij elkaar op
    adc Reg32_2, Reg16, 0  ;Tel hoge bytes + carry bij elkaar op
    clr rTemp              ; rTemp leeg     
    adc Reg32_1, rTemp     ;reken carry door
    adc Reg32_0, rTemp

Wat je met jouw code doet is in ieder geval -1 aftrekken, oftewel +1 optellen. Als de carry dan nog geset is wordt er 1 extra afgetrokken, wat weer op 0 komt. Dus bij carry +0 en zonder carry +1, precies omgekeerd aan wat je wilt. Adc met 0 als 2e register telt normaal 0 op (geen effect), en bij een carry +1 extra. Dat is wel wat je wilt.

edit: Het is trouwens vrij ongebruikelijk om de hoogste byte van een waarde een index 0 te geven, meestal wordt de LSB juist 0 genoemt. Ook met bits gaat het zo dus is het zinnig dit door te zetten in de bytetelling. Byte 0 is dan altijd de laagste byte, in plaats van 'de hoogste' waar je vrij weinig mee kan als je de grootte niet weet. Ook is het logischer bij AVRs omdat deze little-endian werken, de kleinste byte komt dus als eerst in het geheugen.

[Bericht gewijzigd door madwizard op ]

Ik trok de high byte van -1 af, dus zeg maar +0. Ik deed het op deze manier omdat ik dan iig wist dat de immediate 0 was, en vermoedde al dat het bij de carry zat.

Jammer dat er dan nog een register nodig is, maar het zal de makkelijkste manier zijn denk :)

Nogmaal bedankt he

Op 2 augustus 2006 23:01:44 schreef Wouter Sijm:
Ik trok de high byte van -1 af, dus zeg maar +0.

De high byte van -1 is -1. -1 bestaat namelijk uit alleen maar bits die 1 zijn. Alle losse bytes ervan zijn dus ook -1. Het zou wel werken als je de eerste 2 instructies ook subs had, maar dan moet je de reg16 registers weer negatief maken. Het probleem is inderdaad de combinatie van optellen en aftrekken, de carry heeft daar een andere betekenis.