Show pageOld revisionsBacklinksBack to top This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== Funktionsweise einer CPU ====== * Speicher: Array of Bytes, Index wird **Adresse** genannt. Hier laufen die Adressen von 0-255. * Register: Eine Art interne Variablen in der CPU. Hier A,B,C,D, Grösse 1 Byte * Instruction Pointer (IP): Gibt an, wo die nächste auszuführende Instruktion im Speicher liegt. Wird oft auch Programm Counter (PC) genannt. * Stack Pointer (SP): Zeigt auf den ersten freien Platz auf dem Stapel (wächst rückwärts). Startet bei Adresse 231. * Flags: Z (Zero, True wenn ein Ergebnis Null ist), C (Carry, True wenn ein Überlauf stattgefunden hat). F ist True, wenn ein Fehler aufgetreten ist (z.B. eine nicht existente Instruktion, Division durch Null oder ähnliches) * Memory mapped output: Die Bytes 232-255 werden als Buchstaben (entsprechend dem ASCII-Code) in der Ausgabe dargestellt. * Die Bytes 253-255 werden zusätzlich in der Siebensegmentanzeige dargestellt. Die Segmente sind von oben im Uhrzeigersinn nummeriert (Bits 0 bis 5), mit dem inneren Segment mit Nummer 6. * Simulator: https://fginfo.ksbg.ch/~ivo/assembler-simulator/ **Ausgabe auf die 7-Segment Anzeige** <code asm> MOV [253], 119 MOV [254], 124 MOV [255], 57 </code> **For-Loop** <code asm> MOV A, 10 ; loop counter MOV B, 232 ; start output address MOV C, '0' ; start letter loop: MOV [B], C ; Write letter to address pointed at by B INC B ; Increase output position INC C ; Increase letter DEC A ; Decrease loop counter JNZ loop ; last result not zero? Then jump to loop HLT </code> <WRAP todo> Produzieren Sie die Ausgabe 'abcdefghijklmnopqrstuvwx' </WRAP> **Subroutine, Parameter in Registern** <code asm> start: MOV C,232 ; Address in to C MOV B,4 ; Digit in to B CALL showDigit ; Display the digit MOV B,2 ; new digit in B INC C ; Increase address CALL showDigit HLT ; Params in registers: ; B digit to print (as a number 0-9) ; C address where to print showDigit: PUSH B ; Save B onto the stack ADD B,'0' ; Add 48 (Code of '0') MOV [C], B ; Write ASCII to address pointed by C POP B ; Restore B from the stack RET ; Return </code> Eine subroutine sollte Register nicht verändern. Braucht man trotzdem Register, sollen diese erst auf den Stack gesichert und danach wieder vom Stack in umgekehrter Reihenfolge wieder hergestellt werden. Der ''CALL''-Befehl schreibt die Rücksprung-Adresse auf den Stack, die dann vom ''RET''-Befehl wieder gelesen wird. Verfolgen Sie diese im Simulator. Es ist darum absolut notwendig, dass SP vor dem ''RET'' auf die gleiche Adresse zeigt, wie am Anfang der subroutine. D.h. es müssen gleich viele ''PUSH'' und ''POP'' Befehle ausgeführt worden sein. **Subroutine, Parameter auf dem Stack** <code asm> MOV A,42 ; set A PUSH 13 ; we want mod 13, so push it onto the stack CALL mod ; call mod INC SP ; correct Stack-Pointer (Same as POP, but ignore value) HLT ; Result now in register A ; Computes A mod X, where X is on the stack ; Result will be in A mod: PUSH B ; Save B PUSH A ; Save A DIV [SP+4] ; SP+1 is A, SP+2 is B, SP+3 is return address MUL [SP+4] MOV B,A ; B = A - A % X POP A ; restore A SUB A,B ; now A = A % X POP B ; restore B RET ; return, result in A </code> <WRAP todo> Unter Verwendung der obigen Beispiele und subroutinen, schreiben Sie ein Programm, das ein Byte dezimal in die Ausgabe schreibt. <hidden Lösungsvorschlag> <code asm> MOV A, 237 MOV C,232 CALL showByte HLT ; Byte in A ; Address in C showByte: PUSH A ; Save registers PUSH B PUSH C ADD C,2 loopA: PUSH A ; SAVE A PUSH 10 ; Push modulo op to stack CALL mod INC SP ; Correct Stackpointer MOV B,A ; digit to B CALL showDigit ; DEC C ; Adjust for next address POP A ; restore A DIV 10 JNZ loopA POP C POP B POP A RET </code> </hidden> </WRAP> **Verzweigungen (if, else)** <code asm> MOV A, 42 ; 1st value to compare MOV B, 23 ; 2nd value to compare CMP A,B ; Compare (subtraction, sets Z,C flags) JB less ; Carry flag set? then it's less JE equal ; Zero flag set, then it's equal MOV [232],'>' ; Not jumped, so it's greater JMP endif ; Jump to 'after if' less: MOV [232],'<' JMP endif equal: MOV [232],'=' endif: HLT </code> <WRAP todo> Schreiben Sie eine oder mehrere Subroutinen, die ein Byte als zweistellige Hexadezimalzahl in die Ausgabe schreibt (0-padded). Verwenden Sie dafür bitweise logische Operationen. </WRAP> **Arrays** Studieren Sie folgenden Sortier-Algorithmus: <code asm> JMP start arrayStart: DB 's' DB 'y' DB 'i' DB 'b' DB 'p' DB 'o' start: ; copy to output aerea MOV A, arrayStart MOV B, 232 copyLoop: MOV C,[A] MOV [B],C INC A INC B CMP A,start JNE copyLoop ; Write len variable, setup start address MOV A, start MOV B, arrayStart SUB A,B ADD A,232 MOV [last], A MOV A, 232 ; Start sorting loopA: MOV B,A loopB: INC B CMP B,[last] JNC nextA MOV C,[A] MOV D,[B] CMP C,D JBE loopB MOV [A],D MOV [B],C JMP loopB nextA: INC A CMP A,[last] JB loopA HLT last: DB 0 </code> **Ziffern auf 7-Segment-Anzeige** <WRAP todo> Mit Hilfe eines Arrays, schreiben Sie eine subroutine, die eine Ziffer auf der 7-Segment-Anzeige ausgibt. Zusatz: Geben Sie ein Byte auf der 7-Segmentanzeige dezimal aus. Bonus: Implementieren Sie QuickSort. <hidden Animationen auf 7-Segment-Anzeige> <code asm> ; Simple example ; Writes Hello World to the output start: MOV B, dataStart loop: MOV A, 253 MOV C, [B] MOV [A], C MOV C, [B+1] MOV [A+1], C MOV C, [B+2] MOV [A+2], C ADD B, 3 CMP B, dataEnd JNZ loop JMP start dataStart: DB 8 DB 8 DB 8 DB 0 DB 8 DB 12 DB 0 DB 0 DB 14 DB 0 DB 0 DB 7 DB 0 DB 1 DB 3 DB 1 DB 1 DB 1 DB 33 DB 1 DB 0 DB 49 DB 0 DB 0 DB 56 DB 0 DB 0 DB 24 DB 8 DB 0 dataEnd: </code> </hidden> <hidden Animation mit Bytes in Strings codier (unnötig hackisch)> <code asm> start: MOV B, dataStart loop: MOV C, [B] MOV A, [B+6] MOV [253], C MOV [254], A MOV [255], C INC B CMP B, dataEnd JNZ loop JMP start dataStart: DB "!0␌" dataEnd: DB "!␌0" </code> </hidden> <hidden Quicksort-Implementation> <code asm> JMP start arrayStart: DB 4 DB 2 DB 7 DB 9 DB 8 DB 7 DB 4 DB 5 DB 8 DB 9 DB 4 DB 3 DB 6 DB 1 start: MOV A, arrayStart MOV B, start DEC B call quicksort HLT quicksort: ;first elements address in A ;last elements address in B PUSH D PUSH C PUSH B PUSH A MOV C,B SUB C,A JBE ende ; bail if B-A <= 0 MOV [a0], A ; save bounds MOV [b0], B MOV C, [A] ; Pivot value INC A leftloop: ; while C>=[A]: A++ CMP C,[A] JC rightloop ; break if C<[A] INC A CMP A,B JBE leftloop ; repeat if A<=B rightloop: ; while C<=[B]; B-- CMP C,[B] JA swapping ; break if C>[B] DEC B CMP A,B JB rightloop ; repeat if A<B swapping: ; Swaps [A] and [B], if A<B CMP A,B JAE setpivot MOV D, [A] PUSH D MOV D, [B] MOV [A], D POP D MOV [B], D INC A DEC B JMP leftloop setpivot: CMP A,[b0] JBE ok MOV A,[b0] INC A ok: ; swap pivot and [A] DEC A MOV [p0], A ; index of pivot MOV D,[A] MOV [A], C MOV C,[a0] MOV [C], D ;recursion MOV A, [a0] MOV B, [p0] DEC B PUSH [p0] ; save p0 and b0 PUSH [b0] call quicksort POP B ; restore p0 and b0 POP A INC A call quicksort ende: POP A POP B POP C POP C RET a0: DB 0 b0: DB 0 p0: DB 0 </code> </hidden> </WRAP> ===== Hackme ===== * Studieren Sie den Code. * Ändern Sie den String in der DB Zeile, so, dass ''L O L'' in der 7-Segment Anzeige ausgegeben wird. (Das Programm sonst darf nicht verändert werden!) <code asm> ; Dieses Programm gibt den String rechtsbündig ab ; Adresse 250 aus. ; JMP start DB "hello world" ; ; Register ; A Ausgabe-Adresse ; B Position in DB ; C temporär start: MOV A,250 ; Adresse Ausgabe (letzter Buchstabe) MOV B, start ; Adresse+1 vom letzten Buchstaben DEC B ; B vermindern CALL ausgabe HLT ausgabe: MOV C,[B] ; Buchstabe in C MOV [A],C ; Ausgabe DEC A ; A vermindern DEC B ; B vermindern CMP B,1 ; ist B am Anfang angekommen? JNE ausgabe ; sonst wiederholen RET </code> <hidden Hinweise> Welcher für die Programmausführung wichtiger Bereich wird bei zu langem String überschrieben? <hidden weitere Hinweise> Finden Sie eine Eingabe so, dass die Rücksprungadresse manipuliert wird (z.B. Rücksprung auf start). <hidden noch mehr Hinweise> Platzieren Sie den gewünschten Assemblercode im String und setzen Sie die Rücksprungadresse darauf. <hidden Ausgabe vom Assemblercode als String> <code asm> lol: MOV [253], 0111000b MOV [254], 0111111b MOV [255], 0111000b fertig: mov A, fertig dec A mov B, 246 loop: mov C, [A] mov [B], C dec B dec A JNC loop hlt </code> <hidden mögliche Lösungen> Mit Rücksprung direkt in die DB-Konstante (Adresse 0x02) <code asm> DB "ý8þ?ÿ8+ Hello World!" </code> Oder mit Rücksprung in die kopierten Daten an der Adresse 0xdc (was realistischer ist, wenn der String eine Eingabe sein soll): <code asm> DB "ý8þ?ÿ8+Ü Hello World!" </code> </hidden> </hidden> </hidden> </hidden> </hidden> ===== Mögliche Prüfungsfragen ===== Die Ausgabe auf die drei 7-Segment Anzeigen erfolgt auf die Adressen 253 bis 255. Die Bits auf der Anzeige sind wie folgt nummeriert: <code txt> +--0--+ 5 1 :--6--: 4 2 +--3--+ </code> lehrkraefte/blc/informatik/efi-2023/assembler.txt Last modified: 2024/04/23 15:04by Ivo Blöchliger