Teil I.Teil IITeil IIITeil ivTeil vWir entwerfen
Little Man Computer in Verilog.
Der Artikel ĂŒber LMC war auf HabrĂ©.
Online-Simulator dieses Computers ist
hier .
Wir schreiben ein RAM / RAM-Modul, das aus vier (N = 2) Vier-Bit-Wörtern (M = 4) besteht. Daten werden von
data_in bei
adr in den
RAM geladen, wenn Sie auf die SchaltflÀche klicken:
module R0 #(parameter N = 2, M = 4) ( input RAM_button, // input [N-1:0] adr, // input [M-1:0] data_in, // output [M-1:0] RAM_out // ); reg [M-1:0] mem [2**N-1:0]; // mem always @(posedge RAM_button) // mem [adr] <= data_in; // data_in assign RAM_out = mem[adr]; // RAM_out endmodule
SchlieĂen Sie als externen Generator
einen 555 CMOS-
Timer an (Betrieb mit 3,3 V).
Wir verbinden
den 555-Timer mit dem ZĂ€hler, verbinden den ZĂ€hler mit dem Adresseneingang des
RAM :
module R1 #(parameter N = 2, M = 4) ( input timer555, RAM_button, //input [N-1:0] adr, input [M-1:0] data_in, output [M-1:0] RAM_out ); reg [1:0]counter; // always @(posedge timer555) // counter <= counter + 1; // 1 wire [N-1:0] adr; assign adr = counter; // reg [M-1:0] mem [2**N-1:0]; always @(posedge RAM_button) mem [adr] <= data_in; assign RAM_out = mem[adr]; endmodule
Hier werden bei der Beschreibung des
ZÀhlerzÀhlers und des
Mem- Speichers nicht blockierende Zuweisungen verwendet.
<= Zuweisungsoperatoren werden auf der Website
marsohod.org hier berĂŒcksichtigt
Eine Beschreibung des ZĂ€hlers finden
Sie hier auf
marsohod.orgFĂŒgen Sie die Download-Funktion zum ZĂ€hler hinzu.
Das Herunterladen erfolgt mit dem Befehl
Counter_load :
//input Counter_load; wire [3:0] branch_adr; // assign branch_adr = data_in; always @(posedge timer555) begin if(Counter_load) // "Counter_load" "branch_adr" counter <= branch_adr; else counter <= counter + 1; end
Erstellen Sie in einem separaten Modul ein 4-Bit-Register (Batterie):
module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(posedge reg_button) q <= reg_data; endmodule
FĂŒgen Sie den Akkumulator, den
MUX2- Multiplexer und den
Summenaddierer zur allgemeinen Schaltung hinzu.
Der Addierer addiert die Nummer in den Batterie-
Acc- Nummern aus dem Speicher.
Die SignaleingÀnge des Multiplexers erhalten die Zahlen
data_in und
sum .
Als nÀchstes wird die Nummer vom
MUX2- Multiplexer in die
Acc- Batterie geladen:
module R2 #(parameter ADDR_WIDTH = 2, DATA_WIDTH = 4) ( input timer555, Counter_load, RAM_button, input MUX_switch, input Acc_button, input [3:0] data_in, output [3:0] Acc, output [DATA_WIDTH-1:0] RAM, output reg [1:0] counter ); wire [1:0] branch_adr; assign branch_adr = data_in[1:0]; //Counter always @(posedge timer555) begin if(Counter_load) counter <= branch_adr; else counter <= counter + 1; end wire [ADDR_WIDTH-1:0] adr; assign adr = counter; //RAM reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= Acc; assign RAM = mem[adr]; //sum wire [3:0] sum; assign sum = Acc + RAM; //MUX reg [3:0] MUX2; always @* // Always @* â «» MUX2 = MUX_switch ? sum : data_in; //Accumulator register4 Acc_reg( .reg_data(MUX2), .reg_button(Acc_button), .q(Acc) ); endmodule
Immer @ * bedeutet "immer". Einige Synthesizer verstehen dieses Design nicht. Ein Multiplexer kann auch ohne Always @ * geschrieben werden (hier wird er nur als Beispiel verwendet).

Subtraktion
Um eine Subtraktion durchzufĂŒhren, muss eine
subtrahierte Zahl in
einem zusÀtzlichen Code angegeben werden . Informationen zum
Addieren und Subtrahieren von BinĂ€rzahlen finden Sie im Lehrbuch âDigitale Schaltkreise und Computerarchitekturâ (David M. Harris und Sarah L. Harris) in Kapitel
1.4.6 Das Zeichen der BinĂ€rzahlenFĂŒgen Sie dem Hauptmodul ein Element hinzu, das die im Speicher gespeicherten Zahlen von der Zahl in der Batterie abzieht:
wire [3:0] subtract; assign subract = Acc - RAM ;
Ersetzen Sie den Multiplexer mit 2 EingÀngen durch einen Multiplexer mit 4 EingÀngen:
always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : subtract) : (MUX_switch[0] ? sum : data_in);
Wir verbinden das AusgabegerÀt mit der Batterie (4bit'ny Register), wir verbinden auch 2 Flags mit der Batterie:
1. Das Flag "Null" ist ein Protokoll. Element 4 ODER NICHT. Das Flag wird gehisst, wenn der Inhalt von
Ass Null ist.
2. Das Flag âNull oder positive Zahlâ ist ein Protokoll. Das Element befindet sich NICHT auf dem hohen Niveau der 4-Bit-Batterie. Das Flag wird gesetzt, wenn der Inhalt von
Ass gröĂer oder gleich Null ist.
// "" output Z_flag; assign Z_flag = ~(|Acc); // 4- - // " " output PZ_flag; assign PZ_flag = ~Acc[3];
4 ODER NICHTHier haben wir ein Ventil mit mehreren EingÀngen ODER NICHT als ~ (| Acc) beschrieben.
Verilog unterstĂŒtzt auch eine Reihe von Gate-Typen.
Die folgenden SchlĂŒsselwörter sind fĂŒr Logikgatter definiert: und (AND), nand (AND-NOT) oder (OR) oder (OR-NOT), xor (exklusives OR), xnor (exklusives OR-NOT), buf (Pufferelement) , nicht (Negation, NICHT).
In Verilog mĂŒssen Sie bei Verwendung von Gates die Ein- und AusgĂ€nge des Elements sowie (optional) den Namen des Gates angeben. Beispielsweise mĂŒssen die Ventile und und / oder einen Ausgang und zwei oder mehr EingĂ€nge haben. Also, fĂŒr das Nor-Ventil haben wir
noch Name Liste_der_ Argumente
noch mynor (out, in0, in1, in2, in3);

FĂŒgen Sie drei Teams hinzu
1. Laden des Batterieinhalts in
das AusgabegerÀt
data_out2. Laden der Adresse in den ZĂ€hler, wenn das Flag âNullâ gesetzt ist (
JMP, wenn
Acc = 0)
3. Laden der Adresse in den ZĂ€hler, wenn das Flag âNull oder eine positive Zahlâ gesetzt ist (
JMP, wenn
Acc > = 0)
module R3 #(parameter ADDR_WIDTH = 2, DATA_WIDTH = 4) ( input timer555, RAM_button, input JMP, Z_JMP, PZ_JMP, input [1:0] MUX_switch, input Acc_button, input Output_button, input [3:0] data_in, output [3:0] Acc, output [3:0] data_out, output [DATA_WIDTH-1:0] RAM, output Z_flag, PZ_flag, output reg [1:0] counter ); wire [1:0] branch_adr; assign branch_adr = data_in[1:0]; wire Z,PZ; assign Z = Z_flag & Z_JMP; assign PZ = PZ_flag & PZ_JMP; //Counter always @(posedge timer555) begin if(JMP|Z|PZ) counter <= branch_adr; else counter <= counter + 1; end wire [ADDR_WIDTH-1:0] adr; assign adr = counter; //RAM reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= Acc; assign RAM = mem[adr]; //sum wire [3:0] sum; assign sum = Acc + RAM; //subtract wire [3:0] subtract; assign subtract = Acc - RAM; //MUX reg [3:0] MUX4; always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : subtract) : (MUX_switch[0] ? sum : data_in); register4 Acc_reg( .reg_data(MUX4), .reg_clk(Acc_button), .q(Acc) ); register4 Output_reg( .reg_data(Acc), .reg_clk(Output_button), .q(data_out) ); assign Z_flag = ~(|Acc); assign PZ_flag = ~Acc[3]; endmodule

Wir legen die Befehle und Adressen in einen RAM / RAM und die Daten in einen anderen.

Das Schema kann hier heruntergeladen
werden .
In den ersten acht Ziffern werden Befehle gespeichert, in den letzten vier Ziffern wird die Adresse in den ZĂ€hler geladen.
Im Allgemeinen sollte das Laden einer Nummer in die
Ass- Batterie nach dem Umschalten des
MUX-Multiplexers (fĂŒr
ADD- ,
SUB- ,
LDA- Befehle) entsprechend dem Taktabfall erfolgen.
T.O. in unserem Computer das folgende Befehlssystem
48x - ADD fĂŒge eine Nummer aus dem RAM zu Ass hinzu
50x - SUB subtrahiert die im RAM gespeicherte Zahl von Ass
80x - STA speichert die Nummer von der Batterie im RAM unter der Adresse x
58x - LDA lÀdt eine Nummer von Adresse x in Ass
04x - BRA bedingungsloser Ăbergang zur Zelle mit der Adresse x
02x - BRZ-Ăbergang zur Zelle mit der Adresse x, wenn Ass = 0 (bedingter Ăbergang)
01x - BRP-Ăbergang zur Zelle mit der Adresse x, wenn Ass> = 0 (bedingter Ăbergang)
40x - INP lÀdt eine Nummer aus data_input in Ass
20x - OUT lÀdt die Nummer von Ass nach data_out
Wir werden kein
HLT-Team haben .
Nehmen Sie zum Beispiel den Algorithmus zum Ermitteln von maximal zwei Zahlen auf der Website
http://peterhigginson.co.uk/LMC/.Der Algorithmus funktioniert folgendermaĂen: Wir speichern zwei Zahlen aus data_in im Datenspeicher. Subtrahieren Sie die erste von der zweiten Zahl:
- Wenn das Ergebnis negativ ist, schreiben Sie die erste Zahl in Ass, schreiben Sie die Zahl von Ass in data_out;
- Wenn das Ergebnis positiv ist, schreiben Sie die zweite Zahl in Ass, schreiben Sie die Zahl von Ass in data_out.
00 INP
01 STA 11
02 INP
03 STA 12
04 SUB 11
05 BRP 08
06 LDA 11
07 BRA 09
08 LDA 12
09 OUT
In unserem Befehlssystem sieht dieser Algorithmus folgendermaĂen aus
400
80b
400
80c
50b
018
58b
049
58c
200

Das Element
NICHT am Steuereingang des ZÀhlers, der zum Laden von Daten in den ZÀhler benötigt wird, ist ein solches Merkmal des Logisim-Programms. In realen Schemata wird das Element
NICHT am Steuereingang benötigt (zumindest kenne ich solche ZÀhler nicht).
Quartus II kann von der offiziellen
Website heruntergeladen werden .
Wenn Sie sich unter Meine primÀre Jobfunktion * registrieren, wÀhlen Sie Student.
Als nĂ€chstes mĂŒssen Sie den Treiber fĂŒr den Programmierer herunterladen (der Treiber fĂŒr USB-Blaster kann unter C: \ altera \ ... \ quartus \ drivers \ USB-Blaster installiert werden).
Logisim kann hier heruntergeladen
werden .