Compare commits
5 Commits
a5fab4edfb
...
8950ef7703
| Author | SHA1 | Date |
|---|---|---|
|
|
8950ef7703 | |
|
|
eccfd5ce43 | |
|
|
9a33df9c42 | |
|
|
f04a3dc263 | |
|
|
efa44b4496 |
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(ls -la \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\readout_test_record\")",
|
||||||
|
"Read(//d/repo/ezq3p0/design_doc/readout_test_record/**)",
|
||||||
|
"Bash(pip install *)",
|
||||||
|
"Bash(python -c ' *)",
|
||||||
|
"Bash(where python *)",
|
||||||
|
"Read(//c/Users/Administrator/AppData/Local/Programs/**)",
|
||||||
|
"Bash(ls /c/Python*/python.exe)",
|
||||||
|
"Bash(find /c -name \"python.exe\" -type f)",
|
||||||
|
"Bash(dir \"电流测试.xlsx\")",
|
||||||
|
"Bash(/c/Users/Administrator/anaconda3/python.exe -c ' *)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(ls -la \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\case-generator\")",
|
||||||
|
"Read(//d/repo/ezq3p0/design_doc/case-generator/**)",
|
||||||
|
"Bash(cp \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\case-generator\\\\figure\\\\dut.jpg\" \"d:\\\\repo\\\\ezq3p0\\\\manual_doc\\\\rbpu_datasheet\\\\assets\\\\dut.jpg\" && echo \"copied dut.jpg\")",
|
||||||
|
"Bash(cp \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\case-generator\\\\2509_Readout_ChipTest\\\\analog_func\\\\dac\\\\tc_dac_mixhb_auto\\\\base300-2300MHz.png\" \"d:\\\\repo\\\\ezq3p0\\\\manual_doc\\\\rbpu_datasheet\\\\assets\\\\dac_freq_sweep.png\" && echo \"copied\")",
|
||||||
|
"Bash(cp \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\case-generator\\\\2509_Readout_ChipTest\\\\analog_func\\\\adc\\\\tc_adc_full\\\\full.png\" \"d:\\\\repo\\\\ezq3p0\\\\manual_doc\\\\rbpu_datasheet\\\\assets\\\\adc_full.png\")",
|
||||||
|
"Bash(cp \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\case-generator\\\\2509_Readout_ChipTest\\\\analog_func\\\\adc\\\\tc_adc_0\\\\adc0.png\" \"d:\\\\repo\\\\ezq3p0\\\\manual_doc\\\\rbpu_datasheet\\\\assets\\\\adc_sample0.png\")",
|
||||||
|
"Bash(cp \"D:\\\\repo\\\\ezq3p0\\\\design_doc\\\\case-generator\\\\2509_Readout_ChipTest\\\\analog_func\\\\adc\\\\tc_adc_1\\\\adc1.png\" \"d:\\\\repo\\\\ezq3p0\\\\manual_doc\\\\rbpu_datasheet\\\\assets\\\\adc_sample1.png\")",
|
||||||
|
"Read(//d/repo/ezq3p0/manual_doc/**)",
|
||||||
|
"Read(//d/repo/ezq3p0/**)",
|
||||||
|
"WebSearch",
|
||||||
|
"WebFetch(domain:www.analog.com)",
|
||||||
|
"WebFetch(domain:www.sekorm.com)",
|
||||||
|
"Read(//d/share/publications/datasheets/03_芯片手册/04_DAC/ADI/**)",
|
||||||
|
"Read(//d/repo/**)",
|
||||||
|
"Bash(python -c ' *)",
|
||||||
|
"Bash(pip install *)",
|
||||||
|
"Bash(python -m pip install pymupdf)",
|
||||||
|
"Bash(where python *)",
|
||||||
|
"Bash(python -c \"import fitz; print\\('fitz ok'\\)\")"
|
||||||
|
],
|
||||||
|
"additionalDirectories": [
|
||||||
|
"D:\\repo\\ezq3p0\\design_doc\\case-generator\\figure",
|
||||||
|
"D:\\repo\\ezq3p0\\design_doc\\case-generator\\2509_Readout_ChipTest\\analog_func\\dac\\tc_dac_mixhb_auto"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
script/读出子系统IDS表.xls
|
script/读出子系统IDS表.xls
|
||||||
读出芯片用户使用手册.html
|
output/
|
||||||
pin_loc.xlsx
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
本项目是 **RBPU16 读出基带处理芯片** 的数据手册(datasheet/user manual)。RBPU16 是一款用于超导量子比特态信息读出的 SoC 芯片,最大支持 16 个量子比特并行读出,内部集成 PLL、ADC、DAC、DSP 等模块。
|
||||||
|
|
||||||
|
手册基于纯文本管理,通过 Python 脚本生成精美的 HTML 和 PDF 报告(参考 AD9164 数据手册风格)。
|
||||||
|
|
||||||
|
## 文件结构
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
|------|------|
|
||||||
|
| `chapters/*.md` | 手册章节源文件(Markdown,按章节拆分,纯文本 git 友好) |
|
||||||
|
| `chapters/appendix/*.md` | 附录(运维手册、配置用例) |
|
||||||
|
| `data/pin_name.csv` | 管脚定义表(编号、名称、类型、描述) |
|
||||||
|
| `data/pin_loc.csv` | 管脚物理位置网格表(行×列 → 信号名) |
|
||||||
|
| `data/seg_define.csv` | 寄存器地址段定义(功能模块→子模块→起始地址→大小) |
|
||||||
|
| `data/ids.json` | 寄存器详细定义 JSON(由 XLS 生成,供脚本读取) |
|
||||||
|
| `assets/` | 手册内嵌图片(框图、管脚图、协议图等 PNG/JPG 文件) |
|
||||||
|
| `templates/` | Jinja2 模板(base HTML + macros + CSS) |
|
||||||
|
| `templates/css/report.css` | 报告样式表(AD9164 风格,支持打印和屏幕) |
|
||||||
|
| `templates/macros/` | 可复用 Jinja2 宏(管脚表、寄存器表、地址映射表) |
|
||||||
|
| `build.py` | 主构建脚本(一键生成 HTML + PDF) |
|
||||||
|
| `requirements.txt` | Python 依赖(Jinja2, markdown, Pygments, WeasyPrint) |
|
||||||
|
| `output/` | 构建产物(gitignore) |
|
||||||
|
| `script/ids_import.ipynb` | Jupyter notebook:解析 `读出子系统IDS表.xls` 生成 `data/ids.json` |
|
||||||
|
| `script/读出子系统IDS表.xls` | 寄存器详细定义 Excel(多 sheet) |
|
||||||
|
|
||||||
|
### 旧文件(过渡期保留)
|
||||||
|
|
||||||
|
| 路径 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `读出芯片用户使用手册.md` | 旧 MPE 单文件手册(过渡期保留,不再更新) |
|
||||||
|
| `读出芯片用户使用手册.html` | 旧 MPE 导出 HTML |
|
||||||
|
| `specification.md` | 旧 SPI/LVDS 规格(内容已合并到 chapters/) |
|
||||||
|
| `pin_name.csv` (root) | 旧位置(已复制到 data/) |
|
||||||
|
| `pin_loc.csv` (root) | 旧位置(已复制到 data/) |
|
||||||
|
| `seg_define.csv` (root) | 旧位置(已复制到 data/) |
|
||||||
|
| `ids/` | 旧位置(JSON 已复制到 data/ids.json) |
|
||||||
|
| `pin_loc.xlsx` | 旧 Excel 文件 |
|
||||||
|
|
||||||
|
## 构建流程
|
||||||
|
|
||||||
|
### 一键构建
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装依赖
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 构建 HTML + PDF
|
||||||
|
python build.py
|
||||||
|
```
|
||||||
|
|
||||||
|
产物输出到 `output/` 目录:
|
||||||
|
- `output/RBPU16 读出基带处理芯片_数据手册.html`
|
||||||
|
- `output/RBPU16 读出基带处理芯片_数据手册.pdf`
|
||||||
|
|
||||||
|
### 构建步骤(build.py 内部流程)
|
||||||
|
|
||||||
|
1. 加载数据源:`data/*.csv` + `data/ids.json`
|
||||||
|
2. 初始化 Jinja2 模板引擎
|
||||||
|
3. 处理章节文件:`chapters/*.md`
|
||||||
|
- 识别 `<!-- MACRO: xxx -->` 标记并替换为 Jinja2 宏渲染的 HTML
|
||||||
|
- Python-Markdown 将 Markdown 转为 HTML
|
||||||
|
4. 生成目录 (TOC)
|
||||||
|
5. 渲染完整 HTML(封面 + TOC + 章节 + 修订历史)
|
||||||
|
6. WeasyPrint 将 HTML 转为 PDF
|
||||||
|
|
||||||
|
### 宏标记说明
|
||||||
|
|
||||||
|
章节 Markdown 文件中使用 `<!-- MACRO: xxx -->` 注释标记来指示脚本动态生成表格:
|
||||||
|
|
||||||
|
| 宏标记 | 功能 | 数据源 |
|
||||||
|
|--------|------|--------|
|
||||||
|
| `<!-- MACRO: pin_table -->` | 渲染管脚描述表 | `data/pin_name.csv` |
|
||||||
|
| `<!-- MACRO: pin_loc_grid -->` | 渲染 BGA 焊球网格 | `data/pin_loc.csv` |
|
||||||
|
| `<!-- MACRO: address_map -->` | 渲染地址映射总表 | `data/seg_define.csv` |
|
||||||
|
| `<!-- MACRO: register_table -->` | 渲染完整寄存器定义 | `data/ids.json` |
|
||||||
|
|
||||||
|
### 寄存器定义更新流程
|
||||||
|
|
||||||
|
当 XLS 寄存器定义文件更新后:
|
||||||
|
1. 在 VS Code 中打开 `script/ids_import.ipynb`,运行所有 cell
|
||||||
|
2. notebook 解析 `script/读出子系统IDS表.xls` 的多个 sheet
|
||||||
|
3. 输出为 `data/ids.json`
|
||||||
|
4. 运行 `python build.py` 重新构建手册
|
||||||
|
|
||||||
|
## 章节编辑指南
|
||||||
|
|
||||||
|
### 添加新章节
|
||||||
|
|
||||||
|
1. 在 `chapters/` 下创建新 `.md` 文件
|
||||||
|
2. 文件名格式:`{序号}_{英文名}.md`(如 `10_timing_diagrams.md`)
|
||||||
|
3. 文件以 `# 章节标题` 开头
|
||||||
|
4. 运行 `python build.py` 验证
|
||||||
|
|
||||||
|
### 修改管脚定义
|
||||||
|
|
||||||
|
1. 编辑 `data/pin_name.csv`(或根目录 `pin_name.csv`,然后复制到 data/)
|
||||||
|
2. 运行 `python build.py`,管脚表自动更新
|
||||||
|
|
||||||
|
### 修改寄存器定义
|
||||||
|
|
||||||
|
1. 编辑 `script/读出子系统IDS表.xls`
|
||||||
|
2. 运行 `script/ids_import.ipynb` 更新 `data/ids.json`
|
||||||
|
3. 运行 `python build.py`,寄存器表自动更新
|
||||||
|
|
||||||
|
### 修改样式
|
||||||
|
|
||||||
|
编辑 `templates/css/report.css`:
|
||||||
|
- CSS 变量(颜色、字体、间距)在 `:root` 块中
|
||||||
|
- 打印样式使用 `@page` 规则
|
||||||
|
- 屏幕样式使用 `@media screen`
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- **模板引擎**: Jinja2 — Python 标准,Flask 生态
|
||||||
|
- **Markdown 解析**: Python-Markdown + extensions (tables, codehilite, toc, fenced_code)
|
||||||
|
- **HTML→PDF**: WeasyPrint — 纯 Python,CSS Paged Media
|
||||||
|
- **代码高亮**: Pygments — Python-Markdown codehilite 依赖
|
||||||
|
- **数学公式**: KaTeX — CDN 加载,HTML 中动态渲染
|
||||||
|
- **图表**: Mermaid — CDN 加载(当前手册未使用)
|
||||||
|
|
||||||
|
## 关键约定
|
||||||
|
|
||||||
|
- 所有文档内容为中文,技术术语保留英文缩写(ADC、DAC、PLL、LVDS、SPI、AWG、DAQ、MCU、NCO 等)
|
||||||
|
- 管脚编号采用 BGA 网格命名(字母行 + 数字列,如 F4、G7)
|
||||||
|
- 地址和寄存器偏移使用 24 位十六进制表示(如 `0x100000`)
|
||||||
|
- SPI 协议格式:1 bit R/W + 25 bit addr + 5 bit chip_id + 1 bit reserved + N×32 bit data
|
||||||
|
- LVDS 协议帧格式:4 bit header + 16/32/64/128 bit payload + 8 bit CRC8
|
||||||
|
- 章节文件命名:`{序号}_{英文名}.md`,序号决定章节顺序
|
||||||
|
- 图片路径:相对于 repo 根目录,从 `assets/` 引用
|
||||||
|
|
||||||
|
## PDF 生成注意事项
|
||||||
|
|
||||||
|
WeasyPrint 需要系统依赖:
|
||||||
|
- **Windows**: 通常开箱即用
|
||||||
|
- **macOS**: `brew install pango cairo`
|
||||||
|
- **Linux**: `apt install libpango-1.0-0 libpangocairo-1.0-0`
|
||||||
|
|
||||||
|
中文 PDF 字体:若系统缺少中文字体,可在 CSS `:root` 中调整 `--font-body` 和 `--font-heading` 变量,使用系统可用字体。
|
||||||
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 203 KiB |
|
After Width: | Height: | Size: 190 KiB |
|
After Width: | Height: | Size: 209 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
|
@ -0,0 +1,168 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# RBPU16 Data Sheet",
|
||||||
|
"\n\nRun All -> self-contained HTML."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import sys,os,re,base64,mimetypes,subprocess\n",
|
||||||
|
"from datetime import datetime as dt; from pathlib import Path; from html import escape as eh\n",
|
||||||
|
"try: import markdown\n",
|
||||||
|
"except: subprocess.check_call([sys.executable,'-m','pip','install','markdown','-q']); import markdown\n",
|
||||||
|
"B=Path(os.getcwd()).resolve(); os.chdir(str(B)); sys.path.insert(0,str(B))\n",
|
||||||
|
"from doc_builder import import_handler, image_extension, codeblock_extension\n",
|
||||||
|
"print(f' {B.name}')\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Build"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def pc(md_text):\n",
|
||||||
|
" md_text = import_handler.process_imports(md_text,B,pc)\n",
|
||||||
|
" md_text = codeblock_extension.render_code_blocks(md_text,B)\n",
|
||||||
|
" return markdown.markdown(md_text,extensions=[\n",
|
||||||
|
" 'tables','fenced_code','codehilite','nl2br','sane_lists',\n",
|
||||||
|
" image_extension.ImageRowProcessor(),\n",
|
||||||
|
" ],extension_configs={'codehilite':{'css_class':'highlight','guess_lang':False}})\n",
|
||||||
|
"\n",
|
||||||
|
"cn=[]\n",
|
||||||
|
"with open(B/'project.yaml',encoding='utf-8') as f:\n",
|
||||||
|
" ic=False\n",
|
||||||
|
" for line in f:\n",
|
||||||
|
" line=line.rstrip()\n",
|
||||||
|
" if line.startswith('chapters:'): ic=True; continue\n",
|
||||||
|
" if ic:\n",
|
||||||
|
" mx=re.match(r'^\\s*-\\s+(.+)$',line)\n",
|
||||||
|
" if mx: cn.append(mx.group(1).strip())\n",
|
||||||
|
" elif line and not line.startswith(' '): ic=False\n",
|
||||||
|
"\n",
|
||||||
|
"print('Processing...')\n",
|
||||||
|
"chapters=[]\n",
|
||||||
|
"for i,n in enumerate(cn):\n",
|
||||||
|
" fp=B/'chapters'/n\n",
|
||||||
|
" if not fp.exists(): continue\n",
|
||||||
|
" print(f' [{i+1}] {n}')\n",
|
||||||
|
" c=pc(fp.read_text(encoding='utf-8'))\n",
|
||||||
|
" mx=re.search(r'<h1[^>]*>(.*?)</h1>',c)\n",
|
||||||
|
" chapters.append(dict(id=f'ch{i+1}',number=str(i+1),title=mx.group(1) if mx else fp.stem,content=c))\n",
|
||||||
|
"apd=B/'chapters'/'appendix'\n",
|
||||||
|
"if apd.exists():\n",
|
||||||
|
" for j,fp in enumerate(sorted(apd.glob('*.md'),key=lambda p:p.name)):\n",
|
||||||
|
" lb=chr(65+j)\n",
|
||||||
|
" c=pc(fp.read_text(encoding='utf-8'))\n",
|
||||||
|
" mx=re.search(r'<h1[^>]*>(.*?)</h1>',c)\n",
|
||||||
|
" chapters.append(dict(id=f'app{lb}',number=f'Appendix {lb}',title=mx.group(1) if mx else fp.stem,content=c))\n",
|
||||||
|
"\n",
|
||||||
|
"CSS=(B/'doc_builder'/'themes'/'datasheet.css').read_text(encoding='utf-8')\n",
|
||||||
|
"\n",
|
||||||
|
"def _parse_yaml(path):\n",
|
||||||
|
" meta={}; features=[]; in_features=False\n",
|
||||||
|
" with open(path,encoding='utf-8') as f:\n",
|
||||||
|
" for line in f:\n",
|
||||||
|
" s=line.strip(); k=None\n",
|
||||||
|
" if s.startswith('features:'):\n",
|
||||||
|
" in_features=True; continue\n",
|
||||||
|
" if in_features:\n",
|
||||||
|
" if s.startswith('- '):\n",
|
||||||
|
" features.append(s[2:].strip()); continue\n",
|
||||||
|
" elif s and not line.startswith(' '):\n",
|
||||||
|
" in_features=False\n",
|
||||||
|
" if not in_features and ':' in s:\n",
|
||||||
|
" k,v=s.split(':',1)\n",
|
||||||
|
" meta[k.strip()]=v.strip()\n",
|
||||||
|
" meta['features']=features\n",
|
||||||
|
" return meta\n",
|
||||||
|
"\n",
|
||||||
|
"meta=_parse_yaml(B/'project.yaml')\n",
|
||||||
|
"TITLE=meta.get('title','RBPU16')\n",
|
||||||
|
"SUBTITLE=meta.get('subtitle','数据手册')\n",
|
||||||
|
"AUTHOR=meta.get('author','郭成')\n",
|
||||||
|
"AU=AUTHOR\n",
|
||||||
|
"DATE=dt.now().strftime('%Y-%m-%d')\n",
|
||||||
|
"\n",
|
||||||
|
"def _title_html(t):\n",
|
||||||
|
" parts=t.split(' ',1)\n",
|
||||||
|
" if len(parts)>1:\n",
|
||||||
|
" return f'<span class=\"model\">{eh(parts[0])}</span> <span class=\"zh-name\">{eh(parts[1])}</span>'\n",
|
||||||
|
" return eh(t)\n",
|
||||||
|
"_title=_title_html(TITLE)\n",
|
||||||
|
"\n",
|
||||||
|
"COVER=''.join([\n",
|
||||||
|
" '<div class=\"cover-page\">',\n",
|
||||||
|
" '<div class=\"cover-top\"><div class=\"product-family\">READOUT BASEBAND PROCESSOR</div></div>',\n",
|
||||||
|
" '<div class=\"cover-body\">',\n",
|
||||||
|
" f'<h1>{_title}</h1>',\n",
|
||||||
|
" f'<div class=\"subtitle\">{eh(SUBTITLE)}</div>',\n",
|
||||||
|
" '</div>',\n",
|
||||||
|
" f'<div class=\"cover-bottom\"><span class=\"rev\">Rev 1.0 · {DATE}</span><span class=\"author\">{eh(AUTHOR)}</span></div>',\n",
|
||||||
|
" '</div>',\n",
|
||||||
|
"])\n",
|
||||||
|
"ch_html=chr(10).join(f'<div class=\"chapter\" id=\"{c[\"id\"]}\">{c[\"content\"]}</div>' for c in chapters)\n",
|
||||||
|
"FULL=chr(10).join([\n",
|
||||||
|
" '<!DOCTYPE html>','<html lang=\"zh-CN\">','<head>',\n",
|
||||||
|
" '<meta charset=\"utf-8\">','<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">',\n",
|
||||||
|
" f'<title>{TITLE} Data Sheet</title>',f'<meta name=\"author\" content=\"{AU}\">',\n",
|
||||||
|
" '<style>',CSS,'</style>','</head>','<body class=\"auto-numbering\">',\n",
|
||||||
|
" COVER,ch_html,\n",
|
||||||
|
" '<div class=\"page-break\"></div>','<h1>Revision History</h1>',\n",
|
||||||
|
" '<table class=\"revision compact\">',\n",
|
||||||
|
" '<thead><tr><th>Rev</th><th>Date</th><th>Changes</th><th>Author</th></tr></thead>',\n",
|
||||||
|
" f'<tbody><tr><td>1.0</td><td>{DATE}</td><td>Initial</td><td>{AU}</td></tr></tbody>','</table>',\n",
|
||||||
|
" '</body>','</html>',\n",
|
||||||
|
"])\n",
|
||||||
|
"SR=re.compile(r'src=\"(assets/[^\"]+)\"'); mimetypes.init()\n",
|
||||||
|
"def em(m):\n",
|
||||||
|
" r=m.group(1); ip=(B/r).resolve()\n",
|
||||||
|
" if not ip.exists(): return m.group(0)\n",
|
||||||
|
" mt,_=mimetypes.guess_type(str(ip))\n",
|
||||||
|
" if not mt: mt='image/png'\n",
|
||||||
|
" with open(ip,'rb') as f: b64=base64.b64encode(f.read()).decode()\n",
|
||||||
|
" return f'src=\"data:{mt};base64,{b64}\"'\n",
|
||||||
|
"FULL=SR.sub(em,FULL)\n",
|
||||||
|
"out=B/'output'; out.mkdir(exist_ok=True)\n",
|
||||||
|
"hp=out/f'{TITLE}_Data_Sheet.html'; hp.write_text(FULL,encoding='utf-8')\n",
|
||||||
|
"print(f'\\n {hp.name} ({hp.stat().st_size/1024:.0f} KB) OK')\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Done",
|
||||||
|
"\n\nSelf-contained HTML in `output/`."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"name": "python",
|
||||||
|
"version": "3.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 4
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# 简介
|
||||||
|
|
||||||
|
## 主要特点
|
||||||
|
|
||||||
|
* DAC 更新速率最高 12 GSPS
|
||||||
|
* ADC 采样速率最高 6 GSPS
|
||||||
|
* AWG 支持直接/调制波形输出
|
||||||
|
* AWG 支持标记脉冲输出
|
||||||
|
* DAQ 支持多种数据采集模式
|
||||||
|
* DAQ 支持低延迟反馈控制
|
||||||
|
* AWG 和 DAQ 支持 MCU 指令集编程
|
||||||
|
|
||||||
|
## 简要描述
|
||||||
|
|
||||||
|
RBPU16 是一款面向超导量子比特态信息读出的 SoC 芯片,最大支持 16 个量子比特并行读出。芯片内部集成 PLL、ADC、DAC 及 DSP 等模块,利用高速 DAC 产生微波信号激发读取腔,通过数字 I/O 使能外部 Pump 通道,再利用高速 ADC 采集处理反射信号,经 DSP 计算量子态信息后,通过 LVDS 接口实时输出,为量子比特态信息读出提供高集成度解决方案。
|
||||||
|
|
||||||
|
## 功能框图
|
||||||
|
|
||||||
|
{w=100%}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
# 规格参数
|
||||||
|
|
||||||
|
## 电气特性
|
||||||
|
|
||||||
|
测试条件:DIG_VDD = 1.0 V,IO_VDD = 1.8 V,AVDD = 1.0 V,AVDD18 = 1.8 V,TA = 25°C,除非另有说明。
|
||||||
|
|
||||||
|
### 数字接口
|
||||||
|
|
||||||
|
| 参数 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|
|
||||||
|
| SPI 时钟频率 | 50 | — | — | Mbps |
|
||||||
|
| LVDS 数据速率 | 750 | — | — | Mbps |
|
||||||
|
|
||||||
|
### 电源
|
||||||
|
|
||||||
|
| 供电域 | 标称电压 | 最大电流 | 单位 |
|
||||||
|
|:-|:-|:-|:-|
|
||||||
|
| DIG_VDD | 1.0 | 2000 | mA |
|
||||||
|
| IO_VDD | 1.8 | 1000 | mA |
|
||||||
|
| AVDD_ENCODER | 1.0 | 400 | mA |
|
||||||
|
| AVDD_P2S | 1.0 | 150 | mA |
|
||||||
|
| DAC_AVDD18 | 1.8 | 120 | mA |
|
||||||
|
| DAC_DVDD | 1.0 | 50 | mA |
|
||||||
|
| PLL_VDD18 | 1.8 | 50 | mA |
|
||||||
|
| PLL_VDD | 1.0 | 50 | mA |
|
||||||
|
| VCO_VDD | 1.0 | 50 | mA |
|
||||||
|
| PLL_DVDD | 1.0 | 50 | mA |
|
||||||
|
| ADC_VDD | 1.0 | 400 | mA |
|
||||||
|
| ADC_VDD18 | 1.8 | 200 | mA |
|
||||||
|
| ADC_DVDD | 1.0 | 100 | mA |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
以上电流值为各供电域最低过流要求,来源:pin_name.csv。VREF / PLL_VREF520 / ADC_VR850 / ADC_VR350 等基准电压端口电流可忽略(< 1 mA)。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## SPI 时序
|
||||||
|
|
||||||
|
| 参数 | 符号 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|:-|
|
||||||
|
| CSN 下降沿到 SCLK 下降沿 | tCSS | 3 | — | — | ns |
|
||||||
|
| MOSI 建立时间 | tMS | 3 | — | — | ns |
|
||||||
|
| MOSI 保持时间 | tMH | 3 | — | — | ns |
|
||||||
|
| MISO 建立时间 | tSS | 3 | — | — | ns |
|
||||||
|
| MISO 保持时间 | tSH | 3 | — | — | ns |
|
||||||
|
| SCLK 上升沿到 CSN 上升沿 | tCSH | 3 | — | — | ns |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## LVDS 时序
|
||||||
|
|
||||||
|
| 参数 | 符号 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|:-|
|
||||||
|
| 数据速率 | fLVDS | 750 | — | — | Mbps |
|
||||||
|
| 发送延迟 | tTX | — | 85 | — | ns |
|
||||||
|
| 接收延迟 | tRX | — | 75 | — | ns |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 时钟规格
|
||||||
|
|
||||||
|
| 参数 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|
|
||||||
|
| 参考时钟频率 | 50 | 100 / 125 | 250 | MHz |
|
||||||
|
| 参考时钟输入电平(差分) | — | — | — | Vpp |
|
||||||
|
| DAC 更新时钟 | — | — | 12 | GHz |
|
||||||
|
| ADC 采样时钟 | — | — | 6 | GHz |
|
||||||
|
| 数字主时钟 | — | — | 500 | MHz |
|
||||||
|
| PLL 锁定时间 | — | — | — | μs |
|
||||||
|
| 参考时钟相位噪声 @1 kHz | — | — | — | dBc/Hz |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
带 "—" 的参数待补充实测值。
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
# 极限参数
|
||||||
|
|
||||||
|
超出以下极限参数可能导致芯片永久性损坏。长时间在极限条件下工作可能影响芯片可靠性。
|
||||||
|
|
||||||
|
## 绝对最大额定值
|
||||||
|
|
||||||
|
| 参数 | 最小值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|
|
||||||
|
| DIG_VDD | −0.3 | 1.2 | V |
|
||||||
|
| IO_VDD | −0.3 | 2.0 | V |
|
||||||
|
| DAC_AVDD18 | −0.3 | 2.0 | V |
|
||||||
|
| PLL_VDD18 | −0.3 | 2.0 | V |
|
||||||
|
| ADC_VDD18 | −0.3 | 2.0 | V |
|
||||||
|
| AVDD_ENCODER, AVDD_P2S | −0.3 | 1.2 | V |
|
||||||
|
| DAC_DVDD, PLL_DVDD, ADC_DVDD | −0.3 | 1.2 | V |
|
||||||
|
| PLL_VDD, VCO_VDD, ADC_VDD | −0.3 | 1.2 | V |
|
||||||
|
| 数字 I/O 电压(相对于 IO_VDD) | −0.3 | IO_VDD + 0.3 | V |
|
||||||
|
| 模拟输入电压(ADC_VINxx) | −0.3 | ADC_VDD18 + 0.3 | V |
|
||||||
|
| 结温范围 | −40 | +125 | °C |
|
||||||
|
| 存储温度范围 | −65 | +150 | °C |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
以上极限值为设计参考值。实测极限值待芯片表征完成后更新。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## ESD 防护等级
|
||||||
|
|
||||||
|
| 模型 | 等级 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| HBM(人体模型) | — | V |
|
||||||
|
| CDM(充电器件模型) | — | V |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
ESD 防护等级待补充。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 热阻特性
|
||||||
|
|
||||||
|
| 参数 | 符号 | 典型值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|
|
||||||
|
| 结到环境热阻 | θJA | — | °C/W |
|
||||||
|
| 结到壳热阻 | θJC | — | °C/W |
|
||||||
|
| 结到板热阻 | θJB | — | °C/W |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
热阻参数待封装设计完成后补充。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 推荐工作条件
|
||||||
|
|
||||||
|
| 参数 | 符号 | 标称值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|
|
||||||
|
| 数字内核供电 | DIG_VDD | 1.0 | V |
|
||||||
|
| 数字 I/O 供电 | IO_VDD | 1.8 | V |
|
||||||
|
| DAC 模拟 1.0 V 供电 | AVDD_ENCODER, AVDD_P2S | 1.0 | V |
|
||||||
|
| DAC 模拟 1.8 V 供电 | DAC_AVDD18 | 1.8 | V |
|
||||||
|
| DAC 数字 1.0 V 供电 | DAC_DVDD | 1.0 | V |
|
||||||
|
| PLL 模拟 1.0 V 供电 | PLL_VDD, VCO_VDD | 1.0 | V |
|
||||||
|
| PLL 模拟 1.8 V 供电 | PLL_VDD18 | 1.8 | V |
|
||||||
|
| PLL 数字 1.0 V 供电 | PLL_DVDD | 1.0 | V |
|
||||||
|
| ADC 模拟 1.0 V 供电 | ADC_VDD | 1.0 | V |
|
||||||
|
| ADC 模拟 1.8 V 供电 | ADC_VDD18 | 1.8 | V |
|
||||||
|
| ADC 数字 1.0 V 供电 | ADC_DVDD | 1.0 | V |
|
||||||
|
| 工作环境温度 | TA | 25 | °C |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
所有电压以对应地平面(DGND 或 AGND)为参考。
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 管脚配置与功能描述
|
||||||
|
|
||||||
|
## 管脚顶视图
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 管脚定义
|
||||||
|
|
||||||
|
@import "data/pin_name.csv" using render_table.py
|
||||||
|
|
||||||
|
## BGA 焊球位置
|
||||||
|
|
||||||
|
下表列出芯片 13 × 13 BGA 焊球阵列中各位置的信号分配。
|
||||||
|
|
||||||
|
@import "data/pin_loc.csv" using render_bga.py
|
||||||
|
|
||||||
|
## 封装尺寸
|
||||||
|
|
||||||
|
| 参数 | 规格 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 焊球间距 | 1.0 | mm |
|
||||||
|
| 焊球直径 | 0.5 | mm |
|
||||||
|
| 焊球数量 | 13 × 13 = 169 | 个 |
|
||||||
|
| 基板尺寸 | 14 × 14 | mm |
|
||||||
|
| 封装类型 | CSP-BGA | — |
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
# 典型性能特性
|
||||||
|
|
||||||
|
除非另有说明,以下性能指标的测试条件为:DIG_VDD = 1.0 V,IO_VDD = 1.8 V,AVDD = 1.0 V,AVDD18 = 1.8 V,TA = 25°C。满载条件定义为满占空比、功能全开(AWG + DAQ + MIX + 插值 + NCO + 解模)。
|
||||||
|
|
||||||
|
## 电源特性
|
||||||
|
|
||||||
|
### 电流消耗
|
||||||
|
|
||||||
|
| 供电域 | 标称电压 (V) | 空闲电流 (mA) | 满载 12G 电流 (mA) | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|
|
||||||
|
| DIG_VDD | 1.0 | 26.0 | 539.0 | mA |
|
||||||
|
| IO_VDD | 1.8 | 8.0 | 7.0 | mA |
|
||||||
|
| AVDD_ENCODER | 1.0 | 19.2 | 251.0 | mA |
|
||||||
|
| AVDD_P2S | 1.0 | 168.7 | 227.3 | mA |
|
||||||
|
| DAC_AVDD18 | 1.8 | ≅207.8 | ≅206.0 | mA |
|
||||||
|
| DAC_DVDD | 1.0 | 8.0 | 33.0 | mA |
|
||||||
|
| PLL_VDD18 | 1.8 | 包含在 +1.8V 模拟轨 | 包含在 +1.8V 模拟轨 | mA |
|
||||||
|
| PLL_VDD, VCO_VDD | 1.0 | 26.0 | 144.6 | mA |
|
||||||
|
| PLL_DVDD | 1.0 | — | — | mA |
|
||||||
|
| ADC_VDD | 1.0 | 71.0 | 164.7 | mA |
|
||||||
|
| ADC_VDD18 | 1.8 | 包含在 +1.8V 模拟轨 | 包含在 +1.8V 模拟轨 | mA |
|
||||||
|
| ADC_DVDD | 1.0 | — | — | mA |
|
||||||
|
| **总计** | — | **531.7** | **1569.6** | mA |
|
||||||
|
|
||||||
|
数据来源:电流测试.xlsx。
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
+1.8 V 模拟轨对应 DAC_AVDD18 + PLL_VDD18 + ADC_VDD18 + 其它 1.8 V 模拟域,实测稳定在 ~206 mA。+1.0 V DIG 电流随时钟频率变化显著,是总功耗的主要变量。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 功耗
|
||||||
|
|
||||||
|
| 工作状态 | 总功耗 (W) | 条件 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 空闲(复位前) | — | 时钟未配置 |
|
||||||
|
| 待机(复位后) | — | 时钟使能,无激励/采集 |
|
||||||
|
| 满载 6G | — | DAC_CLK = 6 GHz |
|
||||||
|
| 满载 10G | — | DAC_CLK = 10 GHz |
|
||||||
|
| 满载 12G | — | DAC_CLK = 12 GHz |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
功耗数据待根据实测电流和电压计算后填写。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 时钟与 NCO 特性
|
||||||
|
|
||||||
|
| 参数 | 符号 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|:-|
|
||||||
|
| DAC 更新时钟频率 | fDAC | — | — | 12 | GHz |
|
||||||
|
| ADC 采样时钟频率 | fADC | — | — | 6 | GHz |
|
||||||
|
| NCO 频率范围 | fNCO | 100 | — | 2400 | MHz |
|
||||||
|
| NCO 基频 (fs/8) | — | — | 750 | — | MHz |
|
||||||
|
| NCO 频率分辨率 | — | — | — | — | Hz |
|
||||||
|
| 参考时钟频率范围 | fREF | 50 | 100 | 250 | MHz |
|
||||||
|
| PLL 锁定时间 | tLOCK | — | — | — | μs |
|
||||||
|
| 时钟抖动(RMS) | tJITTER | — | — | — | ps |
|
||||||
|
|
||||||
|
NCO 频率扫频测试结果(400–2400 MHz):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## DAC 特性
|
||||||
|
|
||||||
|
### 关键指标
|
||||||
|
|
||||||
|
| 参数 | 符号 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|:-|
|
||||||
|
| 更新速率 | fDAC | — | — | 12 | GSPS |
|
||||||
|
| 分辨率 | — | — | 16 | — | bit |
|
||||||
|
| 输出阻抗 | ZOUT | — | 50 | — | Ω |
|
||||||
|
| 输出频率范围(NRZ 模式) | fOUT | DC | — | 3 | GHz |
|
||||||
|
| 输出频率范围(MIX 模式) | fOUT | 0.3 | — | 2.4 | GHz |
|
||||||
|
| SFDR(1.3 GHz 输出) | SFDR | — | — | — | dBc |
|
||||||
|
| NSD(1.3 GHz 输出) | NSD | — | — | — | dBm/Hz |
|
||||||
|
| 相位噪声 @10 kHz | PN10k | — | — | — | dBc/Hz |
|
||||||
|
| DNL | DNL | — | — | — | LSB |
|
||||||
|
| INL | INL | — | — | — | LSB |
|
||||||
|
| 输出共模电压 | VCM | — | — | — | V |
|
||||||
|
|
||||||
|
### 输出模式频谱
|
||||||
|
|
||||||
|
以 1300 MHz 输出为例,三种输出模式频谱如下:
|
||||||
|
|
||||||
|
| 输出模式 | 频谱图 |
|
||||||
|
|:-|:-|
|
||||||
|
| NRZ 直出 |  |
|
||||||
|
| 混频 (MIX) |  |
|
||||||
|
| 半带混频 (MIX-HB) |  |
|
||||||
|
|
||||||
|
### 扫频特性
|
||||||
|
|
||||||
|
DAC 基带输出扫频(混频 + 半带模式,300–2300 MHz):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## ADC 特性
|
||||||
|
|
||||||
|
| 参数 | 符号 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|:-|
|
||||||
|
| 采样速率 | fADC | — | — | 6 | GSPS |
|
||||||
|
| 分辨率 | — | — | 8 | — | bit |
|
||||||
|
| SNR | SNR | — | — | — | dB |
|
||||||
|
| SINAD | SINAD | — | — | — | dB |
|
||||||
|
| ENOB | ENOB | — | — | — | bit |
|
||||||
|
| SFDR | SFDR | — | — | — | dBc |
|
||||||
|
| 模拟输入带宽 (−3 dB) | BW | — | 3 | — | GHz |
|
||||||
|
| 满量程输入范围(差分) | VFS | — | 0.7 | — | Vpp |
|
||||||
|
| 输入共模电压 | VCM | — | 0.5 | — | V |
|
||||||
|
| 差分输入阻抗 | ZIN | — | 100 | — | Ω |
|
||||||
|
|
||||||
|
ADC 采集波形示例(满量程正弦波输入):
|
||||||
|
|
||||||
|
{w=48%}
|
||||||
|
{w=48%}
|
||||||
|
|
||||||
|
## 数字接口特性
|
||||||
|
|
||||||
|
| 参数 | 符号 | 最小值 | 典型值 | 最大值 | 单位 |
|
||||||
|
|:-|:-|:-|:-|:-|:-|
|
||||||
|
| SPI 时钟频率 | fSCLK | 50 | — | — | Mbps |
|
||||||
|
| LVDS 数据速率 | fLVDS | 750 | — | — | Mbps |
|
||||||
|
| LVDS 发送延迟 | tTX | — | 85 | — | ns |
|
||||||
|
| LVDS 接收延迟 | tRX | — | 75 | — | ns |
|
||||||
|
| SYNC_IN 最小脉宽 | tSYNC | — | — | — | ns |
|
||||||
|
| RST_N 最小脉宽 | tRST | — | — | — | ns |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 数字处理能力
|
||||||
|
|
||||||
|
| 参数 | 规格 | 来源 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| AWG 波形存储容量 | 128 KB | seg_define.csv |
|
||||||
|
| DAQ 采集结果存储容量 | 128 KB | seg_define.csv |
|
||||||
|
| DAQ 并行解模通道数 | 16 | pin_name.csv |
|
||||||
|
| MCU 指令执行速率 | 每 3 个时钟周期 1 条指令 | — |
|
||||||
|
| 匹配滤波器系数存储 (ASIC) | 512 KB | seg_define.csv |
|
||||||
|
| NCO 频率控制字位宽 | 32 bit | ChipConfig.py |
|
||||||
|
| NCO 相位控制字位宽 | — | — |
|
||||||
|
| 死时间 | — | — |
|
||||||
|
| Pump 脉宽范围 | — | — |
|
||||||
|
|
||||||
|
## 温度传感器
|
||||||
|
|
||||||
|
| 参数 | 典型值 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 测温范围 | — | °C |
|
||||||
|
| 分辨率 | — | °C |
|
||||||
|
| 精度 | — | °C |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 中断与异常
|
||||||
|
|
||||||
|
### 中断向量表
|
||||||
|
|
||||||
|
| 中断源 | 触发条件 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| EXIT_IR | MCU 执行退出指令 | 正常退出,任务执行完毕 |
|
||||||
|
| ILLEGAL_ONE | 指令字为 0xFFFFFFFF | 指令内存异常,可能未编程 |
|
||||||
|
| ILLEGAL_ZERO | 指令字为 0x00000000 | 指令内存异常,常见于空白区域 |
|
||||||
|
| UNALIGN_SW | 16 位访问地址未对齐 | 检查 load/store 指令对齐 |
|
||||||
|
| UNALIGN_LW | 32 位访问地址未对齐 | 检查 load/store 指令对齐 |
|
||||||
|
| LINK_DOWN | LVDS 链路同步丢失 | 接收端返回未同步状态 |
|
||||||
|
| FORCE_AWG | 外部强制 AWG 请求 | 寄存器触发 |
|
||||||
|
| FORCE_DAQ | 外部强制 DAQ 请求 | 寄存器触发 |
|
||||||
|
|
||||||
|
### 典型异常波形
|
||||||
|
|
||||||
|
| 异常类型 | 波形图 |
|
||||||
|
|:-|:-|
|
||||||
|
| MCU 正常退出 (EXIT_IR) |  |
|
||||||
|
| 非法指令 (ILLEGAL_ONE) |  |
|
||||||
|
| LVDS 链路断开 (LINK_DOWN) |  |
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
# 术语与缩写
|
||||||
|
|
||||||
|
| 术语 | 全称 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| **ADC** | Analog-to-Digital Converter | 模数转换器 |
|
||||||
|
| **AWG** | Arbitrary Waveform Generator | 任意波形发生器,产生读出激励波形 |
|
||||||
|
| **BGA** | Ball Grid Array | 球栅阵列封装 |
|
||||||
|
| **CDM** | Charged Device Model | 充电器件模型(ESD 测试) |
|
||||||
|
| **CRC** | Cyclic Redundancy Check | 循环冗余校验 |
|
||||||
|
| **CSP** | Chip Scale Package | 芯片级封装 |
|
||||||
|
| **DAC** | Digital-to-Analog Converter | 数模转换器 |
|
||||||
|
| **DAQ** | Data Acquisition | 数据采集模块,采集和处理回波信号 |
|
||||||
|
| **DNL** | Differential Nonlinearity | 微分非线性 |
|
||||||
|
| **DSP** | Digital Signal Processing | 数字信号处理 |
|
||||||
|
| **ENOB** | Effective Number of Bits | 有效位数 |
|
||||||
|
| **ESD** | Electrostatic Discharge | 静电放电 |
|
||||||
|
| **FIFO** | First In, First Out | 先入先出缓冲器 |
|
||||||
|
| **FM** | Frequency Modulation | 频率调制 |
|
||||||
|
| **FPGA** | Field-Programmable Gate Array | 现场可编程门阵列 |
|
||||||
|
| **HB** | Half-Band | 半带滤波器,DAC 插值滤波器 |
|
||||||
|
| **HBM** | Human Body Model | 人体模型(ESD 测试) |
|
||||||
|
| **INL** | Integral Nonlinearity | 积分非线性 |
|
||||||
|
| **LVDS** | Low-Voltage Differential Signaling | 低电压差分信号 |
|
||||||
|
| **MCU** | Micro Controller Unit | 微控制器,AWG/DAQ 内部控制核心 |
|
||||||
|
| **MIX** | Mixer / Mix Mode | 混频器 / 混频输出模式 |
|
||||||
|
| **MSL** | Moisture Sensitivity Level | 湿度敏感等级 |
|
||||||
|
| **NCO** | Numerically Controlled Oscillator | 数控振荡器,用于频率合成 |
|
||||||
|
| **NRZ** | Non-Return-to-Zero | 不归零编码 / DAC 直出模式 |
|
||||||
|
| **NSD** | Noise Spectral Density | 噪声谱密度 |
|
||||||
|
| **PCB** | Printed Circuit Board | 印刷电路板 |
|
||||||
|
| **PLL** | Phase-Locked Loop | 锁相环,片上时钟管理 |
|
||||||
|
| **PlsGen** | Pulse Generator | 脉冲产生器,产生 Pump 使能脉冲 |
|
||||||
|
| **PM** | Phase Modulation | 相位调制 |
|
||||||
|
| **POR** | Power-On Reset | 上电复位 |
|
||||||
|
| **Pump** | — | 外部泵浦通道,上变频基带信号 |
|
||||||
|
| **Qubit** | Quantum Bit | 量子比特 |
|
||||||
|
| **RBPU** | Readout Baseband Processing Unit | 读出基带处理单元 |
|
||||||
|
| **RF** | Radio Frequency | 射频 |
|
||||||
|
| **RMS** | Root Mean Square | 均方根值 |
|
||||||
|
| **SFDR** | Spurious-Free Dynamic Range | 无杂散动态范围 |
|
||||||
|
| **SINAD** | Signal-to-Noise and Distortion | 信纳比 |
|
||||||
|
| **SNR** | Signal-to-Noise Ratio | 信噪比 |
|
||||||
|
| **SoC** | System on Chip | 片上系统 |
|
||||||
|
| **SPI** | Serial Peripheral Interface | 串行外设接口 |
|
||||||
|
| **VCM** | Common Mode Voltage | 共模电压 |
|
||||||
|
| **VCO** | Voltage-Controlled Oscillator | 压控振荡器 |
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
# 操作原理
|
||||||
|
|
||||||
|
## 架构与模块划分
|
||||||
|
|
||||||
|
RBPU16 是一款用于超导量子比特态信息读出的 SoC 基带芯片。芯片模拟部分包含 ADC、DAC、PLL、LVDS、POR 及温度传感器;数字部分包含 DAQ、AWG、PlsGen、Feedback 及 System 模块。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 信号流概述
|
||||||
|
|
||||||
|
**激励信号生成路径**:AWG 控制激励通道波形输出 → DAC 转换为基带读出激励信号 → AWG 同步触发 PlsGen 发出脉冲使能外部 Pump 通道。
|
||||||
|
|
||||||
|
**回波信号处理路径**:ADC 采集反射的读出基带信号 → DAQ 对基带信号进行分析处理 → 结果通过 LVDS 接口发送 → DAQ 触发 Feedback 模块将部分结果上报或下发到外部芯片。
|
||||||
|
|
||||||
|
### 辅助模块
|
||||||
|
|
||||||
|
| 模块 | 功能 |
|
||||||
|
|:-|:-|
|
||||||
|
| PLL | 管理芯片时钟,为 ADC/DAC/数字模块生成所需频率 |
|
||||||
|
| POR | 上电复位,保障芯片正常启动 |
|
||||||
|
| 温度监视 | 实时监测芯片温度变化 |
|
||||||
|
| System | 管理芯片控制状态,支撑运维和调试 |
|
||||||
|
|
||||||
|
<div class="important">
|
||||||
|
读出芯片支持 ASIC 模式和 FPGA 模式两种工作方式。两种模式受限于资源及外部 ADC/DAC 硬件性能差异,部分功能实现存在不同,阅读时需注意区分。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 关键数据路径
|
||||||
|
|
||||||
|
### 读出激励输出通道
|
||||||
|
|
||||||
|
读出激励输出通道(RO 通道)由 AWG 模块和 Pump 模块协同工作,产生基带读出激励信号和 Pump 使能信号。
|
||||||
|
|
||||||
|
#### 编程资源
|
||||||
|
|
||||||
|
AWG 模块需编程六类数据资源:
|
||||||
|
|
||||||
|
| 资源 | 地址空间 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| MCU 指令 (MCU_INS) | `0x700000` | MCU 执行的指令流 |
|
||||||
|
| MCU 数据 (MCU_DAT) | `0x800000` | 指令引用的初始数据 |
|
||||||
|
| 控制寄存器 (AWG_REG) | `0x900000` | AWG 工作模式与参数 |
|
||||||
|
| 波形映射表 (AWG_IDX) | `0xA00000` | 码字 → 波形段映射 |
|
||||||
|
| 波形数据 (AWG_WVE) | `0xB00000` | 波形采样点存储 |
|
||||||
|
| 模拟配置 (SYS_ANA) | — | DAC 输出模式与偏置校准 |
|
||||||
|
|
||||||
|
#### 波形输出流程
|
||||||
|
|
||||||
|
1. MCU 每 3 个时钟周期执行一条指令,发出控制码字
|
||||||
|
2. `WAVE_ID` 字段经查找表映射为波形段起始地址和长度
|
||||||
|
3. 波形数据经希尔伯特变换生成 I/Q 两路
|
||||||
|
4. I/Q 信号与 NCO 混频,实现频率搬移
|
||||||
|
5. 经数字调幅、半带插值滤波
|
||||||
|
6. 输出至 DAC 转换为模拟信号
|
||||||
|
|
||||||
|
#### 输出模式
|
||||||
|
|
||||||
|
| 模式 | 频率范围 | 应用场景 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| **NRZ 直出** | DC–3 GHz | 多音基带信号,多量子比特并行读出 |
|
||||||
|
| **MIX 混频** | 0.3–2.4 GHz | NCO 精确频点控制,腔频扫描 |
|
||||||
|
| **NCO Only** | — | 芯片测试,连续波形输出 |
|
||||||
|
| **HBMIX 半带混频** | 高频段 | 启用半带插值,提升高频信号质量 |
|
||||||
|
|
||||||
|
**射频直出**:NRZ 模式下利用高阶奈奎斯特区可实现 6–7 GHz 射频直出,功率平坦度约 2 dB(受 sinc 滚降限制)。
|
||||||
|
|
||||||
|
**Pump 通道**:MCU 码字 `PUMP_EN` 位触发 PlsGen 产生可编程脉宽信号,经 `PO_PUMP_EN` 管脚输出使能外部 Pump 上变频通道。
|
||||||
|
|
||||||
|
**软复位**:写 AWG_REG 软复位寄存器可复位 AWG 内部状态机和 FIFO,复位后需重新编程所有资源。
|
||||||
|
|
||||||
|
### 读出回波信号处理
|
||||||
|
|
||||||
|
读出回波输入通道(RI 通道)由 ADC 和 DAQ 模块构成,采集并处理反射基带信号。
|
||||||
|
|
||||||
|
#### 模拟前端
|
||||||
|
|
||||||
|
RF 回波信号 → 外部混频器下变频为基带 → 巴伦差分转换 → ADC 采样。
|
||||||
|
FPGA 平台:8 位 @ 4 GSPS;ASIC 平台:8 位 @ 6 GSPS。
|
||||||
|
|
||||||
|
#### 编程资源
|
||||||
|
|
||||||
|
DAQ 模块需编程五类数据资源:
|
||||||
|
|
||||||
|
| 资源 | 地址空间 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| MCU 指令 (MCU_INS) | `0x200000` | DAQ MCU 执行指令流 |
|
||||||
|
| MCU 数据 (MCU_DAT) | `0x300000` | 指令引用的初始数据 |
|
||||||
|
| 控制寄存器 (DAQ_REG) | `0x400000` | DAQ 工作模式与参数 |
|
||||||
|
| 读出参数 (DAQ_PAR) | `0x500000` | 解模参数 |
|
||||||
|
| 匹配滤波器系数 (DAQ_FLT) | `0x580000` | 匹配滤波器权重(ASIC 模式) |
|
||||||
|
| 模拟配置 (SYS_ANA) | — | ADC 参考电压选择 |
|
||||||
|
|
||||||
|
#### 数据处理流程
|
||||||
|
|
||||||
|
1. ADC 采集原始波形
|
||||||
|
2. 数字解模:原始波形与匹配滤波器相关运算 → I/Q 复数数据
|
||||||
|
3. 态判定:根据 I/Q 判定量子态(0 / 1 / 2 / 未定义)
|
||||||
|
4. 态统计:多次测量结果计数
|
||||||
|
5. 结果输出:经 `RSLT_PUSH` LVDS 接口发送
|
||||||
|
|
||||||
|
#### 采集模式
|
||||||
|
|
||||||
|
| 模式 | 输出数据量 | 应用场景 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 原始波形 | 最大 | 调试与原始数据分析 |
|
||||||
|
| IQ 数据 | 64 bit × N | 解模结果分析 |
|
||||||
|
| 态数据 | 2 bit × N | 高速态读出 |
|
||||||
|
| 态统计 | 最小 | 多次测量汇总 |
|
||||||
|
|
||||||
|
**软复位**:写 DAQ_REG 软复位寄存器可复位 DAQ 状态机。
|
||||||
|
|
||||||
|
## 接口控制协议
|
||||||
|
|
||||||
|
### SPI 配置协议
|
||||||
|
|
||||||
|
SPI 采用四线模式,CPOL = 1(空闲高电平),CPHA = 1(首沿输出、次沿采样)。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**帧格式:**
|
||||||
|
|
||||||
|
| 字段 | RW | ADDR | CHIP_ID | RSV | DATA |
|
||||||
|
|:-:|:-:|:-:|:-:|:-:|:-:|
|
||||||
|
| 位宽 | 1 | 25 | 5 | 1 | 32 × N |
|
||||||
|
| 说明 | 0: 读, 1: 写 | 32 MB 地址空间 | 片选 ID | 保留 | 数据 (N ≥ 1) |
|
||||||
|
|
||||||
|
协议以流模式传输:先发送 1 bit 读写标志 + 25 bit 地址 + 5 bit 片选 ID,之后发送/接收 N × 32 bit 数据,直至主控端拉低 CSN 结束通信。每完成 32 bit 后地址自动递增 4 字节。
|
||||||
|
|
||||||
|
### LVDS 通信协议
|
||||||
|
|
||||||
|
芯片数据推送 (`rslt_push_[p,n]`)、反馈上报 (`glb_tx_[p,n]`) 和反馈下发 (`glb_rx_[p,n]`) 接口采用定制 LVDS 协议。
|
||||||
|
|
||||||
|
**帧格式:**
|
||||||
|
|
||||||
|
```
|
||||||
|
+---------------------------------------+
|
||||||
|
| LVDS DATA FRAME |
|
||||||
|
+------+-------------------+------------+
|
||||||
|
| 4 | 16/32/64/128 | 8 |
|
||||||
|
+------+-------------------+------------+
|
||||||
|
| HEAD | Payload | CRC8 |
|
||||||
|
+------+-------------------+------------+
|
||||||
|
MSB LSB
|
||||||
|
```
|
||||||
|
|
||||||
|
HEAD 字段定义:
|
||||||
|
|
||||||
|
| Bit | 说明 |
|
||||||
|
|:-|:-|
|
||||||
|
| [3] | 启动标志(1 = 启动传输) |
|
||||||
|
| [2] | 保留(置 0) |
|
||||||
|
| [1:0] | 载荷长度:0 = 16 bit,1 = 32 bit,2 = 64 bit,3 = 128 bit |
|
||||||
|
|
||||||
|
CRC8 多项式:
|
||||||
|
|
||||||
|
$$x^8 + x^2 + x + 1$$
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**同步机制**:接收端必须先与发送端同步方可接收数据。发送端发送同步码 `hfnl`(32 bit),达到设定次数后发送结束码 `exit`(32 bit)。接收端状态转移:
|
||||||
|
|
||||||
|
* 初始 → **未同步**:等待同步码
|
||||||
|
* **未同步** → **确认**:收到足够次数的同步码
|
||||||
|
* **确认** → **就绪**:收到结束码
|
||||||
|
* **就绪** → **未同步**:数据接收中 CRC8 校验错误
|
||||||
|
|
||||||
|
**空闲**:无数据传输时 LVDS 电平拉高;发送数据时拉低两个数据周期后开始发送。
|
||||||
|
|
@ -0,0 +1,220 @@
|
||||||
|
# 应用信息
|
||||||
|
|
||||||
|
## 模拟接口
|
||||||
|
|
||||||
|
### DAC 输出接口
|
||||||
|
|
||||||
|
DAC 输出频率范围 DC–12 GHz,内部集成 50 Ω 电阻网络。外部需接差分 270 nH 电感到地,经巴伦差分转单端输出。PCB 走线注意阻抗匹配(50 Ω 差分)。
|
||||||
|
|
||||||
|
```schemdraw
|
||||||
|
import schemdraw
|
||||||
|
from schemdraw import elements as e
|
||||||
|
|
||||||
|
with schemdraw.Drawing(show=False) as d:
|
||||||
|
d.config(fontsize=11)
|
||||||
|
d += e.Line().right().label('DAC_OUT_P')
|
||||||
|
d += e.Inductor().down().label('270nH')
|
||||||
|
d += e.Ground()
|
||||||
|
d += e.Line().right().at((2.5, 0))
|
||||||
|
d += e.Transformer().label('Balun')
|
||||||
|
d += e.Line().right()
|
||||||
|
d += e.Resistor().down().label('50ohm')
|
||||||
|
d += e.Ground()
|
||||||
|
d += e.Line().right().at((0, -2.5)).label('DAC_OUT_N')
|
||||||
|
d += e.Inductor().up().label('270nH')
|
||||||
|
d += e.Ground()
|
||||||
|
d += e.Line().right().at((2.5, -2.5))
|
||||||
|
d += e.Line().up()
|
||||||
|
```
|
||||||
|
|
||||||
|
DAC 支持以下输出模式:
|
||||||
|
|
||||||
|
| 模式 | 频率范围 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| NRZ 直出 | DC–3 GHz | 基带波形直接输出,适合多音基带信号 |
|
||||||
|
| MIX 混频 | 0.3–2.4 GHz | 基带与 NCO 混频,精确频点定位 |
|
||||||
|
| MIX-HB 半带混频 | 高频段 | 混频 + 半带插值,提升高频信号质量 |
|
||||||
|
|
||||||
|
频谱参考见 [DAC 特性](#dac-特性)。
|
||||||
|
|
||||||
|
### ADC 输入接口
|
||||||
|
|
||||||
|
ADC 采用差分模拟输入,两组独立通道。
|
||||||
|
|
||||||
|
| 参数 | 规格 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 满量程输入范围(差分) | 0.7 | Vpp |
|
||||||
|
| 输入共模电压 | 0.5 | V |
|
||||||
|
| 差分输入阻抗 | 100 | Ω |
|
||||||
|
| 输入带宽 (−3 dB) | 3 | GHz |
|
||||||
|
| 采样速率 | 最高 6 | GSPS |
|
||||||
|
|
||||||
|
基准电压模式通过 `ADC_REF_SENSE` 选择:
|
||||||
|
|
||||||
|
| 电平 | 模式 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 1.8 V | 内部带隙基准 | 无需外部参考 |
|
||||||
|
| 0.52 V | 外部参考源 | 需提供 ADC_VR850 和 ADC_VR350 |
|
||||||
|
|
||||||
|
波形示例参考见 [ADC 特性](#adc-特性)。
|
||||||
|
|
||||||
|
### 时钟输入
|
||||||
|
|
||||||
|
参考时钟通过 CLK_REF_P / CLK_REF_N 差分输入,AC 耦合。
|
||||||
|
|
||||||
|
| 参数 | 规格 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 频率范围 | 50–250 | MHz |
|
||||||
|
| 典型频率 | 100 或 125 | MHz |
|
||||||
|
| 要求 | 低相噪时钟源 | — |
|
||||||
|
|
||||||
|
内部 PLL 倍频分配:
|
||||||
|
|
||||||
|
| 输出 | 频率范围 | 用途 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| DAC_CLK | 6–12 GHz | DAC 更新时钟 |
|
||||||
|
| ADC_CLK | 3–6 GHz | ADC 采样时钟 |
|
||||||
|
| DIG_CLK | 250–500 MHz | 数字主时钟 |
|
||||||
|
|
||||||
|
### 环路滤波器
|
||||||
|
|
||||||
|
使用内部 PLL 时需外接环路滤波器。
|
||||||
|
|
||||||
|
PLL 电荷泵输出 (CP_OUT) → 外部二阶环路滤波器 → VCTRL。PLL_VREF520 需提供外部 520 mV 参考偏置。
|
||||||
|
|
||||||
|
```schemdraw
|
||||||
|
import schemdraw
|
||||||
|
from schemdraw import elements as e
|
||||||
|
|
||||||
|
with schemdraw.Drawing(show=False) as d:
|
||||||
|
d.config(fontsize=11)
|
||||||
|
d += e.Line().left().label('CP_OUT')
|
||||||
|
d += e.Line().right()
|
||||||
|
d += e.Resistor().right().label('R1')
|
||||||
|
d += e.Line().right().label('VCTRL')
|
||||||
|
d += e.Capacitor().down().at((2, 0)).label('C1')
|
||||||
|
d += e.Ground()
|
||||||
|
d += e.Capacitor().down().at((4, 0)).label('C2')
|
||||||
|
d += e.Ground()
|
||||||
|
```
|
||||||
|
|
||||||
|
**外接元件要求:**
|
||||||
|
|
||||||
|
| 端口 | 配置 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| BIAS_CAP | 100 nF 去耦电容 | PLL 偏置去耦 |
|
||||||
|
| RES_2K | 2 kΩ 电阻到地 | PLL 偏置电阻 |
|
||||||
|
| PORT_BIAS_TB | 10 μF ×1 + 1 μF ×1 + 0.1 μF ×3 到地 | PLL 滤波电容 |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
环路滤波器参数(电荷泵电流、环路带宽、具体阻容值)待 PLL 设计确认后补充。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 基准电压与偏置
|
||||||
|
|
||||||
|
| 端口 | 电压/配置 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| ADC_VR850 | 850 mV | ADC 外部参考,需去耦 |
|
||||||
|
| ADC_VR350 | 350 mV | ADC 外部参考,需去耦 |
|
||||||
|
| ADC_REF_SENSE | 1.8 V / 0.52 V | ADC 带隙基准选择 |
|
||||||
|
| PLL_VREF520 | 520 mV | PLL 外部参考,需去耦 |
|
||||||
|
| VREF500IN | 500 mV | DAC 外部参考,需去耦 |
|
||||||
|
| DAC_VBIAS_IREF_RES | 5.2 kΩ + 10 μF 到地 | DAC 偏置基准电流 |
|
||||||
|
| ADC_VBIAS_IREF_RES | 5.2 kΩ + 10 μF 到地 | ADC 偏置基准电流 |
|
||||||
|
| PLL_CP_OUT | 电荷泵输出 | 经环路滤波器接 VCTRL |
|
||||||
|
|
||||||
|
## 启动与复位
|
||||||
|
|
||||||
|
### 上电时序
|
||||||
|
|
||||||
|
芯片上电须严格遵循以下顺序:
|
||||||
|
|
||||||
|
| 步骤 | 操作 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 1 | 内核供电 (DIG_VDD, DAC_DVDD, PLL_DVDD, ADC_DVDD) | 数字内核上电 |
|
||||||
|
| 2 | IO 供电 (IO_VDD) | 数字 I/O 上电 |
|
||||||
|
| 3 | 模拟供电 (DAC_AVDD18, PLL_VDD18, ADC_VDD18, AVDD_ENCODER, AVDD_P2S, PLL_VDD, VCO_VDD, ADC_VDD) | 模拟域上电 |
|
||||||
|
| 4 | 参考时钟输入 | 提供稳定参考时钟 |
|
||||||
|
| 5 | 解除复位 (PB_RST_N 拉高) | 芯片启动 |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
上电时序波形图待补充。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 复位
|
||||||
|
|
||||||
|
| 复位类型 | 触发方式 | 影响范围 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 上电复位 (POR) | 芯片上电自动触发 | 全芯片 |
|
||||||
|
| 硬复位 | PB_RST_N 拉低 | 全芯片 |
|
||||||
|
| 软复位 | 写 SYS_REG 软复位寄存器 | 可分别复位 AWG / DAQ / System |
|
||||||
|
|
||||||
|
## 配置与操作流程
|
||||||
|
|
||||||
|
读出芯片上电后应先执行校准(ADC/DAC/PLL/系统同步),校准流程参见附录 [运维操作手册](#运维操作手册)。实验操作遵循**数据配置 → 实验运行 → 数据采集**三个阶段。
|
||||||
|
|
||||||
|
### 数据配置阶段
|
||||||
|
|
||||||
|
| 通道 | 配置内容 | 接口 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| RO(激励) | 输出模式、波形查找表、波形数据、MCU 程序 | SPI |
|
||||||
|
| RI(采集) | 采集模式、读出参数、匹配滤波器权重、MCU 程序 | SPI |
|
||||||
|
| Pump | 使能脉宽、码字触发延迟 | SPI |
|
||||||
|
|
||||||
|
<div class="important">
|
||||||
|
若芯片出现异常,实验配置前应通过写寄存器软复位芯片状态机和寄存器默认值。配置用例参考附录 [历史无关配置集](#历史无关配置集)。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 实验运行阶段
|
||||||
|
|
||||||
|
同步触发信号 (SYNC_IN) 启动芯片运行,确保多芯片间时序确定。同步信号经内部延迟模块为 DAQ 和 AWG 分别补偿延迟,保证协同运行。
|
||||||
|
|
||||||
|
MCU 从地址 0 启动,每 3 个时钟周期执行一条指令,通过控制码字驱动:
|
||||||
|
|
||||||
|
* **AWG**:波形输出 + Pump 使能
|
||||||
|
* **DAQ**:数据采集 + 反馈上报/下发
|
||||||
|
|
||||||
|
MCU 执行退出指令后进入空闲状态。
|
||||||
|
|
||||||
|
### 数据采集阶段
|
||||||
|
|
||||||
|
数据采集与 MCU 运行同步启动。若采集量大,MCU 可能先于采集结束;数据继续写入缓存,上报模块持续推送,直至缓存清空。
|
||||||
|
|
||||||
|
可通过检测推送数据量是否达到目标数据量来判断实验完成。若数据量未知,需在 MCU 结束后等待一定时间,通过检测数据返回来判断。
|
||||||
|
|
||||||
|
**速率匹配**:为避免缓存写满,数据产生速率和数据回传速率须匹配。以解模 IQ 数据为例:
|
||||||
|
|
||||||
|
设 *T* 为数据产生间隔,*N* 为并行读出 Qubit 数,*F* 为 LVDS 有效速率,触发间隔须满足:
|
||||||
|
|
||||||
|
$$T > \frac{64 \times N}{F}$$
|
||||||
|
|
||||||
|
## 异常处理
|
||||||
|
|
||||||
|
### 中断管理
|
||||||
|
|
||||||
|
芯片通过 INT_STATUS 和 INT_MASK 寄存器管理中断。INT_STATUS = (INT_MASK & 实际状态) | INT_STATUS,需写寄存器清零。
|
||||||
|
|
||||||
|
### 中断处理流程
|
||||||
|
|
||||||
|
1. 读取 INT_STATUS,确认中断源
|
||||||
|
2. 记录异常信息(类型、时间、运行状态)
|
||||||
|
3. 按中断类型处理:
|
||||||
|
|
||||||
|
| 中断源 | 处理措施 |
|
||||||
|
|:-|:-|
|
||||||
|
| EXIT_IR | 正常退出,可启动下一轮实验 |
|
||||||
|
| ILLEGAL_ONE / ILLEGAL_ZERO | 检查并重新下载 MCU 程序,软复位 MCU |
|
||||||
|
| UNALIGN_SW / UNALIGN_LW | 检查 load/store 指令地址对齐 |
|
||||||
|
| LINK_DOWN | 检查 LVDS 物理连接和信号完整性,重新同步 |
|
||||||
|
| FORCE_AWG / FORCE_DAQ | 按外部控制器逻辑处理 |
|
||||||
|
|
||||||
|
4. 写 INT_STATUS 清零中断标志
|
||||||
|
5. 如需恢复运行:软复位 MCU 状态机并重新配置
|
||||||
|
|
||||||
|
### 异常预防
|
||||||
|
|
||||||
|
* MCU 程序写入后通过回读比对验证正确性
|
||||||
|
* LVDS 传输前确认收发双方已完成同步
|
||||||
|
* 实验运行期间禁止访问运维寄存器(系统/模拟/PLL 配置)
|
||||||
|
* 通过 INT_MASK 启用关注的中断源,屏蔽无关中断
|
||||||
|
* MCU 程序末尾必须包含退出指令 `exit x0, x0, 0`
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
# 寄存器定义
|
||||||
|
|
||||||
|
## 寄存器摘要
|
||||||
|
|
||||||
|
读出芯片偏移地址空间分配如下所示,用户可以通过读写相应地址来控制读出芯片功能和访问芯片状态。读出芯片地址空间包含系统配置状态、模拟配置状态、DAQ 配置状态、AWG 配置状态以及 PLL 配置状态五个部分。
|
||||||
|
|
||||||
|
@import "data/seg_define.csv" using render_address.py
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
|
||||||
|
**注 1:** DAQ 和 AWG 各自包含一个 MCU 模块,MCU 模块仅能够访问模块内部的控制器指令、控制器数据和寄存器配置,访问基地址分别重新映射到了 `0x000000`、`0x100000` 和 `0x200000`。
|
||||||
|
|
||||||
|
**注 2:** MCU 仅能够显示访问控制器数据和对应寄存器配置数据。对于控制器指令空间,控制器自动读取指令并运行,无法显式访问和修改数据。
|
||||||
|
|
||||||
|
**注 3:** 匹配滤波器参数和匹配滤波器权重分别对应 FPGA 和 ASIC 平台。FPGA 平台受限于计算资源有限,采用系数直接存储的方案,需要额外配置 `0x580000` 地址数据,此时 `0x500000` 地址中仅包络参数有效。
|
||||||
|
|
||||||
|
**注 4:** 系统状态配置、模拟配置状态、PLL 配置状态属于运维寄存器,实验时禁止修改。实验只需要修改 DAQ 配置状态和 AWG 配置状态。
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 操作码字定义
|
||||||
|
|
||||||
|
### 激励输出控制码字
|
||||||
|
|
||||||
|
AWG MCU 发出的控制码字格式(13 位):
|
||||||
|
|
||||||
|
| Bit | 字段名 | 说明 |
|
||||||
|
|:-:|:-|:-|
|
||||||
|
| [12] | PULSE_ONLY | 仅脉冲输出模式。置 1 时仅输出 Pump 脉冲,不输出波形 |
|
||||||
|
| [11] | PARAMETER_SEL | 参数选择。0: 使用默认参数;1: 使用码字携带的参数 |
|
||||||
|
| [10] | NCO_CLR_EN | NCO 相位清零使能。置 1 时清零 NCO 相位累加器 |
|
||||||
|
| [9] | MARK_EN | 标记输出使能。置 1 时在当前波形段输出期间使能标记信号 |
|
||||||
|
| [8] | PUMP_EN | Pump 使能。置 1 时触发 Pump 脉冲输出 |
|
||||||
|
| [7:0] | WAVE_ID | 波形段 ID。通过波形映射表查找对应的波形段起始地址和长度 |
|
||||||
|
|
||||||
|
### 采集处理控制码字
|
||||||
|
|
||||||
|
DAQ MCU 发出的控制码字格式(32 位):
|
||||||
|
|
||||||
|
| Bit | 字段名 | 说明 |
|
||||||
|
|:-:|:-|:-|
|
||||||
|
| [31:16] | QUBIT_EN | 16 量子比特使能。每比特对应一个量子比特,1 表示使能对应通道 |
|
||||||
|
| [15] | COUNT_SAVE_EN | 计数统计保存使能 |
|
||||||
|
| [14] | STATE_SAVE_EN | 态结果保存使能 |
|
||||||
|
| [13] | IQ_SAVE_EN | IQ 数据保存使能 |
|
||||||
|
| [12] | WAVE_SAVE_EN | 原始波形保存使能 |
|
||||||
|
| [11] | MTF_IDX_SEL | 匹配滤波器索引选择 |
|
||||||
|
| [10] | DDS_FPW_SEL | DDS 频率/相位字选择 |
|
||||||
|
| [9] | STATE_CLR_VAL | 态统计清零值 |
|
||||||
|
| [8] | DEMOD_CLR_VAL | 解模累加器清零值 |
|
||||||
|
| [7] | GLB_FB_VAL | 全局反馈值(下发到外部芯片) |
|
||||||
|
| [6] | LOC_FB_VAL | 局部反馈值(片上反馈控制) |
|
||||||
|
| [5] | STATE_STS_VAL | 态统计状态值 |
|
||||||
|
| [4] | DEMOD_SUM_VAL | 解模求和值 |
|
||||||
|
| [3:0] | PARA_ID | 读出参数 ID。指向 DAQ_PAR 中的参数组 |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
对于多比特解模,DAQ 按每个量子比特通道执行解模运算,运算顺序为 Qubit 0 → Qubit 15。数据存储顺序与解模顺序一致。态判定在解模完成后进行,态统计在态判定完成后进行。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 寄存器/存储详细定义
|
||||||
|
|
||||||
|
读出芯片的详细寄存器/存储定义参考 [读出芯片 IDS 表](../script/读出子系统IDS表.xls)。相应的驱动软件配置文件参考 [读出芯片 IDS 表 JSON](../data/ids.json)。
|
||||||
|
|
||||||
|
@import "data/ids.json" using render_registers.py
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
# 封装与机械尺寸
|
||||||
|
|
||||||
|
## 封装外形
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 封装参数
|
||||||
|
|
||||||
|
| 参数 | 规格 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 封装类型 | CSP-BGA | — |
|
||||||
|
| 焊球间距 | 1.0 | mm |
|
||||||
|
| 焊球直径 | 0.5 | mm |
|
||||||
|
| 焊球数量 | 13 × 13 = 169 | 个 |
|
||||||
|
| 基板尺寸 | 14.0 × 14.0 | mm |
|
||||||
|
|
||||||
|
## 推荐焊接回流曲线
|
||||||
|
|
||||||
|
| 阶段 | 温度范围 | 持续时间 | 单位 |
|
||||||
|
|:-|:-|:-|:-|
|
||||||
|
| 预热 | — | — | °C / s |
|
||||||
|
| 恒温 | — | — | °C / s |
|
||||||
|
| 回流峰值 | — | — | °C / s |
|
||||||
|
| 冷却 | — | — | °C / s |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
推荐回流曲线参数待封装厂家提供后补充。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 标识信息
|
||||||
|
|
||||||
|
| 位置 | 内容 |
|
||||||
|
|:-|:-|
|
||||||
|
| 顶面 | 芯片型号、批号、生产日期 |
|
||||||
|
| 底面 | — |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
芯片标识格式待确认后补充。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 存储与搬运
|
||||||
|
|
||||||
|
| 参数 | 规格 | 单位 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 存储温度范围 | −65 ~ +150 | °C |
|
||||||
|
| MSL 等级 | — | — |
|
||||||
|
| 防潮包装要求 | — | — |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
MSL 等级和防潮要求待封装设计确认后补充。
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
# 附录 A:运维操作手册
|
||||||
|
|
||||||
|
本章节概述了读出芯片的运维校准流程。完整内容参见 [读出子系统运维操作手册](../../readout_operate/读出子系统运维操作手册.md)。
|
||||||
|
|
||||||
|
## 校准流程概要
|
||||||
|
|
||||||
|
读出芯片在上电后需要执行以下校准步骤:
|
||||||
|
|
||||||
|
1. **通道延迟校准**:校准各通道的模拟和数字延迟,确保多通道间时序对齐
|
||||||
|
2. **输出同步校准**:校准 AWG 输出通道的同步精度
|
||||||
|
3. **采集同步校准**:校准 ADC 采样时钟与 DAQ 触发之间的同步
|
||||||
|
4. **PLL 锁定确认**:验证 PLL 输出频率锁定在目标范围内
|
||||||
|
|
||||||
|
## 硬件安装注意事项
|
||||||
|
|
||||||
|
* 确认所有供电轨上电顺序正确(内核供电 → IO 供电 → 时钟 → 复位)
|
||||||
|
* 检查 SPI 和 LVDS 线缆连接
|
||||||
|
* 确认散热条件满足要求
|
||||||
|
|
||||||
|
## 故障诊断
|
||||||
|
|
||||||
|
常见故障及排查方向:
|
||||||
|
|
||||||
|
| 故障现象 | 可能原因 | 排查步骤 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| SPI 无法通信 | CSN/SCLK 时序异常、CHIP_ID 配置错误 | 检查 SPI 四线连接、上拉电阻、CHIP_ID 跳线 |
|
||||||
|
| LVDS 无法同步 | 同步码发送不足、信号质量差 | 检查差分线缆、增加同步码发送次数 |
|
||||||
|
| DAC 无输出 | PLL 未锁定、DAC 配置未完成 | 检查参考时钟、确认 PLL 锁定指示灯、回读 DAC 配置 |
|
||||||
|
| ADC 采集异常 | 参考电压配置错误、输入信号超量程 | 检查 ADC_REF_SENSE 电平、确认输入信号幅度 |
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
# 附录 B:历史无关配置集
|
||||||
|
|
||||||
|
本章节概述了读出芯片的常用寄存器配置用例。完整内容参见 [读出子系统历史无关配置集](../../readout_config_set/读出子系统历史无关配置集.md)。
|
||||||
|
|
||||||
|
## 激励通道配置
|
||||||
|
|
||||||
|
### 直接波形输出
|
||||||
|
|
||||||
|
配置 AWG 以 NRZ 直出模式输出基带波形:
|
||||||
|
|
||||||
|
1. 写波形数据到 AWG_WVE 地址空间
|
||||||
|
2. 配置波形映射表 (AWG_IDX)
|
||||||
|
3. 编程 MCU 指令 (MCU_INS),在码字中设置 WAVE_ID
|
||||||
|
4. 设置控制寄存器 (AWG_REG) 选择 NRZ 直出模式
|
||||||
|
5. 触发同步信号启动
|
||||||
|
|
||||||
|
### 调制波形输出
|
||||||
|
|
||||||
|
配置 AWG 以 MIX 模式输出调制波形:
|
||||||
|
|
||||||
|
1. 同上写入波形数据和映射表
|
||||||
|
2. 配置 NCO 频率控制字
|
||||||
|
3. 设置控制寄存器选择 MIX 模式
|
||||||
|
4. 编程 MCU 指令,触发波形输出
|
||||||
|
|
||||||
|
## 采集通道配置
|
||||||
|
|
||||||
|
### 波形采集模式
|
||||||
|
|
||||||
|
采集 ADC 原始波形数据:
|
||||||
|
- 设置 DAQ_REG 为波形采集模式
|
||||||
|
- 配置采集触发参数
|
||||||
|
- MCU 码字中使能 WAVE_SAVE_EN
|
||||||
|
|
||||||
|
### IQ 数据采集模式
|
||||||
|
|
||||||
|
解模获取 IQ 复数数据:
|
||||||
|
- 配置解模参数 (DAQ_PAR)
|
||||||
|
- 写入匹配滤波器系数 (DAQ_FLT)
|
||||||
|
- MCU 码字中使能 IQ_SAVE_EN
|
||||||
|
- 选择对应的 PARA_ID
|
||||||
|
|
||||||
|
### 态数据采集模式
|
||||||
|
|
||||||
|
获取量子态判定结果:
|
||||||
|
- 完成 IQ 解模配置
|
||||||
|
- 配置态判定阈值
|
||||||
|
- MCU 码字中使能 STATE_SAVE_EN
|
||||||
|
|
||||||
|
## Pump 通道配置
|
||||||
|
|
||||||
|
* **单次脉冲输出**:MCU 码字中 PUMP_EN = 1,配置脉宽参数
|
||||||
|
* **连续脉冲输出**:MCU 程序循环发出 PUMP_EN 码字
|
||||||
|
|
||||||
|
## 功能项汇总
|
||||||
|
|
||||||
|
| 通道 | 配置项 | 说明 |
|
||||||
|
|:-|:-|:-|
|
||||||
|
| 激励 | 直接波形输出 | NRZ 直出基带波形 |
|
||||||
|
| 激励 | 调制波形输出 | MIX 模式混频输出 |
|
||||||
|
| 采集 | 波形采集 | 原始 ADC 数据 |
|
||||||
|
| 采集 | IQ 采集 | 解模 IQ 数据 |
|
||||||
|
| 采集 | 态采集 | 态判定结果 |
|
||||||
|
| 采集 | 计数采集 | 态统计计数 |
|
||||||
|
| 采集 | 态反馈 | 读出态反馈控制 |
|
||||||
|
| Pump | 单次输出 | 单次 Pump 使能 |
|
||||||
|
| Pump | 连续输出 | 连续 Pump 使能 |
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
以上配置用例均为"历史无关"配置,即无论芯片之前处于何种状态,按照用例流程配置后均可保证功能正确。这一特性对于自动化测试和批量实验至关重要。
|
||||||
|
</div>
|
||||||
|
|
@ -133,7 +133,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"msmt_exci": {
|
"msmt_exc": {
|
||||||
"0": {
|
"0": {
|
||||||
"Exaddr": 0,
|
"Exaddr": 0,
|
||||||
"Cid": 0,
|
"Cid": 0,
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
"""Code block renderer — standalone pre-markdown step.
|
||||||
|
|
||||||
|
Usage in build pipeline:
|
||||||
|
md_text = render_code_blocks(md_text, project_dir)
|
||||||
|
html = markdown.markdown(md_text, extensions=[...])
|
||||||
|
|
||||||
|
Syntax in chapters:
|
||||||
|
```schemdraw
|
||||||
|
import schemdraw
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Runs BEFORE markdown parsing, so avoids priority conflicts with
|
||||||
|
fenced_code / codehilite extensions.
|
||||||
|
|
||||||
|
Renders live in doc_builder/renderers/<tag>.py.
|
||||||
|
Each exports: render(code_text, project_dir) -> HTML string.
|
||||||
|
"""
|
||||||
|
import importlib.util
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from html import unescape as html_unescape
|
||||||
|
|
||||||
|
CODE_BLOCK_RE = re.compile(
|
||||||
|
r'(?:^|\n)```(\w+)\s*\n(.*?)\n```(?:\n|$)',
|
||||||
|
re.DOTALL,
|
||||||
|
)
|
||||||
|
|
||||||
|
PASSTHROUGH = {'mermaid', 'wavedrom', 'python', 'bash', 'json', 'yaml', 'ascii'}
|
||||||
|
|
||||||
|
|
||||||
|
def _load_renderer(lang, project_dir):
|
||||||
|
rp = project_dir / 'doc_builder' / 'renderers' / f'{lang}.py'
|
||||||
|
if not rp.exists():
|
||||||
|
return None
|
||||||
|
spec = importlib.util.spec_from_file_location(
|
||||||
|
f'render_{lang}', str(rp)
|
||||||
|
)
|
||||||
|
mod = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(mod)
|
||||||
|
return getattr(mod, 'render', None)
|
||||||
|
|
||||||
|
|
||||||
|
def render_code_blocks(text, project_dir):
|
||||||
|
"""Find ```lang blocks, dispatch to renderers, replace inline."""
|
||||||
|
result = []
|
||||||
|
last_end = 0
|
||||||
|
|
||||||
|
for match in CODE_BLOCK_RE.finditer(text):
|
||||||
|
lang = match.group(1)
|
||||||
|
code = match.group(2)
|
||||||
|
|
||||||
|
result.append(text[last_end:match.start()])
|
||||||
|
|
||||||
|
if lang in PASSTHROUGH:
|
||||||
|
result.append(match.group(0))
|
||||||
|
else:
|
||||||
|
renderer = _load_renderer(lang, project_dir)
|
||||||
|
if renderer is None:
|
||||||
|
result.append(match.group(0))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
code_text = html_unescape(code.strip())
|
||||||
|
html = renderer(code_text, project_dir)
|
||||||
|
result.append(f'\n{html}\n')
|
||||||
|
except Exception as e:
|
||||||
|
result.append(
|
||||||
|
f'\n<div class="warning">'
|
||||||
|
f'{lang} render error: {e}'
|
||||||
|
f'</div>\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
last_end = match.end()
|
||||||
|
|
||||||
|
result.append(text[last_end:])
|
||||||
|
return ''.join(result)
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
"""Python-Markdown extension: image sizing.
|
||||||
|
|
||||||
|
Syntax:
|
||||||
|
{w=50%} → width 50%, height auto (proportional)
|
||||||
|
{h=50%} → height 50%, width auto (proportional)
|
||||||
|
{w=50%, h=300} → width 50%, max-height 300px (pixel h)
|
||||||
|
 → default: width 80%, height auto
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from markdown.extensions import Extension
|
||||||
|
from markdown.inlinepatterns import ImageInlineProcessor
|
||||||
|
|
||||||
|
IMG_RE = (
|
||||||
|
r'\!\[(?P<alt>.*?)\]\((?P<src>[^)]+)\)'
|
||||||
|
r'(?:\{'
|
||||||
|
r'(?:w=(?P<w>\d+%))?'
|
||||||
|
r'(?:,\s*)?'
|
||||||
|
r'(?:h=(?P<h>\d+)(?:%|px)?)?'
|
||||||
|
r'\})?'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SizedImageProcessor(ImageInlineProcessor):
|
||||||
|
|
||||||
|
def handleMatch(self, m, data):
|
||||||
|
alt = m.group('alt')
|
||||||
|
src = m.group('src')
|
||||||
|
w = m.group('w')
|
||||||
|
h = m.group('h')
|
||||||
|
|
||||||
|
src = src.replace('../assets/', 'assets/')
|
||||||
|
src = src.replace('../circuits/output/', 'assets/')
|
||||||
|
|
||||||
|
if w and h:
|
||||||
|
# Both specified: h could be % or px
|
||||||
|
style = f'width:{w}; height:{h}; max-width:none; max-height:none'
|
||||||
|
elif w:
|
||||||
|
# w only: auto height (proportional)
|
||||||
|
style = f'width:{w}; height:auto; max-width:none; max-height:none'
|
||||||
|
elif h:
|
||||||
|
# h only: auto width (proportional)
|
||||||
|
style = f'height:{h}; width:auto; max-width:none; max-height:none'
|
||||||
|
else:
|
||||||
|
# Default: 80%
|
||||||
|
style = 'width:80%; height:auto; max-width:none; max-height:none'
|
||||||
|
|
||||||
|
img_tag = f'<img src="{src}" alt="{alt}" style="{style}">'
|
||||||
|
el = self.md.htmlStash.store(img_tag)
|
||||||
|
return el, m.start(0), m.end(0)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageRowProcessor(Extension):
|
||||||
|
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
md.inlinePatterns.register(
|
||||||
|
SizedImageProcessor(IMG_RE, md), 'image_sized', 160,
|
||||||
|
)
|
||||||
|
md.inlinePatterns.deregister('image_link')
|
||||||
|
|
||||||
|
|
||||||
|
def makeExtension(**kwargs):
|
||||||
|
return ImageRowProcessor(**kwargs)
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
"""@import handler — thin dispatcher with plugin architecture.
|
||||||
|
|
||||||
|
Syntax:
|
||||||
|
@import "data/file.csv" → default: code display with line numbers
|
||||||
|
@import "data/file.csv" as table → load doc_builder/render_table.py, call render()
|
||||||
|
@import "data/file.json" as registers → load doc_builder/render_registers.py
|
||||||
|
@import "data/file.yaml" as requirements → load doc_builder/render_requirements.py
|
||||||
|
|
||||||
|
How 'as' works:
|
||||||
|
as <name> → importlib loads doc_builder/render_<name>.py
|
||||||
|
calls render(filepath) → returns HTML string
|
||||||
|
|
||||||
|
No 'as' → default code viewer with line numbers
|
||||||
|
|
||||||
|
Each project provides its own render_<name>.py scripts in doc_builder/.
|
||||||
|
Built-in renderers (table, bga, address, registers, requirements) are
|
||||||
|
included and can be copied between projects.
|
||||||
|
"""
|
||||||
|
import importlib
|
||||||
|
import re
|
||||||
|
import traceback
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
IMPORT_RE = re.compile(
|
||||||
|
r'^@import\s+"([^"]+)"(?:\s+using\s+([\w.]+))?\s*$',
|
||||||
|
re.MULTILINE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def handle(import_path, renderer_name, base_dir, process_chapter_fn):
|
||||||
|
"""Resolve @import and dispatch to renderer.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
import_path: file path from @import directive
|
||||||
|
renderer_name: name after 'as' (e.g. 'table', 'registers'), or None
|
||||||
|
base_dir: project root for path resolution
|
||||||
|
process_chapter_fn: callback for recursive .md processing
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HTML string
|
||||||
|
"""
|
||||||
|
fp = (base_dir / import_path).resolve()
|
||||||
|
if not fp.exists():
|
||||||
|
return (
|
||||||
|
f'<div class="warning">'
|
||||||
|
f'@import file not found: {import_path}'
|
||||||
|
f'</div>'
|
||||||
|
)
|
||||||
|
|
||||||
|
# .md files are always processed recursively (no renderer script)
|
||||||
|
if fp.suffix.lower() == '.md':
|
||||||
|
md_text = fp.read_text(encoding='utf-8')
|
||||||
|
return process_chapter_fn(md_text)
|
||||||
|
|
||||||
|
# No as specified → default: code display with line numbers
|
||||||
|
if not renderer_name:
|
||||||
|
return _render_default(fp)
|
||||||
|
|
||||||
|
# as <name> → load renderer script and call render()
|
||||||
|
try:
|
||||||
|
renderer = _load_renderer(renderer_name, base_dir)
|
||||||
|
return renderer(fp)
|
||||||
|
except RendererNotFound:
|
||||||
|
# Graceful fallback: show default code view + note
|
||||||
|
note = (
|
||||||
|
f'<div class="note">'
|
||||||
|
f'Renderer script <code>doc_builder/{renderer_name}</code> not found. '
|
||||||
|
f'Showing default code view. '
|
||||||
|
f'Create this file with a <code>render(filepath)</code> function '
|
||||||
|
f'to customize rendering.'
|
||||||
|
f'</div>'
|
||||||
|
)
|
||||||
|
return note + _render_default(fp)
|
||||||
|
except Exception as e:
|
||||||
|
return (
|
||||||
|
f'<div class="warning">'
|
||||||
|
f'@import renderer error ({import_path} as {renderer_name}): {e}'
|
||||||
|
f'<pre>{traceback.format_exc()}</pre>'
|
||||||
|
f'</div>'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def process_imports(md_text, base_dir, process_chapter_fn):
|
||||||
|
"""Replace all @import directives in md_text with rendered HTML."""
|
||||||
|
def _replace(match):
|
||||||
|
path = match.group(1)
|
||||||
|
hint = match.group(2) # may be None
|
||||||
|
return handle(path, hint, base_dir, process_chapter_fn)
|
||||||
|
return IMPORT_RE.sub(_replace, md_text)
|
||||||
|
|
||||||
|
|
||||||
|
# ---- Renderer plugin loader ----
|
||||||
|
|
||||||
|
class RendererNotFound(Exception):
|
||||||
|
"""Raised when a render_<name>.py script does not exist."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _load_renderer(name, base_dir):
|
||||||
|
"""Load a renderer script from doc_builder/<name>.
|
||||||
|
|
||||||
|
The module must export: render(filepath) → HTML string
|
||||||
|
"""
|
||||||
|
doc_builder = base_dir / 'doc_builder'
|
||||||
|
script = doc_builder / name
|
||||||
|
|
||||||
|
if not script.exists():
|
||||||
|
raise RendererNotFound(
|
||||||
|
f'doc_builder/{name} not found'
|
||||||
|
)
|
||||||
|
|
||||||
|
spec = importlib.util.spec_from_file_location(
|
||||||
|
name.replace('.', '_'), str(script)
|
||||||
|
)
|
||||||
|
mod = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(mod)
|
||||||
|
|
||||||
|
if not hasattr(mod, 'render'):
|
||||||
|
raise RendererNotFound(
|
||||||
|
f'doc_builder/{name} has no render() function'
|
||||||
|
)
|
||||||
|
|
||||||
|
return mod.render
|
||||||
|
|
||||||
|
|
||||||
|
# ---- Default renderer: code with line numbers ----
|
||||||
|
|
||||||
|
def _render_default(filepath):
|
||||||
|
"""Display file content as code with line numbers."""
|
||||||
|
try:
|
||||||
|
with open(filepath, encoding='utf-8') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return '<div class="warning">Cannot display binary file.</div>'
|
||||||
|
|
||||||
|
from html import escape
|
||||||
|
ext = filepath.suffix.lstrip('.').upper()
|
||||||
|
html = [
|
||||||
|
f'<div class="code-block">',
|
||||||
|
f'<div class="code-header">{filepath.name} ({len(lines)} lines)</div>',
|
||||||
|
f'<pre class="code-lines">',
|
||||||
|
]
|
||||||
|
for i, line in enumerate(lines, 1):
|
||||||
|
# escape HTML but keep the line content
|
||||||
|
escaped = escape(line.rstrip('\n\r'))
|
||||||
|
html.append(
|
||||||
|
f'<span class="ln">{i:4d}</span> '
|
||||||
|
f'<span class="lc">{escaped}</span>'
|
||||||
|
)
|
||||||
|
html.append('</pre></div>')
|
||||||
|
return '\n'.join(html)
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
"""Address map table renderer — for seg_define.csv style files."""
|
||||||
|
import csv
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
|
||||||
|
def render(filepath):
|
||||||
|
"""Render CSV as address map table, merging repeated function cells."""
|
||||||
|
rows = []
|
||||||
|
with open(str(filepath), encoding='utf-8') as f:
|
||||||
|
for row in csv.DictReader(f):
|
||||||
|
rows.append({
|
||||||
|
k.strip(): v.strip() if v else ''
|
||||||
|
for k, v in row.items()
|
||||||
|
})
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return '<p><em>empty file</em></p>'
|
||||||
|
|
||||||
|
# Merge consecutive rows with '^' in 功能划分
|
||||||
|
segs, prev = [], ''
|
||||||
|
for r in rows:
|
||||||
|
func = r.get('功能划分', '')
|
||||||
|
if func == '^':
|
||||||
|
func = prev
|
||||||
|
else:
|
||||||
|
prev = func
|
||||||
|
segs.append({
|
||||||
|
'功能划分': func,
|
||||||
|
'子模块': r.get('子模块', ''),
|
||||||
|
'开始地址': r.get('开始地址', ''),
|
||||||
|
'大小': r.get('大小', ''),
|
||||||
|
})
|
||||||
|
|
||||||
|
cols = ['功能划分', '子模块', '开始地址', '大小']
|
||||||
|
h = ['<table><thead><tr>']
|
||||||
|
for c in cols:
|
||||||
|
h.append(f'<th>{escape(c)}</th>')
|
||||||
|
h.append('</tr></thead><tbody>')
|
||||||
|
for s in segs:
|
||||||
|
h.append('<tr>')
|
||||||
|
for c in cols:
|
||||||
|
h.append(f'<td>{escape(str(s.get(c, "")))}</td>')
|
||||||
|
h.append('</tr>')
|
||||||
|
h.append('</tbody></table>')
|
||||||
|
return '\n'.join(h)
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
"""BGA ball grid renderer — for pin_loc.csv style files."""
|
||||||
|
import csv
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
|
||||||
|
def render(filepath):
|
||||||
|
"""Render CSV as BGA ball grid table."""
|
||||||
|
rows = []
|
||||||
|
with open(str(filepath), encoding='utf-8') as f:
|
||||||
|
for row in csv.reader(f):
|
||||||
|
rows.append([c.strip() for c in row])
|
||||||
|
|
||||||
|
if len(rows) < 2:
|
||||||
|
return '<p><em>empty or malformed file</em></p>'
|
||||||
|
|
||||||
|
ncols = len(rows[0]) - 1
|
||||||
|
h = ['<table class="compact pin-grid"><thead><tr><th></th>']
|
||||||
|
for c in range(1, ncols + 1):
|
||||||
|
h.append(f'<th class="text-center">{c}</th>')
|
||||||
|
h.append('</tr></thead><tbody>')
|
||||||
|
|
||||||
|
for r in rows[1:]:
|
||||||
|
if not r:
|
||||||
|
continue
|
||||||
|
h.append(
|
||||||
|
f'<tr><th class="text-center">{escape(r[0])}</th>'
|
||||||
|
)
|
||||||
|
for c in range(1, ncols + 1):
|
||||||
|
val = r[c] if c < len(r) else ''
|
||||||
|
h.append(
|
||||||
|
f'<td class="text-center text-mono"'
|
||||||
|
f' style="font-size:6pt">{escape(val)}</td>'
|
||||||
|
)
|
||||||
|
h.append('</tr>')
|
||||||
|
h.append('</tbody></table>')
|
||||||
|
return '\n'.join(h)
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
"""Register definition (ids.json) → HTML tables."""
|
||||||
|
import json
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
|
||||||
|
MODULE_ORDER = [
|
||||||
|
'SYS_REG', 'SYS_ANA', 'SYS_PLL',
|
||||||
|
'DAQ_REG', 'DAQ_PAR', 'DAQ_FLT',
|
||||||
|
'AWG_REG', 'TRIG_CTRL', 'PUMP_REG', 'MIXER_REG',
|
||||||
|
]
|
||||||
|
|
||||||
|
MODULE_DESC = {
|
||||||
|
'SYS_REG': '系统控制寄存器', 'SYS_ANA': '模拟配置寄存器',
|
||||||
|
'SYS_PLL': 'PLL 配置寄存器', 'DAQ_REG': 'DAQ 控制寄存器',
|
||||||
|
'DAQ_PAR': 'DAQ 读出参数配置', 'DAQ_FLT': 'DAQ 匹配滤波器系数',
|
||||||
|
'AWG_REG': 'AWG 控制寄存器', 'TRIG_CTRL': '触发控制寄存器',
|
||||||
|
'PUMP_REG': 'Pump 控制寄存器', 'MIXER_REG': '混频器控制寄存器',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def eh(s):
|
||||||
|
return escape(str(s))
|
||||||
|
|
||||||
|
|
||||||
|
def _bits_str(bits):
|
||||||
|
if not bits:
|
||||||
|
return ''
|
||||||
|
if len(bits) == 1 or bits[0] == bits[-1]:
|
||||||
|
return f'[{bits[0]}]'
|
||||||
|
return f'[{bits[0]}:{bits[-1]}]'
|
||||||
|
|
||||||
|
|
||||||
|
def _range_str(r):
|
||||||
|
if not r or not r.get('value'):
|
||||||
|
return ''
|
||||||
|
t, v = r.get('type', 'str'), r.get('value', '')
|
||||||
|
if t == 'str':
|
||||||
|
if v == 'ANY':
|
||||||
|
return '<em>任意</em>'
|
||||||
|
if v == 'NA':
|
||||||
|
return '<em>—</em>'
|
||||||
|
return eh(str(v))
|
||||||
|
if t == 'list' and isinstance(v, list):
|
||||||
|
return f'{v[0]} ~ {v[1]}'
|
||||||
|
if t == 'set' and isinstance(v, list):
|
||||||
|
return ', '.join(str(x) for x in v)
|
||||||
|
return eh(str(v))
|
||||||
|
|
||||||
|
|
||||||
|
def _perm_badge(p):
|
||||||
|
badges = {
|
||||||
|
'RW': '<span class="perm-rw">RW</span>',
|
||||||
|
'RO': '<span class="perm-ro">RO</span>',
|
||||||
|
'WC': '<span class="perm-wc">WC</span>',
|
||||||
|
}
|
||||||
|
return badges.get(p, eh(p))
|
||||||
|
|
||||||
|
|
||||||
|
def render(json_path):
|
||||||
|
"""Load ids.json and render all register tables as HTML."""
|
||||||
|
with open(json_path, encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
modules = data.get('Modules', {})
|
||||||
|
|
||||||
|
html = []
|
||||||
|
for mod_name in MODULE_ORDER:
|
||||||
|
if mod_name not in modules:
|
||||||
|
continue
|
||||||
|
entries = modules[mod_name]
|
||||||
|
desc = MODULE_DESC.get(mod_name, '')
|
||||||
|
html.append(
|
||||||
|
f'<h3 id="reg-{mod_name.lower()}">{mod_name} — {desc}</h3>'
|
||||||
|
)
|
||||||
|
html.append(f'<p>共 {len(entries)} 个寄存器/存储段。</p>')
|
||||||
|
|
||||||
|
for seg_name, seg in entries.items():
|
||||||
|
addr = seg.get('OffsetAddress', '')
|
||||||
|
perm = seg.get('Permission', '')
|
||||||
|
sd = seg.get('SegDescription', '')
|
||||||
|
fields = seg.get('Fields', [])
|
||||||
|
|
||||||
|
html.append(
|
||||||
|
f'<h4 id="reg-{seg_name}">{seg_name.upper()}</h4>'
|
||||||
|
)
|
||||||
|
html.append(
|
||||||
|
f'<p class="reg-summary">'
|
||||||
|
f'<strong>偏移地址:</strong><code>{eh(addr)}</code> '
|
||||||
|
f'<strong>权限:</strong>{_perm_badge(perm)} '
|
||||||
|
f'<strong>描述:</strong>{eh(sd)}</p>'
|
||||||
|
)
|
||||||
|
|
||||||
|
if fields:
|
||||||
|
html.append(
|
||||||
|
'<table class="compact"><thead><tr>'
|
||||||
|
'<th style="width:11%">Bits</th>'
|
||||||
|
'<th style="width:18%">Field Name</th>'
|
||||||
|
'<th style="width:14%">Reset Value</th>'
|
||||||
|
'<th style="width:12%">Range</th>'
|
||||||
|
'<th>Description</th>'
|
||||||
|
'</tr></thead><tbody>'
|
||||||
|
)
|
||||||
|
for f in fields:
|
||||||
|
b = f.get('Bits', [])
|
||||||
|
html.append(
|
||||||
|
f'<tr>'
|
||||||
|
f'<td class="bits">{_bits_str(b)}</td>'
|
||||||
|
f'<td class="text-mono">{eh(f.get("FieldName", ""))}</td>'
|
||||||
|
f'<td class="reset-val">{eh(f.get("ResetValue", ""))}</td>'
|
||||||
|
f'<td>{_range_str(f.get("Range"))}</td>'
|
||||||
|
f'<td>{eh(f.get("FieldDescription", ""))}</td>'
|
||||||
|
f'</tr>'
|
||||||
|
)
|
||||||
|
html.append('</tbody></table>')
|
||||||
|
html.append('')
|
||||||
|
return '\n'.join(html)
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
"""YAML requirements renderer — for request_*.yaml style files."""
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
|
||||||
|
def render(filepath):
|
||||||
|
"""Render YAML requirements as grouped tables (F_/P_/S_ sections)."""
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError:
|
||||||
|
return '<div class="warning">pyyaml not installed. Run: pip install pyyaml</div>'
|
||||||
|
|
||||||
|
with open(str(filepath), encoding='utf-8') as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return f'<pre><code>{escape(str(data))}</code></pre>'
|
||||||
|
|
||||||
|
sections = {
|
||||||
|
'F_': ('功能需求', []),
|
||||||
|
'P_': ('性能需求', []),
|
||||||
|
'S_': ('规格需求', []),
|
||||||
|
}
|
||||||
|
other = []
|
||||||
|
|
||||||
|
for key, val in data.items():
|
||||||
|
if not isinstance(val, dict):
|
||||||
|
continue
|
||||||
|
name = val.get('name', key)
|
||||||
|
desc = val.get('description', '')
|
||||||
|
limit = val.get('limit', None)
|
||||||
|
|
||||||
|
limit_str = ''
|
||||||
|
if limit and isinstance(limit, dict):
|
||||||
|
parts = []
|
||||||
|
if 'min' in limit and limit['min'] is not None:
|
||||||
|
parts.append(f'>= {limit["min"]}')
|
||||||
|
if 'max' in limit and limit['max'] is not None:
|
||||||
|
parts.append(f'<= {limit["max"]}')
|
||||||
|
if 'value' in limit:
|
||||||
|
parts.append(str(limit['value']))
|
||||||
|
if 'unit' in limit:
|
||||||
|
parts.append(limit['unit'])
|
||||||
|
if 'count' in limit:
|
||||||
|
parts.append(f'x{limit["count"]}')
|
||||||
|
limit_str = ' '.join(parts)
|
||||||
|
|
||||||
|
entry = {'id': key, 'name': name, 'desc': desc, 'limit': limit_str}
|
||||||
|
placed = False
|
||||||
|
for prefix in sections:
|
||||||
|
if key.startswith(prefix):
|
||||||
|
sections[prefix][1].append(entry)
|
||||||
|
placed = True
|
||||||
|
break
|
||||||
|
if not placed:
|
||||||
|
other.append(entry)
|
||||||
|
|
||||||
|
html = []
|
||||||
|
for prefix, (label, items) in sections.items():
|
||||||
|
if not items:
|
||||||
|
continue
|
||||||
|
html.append(f'<h3>{label}({len(items)} 项)</h3>')
|
||||||
|
html.append(
|
||||||
|
'<table><thead><tr>'
|
||||||
|
'<th style="width:16%">ID</th>'
|
||||||
|
'<th style="width:16%">名称</th>'
|
||||||
|
'<th>描述</th>'
|
||||||
|
'<th style="width:20%">指标</th>'
|
||||||
|
'</tr></thead><tbody>'
|
||||||
|
)
|
||||||
|
for e in items:
|
||||||
|
html.append(
|
||||||
|
f'<tr>'
|
||||||
|
f'<td class="text-mono">{escape(e["id"])}</td>'
|
||||||
|
f'<td>{escape(e["name"])}</td>'
|
||||||
|
f'<td>{escape(e["desc"])}</td>'
|
||||||
|
f'<td>{escape(e["limit"])}</td>'
|
||||||
|
f'</tr>'
|
||||||
|
)
|
||||||
|
html.append('</tbody></table>')
|
||||||
|
return '\n'.join(html)
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""Generic CSV table renderer. Used for all CSV @import unless overridden."""
|
||||||
|
import csv
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
|
||||||
|
def render(filepath):
|
||||||
|
"""Load CSV and render as HTML table."""
|
||||||
|
rows = []
|
||||||
|
with open(str(filepath), encoding='utf-8') as f:
|
||||||
|
for row in csv.DictReader(f):
|
||||||
|
rows.append({
|
||||||
|
k.strip(): v.strip() if v else ''
|
||||||
|
for k, v in row.items()
|
||||||
|
})
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return '<p><em>empty file</em></p>'
|
||||||
|
|
||||||
|
cols = list(rows[0].keys())
|
||||||
|
h = ['<table><thead><tr>']
|
||||||
|
for c in cols:
|
||||||
|
h.append(f'<th>{escape(c)}</th>')
|
||||||
|
h.append('</tr></thead><tbody>')
|
||||||
|
for r in rows:
|
||||||
|
h.append('<tr>')
|
||||||
|
for c in cols:
|
||||||
|
h.append(f'<td>{escape(str(r.get(c, "")))}</td>')
|
||||||
|
h.append('</tr>')
|
||||||
|
h.append('</tbody></table>')
|
||||||
|
return '\n'.join(h)
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
"""Schemdraw code block renderer.
|
||||||
|
|
||||||
|
Executes Python schemdraw code from a chapter code block and returns SVG.
|
||||||
|
|
||||||
|
Usage in markdown:
|
||||||
|
```schemdraw
|
||||||
|
import schemdraw
|
||||||
|
from schemdraw import elements as e
|
||||||
|
with schemdraw.Drawing(show=False) as d:
|
||||||
|
d += e.Resistor().right().label('R1')
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
import base64
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import textwrap
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def render(code: str, project_dir: Path = None) -> str:
|
||||||
|
"""Execute schemdraw code, return inline SVG as HTML <img> tag.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code: Python source code using schemdraw
|
||||||
|
project_dir: project root (unused, kept for interface consistency)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HTML string with inline base64 SVG image
|
||||||
|
"""
|
||||||
|
# Write code to a temp script and execute, capturing SVG output
|
||||||
|
wrapped = textwrap.dedent(code).strip()
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
suffix='.svg', mode='w+', encoding='utf-8', delete=False
|
||||||
|
) as tmp:
|
||||||
|
svg_path = Path(tmp.name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Execute the schemdraw code as a subprocess for isolation.
|
||||||
|
# The script must produce 'OUTPUT: <svg filename>' on the last line,
|
||||||
|
# or we inject a save hook.
|
||||||
|
script = _wrap_code(wrapped, str(svg_path))
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, '-c', script],
|
||||||
|
capture_output=True, text=True, timeout=30,
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
return (
|
||||||
|
f'<div class="warning">'
|
||||||
|
f'Schemdraw error:<pre>{result.stderr[:500] or result.stdout[:500]}</pre>'
|
||||||
|
f'</div>'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Read the generated SVG
|
||||||
|
if svg_path.exists() and svg_path.stat().st_size > 0:
|
||||||
|
svg_content = svg_path.read_text(encoding='utf-8')
|
||||||
|
b64 = base64.b64encode(svg_content.encode('utf-8')).decode('ascii')
|
||||||
|
return (
|
||||||
|
f'<figure class="img-sm">'
|
||||||
|
f'<img src="data:image/svg+xml;base64,{b64}"'
|
||||||
|
f' alt="schemdraw diagram">'
|
||||||
|
f'</figure>'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return (
|
||||||
|
f'<div class="warning">'
|
||||||
|
f'Schemdraw ran but produced no SVG output.'
|
||||||
|
f'</div>'
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
if svg_path.exists():
|
||||||
|
svg_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _wrap_code(code: str, svg_path: str) -> str:
|
||||||
|
"""Wrap user code to redirect schemdraw output to a file."""
|
||||||
|
# schemdraw writes SVG to the 'file' parameter of Drawing().
|
||||||
|
# We modify the code to inject file= if missing.
|
||||||
|
if "file=" not in code and "Drawing(" in code:
|
||||||
|
code = code.replace(
|
||||||
|
'Drawing(show=False)',
|
||||||
|
f"Drawing(show=False, file=r'{svg_path}')",
|
||||||
|
)
|
||||||
|
code = code.replace(
|
||||||
|
'Drawing()',
|
||||||
|
f"Drawing(show=False, file=r'{svg_path}')",
|
||||||
|
)
|
||||||
|
return code
|
||||||
|
|
@ -0,0 +1,283 @@
|
||||||
|
/* ============================================================
|
||||||
|
Datasheet Theme
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg: #fff;
|
||||||
|
--text: #000;
|
||||||
|
--text-muted: #333;
|
||||||
|
--heading: #000;
|
||||||
|
--accent: #003d7c;
|
||||||
|
--th-bg: #f2f2f2;
|
||||||
|
--th-border: #ccc;
|
||||||
|
--stripe: #fafafa;
|
||||||
|
--link: #000;
|
||||||
|
--note-bg: #f7f7f7;
|
||||||
|
--note-border: #999;
|
||||||
|
|
||||||
|
--font-body: "Noto Serif CJK SC", "Source Han Serif SC", "SimSun", Georgia, serif;
|
||||||
|
--font-heading: "Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||||
|
--font-mono: "Cascadia Code", "Fira Code", Consolas, monospace;
|
||||||
|
--size: 16px;
|
||||||
|
--line: 1.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
html { font-size: var(--size); }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font-body);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: var(--line);
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg);
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Cover ---------- */
|
||||||
|
.cover-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4em 2.5em;
|
||||||
|
margin: 0 0 3em 0;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-top { margin-bottom: 4em; }
|
||||||
|
|
||||||
|
.cover-top .product-family {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
letter-spacing: 0.5em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-body { max-width: 100%; }
|
||||||
|
|
||||||
|
.cover-body h1 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 2.6rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.3;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
color: var(--heading);
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-body h1 .model { font-weight: 800; display: inline; }
|
||||||
|
|
||||||
|
.cover-body h1 .zh-name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-muted);
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-body .subtitle {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 1.05rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-muted);
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-bottom {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 3.5em;
|
||||||
|
left: 0; right: 0;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-bottom .rev { font-weight: 700; color: var(--heading); }
|
||||||
|
.cover-bottom .author { white-space: nowrap; }
|
||||||
|
|
||||||
|
/* ---------- Chapters ---------- */
|
||||||
|
.chapter { padding: 2em 2.5em; }
|
||||||
|
|
||||||
|
/* ---------- Headings ---------- */
|
||||||
|
h1 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--heading);
|
||||||
|
margin: 2em 0 0.8em;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 2px solid var(--heading);
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--heading);
|
||||||
|
margin: 1.5em 0 0.6em;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
border-bottom: 1px solid var(--th-border);
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--heading);
|
||||||
|
margin: 1.2em 0 0.5em;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 1.05rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text);
|
||||||
|
margin: 1em 0 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Body ---------- */
|
||||||
|
p { margin: 0.6em 0; text-align: justify; color: var(--text); }
|
||||||
|
ul, ol { margin: 0.6em 0; padding-left: 2em; color: var(--text); }
|
||||||
|
li { margin: 2px 0; }
|
||||||
|
a { color: var(--link); text-decoration: none; }
|
||||||
|
a:hover { text-decoration: underline; }
|
||||||
|
strong { font-weight: 700; color: var(--heading); }
|
||||||
|
|
||||||
|
/* ---------- Tables ---------- */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 1em 0;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
}
|
||||||
|
thead th {
|
||||||
|
background-color: var(--th-bg);
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
text-align: left;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid var(--th-border);
|
||||||
|
border-bottom: 2px solid var(--heading);
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--heading);
|
||||||
|
}
|
||||||
|
tbody td {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid var(--th-border);
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
tbody tr:nth-child(even) { background-color: var(--stripe); }
|
||||||
|
table.compact { font-size: 0.85rem; }
|
||||||
|
table.compact thead th { font-size: 0.82rem; padding: 3px 7px; }
|
||||||
|
table.compact tbody td { padding: 3px 7px; }
|
||||||
|
td.addr, td.bits, td.reset-val { font-family: var(--font-mono); font-size: 0.85em; white-space: nowrap; }
|
||||||
|
td.bits { text-align: center; }
|
||||||
|
|
||||||
|
.perm-rw { color: var(--text); font-weight: 700; }
|
||||||
|
.perm-ro { color: var(--text); font-weight: 700; }
|
||||||
|
.perm-wc { color: var(--text); font-weight: 700; }
|
||||||
|
|
||||||
|
/* ---------- Code ---------- */
|
||||||
|
code {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.9em;
|
||||||
|
background: var(--note-bg);
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--th-border);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
background: var(--note-bg);
|
||||||
|
border: 1px solid var(--th-border);
|
||||||
|
border-left: 3px solid var(--heading);
|
||||||
|
padding: 12px;
|
||||||
|
margin: 1em 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
pre code { background: none; padding: 0; border: none; font-size: inherit; }
|
||||||
|
|
||||||
|
.code-block {
|
||||||
|
margin: 1em 0;
|
||||||
|
border: 1px solid var(--th-border);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.code-header {
|
||||||
|
background: var(--th-bg);
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 4px 10px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
border-bottom: 1px solid var(--th-border);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.code-lines {
|
||||||
|
margin: 0; border: none; border-left: none;
|
||||||
|
font-size: 0.82rem; line-height: 1.55;
|
||||||
|
padding: 8px 0; background: var(--stripe);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.code-lines .ln {
|
||||||
|
display: inline-block; width: 40px;
|
||||||
|
text-align: right; color: var(--text-muted);
|
||||||
|
user-select: none; padding-right: 12px;
|
||||||
|
margin-right: 8px; border-right: 1px solid var(--th-border);
|
||||||
|
}
|
||||||
|
.code-lines .lc { color: var(--text); }
|
||||||
|
|
||||||
|
/* ---------- Figures ---------- */
|
||||||
|
figure { margin: 1.2em auto; text-align: center; max-width: 75%; }
|
||||||
|
figure img { max-width: 100%; max-height: 420px; height: auto; border-radius: 2px; }
|
||||||
|
figure figcaption {
|
||||||
|
font-family: var(--font-heading); font-size: 0.85rem;
|
||||||
|
color: var(--text-muted); margin-top: 4px; font-weight: 700;
|
||||||
|
}
|
||||||
|
p img { max-width: 75%; max-height: 400px; height: auto; display: block; margin: 0.8em auto; border-radius: 2px; }
|
||||||
|
td img { max-width: 100%; max-height: 180px; margin: 0; }
|
||||||
|
.img-row { display: flex; gap: 1em; justify-content: center; align-items: flex-start; margin: 1em 0; }
|
||||||
|
.img-row img { flex: 0 0 auto; margin: 0; border-radius: 2px; }
|
||||||
|
|
||||||
|
/* ---------- Notes ---------- */
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 0; padding: 10px 16px;
|
||||||
|
border-left: 3px solid var(--heading);
|
||||||
|
background: var(--note-bg); font-size: 0.92rem;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg-summary { font-size: 0.9rem; }
|
||||||
|
.reg-summary strong { margin-right: 4px; }
|
||||||
|
.reg-summary code { margin-right: 12px; }
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
background: #f5f5f5; border: 1px solid #999;
|
||||||
|
padding: 10px; margin: 10px 0; color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- Utility ---------- */
|
||||||
|
.text-center { text-align: center; }
|
||||||
|
.text-mono { font-family: var(--font-mono); }
|
||||||
|
.page-break { margin: 2em 0; }
|
||||||
|
|
||||||
|
/* ---------- Auto-numbering ---------- */
|
||||||
|
body.auto-numbering { counter-reset: section; }
|
||||||
|
body.auto-numbering .chapter h1 { counter-increment: section; counter-reset: subsection; }
|
||||||
|
body.auto-numbering .chapter h1::before { content: counter(section) ". "; font-weight: 800; }
|
||||||
|
body.auto-numbering .chapter h2 { counter-increment: subsection; counter-reset: subsubsection; }
|
||||||
|
body.auto-numbering .chapter h2::before { content: counter(section) "." counter(subsection) " "; font-weight: 700; }
|
||||||
|
body.auto-numbering .chapter h3 { counter-increment: subsubsection; }
|
||||||
|
body.auto-numbering .chapter h3::before { content: counter(section) "." counter(subsection) "." counter(subsubsection) " "; font-weight: 700; }
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
title: RBPU16 读出基带处理芯片
|
||||||
|
subtitle: 数据手册
|
||||||
|
author: 郭成
|
||||||
|
theme: datasheet
|
||||||
|
|
||||||
|
features:
|
||||||
|
- DAC 12 GSPS
|
||||||
|
- ADC 6 GSPS
|
||||||
|
- 16 Qubit 并行读出
|
||||||
|
- AWG 任意波形发生器
|
||||||
|
- DAQ 数据采集
|
||||||
|
- 片上 PLL
|
||||||
|
- LVDS 高速接口
|
||||||
|
- SPI 配置接口
|
||||||
|
|
||||||
|
chapters:
|
||||||
|
- 00_cover.md
|
||||||
|
- 01_specifications.md
|
||||||
|
- 02_absolute_maximum.md
|
||||||
|
- 03_pin_description.md
|
||||||
|
- 04_typical_performance.md
|
||||||
|
- 05_terminology.md
|
||||||
|
- 06_theory_of_operation.md
|
||||||
|
- 07_applications.md
|
||||||
|
- 08_register_map.md
|
||||||
|
- 09_package_dimensions.md
|
||||||
|
|
||||||
|
appendix:
|
||||||
|
- calibration.md
|
||||||
|
- config_examples.md
|
||||||
116
readme.md
|
|
@ -1,2 +1,114 @@
|
||||||
# 读出基带处理芯片数据手册
|
# RBPU16 读出基带处理芯片 · 数据手册
|
||||||
本项目为读出基带处理芯片的数据手册,本文档可以帮助相关工程师开展芯片性能评估、芯片硬件设计、芯片驱动开发以及芯片使用等工作。
|
|
||||||
|
纯文本管理,Python 构建,生成自包含 HTML 报告。
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
├── build.ipynb # 构建入口:VS Code 打开 → Run All
|
||||||
|
├── project.yaml # 项目配置(标题、作者、章节列表)
|
||||||
|
├── chapters/ # 章节源文件(Markdown)
|
||||||
|
├── data/ # 结构化数据(CSV / JSON)
|
||||||
|
├── assets/ # 图片(PNG / JPG)
|
||||||
|
├── doc_builder/ # 构建工具(可跨项目复用)
|
||||||
|
│ ├── themes/datasheet.css
|
||||||
|
│ ├── renderers/ # 代码块渲染器
|
||||||
|
│ │ └── schemdraw.py
|
||||||
|
│ ├── render_table.py # @import 渲染器:通用表格
|
||||||
|
│ ├── render_bga.py # @import 渲染器:BGA 网格
|
||||||
|
│ ├── render_address.py # @import 渲染器:地址映射表
|
||||||
|
│ ├── render_registers.py # @import 渲染器:寄存器定义
|
||||||
|
│ ├── render_requirements.py # @import 渲染器:YAML 需求表
|
||||||
|
│ ├── import_handler.py # @import 调度器
|
||||||
|
│ ├── image_extension.py # 图片尺寸扩展
|
||||||
|
│ └── codeblock_extension.py # 代码块渲染(pre-markdown)
|
||||||
|
└── output/ # 构建产物
|
||||||
|
└── RBPU16_Data_Sheet.html
|
||||||
|
```
|
||||||
|
|
||||||
|
## project.yaml
|
||||||
|
|
||||||
|
每个项目根目录的配置文件,`build.ipynb` 读取它来驱动构建。
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
title: RBPU16 读出基带处理芯片
|
||||||
|
subtitle: 数据手册
|
||||||
|
author: 郭成
|
||||||
|
theme: datasheet
|
||||||
|
chapters:
|
||||||
|
- 00_cover.md
|
||||||
|
- 01_specifications.md
|
||||||
|
- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 语法参考
|
||||||
|
|
||||||
|
### 1. 图片
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
 # 默认 80% 宽,高自动等比
|
||||||
|
{w=50%} # 宽 50%,高自动等比
|
||||||
|
{h=50%} # 高 50%,宽自动等比
|
||||||
|
{w=50%, h=300} # 宽 50% + 最大高度 300px
|
||||||
|
```
|
||||||
|
|
||||||
|
- `{w=N%}` — 宽 N%,高自动等比
|
||||||
|
- `{h=N%}` — 高 N%,宽自动等比
|
||||||
|
- `{w=N%, h=M}` — 同时指定宽高(h 为像素时限制最大高度)
|
||||||
|
- 不写 → 默认 `w=80%`
|
||||||
|
- 两张图 `{w=N%}` 相加 ≤ 100% 时自动并排
|
||||||
|
|
||||||
|
### 2. `@import` — 导入数据文件
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
@import "data/file.csv" # 无 using → 行号代码视图
|
||||||
|
@import "data/file.csv" using render_table.py # 通用表格
|
||||||
|
@import "data/pin_loc.csv" using render_bga.py # BGA 焊球网格
|
||||||
|
@import "data/ids.json" using render_registers.py # 寄存器定义表
|
||||||
|
```
|
||||||
|
|
||||||
|
`using <script.py>` 加载项目根目录下的 Python 脚本,调用 `render(filepath)` → HTML。脚本不存在时降级为行号视图,不报错。
|
||||||
|
|
||||||
|
### 3. 代码块渲染
|
||||||
|
|
||||||
|
```schemdraw
|
||||||
|
import schemdraw
|
||||||
|
from schemdraw import elements as e
|
||||||
|
with schemdraw.Drawing(show=False) as d:
|
||||||
|
d += e.Resistor().right().label('R1')
|
||||||
|
```
|
||||||
|
|
||||||
|
构建时在 markdown 之前执行:代码块 → `doc_builder/renderers/<tag>.py` → SVG/HTML。`mermaid` 等标签为 passthrough(浏览器端渲染)。
|
||||||
|
|
||||||
|
### 4. 占位符
|
||||||
|
|
||||||
|
表格中 `—` 表示待补充数据。
|
||||||
|
|
||||||
|
## 构建流程
|
||||||
|
|
||||||
|
```
|
||||||
|
章节 .md 文件
|
||||||
|
│
|
||||||
|
├─→ @import 处理器(替换为渲染 HTML)
|
||||||
|
├─→ 代码块渲染器(```lang → 渲染输出)
|
||||||
|
└─→ Python-Markdown(→ HTML)
|
||||||
|
│
|
||||||
|
├─→ 图片尺寸扩展({w=N%} / {h=N%})
|
||||||
|
└─→ codehilite(代码高亮)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
组装 HTML(封面 + 章节 + 修订历史)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
图片 base64 内嵌 → 自包含单文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 编辑指南
|
||||||
|
|
||||||
|
| 修改内容 | 编辑 | 重建 |
|
||||||
|
|---------|------|------|
|
||||||
|
| 正文 | `chapters/*.md` | Run All |
|
||||||
|
| 管脚 | `data/pin_name.csv` | Run All |
|
||||||
|
| 寄存器 | `script/读出子系统IDS表.xls` | ids_import.ipynb → Run All |
|
||||||
|
| 样式 | `doc_builder/themes/datasheet.css` | Run All |
|
||||||
|
| 配置 | `project.yaml` | Run All |
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
|规格项|最小值|典型值|
|
|
||||||
|:-|:-|:-|
|
|
||||||
|SPI速率|50 Mbps|-|
|
|
||||||
|LVDS速率|750 Mbps|-|
|
|
||||||
|
|
||||||
|标识|定义|时序(ns)|
|
|
||||||
|:-|:-|:-|
|
|
||||||
|Tc2s|SPI帧开始时,CSN下降沿到SCLK下降沿的时间|>3|
|
|
||||||
|Tms|MOSI数据的建立时间|>3|
|
|
||||||
|Tmh|MOSI数据的保持时间|>3|
|
|
||||||
|Tss|MISO数据的保持时间|>3|
|
|
||||||
|Tsh|MISO数据的保持时间|>3|
|
|
||||||
|Tc2s|SPI帧结束时,SCLK上升沿到CSN上升沿的时间|>3|
|
|
||||||
293
读出芯片用户使用手册.md
|
|
@ -1,293 +0,0 @@
|
||||||
---
|
|
||||||
export_on_save:
|
|
||||||
html: true
|
|
||||||
|
|
||||||
html:
|
|
||||||
toc: true
|
|
||||||
embed_local_images: true
|
|
||||||
embed_svg: true
|
|
||||||
|
|
||||||
title: 读出子系统历史无关功能配置项
|
|
||||||
author: 郭成
|
|
||||||
date:
|
|
||||||
---
|
|
||||||
|
|
||||||
# 宣传页封面
|
|
||||||
|
|
||||||
## 主要特点
|
|
||||||
* DAC 更新率最高12 GSPS
|
|
||||||
* ADC采样率最高6 GSPS
|
|
||||||
* AWG支持直接/调制波形输出
|
|
||||||
* AWG支持标记脉冲输出
|
|
||||||
* DAQ支持多种数据采集模式
|
|
||||||
* DAQ支持低延迟反馈控制
|
|
||||||
* AWG\DAQ支持指令集的编程
|
|
||||||
|
|
||||||
## 简要描述
|
|
||||||
RBPU16是一款用于量子比特态信息读出的一款SoC芯片,
|
|
||||||
最大支持16个量子比特态信息并行读出。
|
|
||||||
芯片内部集成了PLL、ADC、DAC和DSP等模块,其可以利用高速DAC产生微波信号激发读取腔,并通过数字I/O使能外部Pump通道,接着利用高速ADC采集处理反射回来的信号,并通过DSP计算量子态信息,最后将读出的量子态信息通过LVDS接口实时发送出去,为量子比特态信息读出提供高集成度解决方案。
|
|
||||||
|
|
||||||
## 功能框图
|
|
||||||

|
|
||||||
|
|
||||||
# 1. 规格参数
|
|
||||||
|
|
||||||
@import "specification.md"
|
|
||||||
|
|
||||||
# 2. 操作最大值
|
|
||||||
TODO
|
|
||||||
|
|
||||||
# 3. 管脚描述
|
|
||||||
芯片配置,顶视图
|
|
||||||

|
|
||||||
|
|
||||||
芯片管脚描述如下
|
|
||||||
@import "pin_name.csv"
|
|
||||||
# 4. 典型性能特点
|
|
||||||
|
|
||||||
# 5. 专业术语
|
|
||||||
|
|
||||||
# 6. 操作原理
|
|
||||||
|
|
||||||
|
|
||||||
## 6.1 原理及模块划分
|
|
||||||
RBPU16是一颗用于完成超导量子比特的态读出的SoC基带芯片。
|
|
||||||
芯片模拟部分包括ADC、DAC、PLL、LVDS、POR和温度传感器;
|
|
||||||
数字部分主要包括DAQ、AWG、PlsGen、Feedback以及System模块。
|
|
||||||
读出芯片的总体功能组成如下图所示。
|
|
||||||

|
|
||||||
|
|
||||||
在激励信号生成路径上,AWG用于控制激励通道待输出的波形,
|
|
||||||
接着波形经过DAC转换成基带读出激励信号,
|
|
||||||
同时AWG模块触发PlsGen模块实时发出脉冲信号使能外部Pump通道。
|
|
||||||
回波信号处理路径上,ADC用于采集反射的读出基带信号,
|
|
||||||
接着DAQ对基带信号进行分析处理,结果再通过LVDS接口发送出去,
|
|
||||||
同时DAQ模块触发Feedback模块将部分结果上报或者下发到外部芯片。
|
|
||||||
|
|
||||||
片内PLL用于管理整个芯片的时钟,为ADC生成采样时钟,
|
|
||||||
为DAC生成更新时钟,为数字模块生成主时钟等。
|
|
||||||
POR用于在芯片上电时对整个芯片进行复位,保障芯片正常工作。
|
|
||||||
温度监视模块用于实时监测芯片温度变化,保障芯片稳定工作。
|
|
||||||
System模块用于管理芯片上控制的状态,为芯片运维和调试提供支撑。
|
|
||||||
|
|
||||||
本章节从读出芯片的原理及模块划分、关键数据路径、接口控制协议几个方面进行介绍。
|
|
||||||
需要注意到的是:读出芯片不仅支持以ASIC芯片模式工作,也支持部分核心控制在FPGA内部工作。
|
|
||||||
这两种工作模式受制于ASIC和FPGA资源以及外部ADC、DAC硬件性能不同,
|
|
||||||
部分功能实现存在差异,后续阅读时需要重点关注。
|
|
||||||
|
|
||||||
## 6.2 关键数据路径
|
|
||||||
### 6.2.1 读出激励输出通道
|
|
||||||
|
|
||||||
@import "../readout_program/ri_datapath.md"
|
|
||||||
|
|
||||||
一般情况下,直出模式用于量子实验,通过直接输出包含多个读出频率的波形,可以实现对多个量子比特的并行读出;调制模式用于腔频扫描等应用,通过实时修改NCO频率,可以实时改变输出频率,配合DAQ进行实时读取,可以实现扫频功能。若基带信号包含多个频点,还能实现多频点并行扫描功能;NCO Only模式可以输出连续波形,方便连接外部仪器上进行测试,用于芯片本身的测试,
|
|
||||||
|
|
||||||
### 6.2.2 读出回波信号处理
|
|
||||||
|
|
||||||
@import "../readout_program/ro_datapath.md"
|
|
||||||
|
|
||||||
|
|
||||||
## 6.3 接口控制协议
|
|
||||||
|
|
||||||
### 6.3.1 SPI配置协议
|
|
||||||
读出芯片通过SPI来配置内部寄存器和内存,SPI采用四线模式。
|
|
||||||
时钟极性CPOL=1,即时钟在空闲时处于高电平状态,
|
|
||||||
时钟相位CPHA=1,即在第一个时钟沿输出数据,第二个时钟沿采样数据。
|
|
||||||
SPI的通信数据格式采用自定义协议,支持流模式发送接收,
|
|
||||||
SPI的通信协议如下图所示:
|
|
||||||

|
|
||||||
|
|
||||||
协议首先发送1比特读写标识位,
|
|
||||||
然后发送25比特地址位,
|
|
||||||
接着再发送5比特的芯片选择信号,
|
|
||||||
最后再发送/接收数据。
|
|
||||||
标识控制位含义如下表所示。
|
|
||||||
数据发送/接收以32比特为单位,
|
|
||||||
以流模式发送,
|
|
||||||
支持发送/接收N*32位的数据,
|
|
||||||
直到主控端将csn信号拉低后结束通信,
|
|
||||||
这里N为大于等于1的整数。
|
|
||||||
流模式要求从设备在完成32比特数据接收/发送后自动对地址进行4字节递增。
|
|
||||||
|
|
||||||
|
|
||||||
|字段|RW|ADDR|CHIP_ID|RSV|DATA|
|
|
||||||
|:-:|:-:|:-:|:-:|:-:|:-:|
|
|
||||||
|位宽|1|25|5|1|32*N|
|
|
||||||
|含义|0:读,1:写|32 MB寻址空间|总线片选|保留位|数据|
|
|
||||||
|
|
||||||
|
|
||||||
### 6.3.2 LVDS通信协议
|
|
||||||
从读出芯片到多功能母卡的数据推送接口rslt_push_[p,n],
|
|
||||||
反馈上报接口glb_tx_[p,n]和从多功能母板到读出芯片的反馈下发接口glb_rx_[p,n]采用了定制的LVDS通信协议,
|
|
||||||
协议帧格式如下图所示:
|
|
||||||
|
|
||||||
```ascii
|
|
||||||
+---------------------------------------+
|
|
||||||
| LVDS DATA FRAME |
|
|
||||||
+------+-------------------+------------+
|
|
||||||
| 4 | 16/32/64/128 | 8 |
|
|
||||||
+------+-------------------+------------+
|
|
||||||
| HEAD | Payload | CRC8 |
|
|
||||||
+-----+--------------------+------------+
|
|
||||||
MSB LSB
|
|
||||||
```
|
|
||||||
|
|
||||||
帧头包含4比特数据,其中最高位比特用于指示是否启动数据传输,
|
|
||||||
次高位置0保留,最低两位用于指示本次传输的数据量。
|
|
||||||
载荷支持16、32、64、128比特四种数据。
|
|
||||||
最后采用8比特校验码作为结束,
|
|
||||||
校验多项式为: $x^8 + x^2 + x + 1$。
|
|
||||||
|
|
||||||
|
|
||||||
当处于空闲状态不用传输数据时,发送端将LVDS信号电平拉高。
|
|
||||||
当传输数据时,发送端将LVDS电平拉低两个数据周期启动数据发送,
|
|
||||||
接着发送两比特数据指示本次载荷数据量,
|
|
||||||
其中0表示16比特,1表示32比特,2表示64比特,3表示128比特;
|
|
||||||
帧头发送完毕后紧接着将帧头指示的数据量的数据载荷发送;
|
|
||||||
最后将载荷计算得到的CRC8校验码发送;
|
|
||||||
|
|
||||||
考虑到接收端可能由于信号亚稳态或者串并转换不能正确采集输入数据,
|
|
||||||
协议要求接收端在接收数据之前必须先和发送端同步。
|
|
||||||
芯片上电后接收端默认处于同步丢失状态,
|
|
||||||
此时发送端通过连续发送同步码来同步接收端,
|
|
||||||
同步码为ascii字符串”hfnl”对应的32比特数据,
|
|
||||||
同步码的数量由`rx_pat_ctrl`寄存器控制,数量为$2^{4+rx\_pat\_ctrl}$。
|
|
||||||
当完成设定数量的同步码发送完毕后再发送一个结束码结束同步过程,
|
|
||||||
接收码为”exit”对应的32比特数据。
|
|
||||||
同步成功后,接收端进入接收就绪状态(SM_READY),
|
|
||||||
发送端同步进入空闲状态。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
发送和接收的状态机如上图所示,
|
|
||||||
接收端后续如果在接收数据过程发现CRC8校验码出错,
|
|
||||||
接收端会再次进入同步丢失状态。
|
|
||||||
|
|
||||||
# 7. 应用注意
|
|
||||||
|
|
||||||
## 7.1 模拟接口
|
|
||||||
### 7.1.1 DAC输出接口
|
|
||||||
DAC输出0-12 GHz信号,内部为50Ω电阻网络,
|
|
||||||
外部差分270 nH电感到地,然后经巴伦差分转单端,注意传输线阻抗匹配。
|
|
||||||
参考电路如下图所示:
|
|
||||||
|
|
||||||
### 7.1.2 ADC输入接口
|
|
||||||
|
|
||||||
### 7.1.3 时钟输入接口
|
|
||||||
|
|
||||||
|
|
||||||
### 7.1.4 环路滤波器
|
|
||||||
使用内部PLL时,外接滤波器结构如图所:
|
|
||||||
|
|
||||||
|
|
||||||
### 7.1.5 基准电压输入
|
|
||||||
此端口的外接电阻决定了基准电流源的大小。其中,
|
|
||||||
ADC_VBIAS_IREF_RES端口要求外接电阻5.2 K到地,
|
|
||||||
DAC_VBIAS_IREF_RES端口要求外接电阻5 K到地。两者都并接电容0.47uF。
|
|
||||||
|
|
||||||
## 7.2 启动顺序
|
|
||||||
为了确保芯片正常工作,需要满足以下启动顺序要求:
|
|
||||||
* 内核供电上电
|
|
||||||
* IO供电上电
|
|
||||||
* 时钟配置完毕
|
|
||||||
* 芯片复位
|
|
||||||
|
|
||||||
## 7.3 配置流程
|
|
||||||
|
|
||||||
读出芯片在上电后应该校准,校准过程用于完成片上ADC、DAC、PLL以及系统同步,校准过程参考[读出子系统运维操作手册](../readout_operate/读出子系统运维操作手册.md)。
|
|
||||||
在实验中读出芯片的操作遵循数据配置、实验运行和数据采集三个阶段。
|
|
||||||
|
|
||||||
### 7.3.1 数据配置阶段
|
|
||||||
|
|
||||||
* RO通道配置:外部硬件通过SPI接口对读出芯片的寄存器(包括输出模式,例如直发模式、NCO Only模式、调制模型)、波形查找表、波形仓库、输出MCU控制程序及数据。
|
|
||||||
* RI通道配置:外部硬件通过SPI接口对读出芯片的寄存器(包括采集模式,例如波形模式、解模模式、态结果模型等)、读出参数、匹配滤波器权重、采集控制程序及数据。
|
|
||||||
* Pump通道配置:主要配置Pump通道输出的使能信号宽度和相对码字触发的延迟。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
若芯片出现异常,在实验配置前应该通过写寄存器来软复位芯片的状态机和寄存器默认值,数据配置用例参考[读出子系统历史无关配置集](../readout_config_set/读出子系统历史无关配置集.md)
|
|
||||||
### 7.3.2 实验运行阶段
|
|
||||||
|
|
||||||
读出芯片的运行通过同步触发信号来启动,
|
|
||||||
从而确保多个芯片间具有确定的时序关系。
|
|
||||||
此外考虑到不同类型通信固有延迟不同,
|
|
||||||
同步信号在芯片内部首先经过同步延迟模块,
|
|
||||||
同步延迟模块能够为DAQ和AWG分别延迟不同的时间,
|
|
||||||
从而确保读出芯片的DAQ和AWG模块能够协同运行。
|
|
||||||
|
|
||||||
同步信号到达DAQ和AWG模块后,DAQ和AWG模块内部的MCU分别启动运行,
|
|
||||||
MCU从0地址加载指令运行,其按照每三个时钟一个指令的速度执行,
|
|
||||||
MCU根据编程指令修改控制寄存器与发出控制码字,
|
|
||||||
对于AWG,控制码字驱动波形输出和Pump使能输出,
|
|
||||||
对于DAQ,控制码字驱动数据采集和反馈上报/下发。
|
|
||||||
MCU运行到退出指令后,退出运行并进入空闲状态。
|
|
||||||
|
|
||||||
### 7.3.3 实验数据采集阶段
|
|
||||||
|
|
||||||
实验数据采集与MCU运行是同时启动的,
|
|
||||||
如果采集数据量较大,存在MCU运行结束但是数据还没采集完成的情况,
|
|
||||||
此时数据继续写入到缓存区,
|
|
||||||
主动数据上报模块继续从缓存中拿取数据并通过数据上报接口推送出去,
|
|
||||||
当缓存中数据推送完毕后结束实验,
|
|
||||||
此时可以通过检测推送数据量与目标数据量是否相等,
|
|
||||||
控制发出读请求信号来指示实验是否完毕。
|
|
||||||
若不能提前确定采集的数据量,
|
|
||||||
则只能在MCU运行结束后通过等待一定的时间,
|
|
||||||
通过检测是否有数据返回来判断实验是否完成。
|
|
||||||
|
|
||||||
在为读出芯片设置好采集数据请求阈值后,
|
|
||||||
当采集到的数据大于等于阈值便会触发一次读数据请求。
|
|
||||||
由于读出芯片通过LVDS接口回传数据,
|
|
||||||
持续进行实验时,为了避免缓存写满,
|
|
||||||
需要确保数据产生速率和数据回传速率匹配。
|
|
||||||
以获取解模IQ数据为例:
|
|
||||||
设T为数据产生时间间隔,N为每次读取的Qubit数量,
|
|
||||||
F为LVDS的有效速率,触发间隔时间需要满足以下公式:
|
|
||||||
$$T > \frac{64*N}{F}$$
|
|
||||||
|
|
||||||
|
|
||||||
## 7.4 异常处理
|
|
||||||
|
|
||||||
INT_STATUS寄存器是INT_MASK与对应实际输入状态按位相与再与INS_STATUS本身按位或运算的结果,需要通过命令清零。
|
|
||||||
|
|
||||||
|
|
||||||
# 8. 寄存器定义
|
|
||||||
## 8.1 寄存器摘要
|
|
||||||
读出芯片偏移地址空间分配如下所示,
|
|
||||||
用户可以通过读写相应地址来控制读出芯片功能和访问芯片状态。
|
|
||||||
读出芯片地址空间包含系统配置状态、模拟配置状态、DAQ配置状态、AWG配置状态以及PLL配置状态五个部分。
|
|
||||||
|
|
||||||
|
|
||||||
@import "seg_define.csv"
|
|
||||||
|
|
||||||
* 注1:DAQ和AWG各自包含一个MCU模块,
|
|
||||||
MCU模块仅能够访问模块内部的控制器指令、控制器数据和寄存器配置,
|
|
||||||
访问基地址分别重新映射到了0x000000, 0x100000和0x200000;
|
|
||||||
* 注2:MCU仅能够显示访问控制器数据和对应寄存器配置数据。
|
|
||||||
对于控制器指令空间,控制器自动读取指令并运行,无法显式访问和修改数据。
|
|
||||||
* 注3:匹配滤波器参数和匹配滤波器权重分别对应FPGA和ASIC平台,
|
|
||||||
FPGA平台受限于计算资源有限,采用系数直接存储的方案,
|
|
||||||
需要额外配置0x580000地址数据,此时0x500000地址中仅包络参数有效。
|
|
||||||
* 注4:系统状态配置、模拟配置状态、PLL配置状态属于运维寄存器,实验时禁止修改。实验只需要修改DAQ配置状态和AWG配置状态。
|
|
||||||
|
|
||||||
## 8.2 操作码字定义
|
|
||||||
|
|
||||||
### 8.2.1 激励输出控制
|
|
||||||
@import "../readout_program/ri_codeword.md"
|
|
||||||
|
|
||||||
### 8.2.2 采集处理控制
|
|
||||||
@import "../readout_program/ro_codeword.md"
|
|
||||||
|
|
||||||
## 8.3 寄存器/存储详细定义
|
|
||||||
读出芯片的详细寄存器/存储定义参考[读出芯片IDS表](script/读出子系统IDS表.xls),
|
|
||||||
相应的驱动软件配置文件参考[读出芯片IDS表](ids/读出子系统IDS表.json)。
|
|
||||||
|
|
||||||
# 9. 芯片尺寸
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* 焊球中心间距1mm
|
|
||||||
* 焊球大小0.5mm
|
|
||||||
* 焊球数量13*13=196个
|
|
||||||
* 基板大小:1.4cm*1.4cm
|
|
||||||