tachibana/demo/fpga/src/spi_regfile.v

97 lines
2.1 KiB
Verilog

`timescale 1ns / 1ps
module spi_regfile(
input clk, rst,
input sck, sdi, ncs,
output reg sdo,
input [7:0] spi_data_in,
output reg [7:0] spi_data_out,
input [7:0] spi_status_word,
output reg [7:0] spi_cmd_word,
output reg spi_cmd_begin,
output reg spi_cmd_active,
output reg spi_cmd_step,
output reg [19:0] spi_cmd_idx,
output [7:0] rxbuf_dbg
);
reg [6:0] txbuf;
reg [7:0] rxbuf;
reg is_cmd_word;
reg last_ncs;
reg last_sck;
reg load_data;
assign rxbuf_dbg = rxbuf;
wire sck_clean, sdi_clean, ncs_clean;
edge_cleaner sck_cleaner (.clk(clk), .in(sck), .out(sck_clean));
edge_cleaner sdi_cleaner (.clk(clk), .in(sdi), .out(sdi_clean));
edge_cleaner ncs_cleaner (.clk(clk), .in(ncs), .out(ncs_clean));
/* SPI mode 0: CPOL = 0, CPHA = 0. Initial SDO setup on falling ~CS edge */
always @(posedge clk) begin
spi_cmd_begin <= 0;
spi_cmd_step <= 0;
last_ncs <= ncs_clean;
last_sck <= sck_clean;
if (rst) begin
is_cmd_word <= 1;
spi_cmd_active <= 0;
spi_cmd_idx <= 0;
end else begin
if (last_ncs && !ncs_clean) begin
txbuf <= spi_status_word[6:0];
sdo <= spi_status_word[7];
rxbuf <= 8'h01;
end
if (!ncs_clean) begin
if (!last_sck && sck_clean) begin /* sampling edge */
if (!rxbuf[7]) begin
rxbuf <= {rxbuf[6:0], sdi_clean};
end else begin
rxbuf <= 8'h01;
load_data <= 1;
if (is_cmd_word) begin
spi_cmd_word <= {rxbuf[6:0], sdi_clean};
is_cmd_word <= 0;
spi_cmd_active <= 1;
spi_cmd_begin <= 1;
spi_cmd_idx <= 0;
end else begin
spi_data_out <= {rxbuf[6:0], sdi_clean};
spi_cmd_idx <= spi_cmd_idx+1;
spi_cmd_step <= 1;
end
end
end else if (last_sck && !sck_clean) begin /* driving edge */
if (load_data) begin
sdo <= spi_data_in[7];
txbuf <= spi_data_in[6:0];
load_data <= 0;
end else begin
sdo <= txbuf[6];
txbuf <= {txbuf[5:0], 1'b0};
end
end
end else begin
spi_cmd_active <= 0;
is_cmd_word <= 1;
end
end
end
endmodule