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, andclkare 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.



