Parte IParte IIParte IIIParte ivParte vEsta é a versão completa do artigo anterior, à qual os bancos de teste foram adicionados.
Desenhamos
Little Man Computer em Verilog.
O artigo sobre o LMC foi
publicado em Habré.
O simulador online deste computador está
aqui .
Vamos escrever um módulo de RAM, composto por quatro (ADDR_WIDTH = 2) palavras de quatro bits (DATA_WIDTH = 4). Os dados são carregados na RAM a partir de data_in em adr quando o clk do sinal do relógio chega.
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
No banco de ensaio, carregue 0001 em 00, 0010 em 01, 0100 em 10, 1000 em 11:
Crie um testbenchCrie um novo projeto, crie os arquivos R0.v e tR0.v (esses arquivos serão adicionados automaticamente ao projeto).
Compile os dois arquivos.
Executar simulação do arquivo compilado 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

Conectamos o contador à entrada de endereço da RAM. É necessário conectar um gerador de relógio à entrada do contador.
Aqui está um exemplo de um programa usando o gerador interno ALTUFM_OSC. Frequência de um gerador padrão de 5,5 MHz (placa de desenvolvimento mínimo MAX II EPM240 CPLD).
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
Você também pode usar um gerador externo, como um timer de 555 CMOS (alimentado por 3,3V). Conectamos o cronômetro 555 ao contador, o contador à entrada de endereço da RAM.
T.O. quando um sinal de relógio chegar ao balcão, iremos para a próxima célula na memória. Vamos conectar o botão RAM_button à entrada do relógio da RAM - os dados na RAM serão carregados quando esse botão for clicado.
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
É assim que o circuito se parece no RTL Viewer

No simulador ModelSim, esse esquema não funcionará, pois o simulador não sabe o valor inicial dos registros do contador [1: 0].
A operação do circuito pode ser verificada baixando diretamente o programa no FPGA.
Em seguida, adicione a função de download ao contador. Faça o download do data_in [1: 0] clicando no botão 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
É assim que a conexão de botões e LEDs no Pin Planner se parece:

Download 0001 às 00, 0010 às 01, 0100 às 10, 1000 às 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

Em um módulo separado, crie um registro 4bit'ny (bateria).
Os dados são carregados no registro quando você clica no botão 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
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.
O número do MUX2 é carregado na bateria Acc pressionando o botão Acc_button.
O número do Ass é carregado na RAM quando o botão RAM_button é pressionado.


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
Para a supressão programática de conversas, você pode usar o esquema simples fornecido nos comentários
/ * reg Acc_dff;
always @ (posedge Acc_button ou negedge timer555)
if (! timer555)
Acc_dff <= 1'b0;
mais
Acc_dff <= timer555; * /
Você também pode ler sobre a supressão de conversas de botão nos comentários do artigo.
Em seguida, adicionaremos os números, por exemplo, 2 e 3.
1. Carregar números na RAM
2. Zero o burro
3. Alterne o MUX2
4. Baixe o primeiro número da RAM para o Ass
5. Adicione o segundo número da RAM ao número no Ass
6. Baixe o valor para 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

Adicione ao módulo principal um elemento que subtraia do número na bateria o número gravado na memória.
wire [3:0] subtract; assign subract = Acc - RAM_out ;
Substituímos o multiplexador de duas entradas pelo de quatro entradas
always @* MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM_out : 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 quatro dígitos. A bandeira é levantada se o conteúdo de Ass for maior ou igual a zero.
// "" output Z_flag; assign Z_flag = ~(|Acc); // // " " output PZ_flag; assign PZ_flag = ~Acc[3];

Adicione três equipes
1. carregar o conteúdo da bateria no dispositivo de saída data_out
2. 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 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. Carregar números na RAM
2. Zero o burro
3. Alterne o MUX2
4. Subtraia o primeiro número (escrito em RAM) de Ass
5. Subtraia o segundo número (escrito em RAM) de Ass
6. Baixe o valor para RAM e 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

Verifique se quando um número positivo está em Ass, a transição Z_JMP não ocorre:
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

Coloque o comando de salto incondicional na RAM

Exibir design
//wire Counter_load; always @ (posedge timer555) if (Counter_load) counter <= RAM_out[3:0]; else counter <= counter + 2'b01;
O ModelSim não funcionará, portanto, usaremos o comando reset_count adicional, que inicializa o contador, redefinindo-o, ou seja,
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
banco de ensaio
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

Adicione ao circuito MUX2 e Ass. Vamos gravar em Ass com o comando RAM_out [6].
assign Acc_button = RAM_out[6];
Vamos conectar um log à entrada do relógio Ass. elemento AND
// regiser4 (posedge reg_button) (negedge reg_button) .reg_button(Acc_button & timer555),
O significado de conectar um log. elemento E para a entrada do relógio é que agora, na frente do timer555, você pode alternar o multiplexador e, ao mesmo tempo, recusar a gravação na bateria. T.O. nós colocamos duas equipes em uma batida.
Mudaremos o MUX2 com o comando 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
No banco de testes, escreva o número 0101 na célula 00 e o número 1010 na célula 01; carregue esses números na bateria
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

Colocamos a segunda RAM no circuito geral e gravamos na RAM com o comando 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
No testbench, carregue os números 0100 e 1000 do Ass para zero 0000 e a primeira célula 0001 da RAM mem2 (carregue esses números no Ass da 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

Vou acrescentar que o esquema c log. o elemento E na entrada do relógio da bateria nem sempre funciona corretamente (dependendo da placa). Substitua o log. elemento E para o gatilho Acc_dff, carregaremos o gatilho na borda negativa (no declínio) do sinal do relógio timer555, carregaremos a bateria na borda positiva
// Acc_dff reg Acc_dff; always @(negedge timer555) Acc_dff <= Acc_button;
Portanto, adicionando os comandos restantes, crie o módulo 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
No testbench, verificaremos como o algoritmo para encontrar o número máximo funciona.
A peculiaridade de carregar comandos na RAM é que, após carregar todos os comandos, precisamos retornar (340ns) à célula 8 e carregar outro comando
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
Link para o github com códigos de programa.
A versão gratuita para estudantes do
ModelSim para Windows pode ser baixada em
www.model.com .
Em seguida, você deve (preenchendo o formulário) fazer o download do arquivo student_license.dat e colocá-lo no diretório principal do programa
ModelSim .
Link para o arquivo
ModelSim para Linux (Ubuntu)
aquiInstruções de instalação
aqui .