Finals

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 29

Architecture!

Chapter 3: CPU Arithmetic


How MUL and DIV really works!

Addition-Subtraction
เราอาศัย 2’s complement ในการคิดบวกลบ และเราจะต้ องดูวา่ มัน overflow ได้ หรื อไม่ด้วย

x y Operation Overflow
+ + Addition Possible, roll to negative
+ - Addition Impossible
- - Addition Possible, to positive
+ + Subtraction Impossible
+ - Subtraction Possible, to negative
- - Subtraction Impossible

Multiplication
เราคูณฐานสองแบบเด็กๆ เลย แบบทางขวาเนี่ย พอเข้ าใจง่ายมัย้

Start Multiplicand (64)


Shift Left

Set product = 0

ALU (64) Multiplier (32)

1 0
Product (64) Control Shift Right

Multiplicand (32)
Shift
1 bit

Shift
1 bit ALU (32)

32 ? No Product (64) Control


Shift Right

Yes
ตัวอย่างการคูณ แสดงดังตารางนี ้

Iteration Operation y x Product Operation x Product (z)


No. (Slow) (Fast)
0 Initialize 0011 0000 0010 0000 0000 Initialize 0010 0000 0011
1 add 0011 0000 0010 0000 0010 add (high) 0010 0010 0011
x<<1 0011 0000 0100 0000 0010 z>>1 0010 0001 0001
y>>1 0001 0000 0100 0000 0010
2 add 0001 0000 0100 0000 0110 add (high) 0010 0011 0001
x<<1 0001 0000 1000 0000 0110 z>>1 0010 0001 1000
y>>1 0000 0000 1000 0000 0110
3 nop 0000 0000 1000 0000 0110 nop 0010 0001 1000
x<<1 0000 0001 0000 0000 0110 z>>1 0010 0000 1100
y>>1 0000 0001 0000 0000 0110
4 nop 0000 0001 0000 0000 0110 nop 0010 0000 1100
x<<1 0000 0010 0000 0000 0110 z>>1 0010 0000 0110
y>>1 0000 0010 0000 0000 0110
จะเห็นว่าแบบ Fast (แบบที่เอา hardware ตัวล่างมา implement) เร็ วกว่าแบบ Slow ที่ใช้ Hardware แบบบน

(สีแดง: ตาแหน่งที่ถกู operate, สีเขียว: การพิจารณาเลือกคาสัง่ )

Signed Multiplication
ทาได้ โดยการ

 จา sign ไว้
 แปลงลบเป็ นบวกให้ หมดก่อน
 คูณปกติ
 แล้ วแปลง sign กลับ

Implementation
ใน MIPS ผลการคูณจะถูกเก็บไว้ ใน HI กับ LO การจะเอาค่าออกมาต้ องใช้ คาสัง่ mfhi, mflo เพื่อเอามาไว้ ใน register ของเรา

Division
Start
Divisor (64)

64 Shift Right

ALU (64) Quotient (32)

64
Remainder (64) Control 0/1 LSB

False True +/- test

Divisor (32)
Shift 1
Shift 0 64

ALU (32)
>>1
64
>>
R(32) | Q(32) << Control
write

33 ? +/- test

End

ลองมาทาการหารกันบ้ างดีกว่า

Iteration Operation Q Divisor R/Dividend Operation R|Q D Status


0 Initialize 0000 0010 0000 0000 0111 Initialize 0 0000 0111 0010
1 Subtract 0000 0010 0000 1110 0111 Compare 0 0000 0111 0010 FAIL
Fail: Undo 0000 0010 0000 0000 0111 RQ<<1 (0) 0 0000 1110 0010
Q << 1 (0) 0000 0010 0000 0000 0111
D >> 1 0000 0001 0000 0000 0111
2 Subtract 0000 0001 0000 1111 0111 Compare 0 0000 1110 0010 FAIL
Fail: Undo 0000 0001 0000 0000 0111 RQ<<1 (0) 0 0001 1100 0010
Q << 1 (0) 0000 0001 0000 0000 0111
D >> 1 0000 0000 1000 0000 0111
3 Subtract 0000 0000 1000 1111 1111 Compare 0 0001 1100 0010 FAIL
Fail: Undo 0000 0000 1000 0000 0111 RQ<<1 (0) 0 0011 1000 0010
Q << 1 (0) 0000 0000 1000 0000 0111
D >> 1 0000 0000 0100 0000 0111
4 Subtract 0000 0000 0100 0000 0011 Compare 0 0011 1000 0010 OK
Q << 1 (1) 0001 0000 0100 0000 0011 Subtract 0 0001 1000 0010
D >> 1 0001 0000 0010 0000 0011 RQ<<1 (1) 0 0011 0001 0010
5 Subtract 0001 0000 0010 0000 0001 Compare 0 0011 0001 0010 OK
Q << 1 (1) 0011 0000 0010 0000 0001 Subtract 0 0001 0001 0010
D >> 1 0011 0000 0001 0000 0001 RQ<<1 (1) 0 0010 0011 0010
เป็ นอันเสร็ จสิ ้นการหาร จะเห็นว่าการหารทางขวาทาได้ เร็ วกว่าทางซ้ าย ทังนี ้ ้ ทางขวานันใช้
้ comparator ในการตรวจสอบค่า (เป็ น Verilog
implementation ของผู้เขียนเองจึงยังไม่ได้ แก้ ไข ที่จริ งต้ องใช้ การลบแล้ วตรวจสอบ sign bit) สาระสาคัญคือ การหารปกติจะทาการ shift 2
ครัง้ ซึง่ ช้ ากว่าแบบเร็ วที่ใช้ การ shift เพียงครัง้ เดียวต่อรอบ โดยการหารด้ วยฮาร์ ดแวร์ ใหม่นี ้ไม่ทาให้ จานวนรอบเพิ่มขึ ้นด้ วย

จริ งๆ แล้ วต้ องใช้ R|Q = 2n+1 bits ถ้ าเราต้ องการหารเลข n bits และเราต้ องเก็บผลลัพธ์ ตามที่ขีดเส้ นใต้ ไว้ อีกด้ วย (ถ้ าไม่ทาแบบนี ้คาตอบ
อาจไม่เท่ากัน)

Signed Division

การหารคิดเครื่ องหมาย หลักการคล้ ายการคูณ คือต้ องแปลงเครื่ องหมายก่อน-หลังการดาเนินการ ทัง้ นี ้ ดังที่เห็นในภาพ เราต้ องทาให้
เครื่ องหมายของเศษตรงกับเครื่ องหมายของตัวตังเสมอ

Interlude: Verilog Programming


เสนอเฉพาะหลั ก การทั่ ว ไปเท่ าที่ จาเป็ น
การเขียน Verilog ทาคล้ ายๆ C + VHDL

Modules
แบ่งโค้ ดของเราเป็ น module ข้ างในก็ทางานไปตามเรื่ องตามราว แต่ modules เหล่านี ้จะทางานตลอดเวลาตามพฤติกรรม ไม่มีการเรี ยก
ฟั งก์ชนั เหมือนภาษาโปรแกรมมิงที่เรารู้จกั ต่อไปนี ้จะเป็ นตัวอย่างการเขียนวงจร NAND และผลลัพธ์ที่ได้

module mynand(in1,in2,out);
input in1,in2;
output out;
assign out = ~(in1&in2)
endmodule

module foo(p,q,p_b,q_b,o)
input p,q,p_b,q_b
output o
wire w, w_b
mynand nand1(.out(w), .in1(p), .in2(q)) ;
mynand nand2(.out(w_b), .in1(p_b), .in2(q_b)) ;
mynand nand3(.out(o), .in1(w), .in2(w_b)) ;
endmodule
Signals in Verilog
สัญญาณมีสรี่ ูปแบบ คือ 0, 1, Z, X ซึง่ สามารถนามา “ผสม” กันได้ โดยจะมีผลดังตารางต่อไปนี ้

0 1 X Z
0 0 X X 0
1 X 1 X 1
X X X X X
Z 0 1 X Z

Bus
บัส คือการรวมสัญญาณย่อยๆ หลายๆ เส้ นเข้ าด้ วยกัน การประกาศและใช้ งานบัสนันคล้
้ ายอาร์ เรย์ แต่มีลกู เล่นแปลกๆ ที่เราสามาถทากับบัส
ได้ ด้วย เช่น การต่อสัญญาณทางขนาน (concatenation)

Assign and Use Buses


input [5:0] a,b; //gives 6-line bus called a, and another 6-line bus called b

a[5:1] = {a[4:0],1’b0}; //equivalent to shift left

Concatenation
Concatenate “once”, for example: assign a[63:0] = {b[31:0], c[31:0]};

Concatenate “many”, for example: assign y = {3{a[3:0]},b[3:2],2'b00};

Sequential Programming (always @)


input [7:0] in1;
input [7:0] in2;
reg [7:0] out;
input select;

always @ (select) begin //ให้ ทางานบล็อกนี ้เมื่อค่า select เปลีย่ นแปลง


if (select==1'b0)
out = in1; //สังเกตว่า out เป็ น reg เพราะ always นัน้ เป็ นการทางานแบบ sequential ทางานครัง้ เดียวก็ผา่ นไป ไม่ได้
เป็ นสายไฟค้างไว้ตลอดเหมื อนข้างนอก จึ งต้องมี เมมโมรี มาจาค่า
else
out = in2;
end

reg [7:0] counter;


always @ (posedge clk) //ให้ ทางานบล็อกนี ้เมื่อค่า clk เปลีย่ นแปลงแบบขอบขาขึ ้น
counter = counter + 1;
สังเกต: เราใช้ begin-end เมื่อคาสัง่ ใน block มีหลายคาสัง่ เท่านัน้
Case
Case เป็ นคาสัง่ หนึง่ ที่สาคัญในการเขียน behavioral modules เช่น decoder ในตัวอย่างต่อไปนี ้

module what_is_me(a,y);
input [2:0] a;
output [7:0] y;
reg [7:0] y;
always @ (a)
case(a)
3'h0 : y = 8'h01;
3'h1 : y = 8'h02;
3'h2 : y = 8'h04;
3'h3 : y = 8'h08;
3'h4 : y = 8'h10;
3'h5 : y = 8'h20;
3'h6 : y = 8'h40;
3'h7 : y = 8'h80;
endcase
endmodule

Chapter 4: Data Path & Control


Hard part…

Hardware Designs

Single-Cycle Design
เป็ นแบบที่เราเคยเรี ยนมา คือมี latch (memory element) ที่เป็ น sequential ผสมกับ combinational logic circuit โดยการออกแบบเป็ น
worst-case design คืออะไรใช้ เวลามากสุด (delay time มาก) ก็จะเป็ นตัวกาหนด clock interval ที่เล็กที่สดุ เท่าที่ทาได้ เช่น วงจรใช้ เวลาวิ่ง
ผ่านเกตรวม 100ns ก็ห้ามทา clock ที่เร็ วกว่านัน้

Pipeline Design
ไม่ใช่ท่อส่งแก๊ ส! แต่เป็ นการออกแบบโปรเซสเซอร์ ที่สงู ขึ ้นมา ทาให้ ทางานได้ อย่างมีประสิทธิภาพมากขึ ้น โดยโยนงานต่อเป็ นทอดๆ และรับ
งานใหม่เข้ ามาอย่างรวดเร็ ว ทาให้ รับงานใหม่ได้ โดยไม่ต้องรองานเก่าวิ่งจนจบ (แค่วิ่งไปให้ พ้นทางก็พอ)

Understanding MIPS
 32 registers
 Instruction Format
o R-type
o I-type
o J-type
 Instruction Types
o ALU/Logic
o Load/Store
o Branch/Jump

How to Design
มีหลายตัว แต่ละอันก็มีความเหมาะสมต่างกัน เช่น หากเราลองออกแบบด้ วย Finite State Machine (FSM)

 32 registers = 32 sequential elements


 แต่ละอันกว้ าง 32 bits
 order of FSM น่าจะประมาณ 2^32*2 states โอ้ ว!
 PC ก็อีก 32 bits

อะไรๆ ก็มากไปหมด จึงไม่เหมาะกับการทางานที่ทวั่ ไป (general-purpose) เพราะมันต้ องทาทุกอย่าง บนทุก states นอกจากนี ้ FSM มีระดับ
การประมวลผลที่ต่าเกินกว่าจะมาออกแบบอะไรแบบนี ้ได้ คิดดูว่าเช็ควงเล็ บยังทาไม่ได้ เลย ต้ องไปใช้ พวก push-down automata + ทา
stack (ยังมี Turing Machine ที่มีความสามารถในการคานวณสูงสุดอีก แต่จะเรี ยนใน Theory)

โครงสร้ างที่จะมาจาลอง Turing Machine แบบง่ายๆ เกิดจาก Memory ต่อกับ ALU ที่มี select มาเลือกคาสัง่ อีกที ส่วนตัว memory ก็ตอ่ กับ
memory control ซึง่ ทังหมดก็
้ รับคาสัง่ มาจาก control อีกที

ข้ อจากัดของ Turing Machine ก็มีเหมือนกัน เช่น Halting Problem (ปั ญหาที่ถามว่าโปรแกรมหนึง่ ๆ จะทางานจนจบหรื อไม่)

How Single-Cycle Data Path works


ภาพประกอบให้ ดทู ี่ภาคผนวก A

Single-Cycle CPU ทางานโดยเราไปดึงคาสัง่ มา คาสัง่ นันก็


้ จะมีสามชนิดคือ R, I, J โดยแต่ละแบบจะไปใช้ งาน CPU ในส่วนต่างๆ กันออกไป

การทางานของ Single-Cycle CPU จะต้ องไม่ให้ ความเร็ วคล็อกเร็ วไปกว่าความเร็ วที่ช้าที่สดุ ของวงจร (อย่าลืมว่าอุปกรณ์ทกุ ชิ ้นในวงจรมี
propagation delay เสมอ ดังที่ได้ เรี ยนไปแล้ วใน Digital Systems)

เราแบ่ง CPU ออกเป็ นห้ าส่วน (ตามภาคผนวก B) โดยแบ่งเป็ น

 Instruction Fetch (IF) มีหน้ าที่ดงึ คาสัง่ ออกมาจาก Instruction Memory (ที่เก็บคาสัง่ ของเรา)
 Instruction Decode (ID / REG) มีหน้ าที่แปลงคาสัง่ และดึงค่าจาก Register ที่ต้องใช้
 Execution (EXE / ALU) มีหน้ าที่ทาการคานวณล้ วนๆ
 Memory (MEM) มีหน้ าที่ store / load ค่าจาก memory
 Write-Back (WB) มีหน้ าที่เขียนค่าใหม่ลงใน Registers (เช่น ค่าที่โหลดมา หรื อผลจากการคานวณ)

เราจะเห็นได้ อย่างชัดเจนว่า คาสัง่ บางคาสัง่ ก็จะใช้ CPU ไม่ครบทุกส่วน เช่น add ไม่ใช้ MEM เลย เพราะว่าไม่ได้ เก็บค่าหรื อดึงค่าใดๆ ออก
จากหน่วยความจา หรื อ beq ที่ไม่มีการเขียนค่ากลับหรื อเข้ า memory เลย เพราะเราโยนผลการบวกออกมาเป็ นการแปลง program counter
ทันทีโดยไม่มีการบันทึกค่า เป็ นต้ น

หลักการคิด clock interval ทาโดยเอาเวลาทางานทังหมดมาบวกกั


้ น คือ สมมติว่า IF = 5ns, ID = 3ns, EXE = 6ns, MEM = 5ns, WB =
4ns เราก็จบั บวกกันได้ 23ns นี่เป็ นคาบเวลาเล็กสุดที่เราจะใช้ กบั CPU รุ่นนี ้ได้
Pipelining
ไม่ใช่ทอ่ ส่งแก๊ ส แต่เป็ นท่อที่จะทาให้ งานของเราสะดวกรวดเร็ วขึน้

ตัวอย่างหนึง่ ที่นา่ สนใจคือการซักผ้ า สมมติเราอยูห่ อแล้ วรวมผ้ ากันซัก ผ้ าต้ องแยกกลุม่ กัน (จะได้ ไม่ปนกัน) ทาทีละตะกร้ าไป ถ้ ามัวแต่ รอกัน
มันก็จะช้ า ซึง่ ไอ้ การรอกันที่วา่ ก็คือหลักของ Single Cycle ทุกประการ

แบบซ้ ายคือแบบ Single-Cycle เราต้ องรองานจบก่อน กับแบบขวาคือ Pipeline เราโยนผ้ าใส่เครื่ องต่อไปได้ เลย จะเห็นว่าแบบซ้ ายใช้ เวลาต่อ
cycle ทังหมด
้ 30+40+20 = 90 นาที ในขณะที่แบบขวาใช้ เวลาต่อ cycle ทังหมด
้ max(30,40,20) = 40 นาที

แบบขวาเร็ วกว่า แต่มีข้อจากัดอยู่

 ถ้ าคาสัง่ ที่ทามีไม่มาก ความคุ้มค่าจะไม่ชดั เจน


 ทายาก เพราะอาจเกิดปั ญหาว่างานเก่ายังไม่ได้ ข้อมูลออกมา งานใหม่ต้องเอาข้ อมูลนันมาด่
้ วนที่สดุ
 ฯลฯ

Clock Trigger Organization


เราต้ องจัด clock trigger ให้ เหมาะสม ระหว่าง “บล็อก” นันเราให้
้ ตีนาฬิกาที่ posedge ไปแล้ ว ข้ างในแต่ละก้ อนก็ต้องเป็ น negedge แทน
สรุปออกมาจะได้ วา่

 PC, regfile: negedge (เพราะเราต้ องให้ เวลามันในการทางานให้ เสร็ จก่อน)


 IF/ID, ID/EX, EX/MEM, MEM/WB: posedge (เป็ นปกติของมัน)

Data Hazard
Data Hazard จะเกิดขึ ้นเมื่อเราต้ องการข้ อมูลทันที แต่มนั ยังไม่มีให้ เพราะคาสัง่ ก่อนหน้ ายังทาไม่เสร็ จ เช่น

add $1,$2,$3
ori $8, $1, 0xff
สังเกตว่า $1 สาหรับ ori มันยังไม่มา เพราะเมื่อ ori วิ่งเข้ า EXE นัน้ add ยังอยูใ่ น MEM (ยังไม่ WB ค่าใหม่จะไม่มา!)

วิธีการแก้ Data Hazard มีดงั นี ้

 Stalling คือเราหยุดการทางานโปรแกรมไว้ ก่อน รอจนค่ามาที่ๆ เราต้ องใช้ แล้ วค่อยลุยต่อ วิธีนี ้เสียเวลาแต่ไม่ต้องแก้ ฮาร์ ดแวร์ เลย
หากเราคิดๆ ดูจะได้ วา่
o ถ้ าคาสัง่ ใช้ คา่ ใน regfile ต่อกันทันที จะเสีย 2 cycles
o ถ้ ามีคาสัง่ อื่นมาคัน ่ กลาง (ที่ไม่ไปทาให้ เกิด stalling เพิ่ม) จะเสีย 1 cycle
 Forwarding
o คือการยินยอมให้ สง่ ค่าบางค่าไปยัง pipeline stage ที่ต้องการได้ ทน
ั ทีโดยไม่ต้องรอจบ cycle เราทาโดยการช็อตขาแล้ ว
เอา MUX มาดักไว้ แล้ วใช้ control signal ในการเลือกค่า
o การจะดูวา่ Forwarding ได้ หรื อไม่นนเราควรเขี
ั้ ยนแผนภาพเวลาด้ วย โดยการ forward จะต้ องไม่ให้ มีการวิ่งย้ อนเวลาได้

ID/EX EX/MEM MEM/WB

MUX
ForwardA

ALU
Reg File
MUX
Memory
(data)

MUX
ForwardB

Rt
MUX

Rd EX/MEM.RegisterRd
Rt
Rs

Forwarding Unit MEM/WB.RegisterRd

ตัวอย่างของ Forwarding

เรามาลองเปรี ยบเทียบกันว่า forwarding แล้ วดีขึ ้นหรื อไม่ กับโจทย์สนๆ


ั ้ นี ้

lw $1, 4($3)
addi $2,$1,10
sub $2,$2,$1
 Without Forwarding
o lw ทางาน + 2 bubble เพราะมีคนรอ $1 มาติดๆ
o addi ทางาน + 2 bubble เพราะมีคนรอ $2 มาติดๆ
o sub ทางาน
o รวมเป็ น 7 clocks
 With Forwarding
o lw แล้ วยังไงก็ต้อง stall 1 clock เพราะเข้ ากรณี lw-stall
o addi แล้ วใช้ forwarding
o sub รับ forwarding มา
o รวมเป็ น 4 clocks
Control Hazard
เราแก้ ปัญหาเรื่ องข้ อมูลเข้ าช้ าได้ แล้ ว ปั ญหาต่อไปคือถ้ าคาสัง่ ที่ n เป็ น branch (beq) แล้ วต่อมาคาสัง่ ที่ n+1 ต้ องทาอะไรต่อล่ะทีนี ้? ในการ
ทางานของ branch นันมั ้ นมีทางเลือกสองทางคือ จะ fall through (ไปบรรทัดต่อไป) หรื อจะกระโดดไปยังตาแหน่งที่อยูใ่ นคาสัง่ เลยดี

beq $8, $9, L1


addi $2, $2, 1 <-- fall-through
sub $3, $2, $4
L1:
lw $3, 16($2) <-- target
กว่าเราจะรู้วา่ ต้ องทา addi หรื อ lw นันก็
้ ต้องรอร้ อรอ รอจน beq มันทา EXE เสร็ จ (ไป MEM นูน่ แล้ ว) เพิ่งจะได้ fetch คาสัง่ ใหม่มา (ช้ าโคตร)
สรุปว่าเราเสียไป 2 clocks ฟรี ๆ

เราสามารถแก้ ปัญหานี ้ได้ โดยใช้ Quick Compare ซึง่ เป็ นการยิงผลลัพธ์จากการเช็คค่าเท่าไม่เท่าในขัน้ EXE กลับมาที่ระบบ update PC เลย
แบบนี ้ก็จะเร็ วขึ ้นไปอีก เพราะคาสัง่ ใหม่จะเข้ ามาในขณะที่ beq อยูใ่ น EXE เท่านัน้ (เสียน้ อยลงเหลือ 1 clock)

อีกวิธีหนึง่ ที่นิยมใช้ กนั คือ Delayed Branching ซึง่ อาจกาจัดการเสีย clock ได้ ทงหมด!!!
ั้ นี่ไม่ใช่วิธีทางฮาร์ ดแวร์ แต่เราอาศัยความสามารถ
ของ MIPS Compiler มาช่วย เช่นเรามีคาสัง่ ภาษาซีวา่ :

z=1;
if (x==a) y=5;
else y=6;
เราแปลงเป็ น Assembly ได้ เป็ น
addi $3, $0, 1
bne $1, $4, L1
addi $2, $0, 5
j L2
L1: addi $2, $0, 6
L2:
แบบนี ้ช้ า เพราะ bne ต้ องเสียเวลา 1 clock ว่างๆ ไป เราจะสลับบรรทัด addi แรกกับ bne

bne $1, $4, L1


addi $3, $0, 1 <- delayed
addi $2, $0, 5
j L2
L1: addi $2, $0, 6
L2:
มันจะเร็ วขึ ้น เพราะเราสามารถยัด addi ไว้ ท้าย bne ได้ เลย เพราะมี "ความปลอดภัยของค่า" อยู่ คือมันจะไม่เขียนทับกันเองแน่นอน คือใน
เมื่อมัน branch ก็เสียคาสัง่ แน่ๆ ก็ลองเอามาไว้ ท้าย branch ก่อน โดยเอามาวางใน delayed slot เช่นในกรณีนี ้เราทาคาสัง่ สีแดง (z=1) ไป
พร้ อมๆ กับการ evaluate branching ไปเลยก็ได้
พูดสรุปกันง่ายๆ คือ เอาคาสัง่ ก่อนหน้ า branch ไปไว้ หลัง branch (ในแง่ของลาดับการทางานของซีพีย)ู ก็จะได้ ทาไปพร้ อมๆ กันเลย ทังนี
้ ้ นี่
เป็ นกระบวนการของ MIPS Compiler ไม่ใช่ MIPS CPU เพราะ MIPS CPU ไม่มีระบบตรวจ control hazard ในตัว

ว่าแต่ที่เรี ยนมานานแล้ วน่ะ แล้ วทาไม jal ถึงเก็บ pc+8? นัน่ ก็เป็ นเพราะใน pc+4 มี delayed slot อยูแ่ ล้ วไง

อีกวิธีที่นา่ สนใจอย่างยิ่งคือ Branch Prediction ซึง่ จะเป็ นการ “จา” ไว้ วา่ ที่ผา่ นมานันเราได้
้ take branch รึ เปล่า เพราะการทางานคาสัง่ บาง
ประเภทเช่น for-loop นันเรามี
้ แนวโน้ มที่จะกลับเข้ าไปบ่อยๆ

ถ้ าเรามีคา่ 1 bit ไว้ เก็บว่าแต่ละบรรทัดจะทางานซ ้าหรื อไม่ เราก็จะเดาได้ ง่ายขึ ้นว่าจะต้ องทางานหรื อไม่ โดยถ้ า branch ก็ใส่ 1 ถ้ าไม่ branch
ก็ใส่ 0 ก่อนจะทาการ branch เราก็โหลดคาสัง่ ที่เหมาะสมมาต่อรอไว้ เลย ถ้ าผิดก็ flush คาสัง่ ทิ ้งไปจากระบบ

แต่ในกรณี loop สองชันนั


้ นมั
้ นใช้ ไม่ได้ เราจะให้ โอกาสแก่ CPU เพิ่มขึ ้น โดยการเพื่มจานวน states เป็ น 4 เพื่อที่จะได้ ยงั ไม่ต้อลเปลี่ยน
สถานะการเดาแม้ ว่าจะผิดแค่ครัง้ เดียว คือ เราจะใส่ “น ้าหนัก” ความเชื่อให้ มนั เป็ น Strong Take, Weak Take, Weak Not Take และ
Strong Not Take ตามลาดับ

Not Taken
T Taken
T

Taken

Not Taken Taken

Taken
NT Not Taken
NT

Not Taken

Chapter 5: Memory
Age of Memory
หน่วยความจามีการพัฒนามาโดยตลอดตังแต่ ้ ยคุ 50’s โดยสมัยนันใช้
้ Core Memory เหนี่ยวนาสนามแม่เหล็กเพื่อเก็บค่า (เกร็ ด: เวลาเครื่ อง
บึ ้มแล้ วมันขึ ้นว่า “Core Dump” ก็หมายถึงกระบวนการโบราณนี ้ คือมัน dump ข้ อมูลมาจาก core memory นัน่ เอง)

ในยุค 70’s ได้ มีการพัฒนาใช้ semiconductor มาทาหน่วยความจา ขนาดของ memory และราคาต่อหน่วยก็ลดลงเรื่ อยๆ

Memory is so expensive!
Memory Type Access Time Cost (Baht per GB) Typical Size in Market
SRAM 1ns 100000 Not for separate sale
DRAM 60ns 2000 4-8GB
Magnetic Disk 10ms 50 Up to 1.5TB-2TB
Solid-State Drive microseconds 500-1000 Up to 512GB (very expensive here!)
แต่ไม่วา่ อย่างไร ของดีมนั ก็ยงั แพงอยูว่ นั ยังค่า แถมเล็กอีกต่างหาก
แล้ วเราจะทาอย่างไรให้ ได้ สงิ่ ที่ทกุ คนต้ องการ?

 เร็ ว
 ใหญ่
 ถูก

มันเป็ นไปไม่ได้ ที่จะทาให้ ได้ ทงสามอย่


ั้ าง แต่เราหลอกผู้ใช้ ได้ อารมณ์ประมาณว่ารถเบนซ์ใส่เครื่ องเซียงกง

Memory Hierarchy
เป็ นผลจากการหลอกผู้ใช้ เราเอาของเร็ ว (SRAM Cache) ไว้ ใกล้ CPU มากที่สดุ เอาของที่ใหญ่แต่ช้าอยู่ห่างออกมาคือ DRAM และเอาของ
ใหญ่มากที่สดุ ไว้ หา่ งๆ คือ Hard Drive

มีหลักการสองข้ อที่ต้องรู้ คือ

 Temporal Locality
o โปรแกรมใช้ ข้อมูลก้ อนนี ้แล้ วมีแนวโน้ มใช้ อีก
 Spatial Locality
o โปรแกรมมักใช้ ข้อมูลใกล้ ๆ กัน

Caching
เปรี ยบเสมือนการสร้ างห้ องเก็บของเล็กๆ เก็บเครื่ องมือที่เราใช้ บอ่ ยที่สดุ จะได้ ไม่ต้องไปเบิก -คืนบ่อยๆ (หยิบเอง = 3 นาที, เบิก = 3 วัน?)

Cache

Main Memory

การ map แบบนี ้ก็เป็ นวิธีหนึง่ สมมติวา่ เราอยากได้ “กล่องสีเขียว” เราก็ดใู น cache ก่อนว่าของเขียวๆ ใช่กล่องสีเขียวที่เราต้ องการหรื อไม่ ถ้ า
เจอก็หยิบไปใช้ ไม่เจอก็ไปเบิกมาใส่ รูปแบบนี ้เป็ นการเก็บแบบอ้ างอิง modulo ซึง่ ก็เป็ นที่ใช้ กนั ทัว่ ไปอย่างหนึง่

Direct-Mapped Cache, and related calculations


การที่เราจะเรี ยกหาข้ อมูลเราจะต้ องทาเป็ นก้ อนละ 32 bits แล้ วแบ่งบาง bits ไปใช้ สาหรับการหา เช่น ถ้ าเรามี Cache ขนาด 4kB = 212
bytes หากเราเก็บ “บรรทัด” ละไบต์ เราก็ต้องมีครบ 212 บรรทัดไปด้ วย เพราะฉะนัน้ เราก็ต้องมี byte-index อยู่ 12 bits ที่เหลือ 32-12 = 20
bits ก็จะเป็ น “tag”
(1) Use Index to see which Cache Line to check

Tag (20) Index (12)

(2) Equal? Yes: HIT (get data), No: MISS (go to DRAM)

Index-1 V Tag (20) Data (8)

Index V Tag (20) Data (8)

Index+1 V Tag (20) Data (8)

Index+2 V Tag (20) Data (8)

...

ภาพข้ างต้ นเป็ นภาพแสดงโครงสร้ างข้ อมูล บรรทัดบนที่ลอยออกมาคือการประมวลค่าเพื่อเอาไปหาใน Cache ส่วนตารางๆ ข้ างล่างคือตัว
Cache เอง สังเกตการเก็บของมันว่า Index นันมี
้ อยูแ่ ล้ วโดยธรรมชาติ ไม่จาเป็ นต้ องเก็บ และแต่ละบรรทัดก็เก็บค่าไว้ 1 byte

แต่จริ งๆ แล้ วเราไม่นิยมเก็บค่าทีละไบต์ เรานิยมเก็บกันทีละ Word (4 byte) เพราะฉะนัน้ จานวน “บรรทัด” จะลดลงเหลือ ¼ ทาให้ จานวน
address bits ลดลงไป 2 bits… ไม่จริ ง!! เพราะเราก็ต้องเผื่อ address ไว้ เรี ยกตาแหน่งไบต์อยูด่ ี

(1) Use Index to see which Cache Line to check

Tag (20) Index (10) B

(2) Equal? Yes: HIT (get data), No: MISS (go to DRAM)
(3) Get by Byte Number

Index-1 V Tag (20) Data (8) Data (8) Data (8) Data (8)

Index V Tag (20) Data (8) Data (8) Data (8) Data (8)

Index+1 V Tag (20) Data (8) Data (8) Data (8) Data (8)

Index+2 V Tag (20) Data (8) Data (8) Data (8) Data (8)

ในสีแดงๆ นันเราเพิ
้ ม่ ก้ อน Data ให้ เป็ น Word (เราจะเรี ยกตามศัพท์ของ Memory ว่า Block เพราะต่อไปอาจมี block ที่ขนาดไม่ใช่ 4 byte)
และยก 2 bits จาก index มาให้ byte address แทน

นอกจากนี ้เรายังเพิ่มจานวน blocks per tag ได้ อีก เราจะพูดถึงในตัวอย่างต่อไป

Associative Cache
เพื่อลด Cache Miss เราจะเพิ่มจานวน Tags Per Line ขึ ้นมา ถ้ าเรามี 2 tags per line ก็จะเรี ยกว่ามันคือ “2-way Association” ปกติเรา
นิยมทา 4-way มากที่สดุ เพราะมีความสมดุลระหว่าง ”ความเร็ ว” กับ “ความชัวร์ ”

ทังนี
้ ้ L1 Cache ต้ องการความเร็ วสูงมาก มากขนาดว่า 4-way ก็ไม่นิยมใช้ เท่าที่ควร เรามาดูโจทย์กนั เลยดีกว่า

โจทย์: กาหนดให้ cache ขนาด 4kB เป็ นแบบ 4-way set associative และให้ มีจานวน blocks ต่อ 1 set เท่ากับ 16 จงคานวณหาจานวน
bits ของ address ขนาด 32 bit ที่ใช้ สาหรับ tag, byte offset, block offset และ index
แผนการ:

 เราทราบว่ามีข้อมูล 4096 = 212 bytes


 ข้ อมูลที่เราทราบ
12 10
o 2 bytes หมายความว่าได้ 2 blocks ทันที แปลว่าจะมี index รวมกันไม่เกิน 10 bits
4 6
o 16 blocks per set ก็หารไปอีก 2 เหลือ 2 sets หมายความว่าเราใช้ 6 index bits ในการเรี ยกหา set ที่ต้องการ
o คาว่า “4-way set associative” แปลว่า 4 tags per line ไม่มีความหมายในตัวเอง แต่จะได้ วา่
o 4 blocks per tag (เกิดจากการหาร 16/4) ซึง่ แปลว่ามี block offset ขนาด 2 bit
o ทราบอยูแ ่ ล้ วว่า 4 bytes per block หมายความว่าจะมี byte offset ขนาด 2 bit
 ตอบ
o Byte offset: 2 bits
o Block offset: 2 bits
o Index: 10-2-2 = 6 bits
o Tag: 32-10 = 22 bits

เสร็ จแล้ ว! นี่คือโครงสร้ างการเก็บ cache และการจัด address ของเรา

Index
Block
Byte

Tag (22)
(6)
4096 Bytes * 1/16 Sets/Block * 1/4 Block/Bytes = 64 Sets

...

Index-1 V Tag (22) Block Block Block Block Tag (22) Block Block Block Block

Tag (22) Block Block Block Block Tag (22) Block Block Block Block

Index V Tag (22) Block Block Block Block Tag (22) Block Block Block Block

Tag (22) Block Block Block Block Tag (22) Block Block Block Block

Index+1 V Tag (22) Block Block Block Block Tag (22) Block Block Block Block

Tag (22) Block Block Block Block Tag (22) Block Block Block Block

...

Memory Trade-Off

Large Block Size


แต่ การโหลดค่ามาใส่ต้องโหลดมาทีละบล็อก

 Pros
o เพิ่ม Spatial Locality = Less cache miss โดยเฉพาะใน array
 Cons
o ลดขนาดของ entries ใน cache ถ้ าโปรแกรมไม่มี spatial locality จะทาให้ miss มากแทน
o warm-up นาน ต้ อง optimize ...
o critical-word first คือ เอาของจาเป็ นที่สดุ มาก่อน ที่เหลือค่อยๆ ตามมา
o early restart

Associative vs. Direct-Mapped


Associative ลดการ miss ได้ มากกว่า direct-mapped

 Direct-mapped = 10.3% miss


 2-way = 8.6% miss
 4-way = 8.3% miss
 มากกว่านี ้เริ่ มไม่ค้ มุ แล้ ว เพราะใช้ เวลาเท่ากับจานวน block

When Cache Misses in MIPS Pipeline


เราต้ อง stall เมื่อ cache miss ทาให้ เสีย clock ไปเท่ากับจานวน stall cycles ซึ่งแปรผันตาม memory access time (ช้ ามาก ประมาณ
100x cache time)

load/store instruction Cycles


 CPI for cache hit = 1 (ก็ถกู แล้ ว)
 CPI for cache miss = 1+stall cycles

Example
กรณี CPU clock rate = 500MHz ถ้ ารันโปรแกรมที่มี ALU 50%, Branch 20%, Load-Store 30% โดยที่ Load-Store มี miss rate = 5%,
miss stall time = 60ns (30 cycles!)

แล้ ว CPI เฉลีย่ = ? (จงหา!)

เรายังไม่ร้ ู CPI ของคาสัง่ แต่ละชนิดเลย เรามากาหนดก่อน

 ALU CPI = 1 (เพราะทาง่ายสุด ทานายก็ง่าย คานวณก็ง่าย forward ไปมาได้ หมด)


 Branch CPI = ??? (เกิด control hazard ทาให้ เสีย clock ได้ เราไม่ร้ ูวา่ Tekken Taken หรื อ Not Taken)
o กรณีเติม delay slot ได้ (เติม Delay slot ด้ วยคาสัง่ ที่มีประโยชน์) -> CPI = 1
o กรณีเติม delay slot ไม่ได้ (คือใส่ nop แทน) -> CPI = 2 (เลือกใช้ 2)
 Load/Store CPI
o Cache Hit = 1
o Cache Miss = 1 + 60ns-in-cycles = 31 cycles! (ถ้ าไม่ใช้ cache เลยก็ไม่ได้ miss อะไรก็จะเป็ น 30 cycles)

CPI ในกรณีที่ hit หมด ! (สุดยอดความเร็ ว)

ในกรณีที่ miss หมด (เหมือนกับว่าไม่มี cache เลย ทุกอย่างต้ อง load/store ผ่าน memory หมด)
สังเกตได้ วา่ ต่างกันเกือบ 10 เท่า !! เมพไหมล่ะ เมพไหมล่ะ !!

CPI กรณีที่มี cache เราต้ องแยกกรณี hit กับ miss

บรรทัดสองกับบรรทัดแรกจะเหมือนกัน แต่เราเขียนยุบๆ แค่นนเอง


ั้

เทียบแบบไม่มี cache จะได้ speed-up ประมาณ 6 เท่า

Write Through & Write Back Cache


การสัง่ store สิง่ ที่มีอยูใ่ น cache จะทาให้ cache กับ main memory เก็บค่าไม่ตรงกัน มีการแก้ สองวิธีคือ

 Write Through = เมื่อ store ก็ update memory ด้ วย


o ตรงไปตรงมา แต่กิน bandwidth มหาศาลมาก
 Write Back = Update เฉพาะตอนจะถีบ entry ออกจาก cache เท่านัน้ เช่น เวลาที่เราต้ องดึง entry ใหม่มาทับ (ตรวจจับโดย dirty
bit)
o ใช้ งานได้ เพราะการอ้ าง memory ใดๆ มันก็ต้องผ่าน cache อยูแ
่ ล้ ว ดังนัน้ เราก็ทาทุกอย่างใน cache นัน่ แหละ พอจะทิ ้ง
ค่าออกจาก cache ค่อย copy กลับไปที่ main memory

Type of Misses
 Cold Miss เกิดจากค่ามันไม่มีอยูใ่ นตอนแรก เป็ น miss ที่เลีย่ งไม่ได้
 Conflict Miss เกิดจากปั ญหาเรื่ อง indexing บังคับให้ คา่ ทับกันไปมา มีเฉพาะใน cache ที่ไม่ใช่ fully associative cache
 Capacity Miss คือ miss ที่ไม่ได้ เกิดจากสองอันแรก เกิดเฉพาะใน fully associative cache

Try a Problem!
Consider the following function:

void vec_add (int x[16], int y[16], int s[16])


{
int i;
for(i=0;i<16;i++)
s[i] = x[i]+y[i];
for(i=0;i<16;i++)
s[i] = s[i]+1;
}
Simple direct-mapped cache: 128 byte cache, 16 byte blocks. Miss rate?

แต่ละ block = 4 words (เพราะ MIPS จะมองค่าเป็ น word เป็ นหลัก)

byte offset 2 bit (4 bytes per word), block offset 2 bit (4 words per block) และเติม address อีก 3 bit จะได้ อ้างได้ ครบ 128 bytes
Addresses

address of x: 0xc0 (tag = 1, index = 4)


0000 0000 0000 0000 0000 0000 1 : 100 : 00 : 00

y: tag=4, index=0
0000 0000 0000 0000 0000 0010 0 : 000 : 00 : 00

s: tag=5, index=2
0000 0000 0000 0000 0000 0010 1 : 010 : 00 : 00

หลักการทางาน:

 โหลด x[0~4] - cold miss (cache ว่างแต่แรกจึงเป็ น compulsory miss)


 โหลด y[0~4] - cold miss
 โหลด s[0~4] - cold miss
 ใช้ งานไปเรื่ อย
 จะมา miss อีกทีตอนใช้ x[4], y[4], s[4] ก็ miss สามที แล้ วมาไล่อพั ค่าต่อ
 พอจะใช้ x[8] ก็โหลดไปใส่ใน cache อีก
 ปั ญหาเกิดตอนโหลด y[8] เพราะ index = 0 ทาให้ y[8] ต้ องลงที่ index 2 ซึง่ จะไปทับ s[0~4]

Multiwh… I mean Multicore


มีที่มาจาก Dance-Hall Architecture ($ คือ cache)

p1 p2 p3 p1 p2 ... pn

$ $ $ $ $ $

Interconnect Network Bus

Mem Mem Mem Shared Mem

ซ้ าย: Dance-Hall Architecture, ขวา: Bus Architecture

Issues with multicore


Cache Coherence

คือปั ญหาที่เกิดจากการมี shared mem แต่ทกุ คนต่างโหลด cache ตัวเองของใครของมัน พอมีการเซฟค่ากลับลงใน cache ทาให้ ค่าที่ได้ ไม่
สัมพันธ์กนั
A: เอาเป็ นว่า x=5 นะ
B,C: อื ้อ

2 นาทีผา่ นไป...

A: เซฟค่าล่ะนะ x=7

อีกห้ องหนึง่ ...

B: อ้ อ x=5 สินะ เมื่อกี ้จดไว้


C: ตรงนี ้ x=1…

3 นาทีผา่ นไป

เจ้ านาย: เฮ้ ย ทาไมงานพวกแกผิดหมดเลยวะ! นี่มนั อะไรกัน!


A: ผมบอกไอ้ B,C ว่า x=5 นะครับ แล้ วทาไม...
B: ก็ตอนทาถึงตรงนี ้ x มันเปลีย่ นเป็ น 7 แล้ วโว้ ยไอ้ ฟาย
C: เฮ้ ย บ้ าแล้ ว 1 ไม่ใช่รึไง!
เจ้ านาย: พวกแกคุยงานยังไงวะ! ไปทามาใหม่!

อารมณ์ประมาณนัน้ ทางแก้ หนึง่ ที่นา่ ลองคือ write-through ให้ หมดเลย แต่ปัญหาคือไม่สามารถไป update cache ของเพื่อนๆ ได้ ด้วย แล้ ว
จะทายังไงให้ cache มีการ update ได้ เหมือนกันทุกคน?

Multicore Challenges

1. ใช้ ประโยชน์จากหลายๆ core


2. การบริ หาร cache และ memory ให้ มีมมุ มองเดียวกัน
3. Memory Consistency
Epilogue
Revision: Verilog
module whatisme(clk,A,B,r)
input A;
input clk, r;
output B;
reg B;
always @ (posedge clk) //start working on positive edge of clk
if (r)
B = 0;
else
B = A;
endmodule;

สรุ ป หน้ าที่ของมันคือ ทุกๆ clock positive edge ถ้ า r = 0 ให้ B = 0, otherwise B = A ซึ่งก็คือบทบาทเดียวกับ D-Flip-Flop นัน่ เอง เราจะ
ทาโจทย์ตอ่ ไปโดยเอา DFF (ต่อไปนี ้เรี ยก whatisme ว่า DFF นะ) มาสร้ างต่อ

D SET
Q
D Q
clk

CLR Q

module whatisme2 (out, in, clk, reset);


output out;
input in, clk, reset;
wire q;
DFF state(clk, out, q, reset);
assign out = in ^ q;
endmodule;

ผลที่ได้ คือ มี DFF อันนึงอยู่ข้างใน ผลลัพธ์ D ที่ออกมา การทางานของมันคือมันจะเปลี่ยนค่า 1-0-1-0 ทุกครัง้ ที่มีสญ
ั ญาณ 1 ใส่เข้ ามา
(เพราะมัน xor กับ memory) เรี ยกสิง่ นี ้ว่า Parity Checker

SET out
D Q q
clk

CLR Q
reset

in
ต่อๆๆ
module whatisme3 (clk, enable, reset, out)
input clk, reset, enable;
output out;
reg out;
always @ (posedge clk)
if(reset)
out = 0;
else if (enable)
out = !out;
endmodule;

ถ้ า reset แล้ ว out = 0 ไม่เช่นนันถ้


้ า enable ให้ กลับค่า out ถ้ าสังเกตการทางาน จะพบว่ามันสลับค่าขึ ้นลงขึ ้นลงเมื่อเรา enable ไว้ ความถี่
output จะลดลงเหลือครึ่งหนึง่ ซึง่ คุณสมบัตินี ้ปรากฏใน T-Flip-Flop และ Divide-by-two counter

เราจะเรี ยกมันว่า divby2counter


module divby4Counter ( clk, enable, reset, out)
divby2Counter beef (clk, enable, reset, out) //เราหมายถึงไอ้กอ้ นเมื่อกี้
always @ (posedge out_temp)
if (reset)
out = 0;
else if (enable)
out = !out_temp;
endmodule;

ก็คือเราครอบลงไปอีกชันอะ

Solutions to Homework 4: Datapath (and Data Hazard)

Problem 1
รูปแบบคาสัง่ ที่เขาต้ องการพิจารณาคือ

lw $2, 4($1)
sw $2, 8($1)

เราจะสร้ าง forwarding network มาช่วย (กาจัด Stall) ได้ หรื อไม่ อย่างไร

ตอบ: ได้ โดยทา forwarding WB -> MEM


Clocks

lw $2, 4($1) IF REG MEM WB

sw $2, 8($1) IF REG MEM WB

This forwarding is possible!

Problem 2
การทางานของ CPU นัน้ สัญญาณแต่ละตัวมีหน้ าที่ตา่ งกันไป

Example RegDst Branch MemRead MemtoReg ALUOp MemWrite ALUSrc RegWrite


add 1 0 0 0 10 0 0 1
lw 0 0 1 1 00 0 1 1
addi 0 0 0 0 10 0 0 1
sw 0 0 0 0 00 1 1 0
beq X 1 0 X 01 0 0 0

Problem 3
สัญญาณ control จะกระจายไปตาม state ต่างๆ

ถ้ าสัญญาณ 1 stuck at zero จะทาให้ เขียนลง regfile ไม่ได้ มีผลกับ

 All ALU Instructions


 load

Cut 2 จะมีผลกรณี data hazard ที่ต้องใช้ forwarding ในการแก้ ไข ส่วน Cut 3 กระทบกับคาสัง่ branch / jump ทังหมด

คาสัง่ ที่ทางานได้

sw $2, 0($10)
sw $3, 4($10)
sw $4, 8($10)

คาสัง่ ที่มีปัญหากับ fault 1

lw $2, 10($1)
add $3, $2, $4
sub $4, $3, $1

คาสัง่ ที่มีปัญหากับ fault 2


add $1, $2, $3
add $4, $1, $2
add $5, $4, $4

คาสัง่ ที่มีปัญหากับ fault 3 (อะไรก็ตามที่มี branch)

addi
subi
beq

New Problem!
พิจารณาชุดคาสัง่ ต่อไปนี ้

I1 = lw $1, 40($6)
I2 = add $2, $3, $1
I3 = add $1, $6, $4
I4 = sw $2, 20($4)
I5 = and $1, $1, $4

ถ้ าส่งคาสัง่ ชุดนี ้เข้ าไปใน MIPS 5-stage pipeline ที่ไม่มี hazard detection และไม่มี forwarding จงใส่ nop เพื่อให้ ชดุ คาสัง่ นี ้ทางานถูกต้ อง
(ใส่ให้ น้อยที่สดุ )

lw $1, 40($8)
nop (no operation)
nop
add $2, $3, $1
add $1, $6, $4
nop
sw $2, 20($4)
and $1, $1, $4

add ต้ องรอให้ lw วิ่งมาจน WB ก่อนจึงจึเข้ า EXE ได้ นัน่ คือต้ องห่างกัน 2 instruction และ add กับ sw ต้ องรอให้ add วิ่งไปถึง MEM ก่อน
SW ถึงจะเริ่ มได้ นัน่ คือห่างกัน 1 instruction

ทาต่อ ถ้ ามี hazard detection + forwarding จงเติม pipeline diagram และบอกว่าจะจบในกี่ cycle

T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11
I1 IF ID EXE MEM WB
I2 IF ID STALL EXE MEM WB
I3 IF STALL ID EXE MEM WB
I4 IF ID EXE MEM WB
I5 IF ID EXE MEM WB
แล้ วถ้ าไม่มี hazard detection? ก็จะเกิดปั ญหาตอน execute I2 ต่อจาก I1 ทันที ค่า $1 จะ forward ไม่ทนั (เพราะมันไม่มีใครมาควบคุมว่า
ต้ อง stall เมื่อไหร่!)

ทังนี
้ ้ MIPS เป็ น in-order processor จึงมี data hazard ได้ แค่แบบเดียวคือ read-after-write (RAW)

Control Hazard
เป็ น Hazard ที่จะทาให้ ประสิทธิภาพของ pipeline ลดลงเนื่องจากไม่สามารถกาหนดทิศทางของคาสัง่ ต่อไปหลังคาสัง่ Branch ได้ แน่นอน

การแก้ ไข Control Hazard ใน MIPS มีไม่กี่วิธี

Delayed Branch
 เป็ นงานของ compiler ที่จะเรี ยงโค้ ดให้ สงิ่ ที่ไม่เกี่ยวกับ branch มาอยูต่ อ่ จาก branch
 Hardware จะไม่ทาอะไร

พิจารณาชุดคาสัง่ ต่อไปนี ้

L1: lw $1, 40($6)


beq $2, $3, L2 ; Taken
add $1, $6, $4
L2: beq $1, $2, L1 ; Not Taken
sw $2, 20($4)
and $1, $1, $4

Case I: add กับ sw ไม่ใช่ delayed branch ที่ถกู ต้ อง ก็ต้องใส่ nop หลัง branch ทังหมดเลย

T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11
I1 IF ID EXE MEM WB
I2 IF ID EXE MEM WB
nop IF ID EXE MEM WB
I4 IF ID EXE MEM WB
Branch Taken!
nop IF ID EXE MEM WB
I5 IF ID EXE MEM WB
I6 IF ID EXE MEM WB
ต่อไปเป็ น Case II: add กับ sw เป็ น delayed branch
T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11
I1 IF ID EXE MEM WB
I2 IF ID EXE MEM WB
I3 IF ID EXE MEM WB
Delayed Slot!
I4 IF ID EXE MEM WB
I5 IF ID EXE MEM WB
I6 IF ID EXE MEM WB
ลองมาดูเคสต่อไปกันดีกว่า!
lw $1, 8($2) //Stall Warning!
add $2, $1, $5
sub $8, $9, $10 //Stall Warning!
addi $7, $8, 50
beq $9, $10, tgt
lw $10, 8($1) //Stall Warning!
tgt; or $12, $10, $10
นี่เป็ นโค้ ดที่มีปัญหาเรื่ องการลาดับโปรแกรม เราต้ องสลับลาดับโปรแกรม หาวิธีจดั การกับปั ญหา hazards ให้ ได้ มากที่สดุ

ปั ญหาคือ beq -> lw -> tgt เพราะมันใช้ $10 หมดเลย แนวคิดที่ปลอดภัยที่สดุ คือเราเอาสิ่งที่อยู่ก่อน branch และเป็ นสิ่งที่ยงั ไงก็ต้องทามา
ใช้ เป็ นการแก้ control hazard ส่วนการแก้ data hazard ทาได้ ง่ายมากโดยการสลับ I2 <-> I3

โปรแกรมใหม่จะเป็ น

lw $1, 8($2)
sub $8, $9, $10
add $2, $1, $5
beq $9, $10, tgt
addi $7, $8, 50
lw $10, 8($1) //Stall Warning!
tgt; or $12, $10, $10
แต่ก็ยงั มีปัญหา (อย่าคิดว่ามันง่าย!) เราต้ องแก้ โดยการเอา add มาไว้ ในตาแหน่งคัน่ lw กับ or แต่วา่ เราต้ องทาให้ add ทางานไม่วา่ จะ
taken หรื อ not taken เราจึงต้ องย้ ายตัว tgt ขึ ้นมาไม่ให้ โดนข้ าม โปรแกรมที่ถกู ต้ องจึงเป็ น

lw $1, 8($2)
sub $8, $9, $10
beq $9, $10, tgt
addi $7, $8, 50
lw $10, 8($1)
tgt: add $2, $1, $5
or $12, $10, $10
ทังนี
้ ้ ในบางกรณีไม่สามารถทาได้ จริ งๆ ก็มี ต้ องยอมรับและปล่อยให้ stall ไป

Memory & Cache

Basics of Cache
 เราจะอ้ างถึง cache กันเป็ น block (1 block มีได้ หลาย byte ที่อยูใ่ นรูปของ 2^n)
 ในแต่ละ block จะมีจานวน byte ที่จะถูก address ได้ เป็ นกาลังของสอง (1,2,4,8,...)
o ปกติเราจะนิยมให้ byte/block มากกว่า 1 เพราะ spatial locality ซึง่ ชัดเจนมากในระดับไบต์ เพราะตัวแปรมักเป็ นตัวแปร
ขนาด 4 byte
 สาหรับ n-way set associative cache ใน 1 set จะมี n blocks

An Example
32-bit address, 128kB Direct-mapped cache. 16 bytes per block.

 Offset Bits = 4 (because: 16 bytes per block)


 Index Bits = 17-4 = 13 bits (because 128k / 16 = 213)
 Tag Bits = 32-4-13 = 15 bits (it’s what remains)

Offset
Tag (15) Index (13) (4)

Block 0 Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte

Block 1 Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte

Block 2 Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte

...

Block 213-1 Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte Byte

แต่เอาเข้ าจริ งๆ เรานิยมแบ่งข้ อมูลให้ เป็ น Words มากกว่า (เวลาเราทางานส่วนใหญ่ก็ 32-bit) ดังนัน้ เมื่อเรามี 4 bytes มาติดๆ กัน เราก็จะ
รวมมันเป็ น 1 Word ดังนัน้ เราจะต้ อง ”เสียสละ” Offset ของเรามาเป็ น “Byte Offset” 2 bit และเรี ยกที่เหลือว่า “Word Offset” แทน

Tag (15) Index (13) W B

Block 0 Word Word Word Word

Block 1 Word Word Word Word

...

Block 213-1 Word Word Word Word

New Problem!
Address 32 bits, 8-way set associative

# blocks = 16

# bytes per block = 32

จงหา

 Offset bits
 Index bits
 Tag bits
 Size of Cache

Size of Cache ไม่ยาก ก็


ถามว่า offset เท่าไหร่ตอบง่ายมาก เพราะเรามี 32 = 25 bytes per block เราจึงต้ องใช้ 5 บิตในการอ้ างถึงทังหมด
้ ตอบ 5 offset bits

มันเริ่ มยาก เพราะนี่เป็ น 8-way set associative คาว่า 8-way หมายถึงเรามี 8 blocks per set ดังนัน้

เนื่องจากเรามีแค่ 2 sets เราใช้ บิตเดียวก็มากเพียงพอที่จะเลือกว่าจะเอา set ไหน จึงตอบว่า 1 bit สาหรับ index bits และที่เหลือจะ
กลายเป็ น tag โดยอัตโนมัติ คือ 32-5-1 = 26

มาดูโครงสร้ างที่เสร็ จแล้ วกันดีกว่า

Offset
Tag (26) I (5)

Set 0 Block Block Block Block Block Block Block Block

Set 1 Block Block Block Block Block Block Block Block

Another problem! Arrrgh!


Address ขนาด 10 บิท, Cache มี 4 blocks, จานวน bytes/block = 4 และเป็ น 2-way set associative และแทนที่ block ด้ วย LRU

Access 0:10001101 1:10110010 2:10111111 3:10001100 4:10011100 5:11101001 6:11111110 7:11101001


Tag 0010001 0010110 0010111 0010001 0010011 0011101 0011111 0011101
Set 1 0 1 1 1 0 1 0
Offset 01 10 11 00 00 01 10 01
Acc. 0 B0 B1 Acc. 2 B0 B1 Acc. 4 B0 B1 Acc. 6 B0 B1
Set 0 Set 0 0010110 Set 0 0010110 Set 0 0010110 0011101
Set 1 0010001 Set 1 0010001 0010111 Set 1 0010001 0010011 Set 1 0011111 0010011
Least Recently Used!
Acc. 1 B0 B1 Acc. 3 B0 B1 Acc. 5 B0 B1 Acc. 7 B0 B1
Set 0 0010110 Set 0 0010110 Set 0 0010110 0011101 Set 0 0010110 0011101
Set 1 0010001 Set 1 0010001 0010111 Set 1 0010001 0010011 Set 1 0011111 0010011
ความหมายของคาที่ใช้ คือ

 4 bytes per block = 2 offset bits


 2-way set associative -> 2 blocks per set = ½ sets per block -> ½ sets per block * 4 blocks = 2 sets ดังนัน้ index 1 bit

Hit Ratio เราอยูท่ ี่ 25% เพราะ 8 access เราได้ hit 2 ครัง้


Appendix A: Single-Cycle Datapath and Control

MUX

ADD ADD

Shift
4
Left 2
RegDst

Branch
MemRead
Control MemtoReg
ALUOp
MemWrite
ALUSrc
RegWrite

Read
Instr[25:21]
Reg.1 Read
PC Read Address
Read data 1
Instr[20:16] Zero
Reg.2
Instr. 0
Read
data 2
Write 0 Result Address
Memory Instr[15:11]
MUX
Reg.
MUX
Read 0
Write
Data
Data MUX

Registers Write
Data

Sign
ALU
Instr[15:0] Extend
Control
(16->32)

Instr[5:0]

Instruction Signals
Instruction RegDst ALUSrc MemtoReg RegWrite MemRead MemWrite Branch ALUOp1 ALUOp2
R-Format 1 0 0 1 0 0 0 1 0
lw 0 1 1 1 1 0 0 0 0
sw X 1 X 0 0 1 0 0 0
beq X 0 X 0 0 0 1 0 1

Instruction Formats
R-Type 0 rs rt rd shamt funct
5 bits 5 bits 5 bits

Load/Store 35 or 43 rs rt address

Branch 4 rs rt address
6 bits 5 bits 5 bits 15 bits
Appendix B: Division of Regions in Single-Cycle and Pipelined CPU
0

MUX

ADD ADD

Shift
4
Left 2
RegDst

Branch
MemRead
Control MemtoReg
ALUOp
MemWrite
ALUSrc
RegWrite

Read
Instr[25:21]
Reg.1 Read
PC Read Address
Read data 1
Instr[20:16] Zero
Reg.2
Instr. 0
Read
data 2
Write 0 Result Address
Memory Instr[15:11]
MUX
Reg.
MUX
Read 0
Write
Data
Data MUX

Registers Write
IF ID/REG EXE/ALU Data
MEM WB
Sign
ALU
Instr[15:0] Extend
Control
(16->32)

Instr[5:0]

Hazard
Detection
FLUSH
WB
M
Control
0
U M WB
X EX M WB

4 <<2

M
U
M M
Instruction Registers = X
U PC Memory U
M Memory M
X X
U U
X X
Signed-
Extend

M
U
X

Forwarding
Unit

คาเตือน: ไม่รับประกันความถูกต้ อง สาหรับ Pipeline Diagram ดูได้ ที่ Patterson & Hennessy p.370
Boilerplate
เอกสารบันทึกนี ้บันทึกจากการสอนวิชา 01204225 Computer Architecture & Organization เฉพาะช่ วงหลังสอบกลางภาค โดย อาจารย์
ดร.ภารุจ รัตนวรพันธุ์ ภาควิชาวิศวกรรมคอมพิวเตอร์ มหาวิทยาลัยเกษตรศาสตร์ ในภาคปลาย ปี การศึกษา 2553

ผู้จดบันทึกไม่มีสิทธิใดๆ ในเนื ้อหารายวิชาและ/หรื อส่วนประกอบอื่นใดที่มาจากแหล่งภายนอก บันทึกนี ้มีวตั ถุประสงค์เพื่อการศึกษาเท่านัน้

แผนภาพส่วนใหญ่วาดให้ พอเพียงสาหรับการใช้ ในห้ องสอบเท่านัน้ และอาจไม่ครบถ้ วนตามแต่กรณี

จดบันทึกโดย LunaticNeko CPE23 และนาออกสูส่ าธารณะในวันที่ 27 พฤษภาคม 2554 หากต้ องการแจ้ งข้ อผิดพลาดใดๆ กรุณาอีเมล์แจ้ งที่
chawanat.n [at] gmail [dot] com (กรุณาอย่าใช้ ช่องทางอื่นแม้ จะทราบ เนื่องจากไม่ได้ ดแู ลทุกช่องทาง) จักเป็ นพระคุณยิ่ง

You might also like