Upline: Infos & Dokus Elektronik

Zilog Z8 - Assembler Rechteckberechnung


Das folgende ist ein Laborprotokoll (1. Labor, Getting Started with Zilog) vom WS2005 des Fachs Microcomputertechnik an der FHTW Berlin, durchgeführt von Prof. Jossifov in den Studienfächern Technische Informatik und Informationstechnik Vernetzte Systeme. Da der Prof so einige Formulierungen bemängelte (nach seiner Meinung uneindeutig) und schon für kleinste Fehler einen Haufen Punkte abzog, gab es darauf nur eine 2.7 - ich habe aber zumind. das meiste beanstandete für diese Onlineversion noch mal überarbeitet. Was jetzt noch fehlen würde, sind einige weitere erklärende Screenshots.

Aufgabenstellung

Task 1

Aufgabe 1: Welche Befehle des Programms aus Task 1 nutzen Register Addressing Mode?
Aufgabe 2: Welche Adressierungsart verwendet der Z8-Befehl DJNZ? Welcher andere Steuerungsbefehl nutzt die selbe Adressierungsart?

Task 2

Aufgabe 1: Welchen Unterschied gibt es zwischen den Variablendefinitionen in den Programmen aus Task 1 und Task 2? Welcher Speicher wird im 1. und welcher im 2. Fall benutzt?
Aufgabe 2: Warum steht der folgende Sourcecodeauszug am Ende der Hauptfunktion?
COUNT db 09H; constant defined ...
Kann die Zeile auch hinter der Initialisierung org %000C stehen? Warum?
Aufgabe 3: Was passiert auf dem Stack und mit dem Stackpointer bei Ausführung des RET-Befehls?
Aufgabe 4: Was ist der Unterschied im Debugger zwischen "Spep over" und "Step into"?

Task 3

Aufgabe 1: Gibt es Befehle in Task 2 oder 3, die den Direct Addressing Mode nutzen?
Aufgabe 2: Welches sind die einzigen Z8-Befehle, die den Direct Addressing Mode nutzen?

Task 4

Programm schreiben, welches 2 Arrays addiert ...

Task 1

Zwischenergebnisse der Programmausführung

1. Durchlauf:
@Addr17h: r8=#00h, r9=#1Eh, flgs=40h (ZF)
@Addr 19h r9=#0Fh, flgs=00h
@Addr 1Bh: r5=8
2. Durchlauf:
r8=#00h, flgs=40h
r9=#07h, flgs=80h => r8=#0Fh, flgs=00h, r5=7
3. Durchlauf:
r8=#07h, flgs=80h (CF)
r9=#83h, flgs=B0h => r8=#16h, flgs=04h, r5=6
4. Durchlauf:
r8=#0Bh, flgs=04h (HCF)
r9=#41h, flgs=94h => r8=#1Ah, flgs=04h, r5=5
5. Durchlauf:
r8=#0Dh
r9=#20h, flgs=84h => r8=#1Ch, flgs=04h, r5=4
6. Durchlauf:
r8=#0Eh, flgs=04h
r9=#10h, flgs=04h, r5=3
7. Durchlauf:
r8=#07h
r9=#08h, r5=2
8. Durchlauf:
r8=#03h, flgs=84h
r9=#84h, flgs=34h, r5=1
9. Durchlauf:
r8=#01h, flgs=84h
r9=#C2h, flgs=24h, r5=0 -> Schleifenende
Damit steht das Ergebnis der Multiplikation von 15*30=450 in den Registern r9:r8.

Questions

  1. Alle ld-Befehle, bei denen sowohl Quelle als auch Ziel Register sind, gehören zu den Registeradressierungen, ebenso rrc, add und inc. Bsp.: ld result_lb, width
  2. Die beiden Sprungbefehle djnz und jr nutzen die relative Adressierung.
In der folgenden Abbildung ist das Ergbnis C201h im Debugfenster rechts oben sichtbar.

Task 2

Questions

  1. Im Task 1 werden die Daten in den Registern r5 bis r9 gespeichert. Daher ist der Zugriff mit den Arbeitsregistern möglich. In Task 2 werden die Daten im Register ab Adresse 20h gespeichert. Die Variablen side_a_hi usw. werden als 1 Byte deklariert. Hierbei ist der Zugriff nicht direkt über die Arbeitsregister möglich. Statt dessen erfolgt der Zugriff auf die Variableninhalte über die Adresse.
    Bsp.:
    ld r1, # SIDE_A_HI
    ld r2, @r1
  2. Es handelt sich im 1. und 2. Fall im Sourcecode um auskommentierte, also nicht aktive Konstantendeklarationen. Würde man das Kommentarzeichen entfernen, so würde der Wert 09h an entsprechender Stelle im Code auftauchen und der Prozessor würde versuchen diesen auszuwerten und auszuführen. Mit sehr großer Wahrscheinlichkeit endet das in einem undefinierten Zustand oder Absturz des Systems. Wegen der besseren Übersicht ist es empfehlenswert, Konstanten im Kopfbereich oder Fußbereich eines Programms bzw. einer Funktion zu definieren. Auf jeden Fall muß dafür gesorgt werden, daß diese Konstanten nicht ausgeführt werden, z.B. durch entsprechende Sprungbefehle. Die Position hinter dem Ende des Programms ist daher für die Konstantendefinition ideal. Alternativ kann man bei einer sauberen Trennung in Code- und Datenbereich über entsprechende Segmente die Grundlage dafür schaffen, dass der Compiler selbständig dafür sorgt, dass die Konstanten nicht als Code interpretiert und ausgeführt werden können. Aus diesen Ausführungen sollte klar werden, dass die nicht auskommentierte Deklaration hinter dem ret von "MultiplyHeight" ungefährlich ist, da die Konstante nicht angesprungen werden kann.
  3. Der ret-Befehl dient dem Rücksprung aus einer Funktion. Hierzu wird vom Stack die entsprechende Adresse geholt, die zuvor durch einen jmp-Befehl oder int-Aufruf dort abgelegt wurde. So der Stack nicht nachträglich geändert wurde, so liegt der nächste Befehl nach dem Sprungbefehl dort. Vergißt man, in der Funktion gepushte Werte wieder zu popen oder popt man mehr, als gepusht wurde, so kann der Prozessor die Rücksprungadresse nicht mehr finden und springt jenachdem, was er auf dem Stack vorfindet an eine zumeist nicht definierte Adresse. Diese Eigenschaft wird im Computerbereich oft von Viren und Würmern ausgenutzt, um gezielt unerwünschten Code anzuspringen und diesen an Stelle des Originals auszuführen.
  4. Beim Step-into wird jeder Befehl einzeln verarbeitet und die Ergebnisse sind z.B. im Debugger ersichtlich. Im Gegensatz dazu dient der Step-Over-Modus dazu, die Ansicht kompletter Codebereiche (Schleifen, Unterprogramme etc.) zu überspringen, diese werden also am Stück ausgeführt. Dies kann gerade beim Debuggen von Quelltexten mit vielen langwierigen Schleifendurchläufen sinnvoll sein.

Sourcecode

;########################################################################################
;#											#
;#	Exercise:									#
;#	Microcontroller Laboratory Exercise with ZILOG DEVELOPER STUDIO 3.68 and Z8	#
;#	Simulator						        		#
;#											#
;#	Task:										#
;# 	The program calculates the area of a trapezium.					#
;#	Write a function (MultiplyIntegers)that multiplies two integers: 16-bit 	#
;#	unsigned word and an 8-bit unsigned byte.					#
;#	The multiplication algorithm is the same as the one given in the		#
;#	"addressingmodes_rectangle.asm", but the counter should be loaded using 	#
;#	indirect register addressing. The addition and division are performed in 	#
;#	the main function, and the multiplication is performed by calling the 		#
;#	"MultiplyIntegers" function.							#
;#	The lengths of the trapezium are given as 16-bit unsigned words.		#
;#	The height is given as unsigned 8-Bit integer.					#
;#	The area of the trapezium is calculated with the formula ((a+c)/2)*h.		#
;#	When carry is generated from the division by two, the result is rounded		#
;#	(incremented by 1). The statement jr NC,MultiplyHeight checks for a carry.	#
;#	If no round is needed the division result is multiplied by the height.		#
;#	The 16-bit result (the area of trapezium) is stored in SIDE_A.			#
;#											#
;#	Note:										#
;#	The Carry Flag is found in the Z8 Flag Register (address FCH)			#
;########################################################################################
define	regfile, org=20H, space=RFILE

;*** RAM memory address allocations - variables ***
segment	regfile
SIDE_A_HI:	ds	%1	;high-byte of the trapezium's side A
SIDE_A_LO:	ds	%1	;low-byte of the trapezium's side A
SIDE_C_HI:	ds	%1	;high-byte of the trapezium's side C
SIDE_C_LO:	ds	%1	;low-byte of the trapezium's side C
HEIGHT:		ds	%1	;trapezium's height

;*** RAM memory address allocations - symbolic address constant****
COUNTER:	.equ	r15	;counter used for the multiplication iterations

;**** These are the working register file settings ****
STACK:		.equ	%3F	;Work. Register Group 3, Work. Register F
WORKREGS:	.equ	%10	;ERF Bank 0, Work. Reg.Group 1
segment	code

init:
 org		%000C
 ;COUNT:	db	09H
 srp		#WORKREGS	;select a Working Reg. Group for access
 ld		SPL,#STACK	;load the Stack Pointer Low Byte (SPL = control
				;register at address FF)
;load the variables with values
 ld	SIDE_A_HI,#0H		;load SIDE_A high-byte with value
 ld	SIDE_A_LO,#06H		;load SIDE_A low-byte with value
 ld	SIDE_C_HI,#0H		;load SIDE_C high-byte with value
 ld	SIDE_C_LO,#05H		;load SIDE_C low-byte with value
 ld 	HEIGHT,#04H
 ;COUNT:	db	09H

AdditionLow:
 add 	SIDE_A_LO,SIDE_C_LO	;add the low bytes of side A and side C
 jr 	NC,AdditionHigh		;check for overflow
 inc	SIDE_A_HI		;overflow occurs, so increment the High Byte
 jr	NC,AdditionHigh
 ret				;END if overflow occurs again

AdditionHigh:
 add	SIDE_A_HI,SIDE_C_HI	;add the high bytes of side A and side C
 jr	NC,Division		;if the number is larger than WORD (SIDE_A > 65535)
 ret				;then Carry Flag = 1; END of program
		
Division:
 rrc	SIDE_A_HI		;Rotate Right Through Carry Flag
 rrc 	SIDE_A_LO		;Rotate Right Through Carry Flag (equal to DIV 2)
 jr	NC,MultiplyHeight	;result is muled by HEIGHT if no carry is generated
				;from the division
 rcf				;Reset Carry Flag
 inc	SIDE_A_LO		;round the result(inc by 1) if carry is generated
				;from the division
 jr	NC,MultiplyHeight	;no carry (SIDE_A_LO is <255 ), so multiply
 rcf				;Reset Carry Flag
 inc	SIDE_A_HI		;increment high byte
 jr	NC,MultiplyHeight	;no carry, so multiply
 ret				;carry = 1, so END of program

MultiplyHeight:
 ld	r2, SIDE_A_HI		;load working reg. r2 with the high byte of SIDE_A
 ld	r3, SIDE_A_LO		;load working register r3 with the low byte of SIDE_A
 ld	r4, HEIGHT		;load working register r4 with HEIGHT
 call	MultiplyIntegers	;call function MultiplyIntegers
 ld	SIDE_A_HI, r2		;load the returned calculated result in SIDE_A
 ld 	SIDE_A_LO, r3
 ret				;END of program execution

COUNT:	db	09H		;constant defined in the program memory (ROM
				;used for the mul-iterations -> 8 bits + 1 = 9
MultiplyIntegers:
 ld	r0, #high COUNT		;loads R0 with high-byte of the address of COUNT
 ld	r1, #low COUNT		;loads R0 with low-byte of the address of COUNT
 lde	COUNTER,@RR0		;ld COUNTER cont of addr[RO,R1] (ind.reg.addressing)
	 			;perform the multiplication
 rcf 				;Reset Carry Flag (CF = 0)

Loop:
 rrc 	R2
 rrc 	R3
 jr	NC,NextIter
 add 	R2,R4

NextIter: 
 djnz	COUNTER,Loop		;Decrement COUNTER (COUNTER = COUNTER - 1) and
				;Jump to Loop if COUNTER is Not Zero (COUNTER <>0)
 ret				;end of function

Task 3

Questions

  1. Lediglich die Befehle call und jp nutzen die direkte Adressierung.
  2. Den call-Befehl findet man auch in Task 2/3.

Sourcecode

;########################################################################################
;#											#
;#	Exercise:									#
;#	Microcontroller Laboratory Exercise with ZILOG DEVELOPER STUDIO 3.68 and Z8	#
;#	Simulator					        			#
;#											#
;#	Task:										#
;# 	Write a program that calculates the area of a trapezium.			#
;#	Implement the function "MultiplyIntegers" using indirect register addressing	#
;#	It multiplies two integers: 16-bit unsigned word and an 8-bit unsigned byte	#
;#	The addition and division are performed in the main function, and the 		#
;#	multiplication is performed by calling the "MultiplyIntegers" function.		#
;#	The lengths of the trapezium are given as 16-bit unsigned words.		#
;#	The height is given as unsigned 8-Bit integer.					#
;#	The area of the trapezium is calculated with the formula ((a+c)/2)*h.		#
;#	When carry is generated from the division by two, the result is rounded		#
;#	(incremented by 1). The statement jr NC,MultiplyHeight checks for a carry.	#
;#	If no round is needed the division result is multiplied by the height.		#
;#	The 16-bit result (the area of trapezium) is stored in SIDE_A.			#
;#											#
;#	Note:										#
;#	The Carry Flag is found in the the Z8 Flag Register (address FCH)		#
;########################################################################################
define	regfile, org=20H ,space=RFILE

;*** RAM memory address allocations - variables ***
segment	regfile
SIDE_A:		ds	%2	;trapezium's 16-bit side A
SIDE_C:		ds	%2	;trapezium's 16-bit side C
HEIGHT:		ds	%1	;trapezium's height

;*** RAM memory address allocations - symbolic address constant****
COUNTER:	.equ	r15	;counter used for the multiplication iterations

;**** These are the working register file settings ****
STACK:		.equ	%3F	;Work. Register Group 3, Work. Register F
WORKREGS:	.equ	%10	;ERF Bank 0, Work. Reg.Group 1

segment	code
init:
 org	%000C
 srp	#WORKREGS		;select a Working Reg. Group for access
 ld	SPL,#STACK		;load the Stack Pointer Low Byte
				;(SPL = control register at address FF)
;perform the initialization
 ld	SIDE_A_HI,#0H		;load SIDE_A high-byte with value
 ld	SIDE_A_LO,#06H		;load SIDE_A low-byte with value
 ld	SIDE_C_HI,#0H		;load SIDE_C high-byte with value
 ld	SIDE_C_LO,#05H		;load SIDE_C low-byte with value
 ld 	HEIGHT,#04H

;perform the addition
AdditionLow:	
 add 	SIDE_A_LO,SIDE_C_LO	;add the low bytes of side A and side C
 jr 	NC,AdditionHigh		;check for overflow
 inc	SIDE_A_HI		;overflow occurs, so increment the High Byte
 jr	NC,AdditionHigh
 ret				;END if overflow occurs again

AdditionHigh:
 add	SIDE_A_HI,SIDE_C_HI	;add the high bytes of side A and side C
 jr	NC,Division		;if the number is larger than WORD (SIDE_A > 65535)
 ret				;then Carry Flag = 1; END of program

;perform the division
Division:
 rrc	SIDE_A_HI		;Rotate Right Through Carry Flag
 rrc 	SIDE_A_LO		;Rotate Right Through Carry Flag (equal to DIV 2)
 jr	NC,MultiplyHeight	;the result is multiplied by HEIGHT if no carry is
				;generated from the division
 rcf				;Reset Carry Flag
 inc	SIDE_A_LO		;round the result(inc 1) if carry is from division
 jr	NC,MultiplyHeight	;no carry (SIDE_A_LO is <255 ), so multiply
 rcf				;Reset Carry Flag
 inc	SIDE_A_HI		;increment high byte
 jr	NC,MultiplyHeight	;no carry, so multiply
 ret				;carry = 1, so END of program

MultiplyHeight:
 ld	r5,# SIDE_A		;load r5 (input parameter) with the address of SIDE_A
 ld	r4,HEIGHT		;load r4 (input parameter) with HEIGHT
 call	MultiplyIntegers	;call function MultiplyIntegers
 ret				;end of program
 COUNT:	db	09H		;constant defined in the program memory (ROM);
				;used for the mul-iterations -> 8 bits + 1 = 9

;*******************************************************************
;* This function multiplies an 16-bit unsigned word and an 8-bit unsigned byte.
;* The result is returned in the memory address [r5].
;* 
;* Input parameters:
;*		r4 - 8-bit multiplicand (multiplicand is passed by value)
;*		r5 - address of the 16-bit multiplier (multiplier is passed by address)
;* Returns: 
;*		- the calculated result is stored in the memory address that is referenced by r5, i.e.
;* 		Indirect Register addressing mode is used to store the result
;*******************************************************************
MultiplyIntegers:
 ld	r0, #high COUNT		;loads R0 with the HB of address from COUNT
 ld	r1, #low COUNT		;loads R0 with the LB of address from COUNT
 lde	COUNTER,@RR0		;load COUNTER with the content of address [RO,R1]
				;(indirect register addressing)
 ld	r6,r5			;r6 = adresse of HB from 16-bit-number
 inc	r6			;gets adress of the LB from the 16-bit-number
 rcf 				;Reset Carry Flag (CF = 0)

 Loop:
  rrc 	@r5
  rrc 	@r6
  jr	NC,NextIter
  ld	r7,@r5			;the z8 needs for add-destination a register
  add 	r7,r4			;this causes in the use of a temp-varible (r7)
  ld	@r5,r7			;and back to @r5
  djnz 	COUNTER,Loop		;Decrement COUNTER (COUNTER = COUNTER - 1) and
				;Jump to Loop if COUNTER is Not Zero (COUNTER <>0)
 ret				;end of function

Task 4

Sourcecode

define	regfile, org=20H ,space=RFILE  
segment	regfile 
;*** Array  ***
array:	db	%5, 4, 3, 2, 1, 11, 12, 13, 14, 15 
;*** temporary variables - RAM memory address allocations ****
COUNTER:	.equ	r15	;counter used for the multiplication iterations
OFFSET:		.equ	r14	;adress:=segmentsize*segmentnumber+offset
;**** These are the working register file settings ****
WORKREGS:	.equ	%10	;ERF Bank 0, Work. Reg.Group 1

segment	code
init:
 org	%000C
 srp	#WORKREGS		;select a Working Reg. Group for access
 ld	OFFSET,#0H		;offset is 0
 ld	COUNTER,#05H		;wanna have 5 additions
Loop:
 ld	r3,20H(r14)		;load the 1./2./3./4./5. value from array into r3
 ld	r4,25H(r14)		;load the 6./7./8./9./10. value from array into r4
 add	r3,r4			;add both values -> result is in r3
 ld	20H(r14),r3		;store result r3 into 1./2./3./4./5. field of array
 inc	OFFSET			;set offset to next arrayfield
 djnz 	COUNTER,Loop		;while COUNTER <> 0 do loop
ret				;end of program