Bascom ganzzahlige Division mit Rest

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.212
58
48
Hennigsdorf
Sprachen
BascomAVR, Assembler
Hallo.

Manchmal, insbesondere wenn man eine Zahl in Dezimalstellen zerhacken will, benötigt man sowohl den Quotienten als auch den Rest einer ganzzahligen Division.
In der Praxis sieht man dann oft solche Code-Stücke:


CodeBox BascomAVR
'Zahl zerlegen in Zehner und Einer:                         Beispiel
Zahl_temp = Zahl         '1234
Einer = Zahl_temp Mod 10 '4

Zahl_temp = Zahl_temp - Einer       '1230
Zahl_temp = Zahl_temp / 10       '123
Zehner = Zahl_temp Mod 10       '3

Zahl_temp = Zahl_temp - Zehner       '120
Zahl_temp = Zahl_temp / 10       '12
Hunderter = Zahl_temp Mod 10       '2

Zahl_temp = Zahl_temp - Hunderter       '10
Zahl_temp = Zahl_temp / 10       '1
Tausender = Zahl_temp Mod 10       '1
Man erkennt also: bei n-Stellen sind es n Modulo-Divisionen und n-1 Divisionen (die n-1 Subtraktionen sind hier unnötig).
Jetzt erinnern wir uns an die Schriftliche Division aus der Grundschule:
Code:
2537 : 17 =
Code:
2537 : 17 = 1
Code:
2537 : 17 = 1
17
--
08
Code:
2537 : 17 = 1
17
--
083
Code:
2537 : 17 = 14
17
--
083
 68
 --
 15
Code:
2537 : 17 = 149
17
--
083
 68
 --
 157
 153
 ---
   4
BASCOM macht quasi dasselbe, nur eben binär. Das ganzzahlige Ergebnis hier wäre also die "149".
Der Rest "4" ist auch vorhanden - wo läßt BASCOM den?

Das kommt darauf an:
  • werden Bytes dividiert, läßt BASCOM den Rest in Register 24 liegen (den Quotienten in Register 16)
  • bei Words und Integern verbleibt der Rest in den Registern 17..16 (MSB..LSB) (der Quotient in R21..R20)
  • bei Long verbleibt der Rest in den Registern 19..16 (MSB..LSB) (der Quotient in R23..R20)
Und wie kommt man da ran?
Indem man das/die Register sofort nach der Division in die entsprechende Variable schreiben läßt.
Bei Bytes also:


CodeBox BascomAVR
Quotient=Divident\Divisor
STS {Rest}, R24

Bei Words/Integern:


CodeBox BascomAVR
Quotient = Divident \ Divisor
STS {rest}, r16
STS {rest+1}, r17

Bei Long zusätzlich noch R18 und R19 "Storen"

Somit sollte sich der Code von oben, den @Thorsten_Sch uns freundlicherweise bereitgestellt hatte, wie folgt vereinfachen lassen:

CodeBox BascomAVR
Tausender=Zahl_temp\10
STS {Einer}, R16
STS {Einer+1}, R17
Tausender=Tausender\10
STS {Zehner}, R16
STS {Zehner+1}, R17
Tausender=Tausender\10
STS {Hunderter}, R16
STS {Hunderter+1}, R17

Nur noch drei Divisionen.

P.S. @dino03 : Kannst Du diesen Beitrag bitte in die FAQ-Übersicht aufnehmen?
 
Zuletzt bearbeitet:

Thorsten_Sch

Mitglied
31 Okt 2010
147
0
16
42
HH
Sprachen
BascomAVR
super verstehe nur bahnhof
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3.212
58
48
Hennigsdorf
Sprachen
BascomAVR, Assembler
Hm...
Wo soll ich anfangen?
Grundsätzliche Informationen zur Harvard-Architektur der AVR findest Du in Dinos "Dampmaschin-Thread".
Die AVR sind 8Bit-Controller, nahezu alle Operationen basieren also auf Bytes.
Nahezu alle Rechenoperationen werden von der ALU durchgeführt.
Die benötigten Operanden müssen sich dazu in einem bzw zwei Registern des Registerfile ( quasi der Schreibtisch des ALU - bis auf wenige AVR immer 32 (Rechen-)Register) befinden - Das Ergebnis landet entsprechend auch in einem (ganz selten in mehreren) dieser Register.
Daten(-Bytes) können außerdem im SRAM (quasi ein Aktenschrank im Flur), oder im Eeprom (Archiv im Keller) ausgelagert werden. Meinetwegen auch in externen Speichern (Hochregallager am anderen Ende der Stadt).

Welche Rechenoperationen beherrschen die AVR?
Addition
Subtraktion
Division/Multiplikation, aber nur mit zwei
(MegaAVR (und X-Core-Tinies) können in gewissem Maße auch multiplizieren)

Divisionen (und Multiplikationen) müssen also mit entsprechenden Schleifen (deswegen der Rechenweg mit der ganzzahligen Division oben) mithilfe der vorhandenen Operationen umgesetzt werden.

BASCOM verwaltet die Variablen im SRAM, für jede Rechenoperation werden die benötigten Variablen also aus dem SRAM in (je) ein Register des Registerfile geladen, dann tut die ALU ihr Werk, anschließend wird das Ergebnis aus dem Registerfile wieder ins SRAM gespeichert.
(Die ALU arbeitet wie gesagt Bytebasiert - wenn Du also zwei Words addierst, lädt BASCOM die vier Bytes (zwei pro Word, klar), die ALU führt zwei Additionen aus (einmal mit Übertrag=Carry), anschließend wird das Ergebnis in Form von zwei Bytes (ein Word) zurückgespeichert (also zwei Speicherinstruktionen).

Vom SRAM ins Registerfile wird mit Load geladen -> LD oder LDS.
Vom Registerfile ins SRAM gespeichert wird mit Store -> ST oder STS.

Jetzt zu dem Code-Schnipsel, den ich Dir stibitzt hatte:
Die drei Subtraktionen in den Zeilen 5, 9 und 13 sind unnötig, da die Variablen ganze Zahlen repräsentieren, die Division ganzzahlig ist.
Die letzten beiden Zeilen liefern auch dasselbe Ergebnis - Effektiv wärst Du auch mit drei Divisionen und drei Modulo-Divisionen ausgekommen.
Also insgesamt sechs Divisionen, bei denen je zwei Words (4 Bytes) vom SRAM ins Registerfile geladen werden, und ein Word (2 Bytes) zurückgespeichert wird.

Was ich mit dem Rechenweg der ganzzahligen dezimalen Division aus der Grundschule da oben verdeutlichen wollte ist, daß auf dem Papier außer dem Ergebnis auch der Rest stehenbleibt, quasi als Abfallprodukt. Wenn Du also als zweite Aufgabe die Berechnung des Rests dieser Division gestellt bekommst, kannst Du entweder das ganze nochmal auf ein neues Blatt kritzeln (=Dein Programm), oder Du nimmst einfach die "4", die da schon unten am Rattenschwanz steht (=mein Programmschnipsel).

BASCOM macht das bei der ganzzahligen Division ("/" bzw "\") genauso, nur eben binär. Es holt sich die Variablen aus dem Aktenschrank im Flur (SRAM) auf den Schreibtisch (Registerfile), kritzelt 'ne Weile auf dem ganzen Schreibtisch rum, und kopiert dann das ganzzahlige Ergebnis zurück in den Schrank.
Entscheidend ist, daß der Tisch nie saubergemacht wird - die Register werden nur durch neue/folgende Instruktionen (bzw Loads) überschrieben.
Wenn man also weiß, wo auf dem Schreibtisch BASCOM bei einer ganzzahligen Division den Rest hingekritzelt hatte, kann man ihn nach der Division einfach von dort in eine Variable im Aktenschrank abspeichern (genau, mit Store bzw STS), ohne irgendwas rechnen lassen zu müssen.

Genau um dieses "Wo?" (und ggf auch das "Wie speichern?") bzw die Antwort darauf ging es mir in diesem Thema.

Mein Code-Schnipsel liefert nämlich dieselben Ergebnisse wie Deiner mit etwa dem halben Rechenaufwand - weil der Rest ein Abfallprodukt der Division ist, den BASCOM auf dem Schreibtisch liegenläßt.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)