Skip to content
Juan Gonzalez-Gomez edited this page Nov 2, 2023 · 124 revisions

Contents

Introduction

In this collection you will find Registers. Use these blocks in your digital circuits for opensource FPGAs created with icestudio

Installation in Icestudio

Find information about collections and how to install them on this link: Installing the iceK collection in Icestudio. It was written for the iceK collection as an example. Use the repo of the iceFF collection instead

Quick Download:

  • Download the ZIP file from the latest release
  • ...or get the ZIP file with the latest changes from the main branch: iceRegs.zip

Registers

The Registers store N-bits of information during a period of time. There are two main flavours: System Registers and standard registers, with or without reset input

System registers

The system register (Sys-Reg) captures the N-bits input data on every clock cycle. Therefore, this component is all the time reading information, at the system clock frecuency (very fast)

The input data at a given cycle n is captured on the rising edge of the system clock and output at the cycle n+1. Its N-bits initial value, (the value at cycle 0) can be set as a parameter. Its default value is 0

This is the Truth table

input (cycle n) output (cycle n+1)
d d

Where d is a N-bits data

Because the System register captures data at cycle n and output it at cycle n+1, it its said that it "Delays" the data 1 cycle

The system registers can be implemented in two diffent ways: Using DFF blocks or directly in Verilog

Implementation 1: DFFs

An N-bits system register is implemented with N DFFs in paralell. As an example, let's examine the 2-bits Sys-reg:

It is composed of two DFFs, one for the storing the least significant bit, b0 and the other for the most significant bit, b1. As it is a 2-bits register, there are 2 parameters, one for each bit

The block is called sys-reg-dff-2-bits. The dff means that this system registers is implemented using DFF blocks

All the N-bits system registers can be implemented in this way, but if we want them to be initialized with a value different than zero, it is difficult to use them, as the initial value should be given in binary. Imagine that we want a 32-bit register to store initially the value 0xFFFF. We have to assign to 1 their 32 parameters!

Currently there is no way in Icestudio to generate inputs for the parameters, other than assigning individual values. Therefore, this implementation is rarely used (Just for educational purposes, for showing graphically how we can build registers)

Implementation 2: Verilog

Although the system registers are composed of N DFFs, they can also be considered fundamental components: Units that store a single data. We use the register for building higher level components, like counters and so on

They can be directly (and easily) be implemented in Verilog:

This is the verilog code:

//-- Generic System register
//-- Number of bits
localparam N = 2;

//-- Initial value
reg [N-1:0] qi = INI;

always @(posedge clk)
  qi <= d;
  
//-- Connect the register with the
//-- output
assign q = qi;

It is a generic register with one parameter: N. Just changing this parameter is enough for creating a system register of a different size

Example 1: Stream of two values

In this example a data stream of two values is generated. The values are 2 and 1, both can be represented with only 2-bits (values 10 and 01 in binary). The value 2 is generated at cycle 0 and the value 1 at cycle 1

In this chronogram is shown the data stream. It initially (at cycle 0) has the value of 2. In the next cycle it changes to 1 (and it remains unchaged until the circuit is reset)

This circuit is implemented using a 2-bit system register with an initial value of 2. The input is connected to the constant 1, so that it will capture this new value in the next cycle

The complete example also includes a 2-bit data LEDOSCOPE, so that we can capture the values at cycles 0 and 1, and show them on the LEDs (one sample at a time)

It initially shows the sample 0 (value 2). When the button is pressed, it shows the sample 1 (value 1). If the botton is pressed again it will shown the sample 0 again

We see the final value in LEDs 0 and 1. As the data stream changes very fast (at the system clock rate of speed) we cannot see how the LEDs changes, so we only see the final value (1). But we can see the two values on the LEDs connected to the LEDOSCOPE (in pins D0 and D1)

We can also use a Logica analyzer but it is easier with the LEDOSCOPE

Example 2: Stream of four 8-bit values

A stream of four 8-bits values: 0x80, 0x20, 0x08 and 0x02 is generated. These values are written on the cycles 0 to 3. This is the chronogram:

This circuit is implemented using three 8-bit system register with the initial values of 0x80, 0x20 and 0x08. They are connected in cascade. The final stable value is implemented with a constant (0x02), that is connected to the system register on the left

These four values are captured by the LEDOSCOPE and displayed on the LEDs. Initially the sample 0 (taken at cycle 0) is shown. When the button is pressed, the next sample is displayed. After the sample 3, it shows again the sample 0

We see the final value in LEDs 0 to 7. As the data stream changes very fast (at the system clock rate of speed) we cannot see how the LEDs changes, so we only see the final value (0x02). But we can see the four values on the LEDs connected to the LEDOSCOPE (in pins from D0 to D3)

We can also use a Logica analyzer but it is easier with the LEDOSCOPE

System registers with reset

The System register with reset (Sys-Reg-rst) works exactly the same as the Sys-Reg: it captures the input data on every clock cycle. But it includes the rst input for setting the register to its initial value (The one set in their Init top parameter)

This is the table that defines how this register works. The rst input has priority over the data input. When rst is 1, the output is always the initial value (regardless of the input data d)

rst d (cycle n) output (cycle n+1)
0 d d
1 d Initial value

Implementation with blocks

The system register with input reset is implemented with a system register and a N-bit 2-1 Multiplexer. While the reset input (rst) is not active (0), the Sys-Reg is capturing the input data (d). When the reset input is active, the initial value is captured.

Notice that the priority is on the rst pin, as it is used for selecting the multiplexer. No matter what value is in d if the rst input is 1

This is the implementation of a 2-bits System register with reset:

Verilog implementation

The system register with reset can be implemented directly in verilog as follows:

This is the verilog code:

//-- Generic System register
//-- with reset
//-- Number of bits
localparam N = 2;

//-- Initial value
reg [N-1:0] qi = INI;

always @(posedge clk)
begin

  //-- Reset: Capture the initial
  //-- value
  if (rst == 1'b1)
    qi <= INI;
    
  //-- No reset: Capture the input
  else
    qi <= d;
end

//-- Connect the register with the
//-- output
assign q = qi;

Notice the N parameter. This implementation correspond to a generic system register with reset. Change this vale to increase/decrease the number of bits

Example 3: Stream of two 8-bit values with reset

If we connect an 8-bit constant (0xAA) to the input of a system register (with an initial value of 0x55), what we get is a sequence of two values: 0x55 and 0xAA

But now, if we use a system register with reset, and we activate its reset input in cycle 1, the result is that this sequence is repeated in the next cycle:

This is the example circuit:

Registers with load input

The standard Register has two inputs: data (d) and load. It only captures the input when load is active (1). If load is 0, the input is ignored and the register does not change its value

Its behaviour is described on this table:

load d output (next cycle) Description
0 data No change The Register does not change its value
1 data data The data is captured

Notice that the Register behaves as a System register when load is 1.

The system Register let's us to store information only for one cycle. In the next cycle a new value will be captured (the sys-reg is capturing all the time). With the standard register we can retain the information all the time we want. It only changes when load is 1

The pulse symbol on the load input means that the Register will capture one data per 1-cycle pulse. If you apply a 2-cycles pulse, the DFF will perform two consecutives captures (on two consecutive cycles)

A Register with the load input connected to the 1 constant it is equivalent to a System register (Sys-Reg): It will capture the input on every system clock cycle

Implementation 1: Blocks

The N-bit Register is implemented with an N-bit system register and an N-bit 2-1 Multiplexer. While the load input (rst) is not active (0), the Sys-Reg is capturing its own value, so there is no change. When load is 1, the input data is captured.

Implementation 2: Verilog

Although the system registers are composed of N DFFs, they can also be considered fundamental components: Units that store a single data. We use the register for building higher level components, like counters and so on

The register with load input can be directly (and easily) implemented in Verilog:

This is the verilog code:

//-- Generic register
//-- Number of bits
localparam N = 8;

//-- Initial value
reg [N-1:0] qi = INI;

always @(posedge clk)

  //-- The value is load only if  
  //-- load is 1
  if (load == 1'b1)
    qi <= d;
  
//-- Connect the register with the
//-- output
assign q = qi;

Example 4: Showing information on the LEDs

This is the classic example of displaying a number on the LEDs. Initially, the value 0xAA is shown. When the SW1 button is pressed, the register captures a 0x55, and the value is shown on the LEDs

Registers with reset and load input

The Register with reset and load (Reg-rst) works exactly the same as the Register with load, but it includes the rst input (with priority over load) for setting the register to its initial value

This is the table that defines how this register works. The rst input has priority over the load input. When rst is 1, the output is always the initial value

rst load d (cycle n) output (cycle n+1)
0 0 data no change
0 1 data data
1 x x Initial value

Implementation 1: Blocks

The Reg-rst is implemented with a system register with reset (sys-reg-rst) and a N-bit 2-1 Multiplexer. While the load input is not active (0), the Sys-Reg-rst is capturing its own value, so there is no change. When load is 1, the input data is captured. When the rst input is set to 1, the register changes to its initial value. The rst has priority over load

Implementation 2: Verilog

The register with reset and load input can be directly (and easily) implemented in Verilog:

This is the verilog code:

//-- Generic register with reset
//-- Number of bits
localparam N = 8;

//-- Initial value
reg [N-1:0] qi = INI;

always @(posedge clk)
begin

  //-- Reset has the priority
  if (rst == 1'b1)
    qi <= INI;
    
  else
    //-- The value is load only if  
    //-- load is 1
    if (load == 1'b1)
      qi <= d;
      
  //-- In any other case the reg
  //-- keeps its value
end

//-- Connect the register with the
//-- output
assign q = qi;

Example 5: Showing information on the LEDs

This is the classic example of displaying a number on the LEDs. Initially, the value 0xAA is shown. When the SW1 button is pressed, the register captures a 0x55, and the value is shown on the LEDs. If the SW2 is pressed, the register is reset and its initial value (0xAA) is displayed again

TestBenches

The circuits used for testing all que components of this collection can be found on this collection:

  • IceRegs-TB: Testbenches for the Registers. It is intended for developers, not for final users

Generation scripts

All the component of this collection have been created from templates by python scripts Each family of registers has its on Template and Generation script:

Block identifier Template Python Script
System registers Sys-reg Template-Sys-reg.ice generate-sys-reg.py
System registers with reset Sys-reg-rst Template-Sys-reg-rst.ice generate-sys-reg-rst.py
Registers Reg Template-Reg.ice generate-reg.py
Registers with reset Reg-rst Template-Reg-rst.ice generate-reg-rst.py

In this example it is shown how the System registers from 2 to 32 bits are created from the template

This is the command line that should be executed within the Template folder:

obijuan@Hoth:~/Develop/Icestudio-collections/iceRegs/Templates
$ python3 generate-sys-reg.py

This is the result:

If you need to modify the registers, open the corresponding template with Icestudio, edit the component (typically changing its verilog code) and save it

Then, you should generate the new registers with the corresponding script

Translations

The collection can be translated to any language. Any translation is very welcome!! 😀️ If you want to translate it to your native languaje please follow these instructions: Translating the collection into your language. This instructions are for the iceK collection, but the translation procedure is the same for any other collection

Organization of the collection

The Organization of this collections is exactly the same than all the other collections. It consist of the following folders:

  • blocks: This is were the icestudio blocks are located, with all the elements of the collection, organized by subfolders
  • examples: Circuit examples ready to use in Icestudio. Inside this examples there are some special elements:
    • 00-Index.ice: Collection index. Here you will see some of the more important blocks that the collection contains
  • icons: Here you will find the SVG files for the icons used in the collection blocks. You can edit them or create new icons from them
    • block+icon: Some of the blocks in SVG, for using them in your documentations. These are some examples:
  • locale: Folder with the English texts and their translation into other languages
  • wiki: Images used in this wiki

This is the Index file:

  • 00-Index.ice:

Contributing to the collection

Contributions are welcome! 😀️

You can contribute in different manners:

  • Adding new blocks
  • Translating the collection to your language
  • Migrating the examples to more boards

These are the steps to follow for contributing:

  1. Fork the iceRegs repo into your github account
  2. Clone it to your computer
  3. Install the collection as an external collection, so that you can access it from icestudio (See: Other uses: External collection)
  4. Create your own block
  5. Save it and click on Tools/Collection/Reload for using it and testing it
  6. Commit and push to your repo
  7. Emit a pull request

Important!

  • The main language is English: Create all your blocks and examples in English (the English text should be inside de .ice files). Then translate it to your local language (if you like), following the instructions mentioned here: Translating the collection into your language

  • The iceRegs collection is ONLY FOR REGISTERS. If you want to contribute with other type of blocks, do it in its corresponding collection (iceK, iceGates, iceRegs, iceCoders, iceFF...)