[ บทความ : เรียนรู้ z80 ] ตอนที่ 5 เรื่อง เรียนรู้คำสั่งของ Z80

รู้จักคำสั่งของ Z80

ตอน คำสั่ง LD

หลังจากหายหน้าหายตาไปนานกับ บทความเกี่ยวกับ Z80 กลับมาคราวนี้เรามาเริ่มกันที่เรื่อง คำสั่ง LD กันเลยครับ ... LD เป็นคำสั่งที่ทำหน้าที่โอนค่าจากที่หนึ่งไปเก็บเอาไว้ ณ อีกที่หนึ่ง รูปแบบหลักๆ ของ LD เป็นดังนี้
        LD   ปลายทาง,ต้นทาง
        LD   (ปลายทาง), ต้นทาง
        LD  ปลายทาง, (ต้นทาง)
นั่นหมายความว่า เมื่อเราเขียนเป็นสัญลักษณ์แทนการทำงาน ก็จะได้เป็นดังนี้
	ปลายทาง <-  ต้นทาง
	(ปลายทาง) <- ต้นทาง
	ปลายทาง <- (ต้นทาง)
หมายเหตุ
ปลายทาง มักเป็นรีจิสเตอร์
ต้นทาง จะเป็นได้ทั้ง รีจิสเตอร์ และ ค่าคงที่ (ตัวเลข ที่เรากำหนด)
(ปลายทาง) หมายความว่า เราจะเอาค่าไปเก็บ ณ หน่วยความจำ
(ต้นทาง) หมายความว่า ข้อมูลที่เราต้องการนั้น อยู่ ในหน่วยความจำ

ตัวอย่าง 1 :

        LD      A, 15
หมายความว่า A <- 15 หรือ นำค่า 15 ไปเก็บในรีจิสเตอร์ A

ตัวอย่าง 2 :

        LD      C,B
หมายความว่า C <- B หรือ นำค่าที่เก็บอยู่ในรีจิสเตอร์ B มาเก้บในรีจิสเตอร์ C

ตัวอย่าง 3:

        LD      A,(1FFFh)
หมายความว่า A <- (1FFFh) หรือ นำค่าที่เก้บเอาไว้ในหน่วยความจำ ณ ตำแหน่ง 1FFFh (h = เป็นการบอกว่าเป็นค่าแบบ ฐานสิบหก) มาเก็บไว้ใน รีจิสเตอร์ A

ตัวอย่าง 4:

        LD    (2FF1h),A
หมาายความว่า (2FF1h) <- A หรือ นำค่าที่เก้บเอาไว้ในรีจิสเตอร์ A มาเก็บไว้ ณ หน่วยความจำตำแหน่ง 2FF1h

ตัวอย่าง 5:

        LD   (IX+5),A
หมายความว่า (IX+5) <- A หรือ นำค่าที่เก้บเอาไว้ในรีจิสเตอร์ A ไปเก็บไว้ในหน่วยความจำ ณ ตำแหน่งที่ IX + 5 เช่น IX เก็บค่า 1FF0h นั่นหมายความว่า ตำแหน่งหน่วยความจำที่จะได้ ก็จะเป็น 1FF0h+5 = 1FF5h นั่นเอง

คราวนี้เรามาดูรูปแบบการเขียนกันดีกว่าครับ

กลุ่ม LD ที่ทำงานกับข้อมูลขนาด 8 บิต

กลุ่ม LD ที่ทำงานกับข้อมูลขนาด 16 บิต

หมายเหตุ

r,r' คือ รีจิสเตอร์ตัวใดก็ได้ดังต่อไปนี้ A, B, C, D, E, H และ L.
p,p' คือ รีจิสเตอร์ตัวใดก็ได้ดังต่อไปนี้ A, B, C, D, E, IX(Hi-Byte) และ IX (Lo-Byte)
q,q' คือ รีจิสเตอร์ตัวใดก็ได้ดังต่อไปนี้ A, B, C, D, E, IY(Hi-Byte) และ IY (Lo-Byte)
dd คือ pair register อันได้แก่ BC,DE,HL และ SP
qq คือ pair register ดังต่อไปนี้ BC, DE, HL และ AF
d คือ ค่าตัวเลขขนาด 16 บิต
n คือ ค่าตัวเลขขนาด 8 บิต
nn คือ ค่าตัวเลขขนาด 16 บิต

Flag note 1

S,Z,F5,F3 flag is set according to the result of the operation (เปลี่ยนแปลงตามผลของการทำงาน)
H,C flag = 0
P/V flag -> The interrupt flip-flop 2 is copied

โปรแกรมตัวอย่างของเราจะเป็นดังนี้ครับ ...

	
	;
	; Filename : LDex.asz
	; Author	 : Supachai Budsaratij   (raek@se-ed.net)
	; Date  : Dec 5, 2000
	; Hardware : ET-Board V6 (Z80 Mode)
	;
	;
	        INCL "etv6.inz"         ; Inlude header for ET-V6
	
	DD      EQU     0AH
	EE      EQU     20H
	NN      EQU     0A000H
	N       EQU     0AH
	
	                ORG        UMEM_ORG        ; Start at UMEM_ORG	
	main
	; --- My code here
	        LD      A, 0A0h
	        LD      B, 0ACh
	        LD      C, A
	        LD      (BC), A
	        LD      (HL), B
	        LD      (IX + DD), C
	        LD      (IX + DD), N
	        LD      (IY + DD), B
	        LD      (IY + DD), N
	        LD      (NN), A
	        LD      (NN), BC
	        LD      A, (BC)
	        LD      A, (IX + DD)
	        LD      A, (IY + DD)
	        LD      A, (NN)
	        LD      A, A
	        LD      IX, (NN)
	        LD      IX, NN
	        LD      IY, (NN)
	        LD      IY, NN
	; ---End of program
		HALT

		END

หลังจากนั้นก็ทำการแปลด้วยคำสั่งต่อไปนี้ครับ

        az80   LDex.asz  -l  LDex.lst  -o  LDex.hex

เมื่อเราคอมไพล์โปรแกรมเสร็จเราก็จะได้ไฟล์มาอีก 2 ไฟล์ คือ .HEX สำหรับ Load เข้า บอร์ด กับ .LST สำหรับบอกรายละเอียดทั้งหมด ... ตัวอย่างของไฟล์ .LST เป็นดังนี้ครับ


	                        ;
	                        ; Filename : LDex.asz
	                        ; Author	 : Supachai Budsaratij   (raek@se-ed.net)
	                        ; Date  : Dec 5, 2000
	                        ; Hardware : ET-Board V6 (Z80 Mode)
	                        ;
	                        ;
	                                INCL    "etv6.inz"         ; Inlude header for ET-V6
	                        ;
	                        ; filename  : etv6.inz
	                        ; assembler : az80
	                        ; author    : Supachai Budsaratij (raek@se-ed.net)
	                        ; hardware  : et-board 6 (Z-80 mode)
	                        ; date      : October 12,2000
	                        ;
                        
	                        ; --- MEMORY
	                        ;
 	  8000                 UMEM_ORG        EQU     08000h   ; User RAM start
	   bdff                 UMEM_END        EQU     0BDFFh   ; User RAM end
	   c000                 XMEM_ORG        EQU     0C000h   ; Expand RAM end
	   dfff                 XMEM_END        EQU     0DFFFh   ; Expand RAM end
	                        
	                        ; --- I/O
	                        ;
	   0000                 S8255_PA        EQU     00h     ; System 8255 port A
	   0001                 S8255_PB        EQU     01h     ; System 8255 port B
	   0002                 S8255_PC        EQU     02h     ; System 8255 port C
	   0003                 S8255_CT        EQU     03h     ; System 8255 control port
	                        ;
	   0020                 U8255_PA        EQU     20h     ; User 8255 port A
	   0021                 U8255_PB        EQU     21h     ; User 8255 port B
	   0022                 U8255_PC        EQU     22h     ; User 8255 port C
	   0023                 U8255_CT        EQU     23h     ; User 8255 control port
	                        ;
	   004d                 SCN_INP         EQU     4Dh     ; SCN2681 - Input port (Switch)
	   004e                 SCN_SEO         EQU     4Eh     ; SCN2681 - Set output port (LED)
	   004f                 SCN_REO         EQU     4Fh     ; SCN2681 - Reset output port (LED)
	                        ;
	   0060                 CLCD_WC         EQU     60h     ; Character LCD write command
	   0061                 CLCD_RC         EQU     61h     ; Character LCD read command
	   0062                 CLCD_WD         EQU     62h     ; Character LCD write data
	   0063                 CLCD_RD         EQU     63h     ; Character LCD read data
	                        ;
	   0064                 GLCD_WC1        EQU     64h     ; Graphics LCD write command (Page 1)
	   0065                 GLCD_RC1        EQU     65h     ; Graphics LCD read command  (Page 1)
	   0066                 GLCD_WD1        EQU     66h     ; Graphics LCD write data    (Page 1)
	   0067                 GLCD_RD1        EQU     67h     ; Graphics LCD read data     (Page 1)
	                        ;
	   0068                 GLCD_WC2        EQU     68h     ; Graphics LCD write command (Page 2)
	   0069                 GLCD_RC2        EQU     69h     ; Graphics LCD read command  (Page 2)
	   006a                 GLCD_WD2        EQU     6Ah     ; Graphics LCD write data    (Page 2)
	   006b                 GLCD_RD2        EQU     6Bh     ; Graphics LCD read data     (Page 2)
	                        ;
                        
                        
	   000a                 DD      EQU     0AH
	   0020                 EE      EQU     20H
	   a000                 NN      EQU     0A000H
	   000a                 N       EQU     0AH
                        
	   8000                         ORG     UMEM_ORG        ; Start at UMEM_ORG
                        
	   8000                 main
	                        ; --- My code here
	   8000   3e a0                 LD      A, 0A0h
	   8002   06 ac                 LD      B, 0ACh
	   8004   4f                    LD      C, A
	   8005   02                    LD      (BC), A
	   8006   70                    LD      (HL), B
	   8007   dd 71 0a              LD      (IX + DD), C
	   800a   dd 36 0a 0a           LD      (IX + DD), N
	   800e   fd 70 0a              LD      (IY + DD), B
	   8011   fd 36 0a 0a           LD      (IY + DD), N
	   8015   32 00 a0              LD      (NN), A
	   8018   ed 43 00 a0           LD      (NN), BC
	   801c   0a                    LD      A, (BC)
	   801d   dd 7e 0a              LD      A, (IX + DD)
	   8020   fd 7e 0a              LD      A, (IY + DD)
	   8023   3a 00 a0              LD      A, (NN)
	   8026   7f                    LD      A, A
	   8027   dd 2a 00 a0           LD      IX, (NN)
	   802b   dd 21 00 a0           LD      IX, NN
	   802f   fd 2a 00 a0           LD      IY, (NN)
	   8033   fd 21 00 a0           LD      IY, NN
	                        ; ---End of program
	   8037   76                    HALT
                        
	   8038                 	END


เอาล่ะ เราจะมา debug โปรแกรมกันครับ ... เริ่มต้นจากการโหลดโปรแกรมเข้าบอร์ด ดังรูปต่อไปนี้เลยครับ

... เริ่ม trace ล่ะนะ ... พิมพ์คำสั่งว่า T 8000 แล้วกด enter แล้วจะมีการแสดงผลดังรูปด้านล่าง

จากการ trace ครั้งแรก ทำให้รู้ว่า คำสั่งที่ ได้ทำไปนั้น คือ LD A,0A0H ผลจากการทำงาน ทำให้ A เก็บค่า A0 เอาไว้ (ดูจาก AF เป็น A000 นั่นหมายความว่า A เป็น A0h และ F เป็น 00h) มาดูคำสั่งถัดไปดีกว่าครับ ... ให้กด enter ต่อไปแล้วจะมีการแสดงผลออกมาดังนี้

คราวนี้เราได้ทำการประมวลผลคำสั่ง LD B,0ACh ทำให้ผลลัพธ์ของรีจิสเตอร์ B เป็น AC

เมื่อ trace อีกครั้ง คราวนี้คำสั่งที่กำลังทำงานเป็นคำสั่ง LD C.A พอจะเดาออกไหมครับว่าค่าของ C จะเปลี่ยนไปเป็นแบบ A ทั้งนี้เพราะเราสั่งให้นำค่าที่เก็บเอาไว้ใน A มาใส่ใน C ... ดังจะเห็นได้จากรูปด้านบนค่า BC จะเป็น ACA0 ซึ่งหมายความว่า B มีค่าเป็น ACh และ C มีค่าเป็น A0h หลังจากนั้นก็ให้กด Enter เพื่อดูผลของคำสั่งต่อไป

จากรูปด้านบนจะเห็นว่า คำสั่งที่กำลังทำงานนั้น คือ LD (BC),A ซึ่งมีความหมายว่า จะนำค่าที่เก็บใน A ซึ่งก็คือ A0h ไปเก็บเอาไว้ในหน่วยความจำ ณ ตำแหน่งที่กำหนด เอาไว้ในรีจิสเตอร์ BC ซึ่งก็คือ ACA0h ดังนั้น ผลการทำงานของคำสั่งนี้จะทำให้ หน่วยความจำ ณ ตำแหน่ง ACA0hเก็บค่า A0h เอาไว้ ... เพื่อให้เห็นผลของการทำงานจริง .. ให้เรากด ESC เพื่อออกจากการ trace แล้วกดคำสั่ง D ACA0,ACAF เพื่อสั่งให้ โปรแกรมมอนิเตอร์ แสดงข้อมุลของหน่วยความจำตำแหน่ง ACA0 ถึง ACAF ออกมาทางหน้าจอ ... ซึ่งผลจะออกมาเป็นดังนี้

จะเห้นว่า ที่ ACA0 มีค่าที่เก็บเอาไว้เป็น A0 ซึ่งเป็นการยืนยันว่า โปรแกรมของเราทำงานได้ถูกต้อง ... แต่ที่เราจะต้องระวัง ก็คือ เราสามารถเขียนโปรแกรม และเขียนลบ ข้อมูลในตำแหน่ง 8000h ขึ้นไปเท่านั้น เพราะ 0000h ถึง 7FFFh นั้นเป็นของโปรแกรมมอนิเตอร์ และถ้าจะให้ดี เราควรเก็บ ข้อมูล เอาไว้ ณ ตำแหน่งที่อยู่สูงกว่า โปรแกรมที่เราเขียน ซึ่งจากตัวอย่างด้านบน เราเข้าถึง หน่วยความจำ ณ ตำแหน่ง ACA0 ซึ่งอยู่ด้านบนของโปรแกรมมอนิเตอร์ และโปรแกรม ที่เราเขียน แต่ถ้าเราไปแก้ไขข้อมูล ณ ตำแหน่งที่เป็นของ โปรแกรมของเรา จะทำให้เกิดข้อผิดพลาดในการทำงานของโปรแกรมได้ แต่ถ้าเราเข้าไปแก้ไขข้อมูล ณ ตำแหน่งของ โปรแกรมมอนิเตอร์ เราก็จะไม่สามารถเปลี่ยนแปลงค่าใดๆ ได้เลย ทั้งนี้เพราะ โปรแกรมมอนิเตอร์เป็นหน่วยความจำแบบ ROM เราจึงไม่สามารถแก้ไขมันได้ นั่นเอง ....

ส่วนถ้าเราจะ run คำสั่งต่อไปก็ให้สั่งว่า T 8006 เพื่อทำการ trace คำสั่ง ณ หน่วยความจำตำแหน่ง 8006 ต่อไป ...แล้วกด enter ไปเรื่อยๆ พร้อมทั้งคอยสังเกตว่า คำสั่งนั้นๆ มีผลกับรีจิสเตอร์อย่างไร บ้าง ... นี่ล่ะครับ style ของการเขียนโปรแกรมด้วยภาษาแอสเซมบลี ... จากตัวอย่างนี้เมื่อทำงานไปเรื่อยๆ สุดท้ายก็จะหยุดทำงานด้วยคำสั่ง HALT ซึ่งทำให้ Z80 หยุดการทำงานทั้งหมด ...

เป็นอย่างไรบ้างครับ คำสั่ง LD ... หวังว่าคงเข้าใจการใช้คำสั่งนี้กันแล้วนะครับ คราวหน้าเราจะมาดูคำสั่ง ที่เกี่ยวกับ stack ครับ ...



เขียนโดย : ศุภชัย บุศราทิจ
Author : Supachai Budsaratij
e-mail : raek@se-ed.net
วันที่ทำการปรับปรุง : ๑๒ ธ.ค. ๒๕๔๓