Partie IPartie IIPartie IIIPartie IVPartie VNous concevons
Little Man Computer dans Verilog.
L'article sur LMC était sur Habré.
Le simulateur en ligne de cet ordinateur est
ici .
Nous écrivons un module RAM / RAM composé de quatre (N = 2) mots de quatre bits (M = 4). Les données sont chargées dans la
RAM à partir de
data_in at
adr lorsque vous cliquez sur le bouton:
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
En tant que générateur externe, connectez
une minuterie CMOS
555 (fonctionnant à partir de 3,3 V).
Nous connectons
la minuterie 555 au compteur, connectons le compteur à l'entrée d'adresse de la
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
Ici, lors de la description du compteur de
compteur et de la mémoire
mem , des affectations non bloquantes sont utilisées
<= Les opérateurs d'affectation sont considérés sur le site
marsohod.org iciUne description du compteur est sur
marsohod.org iciAjoutez la fonction de téléchargement au compteur.
Le téléchargement se fait avec la commande
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
Dans un module séparé, créez un registre 4 bits (batterie):
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 .
Ensuite, le numéro du multiplexeur
MUX2 est chargé dans la batterie
Acc :
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
Toujours @ * signifie "toujours". Certains synthétiseurs ne comprennent pas cette conception. Un multiplexeur peut également être écrit sans Always @ * (ici, il est utilisé uniquement à titre d'exemple).

Soustraction
Pour effectuer une soustraction, il est nécessaire de fournir un nombre
soustrait dans
un code supplémentaire . Vous pouvez lire sur l'addition et la soustraction de nombres binaires dans le manuel «Circuit numérique et architecture informatique» (David M. Harris et Sarah L. Harris) au chapitre
1.4.6 Le signe des nombres binairesAjoutez au module principal un élément qui soustrait du nombre dans la batterie les nombres stockés en mémoire:
wire [3:0] subtract; assign subract = Acc - RAM ;
Remplacez le multiplexeur à 2 entrées par 4 entrées:
always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : 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 4 bits. Le drapeau est levé si le contenu de
Ass est supérieur ou égal à zéro.
// "" output Z_flag; assign Z_flag = ~(|Acc); // 4- - // " " output PZ_flag; assign PZ_flag = ~Acc[3];
4 OU NONIci, nous avons décrit une vanne à entrées multiples OU NON comme ~ (| Acc)
Verilog prend également en charge un ensemble de types de portes.
Les mots clés suivants sont définis pour les portes logiques: et (AND), nand (AND-NOT), ou (OR), ni (OR-NOT), xor (Exclusive OR), xnor (Exclusive OR-NOT), buf (élément Buffer) , pas (Negation, NOT).
Dans Verilog, lorsque vous utilisez des portes, vous devez spécifier les entrées et sorties de l'élément, ainsi que (éventuellement) le nom de la porte. Par exemple, les vannes et et ou doivent avoir une sortie et deux ou plusieurs entrées. Donc, pour la valve nor, nous avons
ni nom list_of_ arguments
ni mynor (out, in0, in1, in2, in3);

Ajouter trois équipes
1. chargement du contenu de la batterie dans le
périphérique de sortie
data_out2. 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 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

Nous mettons les commandes et les adresses dans une RAM / RAM, et les données dans une autre.

Le schéma peut être téléchargé à
partir d'ici .
Dans les huit premiers chiffres, les commandes sont stockées, dans les quatre derniers chiffres, l'adresse est chargée dans le compteur.
En général, le chargement d'un nombre dans la batterie
Ass doit être effectué après la commutation du
multiplexeur MUX (pour les commandes
ADD ,
SUB ,
LDA ), en fonction de la décroissance de l'horloge.
T.O. dans notre ordinateur, le système de commande suivant
48x - AJOUTER ajouter un numéro de RAM à Ass
50x - SUB soustrait le nombre stocké dans la RAM de Ass
80x - STA enregistre le numéro de la batterie dans la RAM à l'adresse x
58x - LDA charge un numéro à partir de l'adresse x dans Ass
04x - BRA transition inconditionnelle vers la cellule avec l'adresse x
02x - BRZ transition vers la cellule avec l'adresse x, si Ass = 0 (transition conditionnelle)
01x - BRP transition vers la cellule avec l'adresse x, si Ass> = 0 (transition conditionnelle)
40x - INP charge un nombre de data_input dans Ass
20x - OUT charge le nombre de Ass vers data_out
Nous
n'aurons pas d'équipe HLT .
Prenez par exemple l'algorithme de recherche du maximum de deux nombres sur le site
http://peterhigginson.co.uk/LMC/L'algorithme fonctionne comme ceci: nous stockons deux nombres de data_in dans la mémoire de données. Soustrayez le premier du deuxième nombre:
- si le résultat est négatif, écrivez le premier nombre dans Ass, écrivez le nombre de Ass dans data_out;
- si le résultat est positif, écrivez le deuxième nombre dans Ass, écrivez le nombre de Ass dans 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
Dans notre système de commande, cet algorithme ressemblera à ceci
400
80b
400
80c
50b
018
58b
049
58c
200

L'élément
NON à l'entrée de contrôle du compteur nécessaire pour charger des données dans le compteur est une telle caractéristique du programme Logisim; dans les schémas réels, l'élément
NON à l'entrée de contrôle n'est pas requis (au moins je ne connais pas de tels compteurs).
Quartus II peut être téléchargé sur le site
officiel .
Lorsque vous vous inscrivez sous la fonction Mon travail principal est *, sélectionnez Étudiant.
Ensuite, vous devez télécharger le pilote pour le programmeur (le pilote pour usb-blaster peut être installé à partir de C: \ altera \ ... \ quartus \ drivers \ usb-blaster).
Logisim peut être téléchargé
ici .