How to make your own processor: Arithmetic Logic Unit (ALU)

Πως να φτιάξετε τον δικό σας επεξεργαστή: Αριθμητική Λογική Μονάδα (ALU)

· Electronics Ηλεκτρονική · processor επεξεργαστής arithmetic αριθμητική logic λογική

IntroductionΕισαγωγή

In our previous articles, we showed how we can use NAND gates to implement addition and subtraction, comparators and (de-)multiplexers and memory elements. In this article, we will present an implementation of the brain of a computer, i.e. of the Arithmetic Logic Unit (ALU). This implementation is interactive (you can change the inputs). You can also double-click on composite components to open and examine them.

Στα προηγούμενα άρθρα μάς, δείξαμε πώς μπορούμε να χρησιμοποιήσουμε NAND πύλες για να υλοποιήσουμε την πρόσθεση και την αφαίρεση, συγκριτές και (απο-)πολυπλέκτες και στοιχεία μνήμης. Σε αυτό το άρθρο θα παρουσιάσουμε μια υλοποίηση του εγκεφάλου ενός υπολογιστή, δηλαδή της Αριθμητικής Λογικής Μονάδας (ALU). Η υλοποιήση αυτή είναι διαδραστική (μπορείτε να αλλάζετε τις εισόδους). Μπορείτε επίσης να κάνετε διπλό κλικ πάνω στα σύνθετα εξαρτήματα για να τα ανοίξετε και να τα εξετάσετε.

Arithmetic Logic Unit (ALU)Αριθμητική Λογική Μονάδα (ALU)

The Arithmetic Logic Unit (ALU) is a combinational digital circuit that serves as the fundamental building block of a processor. It is essentially the part of the computer that actually does the computational work. While other components move values around or remember them, the ALU processes them. The ALU receives values called operands and an operation code (opcode) indicating which operation to perform. It processes this input through a complex arrangement of logic gates to produce a result. Its functions are split into two categories: logic operations and arithmetic operations.

Η Αριθμητική Λογική Μονάδα (ALU) είναι ένα συνδυαστικό ψηφιακό κύκλωμα που αποτελεί το θεμελιώδες δομικό στοιχείο ενός επεξεργαστή. Ουσιαστικά, είναι το τμήμα του υπολογιστή που κάνει την υπολογιστική δουλειά. Ενώ άλλα στοιχεία απλά μετακινούν δεδομένα ή τα αποθηκεύουν, η ALU τα επεξεργάζεται. Η ALU λαμβάνει δεδομένα που ονομάζονται τελεστέοι (operands) και έναν κωδικό εντολής/λειτουργίας (opcode) που υποδεικνύει ποια λειτουργία πρέπει να εκτελεστεί. Επεξεργάζεται αυτήν την είσοδο μέσω μιας πολύπλοκης διάταξης λογικών πυλών για να παράγει ένα αποτέλεσμα. Οι λειτουργίες της χωρίζονται σε δύο κατηγορίες: τις λογικές λειτουργίες και τις αριθμητικές λειτουργίες.

ImplementationΥλοποίηση

Here we present an 8-bit implementation that accepts two 8-bit operands (A and B) and a 5-bit operation code:

Εδώ παρουσιάζουμε μια οκτάμπιτη υλοποίηση που δέχεται δύο τελεστέους 8-bit (A και Β) και έναν κωδικό λειτουργίας 5 bits:

  • zrA: If it is 1, then instead of operand A, the ALU will use 0 as the first operand.
  • ngA: If it is 1, then the ALU will apply NOT to the value of operand A.
  • fn1 and fn0: Operation selection (00 → AND, 01 → OR, 10 → XOR, 11 → ADD).
  • ngO: If it is 1, then the ALU will apply NOT to the output.
  • zrA: Αν είναι 1 τότε αντί για τον τελεστή Α, η ALU θα χρησιμοποιήσει το 0 ως πρώτο τελεστή.
  • ngA: Αν είναι 1 τότε η ALU θα εφαρμόσει NOT στην τιμή του τελεστή Α.
  • fn1 και fn0: Επιλογή λειτουργίας (00 → AND, 01 → OR, 10 → XOR, 11 → ADD).
  • ngO: Αν είναι 1 τότε η ALU θα εφαρμόσει NOT στην έξοδο.

In addition to the 8-bit output/result, we also have 4 bits (flags) indicating various states, which are useful for comparisons:

Εκτός από την έξοδο/αποτέλεσμα 8-bit έχουμε και 4 bits (σημαίες / flags) που σημαίνουν διάφορες καταστάσεις και είναι χρησίμες σε συγκρίσεις:

  • ZF (Zero Flag): It is 1 when the output is 0.
  • SF (Sign Flag): It is 1 when the highest/most significant bit of the output is 1.
  • CF (Carry Flag): It is 1 when there is a carry at the output.
  • OF (Overflow Flag): It is 1 when there is overflow in the addition circuit. It is defined as OF = Cin_MSB ⊕ Cout_MSB (i.e., XOR of the second-to-last carry with the last carry).
  • ZF (Zero Flag): Είναι 1 οταν η έξοδος ειναι 0.
  • SF (Sign Flag): Είναι 1 όταν το υψηλότερο/σημαντικότερο δυαδικό ψηφίο της εξόδου είναι 1.
  • CF (Carry Flag): Είναι 1 όταν υπάρχει κρατούμενο ψηφίο στην έξοδο.
  • OF (Overflow Flag): Είναι 1 όταν υπάρχει υπερχείλιση στο κύκλωμα πρόσθεσης. Ορίζεται ως OF = Cin_MSB ⊕ Cout_MSB (δηλαδή XOR του προτελευταίου κρατούμενου με το τελευταίο κρατουμένο).
{ "width":830, "height":310, "editable": false, "showToolbox":false, "toolbox":[], "devices":[ {"type":"In", "id":"A","x":20,"y":78, "label":"A"}, {"type":"In", "id":"B","x":20,"y":200, "label":"B"}, {"type":"NumSrc", "id":"Zero","x":28,"y":130, "label":"Zero","state":{"direction":0,"on":false}}, {"type":"In", "id":"zrA","x":48,"y":20, "label":"zrA"}, {"type":"In", "id":"ngA","x":218,"y":20, "label":"ngA"}, {"type":"In", "id":"fn0","x":445,"y":20, "label":"fn0"}, {"type":"In", "id":"fn1","x":490,"y":20, "label":"fn1"}, {"type":"In", "id":"ngO","x":598,"y":20, "label":"ngO"}, {"type":"8bitMUX","id":"MUX1","x":80,"y":70, "label":"MUX1"}, {"type":"8bitNOT","id":"NOT1","x":163,"y":110,"label":"NOT","color":"red","bgColor":"yellow"}, {"type":"8bitMUX","id":"MUX2","x":250,"y":70, "label":"MUX2"}, {"type":"8bitAND","id":"AND","x":360,"y":85, "label":"AND","color":"green","bgColor":"cyan"}, {"type":"8bitOR" ,"id":"OR","x":360,"y":135, "label":"OR","color":"blue","bgColor":"gold"}, {"type":"8bitXOR","id":"XOR","x":360,"y":185, "label":"XOR","color":"black","bgColor":"lightsalmon"}, {"type":"8bitAdder","id":"8bitAdder","x":360,"y":235, "label":"8bitAdder"}, {"type":"8bit4to1MUX","id":"4to1MUX","x":455,"y":140, "label":"4to1MUX"}, {"type":"8bitNOT","id":"NOT2","x":540,"y":190,"label":"NOT","color":"red","bgColor":"yellow"}, {"type":"8bitMUX","id":"MUX3","x":628,"y":150, "label":"MUX3"}, {"type":"isZR","id":"isZR","x":700,"y":60,"label":"isZR"}, {"type":"BusIn","id":"bits","x":730,"y":120,"label":"bits"}, {"type":"Out","id":"Out","x":780,"y":20,"label":"Out"}, {"type":"Out","id":"ZF","x":780,"y":95,"label":"ZF"}, {"type":"Out","id":"SF","x":780,"y":145,"label":"SF"}, {"type":"Out","id":"CF","x":780,"y":195,"label":"CF"}, {"type":"Out","id":"OF","x":780,"y":245,"label":"OF"}], "connectors":[{"from":"A.out0","to":"MUX1.in1"}, {"from":"Zero.out0","to":"MUX1.in2"}, {"from":"zrA.out0","to":"MUX1.in0"}, {"from":"MUX1.out0","to":"MUX2.in1"}, {"from":"MUX1.out0","to":"NOT1.in0"}, {"from":"NOT1.out0","to":"MUX2.in2"}, {"from":"ngA.out0","to":"MUX2.in0"}, {"from":"MUX2.out0","to":"AND.in0"}, {"from":"B.out0","to":"AND.in1"}, {"from":"MUX2.out0","to":"OR.in0"}, {"from":"B.out0","to":"OR.in1"}, {"from":"MUX2.out0","to":"XOR.in0"}, {"from":"B.out0","to":"XOR.in1"}, {"from":"MUX2.out0","to":"8bitAdder.in1"}, {"from":"B.out0","to":"8bitAdder.in2"}, {"from":"fn0.out0","to":"4to1MUX.in0"}, {"from":"fn1.out0","to":"4to1MUX.in1"}, {"from":"AND.out0","to":"4to1MUX.in2"}, {"from":"OR.out0","to":"4to1MUX.in3"}, {"from":"XOR.out0","to":"4to1MUX.in4"}, {"from":"8bitAdder.out0","to":"4to1MUX.in5"}, {"from":"ngO.out0","to":"MUX3.in0"}, {"from":"4to1MUX.out0","to":"NOT2.in0"}, {"from":"4to1MUX.out0","to":"MUX3.in1"}, {"from":"NOT2.out0","to":"MUX3.in2"}, {"from":"MUX3.out0","to":"isZR.in0"}, {"from":"isZR.out0","to":"ZF.in0"}, {"from":"8bitAdder.out1","to":"CF.in0"}, {"from":"8bitAdder.out2","to":"OF.in0"}, {"from":"MUX3.out0","to":"Out.in0"}, {"from":"MUX3.out0","to":"bits.in0"}, {"from":"bits.out7","to":"SF.in0"}]}

Opcode analysisΑνάλυση κωδικού λειτουργίας

zrAngAfn0fn1ngOOutputMnemonic
00000A & Band A, B
00001A ⊼ Bnand A, B
00010A ⊕ Bxor A, B
00100A | Bor A, B
01000¬A & Bandn/bic A, B
00011A ⊙ Bxnor A, B
00101A ⊽ Bnor A, B
00110A + Badd A, B
01111A - Bsub A, B
11001¬Bnot B
11110B - 1dec B
11111-Bneg B
100000-
10001-1-
11000B-
{ "width":400, "height":300, "editable": false, "showToolbox":false, "devices":[ {"type":"NumSrc","id":"a0","x":20,"y":15,"label":"a0"}, {"type":"NumSrc","id":"a1","x":20,"y":30,"label":"a1"}, {"type":"NumSrc","id":"a2","x":20,"y":45,"label":"a2"}, {"type":"NumSrc","id":"a3","x":20,"y":60,"label":"a3"}, {"type":"NumSrc","id":"a4","x":20,"y":75,"label":"a4"}, {"type":"NumSrc","id":"a5","x":20,"y":90,"label":"a5"}, {"type":"NumSrc","id":"a6","x":20,"y":105,"label":"a6"}, {"type":"NumSrc","id":"a7","x":20,"y":120,"label":"A"}, {"type":"NumSrc","id":"b0","x":20,"y":155,"label":"b0"}, {"type":"NumSrc","id":"b1","x":20,"y":170,"label":"b1"}, {"type":"NumSrc","id":"b2","x":20,"y":185,"label":"b2"}, {"type":"NumSrc","id":"b3","x":20,"y":200,"label":"b3"}, {"type":"NumSrc","id":"b4","x":20,"y":215,"label":"b4"}, {"type":"NumSrc","id":"b5","x":20,"y":230,"label":"b5"}, {"type":"NumSrc","id":"b6","x":20,"y":245,"label":"b6"}, {"type":"NumSrc","id":"b7","x":20,"y":260,"label":"B"}, {"type":"BusOut","id":"Abits","x":65,"y":40,"label":"A bits"}, {"type":"BusOut","id":"Bbits","x":65,"y":180,"label":"B bits"}, {"type":"NumSrc","id":"zrA","x":120,"y":15,"label":"zrA"}, {"type":"NumSrc","id":"ngA","x":160,"y":15,"label":"ngA"}, {"type":"NumSrc","id":"fn0","x":200,"y":15,"label":"fn0"}, {"type":"NumSrc","id":"fn1","x":240,"y":15,"label":"fn1"}, {"type":"NumSrc","id":"ngO","x":280,"y":15,"label":"ngO"}, {"type":"ALU", "id":"ALU", "x":115, "y":125,"label":"ALU"}, {"type":"BusIn","id":"Outbits","x":300, "y":112,"label":"Out bits"}, {"type":"NumDsp","id":"o0","x":360,"y":85,"label":"o0"}, {"type":"NumDsp","id":"o1","x":360,"y":100,"label":"o1"}, {"type":"NumDsp","id":"o2","x":360,"y":115,"label":"o2"}, {"type":"NumDsp","id":"o3","x":360,"y":130,"label":"o3"}, {"type":"NumDsp","id":"o4","x":360,"y":145,"label":"o4"}, {"type":"NumDsp","id":"o5","x":360,"y":160,"label":"o5"}, {"type":"NumDsp","id":"o6","x":360,"y":175,"label":"o6"}, {"type":"NumDsp","id":"o7","x":360,"y":190,"label":"Out"}, {"type":"LED","id":"ZF","x":150,"y":230,"label":"ZF"}, {"type":"LED","id":"SF","x":200,"y":230,"label":"SF"}, {"type":"LED","id":"CF","x":250,"y":230,"label":"CF"}, {"type":"LED","id":"OF","x":300,"y":230,"label":"OF"}], "connectors":[{"from":"a0.out0","to":"Abits.in0"}, {"from":"a1.out0","to":"Abits.in1"}, {"from":"a2.out0","to":"Abits.in2"}, {"from":"a3.out0","to":"Abits.in3"}, {"from":"a4.out0","to":"Abits.in4"}, {"from":"a5.out0","to":"Abits.in5"}, {"from":"a6.out0","to":"Abits.in6"}, {"from":"a7.out0","to":"Abits.in7"}, {"from":"b0.out0","to":"Bbits.in0"}, {"from":"b1.out0","to":"Bbits.in1"}, {"from":"b2.out0","to":"Bbits.in2"}, {"from":"b3.out0","to":"Bbits.in3"}, {"from":"b4.out0","to":"Bbits.in4"}, {"from":"b5.out0","to":"Bbits.in5"}, {"from":"b6.out0","to":"Bbits.in6"}, {"from":"b7.out0","to":"Bbits.in7"}, {"from":"zrA.out0","to":"ALU.in2"}, {"from":"ngA.out0","to":"ALU.in3"}, {"from":"fn0.out0","to":"ALU.in4"}, {"from":"fn1.out0","to":"ALU.in5"}, {"from":"ngO.out0","to":"ALU.in6"}, {"from":"Outbits.out0","to":"o0.in0"}, {"from":"Outbits.out1","to":"o1.in0"}, {"from":"Outbits.out2","to":"o2.in0"}, {"from":"Outbits.out3","to":"o3.in0"}, {"from":"Outbits.out4","to":"o4.in0"}, {"from":"Outbits.out5","to":"o5.in0"}, {"from":"Outbits.out6","to":"o6.in0"}, {"from":"Outbits.out7","to":"o7.in0"}, {"from":"Abits.out0","to":"ALU.in0"}, {"from":"Bbits.out0","to":"ALU.in1"}, {"from":"ALU.out1","to":"ZF.in0"}, {"from":"ALU.out2","to":"SF.in0"}, {"from":"ALU.out3","to":"CF.in0"}, {"from":"ALU.out4","to":"OF.in0"}, {"from":"ALU.out0","to":"Outbits.in0"}]}

Είτε το πιστεύετε είτε όχι, αρκεί να πρόσθεσουμε σε αυτην την ALU μερικά στοιχεία μνήμης (καταχωρητές, ROM, RAM) και μια μονάδα ελέγχου (που θα φέρνει εντολές από τη μνήμη, θα τις αποκωδικοποιεί και θα τροδοφοτεί την ALU) για να έχουμε έναν υπολογιστή που πρακτικά μπορεί να εκτελεί κάθε είδους κώδικα και εφαρμογές.

Believe it or not, it is enough to add some memory elements (registers, ROM, RAM) and a control unit (which will fetch instructions from the memory, decode them, and feed them to the ALU), for us to have a computer that can practically execute all kinds of code and applications.


See also...

Δείτε επίσης...