VHDLwhiz VHDL Registers UART Test Interface Generator User Manual

June 13, 2024
VHDLwhiz

VHDLwhiz - logo VHDLwhiz.com
VHDL registers UART test interface generator – User manual

Version: 1.0.0
Date: September 1, 2023
Author: Jonas Julian Jensen
Product URL: https://vhdlwhiz.com/product/vhdl-registers-uart-test- interfacegenerator
Contact email: jonas@vhdlwhiz.com
This document describes using VHDLwhiz’s UART test interface generator to produce a custom VHDL module and Python script for reading and writing FPGA register values.

License

The MIT license covers the source code’s copyright requirements and terms of use.
Refer to the LICENSE.txt file in the Zip file for details.

Changelog

These changes refer to the project files, and this document is updated accordingly.

Version Remarks
1.0.0 Initial release

Description

This document describes the following files and folders:

  • gen_uart_regs.py
  • generated/uart_regs.vhd
  • generated/uart_regs.py
  • generated/instantiation_template.vho
  • rtl/uart_regs_backend.vhd
  • rtl/uart_rx.vhd
  • rtl/uart_tx.vhd
  • demo/lattice_icestick/
  • demo/xilinx_arty_a7_35/
  • demo/xilinx_arty_s7_50/

The gen_uart_regs.py script and supporting VHDL files in this project allow you to generate custom interfaces for reading and writing FPGA register values of various types and widths using UART.
You can use the generated VHDL module and Python script to read from or write to any number of registers in your design. The UART accessible registers can have the types std_logic, std_logic_vector, signed, or unsigned.
You can decide on the precise composition of input and output registers and types when generating the output files using the gen_uart_regs.py script.
The Python scripts were created partially with the help of the ChatGPT artificial intelligence tool, while the VHDL code is handcrafted.

Requirements

The scripts in this project must be run through a Python 3 interpreter and the Pyserial package must be installed.
You can install Pyserial through Pip using this command: pip install pyserial

Protocol

The VHDL files and Python script uses a data framing protocol with four control characters:

Name Value Comment
READ REQ OxOA Command from the host to the FPGA to initiate a write sequence

to send all registers back over UART
START_WRITE| Ox0B| Marks the beginning of a write sequence in either direction
END_WRITE| OxOC| Marks the end of a write sequence in either direction
ESCAPE| OxOD| Escape character used for escaping any of the control words, including the ESCAPE character itself, when they appear as data between the START_WRITE and END_WRITE markers.

Any unescaped READ_REQ byte sent to the FPGA is an instruction to send all of its UART-accessible registers (inputs and outputs) back to the host over UART. This command is usually only issued by the uart_regs.py script.
Upon receiving this command, the FPGA will respond by sending the content of all registers back to the host. First, the input signals, then the output signals. If their lengths don’t add up to a multiple of 8 bits, the lower bits of the last byte will be padded zeros.
A write sequence always starts with the START_WRITE byte and ends with the END_WRITE byte. Any bytes between those are considered to be data bytes. If any data bytes have the same value as a control character, the data byte must be escaped. This means sending an extra ESCAPE character before the data byte to indicate that it’s actually data.
If an unescaped START_WRITE arrives anywhere in the stream of bytes, it is considered the start of a write sequence. The uart_regs_backend module uses this information to resynchronize in case the communication gets out of sync.

gen_uart_regs.py

This is the script you must start with to generate the interface. Below is a screenshot of the help menu that you can get by running: python gen_uart_regs.py -hVHDLwhiz VHDL Registers UART Test Interface Generator -
code

To generate a custom interface, you must run the script with each of your desired UART controllable registers listed as arguments. The available types are std_logic, std_logic_vector, unsigned, and signed.
The default mode (direction) is in and the default type is std_logic_vector unless the register is of length: 1. Then, it will default to std_logic.
Thus, if you want to create a std_logic input signal, you can use any of these arguments:
my_sl=1
my_sl=1:in
my_sl=1:in:std_logic
All of the above variants will result in the script generating this UART- accessible signal:VHDLwhiz VHDL Registers UART Test Interface Generator -
code 2

Let’s run the script with arguments to generate an interface with several registers of different directions, lengths, and types:VHDLwhiz VHDL
Registers UART Test Interface Generator - code 3

Generated files

A successful run of the gen_uart_regs.py script will produce an output folder named generated with the three files listed below. If they already exist, they will be overwritten.

  • generated/uart_regs.vhd
  • generated/uart_regs.py
  • generated/instantiation_template.vho

uart_regs.vhd
This is the custom interface module generated by the script. You need to instantiate it in your design, where it can access the registers you want to control using UART.
Everything above the “– UART accessible registers” section will be identical for every uart_regs module, while the composition of port signals below that line depends on the arguments given to the generator script.
The listing below shows the entity for the uart_regs module resulting from the generate command example shown in the gen_uart_regs.py section.VHDLwhiz VHDL Registers
UART Test Interface Generator - code 4

You do not need to synchronize the uart_rx signal, as that’s handled in the uart_rx. module.
When the module receives a read request, it will capture the values of all input and output signals within the current clock cycle. The instantaneous snapshot is then sent to the host over UART.
When a write happens, all output registers are updated with the new values within the same clock cycle. It is not possible to change output signal values individually.
However, the uart_regs.py script allows the user to update only selected outputs by first reading back the current values of all registers. It then writes back all values, including the updated ones.

uart_regs.py
The generated/uart_regs.py file is generated together with the uart_regs VHDL module and contains the custom register information in the header of the file. With this script, you can read from or write to your custom registers with ease.
Help menu
Type python uart_regs.py -h to print the help menu:VHDLwhiz VHDL
Registers UART Test Interface Generator - code 5

Setting the UART port

The script has options to set the UART port using the -c switch. This works on Windows and Linux. Set it to one of the available ports listed in the help menu. To set a default port, you can also edit the UART_PORT variable in the uart_regs.py script.
Listing registers
Information about the register mapping is placed in the header of the uart_regs.py script by the gen_uart_regs.py script. You can list the available registers with the -l switch, as seen below. This is a local command and will not interact  with the target FPGA. VHDLwhiz VHDL Registers UART Test
Interface Generator - code 6

Writing to registers

You can write to any of the out mode registers by using the -w switch. Supply the register name followed by “=” and the value given as a binary, hexadecimal, or decimal value, as shown below.VHDLwhiz VHDL Registers UART
Test Interface Generator - code 7

Note that the VHDL implementation requires the script to write all output registers simultaneously. Therefore, if you don’t specify a complete set of output registers, the script will first perform a read from the target FPGA and then use those values for the missing ones. The result will be that only the specified registers change.
When you perform a write, all specified registers will change during the same clock cycle, not as soon as they are received over UART.

Reading registers
Use the -r switch to read all register values, as shown below. The values marked in yellow are the ones we changed in the previous write example.VHDLwhiz VHDL Registers UART Test Interface Generator - code
8

Every read shows an instantaneous snapshot of all input and output registers. They are all sampled during the same clock cycle.

Debugging

Use the -d switch with any of the other switches if you need to debug the communication protocol. Then, the script will print out all sent and received bytes and tag them if they are control characters, as shown below.

VHDLwhiz VHDL Registers UART Test Interface Generator - code
9

Using the interface in other Python scripts

The uart_regs.py script contains a UartRegs class that you can easily use as the communication interface in other custom Python scripts. Simply import the class, create an object of it, and start using the methods, as shown below.VHDLwhiz VHDL Registers UART Test Interface Generator - code
10

Refer to the docstrings in the Python code for method and descriptions and return value types.

instantiation_template.vho
The instantiation template is generated along with the uart_regs module for your convenience. To save coding time, you can copy the module instantiation and signal declarations into your design.VHDLwhiz VHDL Registers UART Test
Interface Generator - code 11VHDLwhiz
VHDL Registers UART Test Interface Generator - code 12

Static RTL files

You need to include the following files in your VHDL project so that they are compiled into the same library as the uart_regs module:

  • rtl/uart_regs_backend.vhd
  • rtl/uart_rx.vhd
  • rtl/uart_tx.vhd

The uart_regs_backend module implements the finite-state machines that clock in and out the register data. It uses the uart_rx and uart_tx modules to handle the UART communication with the host.

Demo projects

There are three demo projects included in the Zip file. They let you control the peripherals on the different boards as well as a few larger, internal registers.
The demo folders include pre-generated uart_regs.vhd and uart_regs.py files made specifically for those designs.

Lattice iCEstick
The demo/icecube2_icestick folder contains a register access demo implementation for the Lattice iCEstick FPGA board.
To run through the implementation process, open the demo/lattice_icestick/icecube2_proj/uart_regs_sbt.project file in the Lattice iCEcube2 design software.
After loading the project in the iCEcube2 GUI, click Tools →Run All to generate the programming bitmap file.
You can use the Lattice Diamond Programmer Standalone tool to configure the FPGA with the generated bitmap file. When Diamond Programmer opens, click Open an existing programmer project in the welcome dialog box.
Select project file found in the Zip: demo/lattice_icestick/diamond_programmer_project.xcf and click OK.VHDLwhiz
VHDL Registers UART Test Interface Generator - code 13

After the project loads, click the three dots in the File Name column, as shown above. Browse to select the bitmap file that you generated in iCEcube2: demo/lattice_icestick/icecube2_proj/uart_regs_Implmnt/sbt/outputs/bitmap/top_ice stick_bitmap.bin
Finally, with the iCEstick board plugged into a USB port on your computer, select Design→Program to program the SPI flash and configure the FPGA.
You can now proceed to read and write registers by using the demo/lattice_icestick/uart_regs.py script as described in the uart_regs.py section.

Xilinx Digilent Arty A7-35T

You can find the demo implementation for the Artix-7 35T Arty FPGA evaluation kit in the demo/arty_a7_35 folder.
Open Vivado and navigate to the extracted files using the Tcl console found at the bottom of the GUI interface. Type this command to enter the demo project folder: cd /demo/arty_a7_35/vivado_proj/
Execute the create_vivado_proj.tcl Tcl script to regenerate the Vivado project: source ./create_vivado_proj.tcl
Click Generate Bitstream in the sidebar to run through all the implementation steps and generate the programming bitstream file.
Finally, click Open Hardware Manager and program the FPGA through the GUI.
You can now proceed to read and write registers by using the demo/arty_a7_35/uart_regs.py script as described in the uart_regs.py section.

Xilinx Digilent Arty S7-50
You can find the demo implementation for the Arty S7: Spartan-7 FPGA development board in the demo/arty_s7_50 folder.
Open Vivado and navigate to the extracted files using the Tcl console found at the bottom of the GUI interface. Type this command to enter the demo project folder: cd /demo/arty_s7_50/vivado_proj/
Execute the create_vivado_proj.tcl Tcl script to regenerate the Vivado project: source ./create_vivado_proj.tcl
Click Generate Bitstream in the sidebar to run through all the implementation steps and generate the programming bitstream file.
Finally, click Open Hardware Manager and program the FPGA through the GUI.
You can now proceed to read and write registers by using the demo/arty_s7_50/uart_regs.py script as described in the uart_regs.py section.

Implementation

There are no specific implementation requirements.
Constraints
No specific timing constraints are needed for this design because the UART interface is slow and treated as an asynchronous interface.
The uart_rx input to the uart_regs module is synchronized within the uart_rx module. Thus, it doesn’t need to be synchronized in the top-level module.
Known issues

  • You may need to reset the module before it can be used, depending on whether your FPGA architecture supports default register values.

CopyrightVHDLwhiz.com

References

Read User Manual Online (PDF format)

Read User Manual Online (PDF format)  >>

Download This Manual (PDF format)

Download this manual  >>

Related Manuals