56 / 63 · Concepto
Banco de registros de dos lecturas y una escritura con bypass
Implemente lecturas independientes y escritura síncrona y compruebe bypass por dirección, inicialización y valid.
Las lecciones se pueden leer gratis. Inscríbete para guardar el progreso.
Almacenamiento que entrega dos valores a la vez
Para A+B se necesitan dos operandos en el mismo ciclo. Un banco de registrosRegistro Circuito que almacena varios bits de estado. Los registros síncronos de este curso capturan la entrada especificada en el flanco de reloj. Más información 2-read/1-write ofrece dos direcciones de lectura y una de escritura. Aquí almacena ocho palabras de 16 bits y registra ambas lecturas en flanco ascendente: direcciones de tres bits y 128 bits de capacidad. La dirección 0 es normal, sin regla de registro constante.
Cada lectura tiene enable y valid propios. Una puede detenerse mientras la otra lee, y ambas pueden leer la misma dirección. Dos direcciones simultáneas añaden un coste distinto del aumento de capacidad. En bancos pequeños puede usarse una matriz de flip-flopsFlip-flop Elemento que captura la entrada en el flanco de reloj especificado y la conserva hasta el siguiente. La entrada debe cumplir setup y hold. Más información y dos redes de selección; con RAM puede replicarse el almacenamiento y compartir escrituras para obtener más lecturas. La declaración RTL no garantiza el recurso sintetizado.
Si escribe lo que se está leyendo
El contrato responde el dato nuevo si lectura y escritura coinciden en dirección y flanco. Un bypass lleva wr_data directamente a la entrada del registro de lectura, sin esperar a actualizar la matriz. Para el puerto :
Si :
es el contenido previo. Compare cada dirección de lectura de forma independiente. Derivar wr_data a ambos puertos por colisión en uno corrompe el otro operando. Si se omite wr_en, el bypass se activa erróneamente incluso sin escritura cuando wr_addr coincide.
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 cambia la selección de entrada, pero no elimina la etapa registrada. Aplique dirección y solicitud antes del flanco y observe después; un registro posterior puede recibir la respuesta en el siguiente flanco. Cambiar a lectura combinacional altera camino y contrato temporal, no es una simple abreviatura de código.
Ejemplo: solo un puerto colisiona
Suponga M[2]=12 y M[5]=7 previamente escritos. Antes de E0, active ambas lecturas con rd_addr0=2, rd_addr1=5 y escriba 20 en 2. Después, el puerto 0 responde 20 por bypass y el 1 responde 7 almacenado. La suma es 27, frente a 19 de una implementación read-first sin bypass.
En E1, lea 2 en ambos puertos mientras escribe 30 allí: ambos responden 30. En E2, mantenga wr_addr=2, wr_data=99, pero wr_en=0 y lea 2: ambos deben responder 30. Ese ciclo detecta un bypass basado solo en igualdad de direcciones. En E3, rd_en0=0 y rd_en1=1 producen valid 0 y 1 respectivamente.
Cada columna registra un flanco ascendenteFlanco ascendente Instante en que el reloj pasa de 0 a 1. Se distingue del nivel alto, que abarca todo el intervalo con CLK=1. Más información, entradas previas y estados «después» actualizados, sin dibujar retardo físicoRetardo de propagación Tiempo desde un cambio de entrada hasta que la salida se estabiliza en el valor correcto. La equivalencia lógica y el comportamiento temporal son propiedades distintas. Más información. Se parte de M[2]=12,M[5]=7, ambas lecturas siempre activas y escritura en 2. La última columna no debe derivar 99 porque wr_en=0.
Ver los datos de la forma de onda
| Señal | Forma de onda | Valores del bus |
|---|---|---|
| flanco | 234 | E0 → E1 → E2 |
| wr_en | 1.0 | |
| wr_data | 234 | 20 → 30 → 99 |
| rd_addr0 | 2.. | 2 |
| rd_addr1 | 23. | 5 → 2 |
| out0 después | 23. | 20 → 30 |
| out1 después | 23. | 7 → 30 |
Qué necesita inicialización
Reset síncrono activo en alto impide escribir y borra ambos valid; no resetea matriz ni datos de salida. Conservar datos antiguos con valid=0 es correcto. El contenido de la matriz permanece. Si el sistema admite solo trabajos nuevos tras reset, defina su secuencia de inicialización aparte.
Leer una dirección durante su primera escritura sí produce un valor definido mediante bypass. Leerla sin escritura antes de inicializar sigue siendo indeterminado. rd_valid indica respuesta, no un bit initialized por dirección. La referencia debe comprobar que el contenido sea conocido antes de calcular una lectura normal y tratar por separado el bypass simultáneo.
Verifique las cuatro combinaciones de enables, direcciones iguales/distintas, colisión con ningún puerto, con 0, con 1 o con ambos, escrituras consecutivas y prioridad de reset. Múltiples escrituras quedan fuera del alcance: añadirlas exige definir primero la prioridad al escribir simultáneamente la misma dirección. Más puertos cambian contrato y coste.
Inténtalo tú
M[1]=4 y M[4]=9. Con ambas lecturas activas en 1 y 4, se escribe 13 en 4: ¿qué pareja sale? En el siguiente flanco, wr_en=0, wr_addr=1, wr_data=99 y ambas lecturas en 1: ¿qué sale? Después desactive solo el puerto 0 y explique valid y consumo.
Leer la explicación
Primero (4,13): solo el puerto 1 colisiona y deriva el nuevo 13. Después (4,4): wr_en=0 impide usar 99. Al desactivar el puerto 0, rd_valid0=0 y rd_valid1=1; su registro de datos conserva el anterior, pero no debe consumirse como respuesta válida. La dirección 0 es escribible y legible como las demás.