Files
BSI-901-fpga-software/docs/csi040_ctrl_design.html
T
2026-09-11 16:18:36 +08:00

463 lines
42 KiB
HTML
Raw 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.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSI040 控制模块详细设计文档</title>
<style>
:root {
--bg: #f6f7f5;
--paper: #ffffff;
--ink: #202421;
--muted: #667069;
--line: #dfe5df;
--accent: #167c80;
--accent-soft: #e6f4f2;
--warn-soft: #fff7e6;
--code-bg: #1f2422;
--code-ink: #edf2ee;
--shadow: 0 16px 36px rgba(32, 36, 33, 0.08);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
color: var(--ink);
background: var(--bg);
font: 15px/1.72 "Microsoft YaHei", "PingFang SC", "Segoe UI", Arial, sans-serif;
}
.shell {
display: grid;
grid-template-columns: 288px minmax(0, 1fr);
min-height: 100vh;
}
aside {
position: sticky;
top: 0;
height: 100vh;
overflow: auto;
padding: 28px 22px;
border-right: 1px solid var(--line);
background: #fbfcfb;
}
.brand {
padding-bottom: 18px;
margin-bottom: 18px;
border-bottom: 1px solid var(--line);
}
.brand-title {
margin: 0 0 8px;
font-size: 18px;
line-height: 1.35;
font-weight: 700;
}
.brand-meta {
margin: 0;
color: var(--muted);
font-size: 12px;
line-height: 1.5;
}
nav a {
display: block;
color: #35403a;
text-decoration: none;
border-radius: 6px;
padding: 5px 8px;
margin: 1px 0;
}
nav a:hover { background: var(--accent-soft); color: var(--accent); }
.toc-l1 { font-weight: 700; }
.toc-l2 { padding-left: 18px; font-size: 14px; }
.toc-l3 { padding-left: 34px; font-size: 13px; color: var(--muted); }
main {
min-width: 0;
padding: 38px 42px 72px;
}
article {
max-width: 1120px;
margin: 0 auto;
padding: 42px 52px;
background: var(--paper);
border: 1px solid var(--line);
border-radius: 10px;
box-shadow: var(--shadow);
}
h1, h2, h3, h4, h5, h6 {
position: relative;
line-height: 1.32;
margin: 1.9em 0 0.72em;
color: #1d2622;
}
h1 { margin-top: 0; font-size: 30px; padding-bottom: 14px; border-bottom: 2px solid var(--accent); }
h2 { font-size: 23px; border-top: 1px solid var(--line); padding-top: 24px; }
h3 { font-size: 18px; }
h4 { font-size: 16px; }
.anchor {
position: absolute;
left: -24px;
color: var(--accent);
opacity: 0;
text-decoration: none;
font-weight: 500;
}
h1:hover .anchor, h2:hover .anchor, h3:hover .anchor, h4:hover .anchor { opacity: 1; }
p { margin: 0.8em 0; }
ul { padding-left: 1.35em; }
li { margin: 0.25em 0; }
code {
font-family: Consolas, "Cascadia Mono", "SFMono-Regular", monospace;
font-size: 0.92em;
border-radius: 4px;
background: #eef2ef;
padding: 0.12em 0.35em;
}
pre {
position: relative;
overflow: auto;
margin: 18px 0;
padding: 18px 20px;
color: var(--code-ink);
background: var(--code-bg);
border-radius: 8px;
line-height: 1.55;
}
pre code { padding: 0; background: transparent; color: inherit; font-size: 13px; }
.table-wrap { overflow-x: auto; margin: 18px 0 24px; border: 1px solid var(--line); border-radius: 8px; }
table { width: 100%; border-collapse: collapse; min-width: 640px; }
th, td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
th { position: sticky; top: 0; z-index: 1; background: #edf5f3; text-align: left; font-weight: 700; }
tr:nth-child(even) td { background: #fafbfa; }
tr:last-child td { border-bottom: 0; }
.doc-note {
margin: 0 0 28px;
padding: 14px 16px;
background: var(--warn-soft);
border: 1px solid #f1d28a;
border-radius: 8px;
color: #654700;
}
.top-link {
position: fixed;
right: 24px;
bottom: 22px;
padding: 8px 12px;
border-radius: 999px;
background: var(--accent);
color: #fff;
text-decoration: none;
box-shadow: 0 8px 18px rgba(22,124,128,.22);
font-size: 13px;
}
@media (max-width: 980px) {
.shell { display: block; }
aside { position: static; height: auto; max-height: 42vh; border-right: 0; border-bottom: 1px solid var(--line); }
main { padding: 22px 14px 54px; }
article { padding: 28px 18px; border-radius: 8px; }
.anchor { display: none; }
h1 { font-size: 25px; }
h2 { font-size: 20px; }
}
@media print {
body { background: #fff; font-size: 12px; }
.shell { display: block; }
aside, .top-link { display: none; }
main { padding: 0; }
article { max-width: none; padding: 0; border: 0; box-shadow: none; }
h1, h2, h3 { break-after: avoid; }
pre, .table-wrap { break-inside: avoid; }
a { color: inherit; text-decoration: none; }
}
</style>
</head>
<body>
<div class="shell" id="top">
<aside>
<div class="brand">
<p class="brand-title">CSI040 控制模块详细设计文档</p>
<p class="brand-meta">源文件:docs/csi040_ctrl_design.md<br>生成时间:2026-07-01 09:47:07<br>离线单文件 HTML</p>
</div>
<nav aria-label="文档目录">
<a class="toc-l1" href="#csi040-控制模块详细设计文档">CSI040 控制模块详细设计文档</a>
<a class="toc-l2" href="#1-文档范围">1. 文档范围</a>
<a class="toc-l2" href="#2-总体结构">2. 总体结构</a>
<a class="toc-l2" href="#3-模块参数">3. 模块参数</a>
<a class="toc-l3" href="#3-1-csi040-ctrl">3.1 <code>csi040_ctrl</code></a>
<a class="toc-l3" href="#3-2-csi040-spi-master">3.2 <code>csi040_spi_master</code></a>
<a class="toc-l2" href="#4-顶层接口">4. 顶层接口</a>
<a class="toc-l3" href="#4-1-时钟复位">4.1 时钟复位</a>
<a class="toc-l3" href="#4-2-bram-风格控制口">4.2 BRAM 风格控制口</a>
<a class="toc-l3" href="#4-3-状态输出">4.3 状态输出</a>
<a class="toc-l3" href="#4-4-asic-侧引脚">4.4 ASIC 侧引脚</a>
<a class="toc-l2" href="#5-bram-寄存器映射">5. BRAM 寄存器映射</a>
<a class="toc-l3" href="#5-1-status-字段">5.1 <code>STATUS</code> 字段</a>
<a class="toc-l3" href="#5-2-状态清除">5.2 状态清除</a>
<a class="toc-l2" href="#6-高层命令序列设计">6. 高层命令序列设计</a>
<a class="toc-l3" href="#6-1-busy-机制">6.1 Busy 机制</a>
<a class="toc-l3" href="#6-2-写控制寄存器">6.2 写控制寄存器</a>
<a class="toc-l3" href="#6-3-写通道使能">6.3 写通道使能</a>
<a class="toc-l3" href="#6-4-写触发命令">6.4 写触发命令</a>
<a class="toc-l3" href="#6-5-特殊序列-seq-cmd">6.5 特殊序列 <code>SEQ_CMD</code></a>
<a class="toc-l3" href="#6-6-通道参数写">6.6 通道参数写</a>
<a class="toc-l3" href="#6-7-direct-spi-访问">6.7 Direct SPI 访问</a>
<a class="toc-l2" href="#7-spi-master-设计">7. SPI Master 设计</a>
<a class="toc-l3" href="#7-1-命令接口">7.1 命令接口</a>
<a class="toc-l3" href="#7-2-spi-帧格式">7.2 SPI 帧格式</a>
<a class="toc-l3" href="#7-3-spi-状态机">7.3 SPI 状态机</a>
<a class="toc-l3" href="#7-4-读数据采样">7.4 读数据采样</a>
<a class="toc-l2" href="#8-复位行为">8. 复位行为</a>
<a class="toc-l2" href="#9-当前-testbench-覆盖">9. 当前 Testbench 覆盖</a>
<a class="toc-l2" href="#10-仿真与波形">10. 仿真与波形</a>
<a class="toc-l2" href="#11-软件使用建议">11. 软件使用建议</a>
<a class="toc-l2" href="#12-后续可改进点">12. 后续可改进点</a>
</nav>
</aside>
<main>
<article>
<p class="doc-note">优化版 HTML:已添加侧边目录、章节锚点、响应式表格、打印样式和离线 CSS。</p>
<h1 id="csi040-控制模块详细设计文档"><a class="anchor" href="#csi040-控制模块详细设计文档" aria-label="章节链接">#</a>CSI040 控制模块详细设计文档</h1>
<h2 id="1-文档范围"><a class="anchor" href="#1-文档范围" aria-label="章节链接">#</a>1. 文档范围</h2>
<p>本文档描述 CSI040 ASIC 控制模块的 RTL 设计,覆盖以下文件:</p>
<ul><li><code>c64_pro.srcs/sources_1/rtl/csi040/csi040_ctrl.v</code></li><li><code>c64_pro.srcs/sources_1/rtl/csi040/csi040_spi_master.v</code></li><li><code>c64_pro.srcs/sources_1/rtl/csi040/csi040_ctrl_tb.v</code></li></ul>
<p>该模块在 FPGA/PL 侧提供一组 BRAM 风格的控制寄存器。上位逻辑或 PS 通过写这些寄存器来触发 CSI040 ASIC 的 SPI 读写、通道参数配置、模式解锁、触发控制等操作。</p>
<h2 id="2-总体结构"><a class="anchor" href="#2-总体结构" aria-label="章节链接">#</a>2. 总体结构</h2>
<pre><code class="language-text">PS / 软件
|
| BRAM 风格寄存器访问
v
+------------------+
| csi040_ctrl |
| |
| 软件寄存器映射 |
| shadow 寄存器 |
| seq 序列控制器 |
| 状态/错误锁存 |
+--------+---------+
|
| cmd_valid / cmd_ready / cmd_addr / cmd_wdata / cmd_len
v
+---------------------+
| csi040_spi_master |
| |
| SPI 组帧 |
| SCK/CSN/SI/SO 时序 |
+----------+----------+
|
| asic_csn / asic_sck / asic_si / asic_so
v
CSI040 ASIC</code></pre>
<p><code>csi040_ctrl</code> 是上层可见的控制模块,负责接收 BRAM 写操作、保存软件配置、发起高层命令序列,并把命令转换为 SPI master 的抽象命令接口。</p>
<p><code>csi040_spi_master</code> 是底层 SPI 引擎,负责把 opcode、ASIC 地址和数据字节按 SPI 时序移出,并在读操作时采样 <code>asic_so</code></p>
<h2 id="3-模块参数"><a class="anchor" href="#3-模块参数" aria-label="章节链接">#</a>3. 模块参数</h2>
<h3 id="3-1-csi040-ctrl"><a class="anchor" href="#3-1-csi040-ctrl" aria-label="章节链接">#</a>3.1 <code>csi040_ctrl</code></h3>
<div class="table-wrap"><table><thead><tr><th>参数</th><th style="text-align:right">默认值</th><th>说明</th></tr></thead><tbody><tr><td><code>VERSION</code></td><td style="text-align:right"><code>32&#39;h04040001</code></td><td>模块版本号,读 BRAM 地址 <code>0x0000</code> 返回。</td></tr><tr><td><code>SPI_CLK_DIV</code></td><td style="text-align:right"><code>50</code></td><td>SPI SCK 半周期分频系数,<code>f_sck = f_clk / (2 * SPI_CLK_DIV)</code></td></tr><tr><td><code>REG_ADDR_WIDTH</code></td><td style="text-align:right"><code>16</code></td><td>ASIC 内部寄存器地址宽度。</td></tr><tr><td><code>SPI_ADDR_BYTES</code></td><td style="text-align:right"><code>2</code></td><td>SPI 帧中的地址字节数。</td></tr><tr><td><code>MAX_BURST_BYTES</code></td><td style="text-align:right"><code>4</code></td><td>单次 SPI 最大数据字节数。</td></tr><tr><td><code>SPI_OPCODE_WRITE</code></td><td style="text-align:right"><code>8&#39;h00</code></td><td>默认写 opcodetestbench 中重载为 <code>8&#39;h02</code></td></tr><tr><td><code>SPI_OPCODE_READ</code></td><td style="text-align:right"><code>8&#39;h80</code></td><td>默认读 opcodetestbench 中重载为 <code>8&#39;h03</code></td></tr><tr><td><code>CSI_REG_*</code></td><td style="text-align:right">多个地址</td><td>CSI040 ASIC 内部寄存器地址参数。</td></tr></tbody></table></div>
<h3 id="3-2-csi040-spi-master"><a class="anchor" href="#3-2-csi040-spi-master" aria-label="章节链接">#</a>3.2 <code>csi040_spi_master</code></h3>
<div class="table-wrap"><table><thead><tr><th>参数</th><th style="text-align:right">默认值</th><th>说明</th></tr></thead><tbody><tr><td><code>CLK_DIV</code></td><td style="text-align:right"><code>50</code></td><td>SCK 半周期对应的 <code>clk</code> 周期数。</td></tr><tr><td><code>REG_ADDR_WIDTH</code></td><td style="text-align:right"><code>16</code></td><td><code>cmd_addr</code> 地址宽度。</td></tr><tr><td><code>ADDR_BYTES</code></td><td style="text-align:right"><code>2</code></td><td>SPI 地址字段字节数。</td></tr><tr><td><code>MAX_BURST_BYTES</code></td><td style="text-align:right"><code>4</code></td><td>最大 payload 字节数。</td></tr><tr><td><code>OPCODE_WRITE</code></td><td style="text-align:right"><code>8&#39;h00</code></td><td>SPI 写命令 opcode。</td></tr><tr><td><code>OPCODE_READ</code></td><td style="text-align:right"><code>8&#39;h80</code></td><td>SPI 读命令 opcode。</td></tr></tbody></table></div>
<h2 id="4-顶层接口"><a class="anchor" href="#4-顶层接口" aria-label="章节链接">#</a>4. 顶层接口</h2>
<h3 id="4-1-时钟复位"><a class="anchor" href="#4-1-时钟复位" aria-label="章节链接">#</a>4.1 时钟复位</h3>
<div class="table-wrap"><table><thead><tr><th>信号</th><th>方向</th><th>说明</th></tr></thead><tbody><tr><td><code>clk</code></td><td>input</td><td>主时钟,当前所有寄存器逻辑都使用该时钟。</td></tr><tr><td><code>rst_n</code></td><td>input</td><td>异步低有效复位。</td></tr><tr><td><code>bram_clk</code></td><td>input</td><td>接口保留信号,当前 RTL 未使用。</td></tr><tr><td><code>bram_rst</code></td><td>input</td><td>接口保留信号,当前 RTL 未使用。</td></tr></tbody></table></div>
<p>注意:虽然接口里有 <code>bram_clk</code>,但当前实现没有使用它。因此 BRAM 控制访问应与 <code>clk</code> 同步。如果后续接真实 AXI BRAM Controller 且时钟不同,需要补 CDC 或改成 <code>bram_clk</code> 域逻辑。</p>
<h3 id="4-2-bram-风格控制口"><a class="anchor" href="#4-2-bram-风格控制口" aria-label="章节链接">#</a>4.2 BRAM 风格控制口</h3>
<div class="table-wrap"><table><thead><tr><th>信号</th><th>方向</th><th style="text-align:right">位宽</th><th>说明</th></tr></thead><tbody><tr><td><code>bram_addr</code></td><td>input</td><td style="text-align:right">13</td><td>BRAM 字节地址,当前使用 4 字节对齐地址。</td></tr><tr><td><code>bram_din</code></td><td>input</td><td style="text-align:right">32</td><td>写数据。</td></tr><tr><td><code>bram_dout</code></td><td>output reg</td><td style="text-align:right">32</td><td>读数据,在读访问时更新。</td></tr><tr><td><code>bram_en</code></td><td>input</td><td style="text-align:right">1</td><td>BRAM 访问使能。</td></tr><tr><td><code>bram_we</code></td><td>input</td><td style="text-align:right">4</td><td>写使能。当前仅识别 <code>4&#39;hF</code> 为写、<code>4&#39;h0</code> 为读。</td></tr></tbody></table></div>
<p>RTL 中访问判定为:</p>
<pre><code class="language-verilog">assign bram_wr_valid = bram_en &amp;&amp; (bram_we == 4&#39;hF);
assign bram_rd_valid = bram_en &amp;&amp; (bram_we == 4&#39;h0);</code></pre>
<p>因此当前模块不支持 byte enable 局部写。如果软件侧产生 <code>bram_we = 4&#39;h1/4&#39;h3</code> 之类的写操作,该写不会被模块识别。</p>
<h3 id="4-3-状态输出"><a class="anchor" href="#4-3-状态输出" aria-label="章节链接">#</a>4.3 状态输出</h3>
<div class="table-wrap"><table><thead><tr><th>信号</th><th>方向</th><th>说明</th></tr></thead><tbody><tr><td><code>busy</code></td><td>output</td><td>模块忙标志。只要高层序列、SPI master 或待发 SPI 命令任一处于忙状态,该信号为高。</td></tr><tr><td><code>spi_done</code></td><td>output</td><td>SPI master 完成脉冲,持续 1 个 <code>clk</code> 周期。</td></tr><tr><td><code>error_busy</code></td><td>output reg</td><td>忙时启动新命令的粘滞错误标志,需要软件写 <code>STATUS[1]</code> 清除。</td></tr></tbody></table></div>
<h3 id="4-4-asic-侧引脚"><a class="anchor" href="#4-4-asic-侧引脚" aria-label="章节链接">#</a>4.4 ASIC 侧引脚</h3>
<div class="table-wrap"><table><thead><tr><th>信号</th><th>方向</th><th>说明</th></tr></thead><tbody><tr><td><code>asic_rst_n</code></td><td>output reg</td><td>ASIC 复位控制,软件通过 <code>PIN_CTRL[0]</code> 控制,复位默认值为 1。</td></tr><tr><td><code>asic_trig</code></td><td>output reg</td><td>ASIC 外部触发引脚,软件通过 <code>PIN_CTRL[1]</code> 控制,复位默认值为 0。</td></tr><tr><td><code>asic_csn</code></td><td>output</td><td>SPI 片选,低有效。</td></tr><tr><td><code>asic_sck</code></td><td>output</td><td>SPI 时钟,空闲为低。</td></tr><tr><td><code>asic_si</code></td><td>output</td><td>SPI master 输出到 ASIC 的串行数据。</td></tr><tr><td><code>asic_so</code></td><td>input</td><td>ASIC 输出到 SPI master 的串行数据。</td></tr></tbody></table></div>
<h2 id="5-bram-寄存器映射"><a class="anchor" href="#5-bram-寄存器映射" aria-label="章节链接">#</a>5. BRAM 寄存器映射</h2>
<p>所有地址均为字节地址。</p>
<div class="table-wrap"><table><thead><tr><th style="text-align:right">地址</th><th>名称</th><th>访问</th><th>说明</th></tr></thead><tbody><tr><td style="text-align:right"><code>13&#39;h0000</code></td><td><code>VERSION</code></td><td>R</td><td>读取模块版本号 <code>VERSION</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0004</code></td><td><code>STATUS</code></td><td>R/W1C</td><td>读取模块状态;写 bit0 清 <code>done_latched</code>,写 bit1 清 <code>error_busy</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0008</code></td><td><code>SPI_ADDR</code></td><td>R/W</td><td>Direct SPI 访问的 ASIC 地址。</td></tr><tr><td style="text-align:right"><code>13&#39;h000C</code></td><td><code>SPI_WDATA</code></td><td>R/W</td><td>Direct SPI 写数据。payload 第 1 字节来自 <code>bram_din[7:0]</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0010</code></td><td><code>SPI_CTRL</code></td><td>W</td><td>启动 Direct SPI 访问。<code>bit0=write</code><code>bits[15:8]=length</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0014</code></td><td><code>SPI_RDATA</code></td><td>R</td><td>最近一次 SPI 读回数据。</td></tr><tr><td style="text-align:right"><code>13&#39;h0018</code></td><td><code>PIN_CTRL</code></td><td>R/W</td><td><code>bit0=asic_rst_n</code><code>bit1=asic_trig</code></td></tr><tr><td style="text-align:right"><code>13&#39;h001C</code></td><td><code>LAST_ADDR</code></td><td>R</td><td>最近一次完成 SPI 操作的 ASIC 地址。</td></tr><tr><td style="text-align:right"><code>13&#39;h0020</code></td><td><code>CONTROL</code></td><td>R/W</td><td>更新 <code>control_shadow</code>,并写 ASIC 控制寄存器 <code>0x0002</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0024</code></td><td><code>CH_ENABLE</code></td><td>R/W</td><td>更新 <code>ch_enable_shadow</code>,并写 ASIC 通道使能寄存器 <code>0x0007/0x0008</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0028</code></td><td><code>TRIGGER</code></td><td>W</td><td>写 ASIC 触发寄存器 <code>0x0110 = 8&#39;hAA</code></td></tr><tr><td style="text-align:right"><code>13&#39;h002C</code></td><td><code>SEQ_CMD</code></td><td>W</td><td>启动特殊序列:DCS unlock、Test unlock、mode exit、控制寄存器快捷写。</td></tr><tr><td style="text-align:right"><code>13&#39;h0040</code></td><td><code>CH_INDEX</code></td><td>R/W</td><td>选择后续通道参数写入的 channel index。</td></tr><tr><td style="text-align:right"><code>13&#39;h0044</code></td><td><code>CH_MISC</code></td><td>W</td><td>写当前 channel 的 offset <code>0x0</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0048</code></td><td><code>CH_CUR_A</code></td><td>W</td><td>写当前 channel 的 offset <code>0x1</code></td></tr><tr><td style="text-align:right"><code>13&#39;h004C</code></td><td><code>CH_CUR_B</code></td><td>W</td><td>写当前 channel 的 offset <code>0x2</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0050</code></td><td><code>CH_CUR_C</code></td><td>W</td><td>写当前 channel 的 offset <code>0x3</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0054</code></td><td><code>CH_CUR_D</code></td><td>W</td><td>写当前 channel 的 offset <code>0x4</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0058</code></td><td><code>CH_STIM_PW</code></td><td>W</td><td>写当前 channel 的 offset <code>0x5</code></td></tr><tr><td style="text-align:right"><code>13&#39;h005C</code></td><td><code>CH_DZ0</code></td><td>W</td><td>写当前 channel 的 offset <code>0x6</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0060</code></td><td><code>CH_DZ1</code></td><td>W</td><td>写当前 channel 的 offset <code>0x7</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0064</code></td><td><code>CH_SKIP_AB</code></td><td>W</td><td>写当前 channel 的 offset <code>0x8</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0068</code></td><td><code>CH_SKIP_CD</code></td><td>W</td><td>写当前 channel 的 offset <code>0x9</code></td></tr><tr><td style="text-align:right"><code>13&#39;h006C</code></td><td><code>CH_STIM_NUM</code></td><td>W</td><td>写当前 channel 的 offset <code>0xA</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0070</code></td><td><code>CH_DZ2</code></td><td>W</td><td>写当前 channel 的 offset <code>0xB</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0074</code></td><td><code>CH_THERAPY_DELAY</code></td><td>W</td><td>写当前 channel 的 offset <code>0xC</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0078</code></td><td><code>CH_THERAPY_NUM</code></td><td>W</td><td>写当前 channel 的 offset <code>0xD</code></td></tr><tr><td style="text-align:right"><code>13&#39;h007C</code></td><td><code>CH_DZ3</code></td><td>W</td><td>写当前 channel 的 offset <code>0xE</code></td></tr><tr><td style="text-align:right"><code>13&#39;h0080</code></td><td><code>CH_MASTER_NUM</code></td><td>W</td><td>写当前 channel 的 offset <code>0xF</code></td></tr></tbody></table></div>
<h3 id="5-1-status-字段"><a class="anchor" href="#5-1-status-字段" aria-label="章节链接">#</a>5.1 <code>STATUS</code> 字段</h3>
<p>RTL 返回表达式为:</p>
<pre><code class="language-verilog">bram_dout &lt;= {16&#39;d0, seq_id, seq_step, error_busy, done_latched, spi_cmd_ready, ctrl_busy};</code></pre>
<p>该拼接宽度为 26 bit,赋值给 32 bit 时左侧补 0。因此软件侧实际可按低位理解:</p>
<div class="table-wrap"><table><thead><tr><th style="text-align:right"></th><th>名称</th><th>说明</th></tr></thead><tbody><tr><td style="text-align:right"><code>[5]</code></td><td><code>ctrl_busy</code></td><td>当前模块忙。</td></tr><tr><td style="text-align:right"><code>[6]</code></td><td><code>spi_cmd_ready</code></td><td>SPI master 是否空闲可接收新命令。</td></tr><tr><td style="text-align:right"><code>[7]</code></td><td><code>done_latched</code></td><td>最近至少完成过一次 SPI 操作,写 <code>STATUS[0]=1</code> 清除。</td></tr><tr><td style="text-align:right"><code>[8]</code></td><td><code>error_busy</code></td><td>忙时写命令产生的错误,写 <code>STATUS[1]=1</code> 清除。</td></tr><tr><td style="text-align:right"><code>[11:9]</code></td><td><code>seq_step</code></td><td>当前高层序列步骤。</td></tr><tr><td style="text-align:right"><code>[15:12]</code></td><td><code>seq_id</code></td><td>当前高层序列编号。</td></tr><tr><td style="text-align:right">其他</td><td>0</td><td>保留。</td></tr></tbody></table></div>
<h3 id="5-2-状态清除"><a class="anchor" href="#5-2-状态清除" aria-label="章节链接">#</a>5.2 状态清除</h3>
<p><code>BRAM_ADDR_STATUS</code> 时:</p>
<div class="table-wrap"><table><thead><tr><th style="text-align:right">写入位</th><th>行为</th></tr></thead><tbody><tr><td style="text-align:right"><code>bram_din[0] = 1</code></td><td>清除 <code>done_latched</code></td></tr><tr><td style="text-align:right"><code>bram_din[1] = 1</code></td><td>清除 <code>error_busy</code></td></tr></tbody></table></div>
<h2 id="6-高层命令序列设计"><a class="anchor" href="#6-高层命令序列设计" aria-label="章节链接">#</a>6. 高层命令序列设计</h2>
<p>模块内部用 <code>seq_id + seq_step + seq_active</code> 控制多拍或多 SPI 帧操作。</p>
<div class="table-wrap"><table><thead><tr><th style="text-align:right"><code>seq_id</code></th><th>名称</th><th>触发来源</th></tr></thead><tbody><tr><td style="text-align:right"><code>4&#39;h0</code></td><td><code>SEQ_IDLE</code></td><td>空闲。</td></tr><tr><td style="text-align:right"><code>4&#39;h1</code></td><td><code>SEQ_WRITE_CONTROL</code></td><td><code>CONTROL</code>,或 <code>SEQ_CMD[3]/[4]</code></td></tr><tr><td style="text-align:right"><code>4&#39;h2</code></td><td><code>SEQ_CH_ENABLE</code></td><td><code>CH_ENABLE</code></td></tr><tr><td style="text-align:right"><code>4&#39;h3</code></td><td><code>SEQ_TRIGGER</code></td><td><code>TRIGGER</code></td></tr><tr><td style="text-align:right"><code>4&#39;h4</code></td><td><code>SEQ_DCS_UNLOCK</code></td><td><code>SEQ_CMD[0]</code></td></tr><tr><td style="text-align:right"><code>4&#39;h5</code></td><td><code>SEQ_TEST_UNLOCK</code></td><td><code>SEQ_CMD[1]</code></td></tr><tr><td style="text-align:right"><code>4&#39;h6</code></td><td><code>SEQ_MODE_EXIT</code></td><td><code>SEQ_CMD[2]</code></td></tr><tr><td style="text-align:right"><code>4&#39;h7</code></td><td><code>SEQ_CH_WRITE</code></td><td>写任意通道参数寄存器。</td></tr><tr><td style="text-align:right"><code>4&#39;h8</code></td><td><code>SEQ_DIRECT</code></td><td><code>SPI_CTRL</code></td></tr></tbody></table></div>
<h3 id="6-1-busy-机制"><a class="anchor" href="#6-1-busy-机制" aria-label="章节链接">#</a>6.1 Busy 机制</h3>
<p>模块忙信号定义:</p>
<pre><code class="language-verilog">ctrl_busy = seq_active || spi_busy || spi_cmd_valid;
busy = ctrl_busy;</code></pre>
<p>对所有会启动 SPI 的 BRAM 写操作,RTL 都先检查 <code>!ctrl_busy</code>。若忙时写入命令寄存器:</p>
<ul><li>不启动新命令;</li><li><code>error_busy &lt;= 1&#39;b1</code></li><li>该错误保持到软件写 <code>STATUS[1]</code> 清除。</li></ul>
<p>推荐软件流程:</p>
<p>1. 轮询 <code>busy == 0</code><code>STATUS[5] == 0</code>。 2. 写命令寄存器。 3. 等待 <code>done_latched == 1</code> 或等待固定时间。 4. 如有读操作,读取 <code>SPI_RDATA</code>。 5. 写 <code>STATUS[0] = 1</code> 清除 done 标志。</p>
<h3 id="6-2-写控制寄存器"><a class="anchor" href="#6-2-写控制寄存器" aria-label="章节链接">#</a>6.2 写控制寄存器</h3>
<p><code>BRAM_ADDR_CONTROL</code></p>
<p>1. <code>control_shadow &lt;= bram_din[7:0]</code> 2. 启动 <code>SEQ_WRITE_CONTROL</code> 3. 产生 1 个 SPI write</p>
<pre><code class="language-text">ASIC addr = CSI_REG_CONTROL = 0x0002
data = control_shadow
length = 1 byte</code></pre>
<p>testbench 中写:</p>
<pre><code class="language-text">write_bram(13&#39;h0020, 32&#39;h00000010)</code></pre>
<p>期望 SPI 帧:</p>
<pre><code class="language-text">0x02_0002_10</code></pre>
<h3 id="6-3-写通道使能"><a class="anchor" href="#6-3-写通道使能" aria-label="章节链接">#</a>6.3 写通道使能</h3>
<p><code>BRAM_ADDR_CH_ENABLE</code></p>
<p>1. <code>ch_enable_shadow &lt;= bram_din[15:0]</code> 2. 启动 <code>SEQ_CH_ENABLE</code> 3. 分两步写 ASIC</p>
<pre><code class="language-text">seq_step 0: addr 0x0007, data ch_enable_shadow[7:0]
seq_step 1: addr 0x0008, data ch_enable_shadow[15:8]</code></pre>
<p>testbench 中写 <code>0xA55A</code>,期望两帧:</p>
<pre><code class="language-text">0x02_0007_5A
0x02_0008_A5</code></pre>
<h3 id="6-4-写触发命令"><a class="anchor" href="#6-4-写触发命令" aria-label="章节链接">#</a>6.4 写触发命令</h3>
<p><code>BRAM_ADDR_TRIGGER</code> 启动 <code>SEQ_TRIGGER</code>SPI 写:</p>
<pre><code class="language-text">ASIC addr = CSI_REG_STIM_TRIGGER = 0x0110
data = 8&#39;hAA</code></pre>
<p>注意:该 SPI trigger 与 <code>asic_trig</code> 引脚是两个不同路径。<code>asic_trig</code> 只受 <code>PIN_CTRL[1]</code> 控制。</p>
<h3 id="6-5-特殊序列-seq-cmd"><a class="anchor" href="#6-5-特殊序列-seq-cmd" aria-label="章节链接">#</a>6.5 特殊序列 <code>SEQ_CMD</code></h3>
<p><code>BRAM_ADDR_SEQ_CMD</code> 时,RTL 按 bit 优先级解析:</p>
<div class="table-wrap"><table><thead><tr><th style="text-align:right">bit</th><th>序列</th><th>实际 SPI 操作</th></tr></thead><tbody><tr><td style="text-align:right"><code>0</code></td><td>DCS unlock</td><td>连续向 <code>0x0009</code><code>55h, B3h, 0Ah</code></td></tr><tr><td style="text-align:right"><code>1</code></td><td>Test unlock</td><td>连续向 <code>0x0009</code><code>AAh, 4Ch, F5h</code></td></tr><tr><td style="text-align:right"><code>2</code></td><td>Mode exit</td><td><code>0x0009</code><code>F9h</code></td></tr><tr><td style="text-align:right"><code>3</code></td><td>控制快捷写</td><td><code>control_shadow &lt;= 8&#39;h10</code>,随后写 <code>CONTROL</code></td></tr><tr><td style="text-align:right"><code>4</code></td><td>控制快捷写</td><td><code>control_shadow &lt;= 8&#39;h08</code>,随后写 <code>CONTROL</code></td></tr></tbody></table></div>
<p>若多个 bit 同时为 1,优先级从 bit0 到 bit4。</p>
<h3 id="6-6-通道参数写"><a class="anchor" href="#6-6-通道参数写" aria-label="章节链接">#</a>6.6 通道参数写</h3>
<p>通道地址由函数 <code>ch_addr</code> 计算:</p>
<pre><code class="language-verilog">ch_addr = CSI_CH_BASE + (ch * CSI_CH_STRIDE) + offset;</code></pre>
<p>默认:</p>
<pre><code class="language-text">CSI_CH_BASE = 0x0010
CSI_CH_STRIDE = 0x0010</code></pre>
<p>所以:</p>
<pre><code class="language-text">ASIC channel register address = 0x0010 + ch_index * 0x0010 + ch_offset</code></pre>
<p>示例:</p>
<pre><code class="language-text">CH_INDEX = 3
写 CH_CUR_A = 0x7F
offset = 0x1
ASIC addr = 0x0010 + 3 * 0x0010 + 0x1 = 0x0041
SPI frame = 0x02_0041_7F</code></pre>
<p>当前所有通道参数写都只发送 <code>bram_din[7:0]</code></p>
<h3 id="6-7-direct-spi-访问"><a class="anchor" href="#6-7-direct-spi-访问" aria-label="章节链接">#</a>6.7 Direct SPI 访问</h3>
<p>Direct SPI 用于软件直接访问任意 ASIC 寄存器。</p>
<p>操作流程:</p>
<p>1. 写 <code>SPI_ADDR</code>,设置 ASIC 地址。 2. 若是写操作,写 <code>SPI_WDATA</code>。 3. 写 <code>SPI_CTRL</code> 启动 SPI</p>
<pre><code class="language-text">SPI_CTRL[0] = direct_write, 1 为写,0 为读
SPI_CTRL[15:8] = direct_len,单位 byte0 会被转换为 1</code></pre>
<p><code>direct_len</code> 在 SPI master 内部被限制到 <code>1..MAX_BURST_BYTES</code></p>
<p>读操作完成后:</p>
<ul><li><code>last_rdata &lt;= spi_cmd_rdata[31:0]</code></li><li>软件读 <code>SPI_RDATA</code> 获取数据</li><li>软件读 <code>LAST_ADDR</code> 获取最近访问地址</li></ul>
<p>testbench 中直接读 Part ID</p>
<pre><code class="language-text">SPI_ADDR = 0x011D
SPI_CTRL = 0x00000100 // write=0, len=1
期望帧 = 0x03_011D_00
读回 = 0x28</code></pre>
<h2 id="7-spi-master-设计"><a class="anchor" href="#7-spi-master-设计" aria-label="章节链接">#</a>7. SPI Master 设计</h2>
<p><code>csi040_spi_master</code> 接收抽象命令,并转换成 SPI bit 流。</p>
<h3 id="7-1-命令接口"><a class="anchor" href="#7-1-命令接口" aria-label="章节链接">#</a>7.1 命令接口</h3>
<div class="table-wrap"><table><thead><tr><th>信号</th><th>方向</th><th>说明</th></tr></thead><tbody><tr><td><code>cmd_ready</code></td><td>output</td><td>SPI master 空闲时为 1。</td></tr><tr><td><code>cmd_valid</code></td><td>input</td><td>命令有效。空闲时采样。</td></tr><tr><td><code>cmd_write</code></td><td>input</td><td>1 为写,0 为读。</td></tr><tr><td><code>cmd_addr</code></td><td>input</td><td>ASIC 寄存器地址。</td></tr><tr><td><code>cmd_wdata</code></td><td>input</td><td>写 payload。低字节先作为 payload byte0。</td></tr><tr><td><code>cmd_len</code></td><td>input</td><td>payload 字节数。0 转 1,超过最大值则截断。</td></tr><tr><td><code>done</code></td><td>output reg</td><td>SPI 帧完成脉冲,持续 1 个 <code>clk</code></td></tr><tr><td><code>cmd_rdata</code></td><td>output reg</td><td>读回 payload。</td></tr><tr><td><code>busy</code></td><td>output reg</td><td>SPI master 忙。</td></tr></tbody></table></div>
<h3 id="7-2-spi-帧格式"><a class="anchor" href="#7-2-spi-帧格式" aria-label="章节链接">#</a>7.2 SPI 帧格式</h3>
<p>默认 <code>ADDR_BYTES = 2</code>,帧格式为:</p>
<pre><code class="language-text">byte0 opcode
byte1 address high byte
byte2 address low byte
byte3+ payload bytes</code></pre>
<p>1 字节写示例:</p>
<pre><code class="language-text">opcode = 0x02
addr = 0x0002
data = 0x10
frame = 0x02_0002_10</code></pre>
<p>地址字节按 MSB first 输出。payload 来自:</p>
<pre><code class="language-verilog">cmd_wdata[8*n +: 8]</code></pre>
<p><code>cmd_wdata[7:0]</code> 是第一个 payload byte。</p>
<h3 id="7-3-spi-状态机"><a class="anchor" href="#7-3-spi-状态机" aria-label="章节链接">#</a>7.3 SPI 状态机</h3>
<div class="table-wrap"><table><thead><tr><th>状态</th><th>行为</th></tr></thead><tbody><tr><td><code>IDLE_ST</code></td><td><code>cmd_ready=1</code><code>csn=1</code><code>sck=0</code>。若 <code>cmd_valid=1</code>,锁存 frame 并进入传输。</td></tr><tr><td><code>TRANS_ST</code></td><td><code>CLK_DIV</code><code>clk</code> 翻转一次 <code>sck</code>;上升沿采样读数据;下降沿准备下一位输出。</td></tr><tr><td><code>DONE_ST</code></td><td><code>csn</code> 拉高,<code>done</code> 脉冲 1 拍,<code>busy</code> 拉低,返回 idle。</td></tr></tbody></table></div>
<p>SPI 时钟频率:</p>
<pre><code class="language-text">f_sck = f_clk / (2 * CLK_DIV)</code></pre>
<p>testbench 中:</p>
<pre><code class="language-text">f_clk = 100 MHz
CLK_DIV = 2
f_sck = 25 MHz</code></pre>
<p>该值用于加速仿真。实际硬件中应根据 CSI040 SPI 时序要求重新设置 <code>SPI_CLK_DIV</code></p>
<h3 id="7-4-读数据采样"><a class="anchor" href="#7-4-读数据采样" aria-label="章节链接">#</a>7.4 读数据采样</h3>
<p>SPI master 在 header 发送完之后开始采样 <code>so</code></p>
<pre><code class="language-text">HEADER_BITS = 8 * (1 + ADDR_BYTES)</code></pre>
<p>默认地址 2 字节时,header 为 24 bit。读数据从第 25 个 bit 开始采样,采样结果移入 <code>rx_shift</code>,帧结束时赋给 <code>cmd_rdata</code></p>
<h2 id="8-复位行为"><a class="anchor" href="#8-复位行为" aria-label="章节链接">#</a>8. 复位行为</h2>
<p><code>rst_n = 0</code> 时,<code>csi040_ctrl</code> 主要寄存器复位如下:</p>
<div class="table-wrap"><table><thead><tr><th>寄存器</th><th style="text-align:right">复位值</th></tr></thead><tbody><tr><td><code>direct_addr</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>direct_wdata</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>direct_len</code></td><td style="text-align:right"><code>1</code></td></tr><tr><td><code>direct_write</code></td><td style="text-align:right"><code>1</code></td></tr><tr><td><code>control_shadow</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>ch_enable_shadow</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>ch_index</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>ch_data</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>ch_offset</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>seq_id</code></td><td style="text-align:right"><code>SEQ_IDLE</code></td></tr><tr><td><code>seq_step</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>seq_active</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>error_busy</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>done_latched</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>last_rdata</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>last_addr</code></td><td style="text-align:right"><code>0</code></td></tr><tr><td><code>asic_rst_n</code></td><td style="text-align:right"><code>1</code></td></tr><tr><td><code>asic_trig</code></td><td style="text-align:right"><code>0</code></td></tr></tbody></table></div>
<p><code>csi040_spi_master</code> 复位后:</p>
<pre><code class="language-text">csn = 1
sck = 0
si = 0
done = 0
busy = 0
state = IDLE_ST</code></pre>
<h2 id="9-当前-testbench-覆盖"><a class="anchor" href="#9-当前-testbench-覆盖" aria-label="章节链接">#</a>9. 当前 Testbench 覆盖</h2>
<p><code>csi040_ctrl_tb</code> 实例化 DUT 时重载:</p>
<pre><code class="language-verilog">.SPI_CLK_DIV ( 2 ),
.SPI_OPCODE_WRITE ( 8&#39;h02 ),
.SPI_OPCODE_READ ( 8&#39;h03 )</code></pre>
<p>testbench 使用 100 MHz clock,复位 8 个周期后开始测试。</p>
<p>覆盖场景:</p>
<div class="table-wrap"><table><thead><tr><th>测试项</th><th>BRAM 操作</th><th>期望 SPI 帧</th></tr></thead><tbody><tr><td>控制寄存器写</td><td><code>write_bram(0x0020, 0x10)</code></td><td><code>0x02000210</code></td></tr><tr><td>通道使能低字节</td><td><code>write_bram(0x0024, 0xA55A)</code></td><td><code>0x0200075A</code></td></tr><tr><td>通道使能高字节</td><td>同上</td><td><code>0x020008A5</code></td></tr><tr><td>通道 3 Current A</td><td><code>CH_INDEX=3</code><code>CH_CUR_A=0x7F</code></td><td><code>0x0200417F</code></td></tr><tr><td>DCS unlock step0</td><td><code>SEQ_CMD=1</code></td><td><code>0x02000955</code></td></tr><tr><td>DCS unlock step1</td><td>同上</td><td><code>0x020009B3</code></td></tr><tr><td>DCS unlock step2</td><td>同上</td><td><code>0x0200090A</code></td></tr><tr><td>Direct read Part ID</td><td><code>SPI_ADDR=0x011D</code><code>SPI_CTRL=0x0100</code></td><td><code>0x03011D00</code></td></tr><tr><td>读回检查</td><td>ASIC 模型返回 <code>0x28</code></td><td><code>SPI_RDATA[7:0] == 0x28</code></td></tr></tbody></table></div>
<p>testbench 中 SPI monitor 的行为:</p>
<ul><li><code>negedge asic_csn</code> 清空 bit 计数和 shift 寄存器;</li><li><code>posedge asic_sck</code> 采样 <code>asic_si</code></li><li><code>posedge asic_csn</code> 锁存完整帧;</li><li>在读数据阶段从 <code>asic_so</code> 返回 <code>read_response = 8&#39;h28</code></li></ul>
<h2 id="10-仿真与波形"><a class="anchor" href="#10-仿真与波形" aria-label="章节链接">#</a>10. 仿真与波形</h2>
<p>已验证的命令:</p>
<pre><code class="language-powershell">&amp; &#39;C:\Xilinx\Vivado\2023.1\bin\xvlog.bat&#39; `
c64_pro.srcs/sources_1/rtl/csi040/csi040_spi_master.v `
c64_pro.srcs/sources_1/rtl/csi040/csi040_ctrl.v `
c64_pro.srcs/sources_1/rtl/csi040/csi040_ctrl_tb.v
&amp; &#39;C:\Xilinx\Vivado\2023.1\bin\xelab.bat&#39; csi040_ctrl_tb -debug typical -snapshot csi040_ctrl_tb_sim_dbg
&amp; &#39;C:\Xilinx\Vivado\2023.1\bin\xsim.bat&#39; csi040_ctrl_tb_sim_dbg -runall</code></pre>
<p>当前仿真结果:</p>
<pre><code class="language-text">$finish called at time : 10940 ns</code></pre>
<p>未触发 testbench 中的 <code>ERROR ... $stop</code></p>
<p>打开 GUI</p>
<pre><code class="language-powershell">&amp; &#39;C:\Xilinx\Vivado\2023.1\bin\xsim.bat&#39; csi040_ctrl_tb_sim_dbg -gui</code></pre>
<p>GUI 中可用:</p>
<pre><code class="language-tcl">log_wave -r /csi040_ctrl_tb/*
run all</code></pre>
<p>建议观察信号:</p>
<pre><code class="language-text">/csi040_ctrl_tb/bram_addr
/csi040_ctrl_tb/bram_din
/csi040_ctrl_tb/bram_dout
/csi040_ctrl_tb/bram_en
/csi040_ctrl_tb/bram_we
/csi040_ctrl_tb/busy
/csi040_ctrl_tb/spi_done
/csi040_ctrl_tb/error_busy
/csi040_ctrl_tb/asic_csn
/csi040_ctrl_tb/asic_sck
/csi040_ctrl_tb/asic_si
/csi040_ctrl_tb/asic_so
/csi040_ctrl_tb/frame_in
/csi040_ctrl_tb/frame_bits
/csi040_ctrl_tb/dut/seq_id
/csi040_ctrl_tb/dut/seq_step
/csi040_ctrl_tb/dut/seq_active
/csi040_ctrl_tb/dut/spi_cmd_valid
/csi040_ctrl_tb/dut/spi_cmd_ready
/csi040_ctrl_tb/dut/spi_cmd_addr
/csi040_ctrl_tb/dut/spi_cmd_wdata
/csi040_ctrl_tb/dut/spi_cmd_len
/csi040_ctrl_tb/dut/u_csi040_spi_master/cstate
/csi040_ctrl_tb/dut/u_csi040_spi_master/tx_shift
/csi040_ctrl_tb/dut/u_csi040_spi_master/rx_shift
/csi040_ctrl_tb/dut/u_csi040_spi_master/sampled_bits</code></pre>
<h2 id="11-软件使用建议"><a class="anchor" href="#11-软件使用建议" aria-label="章节链接">#</a>11. 软件使用建议</h2>
<p>典型写配置流程:</p>
<pre><code class="language-text">1. 轮询 STATUS[5] == 0
2. 写目标 BRAM 命令寄存器
3. 轮询 STATUS[7] == 1
4. 如是读命令,读取 SPI_RDATA
5. 写 STATUS[0] = 1 清除 done_latched
6. 如 STATUS[8] = 1,记录错误并写 STATUS[1] = 1 清除 error_busy</code></pre>
<p>注意事项:</p>
<ul><li>忙时不要写命令寄存器,否则命令会被丢弃,并置位 <code>error_busy</code></li><li><code>PIN_CTRL</code> 是直接引脚控制,不会自动生成 SPI。</li><li><code>TRIGGER</code> 是 SPI 写 ASIC trigger register,不等同于 <code>asic_trig</code> 引脚。</li><li><code>SPI_CTRL[15:8]</code> 为直接 SPI payload 长度,最大有效值受 <code>MAX_BURST_BYTES</code> 限制。</li><li>当前 BRAM 接口只支持全字写。</li></ul>
<h2 id="12-后续可改进点"><a class="anchor" href="#12-后续可改进点" aria-label="章节链接">#</a>12. 后续可改进点</h2>
<ul><li>明确 <code>bram_clk/bram_rst</code> 的设计意图:要么真正使用它们,要么在接口说明中标记为 unused。</li><li>增加 byte enable 写支持,方便接 AXI BRAM Controller。</li><li><code>STATUS</code> 位定义软件头文件常量,避免软件侧硬编码 bit 位置。</li><li>扩展 testbench</li><li>忙时写命令,检查 <code>error_busy</code></li><li><code>PIN_CTRL</code> 读写;</li><li><code>TRIGGER</code> SPI 序列;</li><li>Test unlock 和 mode exit</li><li>Direct SPI 多字节 burst</li><li><code>cmd_len=0</code>、超过 <code>MAX_BURST_BYTES</code> 的边界行为;</li><li>SPI read 多字节返回数据。</li><li>增加 SystemVerilog assertion,用来约束命令重入、SPI 帧长度和 <code>csn/sck</code> 时序。</li></ul>
</article>
</main>
</div>
<a class="top-link" href="#top">返回顶部</a>
</body>
</html>