ทำไมไม่มีคำสั่ง 'nand' ในซีพียูรุ่นใหม่?


52

ทำไมนักออกแบบ x86 (หรือสถาปัตยกรรม CPU อื่น ๆ ด้วย) ตัดสินใจที่จะไม่รวมมัน มันเป็นประตูตรรกะที่สามารถใช้ในการสร้างประตูตรรกะอื่น ๆ ดังนั้นมันจึงเป็นคำสั่งที่รวดเร็ว แทนที่จะผูกมัดnotและandคำแนะนำ (ทั้งคู่ถูกสร้างขึ้นจากnand) ทำไมไม่มีnandคำสั่ง?


20
สิ่งที่คุณมีสำหรับการเรียนการสอน nand? น่าจะเป็นนักออกแบบ x86 ไม่เคยพบเลย
PlasmaHH

16
ARM มีการเรียนการสอนซึ่งเป็นBIC a & ~bแขน Thumb-2 มีการเรียนการสอนซึ่งเป็นORN ~(a | b)ARM สวยทันสมัย การเข้ารหัสคำสั่งในชุดคำสั่ง CPU มีค่าใช้จ่าย ดังนั้นสิ่งที่ "มีประโยชน์" ที่สุดเท่านั้นที่จะเข้าสู่ ISA
ยูจีน Sh.

24
@ Amumu เราสามารถมีการ~(((a << 1) | (b >> 1)) | 0x55555555)สอนด้วย วัตถุประสงค์จะเป็นเช่นนั้นเพื่อให้~(((a << 1) | (b >> 1)) | 0x55555555)สามารถแปลเป็นคำสั่งเดียวแทนที่จะเป็น 6 ดังนั้นทำไมไม่
253751

11
@ Amumu: นั่นไม่ใช่ usecase และก็ไม่ใช่ ~! usecase เป็นเหตุผลที่น่าสนใจว่าทำไมคำสั่งนั้นมีประโยชน์และสามารถนำไปใช้ได้ที่ไหน เหตุผลของคุณก็เหมือนกับการพูดว่า "ควรมีคำแนะนำเพื่อให้สามารถใช้งานได้" แต่คำถามก็คือ "สิ่งที่ควรใช้เพื่อสิ่งนี้สำคัญมากที่จะมีประโยชน์ในการใช้ทรัพยากร"
PlasmaHH

4
ฉันเขียนโปรแกรมมา 45 ปีเขียนคอมไพเลอร์สองสามตัวและใช้ตัวดำเนินการเชิงตรรกะบางอย่างเมื่อมีเช่น IMP แต่ฉันไม่เคยใช้ตัวดำเนินการหรือคำสั่งของ NAND มาก่อน
user207421

คำตอบ:


62

http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.alangref/idalangref_nand_nd_instrs.htm : POWER มี NAND

แต่โดยทั่วไปแล้วซีพียูรุ่นใหม่นั้นถูกสร้างขึ้นเพื่อให้เข้ากับการสร้างรหัสอัตโนมัติโดยคอมไพเลอร์และ NAND ระดับบิตจะไม่เรียกใช้ Bitwise AND และ OR ถูกใช้บ่อยขึ้นสำหรับการจัดการ bitfields ในโครงสร้างข้อมูล ในความเป็นจริง SSE นั้นมี AND-NOT แต่ไม่ใช่ NAND

ทุกคำสั่งมีค่าใช้จ่ายในการถอดรหัสตรรกะและใช้ opcode ที่สามารถนำไปใช้อย่างอื่นได้ โดยเฉพาะอย่างยิ่งในการเข้ารหัสความยาวผันแปรเช่น x86 คุณสามารถใช้งาน opcodes สั้น ๆ และต้องใช้รหัสที่ยาวกว่าซึ่งอาจทำให้โค้ดทั้งหมดช้าลง


5
@supercat AND-NOT ถูกใช้เพื่อปิดบิตในตัวแปรชุดบิต เช่นif(windowType & ~WINDOW_RESIZABLE) { ... do stuff for variable-sized windows ... }
adib

2
@adib: ใช่แล้ว คุณลักษณะที่น่าสนใจของ "and-not" คือไม่เหมือนกับตัวดำเนินการ "bitwise not" [[]] ขนาดของผลลัพธ์จะไม่สำคัญ หากfooเป็น uint64_t foo &= ~something;บางครั้งคำสั่งอาจล้างบิตมากกว่าที่ตั้งใจไว้ แต่หากมี&~=ผู้ปฏิบัติงานปัญหาดังกล่าวสามารถหลีกเลี่ยงได้
supercat

6
@adib หากWINDOW_RESIZABLEเป็นค่าคงที่ดังนั้นเครื่องมือเพิ่มประสิทธิภาพควรประเมิน~WINDOW_RESIZABLEณ เวลารวบรวมดังนั้นนี่เป็นเพียง AND ในเวลาทำงาน
alephzero

4
@MarkRansom: ไม่สาเหตุและผลกระทบนั้นถูกต้องทั้งหมดจากประวัติการคำนวณ ปรากฏการณ์นี้ของการออกแบบ CPU ที่ปรับให้เหมาะสมสำหรับคอมไพเลอร์แทนที่จะเป็นโปรแกรมเมอร์แอสเซมบลีของมนุษย์เป็นส่วนหนึ่งของการเคลื่อนไหวของ RISC (แม้ว่าการเคลื่อนไหวของ RISC นั้นกว้างกว่าแง่มุมนั้น) ซีพียูที่ออกแบบมาสำหรับคอมไพเลอร์ประกอบด้วย ARM และ Atmel AVR ในช่วงปลายยุค 90 และต้น 00s คนที่ได้รับการว่าจ้างนักเขียนคอมไพเลอร์และโปรแกรมเมอร์ OS ในการออกแบบชุดคำสั่ง CPU
slebetman

3
การดำเนินการลงทะเบียนเพื่อลงทะเบียนในทุกวันนี้นั้นฟรีเมื่อเทียบกับการเข้าถึง RAM การปฏิบัติตามคำแนะนำที่ซ้ำซ้อนจะทำให้ต้นทุนอสังหาริมทรัพย์ซิลิคอนใน CPU ดังนั้นโดยปกติจะมีเพียงหนึ่งรูปแบบของ bitwise-OR และ bitwise-AND เนื่องจากการเพิ่มการดำเนินการลงทะเบียน register-bitwise-complement นั้นแทบจะไม่ทำให้อะไรช้าลงเลย
nigel222

31

ค่าใช้จ่ายของฟังก์ชั่น ALU นั้นคือ

1) ตรรกะที่ทำหน้าที่ของตัวเอง

2) ตัวเลือกที่เลือกผลลัพธ์ของฟังก์ชั่นนี้แทนตัวเลือกอื่น ๆ จากฟังก์ชั่น ALU ทั้งหมด

3) ค่าใช้จ่ายในการมีตัวเลือกนี้ในชุดคำสั่ง (และไม่มีฟังก์ชั่นที่มีประโยชน์อื่น ๆ )

ฉันเห็นด้วยกับคุณว่า 1) ค่าใช้จ่ายเล็กมาก ค่าใช้จ่าย 2) และ 3) อย่างไรก็ตามเกือบจะเป็นอิสระจากฟังก์ชั่น ฉันคิดว่าในกรณีนี้ 3) ค่าใช้จ่าย (บิตที่ถูกครอบครองในคำสั่ง) เป็นเหตุผลที่ไม่มีคำสั่งเฉพาะนี้ บิตในการเรียนการสอนเป็นทรัพยากรที่หายากมากสำหรับผู้ออกแบบ CPU / สถาปัตยกรรม


29

ลองย้อนดูก่อนดูว่าทำไม Nand ถึงได้รับความนิยมในการออกแบบลอจิกฮาร์ดแวร์ - มันมีคุณสมบัติที่มีประโยชน์มากมาย จากนั้นถามว่าคุณสมบัติเหล่านั้นยังคงใช้กับคำสั่ง CPU หรือไม่ ...

TL / DR - ไม่ทำดังนั้นจึงไม่มีข้อเสียในการใช้ And หรือ Or หรือ Not แทน

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

และจำนวนครั้งที่คุณจำเป็นต้องรวมคำแนะนำอื่น ๆ นั้นมีขนาดเล็กมากพอที่จะทำให้ Nand ไม่ได้รับพื้นที่ในชุดคำแนะนำ


1
ในกรณีที่ไม่จำเป็นต้องใช้การแยกอินพุต "และไม่ใช่" จะดูเหมือนว่าถูกมากในฮาร์ดแวร์ ย้อนกลับไปในปี 1977 ฉันออกแบบตัวควบคุมสัญญาณเลี้ยวสำหรับรถพ่วงของผู้ปกครองโดยใช้ทรานซิสเตอร์สองตัวและไดโอดสองตัวต่อแสงเพื่อทำหน้าที่ "XOR" [โคมไฟด้านซ้าย == xor (สัญญาณซ้ายเบรก); right lamp == xor (สัญญาณด้านขวา, เบรก)], โดยพื้นฐานแล้วฟังก์ชั่นทั้งสองและไม่ทำงานสำหรับแต่ละแสง ฉันไม่เห็นกลอุบายดังกล่าวที่ใช้ในการออกแบบ LSI แต่ฉันคิดว่าใน TTL หรือ NMOS ในกรณีที่สิ่งที่ป้อนเข้าจะต้องมีความสามารถในการขับที่เพียงพอเทคนิคดังกล่าวสามารถประหยัดวงจรได้
supercat

12

ฉันต้องการเห็นด้วยกับไบรอันที่นี่และ Wouter และ pjc50

ฉันต้องการเพิ่มให้โดยทั่วไปโดยเฉพาะอย่างยิ่ง CISC ตัวประมวลผลคำสั่งไม่ได้มีปริมาณงานเท่ากัน - การดำเนินการที่ซับซ้อนอาจใช้เวลานานกว่านั้นง่ายกว่า

พิจารณา X86: AND(ซึ่งเป็นการดำเนินการ "และ") อาจจะเร็วมาก NOTเดียวกันจะไปสำหรับ ลองดูที่การถอดชิ้นส่วน:

ใส่รหัส:

#include <immintrin.h>
#include <stdint.h>

__m512i nand512(__m512i a, __m512i b){return ~(a&b);}
__m256i nand256(__m256i a, __m256i b){return ~(a&b);}
__m128i nand128(__m128i a, __m128i b){return ~(a&b);}
uint64_t nand64(uint64_t a, uint64_t b){return ~(a&b);}
uint32_t nand32(uint32_t a, uint32_t b){return ~(a&b);}
uint16_t nand16(uint16_t a, uint16_t b){return ~(a&b);}
uint8_t nand8(uint8_t a, uint8_t b){return ~(a&b);}

คำสั่งในการผลิตประกอบ:

gcc -O3 -c -S  -mavx512f test.c

การชุมนุมเอาท์พุท (สั้นลง):

    .file   "test.c"
nand512:
.LFB4591:
    .cfi_startproc
    vpandq  %zmm1, %zmm0, %zmm0
    vpternlogd  $0xFF, %zmm1, %zmm1, %zmm1
    vpxorq  %zmm1, %zmm0, %zmm0
    ret
    .cfi_endproc
nand256:
.LFB4592:
    .cfi_startproc
    vpand   %ymm1, %ymm0, %ymm0
    vpcmpeqd    %ymm1, %ymm1, %ymm1
    vpxor   %ymm1, %ymm0, %ymm0
    ret
    .cfi_endproc
nand128:
.LFB4593:
    .cfi_startproc
    vpand   %xmm1, %xmm0, %xmm0
    vpcmpeqd    %xmm1, %xmm1, %xmm1
    vpxor   %xmm1, %xmm0, %xmm0
    ret
    .cfi_endproc
nand64:
.LFB4594:
    .cfi_startproc
    movq    %rdi, %rax
    andq    %rsi, %rax
    notq    %rax
    ret
    .cfi_endproc
nand32:
.LFB4595:
    .cfi_startproc
    movl    %edi, %eax
    andl    %esi, %eax
    notl    %eax
    ret
    .cfi_endproc
nand16:
.LFB4596:
    .cfi_startproc
    andl    %esi, %edi
    movl    %edi, %eax
    notl    %eax
    ret
    .cfi_endproc
nand8:
.LFB4597:
    .cfi_startproc
    andl    %esi, %edi
    movl    %edi, %eax
    notl    %eax
    ret
    .cfi_endproc

อย่างที่คุณเห็นสำหรับประเภทข้อมูลขนาด 64- บิตสิ่งต่าง ๆ ล้วนได้รับการจัดการเป็นเวลานาน (เช่น the และlและไม่ใช่l ) เนื่องจากเป็นบิตบิต "ดั้งเดิม" ของคอมไพเลอร์ของฉันอย่างที่เห็น

ความจริงที่ว่ามีmovในระหว่างนั้นเป็นเพียงเพราะความจริงที่ว่าการeaxลงทะเบียนที่มีค่าตอบแทนของฟังก์ชั่น โดยปกติคุณเพียงแค่คำนวณในการediลงทะเบียนทั่วไปเพื่อคำนวณผลลัพธ์

สำหรับ 64 บิตก็เหมือนกัน - เพียงแค่มี "สี่เหลี่ยม" (เพราะฉะนั้นต่อท้ายq) คำพูดและrax/ rsiแทน/eaxedi

ดูเหมือนว่าสำหรับตัวถูกดำเนินการ 128 บิตและใหญ่กว่านั้น Intel ไม่สนใจที่จะใช้การดำเนินการ "ไม่" คอมไพเลอร์สร้าง all- 1register (เปรียบเทียบตัวเองของ register กับตัวเองส่งผลให้เก็บไว้ใน register ด้วยvdcmpeqdคำสั่ง) และxors นั้น

กล่าวโดยย่อ: ด้วยการใช้งานการดำเนินการที่ซับซ้อนด้วยคำสั่งเบื้องต้นหลายคำคุณไม่จำเป็นต้องชะลอการดำเนินการ - ไม่มีประโยชน์ที่จะมีคำสั่งเดียวที่ทำงานหลายคำสั่งถ้ามันไม่เร็วขึ้น


10

ก่อนปิดอย่าสับสนการดำเนินการระดับบิตและตรรกะ

โดยปกติแล้วการใช้งานในระดับบิตจะใช้เพื่อตั้งค่า / ล้าง / สลับ / ตรวจสอบบิตในบิตฟิลด์ การดำเนินการเหล่านี้ไม่จำเป็นต้องมี nand ("และไม่ใช่" หรือที่รู้จักกันว่า "bit clear" มีประโยชน์มากกว่า)

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


10

NAND มักจะไม่ได้รับการติดตั้งโดยตรงเนื่องจากการมีคำสั่ง AND ทำให้คุณสามารถกระโดดขึ้นไปบนเงื่อนไข NAND ได้

การทำการดำเนินการแบบลอจิคัลใน CPU มักจะกำหนดบิตในการตั้งค่าสถานะ

การลงทะเบียนส่วนใหญ่มีค่าสถานะเป็นศูนย์ การตั้งค่าสถานะเป็นศูนย์ถ้าผลลัพธ์ของการดำเนินการแบบลอจิคัลเป็นศูนย์และเคลียร์เป็นอย่างอื่น

CPU ที่ทันสมัยส่วนใหญ่มีคำสั่งการกระโดดที่กระโดดถ้าตั้งค่าสถานะศูนย์ พวกเขายังมีการตัดทอนที่กระโดดถ้าไม่มีการตั้งค่าสถานะเป็นศูนย์

AND และ NAND เป็นส่วนเติมเต็ม หากผลลัพธ์ของการดำเนินการ AND เป็นศูนย์ผลลัพธ์ของการดำเนินการ NAND คือ 1 และในทางกลับกัน

ดังนั้นหากคุณต้องการ ot กระโดดถ้า NAND ของสองค่าเป็นจริงจากนั้นเพียงแค่ดำเนินการ AND และกระโดดถ้าตั้งค่าสถานะศูนย์

ดังนั้นหากคุณต้องการ ot jump ถ้า NAND ของสองค่าเป็นเท็จให้ทำการดำเนินการ AND และกระโดดถ้าค่าสถานะศูนย์ว่าง


อันที่จริง - การเลือกคำสั่งการกระโดดแบบมีเงื่อนไขช่วยให้คุณมีทางเลือกในการสลับกลับและไม่สลับกลับตรรกะสำหรับการเรียนการสอนทั้งชั้นโดยไม่ต้องใช้ตัวเลือกนั้นสำหรับแต่ละรายการ
Chris Stratton

นี่ควรเป็นคำตอบที่ดีที่สุด การดำเนินการตั้งค่าสถานะศูนย์ทำให้ NAND ไม่จำเป็นสำหรับการดำเนินการทางตรรกะเนื่องจาก AND + JNZ และ AND + JZ นั้นเป็นวงจรสั้น / ตรรกะ AND และ NAND ตามลำดับโดยทั้งสองใช้หมายเลข opcode เท่ากัน
Lie Ryan

4

เพียงเพราะสิ่งที่เป็นราคาถูกไม่ได้หมายความว่ามันเป็นค่าใช้จ่ายที่มีประสิทธิภาพ

หากเราใช้เหตุผลในการโต้แย้งของคุณเราจะได้ข้อสรุปว่า CPU ควรประกอบไปด้วยคำสั่ง NOP หลายร้อยรสชาติ - เพราะเป็นวิธีที่ถูกที่สุดในการใช้งาน

หรือเปรียบเทียบกับเครื่องมือทางการเงิน: คุณจะซื้อพันธบัตร $ 1 พร้อมผลตอบแทน 0.01% เพียงเพราะคุณทำได้หรือไม่? ไม่คุณควรบันทึกเงินดอลลาร์เหล่านั้นไว้จนกว่าคุณจะมีเงินเพียงพอที่จะซื้อพันธบัตรมูลค่า $ 10 พร้อมผลตอบแทนที่ดีกว่า ไปด้วยงบประมาณซิลิโคนใน CPU: มันมีประสิทธิภาพในการขวาน ops ราคาถูก แต่ไร้ประโยชน์มากมายเช่น NAND และใส่ทรานซิสเตอร์ที่บันทึกไว้ในบางสิ่งที่แพงกว่า แต่มีประโยชน์อย่างแท้จริง

ไม่มีการแข่งขันที่จะมีตัวเลือกมากที่สุดเท่าที่เป็นไปได้ ในฐานะที่เป็น RISC กับ CISC ได้พิสูจน์สิ่งที่ทัวริงรู้จากจุดเริ่มต้น: น้อยกว่ามาก มันจะดีกว่าถ้ามี ops น้อยที่สุด


nopไม่สามารถใช้ประตูตรรกะอื่น ๆ ทั้งหมด แต่nandหรือnorสามารถสร้างคำสั่งใด ๆ ที่นำมาใช้ใน CPU ในซอฟต์แวร์ได้อย่างมีประสิทธิภาพ ถ้าเราใช้แนวทาง RISC นั่นคือ ..
Amumu

@Amumu ฉันคิดว่าคุณกำลังผสมขึ้นและgate instructionประตูถูกใช้เพื่อดำเนินการตามคำแนะนำไม่ใช่วิธีอื่น ๆ NOPเป็นคำสั่งไม่ใช่ประตู และใช่ซีพียูมีประตู NAND เป็นพันหรืออาจนับล้านเพื่อใช้คำแนะนำทั้งหมด ไม่ใช่แค่คำสั่ง "NAND"
Agent_L

2
@Amumu นั่นไม่ใช่วิธี RISC :) นั่นเป็นวิธี "ใช้ abstractions ที่กว้างที่สุด" ซึ่งไม่ได้มีประโยชน์มากไปกว่าการใช้งานที่เฉพาะเจาะจง แน่นอนว่าnandเป็นประตูเดียวที่สามารถใช้ในการติดตั้งประตูอื่น ๆ แต่คุณมีทุกคำแนะนำอื่นReimplementing พวกเขาโดยใช้nandการเรียนการสอนจะช้าลง และพวกมันก็ถูกใช้บ่อยเกินไปที่จะทนได้ซึ่งต่างจากตัวอย่างเฉพาะที่คุณหยิบมาจากเชอร์รี่ซึ่งnandจะสร้างรหัสที่สั้นกว่า (ไม่ใช่รหัสที่เร็วขึ้นแค่สั้นกว่า) แต่นั่นหายากมากและประโยชน์ก็ไม่คุ้มกับค่าใช้จ่าย
Luaan

@Amumu ถ้าเราใช้วิธีการของคุณเราจะไม่มีหมายเลขตำแหน่ง อะไรคือจุดที่คุณสามารถพูดได้((((()))))แทนที่จะเป็น 5 ใช่ไหม? หมายเลขห้าเป็นหมายเลขเดียวเท่านั้นนั่นคือวิธีที่ จำกัด มากเกินไป - เซตทั่วไปมากกว่า: P
Luaan

@Agent_L ใช่ฉันรู้ว่าจะมีคำแนะนำในการใช้เกต nandใช้ประตูทั้งหมดดังนั้นโดยนัยnandสามารถใช้คำแนะนำอื่น ๆ ทั้งหมด จากนั้นถ้าโปรแกรมเมอร์มีnandคำแนะนำให้ใช้เขาสามารถประดิษฐ์คำสั่งของตัวเองเมื่อคิดในตรรกะประตู สิ่งที่ฉันหมายถึงจากจุดเริ่มต้นคือถ้ามันเป็นพื้นฐานทำไมมันไม่ได้รับคำสั่งของตัวเอง (นั่นคือ opcode ในตรรกะถอดรหัส) เพื่อให้โปรแกรมเมอร์สามารถใช้คำสั่งดังกล่าว แน่นอนหลังจากที่ฉันได้รับคำตอบตอนนี้ฉันรู้ว่ามันขึ้นอยู่กับการใช้งานซอฟต์แวร์
Amumu

3

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

ถ้าเราไม่สนใจกรณี "หรือ" ตรรกะอื่น ๆ ทั้งหมดจะถูกสร้างจาก nand แต่ไม่ใช่เพราะมีหลักฐานทางวิทยาศาสตร์คอมพิวเตอร์บางอย่างที่สามารถสร้างตรรกะการทำงานทั้งหมดได้ - เหตุผลก็คือไม่มีวิธีการเบื้องต้นในการสร้าง xor หรือหรืออื่น ๆ ที่ดีกว่าการสร้างมันขึ้นมาจาก nand

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

สิ่งที่นับแล้วคือจำนวนคำแนะนำที่มีความจำเป็นสำหรับการดำเนินงานที่มีการดำเนินการจริงตามรหัสทั่วไป Nand ไม่มีที่ไหนใกล้ด้านบนของรายการการดำเนินการที่ร้องขอโดยทั่วไป มันเป็นเรื่องธรรมดามากที่และหรือหรือไม่ได้รับการร้องขอ ผู้ออกแบบชุดประมวลผลและชุดคำสั่งจะตรวจสอบรหัสที่มีอยู่จำนวนมากและพิจารณาว่าคำสั่งต่าง ๆ จะมีผลกับรหัสนั้นอย่างไร พวกเขาพบว่าการเพิ่มคำสั่ง nand จะนำไปสู่การลดจำนวนน้อยลงของจำนวนคำสั่งของตัวประมวลผลที่รันเพื่อเรียกใช้โค้ดทั่วไปและการแทนที่คำสั่งที่มีอยู่ด้วย nand จะเพิ่มจำนวนคำสั่งที่ดำเนินการ


2

เพียงเพราะ NAND (หรือ NOR) สามารถใช้เกตส์ทั้งหมดในตรรกะเชิงการรวมกันไม่ได้แปลเป็นโอเปอเรเตอร์ระดับบิตที่มีประสิทธิภาพในลักษณะเดียวกัน หากต้องการใช้งาน AND โดยใช้การดำเนินการ NAND โดยที่ c = a AND b คุณต้องมี c = a NAND b จากนั้น b = -1 จากนั้น c = c NAND b (สำหรับ NOT) การดำเนินการระดับบิตตรรกะพื้นฐานคือ AND, OR, EOR, NOT, NAND และ NEOR นั่นไม่ครอบคลุมมากนักและสี่คนแรกนั้นถูกสร้างขึ้นโดยทั่วไป ในตรรกะเชิงผสมวงจรตรรกะพื้นฐานจะถูก จำกัด ด้วยจำนวนประตูที่มีอยู่เท่านั้นซึ่งเป็นเกมบอลที่แตกต่างกันโดยสิ้นเชิง จำนวนการเชื่อมต่อที่เป็นไปได้ในอาเรย์เกทที่สามารถตั้งโปรแกรมได้ซึ่งดูเหมือนว่าคุณจะเป็นอะไรจริงๆ โปรเซสเซอร์บางตัวมีเกทเรย์ในตัวแน่นอน


0

คุณไม่ได้ติดตั้งลอจิกเกตเพียงเพราะมันมีความสมบูรณ์ในการใช้งานโดยเฉพาะอย่างยิ่งถ้าประตูตรรกะอื่น ๆ นั้นมีให้ใช้ คุณใช้สิ่งที่มีแนวโน้มที่จะใช้มากที่สุดโดยคอมไพเลอร์

NAND, NOR และ XNOR นั้นไม่ค่อยมีความต้องการ นอกจากตัวดำเนินการ bitwise คลาสสิก AND, OR และ XOR เท่านั้น ANDN ( ~a & b) - ซึ่งไม่ใช่ NAND ( ~(a & b)) - จะมียูทิลิตี้ที่ใช้งานได้จริง ถ้ามีซีพียูควรใช้งานนั้น (และแน่นอนว่าบางซีพียูใช้งาน ANDN)

สำหรับการอธิบายยูทิลิตี้ที่ใช้งานได้ของ ANDN ให้จินตนาการว่าคุณมี bitmask ที่ใช้บิตจำนวนมาก แต่คุณสนใจเพียงบางส่วนเท่านั้นซึ่งมีดังต่อไปนี้:

enum my_flags {
    IT_IS_FRIDAY = 1,
    ...
    IT_IS_WARM = 8,
    ...
    THE_SUN_SHINES = 64,
    ...
};

โดยปกติคุณต้องการตรวจสอบบิตที่คุณสนใจใน bitmask หรือไม่

  1. พวกเขาทั้งหมดตั้ง
  2. ตั้งอย่างน้อยหนึ่งรายการ
  3. ไม่ได้ตั้งอย่างน้อยหนึ่งรายการ
  4. ไม่มีการตั้งค่า

เริ่มจากการรวบรวมบิตที่คุณสนใจ:

#define BITS_OF_INTEREST (IT_IS_FRIDAY | IT_IS_WARM | THE_SUN_SHINES)

1. บิตที่น่าสนใจทั้งหมดถูกตั้งค่า: bitwise ANDN + ตรรกะ NOT

สมมติว่าคุณต้องการทราบว่าบิตที่คุณสนใจนั้นพร้อมหรือยัง (my_bitmask & IT_IS_FRIDAY) && (my_bitmask & IT_IS_WARM) && (my_bitmask & THE_SUN_SHINES)คุณสามารถเห็นมันเหมือน อย่างไรก็ตามโดยปกติคุณจะยุบตัวลง

unsigned int life_is_beautiful = !(~my_bitmask & BITS_OF_INTEREST);

2. ตั้งดอกเบี้ยอย่างน้อยหนึ่งบิต: ระดับบิตและระดับ

ตอนนี้สมมติว่าคุณต้องการทราบว่ามีการตั้งดอกเบี้ยอย่างน้อยหนึ่งบิตหรือไม่ (my_bitmask & IT_IS_FRIDAY) || (my_bitmask & IT_IS_WARM) || (my_bitmask & THE_SUN_SHINES)คุณสามารถเห็นมันเป็น อย่างไรก็ตามโดยปกติคุณจะยุบตัวลง

unsigned int life_is_not_bad = my_bitmask & BITS_OF_INTEREST;

3. ไม่ได้ตั้งดอกเบี้ยอย่างน้อยหนึ่งบิต: bitwise ANDN

ตอนนี้สมมติว่าคุณต้องการทราบว่ายังไม่ได้กำหนดดอกเบี้ยอย่างน้อยหนึ่งบิต !(my_bitmask & IT_IS_FRIDAY) || !(my_bitmask & IT_IS_WARM) || !(my_bitmask & THE_SUN_SHINES)คุณสามารถเห็นมันเป็น อย่างไรก็ตามโดยปกติคุณจะยุบตัวลง

unsigned int life_is_imperfect = ~my_bitmask & BITS_OF_INTEREST;

4. ไม่มีการตั้งค่าบิตที่น่าสนใจ: bitwise และ + ตรรกะไม่

ตอนนี้สมมติว่าคุณต้องการทราบว่าบิตทั้งหมดที่น่าสนใจไม่ได้ตั้งค่า !(my_bitmask & IT_IS_FRIDAY) && !(my_bitmask & IT_IS_WARM) && !(my_bitmask & THE_SUN_SHINES)คุณสามารถเห็นมันเป็น อย่างไรก็ตามโดยปกติคุณจะยุบตัวลง

unsigned int life_is_horrible = !(my_bitmask & BITS_OF_INTEREST);

นี่เป็นการดำเนินการทั่วไปที่ดำเนินการกับ bitmask รวมถึง bitwise OR และ XOR แบบคลาสสิก ฉันคิดว่าที่เป็นภาษา (ซึ่งไม่ซีพียู ) ควรจะรวมถึงค่าที่เหมาะสม NAND, NOR และผู้ประกอบการ XNOR (ที่มีสัญลักษณ์จะเป็น~&, ~|และ~^) แม้จะไม่ค่อยได้ใช้ ฉันจะไม่รวมตัวดำเนินการ ANDN ในภาษา แต่เนื่องจากไม่ใช่การสับเปลี่ยน ( a ANDN bไม่ใช่แบบเดียวกันb ANDN a) - ดีกว่าที่จะเขียน~a & bแทนที่จะa ANDN bเป็นแบบเดิมแสดงให้เห็นอย่างชัดเจนถึงความไม่สมดุลของการดำเนินการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.