-
Notifications
You must be signed in to change notification settings - Fork 196
Capítulo 9: Inicializador
Ejemplos de este capítulo en github
Muchos circuitos digitales necesitan inicializarse antes de comenzar a trabajar normalmente. Su funcionamiento se divide en un estado de arranque, donde se inicializan los valores de los registros y un estado de régimen permanente donde se realiza la función para la que han sido diseñados.
Para lograr esto necesitamos un circuito de inicialización que nos genere una señal escalón: que inicialmente esté a cero y al llegar el primer flanco de reloj pase a 1 y permanezca a 1 durante todo el funcionamiento de la máquina.
Esto se implementa de una manera muy sencilla utilizando un registro de 1 bit [1] al que se le cablea un "1" en su entrada. Inicialmente el registro estará a 0. Al llegar el primer flanco de reloj, se captura el 1 y se saca por su salida, generando el flanco de subida para realizar la inicialización. Para el resto de ciclos de reloj esta señal siempre estará a 1
Al tratarse de un registro, lo podemos implementar igual que en el capítulo anterior. Esta es la implementación natural. Otra posibilidad es hacer una implementación optimizada, usando menos código verilog
Es la implementación más lógica. Se parte de un registro genérico de 1 bit, que ya sabemos cómo se modela y simplemente cableamos su entrada a 1 y sacamos su salida hacia fuera:
//-- init.v (implementación natural)
//-- Entrada: cable del reloj
//-- Salida: Cable con la señal de inicialización
module init(input wire clk, output wire ini);
//-- Cable de entrada el registro de 1 bit
wire din;
//-- Salida del registro de 1 bit (inicializado a 0) (solo para simulacion)
//-- En la sintesis siempre estará a 0
reg dout = 0;
//-- Registro genérico: en flanco de subida se captura la entrada
always @(posedge(clk))
dout <= din;
//-- Cablear la entrada a 1
assign din = 1;
//-- Conectar la salida del registro a la señal ini
assign ini = dout;
endmodule
Esta implementación es muy sencilla y se entiende muy bien. Se ve claramente que es un registro con un "1" cableado por la entrada, sin embargo es muy "verbosa". Hay que escribir mucho código
Podemos hacer lo mismo pero con mucho menos código implementando directamente un registro que asigne siempre un "1" a su salida:
//-- init.v (version optimizada)
module init(input wire clk, output ini);
//-- Registro de 1 bit inicializa a 0 (solo para simulacion)
//-- Al sintetizarlo siempre estará a cero con independencia
//-- del valor al que lo pongamos
reg ini = 0;
//-- En flanco de subida sacamos un "1" por la salida
always @(posedge(clk))
ini <= 1;
endmodule
Para probarlo en la fpga simplemente vamos a conectar la salida ini a un led. Al cargarlo en la FPGA sólo veremos cómo se enciende un led, sin embargo con ello tenemos nuestro circuito validado y listo para inicalizar los diseños de los capítulos siguientes
Lo sintetizamos con:
$ make sint
Los recursos utilizados son:
Recurso | ocupación |
---|---|
PIOs | 2 / 96 |
PLBs | 1 / 160 |
BRAMs | 0 / 16 |
Lo cargamos en la FPGA con:
$ sudo iceprog init.bin
El led se encenderá. Nuestro circuito de inicialización funciona, aunque le sacaremos más partido en los capítulos sucesivos :-)
Para simularlo utilizaremos un banco de pruebas simple, en el que no realizamos comprobación de la señal de salida (hay que hacerlo visualmente). Se instancia el componente, se coloca el reloj y el proceso de inicialización
El código Verilog es:
//-- init_tb.v
module init_tb();
//-- Registro para generar la señal de reloj
reg clk = 0;
//-- Datos de salida del componente
wire ini;
//-- Instanciar el componente
init
INIT (
.clk(clk),
.ini(ini)
);
//-- Generador de reloj. Periodo 2 unidades
always #2 clk = ~clk;
//-- Proceso al inicio
initial begin
//-- Fichero donde almacenar los resultados
$dumpfile("init_tb.vcd");
$dumpvars(0, init_tb);
# 20 $display("FIN de la simulacion");
$finish;
end
endmodule
El resultado de la simulación es:
Observamos cómo la señal ini está a 0 al comienzo y en cuanto llega el primer flanco se pone a 1, permaneciendo en ese estado el resto de ciclos
Por defecto, este inicializador está en el estado inicial durante 1 ciclo de reloj. Si nos interesase que estuviese durante más ciclos, sólo habría que añadir un prescaler a la entrada de reloj, y conectar su salida clk_out al reloj del registro
- Ejercicio 1: Modificar el inicializador para que su estado inicial dure más de 1 ciclo de reloj
TODO
[1] Un registro de 1 bit es en realidad un flip-flop. Sin embargo prefiero llamarlo registro de 1 bit para generalizar. Su implementación en Verilog es la misma que la de un registro de N bits
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á