Files

573 lines
27 KiB
Verilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
`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_ADDR、SPI_WDATA、SPI_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