ข้อนี้เป็นข้อที่เก็บคะแนนง่ายที่สุด เพราะอาจารย์แจกชีท Instruction Set ให้ในห้องสอบ ไม่ต้องท่อง แค่ต้องอ่านตารางให้เป็น นับไบต์ให้ถูก และไม่พลาดเรื่อง little-endian
คอลัมน์ในชีทเรียงแบบนี้
| คอลัมน์ | อ่านยังไง |
|---|---|
| Mnemonic | ชื่อคำสั่ง เช่น LD r, r′ — ตัวพิมพ์เล็ก r, n, dd, cc คือ “ช่องว่าง” ที่เราต้องเติมเอง |
| Symbolic Operation | ความหมายทางคณิตศาสตร์ เช่น r ← r′ |
| Flags | • = ไม่กระทบ, 0 = เคลียร์, 1 = เซ็ต, ↕ = เปลี่ยนตามผลลัพธ์ |
| Opcode 76 543 210 | คอลัมน์สำคัญที่สุด — เขียนบิตของ opcode โดยแบ่งเป็น 2-3-3 ตามฟิลด์ ตัวอักษรในนั้น (r, p, q, dd) ให้แทนด้วยรหัสจากตารางท้ายหน้า |
| Hex | ค่าฐานสิบหกสำหรับคำสั่งที่ไม่มีช่องว่างให้เติม ถ้ามี r/n จะเว้นว่างไว้ |
| Bytes | ขนาดคำสั่ง — เอาไปบวก address ของบรรทัดถัดไป |
| M Cycles | จำนวน machine cycle — เอาไปใช้ในข้อ 5 |
| T States | จำนวน T-state — เอาไปคูณกับคาบ clock เป็นเวลา |
LD B, ALD r, r′ ⇒ opcode = 01 r r′000, A = 111 76 543 210
01 000 111 ← r = B (ปลายทาง), r′ = A (ต้นทาง)
= 0100 0111
= 47Hในรูปแบบ 01 d s ฟิลด์กลาง (บิต 5-4-3) คือ ปลายทาง
ฟิลด์ล่าง (บิต 2-1-0) คือ ต้นทาง
LD B,A = 01 000 111 = 47H ส่วน LD A,B = 01 111 000 = 78H — คนละตัวกัน
| 000 | B | 100 | H |
| 001 | C | 101 | L |
| 010 | D | 110 | (HL) |
| 011 | E | 111 | A |
110 คือ (HL) ไม่ใช่ register — จึงทำให้
LD (HL),(HL) ชนกับ HALT (76H) พอดี Zilog เลยยกให้เป็น HALT
| รหัส | dd | |
|---|---|---|
| 00 | BC | BC |
| 01 | DE | DE |
| 10 | HL | HL |
| 11 | SP | AF |
dd ใช้กับ LD/INC/DEC/ADD HL — qq ใช้กับ PUSH/POP เท่านั้น ต่างกันที่ตัวสุดท้าย
| 000 | NZ | 100 | PO |
| 001 | Z | 101 | PE |
| 010 | NC | 110 | P |
| 011 | C | 111 | M |
ใช้กับ JP cc / CALL cc / RET cc
JR ใช้ได้แค่ 4 ตัวแรก (NZ, Z, NC, C)
| รูปแบบบิต | คำสั่ง | ตัวอย่าง |
|---|---|---|
| 01 d s | LD r, r′ | LD B,A = 01 000 111 = 47H |
| 00 r 110 + n | LD r, n | LD A,9FH = 00 111 110 = 3EH, 9F |
| 00 dd0 001 + nn | LD dd, nn | LD HL,2100H = 00 100 001 = 21H, 00, 21 |
| 10 000 s | ADD A, r | ADD A,B = 10 000 000 = 80H |
| 10 001 s | ADC A, r | ADC A,B = 88H |
| 10 010 s | SUB r | SUB B = 90H |
| 10 100 s | AND r | AND B = A0H |
| 10 101 s | XOR r | XOR A = 10 101 111 = AFH |
| 10 110 s | OR r | OR B = B0H |
| 10 111 s | CP r | CP B = B8H |
| 00 r 100 | INC r | INC A = 00 111 100 = 3CH |
| 00 r 101 | DEC r | DEC A = 3DH |
| 11 qq0 101 | PUSH qq | PUSH BC = 11 000 101 = C5H |
| 11 qq0 001 | POP qq | POP AF = 11 110 001 = F1H |
| 11 cc 010 + nn | JP cc, nn | JP NZ,2000H = 11 000 010 = C2H, 00, 20 |
| Prefix | ใช้กับ | ตัวอย่าง | ผลต่อขนาด/เวลา |
|---|---|---|---|
| CB | ปรับบิต: BIT / SET / RES / RLC / RL / SRL … | BIT 0,A = CB 47 | +1 ไบต์, มี M1 เพิ่มอีกรอบ |
| ED | คำสั่งขยาย: LDIR, IN r,(C), OUT (C),r, NEG, IM … | LDIR = ED B0 | +1 ไบต์, +4 T |
| DD | เปลี่ยน HL เป็น IX | LD A,(IX+5) = DD 7E 05 | +1 ไบต์ (+ displacement) |
| FD | เปลี่ยน HL เป็น IY | LD A,(IY+5) = FD 7E 05 | +1 ไบต์ (+ displacement) |
Prefix แต่ละตัวทำให้เกิด M1 cycle เพิ่มอีกรอบ — ทำให้ IN r,(C) ใช้ 12 T
ในขณะที่ IN A,(n) ใช้ 11 T ทั้งที่ดูเหมือนคล้ายกัน
ORG เช่น ORG 0000H ⇒ คำสั่งแรกอยู่ที่ 0000HLOOP: ไม่ใช่คำสั่ง แค่ตั้งชื่อให้ address ปัจจุบันcpu, hof, org, end เป็นคำสั่งสำหรับตัวแปลภาษา
ไม่ใช่สำหรับ CPU ⇒ ไม่มี opcode และไม่มี address
(ดูรายละเอียดว่ามันคืออะไร มาจากไหน)d = address ปลายทาง − (address ของคำสั่ง JR + 2)
; เพราะ PC ถูกเพิ่มไปแล้ว 2 (ขนาดของคำสั่ง JR) ก่อนบวก d
ตัวอย่าง 200BH: LOOP: OUT (40H),A
200EH: JR LOOP
d = 200BH − (200EH + 2) = 200BH − 2010H = −5
−5 ในรูป two's complement 8 บิต = FBH
⇒ machine code = 18 FB
พิมพ์ opcode 1 ไบต์ (ฐานสิบหก) เพื่อดูว่ามันถูกแบ่งฟิลด์ยังไง และหมายความว่าอะไร
จงหา Opcode และ Address ของโค้ดแต่ละคำสั่งในข้อที่ 3
CPU "z80.tbl" ; directive — ไม่กิน address
HOF "INT8" ; directive — ไม่กิน address
ORG 0000H
START: LD SP, 1FFFH
LD HL, 1000H
MAIN: IN A, (84H)
LD (HL), A
LD A, (1000H)
CPL
OUT (40H), A
LD B, 0FFH
DELAY: DJNZ DELAY
JR MAIN
HALT
| คำสั่ง | วิธีคิด |
|---|---|
LD SP,1FFFH |
รูปแบบ 00 dd0 001 · dd ของ SP = 11
⇒ 00 110 001 = 31H ตามด้วย FF 1F (ไบต์ต่ำก่อน) |
LD HL,1000H |
dd ของ HL = 10 ⇒ 00 100 001 = 21H ตามด้วย 00 10 |
IN A,(84H) |
เป็นรหัสตายตัว DBH ตามด้วยเลขพอร์ต 84H · 2 ไบต์ 11 T |
LD (HL),A |
รูปแบบ 01 110 r · r ของ A = 111
⇒ 01 110 111 = 77H · 1 ไบต์ 7 T (2 machine cycle) |
LD A,(1000H) |
รหัสตายตัว 3AH ตามด้วย 00 10 · 3 ไบต์ 13 T (4 machine cycle) |
CPL | รหัสตายตัว 2FH · 1 ไบต์ 4 T |
OUT (40H),A | รหัสตายตัว D3H ตามด้วย 40H · 2 ไบต์ 11 T |
LD B,0FFH |
รูปแบบ 00 r 110 · r ของ B = 000
⇒ 00 000 110 = 06H ตามด้วย FFH |
DJNZ DELAY |
รหัส 10H + displacement · คำสั่งอยู่ที่ 0011H ปลายทาง DELAY = 0011H d = 0011H − (0011H + 2) = −2 = FEH ⇒ 10 FE (วนที่ตัวเอง) |
JR MAIN |
รหัส 18H + displacement · คำสั่งอยู่ที่ 0013H ปลายทาง MAIN = 0006H d = 0006H − (0013H + 2) = 0006H − 0015H = −15 = F1H ⇒ 18 F1 |
HALT | รหัส 76H — ตรงกับช่อง LD (HL),(HL) ที่ไม่มีความหมาย |
address สุดท้าย − address แรก ต้องเท่ากับผลรวมจำนวนไบต์ — ถ้าไม่ตรง แปลว่านับไบต์ผิดที่ใดที่หนึ่ง วิธีนี้จับ error ได้เร็วที่สุดในห้องสอบ
จงหา opcode และ address ของโปรแกรมต่อไปนี้ (จากใบงาน Lab 1)
CPU "z80.tbl"
HOF "INT8"
ORG 2000H
LD A, 1
LD B, 2
LD C, 8
LD D, 3
ADD A, B
ADD A, C
ADD A, D
HALTตรงกับ Listing File ของ Lab 1 ทุกไบต์ · ผลลัพธ์ใน A = 1+2+8+3 = 14 = 0EH
จงหา opcode และ address ของโปรแกรมบวกเลขจากใบงาน Lab 2
CPU "z80.tbl"
HOF "INT8"
ORG 200AH
LD HL, 2100H
LD DE, 2101H
LD A, (HL)
LD B, A
LD A, (DE)
ADD A, B
INC DE
LD (DE), A
HALTLD HL,2100H = 21 00 21 — ไบต์แรกคือ opcode 21H
ไบต์ที่สองคือ 00H (ไบต์ต่ำของ 2100H) ไบต์ที่สามคือ 21H (ไบต์สูง)
บังเอิญเลข 21 ซ้ำกันพอดี อย่าสับสน
จงหา opcode และ address ของโปรแกรม LED จากใบงาน Lab 2
และอธิบายว่าทำไม displacement ของ JR loop ถึงเป็น FBH
CPU "z80.tbl"
HOF "INT8"
ORG 200AH
XOR A
loop: OUT (40H), A
INC A
JR loop
HALTคำสั่ง JR อยู่ที่ 200EH · ปลายทาง loop = 200BH
d = 200BH − (200EH + 2) = 200BH − 2010H = −5
−5 → two's complement 8 บิต: 5 = 0000 0101
กลับบิต = 1111 1010
บวก 1 = 1111 1011 = FBH ✓
ตรงกับ Listing File 200E 18FB ทุกประการ
จงหา opcode ของคำสั่งเหล่านี้จากรูปแบบบิต โดยไม่เปิดคอลัมน์ Hex:
LD C,H · LD (HL),E · SUB (HL) · DEC L ·
PUSH AF · RET NC · JP PE,1234H
| คำสั่ง | รูปแบบ | แทนค่า | บิต | Hex |
|---|---|---|---|---|
| LD C,H | 01 d s | C = 001, H = 100 | 01 001 100 | 4CH |
| LD (HL),E | 01 110 s | E = 011 | 01 110 011 | 73H |
| SUB (HL) | 10 010 s | (HL) = 110 | 10 010 110 | 96H |
| DEC L | 00 r 101 | L = 101 | 00 101 101 | 2DH |
| PUSH AF | 11 qq0 101 | AF = 11 | 11 110 101 | F5H |
| RET NC | 11 cc 000 | NC = 010 | 11 010 000 | D0H |
| JP PE,1234H | 11 cc 010 + nn | PE = 101 | 11 101 010 | EAH 34 12 |
สังเกต JP PE,1234H → operand เก็บเป็น 34 12 ไม่ใช่ 12 34
โปรแกรมหนึ่งเริ่มที่ 1000H และมี machine code ต่อกันดังนี้
3E 55 06 08 D3 40 3C 10 FC 76 จงถอดกลับเป็น assembly พร้อม address ของแต่ละคำสั่ง
| Address | Machine code | Instruction | วิธีถอด |
|---|---|---|---|
| 1000H | 3E 55 | LD A,55H | 3E = 00 111 110 ⇒ LD r,n โดย r = 111 = A |
| 1002H | 06 08 | LD B,08H | 06 = 00 000 110 ⇒ r = 000 = B |
| 1004H | D3 40 | OUT (40H),A | D3 = รหัสตายตัวของ OUT (n),A |
| 1006H | 3C | INC A | 3C = 00 111 100 ⇒ INC r โดย r = 111 = A |
| 1007H | 10 FC | DJNZ 1005H | FCH = −4 ⇒ ปลายทาง = 1007H + 2 + (−4) = 1005H |
| 1009H | 76 | HALT | 76 = HALT |
ปลายทางของ DJNZ คือ 1005H ซึ่งตกกลาง ๆ คำสั่ง D3 40
(คือไบต์ 40) — โปรแกรมนี้จะทำงานผิดพลาด เพราะ 40H = LD B,B
ตัวอย่างนี้แสดงให้เห็นว่า displacement ผิดนิดเดียว โปรแกรมเปลี่ยนความหมายทั้งหมด