Parte IParte IIParte IIIParte ivParte vDesenhamos
Little Man Computer em Verilog.
O artigo sobre o LMC foi
publicado em Habré.
O simulador online deste computador está
aqui .
Escrevemos um módulo RAM / RAM composto por quatro (N = 2) palavras de quatro bits (M = 4). Os dados são carregados na
RAM a partir de
data_in em
adr quando você clica no botão:
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 um gerador externo, conecte
um timer de 555 CMOS (operando a partir de 3,3V).
Conectamos
o cronômetro 555 ao contador, o contador à entrada de endereço da
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
Aqui, ao descrever o contador e a memória
mem , são utilizadas atribuições sem bloqueio
<= Operadores de atribuição são considerados no site
marsohod.org aquiUma descrição do contador está em
marsohod.org aquiAdicione a função de download ao contador.
O download é feito com o 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
Em um módulo separado, crie um registro de 4 bits (bateria):
module register4 ( input [3:0] reg_data, input reg_button, output reg [3:0] q ); always @(posedge reg_button) q <= reg_data; endmodule
Adicione o acumulador
Acc , o multiplexador
MUX2 e o somador ao circuito geral.
O somador adiciona ao número nos números de
Acc da bateria da memória.
As entradas de sinal do multiplexador recebem os números
data_in e
soma .
Em seguida, o número do multiplexador
MUX2 é carregado na bateria
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
Sempre @ * significa "sempre". Alguns sintetizadores não entendem esse design. Um multiplexador também pode ser escrito sem Always @ * (aqui é usado apenas como exemplo).

Subtração
Para executar uma subtração, é necessário fornecer um número
subtraído em
um código adicional . Você pode ler sobre a adição e subtração de números binários no livro “Circuitos digitais e arquitetura de computadores” (David M. Harris e Sarah L. Harris) no capítulo
1.4.6 O sinal de números bináriosAdicione ao módulo principal um elemento que subtraia do número na bateria os números armazenados na memória:
wire [3:0] subtract; assign subract = Acc - RAM ;
Substitua o multiplexador de 2 entradas por 4 entradas:
always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : subtract) : (MUX_switch[0] ? sum : data_in);
Conectamos o dispositivo de saída à bateria (registro 4bit'ny), também conectamos 2 sinalizadores à bateria:
1. A bandeira "Zero" é um log. Elemento 4 OU NÃO. A bandeira é levantada se o conteúdo de
Ass for zero.
2. A bandeira “Número Zero ou Positivo” é um log. o elemento NÃO está no nível alto da bateria de 4 bits. A bandeira é levantada se o conteúdo de
Ass for maior ou igual a zero.
// "" output Z_flag; assign Z_flag = ~(|Acc); // 4- - // " " output PZ_flag; assign PZ_flag = ~Acc[3];
4 OU NÃOAqui descrevemos uma válvula de entrada múltipla OU NÃO como ~ (| Acc)
O Verilog também suporta um conjunto de tipos de portas.
As seguintes palavras-chave são definidas para portas lógicas: e (AND), nand (AND-NOT) ou (OR), nem (OR-NOT), xor (OR exclusivo), xnor (OR-NOT exclusivo), buf (elemento do buffer) , não (Negação, NÃO).
No Verilog, ao usar portões, você deve especificar as entradas e saídas do elemento, bem como (opcionalmente) o nome do portão. Por exemplo, as válvulas e e ou devem ter uma saída e duas ou mais entradas. Então, para a válvula nem, nós temos
nem nome list_of_ argumentos
nem mynor (fora, in0, in1, in2, in3);

Adicione três equipes
1. carregando o conteúdo da bateria no
dispositivo de saída
data_out2. carregando o endereço no contador se a bandeira “zero” for levantada (
JMP se
Acc = 0)
3. carregando o endereço no contador se a bandeira “zero ou um número positivo” for levantada (
JMP se
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

Colocamos os comandos e endereços em uma RAM / RAM e os dados em outra.

O esquema pode ser baixado
aqui .
Nos oito primeiros dígitos, os comandos são armazenados, nos últimos quatro dígitos o endereço é carregado no contador.
Em geral, o carregamento de um número na bateria
Ass deve ser feito após a troca do
multiplexador MUX (para comandos
ADD ,
SUB ,
LDA ), de acordo com a queda do relógio.
T.O. em nosso computador, o seguinte sistema de comando
48x - ADD adiciona um número da RAM ao Ass
50x - SUB subtrai o número armazenado na RAM do Ass
80x - STA salva o número do conjunto da bateria na RAM no endereço x
58x - LDA carrega um número do endereço x no Ass
04x - transição incondicional do BRA para a célula com endereço x
02x - transição BRZ para a célula com o endereço x, se Ass = 0 (transição condicional)
01x - transição BRP para a célula com endereço x, se Ass> = 0 (transição condicional)
40x - INP carrega um número de data_input no Ass
20x - OUT carrega o número de Ass para data_out
Não teremos uma
equipe HLT .
Tomemos, por exemplo, o algoritmo para encontrar o máximo de dois números no site
http://peterhigginson.co.uk/LMC/O algoritmo funciona assim: armazenamos dois números de data_in na memória de dados. Subtraia o primeiro do segundo número:
- se o resultado for negativo, escreva o primeiro número em Ass, escreva o número de Ass em data_out;
- se o resultado for positivo, escreva o segundo número em Ass, escreva o número de Ass em 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
Em nosso sistema de comando, esse algoritmo será parecido com este
400
80b
400
80c
50b
018
58b
049
58c
200

O elemento
NÃO na entrada de controle do contador necessário para carregar dados no contador é um recurso do programa Logisim; em esquemas reais, o elemento
NÃO na entrada de controle não é necessário (pelo menos eu não conheço esses contadores).
O Quartus II pode ser baixado do
site oficial.
Quando o registro em Minha função principal de trabalho for *, selecione Aluno.
Em seguida, é necessário baixar o driver do programador (o driver do usb-blaster pode ser instalado em C: \ altera \ ... \ quartus \ drivers \ usb-blaster).
O Logisim pode ser baixado
aqui .