Nun was ich bekomme:
32767*100, d.h. 0x007fff*0x64, Ergebnis 0x0031ff9c, d.h. 3276700. alles
richtig.
Nun anders: -32767*100, d.h. 0xffff8001*0x64, Ergebnis 0xffce0064,
d.h.-3276700. Auch richtig.
Nun andersrum: 32767*-100, d.h.0x007fff*0x9c. Zu erwarten ist hier
eigentlich auch 0xffce0064, d.h.-3276700. Aber es kommt 0x004e0064,
5111908. Minus auf Plus gibt Plus???
Vielleicht gibt es in diesem Artikel ein Fehler. Leider kann ich den
nicht finden. Könnt Ihr mir bitte helfen?
Natürlich kann ich das Problem entschärfen: auf Zeichen kucken und
gegebenfalls NEG machen, ohne Zeichen multiplizieren und danach wieder,
falls notwendig, NEG. Aber das kostet Zeit, und wenn die Funktion
angeblich signed*signed heißt, wäre es schön, sie in Ordnung zu
bringen...
mulsu scheint da auf den ersten Blick nicht zu passen da der
signed/unsigned rechnet.
Es gibt doch auch die die Appnotes, dort sind solche Funktionen auch
drin. In deiner Kombination 24/8 Bit aber mit sicherheit nicht.
Sascha
Danke!
Das funktioniert! Oben gegebene Test zeigt richtiges Ergebnis!
Ich habe den Artikel
https://www.mikrocontroller.net/articles/Multiplikation_in_Assembler
gelesen und möchte universelle *.inc machen, wo mit #define alle
möglichen Varianten von mul für Mega und Tiny zu wählen sind. Dann kann
ich File einfach in allen Projekten includen und wählen, was ich genau
brauche. Um leichter zu testen, habe ich vorher ebenfalls universelle
bindec.inc gemacht, das funktioniert.
So kann ich die Zahlen in Programm decimal dem Assembler futtern und
dann auch decimal in Register sehen. Dann habe ich mit Testen von
mult.inc begonnen. Alle mul sind in Ordnung, manche muls auch, aber bei
muls_24x8 kam das Problem.
Vielen Dank für die Lösung! Uch werde weiter testen, vielleicht gibt es
noch irgendwo Bug...
Ja, schön. Zwischenzeitlich hatte ich meine Routine auch getestet und
keinen Fehler gefunden.
Bei der ursprünglichen hat nichts gestimmt, Rechtschreibung, Anzahl
Takte, die Routine selbst, und keinem fiel es auf - aber je nun, sowas
kommt vor.
S. Landolt schrieb:> Ja, schön. Zwischenzeitlich hatte ich meine Routine auch getestet und> keinen Fehler gefunden.
Ist auch keiner drin. Weiss ich deshalb, weil sie prinzipiell genauso
aussieht wie meine eigene zu diesem Thema.
> Bei der ursprünglichen hat nichts gestimmt, Rechtschreibung, Anzahl> Takte, die Routine selbst, und keinem fiel es auf - aber je nun, sowas> kommt vor.
Die Routine selbst lag ja sogar in mehrfacher Hinsicht daneben. Aber das
ist halt OpenSource. Jeder darf irgendwo was veröffentlichen und jeder
darf es unbesehen C&P-en...
Hier hatten wir halt mal die Ausnahme von der Regel: Jemand, der
letzteres eben nicht getan hat. Von solchen Leuten müsste es viel mehr
geben. Gibt es aber leider nicht...
Deswegen kann die klare Konsequenz nur sein: traue keinem OSS-Code. Das
genau ist auch, was meine Erfahrung diesbezüglich sagt. Und diese
winzige AVR8-Multiplikation ist ja noch vergleichweise sehr trivial.
Wenn man sich anschaut, was manche sich für ungeheure Mengen an Code
einfach mal in ihre Projekte reinziehen, ohne auch nur andeutungsweise
zu prüfen, was die eigentlich wirklich tun, kann einem nur Angst und
Bange werden...
> prinzipiell genauso aussieht
Nun ja, ein Stück weit hatte ich mich durchaus auf Optik&Analogie
verlassen, sonst hätte ich sie erst gar nicht vorgestellt. Aber manchmal
ist der Teufel ein Eichhörnchen ...
ich habe inzwischen in meinen bindec einen Fehler entdeckt: bei
Minuszeichen war r17 nicht gepusht. Korrigiert.
Ja, man darf nicht zu kritisch sein zu dem, was man als Freizeit
macht...
Ich habe jetzt Lust für Assembler. Um besser zu verstehen, was
C-Compiler macht. Auch wäre schön, beides zusammen zu verwenden.
Besonders ISR kann man oft gut optimieren, da Compiler nicht alles weiß
wie ich, was gebraucht wird.
c-hater schrieb:> Jeder darf irgendwo was veröffentlichen
Ich habe auf Ihrer Idee macro_basic.inc gemacht. Das sieht schrecklich
aus, macht aber die Arbeit. Das sind ja nur Macros, in Code kommt nur,
was gebraucht wird.
Aber keine Garantie, daß alles überall stimmt!
c-hater schrieb:> Und diese> winzige AVR8-Multiplikation ist ja noch vergleichweise sehr trivial.> Wenn man sich anschaut, was manche sich für ungeheure Mengen an Code> einfach mal in ihre Projekte reinziehen, ohne auch nur andeutungsweise> zu prüfen, was die eigentlich wirklich tun, kann einem nur Angst und> Bange werden...
Sehe ich auch so! Ich finde, es sollte so sein, dass man sich Anregungen
für die Lösung eines Problems sucht, mit dem man nicht weiterkommt. Da
schaut man also mal, wie hat der das denn gemacht und schon setzt man,
setze ich, das in meinen eigenen Code um und freue mich, wenn es auf
Anhieb klappt...ist aber eher selten :-)
Gruß Rainer
Maxim B. schrieb:> Zuerst die Funktion aus dem Artikel:
Nein, das ist nicht die Funktion aus dem Artikel. Da sind auch ein paar
Unterstriche drin, die Du nicht verwendet hast.
mulsu_
muls_
mul_
Niemand von uns weiß, wie DU das umgesetzt hast.
Maxim B. schrieb:> Aber keine Garantie, daß alles überall stimmt!
Kann ich nachvollziehen.
"Unterstriche"? Nicht so hurtig, Hugo - die gibt es nur in der
Softwareversion, Maxim B. bezog sich auf die Hardwareversion.
Übrigens, am Rande: zuerst bin ich auch darauf reingefallen.
S. Landolt schrieb:> Eben, es geht hier um 'muls24x8_32'. - ?
Das ist die (entschuldige) "SOFTWARE-VERSION" und nicht die
S. Landolt schrieb:> Maxim B. bezog sich auf die Hardwareversion.
Capiche? :-)
Sie sollten noch einmal, in aller Ruhe, auf der entsprechenden
Forumsseite unter '5 Hardware Version', Unterpunkt '5.3 signed x
signed', Unterpunkt 'muls_24x8_32' nachschauen.
S. Landolt schrieb:> Sie sollten noch einmal, in aller Ruhe, auf der entsprechenden> Forumsseite unter '5 Hardware Version', Unterpunkt '5.3 signed x> signed', Unterpunkt 'muls_24x8_32' nachschauen.
Ich gelobe Besserung. Vielen Dank. Muss ich Dich jetzt auch Siezen?
Nö, allmählich gewöhne ich mich an die ubiquitäre Duzerei, auch wenn es
schwerfällt. Aber selbst wildfremde Menschen zu duzen, das schaffe ich
denn doch nicht.
S. Landolt schrieb:> Aber selbst wildfremde Menschen zu duzen, das schaffe ich> denn doch nicht.
Daran gewöhnst Du Dich in "Internationalen Konzernen" :-/ und in Foren
:-)
S. Landolt schrieb:> Nö, allmählich gewöhne ich mich an die ubiquitäre Duzerei, auch wenn es> schwerfällt. Aber selbst wildfremde Menschen zu duzen, das schaffe ich> denn doch nicht.
Kulturen, Sprachen in denen diese Unterscheidung wichtig ist, sind
konservativ und legen großen Wert auf Etikette. Sprachen, Kulturen die
demonstrativ gegen diese Konventionen arbeiten sind genauso konservativ
und haben natürlich auch ihre heiligen Etikette. Man muß halt manchmal
genau hinhören...sie Arschloch, resp. du Arschloch...kommt immer darauf
an wann, wo und wer das sagt...ist doch klar oder :-)
Gruß Rainer
Hugo H. schrieb:> Niemand von uns weiß, wie DU das umgesetzt hast.
Ich habe zuerst immer Hardware-mul getestet und erst danach Ergebnis mit
Software-mul verglichen. Es gab nie Unterschiede. Wenn Fehler, dann bei
beiden Varianten. Wenn richtig, dann auch bei beiden.
1
.macro m_mul
2
#ifdef _HARDMULT_
3
mul @0,@1
4
#else
5
mov r24,@0
6
mov r25,@1
7
rcall mul_pr
8
#endif
9
.endm
10
11
.macro m_muls
12
#ifdef _HARDMULT_
13
muls @0,@1
14
#else
15
mov r24,@0
16
mov r25,@1
17
rcall muls_pr
18
#endif
19
.endm
20
21
.macro m_mulsu
22
#ifdef _HARDMULT_
23
mulsu @0,@1
24
#else
25
mov r24,@0
26
mov r25,@1
27
rcall mulsu_pr
28
#endif
29
.endm
30
31
#ifndef _HARDMULT_
32
33
_muls_: sub r1,r1 ; clear result High byte and carry
34
ldi r18,8 ; init loop counter
35
brcc PC+2 ; if carry (previous bit) set
36
add r1,r16 ; add multiplicand to result High byte
37
sbrc r0,0 ; if current bit set
38
sub r1,r16 ; subtract multiplicand from result High
39
asr r1 ; shift right result High byte
40
ror r0 ; shift right result L byte and multiplier
41
in r17,SREG
42
dec r18 ; decrement loop counter
43
brne PC-8 ; if not done, loop more
44
ret
45
46
47
_mulsu_:clr r1 ;clear result High byte
48
ldi r18,8 ;init loop counter
49
lsr r0 ;rotate multiplier
50
brcc PC+2 ; carry set
51
add r1,r16 ; add multiplicand to result High byte
52
ror r1 ; rotate right result High byte
53
ror r0 ; rotate right result L byte and multiplier
54
in r17,SREG
55
dec r18 ; decrement loop counter
56
brne PC-6 ; if not done, loop more
57
ret
58
59
;---------------------------------
60
;mul Befehl in Software als call
61
;---------------------------------
62
63
; @0 = r24, @1 = r25
64
mul_pr:
65
clr r1 ;Ergebnis = 0
66
sec ;Multiplikant ersetzt gleichzeitig den Schleifenzaehler
Ich habe Software-mul-routinen aus genanntem Artikel genommen. Die
arbeiten richtig. Einzig habe ich sie aus reinen Macros in Macro mit
Call umgeschrieben, damit Programmcode nicht zu groß wird.
Wenn hier schon Takte gezählt werden ...
Kann mir jemand sagen, was das Gepusche und Gepoppe soll? Zu dem
Zeitpunkt, wo das Null-Register gebraucht wird, findet sich bereits ein
nicht mehr gebrauchtes Eingangsregister.
bitflipser schrieb:> Wenn hier schon Takte gezählt werden ...> Kann mir jemand sagen, was das Gepusche und Gepoppe soll? Zu dem> Zeitpunkt, wo das Null-Register gebraucht wird, findet sich bereits ein> nicht mehr gebrauchtes Eingangsregister.
Ziel ist, Software-Variante möglichst ähnlich zu Hardware-Variante zu
machen. Hardware-mul kann beliebige Register als Quelle nehmen, bei
Software-Variante sollte ich dafür zwei Register benutzen, die bei
Hardware-Variante unberührt bleiben. Deshalb push und pop. Da
Software-Variante sowieso ca.15 mal langsamer ist, spielen hier 8 Cycles
für push und pop kaum noch eine Rolle.
Die Software-Variante wird nur in seltenen Fällen gebraucht, wenn man
Tiny nimmt und doch mul braucht. Heute kann man fast immer Mega nehmen,
es sei denn, man braucht USI statt I2C. Zwar kann man auch dann
ATmega645 u.Ä. nehmen.
Hugo Hurtig schrieb:
> Daran gewöhnst Du Dich in "Internationalen Konzernen"
Als ich noch bei HP Deutschland arbeitete, war der Standard Sie+Vorname
- das ist aber, zugegeben, schon eine Weile her.
bitflipser fragte:
> Kann mir jemand sagen, was das Gepusche und Gepoppe soll?
In Bezug auf Hardware-'muls24X8_32' müsste das Steffen H. beantworten.
Vielleicht sollen die Originalwerte erhalten bleiben.
bitflipser schrieb:> Zu dem> Zeitpunkt, wo das Null-Register gebraucht wird, findet sich bereits ein> nicht mehr gebrauchtes Eingangsregister.
Du solltest es unter dem Aspekt der "universellen" Registernutzung
sehen. Wenn du mit deinem Progrämmchen nichts anderes tust, als 5
Byte(Register) zu verwursten, dann mußt du nichts pushen und pollen.
Wenn deine Routine aber als Unterprogramm laufen soll, dann sorgst du
einfach dafür, dass die benötigten Register vorher gesichert und
hinterher wieder hergestellt werden. Das ist bewährter guter
Programmierstil...
Gruß Rainer
Nun habe ich die Sache etwas gelernt...
Ich kam zum Schluß, daß die auf der Seite
https://www.mikrocontroller.net/articles/Multiplikation_in_Assembler
vorgeschlagene Art, bei Software-Mult die Befehle mul, muls und mulsu
mit macro zu emulieren, bringt nichts. Im Vergleich mit "klassischen"
Varianten gibt das viel mehr Code und ist auch viel langsamer.
Außerdem gibt es auf der Seite
https://www.mikrocontroller.net/articles/Multiplikation_in_Assembler zu
viele Fehler und Schreibfehler, so kann man dort angebotene Code leider
nur teilweise und mit Vorsicht genießen...
Ich habe hier meine Variante für Soft- und Hardmult. Ich habe die
Funktionen als Macro geschrieben. Das hat Vorteil: man kann diese Macro
in Funktionen einbauen, die mehr machen als einfache Multiplikation.
Dabei hat man mehr Freiheit bei Registerauswahl. Natürlich sollte man
diese Macros für Gebrauch als "reine" Mult in Funktionen umwandeln. Aber
das ist ja nicht schwer.
Ich denke, auch bei Mega hat Software-Mult ab und zu Sinn, da bei
Hardware-Mult mit Vorzeichen nicht alle Register für Argumente zu
gebrauchen sind: oft sind nur r16-r23 dafür geeignet. Auch Code ist bei
Softmult oft (nicht immer) sparsamer. Z.B. multsoft_24x24_48 hat 64
bytes, multhard_24x24_48 dagegen 84 bytes; multsoft_24x40_64 hat 76
bytes, multhard_32x32_64 dagegen 162 bytes, wenn auch viel schneller.
Als Null-Register paßt bei Hardware-Mult hervorragend @0, da @0 nach
Multiplikation von LSB nicht mehr geändert wird. Allerdings braucht die
Folge push @0 - clr @0 - pop @0 schon 5 cycles, deshalb bleibt oft auch
andere Folge von Vorteil: mul @x,@y - add @a,r0 - adc @b,r1 - clr r0 -
adc @c,r0 usw. Auf Befehle MOVW habe ich verzichtet, obwohl sie ein paar
cycles sparen könnten: in Macro solcher Art würde das Registerauswahl
zusätzlich beschränken.
Also, hier sind beide INC. Ich habe die Macros sorgfältig geprüft, ich
kann die Fehler natürlich nicht ausschließen. Aber vielleicht wird das
für jemand nützlich.
Viele Grüße.