-
Notifications
You must be signed in to change notification settings - Fork 195
Capítulo 13: Inicializando registros
Ejemplos de este capítulo en github
Ya podemos responder a la pregunta planteada en el capítulo 8 sobre cómo realizar la inicialización de los registros. Los registros sintetizados están a 0. Normalmente necesitamos cargar en ellos un valor inicial, y que luego funcionen para lo que hayan sido diseñados. En este capítulo mostraremos cómo hacerlo, usando las herramientas que ya conocemos: el multiplexor y el inicializador
Partimos de un registro genérico de N bits, que ya conocemos, con una entrada din, una salida dout y una señal de reloj
Queremos que se cargue con un valor inicial al principio y que luego funcione normalmente. Para hacerlo colocamos un multiplexor de 2 a 1 en su entrada (para dividir la entrada en 2). Por una entrada del multiplexor ponemos el valor inicial y por la otra la entrada genérica del registro din2.
Es muy importante que el valor inicial se introduzca por la fuente 0 del multiplexor.
Ahora ya simplemente conectamos un inicializador a la entrada de selección del multiplexor.
De esta forma, al arrancar, el inicializador emitirá un 0 y por la entrada din del registro llegará el valor inicial. En el siguiente flanco de subida este valor inicial se captura y el inicializador pasa a 1, por lo que ahora se seleccionará la fuente 1, que será por donde vengan los datos del registro en el régimen normal de funcionamiento.
Vamos a rehacer el circuito blink4 del capítulo 8. Este circuito hacía parpadear los 4 leds a la vez, produciendo la secuencia: 0000, 1111, 0000 ...
Ahora lo vamos a mejorar haciendo que se pueda poner cualquier valor inicial en el registro, lográndose la secuencia INI, ~INI, INI ... (valor inicial y su negado alternativamente):
La descripción de este circuito en Verilog es:
//-- reginit.v
module reginit(input wire clk, output wire [3:0] data);
//-- Parametros del secuenciador:
parameter NP = 23; //-- Bits del prescaler
parameter INI = 4'b1100; //-- Valor inicial a cargar en registro
//-- Reloj a la salida del presacaler
wire clk_pres;
//-- Salida del regitro
reg [3:0] dout;
//-- Entrada del registro
wire [3:0] din;
//-- Señal de seleccion del multiplexor
reg sel = 0;
//-- Registro
always @(posedge(clk_pres))
dout <= din;
//-- Conectar el registro con la salida
assign data = dout;
//-- Multiplexor de inicializacion
assign din = (sel == 0) ? INI : ~dout;
//-- Inicializador
always @(posedge(clk_pres))
sel <= 1;
//-- Prescaler
prescaler #(.N(NP))
PRES (
.clk_in(clk),
.clk_out(clk_pres)
);
endmodule
El multiplexor de 2 a 1 ha sido implementado usando el operador ? : (similar al operador condicional de lenguaje C). Es un if-else abreviado:
assign din = (sel == 0) ? INI : ~dout;
Es equivalente a:
always @*
if (sel == 0)
din <= INI;
else
din <= ~dout;
pero la primera notación es más compacta
Para sintetizarlo en la fpga conectaremos las salidas data a los leds, y la entrada de reloj a la de la placa iCEstick
Sintetizamos con el comando:
$ make sint
Los recursos empleados son:
Recurso | ocupación |
---|---|
PIOs | 4 / 96 |
PLBs | 10 / 160 |
BRAMs | 0 / 16 |
Para cargar en la FPGA ejecutamos:
$ sudo iceprog reginit4.bin
En este vídeo de Youtube se puede ver la salida de los leds:
El banco de pruebas es uno básico, que instancia el componente reginit, con 1 bit para el prescaler (para que la simulación tarde menos). Tiene un proceso para la señal de reloj y uno para la inicialización de la simulación
El código verilog es:
//-- reginit_tb.v
module reginit_tb();
//-- Registro para generar la señal de reloj
reg clk = 0;
//-- Datos de salida del componente
wire [3:0] data;
//-- Instanciar el componente, con prescaler de 1 bit (para la simulacion)
reginit #(.NP(1))
dut(
.clk(clk),
.data(data)
);
//-- Generador de reloj. Periodo 2 unidades
always #1 clk = ~clk;
//-- Proceso al inicio
initial begin
//-- Fichero donde almacenar los resultados
$dumpfile("reginit_tb.vcd");
$dumpvars(0, reginit_tb);
# 30 $display("FIN de la simulacion");
$finish;
end
endmodule
La simulación se realiza con:
$ make sim
El resultado en gtkwave es:
Se puede ver cómo el registro se carga con su valor inicial 1100 y se van alternando los valores 0011 y 1100
- Ejercicio 1: Modificar el valor inicial para obtener una secuencia diferente
TODO
0 You are leaving the privative sector (EN)
1 ¡Hola mundo! (EN) (RU)
2 De un bit a datos (EN)
3 Puerta NOT (EN)
4 Contador de 26 bits (EN)
5 Prescaler de N bits (EN)
6 Múltiples prescalers (EN)
7 Contador de 4 bits con prescaler (EN)
8 Registro de 4 bits (EN)
9 Inicializador (EN)
10 Registro de desplazamiento (EN)
11 Multiplexor de 2 a 1 (EN)
12 Multiplexor de M a 1 (EN)
13 Inicializando registros (EN)
14 Registro de N bits con reset síncrono
15 Divisor de frecuencias
16 Contador de segundos
17 Generando tonos audibles
18 Tocando notas
19 Secuenciando notas
20 Comunicaciones serie asíncronas
21 Baudios y transmisión
22 Reglas de diseño síncrono
23 Controladores y autómatas finitos
24 Unidad de transmisión serie asíncrona
25 Unidad de recepción serie asíncrona
26 Memoria ROM
27 Memoria ROM genérica
28 Memoria RAM
29 Puertas triestado
30 Hacia el microprocesador y más allá