增加寄存器定义
This commit is contained in:
parent
5ea3213682
commit
3c2b27fa88
|
|
@ -85,6 +85,7 @@ python doc_builder/build.py
|
||||||
| §5.5 | `chapters/05-05-exc-upconversion.md` | EXC 上变频电路配置 |
|
| §5.5 | `chapters/05-05-exc-upconversion.md` | EXC 上变频电路配置 |
|
||||||
| §5.6 | `chapters/05-06-pump-config.md` | Pump 模拟电路配置 |
|
| §5.6 | `chapters/05-06-pump-config.md` | Pump 模拟电路配置 |
|
||||||
| §5.7 | `chapters/05-07-exc-pipeline-demo.md` | EXC-Pump 全流程控制示例 |
|
| §5.7 | `chapters/05-07-exc-pipeline-demo.md` | EXC-Pump 全流程控制示例 |
|
||||||
|
| 附录A | `chapters/80-appendix-ids-table.md` | IDS 寄存器索引表(DAQ_REG / AWG_REG / 地址映射) |
|
||||||
|
|
||||||
## 编辑工作流
|
## 编辑工作流
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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配置数据和通道模拟电路配置进行介绍,
|
本文档通过对不同编程模型下码字指令、通道寄存器配置数据、通道SRAM配置数据和通道模拟电路配置进行介绍,
|
||||||
旨在让用户掌握对读出激励信号的产生和采集信号处理的编程方法。
|
旨在让用户掌握对读出激励信号的产生和采集信号处理的编程方法。
|
||||||
|
|
@ -61,7 +61,7 @@ ez-Q 2.5 ASIC平台读出子系统由读出基带板、读出混频板和读出
|
||||||
通过扩展地址指定同一个板卡内的多个通道、通过地址指定一个通道内的不同配置项。
|
通过扩展地址指定同一个板卡内的多个通道、通过地址指定一个通道内的不同配置项。
|
||||||
|
|
||||||
```
|
```
|
||||||
索引基地址由《读出子系统IDS表.xls》的mapping页定义,本文不对地址翻译进行赘述。
|
索引基地址定义详见[附录A. IDS寄存器索引表](#a-ids)的 [A.1 地址空间映射](#a1) 节。
|
||||||
```
|
```
|
||||||
|
|
||||||
本文所述的三类编程通道具体定义如下:
|
本文所述的三类编程通道具体定义如下:
|
||||||
|
|
|
||||||
|
|
@ -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` = 只写(写清除)
|
||||||
|
|
@ -72,11 +72,15 @@ def load_plugin_modules(directory):
|
||||||
if spec is None or spec.loader is None:
|
if spec is None or spec.loader is None:
|
||||||
continue
|
continue
|
||||||
mod = importlib.util.module_from_spec(spec)
|
mod = importlib.util.module_from_spec(spec)
|
||||||
|
# 注册到 sys.modules 以支持插件间交叉导入
|
||||||
|
sys.modules[py_file.stem] = mod
|
||||||
spec.loader.exec_module(mod)
|
spec.loader.exec_module(mod)
|
||||||
modules[py_file.stem] = mod
|
modules[py_file.stem] = mod
|
||||||
print(f" 已加载: {py_file.stem}")
|
print(f" 已加载: {py_file.stem}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" 警告: 加载 {py_file.name} 失败: {e}")
|
print(f" 警告: 加载 {py_file.name} 失败: {e}")
|
||||||
|
# 加载失败时清理 sys.modules
|
||||||
|
sys.modules.pop(py_file.stem, None)
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -424,15 +428,19 @@ def postprocess_table_rowspan(html):
|
||||||
- 同一行左右连续相同 → colspan
|
- 同一行左右连续相同 → colspan
|
||||||
与 preprocess_mpe_tables 配合:MPE 标记展平后产生重复内容,此处恢复为视觉合并。
|
与 preprocess_mpe_tables 配合:MPE 标记展平后产生重复内容,此处恢复为视觉合并。
|
||||||
|
|
||||||
|
带有 class="no-rowspan" 的 <table> 会被跳过,不进行合并处理。
|
||||||
注意:仅处理 <tbody> 内的 <tr>(Python markdown tables 扩展的输出格式)。
|
注意:仅处理 <tbody> 内的 <tr>(Python markdown tables 扩展的输出格式)。
|
||||||
"""
|
"""
|
||||||
|
# 匹配整个 <table> 元素,检查其 class 属性
|
||||||
|
TABLE_RE = re.compile(r'(<table[^>]*>)(.*?)(</table>)', re.DOTALL)
|
||||||
|
|
||||||
def merge_tbody(match):
|
def merge_tbody(match):
|
||||||
tbody = match.group(1)
|
tbody = match.group(1)
|
||||||
rows = TR_RE.findall(tbody)
|
rows = TR_RE.findall(tbody)
|
||||||
if len(rows) < 2:
|
if len(rows) < 2:
|
||||||
return tbody
|
return tbody
|
||||||
|
|
||||||
# 解析所有单元格
|
# 解析所有单元格(统一补齐到最大列数,处理 rowspan 导致的列数不一致)
|
||||||
row_cells = []
|
row_cells = []
|
||||||
for row_html in rows:
|
for row_html in rows:
|
||||||
cells = []
|
cells = []
|
||||||
|
|
@ -448,6 +456,11 @@ def postprocess_table_rowspan(html):
|
||||||
if num_cols == 0:
|
if num_cols == 0:
|
||||||
return tbody
|
return tbody
|
||||||
|
|
||||||
|
# 统一补齐:不足 num_cols 的行用空单元格补齐
|
||||||
|
for row in row_cells:
|
||||||
|
while len(row) < num_cols:
|
||||||
|
row.append({"attrs": "", "text": ""})
|
||||||
|
|
||||||
# covered[r][c]:该单元格已被 rowspan 或 colspan 覆盖,渲染时跳过
|
# covered[r][c]:该单元格已被 rowspan 或 colspan 覆盖,渲染时跳过
|
||||||
covered = [[False] * num_cols for _ in range(num_rows)]
|
covered = [[False] * num_cols for _ in range(num_rows)]
|
||||||
rowspan = [[1] * 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):
|
for col in range(num_cols):
|
||||||
row = 0
|
row = 0
|
||||||
while row < num_rows:
|
while row < num_rows:
|
||||||
if col >= len(row_cells[row]):
|
|
||||||
row += 1
|
|
||||||
continue
|
|
||||||
count = 1
|
count = 1
|
||||||
r = row + 1
|
r = row + 1
|
||||||
while r < num_rows:
|
while r < num_rows:
|
||||||
if (col < len(row_cells[r])
|
if (row_cells[r][col]["text"] == row_cells[row][col]["text"]
|
||||||
and row_cells[r][col]["text"] == row_cells[row][col]["text"]
|
|
||||||
and row_cells[row][col]["text"] != ""):
|
and row_cells[row][col]["text"] != ""):
|
||||||
count += 1
|
count += 1
|
||||||
covered[r][col] = True
|
covered[r][col] = True
|
||||||
|
|
@ -473,18 +482,18 @@ def postprocess_table_rowspan(html):
|
||||||
break
|
break
|
||||||
if count > 1:
|
if count > 1:
|
||||||
rowspan[row][col] = count
|
rowspan[row][col] = count
|
||||||
row = r # 跳过已被当前 rowspan 覆盖的行
|
row = r
|
||||||
|
|
||||||
# ---- 计算 colspan(逐行扫描,跳过已覆盖单元格) ----
|
# ---- 计算 colspan(逐行扫描,跳过已覆盖单元格) ----
|
||||||
for row in range(num_rows):
|
for row in range(num_rows):
|
||||||
col = 0
|
col = 0
|
||||||
while col < len(row_cells[row]):
|
while col < num_cols:
|
||||||
if covered[row][col]:
|
if covered[row][col]:
|
||||||
col += 1
|
col += 1
|
||||||
continue
|
continue
|
||||||
count = 1
|
count = 1
|
||||||
c = col + 1
|
c = col + 1
|
||||||
while c < num_cols and c < len(row_cells[row]):
|
while c < num_cols:
|
||||||
if (not covered[row][c]
|
if (not covered[row][c]
|
||||||
and row_cells[row][c]["text"] == row_cells[row][col]["text"]
|
and row_cells[row][c]["text"] == row_cells[row][col]["text"]
|
||||||
and row_cells[row][col]["text"] != ""):
|
and row_cells[row][col]["text"] != ""):
|
||||||
|
|
@ -495,14 +504,14 @@ def postprocess_table_rowspan(html):
|
||||||
break
|
break
|
||||||
if count > 1:
|
if count > 1:
|
||||||
colspan[row][col] = count
|
colspan[row][col] = count
|
||||||
col = c # 跳过已被当前 colspan 覆盖的列
|
col = c
|
||||||
|
|
||||||
# ---- 生成带 rowspan / colspan 的 HTML ----
|
# ---- 生成带 rowspan / colspan 的 HTML ----
|
||||||
new_rows = []
|
new_rows = []
|
||||||
for row in range(num_rows):
|
for row in range(num_rows):
|
||||||
new_cells = []
|
new_cells = []
|
||||||
for col in range(num_cols):
|
for col in range(num_cols):
|
||||||
if covered[row][col] or col >= len(row_cells[row]):
|
if covered[row][col]:
|
||||||
continue
|
continue
|
||||||
cell = row_cells[row][col]
|
cell = row_cells[row][col]
|
||||||
rs = rowspan[row][col]
|
rs = rowspan[row][col]
|
||||||
|
|
@ -512,12 +521,27 @@ def postprocess_table_rowspan(html):
|
||||||
attrs += f' rowspan="{rs}"'
|
attrs += f' rowspan="{rs}"'
|
||||||
if cs > 1:
|
if cs > 1:
|
||||||
attrs += f' colspan="{cs}"'
|
attrs += f' colspan="{cs}"'
|
||||||
|
# 修复: attrs 非空时加前导空格,避免 <tdrowspan="..."> 畸形标签
|
||||||
|
if attrs:
|
||||||
new_cells.append(f'<td {attrs}>{cell["text"]}</td>')
|
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>")
|
new_rows.append("<tr>" + "".join(new_cells) + "</tr>")
|
||||||
|
|
||||||
return "<tbody>" + "".join(new_rows) + "</tbody>"
|
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 ----------
|
# ---------- Markdown → HTML ----------
|
||||||
|
|
@ -597,21 +621,28 @@ def slugify(text):
|
||||||
|
|
||||||
|
|
||||||
def generate_toc(html):
|
def generate_toc(html):
|
||||||
"""从 HTML 中提取 H1-H4 标题,生成目录。"""
|
"""从 HTML 中提取 H1-H4 标题,生成目录。
|
||||||
|
锚点直接从标题已有的 id 属性读取,确保与 HTML 中的实际 ID 一致。"""
|
||||||
toc = []
|
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))
|
level = int(m.group(1))
|
||||||
text = re.sub(r'<.*?>', '', m.group(2)).strip()
|
anchor = m.group(2)
|
||||||
toc.append({"level": level, "text": text, "anchor": slugify(text)})
|
text = re.sub(r'<.*?>', '', m.group(3)).strip()
|
||||||
|
toc.append({"level": level, "text": text, "anchor": anchor})
|
||||||
return toc
|
return toc
|
||||||
|
|
||||||
|
|
||||||
def inject_anchors(html):
|
def inject_anchors(html):
|
||||||
"""为所有 H1-H4 标签注入 id 属性,使侧边栏目录可跳转。"""
|
"""为所有 H1-H4 标签注入 id 属性,使侧边栏目录可跳转。
|
||||||
|
如果标题已有 id 属性(如自定义渲染器预设的锚点),则保留原 id。"""
|
||||||
def repl(match):
|
def repl(match):
|
||||||
level = match.group(1)
|
level = match.group(1)
|
||||||
attrs = match.group(2)
|
attrs = match.group(2)
|
||||||
inner = match.group(3)
|
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())
|
anchor = slugify(re.sub(r'<.*?>', '', inner).strip())
|
||||||
return f'<h{level} id="{anchor}"{attrs}>{inner}</h{level}>'
|
return f'<h{level} id="{anchor}"{attrs}>{inner}</h{level}>'
|
||||||
return re.sub(
|
return re.sub(
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -26,3 +26,4 @@ chapters:
|
||||||
- 05-05-exc-upconversion.md
|
- 05-05-exc-upconversion.md
|
||||||
- 05-06-pump-config.md
|
- 05-06-pump-config.md
|
||||||
- 05-07-exc-pipeline-demo.md
|
- 05-07-exc-pipeline-demo.md
|
||||||
|
- 80-appendix-ids-table.md
|
||||||
Loading…
Reference in New Issue