lehrkraefte:blc:informatik:efi-2023:assembler

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.

Ausgabe auf die 7-Segment Anzeige

	MOV [253], 119
	MOV [254], 124
	MOV [255], 57

For-Loop

	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

Produzieren Sie die Ausgabe 'abcdefghijklmnopqrstuvwx'

Subroutine, Parameter in Registern

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

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

	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

Unter Verwendung der obigen Beispiele und subroutinen, schreiben Sie ein Programm, das ein Byte dezimal in die Ausgabe schreibt.

Lösungsvorschlag

Lösungsvorschlag

	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

Verzweigungen (if, else)

	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

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.

Arrays Studieren Sie folgenden Sortier-Algorithmus:

	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

Ziffern auf 7-Segment-Anzeige

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.

Animationen auf 7-Segment-Anzeige

Animationen auf 7-Segment-Anzeige

; 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:

Animation mit Bytes in Strings codier (unnötig hackisch)

Animation mit Bytes in Strings codier (unnötig hackisch)

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"

Quicksort-Implementation

Quicksort-Implementation

	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
  • 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!)
; 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

Hinweise

Hinweise

Welcher für die Programmausführung wichtiger Bereich wird bei zu langem String überschrieben?

weitere Hinweise

weitere Hinweise

Finden Sie eine Eingabe so, dass die Rücksprungadresse manipuliert wird (z.B. Rücksprung auf start).

noch mehr Hinweise

noch mehr Hinweise

Platzieren Sie den gewünschten Assemblercode im String und setzen Sie die Rücksprungadresse darauf.

Ausgabe vom Assemblercode als String

Ausgabe vom Assemblercode als String

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

mögliche Lösungen

mögliche Lösungen

Mit Rücksprung direkt in die DB-Konstante (Adresse 0x02)

DB "ý8þ?ÿ8+       Hello World!"

Oder mit Rücksprung in die kopierten Daten an der Adresse 0xdc (was realistischer ist, wenn der String eine Eingabe sein soll):

DB "ý8þ?ÿ8+Ü       Hello World!"

Die Ausgabe auf die drei 7-Segment Anzeigen erfolgt auf die Adressen 253 bis 255.

Die Bits auf der Anzeige sind wie folgt nummeriert:

+--0--+
5     1
:--6--:
4     2
+--3--+
  • lehrkraefte/blc/informatik/efi-2023/assembler.txt
  • Last modified: 2024/04/23 15:04
  • by Ivo Blöchliger