Conception du processeur ModelSim


Partie I
Partie II
Partie III
Partie IV
Partie V

Il s'agit de la version complÚte de l'article précédent, à laquelle des bancs d'essai ont été ajoutés.

Nous concevons Little Man Computer dans Verilog.

L'article sur LMC était sur Habré.

Le simulateur en ligne de cet ordinateur est ici .

Écrivons un module RAM, composĂ© de quatre (ADDR_WIDTH = 2) mots de quatre bits (DATA_WIDTH = 4). Les donnĂ©es sont chargĂ©es dans la RAM Ă  partir de data_in Ă  adr lorsque le signal d'horloge clk arrive.

module R0 #(parameter ADDR_WIDTH = 2, DATA_WIDTH = 4) ( input clk, //  input [ADDR_WIDTH-1:0] adr, // input [DATA_WIDTH-1:0] data_in, //   output [DATA_WIDTH-1:0] RAM_out //   ); reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; //  mem always @(posedge clk) //    clk mem [adr] <= data_in; //     data_in assign RAM_out = mem[adr]; // RAM_out    endmodule 

Dans le banc d'essai, charge 0001 Ă  00, 0010 Ă  01, 0100 Ă  10, 1000 Ă  11:
Créer un banc d'essai
Créez un nouveau projet, créez les fichiers R0.v et tR0.v (ces fichiers seront automatiquement ajoutés au projet).
Compilez les deux fichiers.
Exécuter la simulation du fichier compilé tR0.v

 module tR0; reg clk; reg [1:0] adr; reg [3:0] data_in; wire [3:0] RAM_out; R0 test_R0 (clk, adr, data_in,RAM_out); initial begin clk = 0; adr[0] = 0; adr[1] = 0; data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; #5 data_in[0] = 1; #5 clk = 1; #5 adr[0] = 1; data_in[0] = 0; data_in[1] = 1; clk = 0; #5 clk = 1; #5 adr[0] = 0; adr[1] = 1; data_in[1] = 0; data_in[2] = 1; clk = 0; #5 clk = 1; #5 adr[0] = 1; adr[1] = 1; data_in[2] = 0; data_in[3] = 1; clk = 0; #5 clk = 1; #5 adr[0] = 0; adr[1] = 0; data_in[3] = 0; clk = 0; #5 adr[0] = 1; adr[1] = 0; #5 adr[0] = 0; adr[1] = 1; #5 adr[0] = 1; adr[1] = 1; #5 adr[0] = 0; adr[1] = 0; #5 adr[0] = 1; adr[1] = 0; #5 adr[0] = 0; adr[1] = 1; #5 adr[0] = 1; adr[1] = 1; #5 adr[0] = 0; adr[1] = 0; #5 adr[0] = 1; adr[1] = 0; #5 adr[0] = 0; adr[1] = 1; #5 adr[0] = 1; adr[1] = 1; end endmodule 



Nous connectons le compteur à l'entrée d'adresse de la RAM. Il est nécessaire de connecter un générateur d'horloge à l'entrée du compteur.

Voici un exemple de programme utilisant le générateur interne ALTUFM_OSC. Fréquence d'un générateur standard 5,5 MHz (MAX II EPM240 CPLD Minimal Development Board).

 module inner_Clock ( output reg LED); ALTUFM_OSC osc( .oscena(1'b1), .osc(clk)); reg signal; reg [24:0] osc_counter; reg [24:0] const_data = 25'b10110111000110110000000; initial begin signal = 1'b0; osc_counter = 25'b0; end //  6 000 000    osc_counter always @(posedge clk) begin osc_counter <= osc_counter+ 1'b1; if(osc_counter == const_data) begin signal <= ~signal; osc_counter <= 25'b0; end LED = signal; // LED  ~1   . end endmodule 

Vous pouvez également utiliser un générateur externe, comme une minuterie CMOS 555 (alimentée par 3,3 V). Nous connectons la minuterie 555 au compteur, connectons le compteur à l'entrée d'adresse de la RAM.

T.O. lorsqu'un signal d'horloge arrive au compteur, nous allons passer à la cellule suivante en mémoire. Nous connecterons le bouton RAM_button à l'entrée d'horloge RAM - les données dans la RAM seront chargées lorsque ce bouton sera cliqué.

 module R1 (timer555, RAM_button, data_in, RAM_out, counter); parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; input timer555; input RAM_button; //input [ADDR_WIDTH-1:0] adr; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM_out; output reg [1:0] counter; // Counter always @(posedge timer555) counter <= counter + 1; // RAM wire [ADDR_WIDTH-1:0] adr; assign adr = counter; reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= data_in; assign RAM_out = mem[adr]; endmodule 

Voici comment le circuit dans RTL Viewer



Dans le simulateur ModelSim, ce schéma ne fonctionnera pas, car le simulateur ne connaßt pas la valeur initiale des registres du compteur [1: 0].
Le fonctionnement du circuit peut ĂȘtre vĂ©rifiĂ© en tĂ©lĂ©chargeant directement le programme sur le FPGA.

Ensuite, ajoutez la fonction de téléchargement au compteur. Téléchargez depuis data_in [1: 0] en cliquant sur le bouton Counter_load

 module R2 (counter, timer555, Counter_load, RAM_button, data_in, RAM_out); parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; output [1:0] counter; input timer555, Counter_load; // input [N-1:0] adr; input RAM_button; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM_out; // Counter reg [1:0] counter; always @ (posedge timer555 or posedge Counter_load) if (Counter_load) counter <= data_in[1:0]; else counter <= counter + 2'b01; // RAM wire [ADDR_WIDTH-1:0] adr; assign adr = counter; reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= data_in; assign RAM_out = mem[adr]; endmodule 

Voici Ă  quoi ressemble la connexion des boutons et des LED dans Pin Planner:



Télécharger 0001 à 00, 0010 à 01, 0100 à 10, 1000 à 11

 module tR2; parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; reg timer555, Counter_load, RAM_button; wire [1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM_out; R2 test_R2(counter, timer555, Counter_load, RAM_button, data_in, RAM_out); initial // Clock generator begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; Counter_load = 0; RAM_button = 0; #5 data_in[0]=0; data_in[1]=0; Counter_load=1; RAM_button=0; #5 data_in[0]=1; data_in[1]=0; Counter_load=0; RAM_button=1; #5 data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; #5 data_in[0]=1; data_in[1]=0; Counter_load=1; RAM_button=0; #5 data_in[0]=0; data_in[1]=1; Counter_load=0; RAM_button=1; #5 data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; #5 data_in[0]=0; data_in[1]=1; Counter_load=1; RAM_button=0; #5 data_in[2]=1; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=1; #5 data_in[2]=0; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; #5 data_in[0]=1; data_in[1]=1; Counter_load=1; RAM_button=0; #5 data_in[3]=1; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=1; #5 data_in[3]=0; data_in[0]=0; data_in[1]=0; Counter_load=0; RAM_button=0; end endmodule 



Dans un module séparé, créez un registre 4bit'ny (batterie).

Les données sont chargées dans le registre lorsque vous cliquez sur le bouton reg_button:

 module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(posedge reg_button) q <= reg_data; endmodule 

Ajoutez l'accumulateur Acc, le multiplexeur MUX2 et l'additionneur de somme au circuit général.
L'additionneur ajoute au nombre dans les numéros d'accumulateur de la batterie de la mémoire.
Les entrées de signal du multiplexeur reçoivent les nombres data_in et sum.
Le numéro de MUX2 est chargé dans la batterie Acc en appuyant sur le bouton Acc_button.
Le numéro de Ass est chargé dans la RAM lorsque le bouton RAM_button est enfoncé.





 module R3 (MUX_switch, Acc_button, Acc, counter, timer555, Counter_load, RAM_button, data_in, RAM_out); parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; input MUX_switch; input Acc_button; output [3:0] Acc; input timer555, Counter_load; output [1:0] counter; // input [N-1:0] adr; input RAM_button; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM_out; // Counter reg [1:0] counter; always @ (posedge timer555 or posedge Counter_load) if (Counter_load) counter <= data_in[1:0]; else counter <= counter + 2'b01; // RAM wire [ADDR_WIDTH-1:0] adr; assign adr = counter; reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= Acc; assign RAM_out = mem[adr]; // sum wire [3:0] sum; assign sum = Acc + RAM_out; // MUX2 reg [3:0] MUX2; always @* MUX2 = MUX_switch ? sum : data_in; //     Acc_button /* reg Acc_dff; always @(posedge Acc_button or negedge timer555) if (!timer555) Acc_dff <= 1'b0; else Acc_dff <= timer555; */ //Acc register4 Acc_reg( .reg_data(MUX2), //.reg_button(Acc_dff), .reg_button(Acc_button), .q(Acc) ); endmodule 

Pour la suppression de bavardage programmatique, vous pouvez utiliser le schéma simple donné dans les commentaires
/ * reg Acc_dff;
toujours @ (posedge Acc_button ou negedge timer555)
si (! timer555)
Acc_dff <= 1'b0;
d'autre
Acc_dff <= timer555; * /

Vous pouvez également lire sur la suppression des bavardages des boutons dans les commentaires de l'article.

Ensuite, nous ajouterons les nombres, par exemple, 2 et 3.

1. Charger des numéros dans la RAM
2. Zero the Ass
3. Commutateur MUX2
4. Téléchargez le premier numéro de RAM vers Ass
5. Ajoutez le deuxiĂšme nombre de RAM au nombre dans Ass
6. Téléchargez le montant sur la RAM

 module tR3; parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; reg MUX_switch; reg Acc_button; wire [3:0] Acc; reg timer555, Counter_load, RAM_button; wire [1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM_out; R3 test_R3(MUX_switch, Acc_button, Acc, counter, timer555, Counter_load, RAM_button, data_in, RAM_out); initial begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; Counter_load = 0; Acc_button = 0; RAM_button = 0; MUX_switch = 0; #5 Counter_load = 1; #5 data_in[0]=0; data_in[1]=1; Counter_load = 0; #5 Acc_button = 1; #5 RAM_button = 1; #5 data_in[0]=0; data_in[1] = 0; Acc_button = 0; RAM_button = 0; #5 data_in[0]=1; data_in[1]=1; #15 Acc_button = 1; #5 RAM_button = 1; #5 Acc_button = 0; #5 data_in[0]=0; data_in[1] = 0; RAM_button = 0; #10 Acc_button = 1; #10 Acc_button = 0; #60 MUX_switch = 1; #10 Acc_button = 1; #10 Acc_button = 0; #30 Acc_button = 1; #10 Acc_button = 0; #30 RAM_button = 1; #10 RAM_button = 0; end endmodule 



Ajoutez au module principal un élément qui soustrait du nombre dans la batterie le nombre enregistré dans la mémoire.

 wire [3:0] subtract; assign subract = Acc - RAM_out ; 


Nous remplaçons le multiplexeur à deux entrées par le multiplexeur à quatre entrées
 always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM_out : subtract) : (MUX_switch[0] ? sum : data_in); 

Nous connectons le périphérique de sortie à la batterie (registre 4bit'ny), nous connectons également 2 drapeaux à la batterie:

1. Le drapeau "Zero" est un journal. ÉlĂ©ment 4 OU NON. Le drapeau est levĂ© si le contenu de Ass est nul.

2. Le drapeau «Numéro zéro ou positif» est un journal. l'élément n'est PAS au niveau haut de la batterie à quatre chiffres. Le drapeau est levé si le contenu de Ass est supérieur ou égal à zéro.

 // "" output Z_flag; assign Z_flag = ~(|Acc); //    // "   " output PZ_flag; assign PZ_flag = ~Acc[3]; 



Ajouter trois équipes

1. chargement du contenu de la batterie dans le périphérique de sortie data_out
2. chargement de l'adresse dans le compteur si le drapeau "zéro" est levé (JMP si Acc = 0)
3. chargement de l'adresse dans le compteur si le drapeau "zéro ou un nombre positif" est levé (JMP si Acc> = 0)

 module R4 (JMP,Z_JMP,PZ_JMP,Z_flag,PZ_flag,Output_button,data_out,MUX_switch,Acc_button,Acc,counter,timer555,RAM_button,data_in,RAM_out); parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; input JMP, Z_JMP, PZ_JMP; output Z_flag, PZ_flag; input Output_button; output [3:0] data_out; input [1:0] MUX_switch; input Acc_button; output [3:0] Acc; input timer555; output [1:0] counter; input RAM_button; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM_out; // flags wire Z,PZ; assign Z = Z_flag & Z_JMP; assign PZ = PZ_flag & PZ_JMP; // Counter reg [1:0] counter; always @ (posedge timer555 or posedge JMP or posedge Z or posedge PZ) if (JMP|Z|PZ) counter <= data_in[1:0]; else counter <= counter + 2'b01; // RAM wire [ADDR_WIDTH-1:0] adr; assign adr = counter; reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= Acc; assign RAM_out = mem[adr]; // sum wire [3:0] sum; assign sum = Acc + RAM_out; //subtract wire [3:0] subtract; assign subtract = Acc - RAM_out; // MUX4 reg [3:0] MUX4; always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM_out : subtract) : (MUX_switch[0] ? sum : data_in); //Acc register4 Acc_reg( .reg_data(MUX4), .reg_button(Acc_button), .q(Acc) ); //data_out register4 Output_reg( .reg_data(Acc), .reg_button(Output_button), .q(data_out) ); assign Z_flag = ~(|Acc); assign PZ_flag = ~Acc[3]; endmodule 



1. Charger des numéros dans la RAM
2. Zero the Ass
3. Commutateur MUX2
4. Soustrayez le premier nombre (écrit en RAM) de Ass
5. Soustrayez le deuxiÚme nombre (écrit en RAM) de Ass
6. Téléchargez le montant sur RAM et data_out

 module tR4; parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; reg JMP, Z_JMP, PZ_JMP; wire Z_flag, PZ_flag; reg Output_button; wire [3:0] data_out; reg [1:0] MUX_switch; reg Acc_button; wire [3:0] Acc; reg timer555, RAM_button; wire [1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM_out; R4 test_R4 (JMP,Z_JMP,PZ_JMP,Z_flag,PZ_flag,Output_button,data_out,MUX_switch,Acc_button,Acc, counter,timer555,RAM_button,data_in,RAM_out); initial begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; JMP = 0; Z_JMP = 0; PZ_JMP = 0; Acc_button = 0; RAM_button = 0; Output_button = 0; MUX_switch[0] = 0; MUX_switch[1] = 0; #5 JMP = 1; #5 data_in[0]=0; data_in[1]=1; JMP = 0; #5 Acc_button = 1; #5 RAM_button = 1; #5 data_in[0]=0; data_in[1] = 0; Acc_button = 0; RAM_button = 0; #5 data_in[0]=1; data_in[1]=1; #15 Acc_button = 1; #5 RAM_button = 1; #5 Acc_button = 0; #5 data_in[0]=0; data_in[1] = 0; RAM_button = 0; #10 Acc_button = 1; #10 Acc_button = 0; #60 MUX_switch[1] = 1; #10 Acc_button = 1; #10 Acc_button = 0; #30 Acc_button = 1; #10 Acc_button = 0; #30 RAM_button = 1; Output_button = 1; #10 RAM_button = 0; Output_button = 0; end endmodule 



Vérifiez que lorsqu'un nombre positif se trouve dans Ass, la transition Z_JMP ne se produit pas:

 module tR4_jmp; parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 4; reg JMP, Z_JMP, PZ_JMP; wire Z_flag, PZ_flag; reg Output_button; wire [3:0] data_out; reg [1:0] MUX_switch; reg Acc_button; wire [3:0] Acc; reg timer555, RAM_button; wire [1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM_out; R4 test_R4 (JMP,Z_JMP,PZ_JMP,Z_flag,PZ_flag,Output_button,data_out,MUX_switch,Acc_button,Acc, counter,timer555,RAM_button,data_in,RAM_out); initial begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; JMP = 0; Z_JMP = 0; PZ_JMP = 0; Acc_button = 0; RAM_button = 0; Output_button = 0; MUX_switch[0] = 0; MUX_switch[1] = 0; #5 JMP = 1; #5 data_in[0]=0; data_in[1]=1; JMP = 0; #5 Acc_button = 1; #5 data_in[0]=1; data_in[1]=1; Acc_button = 1; #5 data_in[0]=1; data_in[1]=1; Acc_button = 0; #5 Z_JMP = 1; #5 PZ_JMP = 1; Z_JMP = 0; #5 PZ_JMP = 0; end endmodule 



Mettez la commande de saut inconditionnel dans la RAM



Voir la conception

 //wire Counter_load; always @ (posedge timer555) if (Counter_load) counter <= RAM_out[3:0]; else counter <= counter + 2'b01; 

ModelSim ne fonctionnera pas, nous utiliserons donc la commande reset_count supplémentaire, qui initialise le compteur, le réinitialise, c'est-à-dire

 module resCount (reset_count, counter, timer555, RAM_button, data_in, RAM_out); parameter ADDR_WIDTH = 4; parameter DATA_WIDTH = 8; input reset_count; output [ADDR_WIDTH-1:0] counter; input timer555; input RAM_button; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM_out; wire Counter_load; assign Counter_load = RAM_out[7]; reg [ADDR_WIDTH-1:0] counter; always @ (posedge timer555 or posedge reset_count) if (reset_count) counter <= 4'b0000; else if (Counter_load) counter <= RAM_out[3:0]; else counter <= counter + 4'b0001; wire [ADDR_WIDTH-1:0] adr; assign adr = counter; reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; always @(posedge RAM_button) mem [adr] <= data_in; assign RAM_out = mem[adr]; endmodule 

banc d'essai

 module tresCount; parameter ADDR_WIDTH = 4; parameter DATA_WIDTH = 8; reg reset_count; reg timer555, RAM_button; wire [ADDR_WIDTH-1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM_out; resCount test_resCount(reset_count, counter, timer555, RAM_button, data_in, RAM_out); initial // Clock generator begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; data_in[4] = 0; data_in[5] = 0; data_in[6] = 0; data_in[7] = 0; RAM_button = 0; reset_count =1; #5 reset_count =0; #1500 data_in[7] =1; #5 RAM_button = 1; #5 data_in[7] =0; RAM_button = 0; end endmodule 



Ajoutez au circuit MUX2 et Ass. Nous enregistrerons dans Ass avec la commande RAM_out [6].

 assign Acc_button = RAM_out[6]; 

Nous allons connecter un journal à l'entrée d'horloge Ass. élément ET

 //  regiser4  (posedge reg_button)  (negedge reg_button) .reg_button(Acc_button & timer555), 

Signification de la connexion d'un journal. élément Et à l'entrée d'horloge est que maintenant sur le devant de timer555 vous pouvez commuter le multiplexeur, et sur le déclin pour enregistrer dans la batterie. T.O. nous avons mis deux équipes en un seul temps.

Nous allons basculer MUX2 avec la commande RAM_out [5]

 assign MUX_switch = RAM_out[5]; 



 module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(negedge reg_button) //  "posedge"  "negedge" q <= reg_data; endmodule module R50 (reset_count, counter, timer555, RAM_button, data_in, RAM_out, mux_switch_out, mux_out,Acc_out); parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 8; input reset_count; output [ADDR_WIDTH-1:0] counter; input timer555; input RAM_button; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM_out; output [3:0] Acc_out; output mux_switch_out; output [3:0] mux_out; wire Counter_load; assign Counter_load = RAM_out[7]; //Counter reg [ADDR_WIDTH-1:0] counter; always @ (posedge timer555 or posedge reset_count) if (reset_count) counter <= 2'b00; else if (Counter_load) counter <= RAM_out[1:0]; else counter <= counter + 2'b01; 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] <= data_in; assign RAM_out = mem[adr]; // MUX2 wire MUX_switch; assign MUX_switch = RAM_out[5]; reg [3:0] MUX2; always @* MUX2 = MUX_switch ? RAM_out : data_in[3:0]; //  4   data_in assign mux_out = MUX2; assign mux_switch_out = MUX_switch; wire Acc_button; assign Acc_button = RAM_out[6]; //Acc register4 Acc_reg( .reg_data(mux_out), .reg_button(Acc_button & timer555), .q(Acc_out) ); endmodule 

Dans le banc de test, écrivez le nombre 0101 dans la cellule 00 et le nombre 1010 dans la cellule 01; charger ces numéros dans la batterie

 module tR50; parameter ADDR_WIDTH = 2; parameter DATA_WIDTH = 8; reg reset_count; reg timer555, RAM_button; wire [ADDR_WIDTH-1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM_out; wire mux_switch_out; wire [3:0] mux_out; wire [3:0] Acc_out; R50 test_R50(reset_count, counter, timer555, RAM_button, data_in, RAM_out, mux_switch_out, mux_out,Acc_out); initial // Clock generator begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 1; data_in[1] = 0; data_in[2] = 1; data_in[3] = 0; data_in[4] = 0; data_in[5] = 1; data_in[6] = 1; data_in[7] = 0; RAM_button = 0; reset_count =1; #5 RAM_button = 1; reset_count = 0; #5 data_in[0]=0; data_in[2]=0; data_in[5]=0; data_in[6]=0; RAM_button=0; #15 data_in[1]=1; data_in[3]=1; data_in[5]=1;data_in[6]=1; #5 RAM_button=1; #5 data_in[1]=0; data_in[3]=0; data_in[5]=0; data_in[6]=0; RAM_button=0; end endmodule 



Nous plaçons la deuxiÚme RAM dans le circuit général et écrivons dans la RAM avec la commande RAM1_out [4].

 assign RAM2_button = RAM1_out[4]; 



 module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(negedge reg_button) q <= reg_data; endmodule module R51 (reset_count, counter, timer555, RAM1_button, data_in, RAM1_out, RAM2_out, mux_switch_out, mux_out,Acc_out); parameter ADDR_WIDTH = 3; parameter DATA_WIDTH = 8; input reset_count; output [ADDR_WIDTH-1:0] counter; input timer555; input RAM1_button; input [DATA_WIDTH-1:0] data_in; output [DATA_WIDTH-1:0] RAM1_out; output [3:0] RAM2_out; output [3:0] Acc_out; output mux_switch_out; output [3:0] mux_out; wire Counter_load; assign Counter_load = RAM1_out[7]; //Counter reg [ADDR_WIDTH-1:0] counter; always @ (posedge timer555 or posedge reset_count) if (reset_count) counter <= 2'b00; else if (Counter_load) counter <= RAM1_out[1:0]; else counter <= counter + 2'b01; wire [ADDR_WIDTH-1:0] adr1; assign adr1 = counter; //RAM1 reg [DATA_WIDTH-1:0] mem1 [2**ADDR_WIDTH-1:0]; always @(posedge RAM1_button ) mem1 [adr1] <= data_in; assign RAM1_out = mem1[adr1]; wire [ADDR_WIDTH-1:0] adr2; assign adr2 = RAM1_out[3:0]; wire RAM2_button; assign RAM2_button = RAM1_out[4]; //RAM2 reg [3:0] mem2 [2**ADDR_WIDTH-1:0]; always @(posedge RAM2_button) mem2 [adr2] <= Acc_out; assign RAM2_out = mem2[adr2]; // MUX2 wire MUX_switch; assign MUX_switch = RAM1_out[5]; reg [3:0] MUX2; always @* MUX2 = MUX_switch ? RAM2_out : data_in[3:0]; assign mux_out = MUX2; assign mux_switch_out = MUX_switch; wire Acc_button; assign Acc_button = RAM1_out[6]; //Acc register4 Acc_reg( .reg_data(mux_out), .reg_button(Acc_button & timer555), .q(Acc_out) ); endmodule 

Dans le banc de test, chargez les nombres 0100 et 1000 de Ass à zéro 0000 et la premiÚre cellule 0001 de RAM mem2 (puis chargez ces nombres dans Ass de RAM mem2)

 module tR51; parameter ADDR_WIDTH = 3; parameter DATA_WIDTH = 8; reg reset_count; reg timer555, RAM1_button; wire [ADDR_WIDTH-1:0] counter; reg [DATA_WIDTH-1:0] data_in; wire [DATA_WIDTH-1:0] RAM1_out; wire [3:0] RAM2_out; wire mux_switch_out; wire [3:0] mux_out; wire [3:0] Acc_out; R51 test_R51(reset_count, counter, timer555, RAM1_button, data_in, RAM1_out, RAM2_out, mux_switch_out, mux_out,Acc_out); initial // Clock generator begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; data_in[4] = 0; data_in[5] = 0; data_in[6] = 1; data_in[7] = 0; RAM1_button = 0; reset_count =1; #5 RAM1_button = 1; reset_count = 0; #5 RAM1_button = 0; data_in[6] = 0; #10 data_in[4] = 1; #5 RAM1_button = 1; #5 data_in[4] = 0; RAM1_button = 0; #30 data_in[6] = 1; #5 RAM1_button = 1; #5 data_in[6] = 0; RAM1_button = 0; #30 data_in[4] = 1; data_in[0] = 1; #5 RAM1_button = 1; #5 data_in[4] = 0; data_in[0] = 0; RAM1_button = 0; #30 data_in[6] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[6] = 0; #30 data_in[5] = 1; data_in[6] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[5] = 0; data_in[6] = 0; #30 data_in[5] = 1; data_in[6] = 1; data_in[0] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[0] = 0; data_in[5] = 0; data_in[6] = 0; #70 data_in[2] = 1; #80 data_in[2] = 0; data_in[3] = 1; #40 data_in[3] = 0; end endmodule 



J'ajouterai que le schéma c log. l'élément And à l'entrée d'horloge de la batterie ne fonctionnera pas toujours correctement (selon la carte). Remplacez le journal. element Et sur le déclencheur Acc_dff, nous chargerons dans le déclencheur sur le front négatif (sur le déclin) du signal d'horloge timer555, nous chargerons sur la batterie sur le front positif

 // Acc_dff reg Acc_dff; always @(negedge timer555) Acc_dff <= Acc_button; 

Donc, en ajoutant les commandes restantes, créez le module R52 (LMC)



 module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(posedge reg_button) // negedge -> posedge q <= reg_data; endmodule module R52 (Z_flag, PZ_flag, reset_count, counter, timer555, RAM1_button, data_in, RAM1_out, RAM2_out, mux_switch_out, mux_out, Acc_out, data_out, Acc_dff); parameter ADDR_WIDTH = 4; parameter DATA_WIDTH = 12; input reset_count; input timer555; input RAM1_button; input [DATA_WIDTH-1:0] data_in; output [ADDR_WIDTH-1:0] counter; output [1:0] mux_switch_out; output [3:0] mux_out; output [3:0] Acc_out; output [3:0] data_out; output [DATA_WIDTH-1:0] RAM1_out; output [3:0] RAM2_out; output Z_flag, PZ_flag; output Acc_dff; wire JMP_button, Z_JMP_button,PZ_JMP_button; assign JMP_button = RAM1_out[6]; assign Z_JMP_button = RAM1_out[5]; assign PZ_JMP_button = RAM1_out[4]; wire Z_JMP,PZ_JMP; assign Z_JMP = Z_flag & Z_JMP_button; assign PZ_JMP = PZ_flag & PZ_JMP_button; //Counter reg [ADDR_WIDTH-1:0] counter; always @ (posedge timer555 or posedge reset_count) if (reset_count) counter <= 4'b0000; else if (JMP_button|Z_JMP|PZ_JMP) counter <= RAM1_out[3:0]; else counter <= counter + 4'b0001; wire [ADDR_WIDTH-1:0] adr1; assign adr1 = counter; //RAM1 reg [DATA_WIDTH-1:0] mem1 [2**ADDR_WIDTH-1:0]; always @(posedge RAM1_button ) mem1 [adr1] <= data_in; assign RAM1_out = mem1[adr1]; //RAM2_adr wire [ADDR_WIDTH-1:0] adr2; assign adr2 = RAM1_out[2:0]; //RAM2_button wire RAM2_button; assign RAM2_button = RAM1_out[11]; //RAM2 reg [3:0] mem2 [2**ADDR_WIDTH-1:0]; always @(posedge RAM2_button) mem2 [adr2] <= Acc_out; assign RAM2_out = mem2[adr2]; // sum wire [3:0] sum; assign sum = Acc_out + RAM2_out; //subtract wire [3:0] subtract; assign subtract = Acc_out - RAM2_out; // MUX4 wire [1:0] mux_switch; assign mux_switch[0] = RAM1_out[7]; assign mux_switch[1] = RAM1_out[8]; reg [3:0] MUX4; always @* MUX4 = mux_switch[1] ? (mux_switch[0] ? RAM2_out : subtract) : (mux_switch[0] ? sum : data_in[3:0]); assign mux_out = MUX4; assign mux_switch_out[0] = mux_switch[0]; assign mux_switch_out[1] = mux_switch[1]; //Acc_button wire Acc_button; assign Acc_button = RAM1_out[10]; // Acc_dff reg Acc_dff; always @(negedge timer555) Acc_dff <= Acc_button; //Acc register4 Acc_reg( .reg_data(mux_out), //.reg_button(Acc_button & timer555), .reg_button(Acc_dff), .q(Acc_out) ); //data_out wire Output_button; assign Output_button = RAM1_out[9]; register4 Output_reg( .reg_data(Acc_out), .reg_button(Output_button), .q(data_out) ); // flags assign Z_flag = ~(|Acc_out); assign PZ_flag = ~Acc_out[3]; endmodule 

Dans le banc de test, nous vérifierons le fonctionnement de l'algorithme de recherche du nombre maximum.

La particularité de charger des commandes dans la RAM est qu'aprÚs avoir chargé toutes les commandes, nous devons retourner (340ns) à la cellule 8 et charger une autre commande

 module tR52; parameter ADDR_WIDTH = 4; parameter DATA_WIDTH = 12; reg reset_count; reg timer555; reg RAM1_button; reg [DATA_WIDTH-1:0] data_in; wire [ADDR_WIDTH-1:0] counter; wire [1:0]mux_switch_out; wire [3:0] mux_out; wire [3:0] Acc_out; wire [3:0] data_out; wire [DATA_WIDTH-1:0] RAM1_out; wire [3:0] RAM2_out; wire Z_flag, PZ_flag; wire Acc_dff; R52 test_R52(Z_flag, PZ_flag, reset_count, counter, timer555, RAM1_button, data_in, RAM1_out, RAM2_out, mux_switch_out, mux_out,Acc_out, data_out, Acc_dff); initial // Clock generator begin timer555 = 0; forever #20 timer555 = ~timer555; end initial begin data_in[0] = 0; data_in[1] = 0; data_in[2] = 0; data_in[3] = 0; data_in[4] = 0; data_in[5] = 0; data_in[6] = 0; data_in[7] = 0; data_in[8] = 0; data_in[9] = 0; data_in[10] = 1; data_in[11] = 0; RAM1_button = 0; reset_count =1; //  1-    #5 RAM1_button = 1; reset_count = 0; #5 RAM1_button = 0; data_in[10] = 0; data_in[0] = 0; //  1-    0 #10 data_in[11] = 1; #5 RAM1_button = 1; #5 data_in[11] = 0; RAM1_button = 0; //  2-    #30 data_in[10] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[10] = 0; //  2-    0 #30 data_in[11] = 1;data_in[0] = 1; #5 RAM1_button = 1; #5 data_in[11] = 0;data_in[0] = 0; RAM1_button = 0; // 1-    #30 data_in[8]=1; data_in[10] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[8]=0; data_in[10] = 0; //  Acc>=0,    8 #30 data_in[4]=1; data_in[3]=1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[4]=0; data_in[3]=0; //  1-  #30 data_in[7] = 1; data_in[8] = 1; data_in[10] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[7] = 0; data_in[8] = 0; data_in[10] = 0; //     9 #30 data_in[6] = 1; data_in[3]=1; data_in[0]=1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[6] = 0; data_in[3]=0; data_in[0]=0; //   data_out #30 data_in[9] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[9] = 0; //     8 #30 data_in[6] = 1; data_in[3]=1; data_in[0]=0; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[6] = 0; data_in[3]=0; data_in[0]=0; // 2-  #30 data_in[7] = 1; data_in[8] = 1; data_in[10] = 1; data_in[0] = 1; #5 RAM1_button = 1; #5 RAM1_button = 0; data_in[7] = 0; data_in[8] = 0; data_in[10] = 0; data_in[0] = 0; #75 RAM1_button = 1; #5 RAM1_button = 0; #230 data_in[2]=1; data_in[0]=0; //  #80 data_in[2]=0; data_in[0]=1; //   end endmodule 

Lien vers github avec les codes de programme.

La version gratuite pour Ă©tudiants de ModelSim pour Windows peut ĂȘtre tĂ©lĂ©chargĂ©e sur www.model.com .
Ensuite, vous devez (en remplissant le formulaire) télécharger le fichier student_license.dat et placer ce fichier dans le répertoire principal du programme ModelSim .

Lien vers le fichier ModelSim pour Linux (Ubuntu) ici
Instructions d'installation ici .

Source: https://habr.com/ru/post/fr412379/


All Articles