增加寄存器定义

This commit is contained in:
guocheng 2026-07-28 12:34:12 +08:00
parent 5ea3213682
commit 3c2b27fa88
9 changed files with 147 additions and 21 deletions

View File

@ -85,6 +85,7 @@ python doc_builder/build.py
| §5.5 | `chapters/05-05-exc-upconversion.md` | EXC 上变频电路配置 |
| §5.6 | `chapters/05-06-pump-config.md` | Pump 模拟电路配置 |
| §5.7 | `chapters/05-07-exc-pipeline-demo.md` | EXC-Pump 全流程控制示例 |
| 附录A | `chapters/80-appendix-ids-table.md` | IDS 寄存器索引表DAQ_REG / AWG_REG / 地址映射) |
## 编辑工作流

View File

@ -26,7 +26,7 @@ ez-Q 2.5测控系统包含5种物理通道对应5类硬件接口分别是A
- 测控系统的寄存器、配置数据和模拟电路配置返回数据统一采用**大端字节序**。
通道寄存器配置数据支持微控制器实时修改,从而让通道的输入/输出控制具备动态控制能力。
ACQ和EXC-Pump通道配置寄存器定义参考[读出子系统IDS表.xls](TODO)的`DAQ_REG`和`AWG_REG`页
ACQ和EXC-Pump通道配置寄存器的地址索引定义详见[附录A. IDS寄存器索引表](#a-ids)的 [A.2 DAQ_REG](#a2-daq_reg-acq) 和 [A.3 AWG_REG](#a3-awg_reg-exc-pump) 节
本文档通过对不同编程模型下码字指令、通道寄存器配置数据、通道SRAM配置数据和通道模拟电路配置进行介绍
旨在让用户掌握对读出激励信号的产生和采集信号处理的编程方法。
@ -61,7 +61,7 @@ ez-Q 2.5 ASIC平台读出子系统由读出基带板、读出混频板和读出
通过扩展地址指定同一个板卡内的多个通道、通过地址指定一个通道内的不同配置项。
```
索引基地址由《读出子系统IDS表.xls》的mapping页定义本文不对地址翻译进行赘述
索引基地址定义详见[附录A. IDS寄存器索引表](#a-ids)的 [A.1 地址空间映射](#a1) 节
```
本文所述的三类编程通道具体定义如下:

View File

@ -0,0 +1,61 @@
# 附录A. IDS寄存器索引表
本附录提供读出子系统通道配置寄存器的地址索引IDS, Index Data Sheet
供软件编程时通过基地址 + 偏移地址访问具体寄存器。
以下所有表格数据来源于 IDS JSON 数据文件对应2509批次读出芯片
由构建时自动渲染生成,确保与硬件设计数据库保持同步。
## A.1. 地址空间映射
读出子系统的配置访问采用四级寻址层级,从网络到寄存器的完整链路如下:
1. **网络地址IP** — 定位机箱。软件通过指定目标机箱的 IP 地址来确定与哪个机箱内的板卡通信。一个机箱内可安装多块 PXIe 板卡IP 地址是整个通信链路的起点。
2. **扩展地址Exaddr** — 定位槽位和总线。[7:3]对应槽位号exaddr[2:0]对应总线号。读出基带板允许安装在4或者15槽泵浦板和混频板分别在左右相邻位置因此软件仅需指定基带板槽位号即可定位全部三个板卡。
3. **片选地址Cid** — 定位总线上芯片ID。采用5比特编码最大支持32颗芯片挂载到同一个spi总线上在当前的实现中直接使用总线编址通道号每个芯片独占一个总线因此Cid固定为0。
4. **配置基地址Base** — 定位具体配置项。采用25比特编码其中高5比特用来定位不同模块配合20比特的偏移地址用来具体指定配置项目。
芯片控制存在MCU视角和配置视角区别是基地址不同。从MCU操控视角来看AWG和DAQ模块寄存器统一映射在对应 MCU 的 **`0x200000`** 地址空间。从上位机配置视角看,基地址和偏移地址定义如下表所示:
### A.1.1. ACQ 通道模块基地址
对应 `msmt_acq` 通道类型(采集通道),共 4 个通道ch0~ch3
每个通道包含 5 个功能模块:
@import "../../rbpu_datasheet/data/ids.json" using render_ids_acq_map
### A.1.2. EXC 通道模块基地址
对应 `msmt_exc` 通道类型(激励通道),共 4 个通道ch0~ch3
每个通道包含 5 个功能模块:
@import "../../rbpu_datasheet/data/ids.json" using render_ids_exc_map
## A.2. DAQ_REG — ACQ 寄存器
ACQ 通道配置寄存器,对应采集通道的 DAQ 模块。寄存器基地址参见
[A.1.1 节](#a11-acq) 中 `DAQ_REG` 行。
各寄存器通过偏移地址在模块内部索引,如下表所示。
@import "../../rbpu_datasheet/data/ids.json" using render_ids_daq_reg
## A.3. AWG_REG — EXC-Pump 寄存器
EXC-Pump 通道配置寄存器,对应激励通道的 AWG 模块。寄存器基地址参见
[A.1.2 节](#a12-exc) 中 `AWG_REG` 行。
各寄存器通过偏移地址在模块内部索引,如下表所示。
@import "../../rbpu_datasheet/data/ids.json" using render_ids_awg_reg
## A.4. 寄存器访问说明
- 所有寄存器支持 **SPI****MCU** 双端口访问
- 静态参数建议通过 SPI 配置后保持不变,动态参数通过 MCU 实时更新
- 寄存器位宽均为 **32 位**(不足 32 位的高位保留)
- 返回数据统一采用 **大端字节序**
- MCU 以固定 **3 个时钟周期/指令** 的速率执行
- 权限缩写:`RW` = 读写,`RO` = 只读,`WC` = 只写(写清除)

View File

@ -72,11 +72,15 @@ def load_plugin_modules(directory):
if spec is None or spec.loader is None:
continue
mod = importlib.util.module_from_spec(spec)
# 注册到 sys.modules 以支持插件间交叉导入
sys.modules[py_file.stem] = mod
spec.loader.exec_module(mod)
modules[py_file.stem] = mod
print(f" 已加载: {py_file.stem}")
except Exception as e:
print(f" 警告: 加载 {py_file.name} 失败: {e}")
# 加载失败时清理 sys.modules
sys.modules.pop(py_file.stem, None)
return modules
@ -424,15 +428,19 @@ def postprocess_table_rowspan(html):
- 同一行左右连续相同 colspan
preprocess_mpe_tables 配合MPE 标记展平后产生重复内容此处恢复为视觉合并
带有 class="no-rowspan" <table> 会被跳过不进行合并处理
注意仅处理 <tbody> 内的 <tr>Python markdown tables 扩展的输出格式
"""
# 匹配整个 <table> 元素,检查其 class 属性
TABLE_RE = re.compile(r'(<table[^>]*>)(.*?)(</table>)', re.DOTALL)
def merge_tbody(match):
tbody = match.group(1)
rows = TR_RE.findall(tbody)
if len(rows) < 2:
return tbody
# 解析所有单元格
# 解析所有单元格(统一补齐到最大列数,处理 rowspan 导致的列数不一致)
row_cells = []
for row_html in rows:
cells = []
@ -448,6 +456,11 @@ def postprocess_table_rowspan(html):
if num_cols == 0:
return tbody
# 统一补齐:不足 num_cols 的行用空单元格补齐
for row in row_cells:
while len(row) < num_cols:
row.append({"attrs": "", "text": ""})
# covered[r][c]:该单元格已被 rowspan 或 colspan 覆盖,渲染时跳过
covered = [[False] * num_cols for _ in range(num_rows)]
rowspan = [[1] * num_cols for _ in range(num_rows)]
@ -457,14 +470,10 @@ def postprocess_table_rowspan(html):
for col in range(num_cols):
row = 0
while row < num_rows:
if col >= len(row_cells[row]):
row += 1
continue
count = 1
r = row + 1
while r < num_rows:
if (col < len(row_cells[r])
and row_cells[r][col]["text"] == row_cells[row][col]["text"]
if (row_cells[r][col]["text"] == row_cells[row][col]["text"]
and row_cells[row][col]["text"] != ""):
count += 1
covered[r][col] = True
@ -473,18 +482,18 @@ def postprocess_table_rowspan(html):
break
if count > 1:
rowspan[row][col] = count
row = r # 跳过已被当前 rowspan 覆盖的行
row = r
# ---- 计算 colspan逐行扫描跳过已覆盖单元格 ----
for row in range(num_rows):
col = 0
while col < len(row_cells[row]):
while col < num_cols:
if covered[row][col]:
col += 1
continue
count = 1
c = col + 1
while c < num_cols and c < len(row_cells[row]):
while c < num_cols:
if (not covered[row][c]
and row_cells[row][c]["text"] == row_cells[row][col]["text"]
and row_cells[row][col]["text"] != ""):
@ -495,14 +504,14 @@ def postprocess_table_rowspan(html):
break
if count > 1:
colspan[row][col] = count
col = c # 跳过已被当前 colspan 覆盖的列
col = c
# ---- 生成带 rowspan / colspan 的 HTML ----
new_rows = []
for row in range(num_rows):
new_cells = []
for col in range(num_cols):
if covered[row][col] or col >= len(row_cells[row]):
if covered[row][col]:
continue
cell = row_cells[row][col]
rs = rowspan[row][col]
@ -512,12 +521,27 @@ def postprocess_table_rowspan(html):
attrs += f' rowspan="{rs}"'
if cs > 1:
attrs += f' colspan="{cs}"'
new_cells.append(f'<td{attrs}>{cell["text"]}</td>')
# 修复: attrs 非空时加前导空格,避免 <tdrowspan="..."> 畸形标签
if attrs:
new_cells.append(f'<td {attrs}>{cell["text"]}</td>')
else:
new_cells.append(f'<td>{cell["text"]}</td>')
new_rows.append("<tr>" + "".join(new_cells) + "</tr>")
return "<tbody>" + "".join(new_rows) + "</tbody>"
return TBODY_RE.sub(merge_tbody, html)
def process_table(match):
table_open = match.group(1)
body = match.group(2)
table_close = match.group(3)
# 跳过带有 no-rowspan class 的表格
if 'no-rowspan' in table_open:
return match.group(0)
# 处理表格内的 <tbody>
body = TBODY_RE.sub(merge_tbody, body)
return table_open + body + table_close
return TABLE_RE.sub(process_table, html)
# ---------- Markdown → HTML ----------
@ -597,21 +621,28 @@ def slugify(text):
def generate_toc(html):
"""从 HTML 中提取 H1-H4 标题,生成目录。"""
"""从 HTML 中提取 H1-H4 标题,生成目录。
锚点直接从标题已有的 id 属性读取确保与 HTML 中的实际 ID 一致"""
toc = []
for m in re.finditer(r'<h([1-4])[^>]*>(.*?)</h\1>', html, re.DOTALL):
# 匹配带 id 属性的标题标签
for m in re.finditer(r'<h([1-4])\s+[^>]*\bid="([^"]*)"[^>]*>(.*?)</h\1>', html, re.DOTALL):
level = int(m.group(1))
text = re.sub(r'<.*?>', '', m.group(2)).strip()
toc.append({"level": level, "text": text, "anchor": slugify(text)})
anchor = m.group(2)
text = re.sub(r'<.*?>', '', m.group(3)).strip()
toc.append({"level": level, "text": text, "anchor": anchor})
return toc
def inject_anchors(html):
"""为所有 H1-H4 标签注入 id 属性,使侧边栏目录可跳转。"""
"""为所有 H1-H4 标签注入 id 属性,使侧边栏目录可跳转。
如果标题已有 id 属性如自定义渲染器预设的锚点则保留原 id"""
def repl(match):
level = match.group(1)
attrs = match.group(2)
inner = match.group(3)
# 保留已有的 id 属性(例如渲染器手动设置的锚点)
if re.search(r'\bid\s*=', attrs):
return f'<h{level}{attrs}>{inner}</h{level}>'
anchor = slugify(re.sub(r'<.*?>', '', inner).strip())
return f'<h{level} id="{anchor}"{attrs}>{inner}</h{level}>'
return re.sub(

View File

@ -0,0 +1,8 @@
"""ACQ 通道模块基地址表渲染器。"""
from render_ids import _load_ids, render_mapping_acq_table
def render(filepath):
"""返回 ACQ 通道模块基地址 HTML 表格(不含标题和描述)。"""
data = _load_ids(filepath)
return render_mapping_acq_table(data)

View File

@ -0,0 +1,8 @@
"""AWG_REG 寄存器表渲染器。"""
from render_ids import _load_ids, render_awg_reg_table
def render(filepath):
"""返回 AWG_REG 寄存器汇总表 + 位域明细 HTML不含标题和描述"""
data = _load_ids(filepath)
return render_awg_reg_table(data)

View File

@ -0,0 +1,8 @@
"""DAQ_REG 寄存器表渲染器。"""
from render_ids import _load_ids, render_daq_reg_table
def render(filepath):
"""返回 DAQ_REG 寄存器汇总表 + 位域明细 HTML不含标题和描述"""
data = _load_ids(filepath)
return render_daq_reg_table(data)

View File

@ -0,0 +1,8 @@
"""EXC 通道模块基地址表渲染器。"""
from render_ids import _load_ids, render_mapping_exc_table
def render(filepath):
"""返回 EXC 通道模块基地址 HTML 表格(不含标题和描述)。"""
data = _load_ids(filepath)
return render_mapping_exc_table(data)

View File

@ -25,4 +25,5 @@ chapters:
- 05-04-exc-waveform-store.md
- 05-05-exc-upconversion.md
- 05-06-pump-config.md
- 05-07-exc-pipeline-demo.md
- 05-07-exc-pipeline-demo.md
- 80-appendix-ids-table.md