blob: 69f255f87712f7d4d89585d01b820cbb0d749cbb [file] [log] [blame]
module spi_slave_controller
#(
parameter DUMMY_CYCLES = 32
)
(
sclk,
sys_rstn,
cs,
en_quad,
pad_mode,
rx_counter,
rx_counter_upd,
rx_data,
rx_data_valid,
tx_counter,
tx_counter_upd,
tx_data,
tx_data_valid,
tx_done,
ctrl_rd_wr,
ctrl_addr,
ctrl_addr_valid,
ctrl_data_rx,
ctrl_data_rx_valid,
ctrl_data_rx_ready,
ctrl_data_tx,
ctrl_data_tx_valid,
ctrl_data_tx_ready,
wrap_length
);
//parameter DUMMY_CYCLES = 32;
input wire sclk;
input wire sys_rstn;
input wire cs;
output wire en_quad;
output reg [1:0] pad_mode;
output reg [7:0] rx_counter;
output reg rx_counter_upd;
input wire [31:0] rx_data;
input wire rx_data_valid;
output reg [7:0] tx_counter;
output reg tx_counter_upd;
output reg [31:0] tx_data;
output reg tx_data_valid;
input wire tx_done;
output wire ctrl_rd_wr;
output wire [31:0] ctrl_addr;
output reg ctrl_addr_valid;
output wire [31:0] ctrl_data_rx;
output reg ctrl_data_rx_valid;
input wire ctrl_data_rx_ready;
input wire [31:0] ctrl_data_tx;
input wire ctrl_data_tx_valid;
output reg ctrl_data_tx_ready;
output wire [15:0] wrap_length;
localparam REG_SIZE = 8;
reg [2:0] state;
reg [2:0] state_next;
wire [7:0] command;
reg decode_cmd_comb;
reg [31:0] addr_reg;
reg [7:0] cmd_reg;
reg [7:0] mode_reg;
reg [31:0] data_reg;
reg sample_ADDR;
reg sample_MODE;
reg sample_CMD;
reg sample_DATA;
wire get_addr;
wire wait_dummy;
wire get_mode;
wire get_data;
wire send_data;
wire enable_cont;
wire enable_regs;
wire cmd_error;
wire [1:0] reg_sel;
wire [7:0] reg_data;
reg reg_valid;
reg ctrl_data_tx_ready_next;
reg [7:0] tx_counter_next;
reg tx_counter_upd_next;
reg tx_data_valid_next;
reg tx_done_reg;
reg [1:0] pad_mode_next;
wire [7:0] s_dummy_cycles;
assign command = (decode_cmd_comb ? rx_data[7:0] : cmd_reg);
spi_slave_cmd_parser u_cmd_parser(
.cmd(command),
.get_addr(get_addr),
.get_mode(get_mode),
.get_data(get_data),
.send_data(send_data),
.wait_dummy(wait_dummy),
.enable_cont(enable_cont),
.enable_regs(enable_regs),
.error(cmd_error),
.reg_sel(reg_sel)
);
spi_slave_regs #(.REG_SIZE(REG_SIZE)) u_spiregs(
.sclk(sclk),
.rstn(sys_rstn),
.wr_data(rx_data[7:0]),
.wr_addr(reg_sel),
.wr_data_valid(reg_valid),
.rd_data(reg_data),
.rd_addr(reg_sel),
.dummy_cycles(s_dummy_cycles),
.en_qpi(en_quad),
.wrap_length(wrap_length)
);
always @(*) begin
pad_mode = (en_quad ? 2'b11 : 2'b01);
rx_counter = 8'h1f;
rx_counter_upd = 0;
tx_counter_next = 8'h1f;
tx_counter_upd_next = 0;
decode_cmd_comb = 1'b0;
sample_ADDR = 1'b0;
sample_MODE = 1'b0;
sample_CMD = 1'b0;
sample_DATA = 1'b0;
ctrl_data_rx_valid = 1'b0;
ctrl_data_tx_ready_next = 1'b0;
reg_valid = 1'b0;
tx_data_valid_next = 1'b0;
state_next = state;
case (state)
3'd0: begin
pad_mode = (en_quad ? 2'b11 : 2'b01);
decode_cmd_comb = 1'b1;
ctrl_data_tx_ready_next = 1'b1;
if (rx_data_valid) begin
sample_CMD = 1'b1;
if (get_addr) begin
state_next = 3'd1;
rx_counter_upd = 1;
rx_counter = (en_quad ? 8'h07 : 8'h1f);
end
else if (get_data) begin
state_next = 3'd4;
rx_counter_upd = 1;
if (enable_regs)
rx_counter = (en_quad ? 8'h01 : 8'h07);
end
else begin
state_next = 3'd3;
tx_counter_upd_next = 1;
tx_data_valid_next = 1'b1;
tx_counter_next = (en_quad ? 8'h07 : 8'h1f);
if (~enable_regs)
ctrl_data_tx_ready_next = 1'b1;
end
end
else
state_next = 3'd0;
end
3'd1: begin
pad_mode = (en_quad ? 2'b11 : 2'b01);
ctrl_data_tx_ready_next = 1'b1;
if (rx_data_valid) begin
sample_ADDR = 1'b1;
if (wait_dummy) begin
state_next = 3'd5;
rx_counter = s_dummy_cycles;
rx_counter_upd = 1;
end
else if (send_data) begin
state_next = 3'd3;
tx_counter_upd_next = 1;
tx_counter_next = (en_quad ? 8'h07 : 8'h1f);
end
else if (get_data) begin
state_next = 3'd4;
rx_counter_upd = 1;
rx_counter = (en_quad ? 8'h07 : 8'h1f);
end
end
else
state_next = 3'd1;
end
3'd2: begin
pad_mode = (en_quad ? 2'b11 : 2'b01);
if (rx_data_valid) begin
if (wait_dummy) begin
state_next = 3'd5;
rx_counter = DUMMY_CYCLES;
rx_counter_upd = 1;
end
else if (get_data) begin
state_next = 3'd4;
rx_counter = (en_quad ? 8'h07 : 8'h1f);
rx_counter_upd = 1;
end
else if (send_data) begin
state_next = 3'd3;
tx_counter_next = (en_quad ? 8'h07 : 8'h1f);
tx_counter_upd_next = 1;
tx_data_valid_next = 1'b1;
if (~enable_regs)
ctrl_data_tx_ready_next = 1'b1;
end
end
else
state_next = 3'd2;
end
3'd5: begin
pad_mode = (en_quad ? 2'b11 : 2'b01);
if (rx_data_valid) begin
if (get_data) begin
state_next = 3'd4;
rx_counter = (en_quad ? 8'h07 : 8'h1f);
rx_counter_upd = 1;
end
else begin
if (en_quad)
pad_mode_next = 2'b10;
state_next = 3'd3;
tx_counter_next = (en_quad ? 8'h07 : 8'h1f);
tx_counter_upd_next = 1;
tx_data_valid_next = 1'b1;
if (~enable_regs)
ctrl_data_tx_ready_next = 1'b1;
end
end
else
state_next = 3'd5;
end
3'd4: begin
pad_mode = (en_quad ? 2'b11 : 2'b01);
if (rx_data_valid) begin
if (enable_regs)
reg_valid = 1'b1;
else
ctrl_data_rx_valid = 1'b1;
if (enable_cont) begin
state_next = 3'd4;
rx_counter = (en_quad ? 8'h07 : 8'h1f);
rx_counter_upd = 1;
end
else begin
state_next = 3'd0;
rx_counter = (en_quad ? 8'h01 : 8'h07);
rx_counter_upd = 1;
end
end
else
state_next = 3'd4;
end
3'd3: begin
pad_mode = (en_quad ? 2'b10 : 2'b00);
if (tx_done_reg) begin
if (enable_cont) begin
state_next = 3'd3;
tx_counter_next = (en_quad ? 8'h07 : 8'h1f);
tx_counter_upd_next = 1;
tx_data_valid_next = 1'b1;
if (~enable_regs)
ctrl_data_tx_ready_next = 1'b1;
end
else begin
state_next = 3'd0;
rx_counter = (en_quad ? 8'h01 : 8'h07);
rx_counter_upd = 1;
end
end
else
state_next = 3'd3;
end
3'd6: state_next = 3'd6;
endcase
end
always @(posedge sclk or posedge cs)
if (cs == 1'b1)
state <= 3'd0;
else
state <= state_next;
always @(posedge sclk or posedge cs)
if (cs == 1'b1) begin
addr_reg <= 'h0;
mode_reg <= 'h0;
data_reg <= 'h0;
cmd_reg <= 'h0;
tx_done_reg <= 1'b0;
ctrl_addr_valid <= 1'b0;
tx_counter_upd <= 1'b0;
tx_data_valid <= 1'b0;
ctrl_data_tx_ready <= 1'b0;
tx_counter <= 'h0;
tx_data <= 'h0;
end
else begin
if (sample_ADDR)
addr_reg <= rx_data;
if (sample_MODE)
mode_reg <= rx_data[7:0];
if (sample_CMD)
cmd_reg <= rx_data[7:0];
if (sample_DATA)
data_reg <= rx_data;
ctrl_addr_valid <= sample_ADDR;
tx_counter_upd <= tx_counter_upd_next;
tx_counter <= tx_counter_next;
tx_data_valid <= tx_data_valid_next;
tx_done_reg <= tx_done;
ctrl_data_tx_ready <= ctrl_data_tx_ready_next;
tx_data <= (enable_regs ? reg_data : ctrl_data_tx);
end
assign ctrl_data_rx = rx_data;
assign ctrl_addr = addr_reg;
assign ctrl_rd_wr = send_data;
endmodule