Tuesday, November 15, 2005

มาลองออกแบบ Abstract Instruction Set กัน (ตอนแรก)

ขอโทษล่วงหน้า ถ้าทำให้ใครบางคนอ่านเรื่องนี้ไม่รู้เรื่องตั้งแต่ต้น ...

บังเอิญว่า อยากจะเอาเรื่องเกี่ยวกับการออกแบบ Instruction Set ของ CPU มาให้ดู ๆ กันบ้างหนะ

Abstract Instruction Set

จุดประสงค์การออกแบบชุดคำสั่ง (Instruction Set) นี้ ไม่ใช่เพื่อให้มันประสิทธิภาพสูงสุด หรือว่าทำเป็นวงจรง่ายหรอกนะ แต่ อยากจะทำให้มันทำงานได้ครบ โดยที่มีคำสั่งน้อย ๆ มากกว่า

Chosen Design: Stack Machine

Stack Machine เป็นแนวคิดที่ว่า Operation ทั้งหลาย ทำบน Stack ... คิดว่าแบบนี้น่าจะทำให้ลดจำนวนคำสั่งลงได้เยอะ

ข้อเสียก็คือ การจะทำอะไรอย่างนึง มันต้องมีหลายคำสั่งน่ะสิ แล้วก็ การทำ Pipelining จะยากด้วย แต่ขอไม่สนเรื่องนี้ก่อน

เหตุผลสนับสนุนอีกอย่างนึงที่ทำให้เลือก Operation on Stack ก็คือ เวลาทำ compiler ให้แปล source code เป็น machine code เนี่ย มันจะค่อนข้างง่ายและตรงมาก (แต่ประสิทธิภาพก็ไม่ได้ดีเท่าไหร่แหละ)

First Two Opcodes: PUSH and POP

เวลาจะทำ Stack ใคร ๆ ก็ต้องคิดถึง Push กับ Pop แน่ ๆ เราก็กำหนดเลยละกันว่า เราจะมีสองคำสั่งนี้

ผลก็คือ เราสามารถสร้างให้คำสั่งอื่น ๆ ไม่รับ operand เองโดยตรงได้ เช่น

คำสั่ง A = B + C

Instruction Set ทั่วไป
ADD A, B, C

Stack-based Operation ของเรา
PUSH B
PUSH C
ADD
POP A

ว่าแต่ว่า ... เราจะระบุสิ่งที่จะ PUSH กับ POP ได้ยังไงหละ?

Types of Operands

เนื่องจากเราจะลดความซับซ้อนให้เหลือน้อยที่สุด เราจะยอมให้มี operand ได้แค่แบบเดียวแบบ คือ
  • Immediate
ไว้จะมาอธิบาย ว่า addressing แบบอื่น สามารถทำได้จากสองแบบนี้ แต่เราต้องพึ่งคำสั่งอื่น ๆ เช่น LOAD กับ ADD

Required Registers

เราจะให้มี register เพียง 3 ตัว ที่สามารถยุ่งเกี่ยวได้ด้วย machine instruction คือ
  • Program Counter (PC) = Address ของคำสั่งปัจจุบัน
  • Base Pointer (BP) = Address แรกของ Local Variable ปัจจุบัน
  • Stack Pointer (SP) = Address ของ Top-of-stack
โดยทั้งสามตัวนี้ ควรจะใช้ Address Space เดียวกัน (Virtual ก็ได้)

สมมติว่า SP จะลดค่าเมื่อ PUSH และเพิ่มค่าเมื่อ POP นะ (ทำตามแบบที่เค้านิยมกัน)

Indirect Indexing: PBASE

เนื่องจาก Base Pointer (BP) เป็น register ที่ควรจะสามารถนำค่าไปบวก-ลบได้ ดังนั้น เราจึงควรจะสร้างคำสั่งที่ใช้อ่านค่า BP ดังนี้

PBASE = Push ค่าของ BP ขึ้น Stack

LOAD and STORE

เราจะกำหนดให้ คำสั่ง LOAD จะใช้ operand เป็นตัวบนสุดของ stack ตัวเดียว มีการทำงานคือ
  1. เอาค่าบนสุดของ stack ไปเป็น address อ้างอิง memory
  2. อ่านค่าจาก memory ในตำแหน่งนั้น
  3. เอาค่าที่อ่านได้ มาแทนที่ในตำแหน่งบนสุดของ stack (ที่เคยเป็น address)
ส่วนคำสั่ง STORE จะใช้ operand 2 ตัว มีการทำงานคือ
  1. POP ตัวแรกออกจาก stack ใช้เป็น address อ้างอิง memory
  2. POP ตัวที่สองออกจาก stack ใช้เป็นค่าที่จะเขียนลง memory
  3. เขียนค่าที่ได้ (จากการ POP ครั้งที่สอง) ลงใน memory (address ได้จากการ POP ครั้งแรก)
จะว่าไป ... LOAD มันก็คือ PUSH แล้ว STORE มันก็คือ POP น่ะแหละ

สังเกตดี ๆ หละ ว่า จริง ๆ เราไม่ต้องมีคำสั่ง POP นะ!!!

Logical Functions: NOT, AND, OR, XOR, IFF

ถึงแม้ว่า จริง ๆ แล้วเราสามารถใช้แค่ NAND หรือ NOR เพียงอย่างเดียวได้ แต่ตรงนี้ ไม่ขอประหยัดจำนวน Opcode นะ เพราะว่ามันไม่ได้เป็นสาระสำคัญเท่าไหร่ (ถ้าอยากจะสร้างแบบประหยัด ให้มันมีแต่ NAND หรือมีแต่ NOR เวลาทำ compiler ก็จะเหนื่อยหน่อย เท่านั้นเอง)

Arithmetic Functions: NEG, ADD, SUB, MUL, DIV, MOD, EXP, LOG, ...

พวกนี้ก็เหมือนกัน ... จริง ๆ มีแค่ NEG ADD แล้วก็ MUL ก็น่าจะพอแล้ว แต่การประหยัดจำนวนคำสั่งตรงนี้ ก็ไม่ใช่สาระสำคัญเหมือนกัน ดังนั้นเราจะถือว่า คำสั่งพวกนี้ มีหมดเลย ก็แล้วกัน

Classical Modes of Addressing

เนื่องจาก Operand เรา มีแต่แบบ Immediate การอ้างถึง Operand ในลักษณะอื่น ๆ แบบที่เครื่องทั่ว ๆ ไปเค้าทำได้ มันจะต้องใช้หลายคำสั่งหน่อยนะ เช่น

Target: Value at memory address X
Abbreviation: [X]
How to PUSH that?
PUSH X
LOAD

Target: Value at memory address BP + X
Abbreviation: [BP + X]
How to PUSH that?
PBASE
PUSH X
ADD
LOAD

Target: Value at memory address (BP + value at X)
Abbreviation: [BP + [X]]
How to PUSH that?
PBASE
PUSH X
LOAD
ADD
LOAD

Target (in C): Array[Index]
Abbreviation: [BP + array + [BP + index]]
How to PUSH that?
PBASE
PUSH array
ADD
PBASE
PUSH index
ADD
LOAD
ADD
LOAD

Simple Branch Instructions: JMP, JPOS, JNEG, JZ, JNZ
  • JMP: POP → PC
  • JPOS: POP → เก็บไว้ แล้ว POP อีกที ถ้าได้ค่าเป็นเลขบวก (มากกว่า 0) ถึงจะกระโดดไปยัง address ที่เก็บไว้
  • JNEG: คล้าย ๆ กับ JPOS แต่จะกระโดดถ้าค่าที่ POP ออกมาครั้งที่ 2 เป็นเลขติดลบ
  • JZ: POP → เก็บไว้ แล้วก็ POP อีกที ถ้าได้ค่าเป็น 0 ถึงจะโดดไปยัง address ที่เก็บไว้
  • JNZ: คล้าย ๆ กับ JZ แต่เงื่อนไขการกระโดดตรงกันข้าม
จริง ๆ จะมีแต่ JPOS ก็ได้แหละ ที่ไม่ตัดตัวอื่นออก ก็เพราะว่ามันไม่ใช่สาระสำคัญ (อีกแล้ว)

Subroutine: CALL, RETURN

คำสั่ง CALL จะวุ่น ๆ หน่อย เพราะมีการทำงานหลายขั้น คือ
  1. POP ค่า address ที่จะกระโดดไป เก็บไว้
  2. PUSH ค่า PC + 1 ไว้
  3. PUSH ค่า BP ไว้
  4. กำหนดค่าให้ BP = SP
  5. กำหนดค่าให้ PC = address ที่ POP ไว้ตอนแรก (ซึ่งก็คือ การกระโดดนั่นเอง)
ส่วนคำสั่ง RETURN จะทำงานกลับกันกับ CALL คือ
  1. POP ค่า Return Code ออกมาเก็บไว้ก่อน
  2. POP ค่ามาใส่ไว้ใน BP
  3. POP อีกค่ามาใส่ไว้ใน PC (ซึ่งก็คือ การกระโดดกลับ)
  4. PUSH ค่า Return Code คืนลงไปใน Stack
จริง ๆ แล้ว ตอนที่ RETURN จะไม่เผื่อที่สำหรับ Return Code ก็ได้ แต่อันนี้เผื่อไว้เพื่อความสะดวกหนะ

Local Variable and Parameters

ถ้าต้องการส่งผ่าน parameter ให้กับ function เราก็จะใช้วิธี PUSH ใส่ stack ไว้ก่อน เช่น
  1. PUSH A
  2. PUSH B
  3. PUSH CustomAdd
  4. CALL
  • ถ้า BP หลัง CALL = x
  • SP ก่อน CALL จะ = x + 1
  • ตำแหน่งของ B ก็เลย = x + 2
  • และ ตำแหน่งของ A ก็ = x + 3
สรุปก็คือ parameter ตัวที่ PUSH มาหลังสุด (ไม่นับ address ของฟังก์ชัน ซึ่งในตัวอย่างนี้คือ CustomAdd) จะมี address เป็น BP + 2

CustomAdd:
  1. PBASE
  2. PUSH 2
  3. SUB
  4. LOAD
  5. PBASE
  6. PUSH 3
  7. SUB
  8. LOAD
  9. ADD
  10. RETURN
สรุปคำสั่ง

ชุดคำสั่งเล็กสุด
PUSH
PBASE
LOAD
STORE
JPOS
CALL
RETURN
NAND
NEG
ADD
MUL

คำสั่งลดความเหนื่อย
JMP
JNEG
JZ
JNZ
NOT
AND
OR
XOR
IFF
SUB
DIV
MOD
...

ตอนนี้เราก็ได้ Instruction Set คร่าว ๆ แล้ว แต่เราไม่พูดถึงขนาดของข้อมูลในแต่ละช่องของ Stack เลยนะเนี่ย ... ก็เลยเรียกว่า Abstract Instruction Set ไงหละ

2 Comments:

At 12/10/2005 3:38 AM, Anonymous Anonymous said...

งุงุ

 
At 9/08/2014 2:20 AM, Anonymous Anonymous said...

Hello! Quick question that's entirely off topic.
Do you know how to make your site mobile friendly? My site looks
weird when viewing from my iphone 4. I'm trying to
find a theme or plugin that might be able to resolve this problem.
If you have any recommendations, please share. With thanks!



Have a look at my homepage somatodrol blog

 

Post a Comment

<< Home