Entity: spi_passthrough
- File: spi_passthrough.sv
Diagram
Description
Copyright lowRISC contributors. Licensed under the Apache License, Version 2.0, see LICENSE for details. SPDX-License-Identifier: Apache-2.0
Serial Peripheral Interface (SPI) Device Passthrough module.
Generics
Generic name | Type | Value | Description |
---|---|---|---|
NumCmdInfo | int unsigned | 16 |
Ports
Port name | Direction | Type | Description |
---|---|---|---|
clk_i | input | SPI input clk | |
rst_ni | input | SPI reset | |
clk_out_i | input | SPI output clk | |
cfg_cmd_filter_i | input | [255:0] | Configurations command filter information is given as 256bit register. It is subject to be changed if command config is stored in DPSRAM. If that is supported, the command config is valid at the 6th command cycle and given only 8 bits. |
cfg_addr_mask_i | input | [31:0] | address manipulation |
cfg_addr_value_i | input | [31:0] | |
cfg_addr_4b_en_i | input | Address mode | |
spi_mode_i | input | spi_mode_e | |
cmd_info_i | input | [NumCmdInfo-1:0] | Command Info structure |
host_sck_i | input | SPI in Though it would be best if passthrough is able to re-use existing spi_s2p and cmdparse, but passthrough has to implement its own s2p and cmdparse to support the A/B binary scheme. | |
host_csb_i | input | ||
host_s_i | input | [3:0] | |
host_s_o | output | [3:0] | clk_out_i domain |
host_s_en_o | output | [3:0] | clk_out_i domain |
passthrough_o | output | passthrough_req_t | SPI to SPI_HOST and terminal to the downstream device |
passthrough_i | input | passthrough_rsp_t | |
mailbox_hit_i | input | Mailbox indicator If a read command falls into the mailbox address and the mailbox feature is enabled, the Read Command process module sends a signal to passthrough to take the control of the SPI line. If this signal asserts during Address phase, passthrough drops CSb to SPI Flash device and waits host's CSb de-assertion. |
|
event_cmd_filtered_o | output | event cmd_filtered : indicator of the incoming command filtered out |
Signals
Name | Type | Description |
---|---|---|
st | passthrough_st_e | |
st_d | passthrough_st_e | |
host_s_en_inclk | logic [3:0] | localparam cmd_type_t CmdInfoNone = '{ addr_en: 1'b 0, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 0, dummy_en: 1'b 0, payload_en: 4'h 0, payload_dir: PayloadIn, addr_size: '0, dummy_size: '0 }; localparam cmd_type_t CmdInfoPayloadIn = '{ addr_en: 1'b 0, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 0, dummy_en: 1'b 0, payload_en: 4'h 1, payload_dir: PayloadIn, addr_size: '0, dummy_size: '0 }; localparam cmd_type_t CmdInfoPayloadOut = '{ addr_en: 1'b 0, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 0, dummy_en: 1'b 0, payload_en: 4'h 2, // S[1] payload_dir: PayloadOut, addr_size: '0, dummy_size: '0 }; localparam cmd_type_t CmdInfoAddrPayloadIn = '{ addr_en: 1'b 1, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 1, dummy_en: 1'b 0, payload_en: 4'h 1, // S[0] only payload_dir: PayloadIn, // Host sends Data addr_size: '0, // Logic decide dummy_size: '0 }; localparam cmd_type_t CmdInfoAddrPayloadInQuad = '{ addr_en: 1'b 1, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 1, dummy_en: 1'b 0, payload_en: 4'h F, // S[3:0] payload_dir: PayloadIn, // Host sends Data addr_size: '0, // Logic decide dummy_size: '0 }; localparam cmd_type_t CmdInfoAddrPayloadOut = '{ addr_en: 1'b 1, addr_swap_en: 1'b 1, addr_4b_affected: 1'b 1, dummy_en: 1'b 0, payload_en: 4'h 2, // S[1] only payload_dir: PayloadOut, // Flash device sends Data addr_size: '0, // Logic decide dummy_size: '0 }; // Address + Dummy + Payload but Address is 3B always localparam cmd_type_t CmdInfoAddr3BDummyPayloadOut = '{ addr_en: 1'b 1, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 0, dummy_en: 1'b 1, payload_en: 4'h 2, // S[1] only payload_dir: PayloadOut, // Flash device sends Data addr_size: '0, // Logic decide dummy_size: 'h 7 }; localparam cmd_type_t CmdInfoAddrDummyPayloadOut = '{ addr_en: 1'b 1, addr_swap_en: 1'b 1, addr_4b_affected: 1'b 1, dummy_en: 1'b 1, payload_en: 4'h 2, // S[1] only payload_dir: PayloadOut, // Flash device sends Data addr_size: '0, // Logic decide dummy_size: 'h 7 }; localparam cmd_type_t CmdInfoAddrDummyPayloadOutDual = '{ addr_en: 1'b 1, addr_swap_en: 1'b 1, addr_4b_affected: 1'b 1, dummy_en: 1'b 1, payload_en: 4'h 3, // S[1:0] only payload_dir: PayloadOut, // Flash device sends Data addr_size: '0, // Logic decide dummy_size: 'h 7 }; localparam cmd_type_t CmdInfoAddrDummyPayloadOutQuad = '{ addr_en: 1'b 1, addr_swap_en: 1'b 1, addr_4b_affected: 1'b 1, dummy_en: 1'b 1, payload_en: 4'h F, // S[3:0] payload_dir: PayloadOut, // Flash device sends Data addr_size: '0, // Logic decide dummy_size: 'h 7 }; localparam cmd_type_t CmdInfoAddr = '{ addr_en: 1'b 1, addr_swap_en: 1'b 0, addr_4b_affected: 1'b 0, // TODO: ?? dummy_en: 1'b 0, payload_en: 4'h 0, payload_dir: PayloadOut, // Flash device sends Data addr_size: '0, // Logic decide dummy_size: 'h 0 }; */ Not synthesizable in DC localparam cmd_type_t PassThroughCmdInfoOld [256] = '{ // 8'h 00 'h 00: CmdInfoNone, // 8'h 01 Write Status 1 'h 01: CmdInfoPayloadIn, // 8'h 15 Write Statur 2 'h 31: CmdInfoPayloadIn, // 8'h 11 Write Status 3 'h 11: CmdInfoPayloadIn, // 8'h 02 Page Program 'h 02: CmdInfoAddrPayloadIn, // 8'h 32 Quad Input Page Program : Expect to be filtered 'h 32: CmdInfoAddrPayloadInQuad, // 8'h 03 Read Data 'h 03: CmdInfoAddrPayloadOut, // 8'h 04 Write Disable 'h 04: CmdInfoNone, // 8'h 05 Read Status 1 'h 05: CmdInfoPayloadOut, // 8'h 35 Read Status 2 'h 35: CmdInfoPayloadOut, // 8'h 15 Read Status 3 'h 15: CmdInfoPayloadOut, // 8'h 06 Write Enable 'h 06: CmdInfoNone, // 8'h 0B Fast Read 'h 0B: CmdInfoAddrDummyPayloadOut, // 8'h 3B Fast Read Dual Output 'h 3B: CmdInfoAddrDummyPayloadOutDual, // 8'h 6B Fast Read Quad Output 'h 6B: CmdInfoAddrDummyPayloadOutQuad, // 8'h 20 Sector Erase (4kB) 'h 20: CmdInfoAddr, // 8'h 52 Block Erase (32kB) 'h 52: CmdInfoAddr, // 8'h D8 Block Erase (64kB) 'h D8: CmdInfoAddr, // 8'h 36 Individual Block Lock 'h 36: CmdInfoAddr, // 8'h 39 Individual Block Unlock 'h 39: CmdInfoAddr, // 8'h 3D Read Block Lock 'h 3D: CmdInfoAddrPayloadOut, // 8'h 38 Enter QPI : Expect to be filtered 'h 38: CmdInfoNone, // 8'h 42 Program Security Register // 8'h 44 Erase Security Register // 8'h 48 Read Security Register // 8'h 4B Read Unique ID // 8'h 5A Read SFDP 'h 5A: CmdInfoAddr3BDummyPayloadOut, // 8'h 90 Manufacture/Device ID // 8'h 9F JEDEC ID 'h 9F: CmdInfoPayloadOut, default: CmdInfoNone }; */ /////////// Signals // /////////// internal clock |
device_s_en_inclk | logic [3:0] | |
is_active | logic | Indicate Passthrough mode is enabled or not. |
opcode | logic [7:0] | |
opcode_d | logic [7:0] | |
unused_opcode_7 | logic | |
filter | logic | If the filter becomes 1 on the 8th beat, it lowers SCK enable signal to CG cell then, at the 8th posedge of SCK, csb_deassert becomes 1. _ SCK / 7 ___/ 8 ____/ _ filter /XXXXXX/ ___________ __ sck_gate_en __________________ __ csb_deassert ______/ |
sck_gate_en | logic | If 1, SCK propagates to the downstream SPI Flash device. |
csb_deassert | logic | CSb to the downstream device control If 1, CSb is de-asserted. This signal is glitch sensitive. This value is changed at SCK posedge. This does not drive CSb output directly. CSb to downstream is OR-ed with this and CSb from host system.cdb_deassert should be latched at the posedge of SCK. filter signal is computed in between the 7th posedge of SCK and the 8th posedge. As the command bit does not arrive until the 7th negedge of SCK, the filter signal is not valid in the first half of the period. By latching the filter signal at the posedge of the SCK, csb_deassert always shows correct value if the command needs to be filtered or not.However, the CSb output to the downstream flash device is better to be in the out clock domain. It helps the design constraints to be simpler. So, the csb_deassert is again latched at the outclk (which is the negedge of SCK). |
csb_deassert_outclk | logic | |
bitcnt | logic [MetaBitCntW-1:0] | |
addrcnt | logic [AddrCntW-1:0] | Address or anything host driving after opcode counter |
addrcnt_outclk | logic [AddrCntW-1:0] | Address or anything host driving after opcode counter |
dummycnt | logic [DummyCntW-1:0] | Dummy counter |
dummycnt_d | logic [DummyCntW-1:0] | Dummy counter |
mailbox_hit | logic | Mailbox hit. |
cmd_7th | logic | 7th beat of transaction |
cmd_8th | logic | in 8th beat of transaction |
cmd_filter | logic [1:0] | |
cmd_info | cmd_info_t | |
cmd_info_d | cmd_info_t | |
cmd_info_7th | cmd_info_t [1:0] | |
cmd_info_7th_d | cmd_info_t [1:0] | |
addr_size_d | logic [AddrCntW-1:0] | |
cmd_info_latch | logic | |
unused_cmd_info_fields | logic | Some of the fields of cmd_info are used in the big FSM below. The opcode field and the addr_* fields are ignored because we pick them from cmd_info_d instead (in a different FSM state). We rely on the synthesis tool not to generate the unneeded flops but must explicitly waive lint warnings about unused fields. |
addr_set | logic | Address swap |
addr_phase | logic | |
addr_phase_outclk | logic | |
addr_swap | logic | Based on AddrCnt, the logic swap. TODO: Handle the DualIO, QuadIO cases |
dummy_set | logic | Dummy Counter |
dummycnt_zero | logic | |
mbyte_set | logic | MByte counter |
mbytecnt_zero | logic | |
mbyte_cnt | logic [1:0] | |
passthrough_s_en | logic [3:0] | |
StFilter | end | |
StWait | end | |
StDriving | end | |
host_s_en_inclk | end | |
StAddress | end | |
st_d | end | |
endcase | end |
Constants
Name | Type | Value | Description |
---|---|---|---|
MetaMaxBeat | int unsigned | 8+32+8 | Cmd + Addr + Dummy |
MetaBitCntW | int unsigned | $clog2(MetaMaxBeat) |
Types
Name | Type | Description |
---|---|---|
passthrough_st_e | enum logic [2:0] { StIdle, StFilter, StWait, // // // StDriving, StHighZ, // // StAddress, StMByte } |
/////////////// Definitions // /////////////// State |
Processes
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
Description
Command Filter: CSb control
- unnamed: ( @(posedge clk_out_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
Description
Bitcnt counter / Bitcnt increases until it hit the max value then wait reset.
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( )
Type: always_comb
Description
Search opcode @ 7th opcode
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( )
Type: always_comb
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_out_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_out_i or negedge rst_ni) )
Type: always_ff
Description
Address swap should happen in outclk domain. The state machine operates in inclk domain. The state generates mux selection signal. The signal latched in outclk domain then activates the mux.
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_out_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_out_i or negedge rst_ni) )
Type: always_ff
- unnamed: ( @(posedge clk_i or negedge rst_ni) )
Type: always_ff
Description
- END: Passthrough Mux (!important) ------------------------------------ ///////////////// State Machine // /////////////////
- unnamed: ( )
Type: always_comb