ALU ในไมโครโปรเซสเซอร์จะแยกความแตกต่างระหว่างหมายเลขที่เซ็นชื่อ -7 ที่แสดงด้วย 1111 และหมายเลขที่ไม่ได้ลงนาม 15 และแสดงด้วย 1111 ได้อย่างไร
ALU ในไมโครโปรเซสเซอร์จะแยกความแตกต่างระหว่างหมายเลขที่เซ็นชื่อ -7 ที่แสดงด้วย 1111 และหมายเลขที่ไม่ได้ลงนาม 15 และแสดงด้วย 1111 ได้อย่างไร
คำตอบ:
คำตอบที่สั้นและง่ายคือมันไม่ ไม่มีซีพียูกระแสหลัก ISA ที่ใช้งานได้ตามที่คุณคิด
สำหรับซีพียูมันเป็นเพียงรูปแบบเล็กน้อย มันขึ้นอยู่กับคุณโปรแกรมเมอร์ที่จะติดตามความหมายของรูปแบบบิตนั้น
โดยทั่วไป ISAs จะไม่แยกความแตกต่างระหว่างชนิดข้อมูลที่แตกต่างกันเมื่อมันมาถึงการจัดเก็บ (ไม่สนใจการลงทะเบียนวัตถุประสงค์พิเศษเช่นการลงทะเบียนแบบลอยใน FPU) มันเป็นเพียงรูปแบบบิตที่ไร้ความหมายต่อซีพียู แต่อกหักจะมีหลายชนิดที่แตกต่างกันของคำสั่งที่อาจตีความรูปแบบบิตในรูปแบบที่แตกต่างกัน ยกตัวอย่างเช่นคำแนะนำทางคณิตศาสตร์เช่นMUL
, DIV
, ADD
, SUB
ตีความรูปแบบบิตเป็นชนิดของบางหมายเลขในขณะที่คำแนะนำการใช้ตรรกะเช่นAND
, OR
, XOR
ตีความว่ามันเป็นอาร์เรย์ของ booleans ดังนั้นขึ้นอยู่กับโปรแกรมเมอร์ (หรือผู้เขียนล่ามหรือคอมไพเลอร์หากคุณใช้ภาษาระดับสูงกว่า) เพื่อเลือกคำแนะนำที่ถูกต้อง
อาจมีคำแนะนำแยกต่างหากสำหรับหมายเลขที่เซ็นชื่อและที่ไม่ได้ลงชื่อเช่น ISAs บางตัวยังมีคำแนะนำสำหรับการคำนวณทางคณิตศาสตร์ด้วยทศนิยมทศนิยม
อย่างไรก็ตามโปรดทราบว่าฉันเขียน "modern กระแสหลัก ISA" ด้านบน ในความเป็นจริงมี ISA ที่ไม่สำคัญหรือมีคุณค่าทางประวัติศาสตร์ที่ทำงานแตกต่างกัน ตัวอย่างเช่นทั้ง CISC ISA แบบ 48 บิตดั้งเดิมของ IBM AS / 400 เช่นเดียวกับ RISC ISA แบบ 64 บิตที่ใช้พลังงานในปัจจุบันซึ่งปัจจุบันเรียกว่า IBM i แยกแยะความแตกต่างระหว่างตัวชี้และค่าอื่น ๆ พอยน์เตอร์จะถูกติดแท็กเสมอและรวมถึงข้อมูลประเภทและการจัดการสิทธิ์ CPU รู้ว่าค่าเป็นตัวชี้หรือไม่และเคอร์เนล i / OS ที่มีสิทธิ์เท่านั้นที่ได้รับอนุญาตให้จัดการพอยน์เตอร์ได้อย่างอิสระ แอปพลิเคชั่นของผู้ใช้สามารถจัดการพอยน์เตอร์ที่ตนเป็นเจ้าของให้ชี้ไปที่หน่วยความจำของตนเองโดยใช้คำแนะนำที่ปลอดภัยเพียงเล็กน้อย
นอกจากนี้ยังมีการออกแบบ ISA ในอดีตที่รวมรูปแบบการรับรู้ประเภทอย่างน้อยบางรูปแบบ
char
ซึ่งเป็น 16 บิตชนิดที่ไม่ได้ลงชื่อ แน่นอนว่ายังไม่มีคำแนะนำเกี่ยวกับเลขคณิตที่ไม่ได้ลงชื่อใน Java bytecode เนื่องจากchar
ค่าใด ๆจะได้รับการส่งเสริมโดยอัตโนมัติint
(ลงนามแบบ 32 บิต) สำหรับเลขคณิต
เวอร์ชั่นสั้น: ไม่รู้ ไม่มีทางที่จะบอกได้
หาก1111
แสดงถึง -7 แสดงว่าคุณมีการแทนค่า sign-magnitudeโดยที่บิตแรกเป็นสัญญาณและบิตที่เหลือเป็นขนาด ในกรณีนี้เลขคณิตค่อนข้างซับซ้อนเนื่องจากการเพิ่มที่ไม่ได้ลงชื่อและการเพิ่มที่เซ็นชื่อใช้ตรรกะที่แตกต่างกัน ดังนั้นคุณอาจจะมีSADD
และUADD
opcode และถ้าคุณเลือกผิดคุณได้รับผลลัพธ์ที่ไร้สาระ
บ่อยขึ้น แต่1111
หมายถึง -1 ในสิ่งที่เรียกว่าเป็นตัวแทน two's-สมบูรณ์ ในกรณีนี้ ALU จะไม่สนใจว่าหมายเลขถูกเซ็นชื่อหรือไม่ได้ลงนาม! 1110 + 0001
ตัวอย่างเช่นลองมาการดำเนินงานของ ในเลขคณิตที่ลงนามหมายถึง "-2 + 1" และผลลัพธ์ควรเป็น -1 ( 1111
) ในเลขคณิตที่ไม่ได้ลงชื่อหมายความว่า "14 + 1" และผลลัพธ์ควรเป็น 15 ( 1111
) ดังนั้น ALU จึงไม่ทราบว่าคุณต้องการผลลัพธ์ที่ลงชื่อหรือไม่ได้ลงชื่อและไม่สนใจ มันเป็นเพียงการเพิ่มราวกับว่ามันไม่ได้ลงนามและถ้าคุณต้องการที่จะถือว่าเป็นจำนวนเต็มหลังจากนั้นนั่นก็ขึ้นอยู่กับคุณ
แก้ไข: เนื่องจาก Ruslan และ Daniel Schepler ชี้ให้เห็นอย่างถูกต้องในความคิดเห็นผู้ดำเนินการบางคนยังต้องการรุ่นที่เซ็นชื่อและไม่ได้ลงชื่อแยกจากกันแม้ในเครื่องเสริมสองเครื่อง การบวกการลบการคูณความเสมอภาคและสิ่งต่าง ๆ เหล่านี้ทำงานได้ดีโดยไม่ทราบว่ามีการลงชื่อหมายเลขหรือไม่ แต่การหารและการเปรียบเทียบที่มากกว่า / น้อยกว่านั้นจะต้องมีรุ่นแยกต่างหาก
แก้ไขแก้ไข: มีตัวแทนบางส่วนเช่นกันของเสริมแต่โดยทั่วไปสิ่งเหล่านี้ไม่เคยใช้อีกดังนั้นคุณไม่ควรกังวลเกี่ยวกับพวกเขา
<
<=
>=
>
จะแตกต่างกันสำหรับตัวถูกดำเนินการที่ลงชื่อและไม่ได้ลงชื่อในขณะที่==
และ!=
ผู้ไม่เชื่อเรื่องพระเจ้า
ข้อดีอย่างหนึ่งของคณิตศาสตร์เสริมสองอย่างซึ่งสถาปัตยกรรมสมัยใหม่ทั้งหมดใช้คือคำแนะนำการบวกและการลบเหมือนกันสำหรับตัวถูกดำเนินการทั้งที่ลงชื่อและไม่ได้ลงชื่อ
ซีพียูจำนวนมากไม่มีคำสั่งการคูณหารหรือโมดูลัส หากพวกเขาทำพวกเขาจะต้องมีรูปแบบการเรียนการสอนที่ลงนามและไม่มีลายเซ็นและคอมไพเลอร์ (หรือโปรแกรมเมอร์ภาษาแอสเซมบลี) เลือกรูปแบบที่เหมาะสม
โดยทั่วไปแล้วซีพียูยังมีคำแนะนำต่าง ๆ สำหรับการเปรียบเทียบที่ลงชื่อหรือไม่ได้ลงชื่อ ตัวอย่างเช่น x86 อาจตามCMP
ด้วยJL
(กระโดดถ้าน้อยกว่า) หากการเปรียบเทียบควรลงนามหรือJB
(กระโดดถ้าด้านล่าง) หากการเปรียบเทียบควรไม่ได้ลงนาม อีกครั้งคอมไพเลอร์หรือโปรแกรมเมอร์จะเลือกคำสั่งที่เหมาะสมสำหรับประเภทข้อมูล
คำแนะนำอื่น ๆ สองสามอย่างมักจะมาในรูปแบบที่มีการเซ็นชื่อและไม่ได้ลงนามเช่นการกะขวาหรือการโหลดค่าในการลงทะเบียนที่กว้างขึ้นโดยมีหรือไม่มีส่วนขยายสัญญาณ
smulh
และumulh
ที่ส่งกลับเฉพาะบิตบนของการคูณและคำแนะนำการลงนามและไม่ได้ลงนาม ส่งคืนผลลัพธ์ในรีจิสเตอร์สองเท่าของตัวถูกดำเนินการต้นทาง
มันไม่ได้ โปรเซสเซอร์ใช้การตั้งค่าคำสั่งเพื่อบอกประเภทของข้อมูลที่ต้องการดูและตำแหน่งที่จะส่ง ไม่มีอะไรเกี่ยวกับ 1s และ 0s ในตัวถูกดำเนินการเองซึ่งสามารถส่งสัญญาณไปยัง ALU โดยเนื้อแท้ไม่ว่าจะเป็นข้อมูลถ่าน, ลอย, int, เซ็นชื่อ int เป็นต้นหาก 1111 กำลังไปยังวงจรไฟฟ้าที่คาดว่าจะเป็นส่วนประกอบ 2 วินาที ที่จะตีความว่าเป็นส่วนเสริม 2s
char
ในระดับฮาร์ดแวร์ บางทีกาลครั้งหนึ่งย้อนกลับไปในยุคของเครื่องโทรพิมพ์ทางกล แต่วันนี้char
เป็นเพียงตัวเลขที่เกี่ยวข้องกับฮาร์ดแวร์ เหตุผลที่ตัวเลขที่แตกต่างกันตรงกับรูปร่างตัวอักษรที่แตกต่างกันบนหน้าจอของคุณคือตัวเลขเหล่านั้นถูกใช้เพื่อเลือกบิตแมปที่แตกต่างกันหรือรูทีนการวาดที่แตกต่างจากตารางขนาดใหญ่ (เช่นจาก "ฟอนต์")
ฉันต้องการเพิ่มคำตอบที่ทำไปแล้ว:
ในคำตอบอื่น ๆ ส่วนใหญ่มีการบันทึกไว้ว่าในเลขคณิตประกอบสองทางผลลัพธ์จะเหมือนกันสำหรับตัวเลขที่ลงนามและไม่ได้ลงนาม:
-2 + 1 = -1 1110 + 0001 = 1111
14 + 1 = 15 1110 + 0001 = 1111
อย่างไรก็ตามมีข้อยกเว้น:
Division:
-2 / 2 = -1 1110 / 0010 = 1111
14 / 2 = 7 1110 / 0010 = 0111
Comparison:
-2 < 2 = TRUE 1110 < 0010 = TRUE
14 < 2 = FALSE 1110 < 0010 = FALSE
"Typical" (*) multiplication:
-2 * 2 = -4 1110 * 0010 = 11111100
14 * 2 = 28 1110 * 0010 = 00011100
(*) สำหรับซีพียูจำนวนมากผลลัพธ์ของการคูณตัวเลขสองบิตคือความกว้างบิต (2 * n)
สำหรับการดำเนินการดังกล่าว CPU มีคำแนะนำที่แตกต่างกันสำหรับเลขคณิตที่ลงชื่อและไม่ได้ลงชื่อ
ซึ่งหมายความว่าโปรแกรมเมอร์ (หรือคอมไพเลอร์) ต้องใช้คำแนะนำอื่น ๆ สำหรับการลงชื่อและเลขคณิตที่ไม่ได้ลงนาม
ยกตัวอย่างเช่นซีพียู x86 มีคำสั่งที่ระบุชื่อdiv
สำหรับการแบ่งส่วนที่ไม่ได้ลงนามและคำสั่งที่ระบุชื่อidiv
สำหรับการแบ่งส่วนที่ลงชื่อ
นอกจากนี้ยังมีคำแนะนำ "เงื่อนไข" ที่แตกต่างกัน (การกระโดดตามเงื่อนไขการตั้งค่าบิตบนเงื่อนไข) รวมถึงคำแนะนำการคูณสำหรับเลขคณิตที่ลงนามและไม่ได้ลงนาม