Hi Leute! Ich will ein Programm schreiben, dass mir 5 Zahlen entgegennimmt und danach in einem Doppelwort abspeichert. Für das entgegennemen benutze ich ein Makro. Dieses Makro schreibt mir den ASCII-Code der Zahl in AL. In der Variable "Zahl" die als Doppelwort deklariert ist, sollen dann die 5 entgegengenommenen Zahlen abgespeichert sein. Mein Problem ist nun, dass ich nicht weiß wie ich den Inhalt von AL in die als Doppelwort deklararierte Variable "Zahl" hineinschreibe. Könnt ihr mir helfen? Ich hab's jetzt schon mal zusammengebracht, mit dem Befehl MOV BYTE PTR[Zahl],BL den Inhalt von BL in Zahl zu kopieren. Das Problem ist aber jetzt, dass er mir in der Variable "Zahl" den vorher reinkopierten wert überschreibt. Was mach ich falsch? Aussehen tut das jetzt so: %noctls ; Listing-Steueranweisungen werden nicht im Listing augegeben %noincl ; Incude-Dateien werden nicht im Listing ausgegeben INCLUDE MACROS.ASM ; Datei Macros.asm einbinden ASSUME CS:CODE, DS:DATA ; Segmentnamen bekannt geben ; „CODE“ wird Codesegment, „DATA“ wird Datensegment ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ DATA SEGMENT ; Beginn des Segmentes „DATA“ Zahl DD 0h DATA ENDS ; Ende des Segmentes „DATA“ ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ;----------------------------------------------------------------------- -------------------------------------------------------- CODE SEGMENT ; Beginn des Segmentes „CODE“ Anfang: MOV AX, DATA ; Datensegmentadresse ins ;Register AX MOV DS, AX ; Inhalt von Register AX ins Register DS MOV AX,0h ; AX auf 0 setzen MOV BX,0h ; BX auf 0 setzen MOV CX,5h ; Abbruchbedingung von LOOP in CX schreiben MOV DX,0h ; DX auf 0 setzen Marke1: Read_KBD_and_Echo ; Makro zum Einlesen einer Zahl aufrufen MOV BL,AL ; Momentanen Inhalt von AL in BL speichern MOV BYTE PTR [Zahl + 2] LOOP Marke1 Terminate_Program ; Makro Terminate_Program aufrufen CODE ENDS ; Ende des Segmentes „CODE“ ;----------------------------------------------------------------------- -------------------------------------------------------- END Anfang ; Ende des Programms ; Programm wird bei Anfang gestartet
Hallo Shiften dürfte nicht so ganz danebenliegen! Wie die Befehle für deinen Assembler aussehen, sagt dir das Handbuch. Gruß Joachim
Angenommen das ist x86 Assembler. > MOV BYTE PTR [Zahl + 2] Wo ist hier der zweite Operand > LOOP Marke1 Den Befehl LOOP kenn ich nicht ist das auch ein Macro? Wo ist die Bedingung für die 5 Durchläufe? gugge da http://www.i8086.de/asm/8086-88-asm-stosb.html
Achja Doppelwort hat nur 4 Byte wie das mit 5 Zeichen Passt ist mir ein Rätsel. Formuliere noch mal klarer was du willst (sollst), beachte Zahl ist nicht Ziffer.
> Den Befehl LOOP kenn ich nicht ist das auch ein Macro?
Nein, das ist ein normaler Assembler-Befehl. Er dekrementiert CX und
springt zur angegebenen Sprungmarke, falls es danach nicht 0 ist.
Skua schrieb: > Achja Doppelwort hat nur 4 Byte wie das mit 5 Zeichen Passt ist mir ein > Rätsel. Es ist zu vermuten, daß der TO fünf Ziffern einlesen will, und diese als fünfstellige Dezimalzahl interpretieren will. Damit ist es mit einer einfachen Schiebeoperation natürlich gar nicht mehr getan, da muss gerechnet werden. Der Algorithmus sieht so aus: - Ziel = 0 (32-Bit-Wert) - Zeichen einlesen - Zeichen in Ziffer umwandeln (0x30 -> 0, 0x39 -> 9) - Ziel += Ziffer (erste Stelle) - Zeichen einlesen - Zeichen in Ziffer umwandeln (0x30 -> 0, 0x39 -> 9) - Ziel *= 10 - Ziel += Ziffer (zweite Stelle) - Zeichen einlesen - Zeichen in Ziffer umwandeln (0x30 -> 0, 0x39 -> 9) - Ziel *= 10 - Ziel += Ziffer (dritte Stelle) - Zeichen einlesen - Zeichen in Ziffer umwandeln (0x30 -> 0, 0x39 -> 9) - Ziel *= 10 - Ziel += Ziffer (vierte Stelle) - Zeichen einlesen - Zeichen in Ziffer umwandeln (0x30 -> 0, 0x39 -> 9) - Ziel *= 10 - Ziel += Ziffer (fünfte Stelle) Erweiterung: Wird beim nach dem Einlesen der Zeichen festgestellt, daß es sich nicht um eine Ziffer handelt, kann die Prozedur abgebrochen werden, "Ziel" enthält dann den bisher eingegebenen Wert, was die Eingabe auch von ein- bis vierstelligen Zahlen ermöglicht. Im Gegensatz zu den hier oft programmierten µCs kann der x86 multiplizieren, daher sollte eine Umsetzung des obigen Algorithmus kein riesiges Problem darstellen.
Rufus t. Firefly schrieb: > Im Gegensatz zu den hier oft programmierten µCs kann der x86 > multiplizieren Also viele AVRs haben aber auch einen Multiplizierer an Board, den man auch per Assembler ansprechen kann auf vielfältige Weise ;)
> Den Befehl LOOP kenn ich nicht ist das auch ein Macro?
Soweit ich mich errinnern kann, ist LOOP <Marke> so etwas:
dec cx
jrnz marke
also ideal für (16Bit) Zählschleifen.
mfG ingo
Läubi .. schrieb: > Also viele AVRs haben aber auch einen Multiplizierer an Board Alle ATmegas und deren Derivate (z.B. AT90CAN128).
@Rolf Magnus + Ingo Danke muss mir irgendwie entfallen sein. Hab seit ca. 3 Jahren kein x86 Assembler genutzt.
Hey Leute! Danke für eure Hilfe! Der Algorithmus von rufus hat mir sehr weitergeholfen. Wenn ich nun mit diesem READ_KBD_and_ECHO eine Zeichen einlese, dann steht dieses Zeichen laut Makrobeschreibung in AL. Zusätzlich dazu steht in AH eine "1". Keine Ahnung wo diese "1" herkommt. Nun rechne ich das Zeichen in eine Zahl um und speichere es wieder in AL. Wie aber bekomme ich diese Zahl nun in das ganze AX? Einfach mit MOV geht's ja nicht weil MOV Befehle der Art AX,AL nicht erlaubt... Wie bekomme ich die Zahl dennoch von AL in AX? Könnt ihr mir helfen?
Klar Mov AH,0 Das mit dem XOR ist nur alte gewohnheit das es früher schneller war. auch hilfreich http://www.cs.cmu.edu/~ralf/files.html
So, also dank eurer Hilfe sieht das ganze jetzt so aus: Anfang: MOV AX, DATA ; Datensegmentadresse ins ;Register AX MOV DS, AX ; Inhalt von Register AX ins Register DS MOV AX,0h ; AX auf 0 setzen MOV BX,0h ; BX auf 0 setzen MOV CX,0h ; CX auf 0 setzen MOV DX,0h ; DX auf 0 setzen Read_KBD_and_Echo ; 1. Zeichen einlesen SUB AL,30h ; 1. Zeichen in 1. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen MOV BX,10000 ; 10000 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren MOV CX,AX ; AX in DX zwischenspeichern Read_KBD_and_Echo ; 2. Zeichen einlesen SUB AL,30h ; 2. Zeichen in 2. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen MOV BX,1000 ; 1000 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren ADD CX,AX ; CX mit AX addieren und in DX speichern Read_KBD_and_Echo ; 3. Zeichen einlesen SUB AL,30h ; 3. Zeichen in 3. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen MOV BX,100 ; 100 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren ADD CX,AX ; CX mit AX addieren und in DX speichern Read_KBD_and_Echo ; 4. Zeichen einlesen SUB AL,30h ; 4. Zeichen in 4. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen MOV BX,10 ; 10 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren ADD CX,AX ; CX mit AX addieren und in DX speichern Read_KBD_and_Echo ; 5. Zeichen einlesen SUB AL,30h ; 5. Zeichen in 5. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen ADD CX,AX ; CX mit AX addieren und in DX speichern Nun hab ich aber doch noch einige Fragen. Nämlich: Mit 5 Zahlen die man eingeben soll ist die größte Zahl 99999. Diese Zahl entspricht 1869Fh. Wenn ich nun mein Programm mit dieser "Zahl" 99999 füttere, dann steht in AX 869Fh. Das ist klar, weil ich mich momentan noch nicht um den Übertrag kümmere. Wie aber mach ich das am besten? Irgendwie muss ich wahrscheinlich noch die Stelle um irgendein Codeschnipsel ergänzen an der addiert bzw. multipliziert wird, denn nur an diesen beiden Stellen kann überhaupt ein Übertrag entstehen. Wie aber fang ich das da ab? Könnt ihr mir nochmal helfen?
Noch eine Frage. Ich soll nun die berechnete Zahl auf dem Bildschirm mittig ausgeben. Ich hab jetzt schon einige Zeit damit verbracht Antwort in meinem Assemblerbuch zu finden, aber über die Makros Display_Char und Display_String kann ich leider keine weiteren Informationen finden. Vor allem stell ich es mir schwierig vor, da ja die Zahl als Hex im Register vorliegt und ich soll ja bestimmt nicht die Hex-Zahl sondern die Dezimalzahl ausgeben... Wie gesagt, ich weiß nicht wie das gehen soll... Vielleicht helft ihr mir einfach nochmal! Dankeschön!
Erstmal Anfang: MOV AX, DATA ; Datensegmentadresse ins ;Register AX MOV DS, AX ; Inhalt von Register AX ins Register DS MOV AX,0h ; AX auf 0 setzen MOV BX,0h ; BX auf 0 setzen MOV CX,0h ; CX auf 0 setzen MOV DX,0h ; DX auf 0 setzen Read_KBD_and_Echo ; 1. Zeichen einlesen SUB AL,30h ; 1. Zeichen in 1. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen PUSH BX MOV BX,10000 ; 10000 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren POP BX MOV CX,AX ; DX:AX in BX:CX zwischenspeichern MOV BX,DX Read_KBD_and_Echo ; 2. Zeichen einlesen SUB AL,30h ; 2. Zeichen in 2. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen PUSH BX MOV BX,1000 ; 1000 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren POP BX ADD CX,AX ; addiere DX:AX auf BX:CX ADC BX,DX Read_KBD_and_Echo ; 3. Zeichen einlesen SUB AL,30h ; 3. Zeichen in 3. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen MOV BX,100 ; 100 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren ADD CX,AX ; addiere DX:AX auf BX:CX ADC BX,DX Read_KBD_and_Echo ; 4. Zeichen einlesen SUB AL,30h ; 4. Zeichen in 4. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen PUSH BX MOV BX,10 ; 10 in BX speichern MUL BX ; Inhalt von AX mit BX multiplizieren POP BX ADD CX,AX ; addiere DX:AX auf BX:CX ADC BX,DX Read_KBD_and_Echo ; 5. Zeichen einlesen SUB AL,30h ; 5. Zeichen in 5. Zahl umrechnen XOR AH,AH ; Funktionsaufruf löschen ADD CX,AX ; addiere DX:AX auf BX:CX ADC BX,DX
Hm, Danke für deine Mühe, aber die Befehle Push, Pop und ADC haben wir noch nicht durchgenommen. Gibt es keine andere Möglichkeit?
Anstatt PUSH POP kannst du das ganze auch im Datensegment speichern. An ADC geht kaum ein weg vorbei. Umständlich: ADD BX,AX JNC Labelx ; Kein Überlauf ADD CX,1 ; bei Überlauf 1 Addieren (INC CX ginge auch) Labelx:
Erst mal die Frage: Wieso willst Du kein XOR verwenden um Register zu nullen? Das ist die einfachste und schnellste Möglichkeit... da Dein Sourcecode kommentiert ist spielt das also keine Rolle. Dann eine andere Frage: Was ist mit SI und DI? Die kann man doch auch bentutzen... oder hab ich da was falsch in Erinnerung? Und zu guter letzt: Register die man benutzt sollte man sichern, initialisieren (z. B. mit 0x00 bzw 0x0000) und zum Schluss wieder herstellen (lernst Du später bei PUSH and POP ;)), nur um die Frage zu beantworten wieso DH 1 war: Weil es ein anderer Programmteil (Dein eigener oder ein anderer) so hinterlassen hat und möglicherweise so auch wieder benötigt (z. B. im Falle nach dme Aufruf von Unterroutinen). Da ich, bis jetzt, nur WinASM genutzt hatte (16 Bit-Coding hab ich recht früh fallen gelassen) weiß ich dass manche Register frei zur Verfügung stehen, manch andere nicht. Das ist so zumindest unter Windows-API-Programmierung. EAX, ESI und EDI sind z. B. solche freien, deren Werte sind undefiniert nach einem API-Call. Alle anderen muss man sichern und wieder herstellen. Daher mein letzter Tipp, da ich den Rest des Codes nicht kenne schadet ein Hinweis sicher nicht. Man sollte sich das gleich angewöhnen um spätere, unerwartete Fehler zu vermeiden. Last but not least: Du willst Zahlen einlesen? Dann stell auch sicher dass die Eingabe eine Zahl war, man kann nicht einfach einen Wert abziehen und hoffen dass draus eine Zahl wird! So was kann in einer bösen Sicherheitslücke enden und man sollte sich von Anfang an angewöhnen Eingabefehler abzufangen, also erst prüfen ob es eine Zahl war, falls nicht muss eine Fehlermeldung ausgegeben werden und die Eingabe beginnt von vorne. Besser wäre natürlich wenn der Benutzer gar keine Zahlen erst eingeben kann... ob das bei "Read_KBD_and_Echo" weiß ich aber nicht, falls das der Fall ist ignoriere meinen Einwand. ;) So, das wars von mir... interessant dass ich noch was davon behalten habe ^^
Tobias Mehrl schrieb: > Der Algorithmus von rufus hat mir sehr weitergeholfen. Und warum hast Du es dann doch anders gemacht? Würdest Du jeweils das Ergebnis mit 10 multiplizieren, hättest Du die Chance, auch Zahlen mit weniger als 5 Stellen einlesen zu können. So aber ist die erste Ziffer immer der Zehntausenderwert.
@Tobias die Kommentare deiner Assemblerbefehle könntest du noch optimieren. einfache Regel: Kommentiere nicht WAS du machst, sondern WARUM du es machst. Schreibe einen Kommentar hinein, den du auch noch in 5 Jahren direkt verstehst, und wo du nicht grübeln mußt "warum hatte ich denn jetzt eigentlich genau diesen Befehl hier verwendet"? --> Das Ziel sollte sein: "Eine Zeile Kommentar ist wertvoller als eine Zeile Code" Beispiele: 1. MOV AX,0h ; AX auf 0 setzen MOV BX,10000 ; 10000 in BX speichern Kommetare wie die zuvor genannten sind ziemlich "unnütz". DAS die Befehle genau das machen was du daneben geschrieben hast, steht im Datenblatt des Prozessors/Assemblerbefehls. Was die Intention ist, in deinem Algorithmus genau diesen Wert zu nutzen, steht jedoch nicht im Datenblatt 2. XOR AH,AH ; Funktionsaufruf löschen DASS damit der AH auf den Wert "0" gesetzt wird ist mit ein bischen Datenblattstudium zu identifizieren (anstelle des "tricky" XOR hätte ich hier ein MOV Statement empfohlen). Aber wieso wird dadurch ein "Funktionsaufruf gelöscht"? 3. SUB AL,30h ; 1. Zeichen in 1. Zahl umrechnen uhhh, Magie greift um sich. Eine Zahl wird umgerechnet. WIESO? Kommentar-Vorschlag z.B. ASCII "0" = 0x30 ... ASCII "9" = 0x39. ACSII-Offset subtrahieren, um echte Binärzahl zu erhalten.
>Vor allem stell ich es mir schwierig vor, da ja die Zahl als Hex im >Register >vorliegt und ich soll ja bestimmt nicht die Hex-Zahl sondern die >Dezimalzahl ausgeben... Wie gesagt, ich weiß nicht wie das gehen soll... Eine reine Hex-Zahl kannst du in Decimal umwandeln wenn du fortlaufend durch 10 teilst. Die Reste pushst du in einer Schleife auf den Stack und liest sie dann, in einer zweiten schleife, wieder runter und gibst sie aus. (Aber Vorsicht, die X86-Division ist ein Befehl den du sehr gut verstehen musst.) Vor der Ausgabe musst natürlich noch auf Ascii (mit Addition) konvertieren. Du bist bestimmt Student im Info-Kurs (das ist eine der typischen Aufgaben mit Fallstricken) und ich schätze mal selbst wenn du dich reinkniest, wirst du Tage brauchen bist du die ganze Aufgabe gelöst hast. Viel Erfolg!
@ asm Guru: Also ich rechne ein Zahl von Hex in Dezimal so um: 3: 3 · 1 = 3 7: 7 · 16 = 112 1: 1 · 256 = 256 B: 11 · 4096 = 45056 —————— 45427 Wie du das meinst mit fortlaufen durch 10 teilen verstehe ich nicht. Von einer Hex-Zahl zurück auf eine Dezimalzahl komme ich doch nur mit dem oben gezeigten Schema... Das mit dem Stack mag dann einleuchten, funktioniert aber auch so lange nicht wie ich nicht die "Reste" meiner eingegebenen fünfstelligen Zahl habe!
Tobias Mehrl schrieb: > Wie du das meinst mit fortlaufen durch 10 teilen verstehe ich nicht. wie zerlegst du die Zahl 4598 in die einzelnen Ziffern? 4598 % 10 macht 8 4598 / 10 macht 459 459 % 10 macht 9 459 / 10 macht 45 45 % 10 macht 5 45 / 10 macht 4 4 % 10 macht 4 4 / 10 macht 0 -> fertig Lies die Ziffern in den Modulo (%) Zeilen von unten nach oben. Da steht 4 5 9 8 und die ursprüngliche Zahl war 4598 > Von > einer Hex-Zahl zurück auf eine Dezimalzahl komme ich doch nur mit dem > oben gezeigten Schema... Du willst das Horner Schema anwenden. Das besagt: anstatt zu rechnen (4 * 1000) + (5 * 100) + (9 * 10) + (8*1) kannst du auch rechnen (((((4) * 10) + 5) * 10) + 9) * 10 + 8 anstelle von unterschiedlichen Multiplikanden 1000, 100, 10 multiplizierst du einfach immer nur mit 10 Die Zerlegung ist dann einfach nur die Umkehrung davon
Wegstaben Verbuchsler schrieb: > Kommentiere nicht WAS du machst, sondern WARUM du es machst. Völlig richtig > --> Das Ziel sollte sein: "Eine Zeile Kommentar ist wertvoller als eine > Zeile Code" Zugegeben: In Assembler ist das verdammt schwer bis unmöglich. Aber das Ziel ist eigentlich, dass der Code sein eigener Kommentar ist. D.h. ein wirklich guter Code braucht nicht unbedingt einen Kommentar, weil alles wichtige schon im Code steht. Wie gesagt: In Assembler geht das nicht, aber in einer Hochsprache schon. zb durch die Wahl von Variablennamen und/oder Funktionsnamen kann ein Code ganz schön sprechend werden. Aber das hindert ja niemanden, auch in Assembler um zb die jeweils günstigste Zahlendarstellung zu kämpfen und sich so dem großen Ziel wenigstens ein bischen anzunähern. In diesem Sinne .... > SUB AL,30h ; 1. Zeichen in 1. Zahl umrechnen > > uhhh, Magie greift um sich. Eine Zahl wird umgerechnet. WIESO? > Kommentar-Vorschlag z.B. > > ASCII "0" = 0x30 ... ASCII "9" = 0x39. > ACSII-Offset subtrahieren, um echte Binärzahl zu erhalten. ... ist es hier die beste Lösung, auf einen Kommentar alle '0' abziehen zu verzichten, sondern gleich zu schreiben SUB AL, '0' ; aus dem Zeichen eine Zahl machen das der ASCII Code für '0' die 0x30 ist, braucht niemand zu interessieren.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.