[ บทความ : เรียนรู้ z80 ] ตอนที่ 4 เรื่อง โปรแกรมต้นแบบ และข้อมูลที่จำเป็น

สวัสดีครับ เรามาเจอกันอีกครั้ง ในเรื่องของ z80 ตอนแรกนั้น ผมคาดว่าจะ เป็นบทความที่เน้นทั้ง การใช้โปรแกรม มอนิเตอร์ และเขียนเองจาก assembler [ download assembler ] ตอนนี้เอาเป็นว่า เขียนเองด้วย assembler เลยดีกว่านะครับ จะได้เป็นการฝึกหัด และเพิ่มทักษะการเขียนโปรแกรมด้วยตนเองไปด้วยกันเลย... ก่อนที่เราจะเริ่มเขียนโปรแกรมได้นั้น นอกจากจะมีตัวแปลภาษาแอสเซมบลีแล้ว เรายังจะต้องเข้าใจถึงความสามารถของไมโครโปรเซสเซอร์ที่ เราใช้ด้วยนะครับ ไม่อย่างนั้น เราจะไม่มีทางเขียนสั่งการไมโครโปรเซสเซอร์ตัวนั้นได้อย่างเต็มประสิทธิภาพเลยทีเดียว ... ยิ่งจะเอาไปประยุกต์ใช้ ด้วยแล้วล่ะก็ยิ่งยากเข้าไปอีกหลายขุม ... ดังนั้น ขอให้อ่านทบทวนบทความเก่า ๆ ให้เข้าใจก่อนนะครับ ... พอเราเข้าใจโครงสร้าง และ ความสามารถของไมโครโปรเซสเซอร์แล้ว ขั้นตอนต่อไปก็มาดูเรื่องฮาร์ดแวร์ที่จะใช้งาน (CPU+MEM+I/O+OS) ... นี่ล่ะที่ลำบากรองลงมา เพราะถ้าเป็นฮาร์ดแวร์ที่เราออกแบบเอง เราก็จะสามารถเข้าใจมันได้เป็นอย่างดี (ผมไม่เคยเห็นคนที่ออกแบบเอง แล้วไม่รู้ว่าตัวเองทำอะไรไป ... ฮา) แต่สำหรับมือสมัครเล่น อย่างผมแล้ว (เน้นนะครับ ว่าผมสมัครเล่น) การออกแบบเอง ยิ่งเป็นไปอย่างยากลำบากทีเดียว (ความยากลำบาก = เกียจคร้าน-1+เกียจคร้าน-2+เกียจคร้าน-3+...+เกียจคร้าน-n+ไม่มีเวลา ... อันนี้ล้อเล่นครับ) เอาเป็นว่าผมเลือกใช้ ET-BOARD V6 ล่ะกันครับ ... ส่วนพวกบอร์ดควบคุม ที่ไม่ใช่ Single board อย่าง บอร์ด jrZ180 ขอเอาไว้กล่าวรายละเอียดทีหลังล่ะกันครับ ...

การจัดสรรหน่วยความจำของ ET-BOARD V6

ขอไม่กล่าวถึงวิธีการใช้โปรแกรมมอนิเตอร์นะครับ เพราะคู่มือของบอร์ดคงอธิบายได้เป็นอย่างดีแล้ว ... เจ้าบอร์ด V6 นั้น มีการ จัดสรรหน่วยความจำดังนี้ครับ
	0000H-7FFFH	โปรแกรมมอนิเตอร์ และฟังก์ชันเสริม (32KB)
	8000H-BDFFH	สำหรับผู้ใช้
	BE00H-BFFFH	ใช้งานโดยโปรแกรมมอนิเตอร์
	C000H-DFFFH	หน่วยความจำขยาย (ใช้ได้เพียง 8KB)
จากการจัดสรรหน่วยความจำดังกล่าว ทำให้เวลาที่เราเขียนโปรแกรมนั้นจะต้องกำหนดให้โปรแกรมของเราทำงานในช่วง 8000H-BDFFH กับ C000H-DFFFH ... ส่วนรายละเอียดของ I/O จะมีดังนี้
	00H	8255 System I/O - Port A
	01H	8255 System I/O - Port B
	02H	8255 System I/O - Port C
	03H	8255 System I/O - Control port

	20H	8255 USER - Port A
	21H	8255 USER - Port B
	22H	8255 USER - Port C
	23H	8255 USER - Control port

	4DH	SCN2681 - User switch  (4 bit, IP0-IP3)
	4EH	SCN2681 - User LED (Set-Output, 4 bit, OP0-OP3)
	4FH	SCN2681 - User LED (Reset-Output, 4 bit, OP0-OP3)

	60H	CH-LCD - Write command
	61H	CH-LCD - Read command
	62H	CH-LCD - Write data
	63H	CH-LCD - Read data

	64H	GR-LCD - Write command (Page 1)
	65H	GR-LCD - Read command (Page 1)
	66H	GR-LCD - Write data  (Page 1)
	67H	GR-LCD - Read data  (Page 1)

	68H	GR-LCD - Write command (Page 2)
	69H	GR-LCD - Read command (Page 2)
	6AH	GR-LCD - Write data  (Page 2)
	6BH	GR-LCD - Read data  (Page 2)
ทั้งหมดเป็นรายละเอียดของบอร์ดที่เราสมควรจะรู้ครับ เพราะ ถ้าเราไม่รู้ว่า เขาออกแบบให้มีอะไรอยู่ที่ใด การเขียนโปรแกรม ก็ทำได้ลำบากมากครับ ยิ่งถ้าไม่มีวงจรให้ไล่ด้วยแล้วล่ะก็ ฝันร้ายสุด ๆ (ใครไม่เคยเจอแบบว่า ... เอาบอร์ดมาให้แล้วก็ให้หาว่า วงจรมันเป็นอย่างไร ... รับรองไม่เข้าใจหรอกครับว่าผมกล่าวถึงอะไร) ตอนนี้รู้รายละเอียดที่จำเป็นไปแล้ว ... คราวนี้มาลอง เขียนโปรแกรมต้นแบบกันก่อนนะครับ

โปรแกรมต้นแบบ สำหรับ ET-V6

เพื่อความสะดวก ผมแยกไฟล์ต้นแบบเป็น 2 ส่วน คือ ส่วนที่เรียกว่าเป็น header-file หรือไฟล์ส่วนหัว (.inz) ซึ่งมีหน้าที่ เป็นไฟล์ที่เก็บข้อมูลของค่าคงที่ต่าง ๆ เช่น ตำแหน่งของหน่วยความจำ , ตำแหน่งของ I/O เป็นต้น ... ส่วนที่ 2 เป็นไฟล์ภาษาแอสเซมบลี (.asz) เอาไว้สำหรับเขียนโปรแกรม

ไฟล์ส่วนหัวมีข้อมูลดังนี้ครับ

	
	;
	; filename  : etv6.inz
	; assembler : az80
	; author    : Supachai Budsaratij (raek@se-ed.net)
	; hardware  : et-board 6 (Z-80 mode)
	; date      : October 12,2000
	;

	; --- MEMORY
	;
	UMEM_ORG        EQU     08000h   ; User RAM start
	UMEM_END        EQU     0BDFFh   ; User RAM end
	XMEM_ORG        EQU     0C000h   ; Expand RAM end
	XMEM_END        EQU     0DFFFh   ; Expand RAM end

	; --- I/O
	;
	S8255_PA        EQU     00h     ; System 8255 port A
	S8255_PB        EQU     01h     ; System 8255 port B
	S8255_PC        EQU     02h     ; System 8255 port C
	S8255_CT        EQU     03h     ; System 8255 control port
	;
	U8255_PA        EQU     20h     ; User 8255 port A
	U8255_PB        EQU     21h     ; User 8255 port B
	U8255_PC        EQU     22h     ; User 8255 port C
	U8255_CT        EQU     23h     ; User 8255 control port
	;
	SCN_INP         EQU     4Dh     ; SCN2681 - Input port (Switch)
	SCN_SEO         EQU     4Eh     ; SCN2681 - Set output port (LED)
	SCN_REO         EQU     4Fh     ; SCN2681 - Reset output port (LED)
	;
	CLCD_WC         EQU     60h     ; Character LCD write command
	CLCD_RC         EQU     61h     ; Character LCD read command
	CLCD_WD         EQU     62h     ; Character LCD write data
	CLCD_RD         EQU     63h     ; Character LCD read data
	;
	GLCD_WC1        EQU     64h     ; Graphics LCD write command (Page 1)
	GLCD_RC1        EQU     65h     ; Graphics LCD read command  (Page 1)
	GLCD_WD1        EQU     66h     ; Graphics LCD write data    (Page 1)
	GLCD_RD1        EQU     67h     ; Graphics LCD read data     (Page 1)
	;
	GLCD_WC2        EQU     68h     ; Graphics LCD write command (Page 2)
	GLCD_RC2        EQU     69h     ; Graphics LCD read command  (Page 2)
	GLCD_WD2        EQU     6Ah     ; Graphics LCD write data    (Page 2)
	GLCD_RD2        EQU     6Bh     ; Graphics LCD read data     (Page 2)
	;

จากข้อมูลในไฟล์ส่วนหัว จะเห็นว่า ผมสร้างค่าคงที่ขึ้นมาแทนการใช้เป็นค่าตัวเลข ทั้งนี้ก็เพื่อความสะดวก ในการเรียก แถมเมื่อเราต้องการเขียนโปรแกรมแบบ อ้างชื่อเดียวกัน แต่ตำแหน่งต่างกัน เช่น ตำแหน่งของหน่วยความจำเริ่มต้น บนบอร์ด ET-V6 อยู่ที่ 8000H (ตั้งชื่อเอาไว้เป็น UMEM_ORG) แต่ในบอร์ด ET-V3.5 ตำแหน่งจะเป็น 2000h ถ้าเป็นการ เขียนแบบทั่วๆ ไป เราจะต้องเปลี่ยนค่าของตำแหน่งเอง แต่พอเราตั้งชื่อเป็นชื่อเดียวกัน ในไฟล์ส่วนหัว เราก็ไม่ต้องไปแก้ไขข้อมูล เลย ... เป็นการประหยัดเวลา และยืดหยุ่นต่อการเขียนโปรแกรมแบบโครงสร้างเดียว แต่ใช้กับหลาย ๆ บอร์ด เลยล่ะครับ (เหมือน ไลบรารี ภาษาซี สำหรับ MCS-51 : Munc5x ที่ผมเขียนไงครับ) ...

ส่วนข้อมูลด้านล่างนี้เป็นข้อมูลของไฟล์ภาษาแอสเซมบลีที่เราเขียนกัน

	
	;
	; filename  : tmplate.asz
	; assembler : az80
	; author    : Supachai Budsaratij (raek@se-ed.net)
	; date      : October 12,2000
	;
	; compile   : az80 tmplate.asz -l tmplate.lst -o tmplate.hex
	;

	        INCL "etv6.inz"         ; Inlude header for ET-V6

	        ORG     UMEM_ORG        ; Start at UMEM_ORG

	main
	; --- Your program start here...

	        HALT                    ; Terminate (HALT) CPU


	        END                     ; End of source code

เอาล่ะครับ ตอนนี้เราได้ไฟล์ต้นแบบมาแล้วครับ ... โปรแกรมนี้ทำอะไรบ้าง พอมองปุ้บ ก็จะเห็นว่า มันทำอย่างเดียวคือ HALT หรือหยุดทำงานนั่นเอง ... นั่นหมายความว่า เมื่อโปรแกรมองเราเริ่มทำงานปุ๊บ มันก็หยุดทำงานทันทีเลย ... ง่ายไปนิดใช่ไหมครับ เอาไว้คราวหน้าค่อยศึกษากันไปเรื่อยๆ ล่ะกันครับ (นะๆ) ...

การคอมไพล์

ตอนนี้เราก็เหลือขั้นตอนอีก 3 ขั้นตอนเท่านั้น คือ ทำการแปลงให้เป็น machine-code, download ไปที่บอร์ด และ ทดสอบโปรแกรม ... ตอนนี้มาสั่งคอมไพล์กันครับ ... คำสั่งที่ผมใช้ก็คือ

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

ที่หน้าจอของเครื่องหลังจากที่แปลเสร็จ โดยไม่มีความผิดพลาด จะเป็นดังนี้ครับ ... ส่วนถ้าผิดพลาดจะมีการรายงานว่า ผิดพลาดเป็นจำนวน error เท่าใด แล้วให้ผู้อ่านเปิดไฟล์ .lst มาดูว่ามีบรรทัดใดบ้างที่ผิด (ไม่น่าจะพิมพ์ผิดจริงไหมครับ... มือระดับนี้แล้ว :D)

หลังจากนี้เราจะมีไฟล์เพิ่มขึ้นมา 2 ไฟล์ คือ .lst และ .hex เราจะเอาไฟล์ .hex มาใช้สำหรับ download ลงบอร์ดครับ...

Download ไฟล์ .hex

ก่อนที่จะทำการ download เรามาทำความรู้จักกับคำว่า download กันก่อน ... download ก็คือ กระบวนการที่เรา นำข้อมูลจากเครื่องคอมพิวเตอร์ของเรา ส่งไปยังเครื่องคอมพิวเตอร์ หรืออุปกรณ์ปลายทาง ... ดังนั้น การ download ไฟล์ .hex ก็คือ การส่งไฟล์ .hex จากเครื่องคอมพิวเตอร์ที่เราเขียนโปรแกรม ส่งไปยังบอร์ด z80 นั่นเอง ... ขั้นตอนเป็นดังนี้ครับ

1. จ่ายไฟเลี้ยงแก่บอร์ด
2. ต่อสาย RS232 ระหว่างเครื่องคอมพิวเตอร์กับบอร์ด
3. เรียกโปรแกรม hyper terminal หรือ โปรแกรมสื่อสารอนุกรม แล้วกำหนดค่าในการทำงานของ hyperterminal ดังนี้

3.1 เลือก File, Properties แล้วจะแสดงหน้าจอดังนี้

3.2 เลือกว่าเราใช้พอร์ตใดอยู่จาก Connect using: (ตามรูปด้านบน ผมใช้ COM1)
3.3 เลือกกดที่ปุ่ม Configure... แล้วแสดงหน้าจอดังนี้

3.4 ให้กำหนดข้อมูลต่าง ๆ ตามรูปตัวอย่างด้านบน
4. เลือกโหมดการทำงานของบอร์ดเป็น remote debugger โดยกด FUNC,3,INC แล้วที่หน้าจอของโปรแกรม hyper terminal จะแสดงดังนี้


5. ตอนนี้แสดงว่าเราพร้อมที่จะทำการ download แล้วครับ ... สั่ง L แล้วจะแสดงผลดังนี้


6. ตอนนี้ บอร์ดกำลังรอให้เราส่งไฟล์ไปให้อยู่ครับ ... เราก็เลือกส่งไฟล์ โดยเลือกที่เมนู Transfer, Send Text file... ดังรูปด้านล่าง


7. เมื่อเราเลือกตามข้อ 6 ก็จะมีหน้าจอ ให้เราเลือกไฟล์ที่จะ download คล้าย ๆ กับรูปด้านล่างนี้ โดยให้ผู้อ่านหาไฟล์ tmplate.hex ให้เจอ แล้วกดปุ่ม Open


8. เสร็จแล้ว ที่หน้าจอโปรแกรม Hyper Terminal ก็จะรายงานออกมาว่า ส่งไฟล์เป็นที่เรียบร้อย ดังรูปด้านล่างนี้


เรียบร้อยไปลแวครับ สำหรับขั้นตอน download ...

เรียกโปรแกรมให้ทำงาน

ตอนนี้โปรแกรมที่เราเขียนเสร็จไปลแวนั้นจอยู่ที่หน่วยความจำของบอร์ด เป็นที่เรียบร้อย ขั้นตอนสุดท้ายของเราก็คือ การ เรียกโปรแกรมที่เรา download ไปที่บอร์ดให้มันทำงาน ... การสั่งการก็ง่ายมากครับ คือ กด g แล้วกด Enter โปรแกรมก็จะทำงานทันที ดังรูปด้านล่างครับ


หลังจากทำงานแล้วมันก็แน่นิ่งไปเลยใช่ไหมครับ แถมที่บอร์ดนั้น หลอด LED สีเขียว (ด้านซ้ายบนของบอร์ด) ก็สว่างขึ้นมา (ดังรูปด้านล่าง) นั่นหมายความว่าเราประสบความสำเร็จแล้วครับ... เย้ !


ส่งท้าย

ตอนนี้เราก็เขียนโปรแกรม และ download พรอ้มทั้ง เรียกใช้เป็นกันแล้วนะครับ คราวหน้า ผมก็จะเริ่มเข้าสู่คำสั่ง ของ Z80 แล้วนะครับ ... บทความนี้เราเริ่มจาก 0 กันเลยนะเนี่ย ... อธิบายค่อนข้างหลายตอนแล้ว ยังไม่ได้เริ่มจริงๆ จัง เสียที ...


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