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,572 @@
`timescale 1 ns / 1 ps
//------------------------------------------------------------------------------
// CSI040 ASIC
//
// BRAM
// shadow
// CSI040 SPI
//
//
// bram_* - 32 bit 访
// busy -
// error_busy -
//
// ASIC
// asic_csn/sck/si/so - csi040_spi_master SPI 线
// asic_rst_n/trig - BRAM PIN_CTRL
//------------------------------------------------------------------------------
module csi040_ctrl#
(
// SPI/ASIC
parameter VERSION = 32'h04040001,
parameter SPI_CLK_DIV = 50,
parameter REG_ADDR_WIDTH = 16,
parameter SPI_ADDR_BYTES = 2,
parameter MAX_BURST_BYTES = 4,
parameter [7:0] SPI_OPCODE_WRITE = 8'h00,
parameter [7:0] SPI_OPCODE_READ = 8'h80,
// CSI040 ASIC
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_STATUS1 = 16'h0000,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_STATUS2 = 16'h0001,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_CONTROL = 16'h0002,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_INTERRUPT = 16'h0003,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_Z_MEAS_SAMP = 16'h0004,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_Z_CURRENT_CAL = 16'h0005,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_Z_DELAY_RANGE = 16'h0006,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_CH_ENABLE1 = 16'h0007,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_CH_ENABLE2 = 16'h0008,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_TEST_DCS_KEY = 16'h0009,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_TEST_MODE = 16'h000A,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_CUR_REF_TRIM = 16'h000B,
parameter [REG_ADDR_WIDTH-1:0] CSI_CH_BASE = 16'h0010,
parameter [REG_ADDR_WIDTH-1:0] CSI_CH_STRIDE = 16'h0010,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_STIM_TRIGGER = 16'h0110,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_PART_ID = 16'h011D,
parameter [REG_ADDR_WIDTH-1:0] CSI_REG_REVISION = 16'h011E
)
(
input clk,
input rst_n,
// BRAM bram_clk/bram_rst
// 访 clk
input [12:0] bram_addr,
input bram_clk,
input [31:0] bram_din,
output reg [31:0] bram_dout,
input bram_en,
input bram_rst,
input [3:0] bram_we,
output busy,
output spi_done,
output reg error_busy,
// ASIC SPI
output reg asic_rst_n,
output reg asic_trig,
output asic_csn,
output asic_sck,
output asic_si,
input asic_so
);
//-------------------------------------------------------------------------
// BRAM
//-------------------------------------------------------------------------
localparam BRAM_ADDR_VERSION = 13'h0000;
localparam BRAM_ADDR_STATUS = 13'h0004;
localparam BRAM_ADDR_SPI_ADDR = 13'h0008;
localparam BRAM_ADDR_SPI_WDATA = 13'h000C;
localparam BRAM_ADDR_SPI_CTRL = 13'h0010;
localparam BRAM_ADDR_SPI_RDATA = 13'h0014;
localparam BRAM_ADDR_PIN_CTRL = 13'h0018;
localparam BRAM_ADDR_LAST_ADDR = 13'h001C;
localparam BRAM_ADDR_CONTROL = 13'h0020;
localparam BRAM_ADDR_CH_ENABLE = 13'h0024;
localparam BRAM_ADDR_TRIGGER = 13'h0028;
localparam BRAM_ADDR_SEQ_CMD = 13'h002C;
localparam BRAM_ADDR_CH_INDEX = 13'h0040;
localparam BRAM_ADDR_CH_MISC = 13'h0044;
localparam BRAM_ADDR_CH_CUR_A = 13'h0048;
localparam BRAM_ADDR_CH_CUR_B = 13'h004C;
localparam BRAM_ADDR_CH_CUR_C = 13'h0050;
localparam BRAM_ADDR_CH_CUR_D = 13'h0054;
localparam BRAM_ADDR_CH_STIM_PW = 13'h0058;
localparam BRAM_ADDR_CH_DZ0 = 13'h005C;
localparam BRAM_ADDR_CH_DZ1 = 13'h0060;
localparam BRAM_ADDR_CH_SKIP_AB = 13'h0064;
localparam BRAM_ADDR_CH_SKIP_CD = 13'h0068;
localparam BRAM_ADDR_CH_STIM_NUM = 13'h006C;
localparam BRAM_ADDR_CH_DZ2 = 13'h0070;
localparam BRAM_ADDR_CH_THERAPY_DELAY = 13'h0074;
localparam BRAM_ADDR_CH_THERAPY_NUM = 13'h0078;
localparam BRAM_ADDR_CH_DZ3 = 13'h007C;
localparam BRAM_ADDR_CH_MASTER_NUM = 13'h0080;
// CSI040
// ASIC = CSI_CH_BASE + ch_index * CSI_CH_STRIDE + CH_OFF_*
localparam CH_OFF_MISC = 4'h0;
localparam CH_OFF_CUR_A = 4'h1;
localparam CH_OFF_CUR_B = 4'h2;
localparam CH_OFF_CUR_C = 4'h3;
localparam CH_OFF_CUR_D = 4'h4;
localparam CH_OFF_STIM_PW = 4'h5;
localparam CH_OFF_DZ0 = 4'h6;
localparam CH_OFF_DZ1 = 4'h7;
localparam CH_OFF_SKIP_AB = 4'h8;
localparam CH_OFF_SKIP_CD = 4'h9;
localparam CH_OFF_STIM_NUM = 4'hA;
localparam CH_OFF_DZ2 = 4'hB;
localparam CH_OFF_THERAPY_DELAY = 4'hC;
localparam CH_OFF_THERAPY_NUM = 4'hD;
localparam CH_OFF_DZ3 = 4'hE;
localparam CH_OFF_MASTER_NUM = 4'hF;
// SPI
// 使DCS
localparam SEQ_IDLE = 4'h0;
localparam SEQ_WRITE_CONTROL = 4'h1;
localparam SEQ_CH_ENABLE = 4'h2;
localparam SEQ_TRIGGER = 4'h3;
localparam SEQ_DCS_UNLOCK = 4'h4;
localparam SEQ_TEST_UNLOCK = 4'h5;
localparam SEQ_MODE_EXIT = 4'h6;
localparam SEQ_CH_WRITE = 4'h7;
localparam SEQ_DIRECT = 4'h8;
// SPI master
reg spi_cmd_valid;
reg spi_cmd_write;
reg [REG_ADDR_WIDTH-1:0] spi_cmd_addr;
reg [8*MAX_BURST_BYTES-1:0] spi_cmd_wdata;
reg [7:0] spi_cmd_len;
wire spi_cmd_ready;
wire [8*MAX_BURST_BYTES-1:0] spi_cmd_rdata;
wire spi_busy;
wire spi_master_done;
// Direct SPI 访访 ASIC
// SPI_ADDRSPI_WDATASPI_CTRL
reg [REG_ADDR_WIDTH-1:0] direct_addr;
reg [31:0] direct_wdata;
reg [7:0] direct_len;
reg direct_write;
reg [31:0] last_rdata;
reg [REG_ADDR_WIDTH-1:0] last_addr;
// shadow
reg [7:0] control_shadow;
reg [15:0] ch_enable_shadow;
reg [3:0] ch_index;
reg [7:0] ch_data;
reg [3:0] ch_offset;
reg [3:0] seq_id;
reg [2:0] seq_step;
reg seq_active;
reg done_latched;
wire bram_wr_valid;
wire bram_rd_valid;
wire ctrl_busy;
// byte enable
assign bram_wr_valid = bram_en && (bram_we == 4'hF);
assign bram_rd_valid = bram_en && (bram_we == 4'h0);
// SPI master
// busy 1
assign ctrl_busy = seq_active || spi_busy || spi_cmd_valid;
assign busy = ctrl_busy;
assign spi_done = spi_master_done;
// CSI040 ASIC
function [REG_ADDR_WIDTH-1:0] ch_addr;
input [3:0] ch;
input [3:0] offset;
begin
ch_addr = CSI_CH_BASE + (ch * CSI_CH_STRIDE) + offset;
end
endfunction
// CSI040 key
// DCS 55, B3, 0A
// Test AA, 4C, F5
// 退 F9
function [7:0] seq_key_data;
input [3:0] id;
input [2:0] step;
begin
case (id)
SEQ_DCS_UNLOCK: begin
case (step)
3'd0: seq_key_data = 8'h55;
3'd1: seq_key_data = 8'hB3;
default: seq_key_data = 8'h0A;
endcase
end
SEQ_TEST_UNLOCK: begin
case (step)
3'd0: seq_key_data = 8'hAA;
3'd1: seq_key_data = 8'h4C;
default: seq_key_data = 8'hF5;
endcase
end
default: seq_key_data = 8'hF9;
endcase
end
endfunction
// SPI csi040_ctrl
//
csi040_spi_master#
(
.CLK_DIV ( SPI_CLK_DIV ),
.REG_ADDR_WIDTH ( REG_ADDR_WIDTH ),
.ADDR_BYTES ( SPI_ADDR_BYTES ),
.MAX_BURST_BYTES ( MAX_BURST_BYTES ),
.OPCODE_WRITE ( SPI_OPCODE_WRITE ),
.OPCODE_READ ( SPI_OPCODE_READ )
)
u_csi040_spi_master
(
.clk ( clk ),
.rst_n ( rst_n ),
.cmd_ready ( spi_cmd_ready ),
.cmd_valid ( spi_cmd_valid ),
.cmd_write ( spi_cmd_write ),
.cmd_addr ( spi_cmd_addr ),
.cmd_wdata ( spi_cmd_wdata ),
.cmd_len ( spi_cmd_len ),
.done ( spi_master_done ),
.cmd_rdata ( spi_cmd_rdata ),
.busy ( spi_busy ),
.csn ( asic_csn ),
.sck ( asic_sck ),
.si ( asic_si ),
.so ( asic_so )
);
//-------------------------------------------------------------------------
// shadow
//
// always
// 1. shadow
// 2. SPI
// 3. BRAM
//-------------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
direct_addr <= 0;
direct_wdata <= 0;
direct_len <= 8'd1;
direct_write <= 1'b1;
control_shadow <= 8'h00;
ch_enable_shadow <= 16'h0000;
ch_index <= 4'h0;
ch_data <= 8'h00;
ch_offset <= 4'h0;
seq_id <= SEQ_IDLE;
seq_step <= 0;
seq_active <= 1'b0;
error_busy <= 1'b0;
done_latched <= 1'b0;
last_rdata <= 0;
last_addr <= 0;
asic_rst_n <= 1'b1;
asic_trig <= 1'b0;
end else begin
// done_latched STATUS[0]
done_latched <= done_latched;
// SPI seq_step
if (spi_master_done) begin
done_latched <= 1'b1;
last_rdata <= spi_cmd_rdata[31:0];
last_addr <= spi_cmd_addr;
case (seq_id)
SEQ_CH_ENABLE: begin
if (seq_step == 3'd1) begin
seq_active <= 1'b0;
seq_id <= SEQ_IDLE;
end else begin
seq_step <= seq_step + 1'b1;
end
end
SEQ_DCS_UNLOCK,
SEQ_TEST_UNLOCK: begin
if (seq_step == 3'd2) begin
seq_active <= 1'b0;
seq_id <= SEQ_IDLE;
end else begin
seq_step <= seq_step + 1'b1;
end
end
default: begin
seq_active <= 1'b0;
seq_id <= SEQ_IDLE;
end
endcase
end
// STATUS done/error 1
if (bram_wr_valid && (bram_addr == BRAM_ADDR_STATUS)) begin
done_latched <= done_latched & (~bram_din[0]);
error_busy <= error_busy & (~bram_din[1]);
end
if (bram_wr_valid) begin
case (bram_addr)
// Direct SPI SPI
// BRAM_ADDR_SPI_CTRL
BRAM_ADDR_SPI_ADDR: direct_addr <= bram_din[REG_ADDR_WIDTH-1:0];
BRAM_ADDR_SPI_WDATA: direct_wdata <= bram_din;
// SPI trigger
BRAM_ADDR_PIN_CTRL: begin
asic_rst_n <= bram_din[0];
asic_trig <= bram_din[1];
end
// CONTROL 8 bit shadow
// SPI ASIC CSI_REG_CONTROL
BRAM_ADDR_CONTROL: begin
control_shadow <= bram_din[7:0];
if (!ctrl_busy) begin
seq_id <= SEQ_WRITE_CONTROL;
seq_step <= 0;
seq_active <= 1'b1;
end else begin
error_busy <= 1'b1;
end
end
// 使 ASIC 0x0007 0x0008
//
BRAM_ADDR_CH_ENABLE: begin
ch_enable_shadow <= bram_din[15:0];
if (!ctrl_busy) begin
seq_id <= SEQ_CH_ENABLE;
seq_step <= 0;
seq_active <= 1'b1;
end else begin
error_busy <= 1'b1;
end
end
// SPI trigger CSI_REG_STIM_TRIGGER 0xAA
BRAM_ADDR_TRIGGER: begin
if (!ctrl_busy) begin
seq_id <= SEQ_TRIGGER;
seq_step <= 0;
seq_active <= 1'b1;
end else begin
error_busy <= 1'b1;
end
end
// bit
// bit0 DCS bit1 test bit2 退
// bit3/bit4
BRAM_ADDR_SEQ_CMD: begin
if (!ctrl_busy) begin
seq_step <= 0;
seq_active <= 1'b1;
if (bram_din[0]) seq_id <= SEQ_DCS_UNLOCK;
else if (bram_din[1]) seq_id <= SEQ_TEST_UNLOCK;
else if (bram_din[2]) seq_id <= SEQ_MODE_EXIT;
else if (bram_din[3]) begin
seq_id <= SEQ_WRITE_CONTROL;
control_shadow <= 8'h10;
end else if (bram_din[4]) begin
seq_id <= SEQ_WRITE_CONTROL;
control_shadow <= 8'h08;
end else begin
seq_active <= 1'b0;
end
end else begin
error_busy <= 1'b1;
end
end
// 使
BRAM_ADDR_CH_INDEX: ch_index <= bram_din[3:0];
// 8 bit BRAM
// CSI040 offset
BRAM_ADDR_CH_MISC,
BRAM_ADDR_CH_CUR_A,
BRAM_ADDR_CH_CUR_B,
BRAM_ADDR_CH_CUR_C,
BRAM_ADDR_CH_CUR_D,
BRAM_ADDR_CH_STIM_PW,
BRAM_ADDR_CH_DZ0,
BRAM_ADDR_CH_DZ1,
BRAM_ADDR_CH_SKIP_AB,
BRAM_ADDR_CH_SKIP_CD,
BRAM_ADDR_CH_STIM_NUM,
BRAM_ADDR_CH_DZ2,
BRAM_ADDR_CH_THERAPY_DELAY,
BRAM_ADDR_CH_THERAPY_NUM,
BRAM_ADDR_CH_DZ3,
BRAM_ADDR_CH_MASTER_NUM: begin
ch_data <= bram_din[7:0];
case (bram_addr)
BRAM_ADDR_CH_MISC: ch_offset <= CH_OFF_MISC;
BRAM_ADDR_CH_CUR_A: ch_offset <= CH_OFF_CUR_A;
BRAM_ADDR_CH_CUR_B: ch_offset <= CH_OFF_CUR_B;
BRAM_ADDR_CH_CUR_C: ch_offset <= CH_OFF_CUR_C;
BRAM_ADDR_CH_CUR_D: ch_offset <= CH_OFF_CUR_D;
BRAM_ADDR_CH_STIM_PW: ch_offset <= CH_OFF_STIM_PW;
BRAM_ADDR_CH_DZ0: ch_offset <= CH_OFF_DZ0;
BRAM_ADDR_CH_DZ1: ch_offset <= CH_OFF_DZ1;
BRAM_ADDR_CH_SKIP_AB: ch_offset <= CH_OFF_SKIP_AB;
BRAM_ADDR_CH_SKIP_CD: ch_offset <= CH_OFF_SKIP_CD;
BRAM_ADDR_CH_STIM_NUM: ch_offset <= CH_OFF_STIM_NUM;
BRAM_ADDR_CH_DZ2: ch_offset <= CH_OFF_DZ2;
BRAM_ADDR_CH_THERAPY_DELAY: ch_offset <= CH_OFF_THERAPY_DELAY;
BRAM_ADDR_CH_THERAPY_NUM: ch_offset <= CH_OFF_THERAPY_NUM;
BRAM_ADDR_CH_DZ3: ch_offset <= CH_OFF_DZ3;
default: ch_offset <= CH_OFF_MASTER_NUM;
endcase
if (!ctrl_busy) begin
seq_id <= SEQ_CH_WRITE;
seq_step <= 0;
seq_active <= 1'b1;
end else begin
error_busy <= 1'b1;
end
end
// Direct SPI bit0 /
// bits[15:8] 0 1
BRAM_ADDR_SPI_CTRL: begin
if (!ctrl_busy) begin
direct_write <= bram_din[0];
direct_len <= (bram_din[15:8] == 0) ? 8'd1 : bram_din[15:8];
seq_id <= SEQ_DIRECT;
seq_step <= 0;
seq_active <= 1'b1;
end else begin
error_busy <= 1'b1;
end
end
endcase
end
end
end
//-------------------------------------------------------------------------
// SPI
//
// SPI master seq_id/seq_step
// cmd_valid SPI
//-------------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
spi_cmd_valid <= 1'b0;
spi_cmd_write <= 1'b0;
spi_cmd_addr <= 0;
spi_cmd_wdata <= 0;
spi_cmd_len <= 8'd1;
end else begin
spi_cmd_valid <= 1'b0;
if (seq_active && !spi_master_done && spi_cmd_ready && !spi_cmd_valid) begin
case (seq_id)
// ASIC 1
SEQ_WRITE_CONTROL: begin
spi_cmd_valid <= 1'b1;
spi_cmd_write <= 1'b1;
spi_cmd_addr <= CSI_REG_CONTROL;
spi_cmd_wdata <= {{(8*MAX_BURST_BYTES-8){1'b0}}, control_shadow};
spi_cmd_len <= 8'd1;
end
// 1 0-7 8-15
SEQ_CH_ENABLE: begin
spi_cmd_valid <= 1'b1;
spi_cmd_write <= 1'b1;
spi_cmd_addr <= (seq_step == 0) ? CSI_REG_CH_ENABLE1 : CSI_REG_CH_ENABLE2;
spi_cmd_wdata <= (seq_step == 0) ?
{{(8*MAX_BURST_BYTES-8){1'b0}}, ch_enable_shadow[7:0]} :
{{(8*MAX_BURST_BYTES-8){1'b0}}, ch_enable_shadow[15:8]};
spi_cmd_len <= 8'd1;
end
// ASIC trigger register
SEQ_TRIGGER: begin
spi_cmd_valid <= 1'b1;
spi_cmd_write <= 1'b1;
spi_cmd_addr <= CSI_REG_STIM_TRIGGER;
spi_cmd_wdata <= {{(8*MAX_BURST_BYTES-8){1'b0}}, 8'hAA};
spi_cmd_len <= 8'd1;
end
// key ASIC key
// seq_key_data step
SEQ_DCS_UNLOCK,
SEQ_TEST_UNLOCK,
SEQ_MODE_EXIT: begin
spi_cmd_valid <= 1'b1;
spi_cmd_write <= 1'b1;
spi_cmd_addr <= CSI_REG_TEST_DCS_KEY;
spi_cmd_wdata <= {{(8*MAX_BURST_BYTES-8){1'b0}}, seq_key_data(seq_id, seq_step)};
spi_cmd_len <= 8'd1;
end
//
SEQ_CH_WRITE: begin
spi_cmd_valid <= 1'b1;
spi_cmd_write <= 1'b1;
spi_cmd_addr <= ch_addr(ch_index, ch_offset);
spi_cmd_wdata <= {{(8*MAX_BURST_BYTES-8){1'b0}}, ch_data};
spi_cmd_len <= 8'd1;
end
// SPI 访
SEQ_DIRECT: begin
spi_cmd_valid <= 1'b1;
spi_cmd_write <= direct_write;
spi_cmd_addr <= direct_addr;
spi_cmd_wdata <= direct_wdata;
spi_cmd_len <= direct_len;
end
endcase
end
end
end
//-------------------------------------------------------------------------
// BRAM bram_dout
//-------------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
bram_dout <= 0;
end else if (bram_rd_valid) begin
case (bram_addr)
BRAM_ADDR_VERSION: bram_dout <= VERSION;
BRAM_ADDR_STATUS: bram_dout <= {16'd0, seq_id, seq_step, error_busy, done_latched, spi_cmd_ready, ctrl_busy};
BRAM_ADDR_SPI_ADDR: bram_dout <= {{(32-REG_ADDR_WIDTH){1'b0}}, direct_addr};
BRAM_ADDR_SPI_WDATA: bram_dout <= direct_wdata;
BRAM_ADDR_SPI_RDATA: bram_dout <= last_rdata;
BRAM_ADDR_PIN_CTRL: bram_dout <= {30'd0, asic_trig, asic_rst_n};
BRAM_ADDR_LAST_ADDR: bram_dout <= {{(32-REG_ADDR_WIDTH){1'b0}}, last_addr};
BRAM_ADDR_CONTROL: bram_dout <= {24'd0, control_shadow};
BRAM_ADDR_CH_ENABLE: bram_dout <= {16'd0, ch_enable_shadow};
BRAM_ADDR_CH_INDEX: bram_dout <= {28'd0, ch_index};
default: bram_dout <= 0;
endcase
end
end
endmodule