-
Notifications
You must be signed in to change notification settings - Fork 195
Capítulo 8: registro de 4 bits
Ejemplos de este capítulo en github
Los registros son elementos esenciales en los circuitos digitales. Nos pemiten almacenar información, desde 1 hasta N bits. Se utilizan para implementar procesadores, realizar segmentación, almacenamiento de resultados intermedios, etc.
El registro básico captura los datos de la entrada, en flanco de subida o bajada del reloj, los almacena y los saca por la salida. Su esquema es:
En este capitulo utilizaremos un registro de 4 bits para hacer que parpadeen los 4 leds de la placa iCEstick
El esquema que utilizaremos es el siguiente:
El registro de 4 bits inicialmente está inicializado a 0. Por la salida dout salen 4 bits a 0, que se convierten en 4 bits a 1 al pasar por el inversor. En el siguiente flanco de subida del reloj, se captura este nuevo valor 4'b1111 en el registro. Al salir por dout, se vuelve a invertir obteniéndose 4 bits a 0, como al principio. El resultado es que se obtiene la siguiente secuencia 0000, 1111, 0000, 1111 ... que cambia con cada flanco de subida del reloj. Si ahora la salida dout la conectamos a los leds, estos empezarán a encenderse y apagarse con la frecuencia del reloj.
El diseño completo a implementar en la FPGA se muestra en esta figura:
Para poder apreciar el parpadeo, se incluye un prescaler. La descripción del hardware en Verilog es:
//-- blink4.v
module blink4(input wire clk, //--Reloj
output wire [3:0] data //-- Salida del registro);
//-- Bits para el prescaler
parameter N = 22;
//-- Reloj principal (prescalado)
wire clk_base;
//-- Datos del registro
reg [3:0] dout = 0;
//-- Cable de entrada al registro
wire [3:0] din;
//-- Instanciar el prescaler
prescaler #(.N(N))
PRES (
.clk_in(clk),
.clk_out(clk_base)
);
//-- Registro
always @(posedge(clk_base))
dout <= din;
//-- Puerta NOT entra la salida y la entrada
assign din = ~dout;
//-- Sacar datos del registro por la salida
assign data = dout;
endmodule
Obsevamos que la implementación de un registro es extremadamente sencilla. Basta con este código:
always @(posedge(clk_base))
dout <= din;
Esta es la razón por la que normalmente no usaremos un diseño jerárquico: no es necesario incluir el código en un fichero a parte por lo sencillo que es.
Hemos usado una definición compacta de los parámetros del módulo blink4: todo está definido en la propia declaración del módulo:
module blink4(input wire clk, output wire [3:0] data);
Esto se podría haber hecho también así:
module blink4(input clk, output [3:0] data);
wire clk;
wire data;
o así:
module blink4(clk, data);
input clk;
output data;
wire clk;
wire [3:0] data;
Esta última forma se utiliza para definir componentes paramétricos (lo veremos más adelante)
Para sintetizar el diseño en la FPGA hacemos:
$ make sint
Los recursos empleados son:
Recurso | ocupación |
---|---|
PIOs | 3 / 96 |
PLBs | 8 / 160 |
BRAMs | 0 / 16 |
Para descargar en la FPGA hacemos:
$ sudo iceprog blink4.bin
En este vídeo se puede ver el resultado:
Los registros sintetizados tienen siempre el valor inicial 0. La línea de código:
reg [3:0] dout = 0;
sólo sirve para la simulación. Se puede dar cualquier valor y lo veremos en la simulación, sin embargo en "hardware de verdad" no podemos hacer esto. Siempre se inicializarán a 0. Para poner otro valor tendremos que cargar el registros con este valor. En el ejemplo blink4, si pudiésemos cargar el registro inicialmente con el valor 1010 (en vez de 0000), al negarse se obtendría el 0101. Por lo que tendríamos una secuencia diferente: 1010, 0101, 1010 ... ¿Cómo podríamos implementar esta carga? Se deja como ejercicio para ir pensando sobre ello. En los siguientes capítulos se mostrarán los elementos necesarios para poder hacerlo.
El banco de pruebas es muy básico. Simplemente se instancia el componente blink4, se genera la señal de reloj y se inicia la simulación. Para que la simulación sea más rápida, se ha establecido el parámetro N del prescaler a 1 bit
El código es:
//-- blink4.v
module blink4_tb();
//-- Registro para generar la señal de reloj
reg clk = 0;
//-- Datos de salida del componente
wire [3:0] data;
//-- Instanciar el componente
blink4 #(.N(1))
TOP (
.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("blink4_tb.vcd");
$dumpvars(0, blink4_tb);
# 100 $display("FIN de la simulacion");
$finish;
end
endmodule
Para simular ejecutamos:
$ make sim
La salida de gtkwave es:
Se observa cómo aparece la secuencia 0000, 1111, 0000, 1111 ...
- Ej1: Cambiar la frecuencia de parpadeo de los leds
- Ej2: ¿Cómo podríamos hacer para que el registros se cargue inicialmente con el valor 1010 y así obtener la secuencia 1010, 0101, 1010.... en vez de la actual? Pensar sobre ello. En los siguientes capítulos se irán enseñando los elementos necesarios para hacerlo
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á