UART
The UART module allows the PicoNut processor to communicate with the outside world. It is a simple module that can be used to send and receive data between the PicoNut and a user’s computer. The module is based on the SiFive UART (SiFive FE310-G000 Manual), which has been implemented in the PicoNut project.
There are two implementations of the UART module in the PicoNut project. The first is the Wishbone UART, a UART module connected to the Wishbone bus, primarily intended for use on an FPGA. The second implementation is the SimUART, a UART module that can be connected to the CSoftPeripheral
interface of the PicoNut processor, designed for use in the simulator.
UART Registers
A list of the registers for the UART module can be found in the documentation (SiFive FE310-G000 Manual) of the SiFive UART module.
Wishbone UART
The following figure provides an overview of the components of the Wishbone UART module.
All subsequent diagrams omit the clk
and rst
signals for clarity.
Fig. 15 Overview of the Wishbone UART module.
-
SC_MODULE(m_wb_uart)
#define
#define *
#define #define * following submodules:
baudgen_x16
: Baud rate generator for the 16x baud rate #define * -baudgen_rx
: Baud rate generator for the receive (rx) baud ratebaudgen_tx
: Baud rate generator for the transmit (tx) baud rateuart_rx
: Receiver moduleuart_tx
: Transmitter moduleuart_rx_fifo
: Receiver FIFOuart_tx_fifo
: Transmitter FIFO
- Author
Lukas Bauer
It connects the submodules and handles the Wishbone interface. It provides the registers as specified for the SiFive UART. The registers are:
txdata
: Transmit data registerrxdata
: Receive data registertxctrl
: Transmit control registerrxctrl
: Receive control registerie
: Interrupt enable registerip
: Interrupt pending registerdiv
: Baud rate divisor register
The module provides control functionality for the FIFOs, receiver, and transmitter. It initiates UART transmissions when data is written to the FIFOs, or writes the received data to the
rx_fifo
. It also controls whether the receiver or transmitter are enabled and at what baud rate they operate. Interrupts are also activated and deactivated by this module. A FIFO state machine handles Wishbone access to both FIFOs to prevent invalid transactions of data to and from the UART module.There are two configuration options in the
config.mk
file:CFG_WB_UART_DISABLE_FIFO
: This disables the FIFOs of the UART module. In this mode, only therx
andtx
data registers are usable, meaning therxdata_empty
andtxdata_full
flags are set when the registers are in use. This also changes the behavior of the interrupts, where thetxctrl_txcnt
andrxctrl_rxcnt
watermark levels have no effect. The watermark levels are set to 1, and the interrupts are triggered when thetxdata
andrxdata
registers exceed the threshold as described in the SiFive UART specification.CFG_WB_UART_BASE_ADDRESS
: This sets the base address of the UART module in the Wishbone bus address space.
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
stb_i – [in] wb strobe
cyc_i – [in] wb cycle
we_i – [in] wb write enable
sel_i – [in] wb byte select
ack_o – [out] wb acknowledge
err_o – [out] wb error
rty_o – [out] wb retry
addr_i – [in] wb address
dat_i – [in] wb data in
dat_o – [out] wb data out
rx – [in] rx line
tx – [out] tx line
The Wishbone UART module consists of the following components:
Baudgen: Multiple Baudgenerators that divide the system clock to generate the baudrate for the UART module.
Majority Filter: The majority filter is used to filter the received data. To ensure that the bit is received correctly.
FIFOs: The FIFOs are used to buffer the data that is sent and received by the UART module.
uart_rx: The receiver receives data from the outside world.
uart_tx: The transmitter sends data to the outside world.
Baudgen
Fig. 16 Diagramm of the Baudrate Generator.
-
SC_MODULE(m_baudgen)
clockdivider to generate the baudtick for the UART
This clock divider can be configured by setting a divider value in the 16-bit
div
register. If the module is enabled, the baud generator counts up until the divider value is reached. Then, thebaudtick
is set to high, and the counter is reset.- Author
Lukas Bauer
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
en_i – [in] enable for baudgen module
clear_i – [in] clearing the baudgen (synchronous reset)
div_i – [in] <16> divider value for baudgen
baudtick_o – [out] generated baudtick
Majority Filter
Fig. 17 Diagramm of the Majority Filter.
-
SC_MODULE(m_majority_filter)
majority filter to filter a input signal
This module allows checking if a signal remains stable for a certain amount of time. If the module is enabled, the input signal is checked every clock cycle. When the signal is low, the counter is incremented. Once the threshold is reached, the output signal is set to low. Otherwise, the output signal remains high.
- Author
Lukas Bauer
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
filter_i – [in] Signal to be filtered
capture_i – [in] Enable Signal to capture the filter signal
clear_i – [in] Clear the filter signal
filter_o – [out] Filtered Signal
FIFOs
Fig. 18 Diagramm of the FIFOs.
-
SC_MODULE(m_uart_fifo)
first in first out buffer for UART
This module is a simple first-in, first-out (FIFO) buffer for the UART RX and TX. If the read and write pointers are equal, the buffer is empty. If the write pointer and the addresses are as far apart as possible, the buffer is full. The
usage
signal is a counter for the number of elements in the buffer. Theclear
signal resets the read and write pointers, as well as the usage counter. Ifwrite
is set and the buffer is not full, the data is written to the buffer. Ifread
is set and the buffer is not empty, the data is read from the buffer. The width of the data can be set using theUART_FIFO_WIDTH
parameter. The size of the buffer can be set using theUART_FIFO_SIZE_2E
parameter, which is the log2 of the size of the buffer. The buffer is implemented as a circular buffer.- Author
Lukas Bauer
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
clear_i – [in] clear the content of the FIFO
write_i – [in] write enable for the FIFO
read_i – [in] read enable for the FIFO
data_i – [in] <8> data to be written to the FIFO
data_o – [out] <8> data to be read from the FIFO
full_o – [out] FIFO is full
empty_o – [out] FIFO is empty
usage_o – [out] <4> usage of the FIFO
uart_rx
Fig. 19 Diagramm of the Receiver.
-
SC_MODULE(m_uart_rx)
Implementation of the UART receiver.
The UART receiver is a state machine that waits for the start bit of a UART frame. It contains the following submodule:
Majority Filter Once the receiver detects the start bit, it starts the baudtick generation and waits for the next baudtick to sample the RX line. The received bits are stored in a shift register. They are then filtered by a majority filter to reduce noise. When the stop bit is received, the data is stored in the data register, and the
rx_finished
signal is set. The number of stop bits can be configured to 1 or 2.
- Author
Lukas Bauer
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
baudtick_i – [in] baudtick input
baudtick_x16_i – [in] baudtick x16 input
stopbit_8_9_i – [in] unset for 1 stop bit, set for 2 stop bits
rx_i – [in] UART rx line
data_o – [out] <16> Data Output
rx_finished_o – [out] RX finished output
baudtick_disable_o – [out] disable the baudtick generation if needed
uart_tx
Fig. 20 Diagramm of the Transmitter.
-
SC_MODULE(m_uart_tx)
Implementation of the UART transmitter.
This module is used to transmit data over the UART interface. The data is provided to the module as an 8-bit word, and the module will transmit the data over the
tx_o
line. Transmission is initiated by setting thetx_start_i
signal. The module will then transmit the data and set thetx_finish_o
signal when the transmission is complete. The module also handles the stop bits. If thestopbit_cnt_i
signal is set, the module will transmit 2 stop bits. If the signal is unset, the module will transmit 1 stop bit.- Author
Lukas Bauer
- Ports:
- Parameters:
clk – [in] clock of the module
reset – [in] reset of the module
baudtick_i – [in] baudtick input
tx_start_i – [in] start signal for transmission
stopbit_cnt_i – [in] unset: 1 stopbit, set: 2 stopbits
tx_data_i – [in] <8> 8-bit word to transmit
tx_finish_o – [out] transmission finished signal
tx_o – [out] tx line signal
System for hardware test
To test the Wishbone UART module on hardware, a system has been created. This system contains a test module that can configure the UART module and echo the received data back. The system is synthesizable for the ULX3S board.
It contains two SystemC modules:
uart_wb_uart: Contains the test hardware for the UART module.
top: Contains a wrapper for synthesis
uart_test
-
SC_MODULE(m_uart_test)
a hardware module to test the wb_uart
This module initializes the wb_uart module via its Wishbone interface by setting the baud rate and enabling RX and TX. It then periodically checks the rxdata register to see if the RX FIFO is no longer empty. If that is the case, it saves the received data in a register and sends it to the txdata register to be sent back. This effectively echoes the received data back to the sender to check the basic functionality of the wb_uart module in hardware.
- Author
Lukas Bauer
- Ports:
- Parameters:
clk – [in] the clock signal of the module
reset – [in] the reset signal of the module
rx – [in] the receive signal of the uart
tx – [out] the transmit signal of the uart
top
-
SC_MODULE(m_top)
wrapper for synthesis
This module is just the top level wrapper for synthesis
- Author
Lukas Bauer
- Ports:
- Parameters:
clk_25 – [in] the clock signal comming form the board
reset – [in] the reset signal of the module
rx – [in] the receive signal of the uart
tx – [out] the transmit signal of the uart
SimUART
The SimUART module implements a UART module that can be connected to the CSoftPeripheral
interface of the PicoNut processor, which is described in Chapter Software Library Documentation.
The following figure provides an overview of the components of the SimUART module.
Fig. 21 Overview of the SimUART module.
- group c_soft_uart
soft peripheral implementation of the sifive UART for simulation
This module is used to simulate the UART peripheral of the SiFive core. The module is implemented as a soft peripheral and can be used in the simulation environment. The module has the same registers as the SiFive UART. They are:
txdata
: 32-bit register for the transmit datarxdata
: 32-bit register for the receive datatxctrl
: 32-bit register for the transmit controlrxctrl
: 32-bit register for the receive controlie
: 32-bit register for the interrupt enableip
: 32-bit register for the interrupt pendingdiv
: 32-bit register for the baud rate divider
- Author
Lukas Bauer
The module has a 32-bit memory interface and can be accessed by the soft peripheral interface.
Note: At the moment, the module only implements transmit functionality, meaning it can only display data on
stdout
, but cannot receive data onstdin
.Note: The module is not synthesizable and is only used for simulation purposes.
Note: The module does not simulate the baud rate because it is not needed for the simulation, meaning the
div
register has no effect on the module.
CSoftPeripheral Interface
The following methods are those implemented from the CSoftPeripheral
interface.
To enable the UART module to be connected to the CSoftPeripheral
interface, the following methods must be implemented:
-
inline c_soft_uart::c_soft_uart(uint64_t size, uint64_t base_address)
Construct a new Soft Uart object.
- Parameters:
size – address space of the peripheral
base_address – base address of the peripheral in address space of the simulation
-
inline const char *c_soft_uart::get_info() override
-
inline uint8_t c_soft_uart::read8(uint64_t adr) override
-
inline void c_soft_uart::write8(uint64_t adr, uint8_t data) override
-
inline void c_soft_uart::write32(uint64_t adr, uint32_t data) override
-
inline uint32_t c_soft_uart::read32(uint64_t adr) override
-
inline bool c_soft_uart::is_addressed(uint64_t adr) override
UART Emulation
The following methods are implemented to emulate the functionality of the SiFive UART module. They handle data transmission, the FIFO, and interrupt generation.
-
void c_soft_uart::handel_transmit()
handels the transmit of the uart
Handles the transmission of the UART by checking if txen is enabled, and then sending the data from the tx_fifo if the UART is enabled and the tx_fifo is not empty. The data is sent to stdout.
-
void c_soft_uart::update_txfull()
updates the txfull flag in the txdata register
if the fifo is not full its set to false else to true
-
void c_soft_uart::handel_interrupt()
sets the values in the ip register according to the conditions
Checks if the interrupts are enabled and then sets the interrupt flag if the cnt register has the correct value.
-
void c_soft_uart::update_uart()
runs handel_interrupt and handel_transmit to update the uart