[ บทความ : เรียนรู้ z80 ] ตอนที่ 13 เรื่อง คำสั่งติดต่อกับ I/O |
เรียนรู้ Z80 ตอนที่ 13
คำสั่งติดต่อกับ I/O
ช่วงนี้ก็ใกล้สงกรานต์ วันปีใหม่ของไทยเราแล้วนะครับ พอผ่านวันสงกรานต์ก็เป็นวันครอบครัวอีกต่างหาก ... หวังว่า ทุกคนคงมีความสุขกับปีใหม่ไทยปีนี้นะครับ ... ส่วนบทความของเราตอนนี้เป็นคำสั่งที่เกี่ยวกับ การติดต่อกับ I/O ซึ่ง Z80 นั้น ถูกออกแบบให้สามารถติดต่อกับ I/O ได้ถึง 256 พอร์ต นั่นก็คือ พอร์ตหมายเลข 0 จนถึง 255 (โดยแยกออกจากหน่วยความจำ ของ Z80) คราวนี้ ถ้าถามผมว่า แต่ละพอร์ตนั้นมีหน้าที่ทำอะไรบ้าง ... อืม ... ผมตอบได้เพียงแค่ว่า แต่ละพอร์ตนั้น จะ เป็นส่วนที่ติดต่อกับอุปกรณ์อะไรนั้น ขึ้นอยู่กับ ผู้ออกแบบบอร์ดไงล่ะ ... คราวนี้เราจะอ้างอิง ET-BOARD V6 เป็นหลักใช่ไหม (ที่ผ่านๆ มา มีหลายบทความที่ผมใช้บอร์ดอื่นๆ ทั้งนี้เพราะว่า บอร์ดทั้งหมดเป็นของบริษัท ETT การออกแบบเลยเหมือนๆ กัน พอเขียนโปรแกรม ผมก็สบายหน่อย) เอาล่ะ ว่าแล้วเรามาลองดูคำสั่งที่เกี่ยวกับ I/O กันครับ
ตาราง 13-1 ชุดคำสั่งสำหรับอ่านข้อมูลจาก I/O
Instruction Source/Target Flag Operation IN A,(C) Z, P, S, N=0, H A = ข้อมูล ณ พอร์ตที่กำหนดโดย C IN A,(n) ไม่มีผลกับ flag A = ข้อมูล ณ พอร์ตที่ n IN B,(C) Z, P, S, N=0, H B = ข้อมูล ณ พอร์ตที่กำหนดโดย C IN C, (C) Z, P, S, N=0, H C = ข้อมูล ณ พอร์ตที่กำหนดโดย C IN D, (C) Z, P, S, N=0, H D = ข้อมูล ณ พอร์ตที่กำหนดโดย C IN E,(C) Z, P, S, N=0, H E = ข้อมูล ณ พอร์ตที่กำหนดโดย C IN H, (C) Z, P, S, N=0, H H = ข้อมูล ณ พอร์ตที่กำหนดโดย C IN L, (C) Z, P, S, N=0, H L = ข้อมูล ณ พอร์ตที่กำหนดโดย C INI ไม่มี ถ้า B-1 เป็น 0 จะได้ Z=1 ไม่เช่นนั้น Z=0,
N=1(HL) = ข้อมูลจากพอร์ตที่กำหนดโดย C
B <- B-1
HL <- HL + 1
INIR ไม่มี Z=1 และ N=1 เสมอ (HL) = ข้อมูลจากพอร์ตที่กำหนดโดย C
B <- B-1
HL <- HL + 1
และทำจนกว่า B จะเป็น 0IND ไม่มี ถ้า B-1 เป็น 0 จะได้ Z=1 ไม่เช่นนั้น Z=0,
N=1(HL) = ข้อมูลจากพอร์ตที่กำหนดโดย C
B <- B-1
HL <- HL - 1
INDR ไม่มี Z=1 และ N=1 เสมอ (HL) = ข้อมูลจากพอร์ตที่กำหนดโดย C
B <- B-1
HL <- HL - 1
และทำจนกว่า B จะเป็น 0
ตาราง 13-2 ชุดคำสั่งสำหรับเขียนข้อมูลจาก I/O
Instruction Source/Target Flag Operation OUT (C),A ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน A ไปที่พอร์ตหมายเลข C OUT (n) ,A ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน A ไปที่พอร์ตหมายเลข n OUT (C) , B ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน B ไปที่พอร์ตหมายเลข C OUT (C), C ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน C ไปที่พอร์ตหมายเลข C OUT (C), D ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน D ไปที่พอร์ตหมายเลข C OUT (C), E ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน E ไปที่พอร์ตหมายเลข C OUT (C), H ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน H ไปที่พอร์ตหมายเลข C OUT (C), L ไม่มีผลกับ flag ส่งข้อมูลที่เก็บใน L ไปที่พอร์ตหมายเลข C OUTI ไม่มี ถ้า B-1 เป็น 0 จะได้ Z=1 ไม่เช่นนั้น Z=0,
N=1ส่งข้อมูลที่เก็บใน (HL) ไปที่พอร์ตหมายเลข C
B <- B-1
HL <- HL + 1
OTIR ไม่มี Z=1 และ N=1 เสมอ ส่งข้อมูลที่เก็บใน (HL) ไปที่พอร์ตหมายเลข C
B <- B-1
HL <- HL + 1
และทำจนกว่า B จะเป็น 0OUTD ไม่มี ถ้า B-1 เป็น 0 จะได้ Z=1 ไม่เช่นนั้น Z=0,
N=1ส่งข้อมูลที่เก็บใน (HL) ไปที่พอร์ตหมายเลข C
B <- B-1
HL <- HL - 1
OTDR ไม่มี Z=1 และ N=1 เสมอ ส่งข้อมูลที่เก็บใน (HL) ไปที่พอร์ตหมายเลข C
B <- B-1
HL <- HL - 1
และทำจนกว่า B จะเป็น 0เป็นอย่างไรบ้างครับ กับชุดคำสั่งที่เกี่ยวข้องกับการติดต่อกับ I/O ... ถ้าสังเกตดูจะเห็นว่า ทั้งในกลุ่มของ INPUT และ OUTPUT จะมีการสั่งการได้ 2 ลักษณะ คือ แบบอาศัย Register แล้วส่งไปยังพอร์ต หรืออ่านจากพอร์ตมา เก็บใน Register กับแบบที่มีการส่งข้อมูลจากหน่วยความจำไปที่พอร์ต และอ่านจากพอร์ตมาเก็บในหน่วยความจำ โดย แบบหลังนี้จะทำงานเป็นกลุ่มข้อมูล ซึ่งรูปแบบการทำงานลักษณะแบบนี้ผมได้เคยอธิบายไปแล้ว ... (ขอไม่อธิบายเพิ่มเติมล่ะกันครับ ... ใครที่จำไม่ได้ก็อ่านได้จากบทความเก่าๆ นะครับ :D) ...
คราวนี้ก็เป็นเรื่องของตัวอย่างบ้างล่ะ ... ปัญหาของผมตอนนี้ก็คือว่า พอผมเปิดคู่มือบอร์ดของ ET-V6, ET-V4 และ ET-V3.5 นั้นมีการออกแบบตำแหน่งของพอร์ตที่ติดต่อกับ LED (Flag LED) ไม่เหมือนกัน ... อืม ... ผมเองต้องการเขียนโปรแกรม สำหรับ สั่งให้หลอด LED บนบอร์ดนั้น ติด/ดับ สลับกันไปเรื่อยๆ ... เอาล่ะ เขียนโปรแกรมเป็น 3 ตัวก็ได้ ... แต่ อ้าว ... บอร์ด ET-V3.5 ของ ผมมีอันเป็นไปเสียแล้วครับ ... (เศร้าๆ ของมันเก่ามากน่ะครับ มันก็เลยเสีย แบบว่าลาย print มันพองมากๆ อาจจะทำให้เกิด noise เวลา download โปรแกรมมันเลยแน่นิ่งไปเลย ....) เอาเป็นว่า ผมลงตัวอย่างโปรแกรม 2 ตัวล่ะกันครับ เป็นของ ET-V6 กับ ET-V4 มาดูโปรแกรม และผลลัพธ์ของ ET-V6 กันก่อนครับ
; ; Filename : IO1.asz ; Author : Supachai Budsaratij (raek@se-ed.net) ; Date : 04/08/2001 ; Hardware : ET-Board V6 (Z80 Mode) ; INCL "etv6.inz" ; Include header for ET-V6 P_DIGIT EQU S8255_PA P_SEGM EQU S8255_PB P_LEDFLAG EQU 6 ORG UMEM_ORG ; Start at UMEM_ORG main LD D,0 LD BC,1 ; --- Move light loop LD A,P_LEDFLAG ; Select LED FLAG device OUT (P_DIGIT),A ; LD A,D ; Send the data to LED OUT (P_SEGM),A ; ;--- Delay LD HL,8000h delay SBC HL,BC JP NZ,delay ;--- Swap the pattern of the LED. LD A,0FFh SUB D LD D,A ;--- Do again JR loop END
,คราวนี้มาดูโปรแกรมสำหรับ ET-V4 กันบ้างครับ
; ; Filename : IO1a.asz ; Author : Supachai Budsaratij (raek@se-ed.net) ; Date : 04/08/2001 ; Hardware : ET-Board V4 ; INCL "etv4.inz" ; Include header for ET-V4 ORG UMEM_ORG ; Start at UMEM_ORG main LD D,0 LD BC,1 ; --- Move light loop LD A,D ; Send the data to LED OUT (LED_FLAG),A ; ;--- Delay LD HL,8000h delay SBC HL,BC JP NZ,delay ;--- Swap the pattern of the LED. LD A,0FFh SUB D LD D,A ;--- Do again JR loop END
,จบแล้วล่ะครับ คำสั่งเกี่ยวกับการติดต่อกับ I/O หวังว่า ตัวอย่างโปรแกรมตอนนี้คงทำให้ผู้สนใจ Z80 พอจะมีกำลังใจเขียน โปรแกรมกันบ้างนะครับ ... ในคราวหน้า ผมจะเขียนถึงคำสั่งที่เกี่ยวกับ การกระทำทางตรรกศาสตร์ (ก็พวก AND, OR, NOT พวกนั้นแหละครับ) ... อ๊ะๆ ก่อนจาก ... ใครที่ใช้ ET-V6 อยู่ลองเอาโปรแกรมนี้ไปลอง RUN ดูสิครับ ...
; ; Filename : IO2.asz ; Author : Supachai Budsaratij (raek@se-ed.net) ; Date : 04/08/2001 ; Hardware : ET-Board V6 (Z80 Mode) ; INCL "etv6.inz" ; Include header for ET-V6 P_DIGIT EQU S8255_PA P_LEDFLAG EQU 6 ORG UMEM_ORG ; Start at UMEM_ORG main LD D,0 LD BC,1 ; --- Move light loop LD A,P_LEDFLAG ; Select LED FLAG device OUT (P_DIGIT),A ; LD A,D ; Send the data to LED OUT (P_LEDFLAG),A ; ;--- Delay LD HL,8000h delay SBC HL,BC JP NZ,delay ;--- Swap the pattern of the LED. LD A,0FFh SUB D LD D,A ;--- Do again JR loop ENDตอนนี้ Bye bye ครับ