อาจารย์บอกว่า Final จะออกเหมือนชุดนี้ แต่ปรับตัวเลข ย้ายสายเส้นนั้นเส้นนี้ หรือเปลี่ยนเลข operation — ทุกข้อในหน้านี้จึงมี เครื่องปั่นโจทย์ ให้เปลี่ยนเองได้ และทุกครั้งที่เปลี่ยนจะได้เฉลยกับคำอธิบายชุดใหม่ ฝึกจน “วิธีคิด” ติดมือ ไม่ใช่จำคำตอบ
| ข้อ | เรื่อง | รูปแบบคำตอบ |
|---|---|---|
| 1 | บวกเลข 4 บิต signed/unsigned + overflow | ฐานสอง + True/False |
| 2 | ALU control: Ainv, Binv, CarryIn, Operation | ตาราง 0/1/x |
| 3 | Main control ของ multicycle 3 state | ตาราง 0/1 + next state |
| 4 | ต่อสาย datapath ของ srl กับ barrel shifter | วาดในกระดาษ |
| 5 | เวลา pipeline + ชื่อ hazard และวิธีแก้ | ตัวเลข + ศัพท์ |
| 6 | ทำไม stage หลัง ID ได้ control ถูกตัว | เขียนอธิบาย |
ข้อ 1–3 และ 5 ส่งคำตอบเข้า autolab · ข้อ 4 และ 6 เขียนในกระดาษ

สอบครั้งที่ 2 เทอมปลาย ปีการศึกษา 2561 · 3 ชั่วโมง · ห้ามนำเอกสาร · อนุญาตเครื่องคิดเลข · ส่งคำตอบทาง autolab

บวกเลข 4 บิต 8 ข้อ ตอบ Result 4 บิต และ Overflow — ข้อนี้ ไม่มี partial credit ผิดช่องเดียวเสียทั้งข้อ จุดที่คนพลาดบ่อยคือข้อที่ operand เหมือนกันแต่ชนิดต่างกัน (1.3 กับ 1.4) ซึ่ง Result เหมือนกันแต่ Overflow ไม่เหมือนกัน อาจารย์เปลี่ยนตัวเลขได้ง่ายที่สุดในข้อนี้ จึงต้องทำได้ทุกตัวเลข
เลข n บิตชุดเดียวกัน ถ้าอ่านแบบ unsigned จะได้ 0 ถึง 2n−1 ถ้าอ่านแบบ signed (two’s complement) บิตซ้ายสุดมีน้ำหนักเป็น −2n−1 จึงได้ช่วง −2n−1 ถึง 2n−1−1 — สำหรับ 4 บิตคือ 0…15 กับ −8…7
| บิต | unsigned | signed | บิต | unsigned | signed |
|---|---|---|---|---|---|
| 0000 | 0 | 0 | 1000 | 8 | −8 |
| 0001 | 1 | +1 | 1001 | 9 | −7 |
| 0010 | 2 | +2 | 1010 | 10 | −6 |
| 0011 | 3 | +3 | 1011 | 11 | −5 |
| 0100 | 4 | +4 | 1100 | 12 | −4 |
| 0101 | 5 | +5 | 1101 | 13 | −3 |
| 0110 | 6 | +6 | 1110 | 14 | −2 |
| 0111 | 7 | +7 | 1111 | 15 | −1 |
หาค่าลบเร็วๆ: กลับทุกบิตแล้ว +1 เช่น 1011 → 0100 + 1 = 0101 = 5 ⇒ 1011 = −5 · หรือคิดจากน้ำหนัก 1011 = −8 + 0 + 2 + 1 = −5
ALU บวกเลขทีละบิตด้วย full adder ต่อกันเป็นทอด (ripple carry) — บิตผลลัพธ์ที่ออกมา ไม่สนว่าเป็น signed หรือ unsigned สิ่งที่ต่างกันมีแค่ การตีความ และ กฎตัดสิน overflow นี่คือเหตุผลที่ในโจทย์ 1.3 กับ 1.4 ช่อง Result ตอบเหมือนกันทุกบิต
คือ “ค่าจริงของผลลัพธ์เก็บไม่ได้ใน n บิต” — วิธีตัดสินเปลี่ยนตามชนิดของการคำนวณ
| ชนิด | overflow เมื่อ | ดูจากฮาร์ดแวร์ |
|---|---|---|
| unsigned + | ผลจริง > 2n−1 | carry out ของบิตบนสุด = 1 |
| unsigned − | A < B (ติดลบ) | carry out = 0 (ต้องยืม) |
| signed + | บวก+บวก ได้ลบ หรือ ลบ+ลบ ได้บวก | carry เข้าบิตบนสุด ≠ carry ออก |
| signed − | บวก−ลบ ได้ลบ หรือ ลบ−บวก ได้บวก | carry เข้าบิตบนสุด ≠ carry ออก |
การลบ: ฮาร์ดแวร์ทำ A − B = A + (~B) + 1 คือกลับบิต B แล้วป้อน carry-in ตัวแรกเป็น 1 (นี่คือที่มาของ Binvert และ CarryIn ในข้อ 2)
เนื้อหาเต็มอยู่ในบท Arithmetic for computers I สไลด์หน้า 3–11
| ข้อ | ชนิด | Op 1 + Op 2 | Result | Overflow | ทำไม |
|---|---|---|---|---|---|
| 1.1 | Signed | 0010 + 0100 | 0b0110 | False | +2 + +4 = +6 อยู่ใน −8…7 |
| 1.2 | Unsigned | 0010 + 0100 | 0b0110 | False | 2 + 4 = 6 ≤ 15 · carry out = 0 |
| 1.3 | Signed | 0101 + 0110 | 0b1011 | True | +5 + +6 = +11 เกิน 7 · บวก+บวก ได้บิตบนสุดเป็น 1 |
| 1.4 | Unsigned | 0101 + 0110 | 0b1011 | False | 5 + 6 = 11 ≤ 15 · บิตเหมือน 1.3 แต่ไม่ overflow |
| 1.5 | Signed | 1111 + 1011 | 0b1010 | False | −1 + −5 = −6 อยู่ในช่วง (carry out ทิ้งไป ไม่เกี่ยว) |
| 1.6 | Signed | 1001 + 1011 | 0b0100 | True | −7 + −5 = −12 ต่ำกว่า −8 · ลบ+ลบ ได้บวก |
| 1.7 | Signed | 1001 + 0011 | 0b1100 | False | −7 + +3 = −4 · ต่างเครื่องหมายไม่มีทาง overflow |
| 1.8 | Signed | 0111 + 1000 | 0b1111 | False | +7 + −8 = −1 |
add/addi/sub เกิด exception · addu/addiu/subu ไม่สนใจ
ให้เติม Ainv, Binv, CarryIn, Operation ของ ALU ในรูปที่ 1 ให้ทำงานตาม Goal แต่ละแถว · ตอบเป็นฐานสอง ใช้ x แทน don’t care — ข้อนี้อาจารย์บอกชัดว่าอาจย้ายสายในรูป เช่น สลับว่าขาไหนของ MUX ต่อกับอะไร ดังนั้นห้ามท่องเลข ต้องอ่านรูปทุกครั้ง
a หรือ ~a ต่อไป คุมด้วย Ainvert (ในข้อสอบเขียนว่า Aint)b หรือ ~b คุมด้วย BinvertCarryOut ของบิต i ต่อเข้า CarryIn ของบิต i+1 (ripple carry) — สายควบคุม CarryIn ที่ต้องตอบในตารางคือ CarryIn ของ ALU0 เท่านั้น ส่วน Ainvert, Binvert, Operation ต่อขนานเข้าทุกบิต ทุกบิตจึงทำ operation เดียวกัน
| อยากได้ | เขียนใหม่เป็น | ตั้งค่า |
|---|---|---|
| A − B | A + (~B) + 1 | Binvert = 1, CarryIn = 1, เลือก adder |
| NOR ~(A | B) | (~A) & (~B) — De Morgan | Ainvert = 1, Binvert = 1, เลือก AND |
| slt (A < B ? 1 : 0) | ดูเครื่องหมายของ A − B | ทำแบบลบ แล้วเลือกขา Less |
สไลด์บท Datapath I ให้ ALU control เป็น 4 บิต: and = 0000, or = 0001, add = 0010, sub = 0110, slt = 0111, nor = 1100 — จริงๆ แล้ว 4 บิตนี้คือ [Ainvert | Bnegate | Operation 2 บิต] โดย Bnegate คือ Binvert กับ CarryIn ที่ต่อเป็นสายเดียวกัน ข้อสอบชุดนี้แยก CarryIn ออกมาเป็นอีกสาย เลยต้องตอบสี่ช่อง
ช่องไหน “ไม่ว่าจะเป็น 0 หรือ 1 Result ก็เหมือนเดิม” ใส่ x — ในวงจรนี้มีแค่ CarryIn ตอนที่ไม่ได้เลือก adder (AND, OR, NOR) · ส่วน Ainvert/Binvert ห้ามเป็น x เพราะทุก operation ใช้ a′ และ b′
เนื้อหาเต็มอยู่ในบท Arithmetic for computers I สไลด์หน้า 27–34 และ Datapath and control I หน้า 25–28
| ข้อ | ALUOp | Funct | Goal | Ainv | Binv | CarryIn | Operation |
|---|---|---|---|---|---|---|---|
| 2.1 | 00 | xxxxxx | add | 0 | 0 | 0 | 10 |
| 2.2 | 01 | xxxxxx | subtract | 0 | 1 | 1 | 10 |
| 2.3 | 10 | 100000 | add | 0 | 0 | 0 | 10 |
| 2.4 | 10 | 100010 | subtract | 0 | 1 | 1 | 10 |
| 2.5 | 10 | 100100 | AND | 0 | 0 | x | 00 |
| 2.6 | 10 | 100101 | OR | 0 | 0 | x | 01 |
| 2.7 | 10 | 100111 | NOR | 1 | 1 | x | 00 |
| 2.8 | 10 | 101010 | slt | 0 | 1 | 1 | 11 |

ข้อนี้มีสองตาราง — ตาราง 3 คือ RTL ของแต่ละ state (เติมเองในกระดาษ ไม่มีคะแนน แต่เป็นทางไปสู่คำตอบ) และ ตาราง 4 คือค่าสัญญาณควบคุมทุกเส้นของ main control (มีคะแนน) · ใช้ 0 แทน don’t care ของสัญญาณ แต่ opcode ใช้ xxxxxx — ถ้าอาจารย์ย้ายสายเข้า MUX หรือเปลี่ยนรหัส ALUOp ตัวเลขในตารางจะเปลี่ยนทั้งหมด จึงต้องคิดจากรูปทุกครั้ง


single-cycle machine ทำหนึ่งคำสั่งจบในหนึ่ง clock ทำให้ clock ต้องยาวเท่าคำสั่งที่ช้าที่สุด (lw) และต้องมี adder กับ memory หลายชุด · multicycle แบ่งคำสั่งเป็นหลายขั้น ขั้นละหนึ่ง clock ใช้ ALU ตัวเดียวและ memory ตัวเดียวซ้ำได้ในคนละ clock โดยมี register ภายในอย่าง IR และ ALUOut คอยเก็บผลระหว่างขั้น
| State | ทำอะไร | ใช้กับ |
|---|---|---|
| 0 | fetch: IR ← Mem[PC] และ PC ← PC + 4 พร้อมกัน | ทุกคำสั่ง (เหมือนกันหมด) |
| 1 | คำนวณหลัก: ผลของ ALU เก็บลง ALUOut (หรือ j เขียน PC แล้วจบเลย) | แยกตาม opcode |
| 2 | ปิดงาน: เขียน register / อ่าน-เขียน memory / beq ตัดสินว่าจะกระโดดไหม | ทุกคำสั่งยกเว้น j |
เพราะไม่มี A, B, MDR ค่าจาก register file จึงวิ่งตรงเข้า ALU ได้เลย และ lw อ่าน memory แล้วเขียนลง register ได้ใน state 2 รอบเดียว
| สัญญาณ | ชนิด | หน้าที่ |
|---|---|---|
| PCWrite | write enable | เขียน PC แน่ๆ (fetch, j) |
| PCWriteCond | write enable | เขียน PC เฉพาะเมื่อ ALU ให้ Zero = 1 (beq) |
| MemRead / MemWrite | enable | อ่าน/เขียนหน่วยความจำ |
| IRWrite | write enable | เก็บคำสั่งที่อ่านได้ลง IR (มีแค่ตอน fetch) |
| RegWrite | write enable | เขียน register file |
| IorD | MUX 2 ขา | address ของ memory มาจาก PC (คำสั่ง) หรือ ALUOut (ข้อมูล) |
| ALUSrcA | MUX 2 ขา | ALU ขา A = PC หรือ Reg[rs] |
| ALUSrcB | MUX 4 ขา | ALU ขา B = Reg[rt], 4, signext, signext<<2 |
| ALUOp | 2 บิต | บอก ALU control ว่าให้บวก ลบ หรือดู funct (ตาราง 1) |
| PCSource | MUX 3 ขา | PC ใหม่ = ผล ALU สด, ALUOut, หรือ jump address |
| RegDst | MUX 2 ขา | register ปลายทาง = rt (I-type) หรือ rd (R-type) |
| MemtoReg | MUX 2 ขา | ข้อมูลที่เขียนลง register = ALUOut หรือข้อมูลจาก memory |
ALU result คือค่าที่ ALU กำลังคำนวณ ใน clock นี้ · ALUOut คือค่าที่ ALU คำนวณไว้ เมื่อ clock ก่อน — fetch ใช้ ALU result (PC+4 คำนวณเสร็จใน clock เดียวกัน) แต่ beq ใช้ ALUOut เพราะ branch target ถูกคำนวณไว้ตั้งแต่ state 1
เนื้อหาเต็มอยู่ในบท Datapath and control II สไลด์หน้า 2–8
| Step | j | beq | R-type | lw | sw |
|---|---|---|---|---|---|
| 0 | IR ← Mem[PC]; PC ← PC + 4 IorD=0, MemRead, IRWrite, ALUSrcA=0, ALUSrcB=01, ALUOp=00, PCSource=00, PCWrite | ||||
| 1 | PC ← {PC[31:28], IR[25:0], 00} PCSource=10, PCWrite | ALUOut ← PC + (signext(IR[15:0]) << 2) ALUSrcA=0, ALUSrcB=11, ALUOp=00 | ALUOut ← Reg[rs] op Reg[rt] ALUSrcA=1, ALUSrcB=00, ALUOp=10 | ALUOut ← Reg[rs] + signext(IR[15:0]) ALUSrcA=1, ALUSrcB=10, ALUOp=00 | |
| 2 | — | if (A == B) PC ← ALUOut ALUSrcA=1, ALUSrcB=00, ALUOp=01, PCSource=01, PCWriteCond | Reg[IR[15:11]] ← ALUOut RegDst=1, MemtoReg=0, RegWrite | Reg[IR[20:16]] ← Mem[ALUOut] IorD=1, MemRead, RegDst=0, MemtoReg=1, RegWrite | Mem[ALUOut] ← Reg[IR[20:16]] IorD=1, MemWrite |
| State | Opcode | PCWrite | PCWriteCond | MemWrite | MemRead | IRWrite | RegWrite | PCSource | IorD | MemtoReg | RegDst | ALUOp | ALUSrcA | ALUSrcB | Next |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | xxxxxx | 1 | 0 | 0 | 1 | 1 | 0 | 00 | 0 | 0 | 0 | 00 | 0 | 01 | 1 |
| 1 | 000000 | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 0 | 0 | 0 | 10 | 1 | 00 | 2 |
| 1 | 000010 | 1 | 0 | 0 | 0 | 0 | 0 | 10 | 0 | 0 | 0 | 00 | 0 | 00 | 0 |
| 1 | 000100 | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 0 | 0 | 0 | 00 | 0 | 11 | 2 |
| 1 | 100011 | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 0 | 0 | 0 | 00 | 1 | 10 | 2 |
| 1 | 101011 | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 0 | 0 | 0 | 00 | 1 | 10 | 2 |
| 2 | 000000 | 0 | 0 | 0 | 0 | 0 | 1 | 00 | 0 | 0 | 1 | 00 | 0 | 00 | 0 |
| 2 | 000100 | 0 | 1 | 0 | 0 | 0 | 0 | 01 | 0 | 0 | 0 | 01 | 1 | 00 | 0 |
| 2 | 100011 | 0 | 0 | 0 | 1 | 0 | 1 | 00 | 1 | 1 | 0 | 00 | 0 | 00 | 0 |
| 2 | 101011 | 0 | 0 | 1 | 0 | 0 | 0 | 00 | 1 | 0 | 0 | 00 | 0 | 00 | 0 |
| Step | R-type | lw | sw | beq | j |
|---|---|---|---|---|---|
| 1 | IR ← Mem[PC]; PC ← PC+4 — IorD=0, MemRead, IRWrite, ALUSrcA=0, ALUSrcB=01, ALUOp=00, PCSource=00, PCWrite | ||||
| 2 | A ← Reg[rs]; B ← Reg[rt]; ALUOut ← PC + (signext << 2) — ALUSrcA=0, ALUSrcB=11, ALUOp=00 (คิดเผื่อ beq ไว้ก่อนทุกคำสั่ง) | ||||
| 3 | ALUOut ← A op B ALUSrcA=1, ALUSrcB=00, ALUOp=10 | ALUOut ← A + signext ALUSrcA=1, ALUSrcB=10, ALUOp=00 | if (A==B) PC ← ALUOut ALUSrcA=1, ALUSrcB=00, ALUOp=01, PCSource=01, PCWriteCond | PC ← jump address PCSource=10, PCWrite | |
| 4 | Reg[rd] ← ALUOut RegDst=1, MemtoReg=0, RegWrite | MDR ← Mem[ALUOut] IorD=1, MemRead | Mem[ALUOut] ← B IorD=1, MemWrite | — | — |
| 5 | — | Reg[rt] ← MDR RegDst=0, MemtoReg=1, RegWrite | — | — | — |
ความต่างหลัก: 5 state มี register A, B, MDR คั่น ทำให้แต่ละขั้นสั้นลง (clock เร็วขึ้น) แต่ใช้จำนวน clock มากกว่า — R-type 4, lw 5, sw 4, beq 3, j 3 clock

ให้ลากสายเชื่อม IR, Barrel Shifter และ Register File ให้ทำคำสั่ง srl ได้ พร้อมระบุบิตทุกเส้นที่คลุมเครือ — ข้อนี้มาจากส่วน “Version 3” ของบท multicycle ที่เพิ่มคำสั่ง sll/srl เข้าไป ตัวที่อาจารย์เปลี่ยนได้ง่ายคือชนิดคำสั่ง (sll, srlv) และลำดับชั้นของ shifter
srl rd, rt, shamt ทำ R[rd] = R[rt] >> shamt (เลื่อนขวาแบบ logical เติม 0 ทางซ้าย) เป็น R-type: opcode = 0, rs = 0 (ไม่ใช้), rt = ค่าที่จะเลื่อน, rd = ปลายทาง, shamt = IR[10:6] คือจำนวนบิต, funct = 0x02
การเลื่อนคือการเดินสายใหม่ (rewiring) — เลื่อนขวา 1 บิตก็แค่ต่อบิต 1 ของ input ไปบิต 0 ของ output ต่อไปเรื่อยๆ แล้วเติม 0 · barrel shifter ต่อวงจรเลื่อนคงที่ 1, 2, 4, 8, 16 ไว้ 5 ชั้น แต่ละชั้นมี MUX เลือกว่าจะ “เลื่อน” หรือ “ผ่านตรง” · เลขใดๆ 0–31 เขียนเป็นผลบวกของ 1, 2, 4, 8, 16 ได้เสมอ (คือเลขฐานสอง 5 บิต) บิตที่ j ของ shamt จึงคุมชั้นที่เลื่อน 2j
ตัวอย่าง shamt = 13 = 01101₂ ⇒ ชั้น >>1 เลื่อน, >>2 ผ่าน, >>4 เลื่อน, >>8 เลื่อน, >>16 ผ่าน ⇒ รวม 1 + 4 + 8 = 13
มีพอร์ตอ่าน 2 ชุด (Read register → Read data) และพอร์ตเขียน 1 ชุด (Write register, Write data, RegWrite) — สาย register number กว้าง 5 บิต สาย data กว้าง 32 บิต
เนื้อหาเต็มอยู่ในบท Arithmetic for computers I สไลด์หน้า 35–36 และ Datapath and control II หน้า 8
| ต่อจาก | ไปที่ | ขนาด |
|---|---|---|
| IR[20:16] (rt) | Read register 1 | 5 บิต |
| Read data 1 | Data in ของ barrel shifter | 32 บิต |
| IR[6] | s0 (ชั้น >>1) | 1 บิต |
| IR[7] | s1 (ชั้น >>2) | 1 บิต |
| IR[8] | s2 (ชั้น >>4) | 1 บิต |
| IR[9] | s3 (ชั้น >>8) | 1 บิต |
| IR[10] | s4 (ชั้น >>16) | 1 บิต |
| Data out | Write data | 32 บิต |
| IR[15:11] (rd) | Write register | 5 บิต |
| ค่าคงที่ 1 (จาก control) | RegWrite | 1 บิต |
ใน Lab ด้านล่าง กด “วาดสายเฉลย” เพื่อดูภาพการต่อสายแบบเดียวกับที่ต้องวาดในกระดาษ


ข้อ 5.1 เป็นการคำนวณเวลา · ข้อ 5.2–5.10 ให้บอกชื่อของปัญหาหรือวิธีแก้จากสถานการณ์ — ตัวเลข register, clock หรือชนิดคำสั่งในโจทย์เปลี่ยนได้ แต่ชื่อที่ต้องตอบมีอยู่ไม่กี่คำ สิ่งที่ต้องฝึกคืออ่านสถานการณ์แล้วรู้ว่าเป็นแบบไหน










แบ่งการทำคำสั่งเป็น 5 stage — IF (fetch คำสั่ง) · ID (decode + อ่าน register) · EX (ALU) · MEM (อ่าน/เขียน data memory) · WB (เขียนผลกลับ register) แล้วให้หลายคำสั่งซ้อนเวลากันแบบซักผ้าทีละตะกร้า ตะกร้าแรกเข้าเครื่องอบ ตะกร้าที่สองก็เข้าเครื่องซักได้เลย
Latency ของคำสั่งเดียวไม่ได้ลดลง (ยังใช้ 5 clock) แต่ throughput เพิ่มขึ้นเป็นเกือบ 1 คำสั่งต่อ clock ⇒ speedup เข้าใกล้จำนวน stage เมื่อมีคำสั่งเยอะๆ
| ชนิด | เกิดเพราะ | วิธีแก้ |
|---|---|---|
| Structural hazard | ฮาร์ดแวร์ชิ้นเดียว สองคำสั่งต้องใช้ใน clock เดียวกัน (เช่น memory ตัวเดียว) | เพิ่มฮาร์ดแวร์: แยก instruction/data memory หรือ I-cache/D-cache · หรือ stall |
| Data hazard | คำสั่งหลังต้องใช้ค่าที่คำสั่งก่อนหน้ายังเขียนไม่เสร็จ | Forwarding (bypassing) · ถ้าไม่ทัน (load-use) ต้อง stall · compiler ช่วยด้วย code scheduling |
| Control hazard | ยังไม่รู้ผลของ branch จึงไม่รู้ว่าต้อง fetch คำสั่งไหน | stall · ตัดสิน branch ให้เร็วขึ้น (ย้ายไป ID) · branch prediction แล้ว flush ถ้าเดาผิด |
ALU คิดผลเสร็จตอนจบ EX จึงส่งต่อให้ EX ของคำสั่งถัดไปทันพอดี แต่ lw ได้ข้อมูลตอนจบ MEM ซึ่งเป็น clock เดียวกับที่คำสั่งถัดไปอยู่ใน EX แล้ว — ต้องส่งข้อมูล “ย้อนเวลา” ซึ่งทำไม่ได้ จึงต้องพักคำสั่งถัดไป 1 clock ก่อนแล้วค่อย forward
เนื้อหาเต็มอยู่ในบท Datapath and control III สไลด์หน้า 2–20 และ 37–64
lw และอยู่ติดกัน ⇒ Load-use data hazard| ข้อ | คำตอบ | เหตุผลสั้นๆ |
|---|---|---|
| 5.1 | 1 คำสั่ง = 5 clock = 5 ns 10 คำสั่ง = 14 clock = 14 ns 1,000,000 คำสั่ง = 1,000,004 clock ≈ 1 ms | (5 + n − 1) × 1 ns · ถ้าใช้ period ตามที่โจทย์พิมพ์ (1 µs) ก็จะเป็น 5 µs, 14 µs, 1,000,004 µs — เขียนเป็นจำนวน clock กำกับไว้เสมอ |
| 5.2 | Structural hazard | MEM ของ Inst. 1 กับ IF ของ Inst. 4 ใช้ memory ตัวเดียวกันใน clk 4 |
| 5.3 | Control hazard (branch hazard) | ยังไม่รู้ผล beq แต่ต้อง fetch คำสั่งถัดไปแล้ว |
| 5.4 | Data hazard (RAW: read after write) | ori ต้องใช้ $s0 ก่อนที่ addi จะเขียนเสร็จ |
| 5.5 | Forwarding (bypassing) | ส่งผลจาก EX/MEM เข้า ALU ตรงๆ |
| 5.6 | Load-use data hazard | ข้อมูลจาก lw มาไม่ทัน EX ของคำสั่งถัดไป แม้มี forwarding |
| 5.7 | Stall (ใส่ bubble / pipeline interlock) | หยุดคำสั่งไว้ 1 clock |
| 5.8 | Code scheduling (instruction reordering) | คอมไพเลอร์สลับลำดับคำสั่งที่ไม่ขึ้นต่อกัน |
| 5.9 | Control hazard | เดาผล branch เพื่อไม่ต้องรอ |
| 5.10 | Structural hazard (การแย่งใช้หน่วยความจำ) | มี I-cache กับ D-cache แยกกัน IF กับ MEM จึงเข้าถึงพร้อมกันได้ และ cache ที่เร็วทำให้เข้าถึงหน่วยความจำเสร็จใน 1 clock |

หน่วย control มีชุดเดียวอยู่ที่ ID แต่ pipeline ทำงาน 5 คำสั่งพร้อมกัน — โจทย์ถามว่าอะไรทำให้ EX, MEM, WB ได้สัญญาณของคำสั่งที่ตัวเองกำลังทำอยู่ ไม่ใช่ของคำสั่งที่อยู่ใน ID ตอนนั้น คำตอบสั้นแต่ต้องเขียนให้ครบกลไก
Pipeline register (IF/ID, ID/EX, EX/MEM, MEM/WB) คั่นระหว่าง stage ทุกคู่ ทำหน้าที่ “ถือ” ทุกอย่างที่คำสั่งนั้นยังต้องใช้ใน stage ถัดๆ ไป ทุก clock มันจะส่งของต่อไปข้างหน้าพร้อมกันทั้งหมด จึงทำงานหลาย stage พร้อมกันได้โดยข้อมูลไม่ปนกัน
| Register | ข้อมูลที่ถือ | สัญญาณควบคุมที่ถือ |
|---|---|---|
| IF/ID | คำสั่ง (instruction), PC + 4 | — (ยังไม่ decode) |
| ID/EX | ค่า Reg[rs], Reg[rt], immediate ที่ sign-extend แล้ว, เลข rs/rt/rd, PC + 4 | EX (RegDst, ALUOp, ALUSrc) · M · WB |
| EX/MEM | ผล ALU, Zero, branch target, ค่าที่จะ store, เลข register ปลายทาง | M (Branch, MemRead, MemWrite) · WB |
| MEM/WB | ข้อมูลที่อ่านจาก memory, ผล ALU, เลข register ปลายทาง | WB (RegWrite, MemtoReg) |
สังเกตว่าแม้แต่ เลข register ปลายทาง ก็ต้องเดินตามไปถึง MEM/WB — ถ้าใช้เลขจาก IF/ID ตอน WB จะได้เลขของคำสั่งอื่น (สไลด์ “Corrected Datapath for Load” แก้จุดนี้)
Hazard detection unit ตรวจ load-use แล้วสั่ง stall โดยบังคับสัญญาณควบคุมที่จะเข้า ID/EX เป็น 0 · Forwarding unit เทียบเลข register ใน EX/MEM, MEM/WB กับ ID/EX แล้วเลือกทางลัดให้ ALU
เนื้อหาเต็มอยู่ในบท Datapath and control III สไลด์หน้า 21–36 และ 47–56
ข้อสอบแต่ละข้อมาจากบทเหล่านี้ — ข้อ 1–2 และ 4 จาก Arithmetic I · ข้อ 3 จาก Datapath II · ข้อ 5–6 จาก Datapath III · บทที่เหลือเป็นพื้นฐานที่ต้องเข้าใจก่อน