Skip to content

Capítulo 13: Inicializando registros

Rafa Couto edited this page Nov 23, 2016 · 24 revisions

Ejemplos de este capítulo en github

Introducción

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

Inicializando registros

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.

reginit.v: Secuenciador de 2 estados con registro

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 ...

Imagen 3

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

Síntesis en la FPGA

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:

Click to see the youtube video

Simulación

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

Imagen 3

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:

Imagen 4

Se puede ver cómo el registro se carga con su valor inicial 1100 y se van alternando los valores 0011 y 1100

Ejercicios propuestos

  • Ejercicio 1: Modificar el valor inicial para obtener una secuencia diferente

Conclusiones

TODO

Clone this wiki locally