This project implements an SPI (Serial Peripheral Interface) slave with a single-port RAM, using a finite state machine (FSM). The design explores three different FSM encoding styles (Gray, One-Hot, and Sequential) to achieve the highest operating frequency based on timing performance.
-
SPI Slave Functionality:
- Inputs:
rst_n
,SS_n
,MOSI
,clk
- Output:
MISO
- Functionalities include reading from and writing to RAM via SPI.
- Inputs:
-
FSM Encoding Evaluation:
- Gray, One-Hot, and Sequential encoding styles were implemented.
- The encoding with the best timing performance was chosen based on setup/hold slack in the timing report.
-
Debug Core Integration:
- Internals like
MISO
,MOSI
,SS_n
,rst_n
, andclk
are accessible for debugging. - Waveform data captured via QuestaSim for analysis.
- Internals like
The SPI slave module is responsible for receiving data from the master device and interacting with the RAM module. It has the following ports:
Name | Type | Size | Description |
---|---|---|---|
clk | Input | 1 bit | Clock signal |
rst_n | Input | 1 bit | Active low reset signal |
SS_n | Input | 1 bit | Slave Select signal |
MOSI | Input | 1 bit | Master-Out-Slave-In data signal |
tx_data | Input | 10 bit | Transfer data output signal, Takes MOSI for 10 clock cycles and stores it in tx_data to send it to the RAM |
tx_valid | Input | 1 bit | Indicates when tx_data is valid |
MISO | Output | 1 bit | Master-In-Slave-Out data signal |
rx_data | Output | 10 bit | Received data from the memory |
rx_valid | Output | 1 bit | Indicates when rx_data is valid |
The single port asynchronous RAM module implements a memory block with a single data port.
- It has the following parameters:
- MEM_DEPTH (default: 256): Depth of the memory.
- ADDR_SIZE (default: 8): Size of the memory address.
Name | Type | Size | Description |
---|---|---|---|
clk | Input | 1 bit | Clock signal |
rst_n | Input | 1 bit | Active low reset signal |
din | Input | 10 bit | Data input |
rx_valid | Input | 1 bit | If HIGH, accepts din[7:0] to save the write/read address internally or writes a memory word depending on the most significant 2 bits din[9:8] |
dout | Output | 8 bit | Data output |
tx_valid | Output | 1 bit | Whenever the command is a memory read, tx_valid should be HIGH |
- The most significant bits of din (din[9:8]) determine the operation to be performed:
Port | din[9:8] | Command | Description |
---|---|---|---|
din | 00 | Write | Holds din[7:0] internally as a write address |
din | 01 | Write | Writes din[7:0] to the memory with the write address held previously |
din | 10 | Read | Holds din[7:0] internally as a read address |
din | 11 | Read | Reads the memory with the read address held previously. tx_valid should be HIGH, and dout holds the word read from the memory. din[7:0] is ignored |
- FSM Implementation:
- Designed using a synchronous active-low reset.
- Evaluated three encoding styles for optimal performance.
-
Testbench:
- Verified state transitions through SPI interactions with RAM by doing an SPI Wrapper, which you can find in the repository here by the file name "Wrapper_tb.v".
-
Timing and Synthesis Analysis:
- Generated reports highlighting critical paths and performance metrics using Vivado.