Forum: Mikrocontroller und Digitale Elektronik BCD Multiplikationsprogramm


von Juergen B. (jbaben)


Angehängte Dateien:

Lesenswert?

Hallo,
ich habe ein Problem mit dem gezeigten Assembler-Programm 
(BCD-Multiplikationsprogramm).
Das Beispiel habe ich aus dem Buch "MC-Tools 2" von Otmar Feger.
In dem gezeigten Beispiel soll eine Multipliaktion von 200*200 
ausgeführt werden. Das Ergebnis ist aber nicht "40000" sondern "400".
Das Ergebnis sollte in den Speicherstellen "37 36 35 34 (MSB .. .. LSB) 
stehen. Bei dem gezeigten Ergebnis ist aber: 37 36 35 34: 00 00 04 00.
Vieleicht kennt ja jemand das Program und kennt den Fehler oder ich habe 
nicht die richtigen Parameter zugeordnet.
BCD-Multiplikationsprogramm MUL_BCD:
1
; Test BCD-Arithmetik
2
; BCD-Multiplikationsprogramm MUL_BCD
3
; Beispiel aus dem Buch MC-Tools 2 von Otmar Feger 1992
4
; Compiler: Keil-C uVision V5.38.0.0
5
6
ORG  0000H
7
   LJMP ANFANG
8
   
9
   ORG  000BH
10
   RETI                     ; TIMERINTERRUPT
11
12
   ORG  0100H
13
    
14
ANFANG:
15
           MOV  (30H),#00H      ; LSB Multiplikant
16
           MOV  (31H),#02H      ; MSB Multiplikant
17
           MOV  (32H),#00H      ; LSB Multiplikator
18
           MOV  (33H),#02H      ; MSB Multiplikator
19
           CALL MUL_BCD           ; Rechnung 200 * 200 
20
           SJMP  $
21
           
22
; ********************************************************************
23
; * BCD-Multiplikationsprogramm MUL_BCD (MC-Tools 2: Seite 76-79)
24
Multiplikant  EQU 2          ; Byteanzahl
25
Multiplikator EQU 2           ; Byteanzahl
26
PRODUKT      EQU MULTIPLIKANT+MULTIPLIKATOR  ; Byteanzahl
27
MANZ      EQU MULTIPLIKANT*2      ; Halbbyte-Anzahl
28
AREG           EQU 30H        ; Register (LSB) für Multiplikant
29
BREG      EQU 32H        ; Register (LSB) für Multiplikator
30
CREG      EQU 34H        ; Register (LSB) für Ergebnis
31
ABIT      BIT 0D1H        ; Stelle für Multiplikation (Nibble-Marke)
32
BBIT      BIT 0F0H        ; Stelle für Multiplikant
33
;R0        ; Register für AREG
34
;R1        ; Register für CREG
35
;R2        ; Adresse für BREG
36
;R3        ; Halbbyte des Multiplikators
37
;R4        ; Summierregister LSB
38
;R5        ; Summierregister MSB
39
;R6              ; Stellenzähler Multiplikant
40
ENDE      EQU CREG+PRODUKT
41
MUL_BCD:
42
    MOV  R0,#34H    ; Register für das Ergebnis
43
    MOV R2,#PRODUKT          ; initialisieren
44
    CLR A
45
M00:  MOV @R0,A
46
    INC R0
47
    DJNZ R2,M00
48
    MOV R0,#AREG  ; Register für AREG (Multiplikant LSB)
49
    MOV R1,#CREG   ; Register für CREG  (Ergebnis LSB
50
    MOV R2,#BREG  ; Register für BREG (Multiplikator LSB)
51
    
52
    MOV R6,A    ; Stellenzähler löschen
53
    CLR ABIT    ; Stellenbits löschen
54
    CLR BBIT    ; 
55
; Eine Stelle des Multiplikators rechtsbündig in <KONSTANTE> speichern
56
M0:
57
  MOV B,R1      ; CREG_PNTR speichern
58
  MOV A,R2      ; BREG_ADR -> R1(CREG_PNTR)
59
  MOV R1,A
60
  MOV A,@R1      ; <BREG_ADR> -> Akku
61
  JNB BBIT,M1      ; Sprung, falls unteres Halbbyte
62
  SWAP A        ; Akku swappen: 
63
M1:
64
  ANL A,#0FH      ; oberes Halbbyte ausblenden
65
  MOV R3,A      ; Akku -> KONSTANTE
66
  MOV R1,B      ; CREG_PNTR restaurieren
67
; Multiplikation von <KONSTANTE> mit einer Stelle des Multiplikanten
68
; und Abspeichern des stellenrichtigen Ergebnisses in <ZWSUM_LSB> und <ZWSUM_MSB>
69
M2:
70
  MOV A,R6      ; Prüfen, ob unteres Halbbyte
71
  RRC A        ; oder oberes Halbbyte des Multiplikanten
72
  MOV A,@R0
73
  JNC  M3        ; Sprung, falls unteres Halbbyte
74
  SWAP A        ; Akku swappen
75
M3:
76
  ANL A,#0FH      ; oberes Halbbyte ausblenden
77
  MOV B,R3      ; <KONSTANTE> -> B
78
  MUL AB
79
  MOV B,#10      ; Ergebnis aufteilen in   **16
80
  DIV AB        ; Zehner- und Einerstelle **17
81
  JB ABIT,M4      ; Sprung falls ABIT=1
82
  SWAP A
83
  ADD A,B        ; addieren nieder- und höherwertige Stelle
84
  MOV R4,A      ; in <ZWSUM_LSB> speichern
85
  SJMP M5  
86
M4:
87
  MOV R5,A      ; ? höherwertigere Stelle speichern
88
  MOV A,B        ; niederwertigere Stelle
89
  SWAP A        ; linksbündig
90
  MOV R4,A      ; in <ZWSUM_LSB> speichern
91
; Addition von <ZWSUM_LSB> und <ZWSUM_MSB> auf Produktregister CREG
92
M5:
93
  MOV B,R1      ; CREG_PNTR speichern
94
  MOV A,@R1      ; <ZWSUM_LSB> zu @<CREG_PNTR>
95
  ADD A,R4      ; BCD addieren     **18
96
  DA A        ; Dezimalkorrektur
97
  MOV @R1,A      ; 
98
  JNB ABIT,M6      ; Sprung falls ABIT=0
99
  INC R1        ; nächstes CREG_PNTR-Register
100
  MOV A,@R1      ; <ZWSUM_LSB>+CY zu <CREG_PNTR>
101
  ADDC A,R5      ; addieren (BCD)
102
  DA A         ; **19
103
  MOV @R1,A      ; 
104
M6:
105
  JNC M9        ; Sprung falls kein Überlauf
106
M7:
107
  INC R1        ; nächstes CREG_PNTR-Register
108
  CJNE R1,#ENDE,M8  ; CREG-Bereich überschritten ?
109
  SJMP M9
110
M8:
111
  MOV A,#1      ; Übertrag zu @<CREG_PNTR>
112
  ADD A,@R1      ; addieren (BCD)
113
  DA A        ; **20
114
  MOV @R1,A      ; 
115
  JC M7        ; Sprung falls erneuter Überlauf
116
M9:
117
  MOV R1,B      ; CREG_PNTR restaurieren
118
  INC R6        ; Nächste Multiplikantenstelle
119
; Steuerung von ABIT, BBIT, R0, M_CNTR,BREG_ADR,CREG_PNTR
120
M10:
121
  CJNE R6,#MANZ,M12  ; Letzte Stelle des Multilikanten ?
122
  MOV R6,#0      ; Stellenzähler zurücksetzen
123
  MOV R0,#AREG    ; R0 zurücksetzen
124
  CPL BBIT      ; Nächste Stelle des Multiplikator
125
  SETB ABIT
126
  JB BBIT,M11      ; Sprung falls Stelle mit oberen Halbbyte
127
  CLR ABIT      ; Stelle mit unterem Halbbyte
128
  INC R2        ; BREG_PNTR erhöhen ?
129
  CJNE R2,#CREG,M11  ; Multiplikation beendet ?
130
  SJMP MEXIT
131
M11:
132
  MOV A,R1      ; Startwert für CREG_PNTR
133
  CLR C        ; berechnen und laden
134
  SUBB A,#MULTIPLIKANT-1  ;
135
  MOV R1,A
136
  SJMP M0
137
M12:
138
  CPL ABIT
139
  JB ABIT,M13
140
  INC R1        ; CREG_PNTR erhöhen, falls ABIT=0
141
M13:
142
  JB ABIT,M14
143
  JNB BBIT,M15
144
  SJMP M2
145
M14:
146
  JNB BBIT,M2
147
M15:
148
  INC R0        ; R0 erhöhen, falls ABIT u. BBIT=0
149
  SJMP M2        ; oder ABIT u. BBIT=1
150
MEXIT: RET
151
152
END
Im Anhang nochmals das Programm.

Juergen

von Thorsten S. (whitejack)


Lesenswert?

Ad hoc:

https://en.wikipedia.org/wiki/Endianness#/media/File:32bit-Endianess.svg

https://en.wikipedia.org/wiki/Endianness

Nur eine Vermutung, aber ich glaube das ist es nicht.

Bin zwar schon lange nicht mehr im Thema, aber ich finde so erstmal 
nicht die Stellen wo die 200d (oder 0xC8 / C8h) in irgendein Register 
geladen werden...

: Bearbeitet durch User
von Juergen B. (jbaben)


Lesenswert?

Hallo,
vielen Dank für den schnellen Hinweis.
Ich weiss leider nicht genau was das zu meiner Lösung beitragen soll, 
außer das die Funktion "MUL_BCD" Little Endian verwendet.
Juergen

von Thorsten S. (whitejack)


Lesenswert?

Thorsten S. schrieb:
> aber ich finde so erstmal
> nicht die Stellen

           MOV  (30H),#00H      ; LSB Multiplikant
           MOV  (31H),#02H      ; MSB Multiplikant
           MOV  (32H),#00H      ; LSB Multiplikator
           MOV  (33H),#02H      ; MSB Multiplikator

rrr, ist ja BCD...

Juergen B. schrieb:
> Ich weiss leider nicht genau was das zu meiner Lösung beitragen soll

Ganz einfach, der Gedanke war, dass sie BYtes im Ergebnis verdreht sein 
könnten...

0x 00 00 04 00

Wären Byteweise von rechts nach links gelesen 40000...

LSB...MSB

: Bearbeitet durch User
von Juergen B. (jbaben)


Lesenswert?

Hallo,
Danke.
Das hatte ich schon probiert. 400 = 20*20.
Juergen

von Thorsten S. (whitejack)


Lesenswert?

Juergen B. schrieb:
> Das hatte ich schon probiert.

Wo steht das? Was wurde denn noch so probiert.

Juergen B. schrieb:
> 400 = 20*20.

Ist in der Regel wohl so???

Versuche mal krumme Werte:

           MOV  (30H),#23H      ; LSB Multiplikant
           MOV  (31H),#01H      ; MSB Multiplikant
           MOV  (32H),#23H      ; LSB Multiplikator
           MOV  (33H),#01H      ; MSB Multiplikator

von Juergen B. (jbaben)


Lesenswert?

Hallo,
gut das ich gefragt habe.
Der Hinweis auf die andere Reihenfolge beim Ergebnis ist richtig.
Getestet mit 300 * 300 = 90000.
Speicher 34 35 36 37 = 00 09 00 00.
Danke.
Leider funktioniert das angegebene Beispiel: 1358 * 7916 = 10749928 
nicht.
Bei mir: 34 35 36 37 = 70 03 02 00.
Juergen

von Juergen B. (jbaben)


Lesenswert?

Hallo,
mit: 123 * 123 erhalte ich: 34 35 36 27 = 92 84 00 00.
Richtig wäre: 00 01 51 29

Juergen

von Juergen B. (jbaben)


Lesenswert?

Hallo,
mit dem angegebenen Programm-Code funktioniert die Funktion "MUL_BCD" 
nicht.
Die Funktion funktiniert nur mit der LSB-Stelle = 00H und MSB-Stelle = 
09H,
also bis: 900 * 900 = 00 81 00 00.

Juergen

von Rainer W. (rawi)


Lesenswert?

Juergen B. schrieb:
> BCD-Multiplikationsprogramm MUL_BCD:; Test BCD-Arithmetik
> ; BCD-Multiplikationsprogramm MUL_BCD
> ; Beispiel aus dem Buch MC-Tools 2 von Otmar Feger 1992
> ; Compiler: Keil-C uVision V5.38.0.0

Wichtige Regeln - erst lesen, dann posten!
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Is' doch nicht sooh schwer zu verstehen. Sobald der automatische 
Zeilenzähler ein Formatproblem bekommt, kannst du dir ganz sicher sein, 
dass der Code in diesem Sinne als "länger" zu betrachten ist ;-)

Juergen B. schrieb:
> as Ergebnis ist aber nicht "40000" sondern "400".
> Das Ergebnis sollte in den Speicherstellen "37 36 35 34 (MSB .. .. LSB)
> stehen. Bei dem gezeigten Ergebnis ist aber: 37 36 35 34: 00 00 04 00.

Dann überleg dir, was in jedem Programmschritt passieren muss, damit das 
richtige Ergebnis berechnet wird und verfolge mit dem Debugger notfalls 
Schritt für Schritt, ob der Ablauf passt bzw. wo es Abweichungen gibt.

: Bearbeitet durch User
von Egon (egonm)


Lesenswert?

Juergen B. schrieb:
> Getestet mit 300 * 300 = 90000.
> Speicher 34 35 36 37 = 00 09 00 00.
> Danke.
> Leider funktioniert das angegebene Beispiel: 1358 * 7916 = 10749928
> nicht.
> Bei mir: 34 35 36 37 = 70 03 02 00.

Juergen B. schrieb:
> mit: 123 * 123 erhalte ich: 34 35 36 27 = 92 84 00 00.
> Richtig wäre: 00 01 51 29

Wenn du sowieso jedes Paar des Einmaleins einzeln testen möchtest, 
schlage ich vor, dass du ein zweidimensionales Array aller Pärchen mit 
Ergebnis anlegst. Dann indizierst du in das Array und kannst sicher 
sein, das richtige Ergebnis zu erhalten.
Du kannst sogar zwei unterschiedliche Arrays für LSB und MSB anlegen und 
wirst hardwareunabhängig!!

von Thorsten S. (whitejack)


Lesenswert?

Egon schrieb:
> dass du ein zweidimensionales Array

Junge, das hier ist Assembler Code. Lass die Trollerei...Bitte.

Wenn du wirklich neu hier bist, Anmeldung 06.12.24 dann starte erstmal 
hier:

https://www.mikrocontroller.net/articles/AVR-Tutorial

https://www.mikrocontroller.net/articles/Hauptseite

: Bearbeitet durch User
von Rainer W. (rawi)


Lesenswert?

Thorsten S. schrieb:
> Junge, das hier ist Assembler Code. Lass die Trollerei...Bitte.

Bevor du hier so große Töne spuckst:

Es geht um die Struktur, nicht um die Syntax.
Auch in Assembler Code lassen sich Daten über Indizierung geeignet 
ansprechen - das konnte vor fast 50 Jahren schon ein 6502.
Aber vielleicht fehlt dir da die Erfahrung.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ich vermute mal, in dem Buch gibt es eine ausführliche Erklärung zu dem 
Code.
Den Code allein kann ich nicht nachvollziehen. Was mir nur auffällt, daß 
eine ganze Menge Umstände nötig sind, da die CPU ja alle Rechenschritte 
nur im Binärformat durchführen kann und nicht in BCD.
Ich selber habe daher auch nur Routinen erstellt, die das Binärformat 
benutzen. Warum man das umständliche BCD-Format benutzen sollte, 
erschließt sich mir nicht.
Falls Interesse besteht, könnte ich meine A51 Math-Lib mal raussuchen 
und posten. Sie ist für ein variables Format ausgelegt, d.h. man könnte 
z.B. auch mit 20 Byte Zahlen (1.4615e+48) rechnen. Die Operanden werden 
quasi als eine Art Stack abgelegt. Die Operationen werden also über die 
obersten 2 Operanden ausgeführt.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Juergen B. schrieb:

> ich habe ein Problem mit dem gezeigten Assembler-Programm
> (BCD-Multiplikationsprogramm).

Ja, du weißt scheinbar nicht einmal was die Zielarchitektur ist. Und du 
weißt obendrein nicht, dass man diese für erfolgreiche 
Assemblerprogrammierung unweigerlich kennen muss.

Wäre es anders, hättest du sie angegegen.

>
1
> ; Compiler: Keil-C uVision V5.38.0.0
2
>

Womit das Assemblerprogramm dann übersetzt werden, ist natürlich auch 
nicht völlig irrelevant, aber im Vergleich zu der Angabe, um welche 
Ziel-Architektur es eigentlich geht, doch schon ziemlich irrelevant...

von Juergen B. (jbaben)


Lesenswert?

Peter D. schrieb:
> Ich vermute mal, in dem Buch gibt es eine ausführliche Erklärung zu dem
> Code.
> Den Code allein kann ich nicht nachvollziehen. Was mir nur auffällt, daß
> eine ganze Menge Umstände nötig sind, da die CPU ja alle Rechenschritte
> nur im Binärformat durchführen kann und nicht in BCD.
> Ich selber habe daher auch nur Routinen erstellt, die das Binärformat
> benutzen. Warum man das umständliche BCD-Format benutzen sollte,
> erschließt sich mir nicht.
> Falls Interesse besteht, könnte ich meine A51 Math-Lib mal raussuchen
> und posten. Sie ist für ein variables Format ausgelegt, d.h. man könnte
> z.B. auch mit 20 Byte Zahlen (1.4615e+48) rechnen. Die Operanden werden
> quasi als eine Art Stack abgelegt. Die Operationen werden also über die
> obersten 2 Operanden ausgeführt.
Hallo,
eine ausführliche Erklärung gibt es in dem Buch leider nicht.
Ich denke mal das der Autor davon ausgeht wie eine BCD-Multiplikation 
funktioniert.
Ein Interesse besteht natürlich an die A51 Math-Lib (Danke).
Juergen

von Juergen B. (jbaben)


Lesenswert?

Ob S. schrieb:
> Juergen B. schrieb:
>
>> ich habe ein Problem mit dem gezeigten Assembler-Programm
>> (BCD-Multiplikationsprogramm).
>
> Ja, du weißt scheinbar nicht einmal was die Zielarchitektur ist. Und du
> weißt obendrein nicht, dass man diese für erfolgreiche
> Assemblerprogrammierung unweigerlich kennen muss.
>
> Wäre es anders, hättest du sie angegegen.
>
>>
1
>> ; Compiler: Keil-C uVision V5.38.0.0
2
>>
>
> Womit das Assemblerprogramm dann übersetzt werden, ist natürlich auch
> nicht völlig irrelevant, aber im Vergleich zu der Angabe, um welche
> Ziel-Architektur es eigentlich geht, doch schon ziemlich irrelevant...
Hallo,
ich weiss schon das es wichtig ist welcher MC verwendet wird.
Der Compiler fragt ja beim Anlegen eines Projektes nach dem 
entsprechenden Device. Bei mir ist das: AT89C51RC2.
Mein eigentliches Anliegen war:
Ich wollte wissen ob jemand die Funktion kennt und wenn ja ob die 
Funktion
funktioniert oder ein Fehler vorliegt.
Wenn jemand die Funktion kennt, hätte ich mir das debuggen ersparen 
können.
Juergen

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Juergen B. schrieb:
> Ein Interesse besteht natürlich an die A51 Math-Lib (Danke).

Anbei mal die Lib.
Im Testprogramm ist precision mit 4 Bytes (32 Bit) definiert und Platz 
für 4 Operanden reserviert.

von Juergen B. (jbaben)


Lesenswert?

Hallo,
so die Funktion "MUL_BCD" funktioniert nun.
Das Problem lag an den verwendeten Bits für ABIT bzw. BBIT.
Mit: ABIT BIT 20H.0, BBIT BIT 20H.1 funktioniert "MUL_BCD" mit der 
Rechnung 1358 * 7916 = 10749928.
Vielen Dank für Eure Hinweise, besonderen Dank an Peter D. für seine 
Lib.
Werde ich noch testen.

Juergen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.