-
Notifications
You must be signed in to change notification settings - Fork 195
Chapter 8: 4 bit register
Examples of this chapter on github
Registers are essential elements in digital circuits. We can store information, from 1 to N bits. They are used to implement processors, perform segmentation, storage of intermediate results, and more.
The basic register captures the input data on the rising or falling edge of a clock, stores the data, and outputs it. The diagram is:
In this chapter we will use a 4 bit register to make the 4 LEDs on the iCEstick board blink.
The design we will use is the following:
The 4-bit register is initialized to 0. For the output dout 4 bits are output to 0. These 4 bits are changed to 1 when passing through the invertor. On the next rising ege of the clock, this new value of 4'b1111 is captured in the register. When the output dout is updated to 4b'1111, these results are again inverted and we've cycled back to the beginning. The result is the following sequence 0000, 1111, 0000, 1111 ... is obtained with each change corresponding to the rising edge of the clock. If the dout is connected to the LEDs, they were start turning on and off at 1/2 the clock frequency.
The complete design to be implemented in the FPGA is shown in this figure:
In order to actually be able to see the LEDs flicker, a prescaler is included. The hardware description in verilog is:
//-- blink4.v
module blink4(input wire clk, //--clock
output wire [3:0] data //-- output register);
//-- Bits for the prescaler
parameter N = 22;
//-- main clock (prescalor)
wire clk_base;
//-- register data
reg [3:0] dout = 0;
//-- wire to the register
wire [3:0] din;
//-- Instance of the prescaler
prescaler #(.N(N))
PRES (
.clk_in(clk),
.clk_out(clk_base)
);
//-- Register
always @(posedge(clk_base))
dout <= din;
//-- Not gate sets the input to the output
assign din = ~dout;
//-- output data from the register to the output of the module
assign data = dout;
endmodule
We remember that the implementation of a register is extremely simple. Just use this code:
always @(posedge(clk_base))
dout <= din;
This is the reason why we won't normally use hiearchical design for registers: it's too simple for hierarchy makes any improvements.
We have used a compact definition of the blink4 module parameters: everything is defined in the module declaration itself:
module blink4(input wire clk, output wire [3:0] data);
But this could have been done as well:
module blink4(input clk, output [3:0] data);
wire clk;
wire data;
or this way:
module blink4(clk, data);
input clk;
output data;
wire clk;
wire [3:0] data;
The later form is used to define parametric components (see below)
To synthesize the design in the FPGA we run:
$ make sint
The resources used are:
Resource | utilization |
---|---|
PIOs | 3 / 96 |
PLBs | 8 / 160 |
BRAMs | 0 / 16 |
To download to the FPGA we do:
$ sudo iceprog blink4.bin
In the video you can see the result:
The synthesized registers always have an initial value of 0. The line of code defining the register is:
reg [3:0] dout = 0;
But the initialization in this line only works for simulation. It can give any value and we will see it in the simulation, however in "real hardware" we cannot do this. They will always be initialized to 0. To put another value we would have to load the register with this value. In the example blink4, if we could load the record initially with the value 1'b1010 (instead of 1'b0000), inverting it woudl yield 1'b0101. So we would have a different sequence: 1010, 0101, 1010 ... How coudl we implement this load? It is left as an exercise for the user to think about. In the following chapters we will show the necessary elements to accomplish it.
The test bench is very basic. It simply instantiates the blink4 component, generates the clock signal, and starts the simulation. For the simulation to run for less cycles, the prescaler N parameter has been set to 1 bit.
The code is:
//-- blink4.v
module blink4_tb();
//-- register to generate the clock signal
reg clk = 0;
//-- output data of the component
wire [3:0] data;
//-- Instantiate the component
blink4 #(.N(1))
TOP (
.clk(clk),
.data(data)
);
//-- generate the clock with a 2 period cycle
always #1 clk = ~clk;
//-- process to start
initial begin
//-- file to store the results
$dumpfile("blink4_tb.vcd");
$dumpvars(0, blink4_tb);
# 100 $display("FIN de la simulacion");
$finish;
end
endmodule
to simulate, we execute:
$ make sim
The output of gtkwave is:
You can see the sequence 0000, 1111, 0000, 1111 ...
- Ex1: Change the flashing frequency of the LEDs
- Ex2: How could we make it so that the registers are loaded with 1'b1010 initially and thus get the sequence 1010, 0101, 1010.... instead of the current one? Think about it. In the following chapters we will go over the necessary elements to do it.
- Ex3: Add self checking to the simulation so that the simulation warns you if the sequence is wrong. Change the simulation initialization to 1'b1111 to verify the self checking works.
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á