1 // © 2017 - 2022 Raptor Engineering, LLC
3 // Released under the terms of the GPL v3
4 // See the LICENSE file for full details
7 // Single data rate, quad transfer
8 // This module assumes it is on the same clock domain as the external control logic
9 module spi_master_phy_quad(
10 input wire platform_clock,
13 input wire [31:0] tx_data,
14 output reg [31:0] rx_data,
15 input wire [7:0] dummy_cycle_count,
16 input wire hold_ss_active,
17 input wire qspi_mode_active,
18 input wire qspi_transfer_mode, // 0 == byte transfer, 1 == word transfer
19 input wire qspi_transfer_direction, // 0 == read (input), 1 == write (output)
20 input wire cycle_start,
21 output reg transaction_complete,
24 output reg spi_d0_out,
26 output reg spi_d1_out,
28 output reg spi_d2_out,
30 output reg spi_d3_out,
33 output reg spi_data_direction, // 0 == tristate (input), 1 == driven (output)
34 output reg spi_quad_mode_pin_enable
39 reg [3:0] transfer_state = 0;
40 reg [31:0] data_shift_out = 0;
42 reg [7:0] state_iteration = 0;
43 reg ss_state_at_idle = 1'b1;
45 reg [7:0] dummy_cycle_count_reg = 0;
46 reg [7:0] dummy_cycle_ctr = 0;
48 reg qspi_transfer_mode_reg = 0;
49 reg [7:0] sspi_transfer_cycle_stop_value = 0;
50 reg [3:0] qspi_transfer_cycle_stop_value = 0;
52 assign ready = phy_ready;
54 always @(posedge platform_clock) begin
59 transaction_complete <= 1;
60 dummy_cycle_count_reg <= 0;
67 ss_state_at_idle <= 1'b1;
68 spi_data_direction <= 1'b0;
69 spi_quad_mode_pin_enable <= 1'b0;
76 spi_ss_n <= ss_state_at_idle;
77 transaction_complete <= 0;
79 if (cycle_start) begin
82 dummy_cycle_count_reg <= dummy_cycle_count;
83 data_shift_out <= tx_data;
84 spi_quad_mode_pin_enable <= qspi_mode_active;
85 spi_data_direction <= qspi_transfer_direction;
86 qspi_transfer_mode_reg <= qspi_transfer_mode;
87 if (qspi_transfer_mode == 0) begin
88 // Byte transfer (2 nibbles per word)
89 qspi_transfer_cycle_stop_value <= 1;
90 sspi_transfer_cycle_stop_value <= 7;
92 // Word transfer (4 bytes / 8 nibbles per word)
93 qspi_transfer_cycle_stop_value <= 7;
94 sspi_transfer_cycle_stop_value <= 31;
104 if (!hold_ss_active) begin
105 ss_state_at_idle <= 1'b1;
107 spi_quad_mode_pin_enable <= 0;
113 // Shift out TX byte / toggle clock
116 if (spi_quad_mode_pin_enable) begin
117 if (qspi_transfer_mode_reg) begin
118 spi_d3_out <= data_shift_out[31];
119 spi_d2_out <= data_shift_out[30];
120 spi_d1_out <= data_shift_out[29];
121 spi_d0_out <= data_shift_out[28];
123 spi_d3_out <= data_shift_out[7];
124 spi_d2_out <= data_shift_out[6];
125 spi_d1_out <= data_shift_out[5];
126 spi_d0_out <= data_shift_out[4];
128 data_shift_out <= data_shift_out << 4;
130 if (qspi_transfer_mode_reg) begin
131 spi_d0_out <= data_shift_out[31];
133 spi_d0_out <= data_shift_out[7];
135 data_shift_out <= data_shift_out << 1;
140 // Shift in RX byte / toggle clock
143 state_iteration <= state_iteration + 1;
144 if (spi_quad_mode_pin_enable) begin
145 if (qspi_transfer_mode_reg) begin
146 rx_data <= {rx_data[27:0], spi_d3_in, spi_d2_in, spi_d1_in, spi_d0_in};
148 rx_data <= {rx_data[3:0], spi_d3_in, spi_d2_in, spi_d1_in, spi_d0_in};
150 if (state_iteration >= qspi_transfer_cycle_stop_value) begin
151 if (hold_ss_active) begin
152 ss_state_at_idle <= 1'b0;
154 ss_state_at_idle <= 1'b1;
156 if (dummy_cycle_count_reg == 0) begin
157 transaction_complete <= 1;
160 dummy_cycle_ctr <= 0;
167 if (qspi_transfer_mode_reg) begin
168 rx_data <= {rx_data[30:0], spi_d1_in};
170 rx_data <= {rx_data[6:0], spi_d1_in};
172 if (state_iteration >= sspi_transfer_cycle_stop_value) begin
173 if (hold_ss_active) begin
174 ss_state_at_idle <= 1'b0;
176 ss_state_at_idle <= 1'b1;
178 transaction_complete <= 1;
179 if (dummy_cycle_count_reg == 0) begin
182 dummy_cycle_ctr <= 0;
191 // Wait for host to deassert transaction request
192 if (!cycle_start) begin
193 transaction_complete <= 0;
201 spi_ss_n <= ss_state_at_idle;
202 spi_data_direction <= 0;
203 spi_quad_mode_pin_enable <= 0;
206 // Increment counter / toggle clock
208 dummy_cycle_ctr <= dummy_cycle_ctr + 1;
213 if (dummy_cycle_ctr < dummy_cycle_count_reg) begin
216 transaction_complete <= 1;