รหัสเครื่อง

[thumb|จอภาพแสดงรหัสเครื่องใน[คอมพิวเตอร์บอร์ดเดี่ยว W65C816S แสดงการทำย้อนกลับเป็นรหัสแอสเซมบลี พร้อมด้วยเรจิสเตอร์ของหน่วยประมวลผล และข้อมูลเทออกจากหน่วยความจำ]]
**รหัสเครื่อง** หรือ **ภาษาเครื่อง** คือกลุ่มของคำสั่งเครื่องที่กระทำการโดยตรงโดยหน่วยประมวลผลกลาง (CPU) ของคอมพิวเตอร์ คำสั่งเครื่องแต่ละคำสั่งจะปฏิบัติงานเฉพาะกิจงานเดียวเท่านั้น เช่นการบรรจุ (load) การกระโดด (jump) หรือการดำเนินการผ่านหน่วยคำนวณและตรรกะ (ALU) บนหน่วยของข้อมูลในหน่วยความจำหรือเรจิสเตอร์ ทุก ๆ โปรแกรมที่กระทำการโดยหน่วยประมวลผลกลางสร้างขึ้นจากอนุกรมของคำสั่งเครื่องเช่นว่านั้น

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

ปัจจุบันนี้โปรแกรมเกือบทั้งหมดในทางปฏิบัติเขียนขึ้นด้วยภาษาแอสเซมบลีหรือภาษาระดับสูงกว่า แล้วแปลเป็นรหัสเครื่องที่กระทำการได้โดยคอมไพเลอร์และ/หรือแอสเซมเบลอร์ กับลิงเกอร์ อย่างไรก็ดี โปรแกรมที่เขียนด้วยภาษาที่แปลด้วยอินเทอร์พรีเตอร์ จะไม่ถูกแปลเป็นรหัสเครื่อง ถึงแม้ว่าอินเทอร์พรีเตอร์ (ซึ่งอาจเห็นเป็นชื่อ *ตัวกระทำการ* หรือ *ตัวประมวลผล*) โดยทั่วไปประกอบขึ้นจากรหัสเครื่องที่กระทำการได้โดยตรง

## คำสั่งเครื่องที่เป็นรหัสเครื่อง

หน่วยประมวลผลหรือตระกูลของหน่วยประมวลผลทุก ๆ ชิ้นมีชุดของคำสั่งเครื่อง (instruction set) ที่เป็นรหัสของมันเอง คำสั่งเครื่องคือแบบรูปต่าง ๆ ของบิต ซึ่งการออกแบบเชิงกายภาพสอดคล้องกับคำสั่งงานที่แตกต่างกันของเครื่อง ดังนั้นชุดของคำสั่งเครื่องจึงใช้ได้กับประเภทของหน่วยประมวลผลที่ใช้สถาปัตยกรรมเดียวกัน การออกแบบหน่วยประมวลผลรุ่นหลังหรือรุ่นต่อยอดก็มักจะรวมคำสั่งทั้งหมดของรุ่นก่อนหน้าไว้ และอาจเพิ่มเติมคำสั่งใหม่เข้าไปอีกด้วย หน่วยประมวลผลรุ่นหลังอาจยกเลิกหรือเปลี่ยนแปลงรหัสของคำสั่งเครื่องในบางครั้ง (สาเหตุทั่วไปก็คือมันจำเป็นสำหรับจุดประสงค์ใหม่) ส่งผลกระทบต่อความเข้ากันได้ของรหัสในบางขอบข่าย แม้กระทั่งหน่วยประมวลผลที่เข้ากันได้เกือบสมบูรณ์ก็อาจแสดงพฤติกรรมต่างไปจากเดิมเล็กน้อยสำหรับบางคำสั่ง แต่ปัญหานี้พบได้น้อยมาก ระบบต่าง ๆ ก็อาจแตกต่างกันในรายละเอียดอื่น เช่น การจัดการหน่วยความจำ ระบบปฏิบัติการ หรืออุปกรณ์รอบข้าง เนื่องจากตามปกติแล้วโปรแกรมจะยึดถือปัจจัยดังกล่าว ระบบที่แตกต่างกันก็จะไม่ทำงานด้วยรหัสเครื่องที่เหมือนกัน ถึงแม้ว่าใช้หน่วยประมวลผลชนิดเดียวกันก็ตาม

รหัสของชุดของคำสั่งเครื่องอาจมีความยาวเท่ากันหมดทุกคำสั่งหรือมีความยาวแปรผันก็ได้ วิธีการจัดการแบบรูปของรหัสเครื่องขึ้นอยู่กับสถาปัตยกรรมนั้น ๆ เป็นอย่างยิ่ง และมักจะขึ้นอยู่กับชนิดของคำสั่ง คำสั่งเครื่องส่วนมากมีฟีลด์ออปโคด (opcode) หนึ่งฟีลด์หรือมากกว่าซึ่งใช้ระบุชนิดของคำสั่งพื้นฐาน (เช่นเลขคณิต ตรรกศาสตร์ การกระโดด ฯลฯ) และการดำเนินการแท้จริง (เช่นการบวก การเปรียบเทียบ) และมีฟีลด์อื่น ๆ ที่อาจใช้สำหรับระบุชนิดของตัวถูกดำเนินการ (operand) ภาวะการกำหนดตำแหน่งที่อยู่ (addressing mode) ออฟเซตของตำแหน่งที่อยู่หรือดัชนี หรือค่าแท้จริงโดยตัวมันเอง (ตัวถูกดำเนินการที่เป็นค่าคงตัวที่บรรจุอยู่ในคำสั่งเครื่องเช่นนั้นเรียกว่า *ค่าใช้ทันที*, immediate)

ไม่ใช่ว่าทุกเครื่องหรือทุกคำสั่งจะมีตัวถูกดำเนินการชัดแจ้ง เครื่องที่ใช้ตัวสะสม (accumulator machine) มีตัวถูกดำเนินการข้างซ้ายแบบผสม และคืนค่าผลลัพธ์ในตัวสะสม (accumulator) ปริยาย สำหรับคำสั่งเลขคณิตส่วนใหญ่ สถาปัตยกรรมอื่น (เช่น 8086 และตระกูล x86) มีคำสั่งธรรมดาในรุ่นของตัวสะสมอยู่ด้วย ซึ่งคำสั่งที่ยาวกว่าจะทำเรจิสเตอร์อันหนึ่งในเรจิสเตอร์ทั่วไปเป็นตัวสะสม เครื่องที่ใช้กองซ้อน (stack machine) มีตัวถูกดำเนินการส่วนใหญ่หรือทั้งหมดอยู่บนกองซ้อนปริยาย คำสั่งเครื่องที่มีจุดประสงค์พิเศษก็มักจะขาดตัวถูกดำเนินการชัดแจ้ง (ตัวอย่างเช่น ซีพียูไอดีในสถาปัตยกรรม x86 เขียนค่าต่าง ๆ ลงในเรจิสเตอร์ปลายทางเป็นปริยาย 4 เรจิสเตอร์) ความแตกต่างระหว่างตัวถูกดำเนินการชัดแจ้งกับปริยายเช่นนี้สำคัญต่อโปรแกรมสร้างรหัสเครื่อง โดยเฉพาะอย่างยิ่งในเรื่องการจัดสรรเรจิสเตอร์และส่วนติดตามพิสัยแบบสด โปรแกรมทำรหัสให้เหมาะที่สุด (code optimizer) ที่ดีสามารถติดตามตัวถูกดำเนินการทั้งชัดแจ้งและปริยาย ซึ่งอาจช่วยให้เกิดการแพร่กระจายค่าคงตัว (constant propagation) ได้บ่อยยิ่งขึ้น การพับทบค่าคงตัว (constant folding) ของเรจิสเตอร์ (เรจิสเตอร์ที่กำหนดให้เป็นผลลัพธ์จากนิพจน์ของค่าคงตัวจะถูกแทนที่ด้วยค่าคงตัวนั้น) และการปรับปรุงรหัสอื่น ๆ ให้ดีขึ้น

## โปรแกรม
โปรแกรมคอมพิวเตอร์คือลำดับของคำสั่งเครื่องที่กระทำการโดยหน่วยประมวลผลกลาง ขณะที่หน่วยประมวลผลอย่างง่ายกระทำการคำสั่งเครื่องทีละคำสั่ง แต่หน่วยประมวลผลซูเปอร์สเกลาร์ (superscalar) สามารถกระทำการคำสั่งเครื่องได้พร้อม ๆ กันทีละหลายคำสั่ง

## ภาษาแอสเซมบลี

การถอดความรหัสเครื่องที่สามารถอ่านได้ง่ายขึ้นอย่างมากอย่างหนึ่งคือภาษาแอสเซมบลี ซึ่งเป็นภาษาที่ใช้รหัสช่วยจำ (mnemonic code) อ้างถึงรหัสของคำสั่งเครื่อง แทนที่จะใช้ค่าตัวเลขของคำสั่งเครื่องโดยตรง ตัวอย่างเช่น หน่วยประมวลผล ซิล็อก แซด80 (Zilog Z80) รหัสเครื่อง `00000101` คือคำสั่งที่ทำให้หน่วยประมวลผลกลางลดค่าเรจิสเตอร์ B ลงหนึ่ง จะเขียนแทนด้วยภาษาแอสเซมบลีว่า `DEC B` เป็นต้น

## ตัวอย่าง
สถาปัตยกรรมมิปส์ (MIPS architecture) ได้ให้ตัวอย่างรหัสเครื่องไว้ ซึ่งคำสั่งเครื่องของมันจะมีขนาด 32 บิตเสมอ ชนิดของคำสั่งกำหนดด้วยฟีลด์ *op* (การดำเนินการ) คือบิตบนสุด 6 บิต คำสั่งชนิด J (กระโดด) และชนิด I (ค่าใช้ทันที) จะระบุไว้อย่างชัดเจนด้วย *op* ส่วนคำสั่งชนิด R (เรจิสเตอร์) ต้องมีฟีลด์ *funct* (ฟังก์ชัน) เพิ่มขึ้นมาเพื่อเจาะจงการดำเนินการที่แน่นอน ฟีลด์ที่ใช้ในคำสั่งสามชนิดมีดังนี้

    6      5     5     5     5      6 บิต
 [  op  |  rs |  rt |  rd |shamt| funct]  ชนิด R
 [  op  |  rs |  rt | address/immediate]  ชนิด I
 [  op  |        target address        ]  ชนิด J

*rs*, *rt*, และ *rd* คือเรจิสเตอร์ที่ถูกดำเนินการ; *shamt* คือปริมาณการเลื่อน; *address* หรือ *immediate* คือค่าที่ถูกดำเนินการโดยตรง

ตัวอย่าง การบวกเรจิสเตอร์ 1 กับเรจิสเตอร์ 2 แล้วเก็บผลลัพธ์ไว้ในเรจิสเตอร์ 6 เขียนได้ดังนี้

 [  op  |  rs |  rt |  rd |shamt| funct]
     0     1     2     6     0     32     ฐานสิบ
  000000 00001 00010 00110 00000 100000   ฐานสอง

การบรรจุค่าให้กับเรจิสเตอร์ 8 โดยนำค่ามาจากเซลล์หน่วยความจำที่ 68 ถัดจากตำแหน่งที่ระบุในเรจิสเตอร์ 3 เขียนได้ดังนี้

 [  op  |  rs |  rt | address/immediate]
    35     3     8           68           ฐานสิบ
  100011 00011 01000 00000 00001 000100   ฐานสอง

การกระโดดไปที่ตำแหน่ง 1024 เขียนได้ดังนี้

 [  op  |        target address        ]
     2                 1024               ฐานสิบ
  000010 00000 00000 00000 10000 000000   ฐานสอง

## ความสามารถในการอ่านได้โดยมนุษย์
รหัสเครื่องไม่สามารถอ่านได้อย่างยิ่ง ดังเช่นที่สำนักงานลิขสิทธิ์แห่งสหรัฐ (United States Copyright Office) ไม่สามารถระบุได้ว่า โปรแกรมที่เข้ารหัสแล้วแต่ละโปรแกรมเป็นผลงานต้นฉบับของผู้ถือลิขสิทธิ์หรือไม่ อย่างไรก็ตามสำนักงานลิขสิทธิ์ก็อนุญาตให้จดทะเบียนลิขสิทธิ์ของโปรแกรมคอมพิวเตอร์ได้ ดักลาส ฮอฟสตัดเทอร์ (Douglas Hofstadter) ได้เปรียบเทียบรหัสเครื่องกับรหัสพันธุกรรมว่า "การมองดูโปรแกรมที่ถูกเขียนเป็นรหัสเครื่อง ก็เทียบได้อย่างกว้าง ๆ กับการมองดูโมเลกุลดีเอ็นเอทีละอะตอม"

## อ้างอิงและเชิงอรรถ

หมวดหมู่:ภาษาแอสเซมบลี