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í .