 Parte 1Parte IIParte IIIParte ivParte v
Parte 1Parte IIParte IIIParte ivParte vDiseñamos 
Little Man Computer en Verilog.
El artículo sobre LMC fue sobre Habré.
El simulador en línea de esta computadora está 
aquí .
Escribimos un módulo RAM / RAM que consta de cuatro (N = 2) palabras de cuatro bits (M = 4). Los datos se cargan en la 
RAM desde 
data_in en 
adr cuando hace clic en el botón:
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 
Como generador externo, conecte 
un temporizador 555 CMOS (que funcione desde 3.3V).
Conectamos 
el temporizador 555 al contador, conectamos el contador a la entrada de dirección de 
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 
Aquí, al describir el contador del 
contador y la memoria de memoria, se utilizan asignaciones sin bloqueo 
<= Los operadores de asignación se consideran en el 
sitio web 
marsohod.org aquíUna descripción del contador está en 
marsohod.org aquíAgregue la función de descarga al contador.
La descarga se realiza con el comando 
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 
En un módulo separado, cree un registro de 4 bits (batería):
 module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(posedge reg_button) q <= reg_data; endmodule 
Agregue el acumulador 
Acc , el multiplexor 
MUX2 y el sumador al circuito general.
El sumador agrega al número en la batería los números 
Acc de la memoria.
Las entradas de señal del multiplexor reciben los datos 
data_in y 
sum .
A continuación, el número del multiplexor 
MUX2 se carga en la batería 
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 
Siempre @ * significa "siempre". Algunos sintetizadores no entienden este diseño. También se puede escribir un multiplexor sin Always @ * (aquí se usa solo como ejemplo).

Resta
Para realizar una resta, es necesario proporcionar un número 
restado en 
un código adicional . Puede leer sobre la suma y resta de números binarios en el libro de texto "Circuitos digitales y arquitectura de computadoras" (David M. Harris y Sarah L. Harris) en el capítulo 
1.4.6 El signo de los números binariosAgregue al módulo principal un elemento que resta del número en la batería los números almacenados en la memoria:
 wire [3:0] subtract; assign subract = Acc - RAM ; 
Reemplace el multiplexor de 2 entradas con 4 entradas:
 always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : subtract) : (MUX_switch[0] ? sum : data_in); 
Conectamos el dispositivo de salida a la batería (4bit'ny registro), también conectamos 2 banderas a la batería:
1. La bandera "Cero" es un registro. Elemento 4 O NO. La bandera se levanta si el contenido de 
Ass es cero.
2. La bandera "Número cero o positivo" es un registro. el elemento NO está en el nivel alto de la batería de 4 bits. La bandera se levanta si el contenido de 
Ass es mayor o igual que cero.
 // "" output Z_flag; assign Z_flag = ~(|Acc); // 4-  - // "   " output PZ_flag; assign PZ_flag = ~Acc[3]; 
4 o noAquí describimos una válvula de entrada múltiple O NO como ~ (| Acc)
Verilog también es compatible con un conjunto de tipos de puerta.
Las siguientes palabras clave se definen para puertas lógicas: y (AND), nand (AND-NOT) u (OR), ni (OR-NOT), xor (Exclusive OR), xnor (Exclusive OR-NOT), buf (elemento Buffer) , no (Negación, NO).
En Verilog, cuando use puertas, debe especificar las entradas y salidas del elemento, así como (opcionalmente) el nombre de la puerta. Por ejemplo, las válvulas y y o deben tener una salida y dos o más entradas. Entonces, para la válvula nor, tenemos
ni nombrar list_of_ argumentos
ni mynor (fuera, in0, in1, in2, in3);
 
Agrega tres equipos
1. cargar el contenido de la batería en el 
dispositivo de salida 
data_out2. cargar la dirección en el contador si se levanta la bandera "cero" ( 
JMP si 
Acc = 0)
3. cargar la dirección en el contador si se levanta la bandera "cero o un número positivo" ( 
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 

Ponemos los comandos y las direcciones en una RAM / RAM, y los datos en otra.

El esquema se puede descargar 
desde aquí .
En los primeros ocho dígitos, los comandos se almacenan, en los últimos cuatro dígitos la dirección se carga en el contador.
En general, la carga de un número en la batería 
Ass debe realizarse después de cambiar el 
multiplexor MUX (para los comandos 
ADD , 
SUB , 
LDA ), de acuerdo con la caída del reloj.
T.O. en nuestra computadora el siguiente sistema de comando
48x - AGREGAR agrega un número de RAM a Ass
50x - SUB resta el número almacenado en la RAM del culo
80x: STA guarda el número del culo de la batería en la RAM en la dirección x
58x - LDA carga un número de la dirección x en Ass
04x: transición incondicional de BRA a la celda con dirección x
02x: transición de BRZ a la celda con la dirección x, si Ass = 0 (transición condicional)
01x: transición de BRP a la celda con dirección x, si Ass> = 0 (transición condicional)
40x - INP carga un número de data_input en Ass
20x - OUT carga el número de Ass a data_out
No tendremos un 
equipo HLT .
Tomemos, por ejemplo, el algoritmo para encontrar el máximo de dos números del sitio 
http://peterhigginson.co.uk/LMC/El algoritmo funciona así: almacenamos dos números de data_in en la memoria de datos. Resta el primero del segundo número:
- si el resultado es negativo, escriba el primer número en Ass, escriba el número de Ass en data_out;
- si el resultado es positivo, escriba el segundo número en Ass, escriba el número de Ass en 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
En nuestro sistema de comando, este algoritmo se verá así
400
80b
400
80c
50b
018
58b
049
58c
200

El elemento que 
NO está en la entrada de control del contador necesario para cargar datos en el contador es una característica del programa Logisim; en esquemas reales, el elemento que 
NO está en la entrada de control no es necesario (al menos no conozco tales contadores).
Quartus II se puede descargar desde el sitio 
web oficial.
Cuando se registre en Mi función de trabajo principal es *, seleccione Estudiante.
A continuación, debe descargar el controlador para el programador (el controlador para usb-blaster se puede instalar desde C: \ altera \ ... \ quartus \ drivers \ usb-blaster).
Logisim se puede descargar 
aquí .