Overview
This article provides a high-level description of the networked soft controller for the Private Island ® open source project. This simple controller and supporting modules are implemented in behavioral Verilog.
This description is current as of Git commit 8363d90c, which is currently being used on a pre-release verion of the Betsy™ FPGA maker board.
This article uses the following conventions:
- module names are written with italics
- FSM state names are CAPITALIZED.
- variable and wire names are are lower case and bold.
A block diagram of the controller with its supporting modules are shown in the figure below. The controller interfaces with a half_fifo module to receive data from the LAN and queue data for transmit. The module is named half FIFO since the switch side interface implements a FIFO, but the controller side interface implements memory mapped circular buffers. The switch module is responsible for routing receive data from one port (PHY) to another port depending on the soft priority logic implemented within the switch module.
The controller receives and responds to messages via the LAN. A future revision will support independently queuing messages for transmit to update external nodes based on internal events within the networked system, such as pattern matching and metrics for machine learning applications.
Message Protocol
The message protocol is defined in "cont_param.v". It is currently an eight-byte fixed length message with a 32-bit data field. However, future revisions will support variable length data.
- Message Type
- Message Token for associating a query and its response.
- Address field (16-bits)
- Data field (32-bits)
On reads, the data field can be used to mask or tag specific data bits of a register.
The message types are defined below.
- MSG_TYPE_NULL = 0
- MSG_TYPE_WRITE = 1
- MSG_TYPE_READ = 2
- MSG_TYPE_REPLY_SUCCESS = 3
- MSG_TYPE_REPLY_ERROR = 4
- MSG_TYPE_NOTIFY = 5
Controller Finite State Machines (FSM)
The controller implements two state machines and related logic, which are described below.
Top-Level State Machine
This section describes each state of cont_state. Note that this state machine will be expanded as the controller implements additional functionality, such as independently queueing variable length messages for transmit.
cont_state == CONT_ST_INIT: reset state
cont_state == CONT_ST_IDLE: waiting for an event, such as receiving a message via the LAN
cont_state == CONT_ST_BUSY: the controller sub blocks are busy performing an action, such as an MDIO read or write to an Ethernet PHY.
cont_state == CONT_ST_DONE: event has completed
Memory State Machine
This section describes each state of mem_state.
mem_state < MEM_ST_IDLE: These states are used to initialize various registers internal to the system after reset. This is useful during experimentation and prototyping.
mem_state == MEM_ST_IDLE:
- Waiting for an event, such as an interrupt.
- Use this state to reset internal variables.
mem_state == MEM_ST_RX_START:
- first state in responding to an event, such as an interrupt from the LAN. Get ready to read the network data.
- Assert hf_ptrs_sel and set mem_addr to read the latched receive write pointer (HF_RX_WR_PTR_LTCH_ADDR) from the half_fifo.
- Advance rx_rd_ptr past Ethernet, IPV4, and UDP headers
mem_state == MEM_ST_RX_GET_WR_PTR
- negate hf_ptrs_sel and assert hf_rx_sel for reading directly from the half_fifo RX DPRAM.
- set mem_addr = internal rx_rd_ptr address
- update internal rx_wr_ptr from half_fifo
mem_state == MEM_ST_RD_FIFO_START
- assert rx_rd_active while the internal receive read ptr != write ptr.
- keep hf_rx_sel asserted to read directly from receive DPRAM
mem_state == MEM_ST_RD_FIFO
- This state does not advance until rx_rd_active is negated
- keep hf_rx_sel asserted to read directly from receive DPRAM
- During this state, the message fields are captured into registers depending on rx_cnt
- assert rx_msg_captured once rx_rd_active is negated
mem_state == MEM_ST_RD_FIFO_DONE
- This state does not advance until top level state machine is done.
- When top level controller begins, negate all half_fifo selects and perform the message function, such as a write.
- Assign the msg_response once top level controller is done. A write will have already taken place, so the response includes any side effects to the register.
mem_state == MEM_ST_VALIDATE
- advance to next reply state if received message is valid.
mem_state == MEM_ST_REPLY_START
- flow control: wait for any active transmits to finish
- Assert hf_ptrs_sel and set mem_addr to the half_fifo transmit count register.
- Reset the tx_cnt register.
- Assert tx_wr_active.
mem_state == MEM_ST_REPLY
- negate hf_ptrs_sel and assert hf_tx_sel for writing directly to the half_fifo TX DPRAM.
- Write the each message response field depending on the value of tx_cnt
- don't advance until tx_wr_active is negated.
mem_state == MEM_ST_DONE
- negate active flags, reset TX variables for next cycle, and perform any final write pointer increments
Half FIFO
A block diagram of the half_fifo module is shown below. The receive and transmit queues are implemented as two inferred DPRAMs, one for each direction. The network side (DPRAM B side) interface emulates a receive and transmit FIFO clocked at the network fabric rate. The controller side basically maps the DPRAM interface to the controller module. Both sides require various pointers and flags to implement the interfaces and compensate for cross domain clocking since it is assumed that the network clock and controller clock are asynchronous.
Use Signal Tap to Inspect a Message Read Cycle
The screenshot below is from Signal Tap using the Quartus Prime Standard edition and shows various controller variables involved in reading back the controller version (0x1 at address 0x0000).
Known Issues, Notes, and Future Revisions
- The implementation assumes that the controller clock and network clock are asynchronous, which isn't necessarily true. A directive will be added to remove the synchronizer chains when not required.
- Better error handling is needed and planned.
- Flow control is being reviewed and reworked. tx_fifo_empty requires a CDC synchronizer.
- Define additional controller events that will trigger transmitting internal variable sized data, such as pre-processed data for machine learning applications.




