sync chunk 11/12

This commit is contained in:
chunk-sync
2026-09-11 16:18:36 +08:00
parent c315cef09e
commit c2c1bb2648
922 changed files with 102283 additions and 6793 deletions
@@ -0,0 +1,228 @@
`timescale 1 ns / 1 ps
//------------------------------------------------------------------------------
// CSI040 SPI master
//
// request/ready
// cmd_valid cmd_ready 1 SPI
// cmd_write opcode opcode
// cmd_addr opcode
// cmd_wdata payload byte0 cmd_wdata[7:0]
// cmd_len payload 1..MAX_BURST_BYTES
//
// SPI
// csn
// sck
// si 沿
// 沿 so
//------------------------------------------------------------------------------
module csi040_spi_master#
(
parameter CLK_DIV = 50, // SCK clk
parameter REG_ADDR_WIDTH = 16,
parameter ADDR_BYTES = 2,
parameter MAX_BURST_BYTES = 4,
parameter [7:0] OPCODE_WRITE = 8'h00,
parameter [7:0] OPCODE_READ = 8'h80
)
(
input clk,
input rst_n,
// csi040_ctrl
output cmd_ready,
input cmd_valid,
input cmd_write,
input [REG_ADDR_WIDTH-1:0]cmd_addr,
input [8*MAX_BURST_BYTES-1:0] cmd_wdata,
input [7:0] cmd_len,
output reg done,
output reg [8*MAX_BURST_BYTES-1:0] cmd_rdata,
output reg busy,
// ASIC SPI
output csn,
output sck,
output si,
input so
);
// opcode + + payload
// HEADER_BITS + 8*safe_cmd_len bit
localparam FRAME_MAX_BITS = 8 * (1 + ADDR_BYTES + MAX_BURST_BYTES);
localparam HEADER_BITS = 8 * (1 + ADDR_BYTES);
localparam [15:0] MAX_BURST_BYTES_W = MAX_BURST_BYTES;
localparam [15:0] HEADER_BITS_W = HEADER_BITS;
localparam IDLE_ST = 2'd0;
localparam TRANS_ST = 2'd1;
localparam DONE_ST = 2'd2;
//
reg [1:0] cstate;
reg [FRAME_MAX_BITS-1:0] tx_shift;
reg [8*MAX_BURST_BYTES-1:0] rx_shift;
reg [15:0] half_cnt;
reg [15:0] total_bits;
reg [15:0] sampled_bits;
reg csn_r;
reg sck_r;
reg si_r;
reg cmd_write_r;
reg [7:0] cmd_len_r;
reg last_sampled;
//
reg [FRAME_MAX_BITS-1:0] frame;
reg [REG_ADDR_WIDTH-1:0] addr_pad;
integer n;
wire half_tick;
wire data_bit_phase;
wire sample_data_bit;
wire [15:0] safe_cmd_len;
wire [15:0] cmd_total_bits;
// cmd_len CSI040 byte 访
// 0 1
assign safe_cmd_len = (cmd_len == 0) ? 16'd1 :
(cmd_len > MAX_BURST_BYTES) ? MAX_BURST_BYTES_W :
{8'd0, cmd_len};
// bit = opcode + + payload
assign cmd_total_bits = HEADER_BITS_W + (safe_cmd_len << 3);
// SCK
assign half_tick = (half_cnt == (CLK_DIV - 1));
// opcode/address
assign data_bit_phase = (sampled_bits >= HEADER_BITS);
assign sample_data_bit = (!cmd_write_r) && data_bit_phase;
assign cmd_ready = (cstate == IDLE_ST);
assign csn = csn_r;
assign sck = sck_r;
assign si = si_r;
// SPI
// [opcode][addr MSB..LSB][payload byte0][payload byte1]...
// payload byte0 cmd_wdata[7:0]
always @(*) begin
frame = {FRAME_MAX_BITS{1'b0}};
addr_pad = cmd_addr;
frame[FRAME_MAX_BITS-1 -: 8] = cmd_write ? OPCODE_WRITE : OPCODE_READ;
for (n = 0; n < ADDR_BYTES; n = n + 1) begin
frame[FRAME_MAX_BITS-1-8*(n+1) -: 8] =
addr_pad[8*(ADDR_BYTES-n)-1 -: 8];
end
for (n = 0; n < MAX_BURST_BYTES; n = n + 1) begin
frame[FRAME_MAX_BITS-1-8*(1+ADDR_BYTES+n) -: 8] =
cmd_wdata[8*n +: 8];
end
end
// SPI CLK_DIV clk SCK
// SCK 沿SCK 沿 SI
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cstate <= IDLE_ST;
tx_shift <= 0;
rx_shift <= 0;
half_cnt <= 0;
total_bits <= 0;
sampled_bits <= 0;
csn_r <= 1'b1;
sck_r <= 1'b0;
si_r <= 1'b0;
cmd_write_r <= 1'b0;
cmd_len_r <= 0;
last_sampled <= 1'b0;
done <= 1'b0;
cmd_rdata <= 0;
busy <= 1'b0;
end else begin
done <= 1'b0;
case (cstate)
IDLE_ST: begin
csn_r <= 1'b1;
sck_r <= 1'b0;
si_r <= 1'b0;
half_cnt <= 0;
sampled_bits <= 0;
last_sampled <= 1'b0;
busy <= 1'b0;
if (cmd_valid) begin
// 线
tx_shift <= frame;
rx_shift <= 0;
total_bits <= cmd_total_bits;
cmd_write_r <= cmd_write;
cmd_len_r <= safe_cmd_len[7:0];
csn_r <= 1'b0;
si_r <= frame[FRAME_MAX_BITS-1];
busy <= 1'b1;
cstate <= TRANS_ST;
end
end
TRANS_ST: begin
busy <= 1'b1;
if (half_tick) begin
half_cnt <= 0;
if (!sck_r) begin
// 沿ASIC SI payload master SO
sck_r <= 1'b1;
if (sample_data_bit)
rx_shift <= {rx_shift[8*MAX_BURST_BYTES-2:0], so};
sampled_bits <= sampled_bits + 1'b1;
if (sampled_bits == (total_bits - 1))
last_sampled <= 1'b1;
end else begin
// 沿
sck_r <= 1'b0;
if (last_sampled) begin
cstate <= DONE_ST;
cmd_rdata <= rx_shift;
end else begin
tx_shift <= {tx_shift[FRAME_MAX_BITS-2:0], 1'b0};
si_r <= tx_shift[FRAME_MAX_BITS-2];
end
end
end else begin
half_cnt <= half_cnt + 1'b1;
end
end
DONE_ST: begin
// CSN 1 clk done
csn_r <= 1'b1;
sck_r <= 1'b0;
si_r <= 1'b0;
busy <= 1'b0;
done <= 1'b1;
last_sampled <= 1'b0;
cstate <= IDLE_ST;
end
default: begin
cstate <= IDLE_ST;
end
endcase
end
end
endmodule