[แปล+สรุป] Computer Architecture – ตอนที่ 2.1 Computer Functions

developer

บทความชุด: Computer Architecture and Organization

บทความนี้แปลจากวีดีโอรายวิชา Introduction to Computer Architecture
บรรยายโดย อาจารย์ชัยวัฒน์ สุเมธพงศ์ (ICT มหิดล)

ใน CPU มีอะไร? (ต่อ)

คราวที่แล้วเราพูดค้างเอาไว้เรื่อง CPU ซึ่งขอตัดจบแล้วบอกไว้ว่าจะมาพูดกันต่อในบล๊อกนี้เพราะเนื้อหายาวละเกิน เขียนไม่ไหว

ตอนนี้ขอassumeว่าทุกคนรู้จักรีจิสเตอร์แล้วนะ โอเค!

CPU แบ่งออกเป็น 2 ส่วนทำหน้าที่ประสานกันเพื่อให้คอมพิวเตอร์ทำงานไปได้ นั่นคือ...

  1. ALU (Arithmetic Logic Unit)
    หน่วยประมวลผลคณิตศาสตร์และโลจิค หรือเรียกง่ายๆ ว่า "เครื่องคิดเลข" ละกัน (ฮา) ในALUจะเต็มไปด้วยรีจิสเตอร์ที่เอาไว้คิดเลข ตั้งแต่ บวก ลบ คูณ หาร ม๊อด ซึ่งเป็นคำสั่งพื้นฐานแบบเดียวกับเครื่องคิดเลขเลย ไปจนถึงพวกที่เอาไว้คิดตรรกะศาสตร์พวก AND OR NOT XOR
    เจ้าส่วนนี้คิดเลขอะไรพวกนี้เก่งมาก แต่มันเป็นเหมือนกับ f(x) ฟังก์ชันเวลาเราเขียนโปรแกรม นั่นคือไม่ทำงานด้วยตัวเอง รอคนอื่นเรียกใช้อย่างเดียวเลย แล้วใครล่ะที่จะมาเรียกมัน คำตอบคือส่วนต่อไปที่เรากำลังจะพูดถึงของCPU...
  2. CU (Control Unit)
    หน่วยความคุมหลัก เทียบได้กับสมองของคอมพิวเตอร์ รีจิสเตอร์ในส่วนนี้คิดอะไรไม่ค่อยได้ (หมายถึงคิดเลขอะไรพวกนั้นนะ) แต่มันเก่งในเรื่องการควบคุมและจัดการ คิดง่ายๆ มันคล้ายๆ กับ Manager ผู้จักการของบริษัทนั่นแหละ
    เมื่อกี้บอกไปว่าALUรอคนอื่นมาเรียกใช้ ก็รอเจ้าCUนี่แหละ ที่จะคอยดูว่าโปรแกรมต้องทำงานอะไรบ้างแล้วยิงคำสั่งไปให้ALUคิดเรื่อยๆ

เอาล่ะ มาดูแผนผังของ CPU แบบคร่าวๆ กันอีกที

ในอาคีเทคแบบแรกที่วอน นิวแมนสร้างขึ้นมามีส่วนประกอบหลัก 3 ส่วนคือ CPU-Memory-I/O ซึ่งตัว CPU เป็นศูนย์กลาง คุยประสานงานให้ทั้งเมมโมรี่และ I/O ในตอนนี้เราจะยังไม่พูดถึง I/O นะเพราะเนื้อหามันอยู่บทหลังๆ ตอนนี้เอาแค่ CPU-Memory ให้รอดก่อน (หึหึ)

ภาพข้างบนเป็นโครงสร้างรีจิสเตอร์หลักๆ ใน CPU ซึ่งเป็นระดับคอนเซ็ปนะ หมายความว่าปัจจุบันพัฒนาไปไกลกว่านี้แล้ว แต่ไม่ว่าจะพัฒนายังไง ก็ขาดเจ้าพวกนี้ไม่ได้ล่ะ

  1. ALC (Arithmetic Logic Circuit)
    วงจรรวมสำหรับคิดเลขและโลจิค เป็นตัวหลักของ ALU ซึ่งจะทำงาน/จ่ายงานต่อให้กับ AC และ MQ
  2. AC (Accumulator)
    เคยสงสัยมั้ยว่าปุ่ม [AC]บนเครื่องคิดเลข มันย่อมาจากอะไร มันคือเจ้านี่แหละ "แอคคิวมูเลเตอร์" หรือตัว...เอ่อ ...คิดทำไทยไม่ออก ฮ่าๆ เอาเป็นว่ามันคือรีจิสเตอร์ที่เอาไว้เก็บคำตอบผลลัพธ์การบวก ลบ คูณ หาร บลาๆๆ พวกนั้น อ้อ แปลอย่างนี้ละกัน...

    ที่สำหรับสะสมค่า

    ลองคิดถึงเครื่องคิดเลข ไม่ว่าเราจะกดคำนวนเลขอะไรไปก็ตามมันจะไปโผล่บนหน้าปัทม์เครื่อง (ห้ามบอกว่ามันก็ต้องแสดงตรงนั้นอยู่แล้วนะ เออ รู้แล้ว!) แต่รู้มั้ยว่าค่าที่แสดงอยู่นั้นน่ะ คือค่าที่จะดูดมาจากค่าใน AC ของเครื่องคิดเลขเสมอ ดังนั้นปุ่มACบนเครื่องคิดเลขที่พอกดปุ๊บหน้าจอจะกลับเป็น 0 ใหม่นั่นก็คือ "ปุ่มล้างค่าในAC" นั่นเอง
    *Tip: เดี๋ยวต่อไปคุณจะเจอการพูดถึงคำสั่งพวก LOAD, STORE, ADD อะไรแบบนี้ เช่น LOAD x ไม่ต้องสงสัยว่าแล้วมันจะโหลดค่ามาใส่อะไร หรือADDหรือSTOREค่ากับอะไร ให้รู้ไว้เลยว่าทำกับ AC ทั้งหมด

  3. MQ (Multiple Quotient)
    บอกก่อนว่า quotient = remainder หรือพวกเศษจากการหารเผื่อใครที่แปลไม่ออก, ในการบวกกับลบเราไม่ต้องแคร์เรื่องขนาดข้อมูลคำตอบเท่าไหร่ เพราะใน Digital System เราเรียนมาแล้วว่าการ + - นั้นจะต้องทำโดยข้อมูลที่มีขนาด bit เท่ากัน เช่นเอาเลข8บิตมา ก็ต้องบวก/ลบกับข้อมูล8บิต และคำตอบก็ยังได้ข้อมูล8บิตออกมาเช่นเคย (ห้ามถามว่าเราเอา 1111 11112 + 1111 11112 มันจะเกิน8บิตนะ ใครถามตีเลย! ลืมเรื่อง Overflow ไปแล้วใช่มั้ย?) แต่สำหรับการคูณแล้วคำตอบมีสิทธิ์เกินได้ ส่วนการหารนั้นอาจจะไม่เกินก็จริงแต่มันมักจะมีเศษหรือquotientออกมา
    รีจิสเตอร์ MQ จะทำงานคู่กับ AC ในกรณีที่ทำ * และ / พวกเลขส่วนเกินที่ยังต้องเก็บไว้จะถูกดันมาใส่ไว้ใน MQ นี่แหละ
  4. MBR (Memory Buffer Register)
    เป็นรีจิสเตอร์ที่ทำหน้าที่เป็นตัวบัฟเฟอร์กลางระหว่าง CPU และเมมโมรี่ (บัฟเฟอร์คือไรอ่านที่หัวข้อข้างล่างนะ) ข้อมูลทุกตัวที่จะผ่านจากเมมโมรี่เข้ามายัง CPU หรือ CPUจะเขียนข้อมูลลงเมมโมรี่จะต้องผ่านรีจิสเตอร์ตัวนี้ เหมือนกับเป็นทางเข้า-ออกหลักของ data นั่นแหละ
  5. MAR (Memory Address Register)
    คล้ายๆ กับ MBR แต่แทนที่จะเป็น data จะเป็นตัวรับ-ส่ง address ของตำแหน่งเมมโมรี่แทน
  6. PC (Program Counter)
    โปรแกรมประกอบด้วยคำสั่งมากมายที่มาเรียงๆ กัน แต่คอมพิวเตอร์ไม่มีความจำ มันก็จะจำไม่ได้ไงล่ะว่าทำงานถึงคำสั่งไหนแล้ว เลยต้องมี PC เอาไว้เก็บตำแหน่งล่าสุดว่าโปรแกรมนี้รันถึงไหนแล้ว ชี้เป็น pointer นะ
  7. IR (Instruction Register)
    CPU ไม่ได้ต้องการอ่านแค่ data เข้ามาโปรเซส ต้องรู้ด้วยว่าตอนนี้จะให้ทำอะไร แปลว่ามันจะต้องไปอ่าน instruction เข้ามาด้วย (สลับกันอ่านกับ data .. ใครจำไม่ได้กลับไปดูเรื่อง Instruction Cycle อีกที) แต่ instruction เข้ามาไม่ใช่ในฐานะ data มันจะไม่เข้าไปอยู่ใน AC พวกนั้น เลยต้องมีรีจิสเตอร์เอาไว้เก็บมันด้วย ก็คือใช้เจ้า IR นี่แหละ
    ในบางกรณี instruction อาจจะมีขนาดใหญ่มาก ดังนั้น IR จะทำงานคู่กับ IBR (Instruction Buffer Register) เพื่อขยายขนาดการเก็บ instruction นะ เคสนี้จะคล้ายๆ กับ ACทำงานคู่กับMQล่ะ

Buffer มันคืออะไรอีกละเนี่ย?

บัฟเฟอร์เป็นหนึ่งในคอนเซ็ปที่สำคัญมากในคอมพิวเตอร์เลย ไม่เฉพาะวิชาฝั่งฮาร์ดแวร์เท่านั้นนะ ในการเขียนโปรแกรมกับภาษาระดับที่ยังไม่สูงมากกก เราก็ต้องมีความรู้เรื่องบัฟเฟอร์เล็กน้อยเพื่อจะเขียนโปรแกรมได้ เช่นตอนที่เขียนภาษาซี

char c1, c2;
scanf("%c", &c1);
scanf("%c", &c2);

ในภาษาซีเราเขียน scan ต่อกัน 2 ตัวกับตัวแปรที่เป็น char ไม่ได้เพราะจะมี char ของ [Enter] ค้างอยู่ในบัฟเฟอร์ ซึ่งต้องแก้โดย

char c1, c2, dummy;
scanf("%c", &c1);
scanf("%c", &dummy);
scanf("%c", &c2);

//หรือ

char c1, c2;
scanf("%c", &c1);
fflush(stdin)
scanf("%c", &c2);

คำสั่ง fflush(stdin) นั่นแหละคือคำสั่งล้างบัฟเฟอร์

โอเค ออกนอกเรื่องเยอะไปหน่อย กลับมาดูกันดีกว่าว่าบัฟเฟอร์คืออะไร

คอนเซ็ปของบัฟเฟอร์เกิดขึ้นพร้อม I/O ในI/Oทุกตัวจะมีการคิดตั้งเมมโมรี่เล็กๆ เอาไว้ซึ่งแต่ละตัวจะไม่เท่ากัน เช่น คีย์บอร์ดอาจจะติดไว้ให้1KB ปริ๊นเตอร์อาจจะติดไว้ให้เยอะหน่อยสัก2MB อะไรแบบนั้น หน้าที่ของมันขอยกตัวอย่างคีย์บอร์ด (เป็นตัวแทนของ Input นะ) ทุกครั้งที่เรากดปุ่มบนคีย์บอร์ด ข้อมูลพวกนี้จะต้องถูกส่งต่อไปให้ CPU จัดการใช้มั้ย แต่บางครั้ง CPU ก็ยังไม่ว่างมาจัดการ แต่ถ้าจังหวะนั้นไม่มีใครรับข้อมูลไว้ให้จะเกิดไรขึ้น ข้อมูลที่ผู้ใช้กดไปเมื่อกี้ก็อันตรธานหายไปเลยน่ะสิ! วิธีแก้คือ Input ทุกตัวจะไม่ส่งข้อมูลให้ CPU ตรงๆ แต่จะวางไว้ในเมมโมรี่ตัวเมื่อกี้ ซึ่งเราจะเรียกเมมโมรี่เนี่ยว่า Buffer นั่นเอง ... ทีนี้ งานจะไปตกอยู่ที่ CPU แทน โดยมันจะต้องคอยวนมาดูว่าบัฟเฟอร์เนี่ยมีของคาอยู่มั้ย ถ้ามีก็ดึงออกไปใช้ได้เลย แต่ส่วนใหญ่แล้วเหตุการณ์มันจะเกิดขึ้นเร็วมาก เรากดคีย์บอร์ดพิมพ์ๆๆๆๆ ทันทีที่กดเสร็จตัวอักษรจะขึ้นไปอยู่บนหน้าจอทันที นั่นเพราะว่า CPU ทำงานเร็วกว่า I/O มากน่ะสิ เราเลยไม่ค่อยเห็นเหตุการณ์ที่ของวางกองคาอยู่ในบัฟเฟอร์เยอะๆ

แต่เดี๋ยวก่อน! ลองนึกถึงเวลาคอมช้าๆ ค้างๆ นะ กำลังพิมพ์อะไรสักอย่างอยู่ แต่โปรแกรมค้าง พิมพ์ ABCDEFG ลงไป แต่บนหน้าจอไม่ขึ้นตัวอะไรมาเลย แต่พออีกสักพักหนึ่งผ่านไป โปรแกรมรันทันแล้วในจังหวะนั้นมันเลยมาดูดข้อมูลในบัฟเฟอร์ไปรวดเดียวเลย เราจะเห็นตัว ABCDEFG โผล่พราดเดียวขึ้นมาทั้งหมดเลย นั่นแหละ สถานการณ์ที่มีของค้างอยู่ในบัฟเฟอร์

ในทางกลับกัน สำหรับOutput เช่นปริ๊นเตอร์ สมมุติว่าเราสั่งพิมพ์งานละกัน เนื่องจาก CPU ทำงานเร็วสุดๆ ปริ๊นเตอร์ไม่มีทางปริ๊นงานออกไปทันข้อมูลที่ CPU ส่งมาให้หรอก ดังนั้นเวลา CPU จะส่งข้อมูลไปให้ปริ๊นเตอร์มันจะส่งตรงๆ ไม่ได้ แต่จะต้องเอาไปวางไว้ในบัฟเฟอร์ก่อน (ส่วนใหญ่บัฟเฟอร์ของปริ๊นเตอร์จะใหญ่เพราะไฟล์ที่ปริ๊นมักจะใหญ่นั่นเอง) แล้วปริ๊นเตอร์จะมาไล่อ่านข้อมูลทีละนิดแล้วพิมพ์ออกไปเรื่อยๆ

สรุปคือหลักการของบัฟเฟอร์คือการใช้ Queue นั่นเอง
(คอนเซ็ป Producer-Consumer ใน Data Structure เลย)

แต่เมื่อมันเป็นคิว ก็แสดงว่ามัน "ล้น" ได้นะ เช่นคีย์บอร์ด ถ้าคุณกดคีย์เร็วๆ มากๆ แล้ว CPU มาอ่านไม่ทัน บัฟเฟอร์เต็ม คุณจะได้ยินคอมร้อง "บี๊บ!" เพื่อบอกว่าบัฟเฟอร์เต็มแล้วนะ ... ด้านปริ๊นเตอร์ กำลังพิมพ์อยู่กระดาษหมดเงี้ย แต่CPUยังส่งข้อมูลมาเรื่อยๆ แป๊ปเดียวกันเต็มแล้วนะ แต่คราวนี้ปริ๊นเตอร์จะไม่ร้องแต่แจ้งทางพาเนลแทนว่า Out of Paper

การไหลของ data/instruction จะวิ่งตาม Instruction Cycle

ขอเอา Instruction Cycle กลับมาให้ดูอีกรอบ

ไม่ว่าจะเป็นโปรแกรมอะไร CPUจะมีวิธีการรันเป็นแบบนี้เสมอ ซึ่งพวกมันจะทำงานด้วยรีจิสเตอร์ที่เพิ่งพูดไปข้างบน

แต่พูดไปก็คงไม่เข้าใจ มาดูตัวอย่างแทนดีกว่า สมมุติให้เรามี data คือ x, y แบบนี้

x = 6;
y = 3;

รู้กันแล้วนะว่า data น่ะจะเก็บอยู่ในเมมโมรี่ ขอสมมุติว่า xอยู่ที่address=940 และ yอยู่ที่address=941 ละกันนะ

ต่อมา เราต้องการจะรันโค้ด

x = x + y;

มันดูง่ายมากเลยใช่มั้ยล่ะ แต่คอมพิวเตอร์ไม่เข้าใจภาษาระดับสูงหรอกนะ

งั้นเอาใหม่ มาดูโค้ดหลังจาก compiler แปลงเป็นภาษา Assembly แบบง่ายๆ กัน

LOAD X
ADD Y
STORE X

; หรือถ้าเขียนแบบเต็มขึ้นมาหน่อยจะเป็น...

LOAD Register, X
ADD Register, Y
STORE X, Register

 อธิบายโค้ด: เราจะทำ x+y เสร็จแล้วคำตอบที่ได้เอาไปใส่ไว้ใน x ... ก่อนอื่นต้องเข้าใจว่า CPU โหลดข้อมูลได้ทีละตัว (ปัจจุบันได้มากกว่านี้แล้ว) ดันนั้นมันเลยสั่ง LOAD x เข้ามา แล้วสั่งต่ออีกว่า ADD y นั่นคือตอนนั้น CPU ถือเลขอะไรอยู่ เอาค่า y ไปบวกเพิ่มนะ (คำตอบของการบวกจะค้างอยู่ใน CPU นะ) แล้วต้องการจะเอาคำตอบกลับไปเขียนลง x เลยสั่งว่า STORE x เอาค่าคำตอบตอนเนี้ยไปเก็บใน x

สรุปคือในตัวอย่างนี้เราจะเจอ Instruction 3ตัว แต่สำหรับความที่รู้จักแต่เลข แปลว่าคำสั่งแต่ละอันจะต้องแทนด้วยรหัสคำสั่งสักอย่างแน่ๆ เลยขอสมมุติอีกว่าเป็นแบบนี้ละกัน

  1. LOAD = รหัส 1
  2. ADD = รหัส 5
  3. STORE = รหัส 2

สรุปท้าย โปรแกรมของเราก็จะมีหน้าตาแบบนี้

0001 1001 0100 0000
0101 1001 0100 0001
0010 1001 0100 0000

อ่านไม่ออกล่ะสิ (ฮา) ... งั้นดูแบบนี้ดีกว่า เอาแบบเป็นเลขฐาน10ก่อน แต่อย่าลืมนะว่าจริงๆ มันอยู่ในรูปฐาน2ทั้งหมด

1940
5941
2940

LOAD x ก็จะเป็น 1 และ 940
ADD y ก็จะเป็น 5 และ 941
STORE x ก็จะเป็น 2 และ 940 ไงล่ะ

สรุปคือโปรแกรมเราตอนนี้มี 3 instruction และ 2 data นั่นต้องใช้พื้นที่ในเมมโมรี่ 5 words ในการเก็บนะ แต่เราไม่จำเป็นต้องเก็บพวกมันไว้ติดกัน instrcution ไว้ที่นึง data ไว้อีกที่ก็ได้ (แต่ลำดับโปรแกรมของ instruction ต้องเรียงกัน)

เดี๋ยวขอกลับไปเรื่อง Instruction Cycle อีกหน่อยเพราะเหมือนจะพูดข้ามไปนิด

การทำงานของ CPU จะเป็นการลูปไปเรื่องๆ ระหว่างรอบของการอ่านว่าจะทำอะไร (Fetch) แล้วก็ทำ (Exec) แบบนี้วนไปเรื่อยๆ แน่นอนว่าคอมไม่มีสมอง (ฮา) เราเลยต้องมี instruction เรียงไว้ให้มันทำเยอะๆ  จะลองคิดตามดู จะพบว่าไม่ว่าการ exec จะเป็นอะไร ยังไงก็ต้องเริ่มด้วยการ fetch แน่นอนอยู่แล้วล่ะ

สรุปก็คือ

อันนี้เอาไซเคิลแรกมาวาดลงรายละเอียดด้วย (ก็คือรูปที่เห็นกันมาแล้วนั่นแหละนะ) step 1-3 นั่นคือการ Fetch ที่ยังไงก็ต้องทำ เป็นคอร์สบังคับเลย แต่ step 4-8 นั้นเป็นส่วนของการ Exec ซึ่งแตกย่อยได้ออกเป็น

Read -> Do Something! -> Write

Read คือส่วนที่อนุญาตให้ CPU อ่านค่าที่ต้องใช้ออกมาจากเมมโมรี่ได้ (คือวง A ในรูปนะ)

Do Something คือส่วนที่ CPU กำลัง exec อยู่นั่นแหละ (คือตัว B ในรูป)

Write คือตอนจบที่ CPU ทำงานเสร็จจนรอบแล้ว และอาจจะมีการเขียนข้อมูลกลับลงไปในเมม (ในรูปคือวง C นะ)

ถ้าเรียงการทำงานแบบเต็มๆ มันก็จะเริ่มด้วย [F] -> [A] -> [B] -> [C] ใช้ม๊ะ แต่เวลาทำงานจริงๆ กลับไม่ได้เป็นอย่างนั้น

LOAD X
ADD Y
STORE X

ข้ามการพูดถึง [F] ไปเลยนะเพราะยังไงก็ต้องทำทุกรอบ ในแต่ละคำสั่งต้องทำอะไรบ้างใน exec

  • LOAD X คือคำสั่งสำหรับโหลดค่า X เข้ามา (เข้ามาในไหน? เมื่อกี้บอกไปแล้วไง AC ไงล่ะ!) มีแต่การดึงค่าเข้ามาก็คือ [F] -> [A]
  • ADD Y คือการเอาค่า Y ไปบวกเพิ่ม (ที่ไหนล่ะ? ก็อีกแล้ว เพิ่มให้ใน AC นะ) แปลว่ามันจะทำงานแบบ [F] -> [A] -> [B]
  • STORE X อันนี้คือเอาค่า (จาก AC อีกนั่นแหละ) ไปเก็บไว้ใน X ก็จะเหลือแค่ [F] -> [C]

เก็ทไอเดียแล้วนะ ว่าเราจะต้องเริ่มด้วยการ Fetch! แต่ส่วน Exec นั้นเราสามารถเลือกได้ว่าจะให้ทำอะไรบ้าง ทีนี้ก็จะเกิดคำถามต่อมาอีกว่าแล้วเราจะรู้ได้ไงล่ะว่ามันต้องทำอะไรกับคำสั่งนี้บ้าง จริงม๊ะ?

Decoding ถอดรหัสก่อน จะได้รู้ว่าต้องทำอะไร

ทำไมเราถึงรู้ว่า LOAD X คือการอ่านค่า X เข้ามาใส่ AC?
ทำไมเราถึงรู้ว่า ADD Y คือการเอาค่า Y มาบวกค่าใน AC แล้วใส่มันกลับลงไปใน AC อีกรอบ?

ห้ามตอบว่าเพราะเราอธิบายไปเมื่อกี้นะ ม่ายย!

ที่มันรู้ว่าคำสั่งไหนจะต้องทำอะไรบ้างมาจากการ decode รหัสคำสั่ง โดย CPU แต่ละอาคีเทคจะมีเซ็ตของคไสั่ง Instruction ที่ไม่เหมือนกัน แต่หน้าที่ที่จะรู้ว่า CPU ตัวนี้มีคำสั่งอะไรให้ใช้บ้างไม่ใช่หน้าที่ของเรา แต่เป็น Compiler ตั้งหาก

เราเรียนกันไปตั้งแต่วิชาโปรแกรมมิ่งแล้วว่า Compiler ทำหน้าที่แปลงภาษาระดับสูงที่คอมอ่านไม่รู้เรื่องให้กลายเป็นภาษาเครื่อง แต่การเขียนภาษาระดับสูงคำสั่งจะดูง่ายกว่าคำสั่งที่มีใน CPU แน่นอน ดังนั้นคอมไพเลอร์จะต้องรู้ว่า CPU มีไรให้ใช้บ้างไง ทีนี้ ลองคิดกันเล่นๆ ดู

ADD A, B

ถ้ามีคำสั่งแบบนี้คุณจะแปลมันว่าอะไร หรือ

ADD A, B, C

คุณจะแปลความหมายของมันว่าอะไรล่ะ?

คำตอบคือ ไม่รู้หรอก!
ขึ้นอยู่กับการดีไซน์ของคนออกแบบ CPU

ADD A, B อาจจะแปลว่า A = A + B ก็ได้ ส่วน ADD A,B,C อาจจะแปลว่า A = B + C ก็ยังได้!

ดังนั้นจงรู้ก่อนนะ ว่า Instruction Set ของ CPU คุณมีอะไรให้ใช้บ้าง

 

....

โอเคๆ กลับมาเรื่องเดิมนะ เมื่อกี้จำเป็นต้องออกไปพูดเรื่องอื่นเยอะมาก ดูข้างล่างต่อ

ขอเปลี่ยนหน้าตาของ Regsiter ใน CPU เป็นแบบนี้เพื่อความง่ายในการอธิบายนะ สเตจเริ่มต้นก็จะเป็นประมาณข้างบน อ้อ..ลืมบอกไป ถือว่า instruction ของเราเก็บอยู่เริ่มต้นที่ตำแหน่ง address=300 ละกันนะ

Execute it for Example!

ตัวอย่างการ exec โค้ดข้างล่างลองดูเทียบกับ Instruction ไปด้วยล่ะ

1. [Instruction Address Calculate]

โปรแกรมเริ่มโดย PC นับ addr. 300 หมายความว่า ins.ของโปรแกรมนี้คำสั่งแรกอยู่ที่เมมโมรี่ช่องที่ 300
การจะขอดึง ins. ออกมาต้องส่งค่าจาก PC ไปที่ MAR ก่อนเพื่อชี้ไปยังเมมโมรี่ช่องที่ 300

 

2. [Instruction Fetch]

ในช่องที่ 300 เก็บค่า [1940] เอาไว้ ต้องส่งค่านี้ไปยัง IR โดยผ่าน MBR

3. จบการ fetch ins. จึงทำการ increment PC อีก1

4. [Instruction Operation ‘DECODING’]

ทำการ decode เจ้า ins. ใน IR เพื่อจะได้รู้ว่าคำสั่งนี้จะ "ทำอะไร" กับ "data" ตัวไหน ... ในที่นี้คือ 1=LOAD / addr=940

[Operand Address Calculate]
แปลว่า data อยู่ที่เมมโมรี่ช่องที่ 940 การจะดึงข้อมูลออกมาจะต้องทำเหมือนเดิมคือส่ง addr นี้ไปที่ MAR เพื่อชี้ไปยังเมมโมรี่ช่องที่940ก่อนว่าจะดึงที่ช่องนี้ล่ะ

5. [Operand Fetch ]

ทำเหมือนตอน fetch ins. แต่ครั้งนี้เป็น fetch data แทน เป้าหมายเลยกลายเป็นดึงข้อมูลเข้ามาใส่ AC แทน (ครั้งที่แล้วของ ins. เป็น IR) แต่ยังไงก็ต้องทำผ่าน MBR เหมือนเดิม
**มาถึงตรงนี้ถือว่าจบ Ins. cycle รอบที่หนึ่งแล้วนะ

6. [Instruction Address Calculate]

เริ่มทำคำสั่งต่อไป (แต่คอมไม่มีความจำเลยต้องดูที่..) PC เก็บค่า 301 เอาไว้จึงโยนผ่าน MAR ไปที่เมมโมรี่เพื่อบอกว่าขอข้อมูลช่องที่ 301

7. [Instruction Fetch]

เมมโมรี่ส่งข้อมูล [5941] มาให้ในฐานะ ins. จึงโยนเข้าไปใส่ IR (ผ่าน MBR เหมือนเดิมนะ)

8. จบการ fetch ins. จึงทำการ increment PC อีก1

9. [Instruction Operation ‘DECODING’]

ทำการ decode คำสั่งอีก ครั้งนี้ได้ว่า 5=ADD / addr=941

[Operand Address Calculate]
จึงขอข้อมูลจากเมมโมรี่โดยสั่งผ่าน MAR เช่นเดิมให้ชี้ไปที่ช่อง 941

10. [Operand Fetch ]
โหลด data (ที่มีค่า3) เข้ามา

[Data ‘Operation’]
แต่ครั้งนี้คำสั่งคือ ADD จึงนำค่า3ไปบวกเพิ่มให้กับค่าเดิมที่คาอยู่ใน AC นั่นคือ6 สรุปว่าบวกกันได้9 ผลสุดท้ายใน AC เลยเก็บค่า9เอาไว้

**จบ Ins. cycle ไปอีกรอบ

11. [Instruction Address Calculate]
มาต่อที่คำสั่งต่อไป เหมือนเดิมคือคอมไม่มีความจำ ดังนั้นต้องไปดูที่ PC ซึ่งชี้ว่าคำสั่งต่อไปอยู่ที่ 302 ก็โยนต่อให้ MAR ชี้เป้าล่ะนะ

12. [Instruction Fetch]
ดึง ins. เข้ามาใส่ IR เหมือนเดิมเนอะ

13. จบการ fetch ins. จึงทำการ increment PC อีก1

14. [Instruction Operation ‘DECODING’]
ทำการ decode คำสั่งอีก

[Operand Address Calculate]
ครั้งนี้ได้ว่า 2=STORE / addr=940

คราวนี้จะแปลกว่าครั้งก่อนๆ เพราะคำสั่ง STORE ไม่ได้ต้องการดึงข้อมูลจากตัวแปรในเมมโมรี่ แต่ต้องการจะส่ง data กลับไปเขียนลงเมมโมรี่ตั้งหาก มันเลยส่งตำแหน่ง 940 ไปให้ MAR ชี้เป้าก่อนว่าฉันจะเขียนข้อมูลลงตำแหน่งนั้นนะ

15. [Operand Store]
จากนั้น การจะคุยกับเมมโมรี่นั้นทำตรงๆ ไม่ได้เหมือนตอนที่อ่านข้อมูลมานั่นแหละ เลยต้องส่งค่า9 (คำตอบจากการ 6+3 ไง) ไปให้ MBR ซึ่งตอนนี้มี MAR ชี้เป้าให้อยู่แล้ว เลยโยน data เข้าไปเขียนในเมมโมรี่ได้เลย

**อันนี้ก็จบไปอีกหนึ่ง Ins. cycle ด้วยนะ

ขอจบแค่นี้ก่อนละกัน บทนี้ยาวสุดๆ ขอบคุณที่ทนอ่านจนจบนะ ^__^
แล้วมาเจอกันใหม่ในบทหน้า เราจะมาพูดถึงเรื่อง Interrupt กัน

11905 Total Views 2 Views Today
Ta

Ta

สิ่งมีชีวิตตัวอ้วนๆ กลมๆ เคลื่อนที่ไปไหนโดยการกลิ้ง .. ถนัดการดำรงชีวิตโดยไม่โดนแสงแดด
ปัจจุบันเป็น Senior Software Engineer อยู่ที่ Centrillion Technology
งานอดิเรกคือ เขียนโปรแกรม อ่านหนังสือ เขียนบทความ วาดรูป และ เล่นแบดมินตัน

You may also like...

2 Responses

  1. โมะโมะ พูดว่า:

    รอบทความต่อไปอยู่นะฮับบบบบ

  1. 15 พฤษภาคม 2016

    […] ถ้าอยากจำได้กลับไปอ่านที่ http://www.tamemo.com/post/98/ […]

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องที่ต้องการถูกทำเครื่องหมาย *