module spi_shift ( | |
input clk_i, // system clock | |
input rst_ni, // reset | |
input latch, // latch signal for storing the data in shift register | |
input [3:0] byte_sel, // byte select signals for storing the data in shift register | |
input [`SPI_CHAR_LEN_BITS-1:0] len, // data len in bits (minus one) | |
input lsb, // lbs first_ni on the line | |
input go, // start stansfer | |
input pos_edge, // recognize posedge of sclk_i | |
input neg_edge, // recognize negedge of sclk_i | |
input rx_negedge, // s_in is sampled on negative edge | |
input tx_negedge, // s_out is driven on negative edge | |
output reg tip, // transfer in progress | |
output last, // last bit | |
input [31:0] p_in, // parallel in | |
output [`SPI_MAX_CHAR-1:0] p_out, // parallel out | |
input s_clk, // serial clock | |
input s_in, // serial in | |
output reg s_out, // serial out | |
input rx_en // serial rx enable | |
); | |
// reg s_out; | |
// reg tip; | |
reg [`SPI_CHAR_LEN_BITS:0] cnt; // data bit count | |
reg [`SPI_MAX_CHAR-1:0] data; | |
reg [`SPI_MAX_CHAR-1:0] data_rx; // shift register | |
wire [`SPI_CHAR_LEN_BITS:0] tx_bit_pos; // next bit position | |
wire [`SPI_CHAR_LEN_BITS:0] rx_bit_pos; // next bit position | |
wire rx_clk_i; // rx clock enable | |
wire tx_clk_i; // tx clock enable | |
assign p_out = data_rx; | |
assign tx_bit_pos = lsb ? {!(|len), len} - cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1}; | |
assign rx_bit_pos = lsb ? {!(|len), len} - (rx_negedge ? cnt + {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1} : cnt) : | |
(rx_negedge ? cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1}); | |
assign last = !(|cnt); | |
assign rx_clk_i = (rx_negedge ? neg_edge : pos_edge) && (!last || s_clk); | |
assign tx_clk_i = (tx_negedge ? neg_edge : pos_edge) && !last; | |
// Character bit counter | |
always @(posedge clk_i or negedge rst_ni) | |
begin | |
if(~rst_ni) | |
cnt <= {`SPI_CHAR_LEN_BITS+1{1'b0}}; | |
else | |
begin | |
if(tip) | |
cnt <= pos_edge ? (cnt - {{`SPI_CHAR_LEN_BITS{1'b0}}, 1'b1}) : cnt; | |
else | |
cnt <= !(|len) ? {1'b1, {`SPI_CHAR_LEN_BITS{1'b0}}} : {1'b0, len}; | |
end | |
end | |
// Transfer in progress | |
always @(posedge clk_i or negedge rst_ni) | |
begin | |
if(~rst_ni) | |
tip <= 1'b0; | |
else if(go && ~tip) | |
tip <= 1'b1; | |
else if(tip && last && pos_edge) | |
tip <= 1'b0; | |
end | |
// Sending bits to the line | |
always @(posedge clk_i or negedge rst_ni) | |
begin | |
if (~rst_ni) | |
s_out <= 1'b0; | |
else | |
s_out <= (tx_clk_i || !tip) ? data[tx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] : s_out; | |
end | |
// Receiving bits from the line | |
always @(posedge clk_i ) | |
begin | |
if (~rst_ni) | |
data <= {`SPI_MAX_CHAR{1'b0}}; | |
else if (latch && !tip) | |
begin | |
if (byte_sel[0]) | |
data[7:0] <= p_in[7:0]; | |
if (byte_sel[1]) | |
data[15:8] <= p_in[15:8]; | |
if (byte_sel[2]) | |
data[23:16] <= p_in[23:16]; | |
if (byte_sel[3]) | |
data[`SPI_MAX_CHAR-1:24] <= p_in[`SPI_MAX_CHAR-1:24]; | |
end | |
else if (rx_en && tip) begin | |
data_rx[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] <= rx_clk_i ? s_in : data_rx[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]]; | |
end | |
end | |
endmodule | |