56 / 63 · Conceito
Banco de registradores de duas leituras e uma escrita com bypass
Implemente leituras independentes e escrita síncrona e confira bypass por endereço, inicialização e valid.
As aulas podem ser lidas gratuitamente. Inscreva-se para salvar o progresso.
Armazenamento que entrega dois valores simultaneamente
Para A+B, dois operandos são necessários no mesmo ciclo. Um banco de registradoresRegistrador Circuito que armazena vários bits de estado. Os registradores síncronos deste curso capturam a entrada especificada na borda de clock. Saiba mais 2-read/1-write oferece dois endereços de leitura e um de escrita. Aqui armazena oito palavras de 16 bits e registra ambas as leituras na borda de subida: endereços de três bits e capacidade de 128 bits. O endereço 0 é normal, sem regra de registrador constante.
Cada leitura tem enable e valid próprios. Uma pode parar enquanto a outra lê, e ambas podem ler o mesmo endereço. Dois endereços simultâneos acrescentam um custo diferente do aumento de capacidade. Em circuitos pequenos, pode-se usar uma matriz de flip-flopsFlip-flop Elemento que captura a entrada na borda de clock especificada e a mantém até a próxima. A entrada deve cumprir setup e hold. Saiba mais e duas redes de seleção; com RAM, pode-se replicar o armazenamento e compartilhar escritas para obter mais leituras. A declaração RTL não garante o recurso sintetizado.
Se a escrita coincide com a leitura
O contrato define que a leitura retorna o novo dado quando leitura e escrita coincidem em endereço e borda. Um bypass leva wr_data diretamente à entrada do registrador de leitura, sem esperar a atualização da matriz. Para a porta :
Se :
é o conteúdo anterior. Compare cada endereço de leitura independentemente. Encaminhar wr_data às duas portas por causa de uma colisão em apenas uma delas corrompe o outro operando. Omitir wr_en causa bypass incorreto mesmo sem escrita, se wr_addr coincidir.
module regfile8x16_2r1w (
input logic clk, rst, wr_en,
input logic [2:0] wr_addr,
input logic [15:0] wr_data,
input logic rd_en0, rd_en1,
input logic [2:0] rd_addr0, rd_addr1,
output logic [15:0] rd_data0, rd_data1,
output logic rd_valid0, rd_valid1
);
timeunit 1ns;
timeprecision 1ps;
logic [15:0] mem [0:7];
always_ff @(posedge clk) begin
if (rst) begin
rd_valid0 <= 1'b0;
rd_valid1 <= 1'b0;
end else begin
rd_valid0 <= rd_en0;
rd_valid1 <= rd_en1;
if (wr_en)
mem[wr_addr] <= wr_data;
if (rd_en0)
rd_data0 <= (wr_en && wr_addr == rd_addr0)
? wr_data : mem[rd_addr0];
if (rd_en1)
rd_data1 <= (wr_en && wr_addr == rd_addr1)
? wr_data : mem[rd_addr1];
end
end
endmoduleBypass muda a seleção de entrada, mas não elimina o estágio registrado. Aplique endereço e solicitação antes da borda e observe depois; um registrador seguinte pode receber a resposta na próxima borda. Mudar para leitura combinacional altera caminho e contrato temporal, não é uma simples abreviação de código.
Exemplo: apenas uma porta colide
Suponha M[2]=12 e M[5]=7 previamente escritos. Antes de E0, ative ambas as leituras com rd_addr0=2, rd_addr1=5 e escreva 20 em 2. Depois, a porta 0 responde 20 por bypass e a 1 responde 7 armazenado. A soma é 27, contra 19 numa implementação read-first sem bypass.
Em E1, leia 2 em ambas as portas enquanto escreve 30 ali: ambas respondem 30. Em E2, mantenha wr_addr=2, wr_data=99, mas wr_en=0 e leia 2: ambas devem responder 30. Esse ciclo detecta bypass baseado apenas em igualdade de endereços. Em E3, rd_en0=0 e rd_en1=1 produzem valid 0 e 1 respectivamente.
Cada coluna registra uma borda de subidaBorda de subida Instante em que o clock passa de 0 para 1. É diferente do nível alto, que abrange todo o intervalo com CLK=1. Saiba mais, entradas anteriores e estados «depois» atualizados, sem desenhar atraso físicoAtraso de propagação Tempo entre uma mudança de entrada e a estabilização da saída no valor correto. Equivalência lógica e comportamento temporal são propriedades distintas. Saiba mais. Parte-se de M[2]=12,M[5]=7, ambas as leituras sempre ativas e escrita em 2. A última coluna não deve encaminhar 99 porque wr_en=0.
Ver os dados da forma de onda
| Sinal | Forma de onda | Valores do barramento |
|---|---|---|
| borda | 234 | E0 → E1 → E2 |
| wr_en | 1.0 | |
| wr_data | 234 | 20 → 30 → 99 |
| rd_addr0 | 2.. | 2 |
| rd_addr1 | 23. | 5 → 2 |
| out0 depois | 23. | 20 → 30 |
| out1 depois | 23. | 7 → 30 |
O que precisa de inicialização
Reset síncrono ativo em nível alto impede escrever e zera ambos os valid; não reseta matriz nem dados de saída. Manter dados antigos com valid=0 é correto. O conteúdo da matriz permanece. Se o sistema admitir apenas trabalhos novos após reset, defina sua sequência de inicialização separadamente.
Ler um endereço durante sua primeira escrita produz, sim, valor definido por bypass. Lê-lo sem escrita antes da inicialização continua indeterminado. rd_valid indica resposta, não um bit initialized por endereço. A referência deve conferir se o conteúdo é conhecido antes de calcular uma leitura normal e tratar separadamente o bypass simultâneo.
Verifique as quatro combinações de enables, endereços iguais/diferentes, colisão com nenhuma porta, com 0, com 1 ou com ambas, escritas consecutivas e prioridade de reset. Múltiplas escritas estão fora do escopo: acrescentá-las exige definir primeiro a prioridade ao escrever simultaneamente no mesmo endereço. Mais portas mudam contrato e custo.
Experimente
M[1]=4 e M[4]=9. Com ambas as leituras ativas em 1 e 4, escreve-se 13 em 4: qual par sai? Na próxima borda, wr_en=0, wr_addr=1, wr_data=99 e ambas as leituras em 1: qual saída? Depois desative apenas a porta 0 e explique valid e consumo.
Ler a explicação
Primeiro (4,13): apenas a porta 1 colide e recebe o novo 13 por bypass. Depois (4,4): wr_en=0 impede usar 99. Ao desativar a porta 0, rd_valid0=0 e rd_valid1=1; seu registrador de dados mantém o anterior, mas não deve ser consumido como resposta válida. O endereço 0 pode ser escrito e lido como os demais.