Ich versuche seit ein paar Tagen eine relativ simple Berechnung auf
einem Atmega88 in Assembler zu programmieren.
Ich möchte den Wert des Timer1 (16bit unsigned) mit einer 16bit sigend
Zahl multiplizieren.
Dabei habe ich schon etliche Beiträge hier im Forum durch gelesen aber
nichts gefunden.
Ich habe es mit einigen Zahlen getestet aber mit den Folgenden konnten
immer Fehler erzeugt werden
65217*712
3289*-341
769*-27819
Dabei ist mir aufgefallen, das in bestimmten situation in meinem Code
das MSB des Highbyte falsch ist. Immer um genau eine Stelle.
1
; u16bit * s16bit multiplikation
2
; r19:r18 * r21:r20 = r11:r10:r9:r8
3
clr r10
4
clr r11
5
6
mul r20,r18
7
mov r8 , r0
8
mov r9 , r1
9
10
mulsu r21,r18
11
add r9 , r0
12
adc r10, r1
13
14
mul r20,r19
15
add r9 , r0
16
adc r10, r1
17
18
mulsu r21,r19
19
sbc r11, null ;manchmal notwendig
20
add r10, r0
21
adc r11, r1
22
sbc r11, null ;manchmal notwendig
Dieses Dokument habe ich mir auch schon angeschaut aber genau der fall
ist eben nicht aufgeführt
http://www.atmel.com/Images/doc1631.pdf
die sbc befehle habe ich einfach von hier Kopiert.
Beitrag "Assembler 16bit signed Multiplikation"
In bestimmten Fällen bringt der erste sbc Befehl den richtigen Wert und
in anderen fällen halt der andere sbc Befehl.
Die unsigned Multiplikation verstehe ich aber die signed leider nicht
wirklich. Vermutlich ist es nur eine kleinigkeit die geändert werden
muss.
Über eine kleine Hilfe wäre ich sehr dankbar.
du solltest eine signed 24 oder 32 bit multiplikation vornehmen, da der
unsigned 16 bit (16 bit value) den wertebereich des signed 16 bit (15
bit value) übersteigen kann.
Hallo,
warum eliminierst du nicht einfach das Vorzeichen und führst eine U16 *
U16 Multiplikation durch? Das Ergebnis bekommt dann einfach das
eliminierte Vorzeichen.
Gruss Reinhard
Ronny H. schrieb:> Dabei habe ich schon etliche Beiträge hier im Forum durch gelesen aber> nichts gefunden.
Nunja, manchmal hilft es auch, die existierenden Beispiele wirklich zu
VERSTEHEN. Dann kann man sie nämlich auch korrekt abwandeln und ist
nicht mehr darauf angewiesen, irgendwo im Netz eine exakt passende
Kopiervorlage zu finden...
> ; u16bit * s16bit multiplikation> ; r19:r18 * r21:r20 = r11:r10:r9:r8> clr r10> clr r11>> mul r20,r18> mov r8 , r0> mov r9 , r1
Bis hierhin richtig, aber zwei Takte nutzlos verschwendet.
> mulsu r21,r18> add r9 , r0> adc r10, r1
Falsch. Da fehlen zwei Operationen.
> mul r20,r19> add r9 , r0> adc r10, r1
Falsch. Da fehlt eine Operation.
> mulsu r21,r19> sbc r11, null ;manchmal notwendig> add r10, r0> adc r11, r1> sbc r11, null ;manchmal notwendig
Falsch. Zwei Operationen zuviel. Und wenn man sich ansieht, was dann
überbleibt, hat man auch die Erklärung dafür, warum die zwei Takte am
Anfang nutzlos verschwendet sind.
>> ; u16bit * s16bit multiplikation>> ; r19:r18 * r21:r20 = r11:r10:r9:r8>> clr r10>> clr r11>>>> mul r20,r18>> mov r8 , r0>> mov r9 , r1>> Bis hierhin richtig, aber zwei Takte nutzlos verschwendet.
Ich sehe leider nicht welche takte da zu viel sind.
Das clr muss ich machen, da ich ja nicht weiß was in r10,r11 steht.
Und das Ergebnis des mul muss ich doch wo anderst ablegen da das nächste
Ergebnis wieder in r0,r1 steht.
>> mulsu r21,r18>> add r9 , r0>> adc r10, r1>> Falsch. Da fehlen zwei Operationen.
OK und welche? Ich vermute mal zwei sbc befehle
>> mul r20,r19>> add r9 , r0>> adc r10, r1>> Falsch. Da fehlt eine Operation.
Wohl wieder ein sbc.
>> mulsu r21,r19>> sbc r11, null ;manchmal notwendig>> add r10, r0>> adc r11, r1>> sbc r11, null ;manchmal notwendig>> Falsch. Zwei Operationen zuviel. Und wenn man sich ansieht, was dann> überbleibt, hat man auch die Erklärung dafür, warum die zwei Takte am> Anfang nutzlos verschwendet sind.
Verstehe ich überhaupt nicht da in r11,r10 immer was anderes Steht in
abhängigkeit von der Rechnung natürlich.
Ich werde es aber so machen wie Herr Kern es vorgeschlagen hat.
Da bin ich heute im laufe des Tages auch drauf gekommen.
Ich überprüfe ob der zweite Multiplikator negativ ist.
Wenn ja dann wird er gedreht und ich füre eine
u16*u16 durch.
Danach wird das Ergebnis dann einfach entsprechend des zweiten
Multiplikators gedreht.
Das kann ich noch sehr gut verstehen.
Leider bin ich nicht in der lagen jeden Code zu verstehen.
Dazu fehlt mir das nötige Wissen und die Erfahrung.
Aber danke an alle für die schnelle Hilfe.
Ronny H. schrieb:> Ich sehe leider nicht welche takte da zu viel sind.> Das clr muss ich machen, da ich ja nicht weiß was in r10,r11 steht.
Nein, mußt du nicht.
> OK und welche? Ich vermute mal zwei sbc befehle
Nein. Einmal sbc und einmal adc.
> Wohl wieder ein sbc.
Nein. Einmal adc.
> Verstehe ich überhaupt nicht da in r11,r10 immer was anderes Steht in> abhängigkeit von der Rechnung natürlich.
Kommutativgesetz der Addition. Oder anders ausgedrückt: Es spielt keine
Geige, in welcher Reihenfolge Additionen ausgeführt werden. Der Trick
ist, diesen Term als ersten oder zweiten zu berechnen. Dann wäre er nur
zu Null zu addieren, denn keine vorherige Operation hat bereits zum
Inhalt von R11:R10 beitragen können, sprich: er stellt selber bereits
das Ergebnis der Addition dar und kann deshalb direkt als initialer
Inhalt von R11:R10 verwendet werden. Im Prinzip genau dasselbe, wie du
es bei deinem ersten Term machst. Aber naja, das machst ja nicht du,
sondern der von dir "adoptierte" Code fremder Leute, den du sowieso
niemals verstanden hast.
> Ich werde es aber so machen wie Herr Kern es vorgeschlagen hat.
Funktioniert sicher, ist aber suboptimal. Mindestens drei weitere
sinnlos verbratene Takte. Aber das auch nur bei intelligenter Umsetzung
des Ansatzes, ansonsten werden es noch mehr...
c-hater schrieb:> Ronny H. schrieb:>>> Ich sehe leider nicht welche takte da zu viel sind.>>> Das clr muss ich machen, da ich ja nicht weiß was in r10,r11 steht.>> Nein, mußt du nicht.>>> OK und welche? Ich vermute mal zwei sbc befehle>> Nein. Einmal sbc und einmal adc.>>> Wohl wieder ein sbc.>> Nein. Einmal adc.>>> Verstehe ich überhaupt nicht da in r11,r10 immer was anderes Steht in>> abhängigkeit von der Rechnung natürlich.>> Kommutativgesetz der Addition. Oder anders ausgedrückt: Es spielt keine> Geige, in welcher Reihenfolge Additionen ausgeführt werden. Der Trick> ist, diesen Term als ersten oder zweiten zu berechnen. Dann wäre er nur> zu Null zu addieren, denn keine vorherige Operation hat bereits zum> Inhalt von R11:R10 beitragen können, sprich: er stellt selber bereits> das Ergebnis der Addition dar und kann deshalb direkt als initialer> Inhalt von R11:R10 verwendet werden. Im Prinzip genau dasselbe, wie du> es bei deinem ersten Term machst.
Ok das habe ich verstanden und versuche es mal um zu setzen. Natürlich
gefällt mir die Methode mit dem hin un her drehen nicht aber im notfall
funktioniert es. Ich werde aber versuchen die Multiplikation richtig
aufzustellen.
>Aber naja, das machst ja nicht du,> sondern der von dir "adoptierte" Code fremder Leute, den du sowieso> niemals verstanden hast.
Absolut unötig. Aber diskriminierungen sind hier in dem Forum leider des
öfteren anzutreffen.
>> Ich werde es aber so machen wie Herr Kern es vorgeschlagen hat.>> Funktioniert sicher, ist aber suboptimal. Mindestens drei weitere> sinnlos verbratene Takte. Aber das auch nur bei intelligenter Umsetzung> des Ansatzes, ansonsten werden es noch mehr...
Ich als eingeschränkter Mensch würdes natürlich nicht in 3 Takten
schaffen.
Danke Johann L. Ich bin schon dabei das Script zu analysieren.
c-hater schrieb im Beitrag #3204695:
> Ronny H. schrieb:>>> Absolut unötig. Aber diskriminierungen sind hier in dem Forum leider des>> öfteren anzutreffen.>> Wer das Aussprechen eines offensichtlich wahren Sachverhaltes als> Diskriminierung bezeichnet, ist der schlimmste Zensor, den es gibt.
Ich habe in meinem Post VOR deinem schon erwähnt, dass ich nicht in der
Lage bin jeden Quell-Code zu verstehen. Dadurch ist deine Aussage eine
unnötige Diskriminierung geworden weil ich den Sachverhalt schon selber
erkannt habe.
Dank deiner Hilfe und der von Johann konnte ich den Code verbessern und
habe auch bedeutend mehr davon verstanden.
Ronny H. schrieb:> Dank deiner Hilfe und der von Johann konnte ich den Code verbessern und> habe auch bedeutend mehr davon verstanden.>> ; u16bit * s16bit multiplikation> ; r19:r18 * r21:r20 = r11:r10:r9:r8>> mul r20,r18> mov r8, r0> mov r9, r1
hier geht auch "movw r8, r0" denn jeder Core, der MUL kann, beherrscht
auch MOVW.
> mul r21,r19> mov r10, r0> mov r11, r1
Ditto.
Das ich movw anstatt von mov verwenden kann wusste ich schon aber ist es
denn auch schneller? Wenn ich jetzt so drüber nachdenke Verbraucht es in
jedenfall weniger Speicher.
Werde diese Änderung noch mit einbeziehen. Sonst vom ablauf scheint es
zu funktionieren. Ich konnte keinen Fehler produzieren.
Besten dank Johann L.
Ronny H. schrieb:> Das ich movw anstatt von mov verwenden kann wusste ich schon aber ist es> denn auch schneller?
Nein, MOVW beaucht 2 Ticks. Es hilft aber Flash zu sparen.
Johann L. schrieb:> Nein, MOVW beaucht 2 Ticks. Es hilft aber Flash zu sparen.
Nein. movw braucht nur einen Tick und hilft somit sehr wohl auch beim
Rechenzeit sparen.
Siehe "avr instruction set reference" Seite 96.