Initial JPEG-LS FPGA encoder baseline with tooling and timeout fix
This commit is contained in:
1118
fpga/srs/SystemVerilog coding style.md
Normal file
1118
fpga/srs/SystemVerilog coding style.md
Normal file
File diff suppressed because it is too large
Load Diff
765
fpga/srs/jpeg_ls.md
Normal file
765
fpga/srs/jpeg_ls.md
Normal file
@@ -0,0 +1,765 @@
|
||||
# JPEG-LS FPGA IP 核需求规格说明
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1 项目目标
|
||||
|
||||
基于 ITU-T T.87 / ISO/IEC 14495-1 JPEG-LS Baseline 标准,使用
|
||||
SystemVerilog 实现 JPEG-LS 图像压缩 FPGA IP 核。目标器件为 Xilinx
|
||||
Virtex-7 XC7V690T,目标时钟频率为 250 MHz。
|
||||
|
||||
本 IP 面向灰度图像编码,输入处理流水线的峰值目标为 1 像素/周期,即
|
||||
250 MPixel/s。由于输出接口固定为 9 bit 字节流,端到端持续吞吐率受实际压缩
|
||||
码率、字节填充、头部开销和内部输出缓冲状态限制;当内部输出缓冲接近满时,
|
||||
允许暂停输入 FIFO 读取。
|
||||
|
||||
### 1.2 参考资源
|
||||
|
||||
- 标准:ITU-T T.87 / ISO/IEC 14495-1 JPEG-LS Baseline
|
||||
- 参考实现:https://github.com/team-charls/charls
|
||||
- jpeg.org 列出的 libjpeg 参考库:https://github.com/thorfdbg/libjpeg/tree/master
|
||||
- 动态误差控制参考:https://patents.google.com/patent/CN102088602A/zh
|
||||
- 目标芯片:Xilinx Virtex-7 XC7V690T
|
||||
- 目标频率:250 MHz
|
||||
- 设计图:`fpga/srs/jpeg_ls_design.drawio`,包含软件框图和工作流程图
|
||||
|
||||
后续需求评审中新增或变更的用户要求,必须及时补充进入本文档,避免对话上下文
|
||||
丢失导致实现偏离需求。项目推进原则为:尽早提出需要用户确认的问题;非必要不
|
||||
停止推进;若后续实现过程中发现会改变接口、码流结构、性能目标、验证准则或资源
|
||||
边界的事项,必须先提出评审。
|
||||
|
||||
### 1.3 支持范围
|
||||
|
||||
- 仅支持灰度图像,JPEG-LS 帧头中的 component 数量固定为 1。
|
||||
- 支持像素位宽:8、10、12、14、16 bit。
|
||||
- 第一版仅实现 encoder RTL,不实现 FPGA decoder。
|
||||
- 输出必须是标准 JPEG-LS 码流;第一版将一幅输入图像拆成多个水平条带,
|
||||
每个条带输出一个完整 `SOI ... EOI` JPEG-LS frame,多个 frame 按条带顺序
|
||||
连续输出。
|
||||
- 不输出 SPIFF header。
|
||||
- 支持 JPEG-LS regular mode 和 run mode。
|
||||
- 不插入 restart markers,不输出 DRI 段。
|
||||
- 通过独立条带 frame 结构支持分段动态调整 `NEAR`。
|
||||
- 每个条带覆盖完整行宽,默认每 16 行一个条带;每个条带 frame 内只包含一个
|
||||
JPEG-LS scan。
|
||||
- 每个条带 frame 开始时重置 JPEG-LS 上下文、行缓存边界和 run mode 状态。
|
||||
- 每个条带 frame 的 `SOS` 前显式输出 LSE preset coding parameters 段,参数值采用标准默认
|
||||
`MAXVAL/T1/T2/T3/RESET` 计算结果。
|
||||
- 每个条带 frame 的 `SOS` 段写入该条带当前使用的 `NEAR`。
|
||||
|
||||
### 1.4 码流结构决策与兼容性验证
|
||||
|
||||
第一版码流结构确定为:每个水平条带输出一个独立完整 JPEG-LS frame,多个 frame
|
||||
按条带顺序连续输出。每个条带 frame 的图像宽度等于 `active_pic_col`,图像高度等于
|
||||
`SCAN_ROWS`,component 数量固定为 1,且该 frame 内只包含一个 JPEG-LS scan。
|
||||
|
||||
外部 `ofifo_wdata[8]` 的帧开始标志只在原始输入图像的第一个条带的 `SOI` 第一个
|
||||
字节上置 1,避免外部系统将每个条带误判为一幅新图像。
|
||||
外部系统不依赖 `cfg_pic_row` 或 `SCAN_ROWS` 做分组,而是通过
|
||||
`ofifo_wdata[8]` 识别原始图像开始;同一原始图像的后续条带 frame 仍可通过
|
||||
JPEG-LS frame header 解析出条带宽高,并按输出顺序拼回原图。
|
||||
第一版不提供原始图像结束 sideband。外部系统通过下一次
|
||||
`ofifo_wdata[8]=1` 或输出流空/超时判断上一幅原始图像已经结束。
|
||||
|
||||
每个条带 frame 的 `SOS` 前输出 LSE preset coding parameters 段。若兼容性实验表明该
|
||||
位置不被 CharLS 或标准语法接受,则允许改为仅在标准允许位置输出 LSE,或不
|
||||
输出 LSE 并使用标准默认参数。
|
||||
`jls_header_writer` 架构必须保留 LSE 输出策略调整空间,不能把每条带输出
|
||||
LSE 固化为无法修改的路径。
|
||||
|
||||
兼容性实验工具放在 `tools/jls_compat`,CharLS 源码作为第三方参考工具放在
|
||||
`third_party/charls`。`tools/jls_compat/duplicate_sos_probe.py` 已使用
|
||||
imagecodecs/CharLS 2.4.1 验证:原始单 component 码流可解码,在同一 frame 中插入
|
||||
第二个 `SOS` 后被解码器拒绝。因此第一版 RTL 不采用单 frame 多 scan 水平条带结构;
|
||||
若后续需要重新尝试单 frame 多 scan,必须先提供独立的标准依据和 CharLS 3.x 动态
|
||||
解码通过结果。
|
||||
|
||||
## 2. 系统参数
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 合法范围 | 说明 |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| `PIX_WIDTH` | int | 16 | 8, 10, 12, 14, 16 | 编译期像素位宽 |
|
||||
| `DEFAULT_PIC_COL` | int | 6144 | 16..6144 | 默认图像宽度 |
|
||||
| `DEFAULT_PIC_ROW` | int | 256 | 16..4096 | 默认图像高度 |
|
||||
| `MAX_PIC_COL` | int | 6144 | 6144 | 最大图像宽度 |
|
||||
| `MAX_PIC_ROW` | int | 4096 | 4096 | 最大图像高度 |
|
||||
| `SCAN_ROWS` | int | 16 | 1..4096 | 每个条带 frame 的行数 |
|
||||
| `MAX_NEAR` | int | 31 | 31 | 动态 `NEAR` 最大值 |
|
||||
| `OUT_BUF_BYTES` | int | 8192 | 实现相关 | 内部输出缓冲字节数 |
|
||||
| `OUT_BUF_AFULL_MARGIN` | int | 256 | 实现相关 | 输出缓冲暂停输入的余量 |
|
||||
|
||||
约束:
|
||||
|
||||
- `PIX_WIDTH` 不是运行时配置项,综合时固定。
|
||||
- 运行时图像尺寸由 `cfg_pic_col` 和 `cfg_pic_row` 决定。
|
||||
- 若任一尺寸配置非法,则整帧使用默认尺寸 `DEFAULT_PIC_COL x
|
||||
DEFAULT_PIC_ROW`。
|
||||
- 非法尺寸包括:宽度为 0、高度为 0、宽度小于 16、高度小于 16、宽度大于
|
||||
`MAX_PIC_COL`、高度大于 `MAX_PIC_ROW`、高度不能被 `SCAN_ROWS` 整除。
|
||||
- 上游应保证有效图像高度是 `SCAN_ROWS` 的整数倍。
|
||||
- `MAXVAL = 2^PIX_WIDTH - 1`,输入保留位不参与 `MAXVAL` 计算。
|
||||
|
||||
## 3. 端口定义
|
||||
|
||||
### 3.1 时钟与复位
|
||||
|
||||
| 标识 | 方向 | 位宽 | 名称 | 说明 |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| `clk` | 输入 | 1 | 主时钟 | 250 MHz,上升沿有效 |
|
||||
| `rst` | 输入 | 1 | 复位 | 同步复位,高电平有效 |
|
||||
|
||||
### 3.2 运行时配置
|
||||
|
||||
| 标识 | 方向 | 位宽 | 名称 | 说明 |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| `cfg_pic_col` | 输入 | 13 | 图像宽度 | SOF 像素被接收时采样,0 或非法值使用默认尺寸 |
|
||||
| `cfg_pic_row` | 输入 | 13 | 图像高度 | SOF 像素被接收时采样,0 或非法值使用默认尺寸 |
|
||||
| `ratio` | 输入 | 4 | 目标压缩比 | SOF 像素被接收时采样,整帧保持不变 |
|
||||
|
||||
`ratio` 编码:
|
||||
|
||||
| `ratio` | 目标压缩比 | `NEAR` 策略 |
|
||||
| ---: | --- | --- |
|
||||
| 0 | 1:1 | 强制无损,`NEAR=0`,不做动态增大 |
|
||||
| 1 | 1:2 | 动态调整 `NEAR` |
|
||||
| 2 | 1:4 | 动态调整 `NEAR` |
|
||||
| 3 | 1:8 | 动态调整 `NEAR` |
|
||||
| 其他 | 1:1 | 按 `ratio=0` 处理 |
|
||||
|
||||
配置时序要求:
|
||||
|
||||
- `cfg_pic_col`、`cfg_pic_row`、`ratio` 必须在 SOF 前至少 1 个 `clk` 稳定。
|
||||
- 配置必须在当前帧处理期间保持不变;帧内变化属于上游协议错误,RTL 不保证
|
||||
输出正确。
|
||||
|
||||
### 3.3 输入 FIFO 接口
|
||||
|
||||
| 标识 | 方向 | 位宽 | 名称 | 说明 |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| `ififo_rclk` | 输出 | 1 | 输入 FIFO 读时钟 | 与 `clk` 同频同相 |
|
||||
| `ififo_rd` | 输出 | 1 | 输入 FIFO 读使能 | 高电平有效 |
|
||||
| `ififo_rdata` | 输入 | `ceil(PIX_WIDTH/8)*9` | 输入 FIFO 数据 | 见输入打包格式 |
|
||||
| `ififo_empty` | 输入 | 1 | 输入 FIFO 空 | 高电平有效 |
|
||||
| `ififo_alempty` | 输入 | 1 | 输入 FIFO 即将空 | 高电平有效,用于读取优化 |
|
||||
|
||||
输入 FIFO 采用标准同步 FIFO 时序:`ififo_rd` 有效后,下一周期
|
||||
`ififo_rdata` 有效。
|
||||
|
||||
读取策略:
|
||||
|
||||
- 当 `ififo_alempty=0` 时,允许连续读取以提高吞吐率。
|
||||
- 当 `ififo_alempty=1` 时,转为保守读取模式,每次读取前检查
|
||||
`ififo_empty=0`。
|
||||
- 当 `ififo_empty=1` 或内部输出缓冲接近满时,`ififo_rd=0`,暂停读取输入
|
||||
FIFO。
|
||||
- 暂停期间保持当前图像坐标、编码上下文和已读像素处理状态;恢复后继续。
|
||||
- 已经从 FIFO 读出的当前像素必须完成编码并进入内部输出缓冲。
|
||||
|
||||
输入像素顺序固定为从左到右、从上到下的逐行扫描顺序。每帧输入
|
||||
`active_pic_col * active_pic_row` 个像素,中间允许因 FIFO 空或内部输出缓冲
|
||||
满而暂停,但不允许乱序、跳行或缺失像素。
|
||||
|
||||
JPEG-LS 邻域边界扩展按标准行缓存语义处理。条带顶行的上一行样本
|
||||
按 0 处理;左边界 `x=0` 时 `Ra=Rb`,`Rc` 使用上一行的左边界扩展
|
||||
样本,而不是固定为 0;右边界时 `Rd=Rb`。该规则用于保证与 CharLS
|
||||
等标准参考实现的码流兼容性。
|
||||
|
||||
SOF 协议:
|
||||
|
||||
- 编码器只在检测到输入像素的 SOF 标志为 1 后开始一帧图像处理。
|
||||
- 一帧图像的第一个像素 SOF 标志为 1,其余像素 SOF 标志必须为 0。
|
||||
- 等待帧开始时若收到 SOF 为 0 的像素,继续等待有效 SOF。
|
||||
- 一帧未收满 `active_pic_col * active_pic_row` 个像素时又收到新的 SOF,
|
||||
属于上游协议错误,RTL 不保证输出正确。
|
||||
|
||||
输入打包格式:
|
||||
|
||||
- `PIX_WIDTH=8`:`ififo_rdata[8]` 为 SOF,`ififo_rdata[7:0]` 为像素值。
|
||||
- `PIX_WIDTH=10/12/14/16`:`ififo_rdata[17]` 为 SOF,
|
||||
`ififo_rdata[16]` 为保留位,`ififo_rdata[PIX_WIDTH-1:0]` 为像素值。
|
||||
- 对于 10/12/14 bit,`ififo_rdata[15:PIX_WIDTH]` 为保留位。
|
||||
- 所有保留位需求上必须为 0,RTL 不做检查和处理。
|
||||
- 输入像素作为数值处理,无需定义输入字节序。
|
||||
|
||||
### 3.4 输出 FIFO 接口
|
||||
|
||||
| 标识 | 方向 | 位宽 | 名称 | 说明 |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| `ofifo_wclk` | 输出 | 1 | 输出 FIFO 写时钟 | 与 `clk` 同频同相 |
|
||||
| `ofifo_wr` | 输出 | 1 | 输出 FIFO 写使能 | 高电平有效 |
|
||||
| `ofifo_wdata` | 输出 | 9 | 输出 FIFO 数据 | `[8]` 为帧开始标志,`[7:0]` 为输出字节 |
|
||||
| `ofifo_full` | 输入 | 1 | 输出 FIFO 满 | 保留端口,第一版忽略 |
|
||||
| `ofifo_alfull` | 输入 | 1 | 输出 FIFO 即将满 | 保留端口,第一版忽略 |
|
||||
|
||||
输出协议:
|
||||
|
||||
- `ofifo_wdata[7:0]` 按标准 JPEG-LS marker stream 的字节顺序输出。
|
||||
- marker 按大端字节顺序输出,例如 `SOI=0xFF,0xD8` 时先输出 `0xFF`。
|
||||
- 每幅输入图像的第一个条带 frame 的 `SOI` 第一个字节输出时,`ofifo_wdata[8]`
|
||||
置 1。
|
||||
- 同一幅输入图像的后续字节,包括后续条带 frame 的 `SOI/SOF55/LSE/SOS/EOI`
|
||||
字节,`ofifo_wdata[8]` 均置 0。
|
||||
- 连续多帧图像输出时,每幅输入图像的第一个条带 frame 的第一个 `SOI` 字节均
|
||||
置 1。
|
||||
- `ofifo_full` 和 `ofifo_alfull` 第一版完全忽略;系统集成必须保证外部输出
|
||||
FIFO 能持续接收写入。
|
||||
- 若前级输入处理不忙,允许在上一帧码流尚未完全从 `ofifo` 输出时接收下一帧
|
||||
输入;输出字节流必须严格按输入帧顺序排队输出,不允许帧间字节交错。
|
||||
- 输出队列仅使用 `ofifo_wdata[8]` 随字节流标记原始输入图像的开始,不维护额外
|
||||
帧元数据 sideband。
|
||||
|
||||
## 4. 压缩比控制
|
||||
|
||||
### 4.1 目标统计
|
||||
|
||||
压缩比目标以 bit 为单位计算,不按字节向上取整:
|
||||
|
||||
- 原始输入 bit 数:`processed_pixel_count * PIX_WIDTH`。
|
||||
- `ratio=1` 的目标 bit 数:原始输入 bit 数 / 2。
|
||||
- `ratio=2` 的目标 bit 数:原始输入 bit 数 / 4。
|
||||
- `ratio=3` 的目标 bit 数:原始输入 bit 数 / 8。
|
||||
- 实际输出 bit 数:当前原始输入图像已生成并写入内部输出缓冲的所有条带
|
||||
JPEG-LS frame 码流字节数 * 8。
|
||||
|
||||
实际输出统计包含完整输出码流中的所有字节,包括 `SOI`、`SOF55`、`LSE`、
|
||||
`SOS`、熵编码 payload、byte stuffing、`EOI` 和其它必要 marker。
|
||||
|
||||
### 4.2 动态 `NEAR` 调节
|
||||
|
||||
- 每帧开始时 `NEAR` 初值为 0。
|
||||
- `ratio=0` 或非法 ratio 时,整帧 `NEAR` 固定为 0,不进行动态调整。
|
||||
- `ratio=1/2/3` 时,每个条带 frame 结束后比较累计实际输出 bit 数与累计目标
|
||||
bit 数,并调整下一条带 frame 的 `NEAR`。
|
||||
- 第一版调节策略:
|
||||
- 若累计实际输出 bit 数大于累计目标 bit 数,`NEAR = NEAR + 1`。
|
||||
- 若累计实际输出 bit 数小于累计目标 bit 数且 `NEAR > 0`,
|
||||
`NEAR = NEAR - 1`。
|
||||
- 若二者相等,`NEAR` 保持不变。
|
||||
- `NEAR` 钳位到 `0..31`。
|
||||
- 如果第一版效果不理想,再参考 CN102088602A 所述方法优化调节步长和累计偏差
|
||||
控制策略。
|
||||
|
||||
### 4.3 误差验收
|
||||
|
||||
- 对 `ratio=0`,要求 CharLS 和 libjpeg 参考库解码结果均与原图逐像素一致。
|
||||
- 对 `ratio=1/2/3`,每个像素的重建误差不得超过该像素所属条带 frame 的实际
|
||||
`NEAR`;全帧最大误差也必须不超过 31。
|
||||
- `ratio=1/2/3` 的压缩比目标误差阈值为 10%。如果 `NEAR` 已经达到 31 后
|
||||
仍无法满足目标压缩比误差,验证报告标记为 FAIL,但 RTL 不提供错误端口。
|
||||
- 验证报告需要记录每个条带 frame 的 `NEAR`、累计实际输出 bit 数和累计目标 bit
|
||||
数。
|
||||
- 第一版只报告 PSNR 等图像质量指标,不将其作为约束。
|
||||
|
||||
## 5. JPEG-LS 码流要求
|
||||
|
||||
- 每个条带 frame 输出完整标准 JPEG-LS marker stream:`SOI ... EOI`。
|
||||
- 灰度图像 component 数量固定为 1,component id 固定为 1。
|
||||
- 每个条带 frame 的 `SOF55` 中样本精度等于 `PIX_WIDTH`,宽度等于
|
||||
`active_pic_col`,高度等于 `SCAN_ROWS`。
|
||||
- `MAXVAL = 2^PIX_WIDTH - 1`。
|
||||
- 每个条带 frame 的 `SOS` 前输出 LSE preset coding parameters 段,参数值为
|
||||
标准默认参数;即使相邻条带 frame 的 `NEAR` 未变化,也照常输出。
|
||||
- 若兼容性实验表明该 LSE 输出方式不符合 CharLS 或标准语法要求,则按
|
||||
1.4 节的兼容性策略调整。
|
||||
- 每个条带 frame 的 `SOS` header 中写入该条带当前 `NEAR`。
|
||||
- 条带 frame 的 scan 结束进入 `EOI` marker 前,bit packer 必须按 JPEG-LS 规则补齐到字节
|
||||
边界,补齐产生的字节计入输出统计。
|
||||
- 熵编码段必须实现 JPEG-LS marker/zero-bit stuffing;stuffing 字节计入输出
|
||||
统计。
|
||||
- 禁止将 JPEG-LS marker/zero-bit stuffing 简化为传统 JPEG 的 0xFF 后插入
|
||||
0x00 byte stuffing;实现必须按 JPEG-LS 标准位填充规则处理。
|
||||
- 不输出 SPIFF header。
|
||||
- 不输出 DRI 段,不插入 restart markers。
|
||||
- 不实现 raw bypass;即使 `ratio=0` 时 JPEG-LS 码流大于原始图像,也继续输出
|
||||
标准 JPEG-LS 无损码流。
|
||||
|
||||
## 6. 模块架构
|
||||
|
||||
顶层模块名采用 `jpeg_ls_encoder_top`,内部模块统一使用 `jls_` 前缀。
|
||||
|
||||
建议模块划分:
|
||||
|
||||
| 模块 | 功能 |
|
||||
| --- | --- |
|
||||
| `jpeg_ls_encoder_top` | 顶层互连,只例化子模块 |
|
||||
| `jls_input_ctrl` | 输入 FIFO 读取、SOF 检测、尺寸与 ratio 采样 |
|
||||
| `jls_scan_ctrl` | 图像坐标、条带 frame 划分、条带边界重置控制 |
|
||||
| `jls_header_writer` | `SOI/SOF55/LSE/SOS/EOI` 等 marker 输出 |
|
||||
| `jls_predictor` | MED 预测器与边界处理 |
|
||||
| `jls_context_model` | regular mode 上下文建模与统计更新 |
|
||||
| `jls_run_mode` | run mode 检测、run 长度编码与中断样本处理 |
|
||||
| `jls_golomb_encoder` | 映射误差与 Golomb-Rice 编码 |
|
||||
| `jls_bit_packer` | 变长码 bit 打包、byte stuffing |
|
||||
| `jls_near_ctrl` | 条带 frame 级动态 `NEAR` 统计与更新 |
|
||||
| `jls_output_buffer` | 内部输出缓冲、按帧顺序输出到 9 bit FIFO |
|
||||
|
||||
近损模式下,预测历史、上下文更新和行缓存必须使用编码端重建像素值,而不是原始
|
||||
输入像素值,以保证与标准 JPEG-LS 解码端一致。
|
||||
|
||||
为提高流水线吞吐,允许使用原始像素值、旧行缓存值或其它可提前获得的值进行
|
||||
梯度、预测、context 读地址、run/regular mode 判断等投机预计算或预取;但这些
|
||||
投机结果不得直接提交为最终码流、上下文更新或重建历史。最终提交的 `Ra/Rb/Rc/Rd`、
|
||||
`Px`、`Q1/Q2/Q3`、context index、run/regular mode 选择、`Errval/MErrval/k` 和
|
||||
`A/B/C/N/Nn/RUNindex` 更新必须与真实编码端重建像素历史重新计算或校验后保持一致。
|
||||
若投机结果与真实重建邻域不一致,RTL 必须丢弃投机结果并重算、重放或暂停,禁止
|
||||
为了实现无气泡流水而输出非标准 JPEG-LS 码流。`NEAR=0` 无损场景中原始值与重建值
|
||||
理论等价,仍应在实现说明中明确等价依据;该等价不得推广到 `NEAR>0` 场景。
|
||||
当前 RTL 允许在 `NEAR=0` lossless strip 中将输入样本 `X` 立即提交为 line history
|
||||
中的 `Rx`,以减少重建反馈气泡;`NEAR>0` near-lossless strip 必须等待真实重建
|
||||
样本或使用经校验/重放保证等价的流水机制。
|
||||
regular mode 中,`jls_regular_error_quantizer` 在标准 Annex A.5 的 `Errval`
|
||||
量化和 modulo 规范化后已经得到真实重建样本 `Rx`;后续 Annex A.6 context
|
||||
更新、`MErrval` 映射和 Golomb 编码不会再改变该 `Rx`。因此 RTL 允许在 regular
|
||||
误差量化结果被接受后立即把 `Rx` 回写到 line history,以缩短 `NEAR>0`
|
||||
反馈等待;但 context 写回、`MErrval/k`、Golomb 码字和 bitstream 顺序仍必须按
|
||||
逐像素标准语义提交,禁止因为提前回写 `Rx` 而重排熵编码事件。
|
||||
`NEAR>0` 下,若重建写回像素不是行尾,且输入端当前等待的是同一行的下一列像素,
|
||||
`jls_neighbor_provider` 允许在同一时钟沿接受该下一像素,并把刚返回的 `Rx`
|
||||
旁路作为下一像素的 `Ra`。该优化仅适用于同一行连续像素;行尾到下一行 `x=0`
|
||||
的 bank 切换、`left_edge_Rc` 和 `row_left_Rb` 更新必须先完成,不能做同周期
|
||||
旁路。
|
||||
|
||||
内部输出缓冲仅用于吸收变长编码和单字节输出接口之间的短时速率差异,不保证在
|
||||
最坏无损图像下维持全帧输入不暂停。当输出缓冲剩余空间小于
|
||||
`OUT_BUF_AFULL_MARGIN` 时,输入读取逻辑必须暂停。`OUT_BUF_BYTES` 默认值为
|
||||
8192 bytes;如性能验证需要调整该参数,必须经需求评审确认。
|
||||
`OUT_BUF_AFULL_MARGIN` 默认值为 256 bytes,实现前必须估算 header burst、
|
||||
LSE/SOS、极端 Golomb 长码和 bit packer flush 等单次不可暂停最大写入量;若
|
||||
默认值不足,需提交评审后调大。
|
||||
|
||||
### 6.1 高流水线实现约束
|
||||
|
||||
为满足 250 MHz 时钟和 200 MPixel/s 连续输入吞吐目标,RTL 实现必须优先采用高
|
||||
流水线架构:
|
||||
|
||||
- 关键数据通路按预测、上下文建模、误差映射、Golomb 参数计算、熵编码、bit
|
||||
打包和输出缓冲等阶段拆分流水。
|
||||
- 每级流水的组合逻辑深度应尽量控制在较小范围内,避免跨多个算法步骤形成长
|
||||
组合路径。
|
||||
- 上下文表读写、line buffer 访问、Golomb 参数更新和 bit packer 累积状态更新
|
||||
应使用寄存器切分关键路径。
|
||||
- 上下文统计表读写必须保持 JPEG-LS 逐像素标准语义。连续像素访问同一
|
||||
context 且流水线存在读写冲突时,优先使用 bypass/forwarding 将更新后的
|
||||
`A/B/C/N` 等统计值转发给后续像素;若极端冲突无法旁路解决,允许插入暂停
|
||||
周期并计入吞吐统计。禁止为追求吞吐率读取旧 context,导致码流与标准语义不
|
||||
一致。
|
||||
- 允许采用投机流水隐藏“梯度计算依赖重建值、重建值又由后级产生”的闭环等待:
|
||||
前级可基于原始值或旧值先行预计算,但提交前必须基于真实重建邻域进行校验。
|
||||
校验一致时可使用投机结果;校验失败时必须重算或重放该像素,相关暂停计入
|
||||
吞吐统计。禁止把投机结果作为标准状态直接更新,以换取表面无气泡流水。
|
||||
- 优先使用时序逻辑保存中间结果,减少大规模组合表达式、深层 if-else 嵌套和
|
||||
宽位宽组合比较链。
|
||||
- 对除法、取模、可变长度移位、优先级编码等潜在长路径逻辑,应采用查表、分级
|
||||
计算或多周期流水方式实现。
|
||||
- `NEAR>0` 误差量化不得使用单周期大组合除法;优先采用倒数查表、乘法、商校正
|
||||
和寄存器切分的流水实现。若采用多周期计算,必须在验证中覆盖 `NEAR=31` 等
|
||||
最大值路径。
|
||||
- 与 `NEAR` 相关的 DSP 乘法关键路径必须在输入操作数侧和乘积输出侧按需要加入
|
||||
触发器流水,特别是 `Errval*(2*NEAR+1)`、`RANGE*(2*NEAR+1)`、倒数查表乘法
|
||||
和商校正相关路径。流水拆分不得改变 JPEG-LS 标准码流语义,新增延迟必须由
|
||||
valid/ready 或状态机显式对齐。
|
||||
- regular mode 的重建像素 `Rx` 可在误差量化流水级计算完成并被接受后回写
|
||||
line history,不需要等待 `MErrval` 映射、Golomb 编码或 bit packer 完成;
|
||||
该优化只作用于重建历史反馈,不能改变 entropy 事件顺序或 context 更新顺序。
|
||||
- `NEAR>0` 行缓存反馈允许同一行 `Rx -> Ra` 同周期旁路,以减少逐像素反馈气泡;
|
||||
行尾换行、strip 边界和任何非连续坐标场景必须停顿等待状态提交完成。
|
||||
- 允许熵编码和 bit packer 对极端长码进行多周期处理,并通过暂停输入保护内部
|
||||
状态;该暂停周期计入吞吐统计。
|
||||
- run mode 已提交一个 run 段后,若后续像素仍为非 EOL 的 run 匹配像素且不会
|
||||
立即产生熵输出,允许继续接收并累加下一段 run length;遇到 regular 像素、
|
||||
run interruption 或 EOL run 段时,必须等待前一 run 段熵输出完成,防止码流
|
||||
顺序被重排。
|
||||
- 允许条带边界上下文重置插入暂停周期,暂停周期计入吞吐统计,并应尽量降低
|
||||
对 200 MPixel/s 指标的影响;若影响明显,应采用 epoch/tag、双表或其它流水化
|
||||
重置方案优化。
|
||||
- 当前 RTL 应优先采用 context written-bit/epoch/tag 惰性初始化等价实现,在条带
|
||||
开始锁存默认 `A/B/C/N` 并把未写 context 读作默认值,避免 365 个 regular
|
||||
context 逐项清表形成固定长暂停。
|
||||
- 允许使用多周期计算,但不得牺牲主时钟频率或 200 MPixel/s 连续输入吞吐目标;
|
||||
若多周期实现形成吞吐瓶颈,必须继续拆分逻辑深度并流水化。
|
||||
- 复杂条件判断必须拆分为多个流水节拍,禁止在单个 `always_comb` 或
|
||||
`always_ff` 块中形成长条件链。
|
||||
- 复杂条件分支优先使用 `case` 或分级状态机实现,避免深层 `if-else` 链。
|
||||
- `LSE` 默认参数、阈值参数和与 `PIX_WIDTH/NEAR` 相关的固定组合可使用常量表或
|
||||
ROM 方式实现,避免运行时复杂组合计算。
|
||||
- 允许增加固定流水延迟换取时序收敛;首字节延迟和单帧输出完成延迟不作为硬性
|
||||
指标。
|
||||
- 时序优化必须用 quick synthesis 或更完整的实现报告验证;若缓冲、扇出属性、
|
||||
控制复制等优化尝试导致 WNS/TNS 恶化,应回退并记录原因。时序收敛评审应先导出
|
||||
全部负 slack 路径,再按是否包含 DSP48 和逻辑级数分类;当 DSP 乘法器路径暂时
|
||||
难以继续优化时,先优化不含 DSP 且逻辑级数大于 1 的 ready/CE、行边界判断、
|
||||
输出槽满/空判断等控制路径,降低非 DSP 路径压力后再复查 DSP 路径是否仍主导
|
||||
WNS。对宽 DSP 乘法的进一步拆分必须继续用综合结果验证,已经证明会显著恶化
|
||||
WNS 的手动高/低半字拆分方案不应保留。
|
||||
- 各模块输出原则上采用寄存器输出,跨模块接口避免直接串接长组合逻辑。
|
||||
- 为降低复位扇出和时序压力,允许同步复位只覆盖状态机、valid 标志、计数器、
|
||||
FIFO 指针等控制状态;纯数据流水寄存器可不复位,但必须由 valid 信号保证无效
|
||||
数据不会参与新的图像压缩。
|
||||
|
||||
## 7. 性能指标
|
||||
|
||||
| 指标 | 目标值 | 说明 |
|
||||
| --- | ---: | --- |
|
||||
| 时钟频率 | 250 MHz | 综合后目标频率 |
|
||||
| 输入流水线峰值 | 1 像素/周期 | 输出缓冲可用时的峰值处理能力 |
|
||||
| 峰值输入吞吐 | 250 MPixel/s | 多帧连续输入场景下的目标峰值 |
|
||||
| 输出接口吞吐 | 1 byte/周期 | `ofifo_wdata[7:0]` 固定字节流 |
|
||||
| 首字节延迟 | 实现相关 | 受 header 输出和内部流水线影响 |
|
||||
| 单帧输出完成延迟 | 不作强约束 | 受压缩率、byte stuffing 和输出接口限制 |
|
||||
|
||||
连续多帧输入吞吐测试定义为:连续 10 幅图像输入时,从第一幅图像第一个像素被
|
||||
读取开始,到第 10 幅图像最后一个像素被读取结束的平均输入吞吐率。
|
||||
在 250 MHz 时钟下,连续 10 帧测试的平均输入读取吞吐率应不低于
|
||||
200 MPixel/s。该硬性指标适用于 `ratio=1/2/3`、默认尺寸 `6144 x 256`、连续
|
||||
10 幅代表性图像的性能测试;`ratio=0` 无损模式只报告吞吐率,不作为
|
||||
200 MPixel/s 硬性约束。统计时排除上游 `ififo_empty=1` 导致的空等待周期;
|
||||
内部输出缓冲接近满、熵编码极端长码处理和条带边界重置导致的暂停周期计入吞吐统计。
|
||||
|
||||
### 7.1 带宽说明
|
||||
|
||||
16 bit 图像在 250 MHz、1 像素/周期输入时,原始输入数据率为 500 MByte/s。
|
||||
输出接口固定为每周期 1 byte,即 250 MByte/s。无损或低压缩率图像可能导致输出
|
||||
缓冲积压,因此端到端持续吞吐不承诺等于输入流水线峰值。
|
||||
|
||||
## 8. 编码规范
|
||||
|
||||
- 使用 SystemVerilog 实现。
|
||||
- 所有端口使用 `logic` 类型,不使用 `wire` 和 `reg` 端口类型。
|
||||
- 简单直连允许使用 `assign`;禁止在 `assign` 中实现两级及以上组合逻辑。
|
||||
- 组合逻辑采用 `always_comb`。
|
||||
- 时序逻辑采用 `always_ff`。
|
||||
- `always_ff` 中只能使用非阻塞赋值,禁止使用阻塞赋值。
|
||||
- `always_comb` 中使用阻塞赋值描述组合逻辑。
|
||||
- 禁止在 `always`、`always_comb`、`always_ff` 块内部定义局部变量;局部变量必须
|
||||
在过程块外声明。
|
||||
- 不使用 `task`。
|
||||
- 不使用复杂 `function`;仅允许简单、无状态、无全局变量依赖、不会形成长组合
|
||||
路径的函数。复杂算法逻辑必须拆分为模块或流水级。
|
||||
- 复杂条件分支优先使用 `case` 或状态机,避免深层 `if-else`。
|
||||
- 复杂条件判断必须拆分为多个节拍,不允许在一个过程块中完成过深判断链。
|
||||
- 统一时钟域,上升沿触发。
|
||||
- 所有模块采用同步复位,高电平有效。
|
||||
- 信号命名采用小写加下划线,例如 `pixel_data`。
|
||||
- 参数命名采用大写加下划线,例如 `PIX_WIDTH`。
|
||||
- 所有参数、关键内部变量和跨模块接口信号必须添加有意义的英文注释,说明物理
|
||||
含义、单位、合法范围和与 JPEG-LS 标准的关系,避免只重复变量名。
|
||||
- 与 JPEG-LS 标准伪代码重合的变量,应尽量沿用标准中的名称或可直接对应的名称,
|
||||
例如 `A`、`B`、`C`、`N`、`Nn`、`Ra`、`Rb`、`Rc`、`Rd`、`Px`、`Errval`、
|
||||
`MErrval`、`k`、`RUNindex`、`RUNval`、`RItype`、`EMErrval` 等;若因工程命名
|
||||
规范需要改写大小写或加前缀,必须在注释中标明对应的标准变量。
|
||||
- 对复杂数据结构和处理流程必须在代码或配套文档中给出示例说明,例如 context
|
||||
表项含义、line buffer 像素邻域、near-lossless 重建像素更新、Golomb code
|
||||
bitstream 打包、条带边界 flush、动态 `NEAR` 更新等。
|
||||
- 每个关键处理过程必须添加标准可追溯注释,标明标准名称、章节、图、表和伪代码
|
||||
或代码片段来源。若该处理过程没有对应图或表,应明确写 `Figure: N/A` 或
|
||||
`Table: N/A`;禁止凭记忆编造图号、表号或章节号。
|
||||
- 状态命名采用 `st_module_state` 风格。
|
||||
- 一个模块一个文件,文件名与模块名一致。
|
||||
- 顶层仅包含子模块例化。
|
||||
- 单模块不超过 1000 行。
|
||||
- 单文件注释率不低于 20%。
|
||||
- 代码注释使用英文。
|
||||
- RTL 设计文件不得包含 `ifdef SYNTHESIS`、`ifndef SYNTHESIS`、`translate_off/on`
|
||||
等导致仿真路径和综合路径行为不一致的分支;不得在 RTL 设计文件中放置仿真专用
|
||||
功能逻辑、断言、错误判定或影响验证 PASS/FAIL 的检查。调试打印若确需保留,
|
||||
必须先评审确认,且不得改变 RTL 行为或作为验证通过依据。默认情况下,所有此类
|
||||
检查必须放在 testbench、monitor、scoreboard 或验证脚本中。
|
||||
- 其它规则参见 `fpga/srs/SystemVerilog coding style.md`。
|
||||
|
||||
### 8.1 标准可追溯注释规范
|
||||
|
||||
关键模块文件头或关键过程块前必须包含如下格式的英文注释:
|
||||
|
||||
```systemverilog
|
||||
// Standard : ITU-T T.87 (06/1998) / ISO/IEC 14495-1 JPEG-LS Baseline
|
||||
// Clause : Annex A.4 Prediction
|
||||
// Figure : N/A
|
||||
// Table : N/A
|
||||
// Pseudocode : Standard prediction procedure, mapped to Px calculation
|
||||
// Example : See docs/jls_traceability.md, section "MED predictor example"
|
||||
```
|
||||
|
||||
标准引用约束:
|
||||
|
||||
- `Standard` 必须写完整标准名称:`ITU-T T.87 (06/1998) / ISO/IEC 14495-1
|
||||
JPEG-LS Baseline`。
|
||||
- `Clause` 必须填写官方标准中的精确章节、附录或小节号。
|
||||
- `Figure` 和 `Table` 必须填写官方标准中的精确编号;若无对应项,写 `N/A`。
|
||||
- `Pseudocode` 必须说明该 RTL 过程对应标准伪代码中的哪一段处理。
|
||||
- 复杂处理必须在配套文档中给出小规模输入示例、关键中间变量和输出结果。
|
||||
- 若实现逻辑与标准伪代码存在流水化、查表、旁路或多周期等结构差异,注释必须
|
||||
说明等价关系。
|
||||
- 不得在 RTL 注释中大段复制标准原文;只记录引用位置、变量对应关系和工程化
|
||||
说明。
|
||||
|
||||
处理过程与标准章节的初始对照如下,后续应在 RTL 前根据正式标准 PDF 补齐精确图
|
||||
号、表号和伪代码位置:
|
||||
|
||||
| 处理过程 | 主要 RTL 模块 | 标准章节 |
|
||||
| --- | --- | --- |
|
||||
| 编码总体流程 | `jpeg_ls_encoder_top`, `jls_scan_ctrl` | Clause 4.4, Annex A.8, Annex D.1-D.3 |
|
||||
| 单分量编码参数和压缩数据 | `jls_scan_ctrl`, `jls_header_writer` | Annex A.1 |
|
||||
| 初始化和约定 | `jls_scan_ctrl`, `jls_context_model` | Annex A.2 |
|
||||
| 上下文确定 | `jls_context_model` | Annex A.3, Annex G.1 |
|
||||
| MED 预测 | `jls_predictor` | Annex A.4 |
|
||||
| 预测误差编码 | `jls_golomb_encoder` | Annex A.5, Annex G.2 |
|
||||
| 上下文变量更新 | `jls_context_model` | Annex A.6 |
|
||||
| run mode 编码 | `jls_run_mode` | Annex A.7, Annex G.3 |
|
||||
| JPEG-LS 码流格式和 marker | `jls_header_writer`, `jls_bit_packer` | Annex C.1-C.4 |
|
||||
| scan 控制流程 | `jls_scan_ctrl`, `jls_header_writer` | Annex D.3 |
|
||||
| bitstream 输出示例 | `jls_bit_packer` | Annex H.2 |
|
||||
| 详细编码示例 | 多模块联合说明 | Annex H.3 |
|
||||
| 解码一致性验证 | 验证脚本、CharLS 和 libjpeg 参考库对比 | Annex F.1 |
|
||||
|
||||
## 9. 验证方案
|
||||
|
||||
### 9.1 工具与目录
|
||||
|
||||
- RTL 仿真使用 QuestaSim。
|
||||
- 仿真平台放在 `fpga/simulation`。
|
||||
- 综合工程和脚本放在 `fpga/synthesis`。
|
||||
- CharLS 参考工具放在 `third_party/charls`。
|
||||
- jpeg.org 列出的 libjpeg 参考库放在 `third_party/libjpeg`,用于与 CharLS 共同
|
||||
做标准码流兼容性验证。该库来源记录为 jpeg.org JPEG-LS Software 页面列出的
|
||||
`thorfdbg/libjpeg` 项目,GitHub 地址为
|
||||
https://github.com/thorfdbg/libjpeg/tree/master。
|
||||
- CharLS-JS 浏览器页面可作为人工快速查看工具:
|
||||
https://chafey.github.io/charls-js/test/browser/index.html
|
||||
- 条带多 frame 兼容性实验工具放在 `tools/jls_compat`。参考解码对比脚本使用
|
||||
`tools/jls_compat/reference_decode_compare.py`,该脚本通过 CharLS 与
|
||||
jpeg.org/libjpeg 参考库对 RTL 输出 `.rtljls` 做解码和像素比较。
|
||||
|
||||
### 9.2 验证方法
|
||||
|
||||
1. 单元测试:各子模块独立验证。
|
||||
2. 集成测试:完整 encoder 生成 JPEG-LS 码流。
|
||||
3. 标准兼容性测试:使用 CharLS 和 jpeg.org/libjpeg 参考库解码 RTL 输出码流。
|
||||
4. 误差测试:比较参考库解码图像与输入图像。
|
||||
5. 压缩比测试:按实际 bit 数统计目标值与输出值。
|
||||
6. 性能测试:统计输入吞吐、输出吞吐、暂停周期和内部输出缓冲水位。
|
||||
|
||||
参考库验证策略:
|
||||
- 冒烟测试阶段使用小规模测试集合优先跑通 libjpeg 参考库解码验证,用于快速发现
|
||||
marker、header、bit stuffing、条带多 frame 拼接等基础兼容性问题。
|
||||
- 设计成熟后,完整回归测试必须同时使用 CharLS 和 libjpeg 参考库解码 RTL 输出。
|
||||
- 若 CharLS 与 libjpeg 对同一码流的解码结果或错误判断不一致,验证报告必须记录
|
||||
差异,并将该用例标记为兼容性待评审项;在评审关闭前不得作为通过项。
|
||||
|
||||
### 9.3 测试用例
|
||||
|
||||
- 8 bit 灰度图像,`ratio=0` 无损编码。
|
||||
- 10 bit 灰度图像,`ratio=1/2/3` 近损编码。
|
||||
- 12 bit 灰度图像,`ratio=1/2/3` 近损编码。
|
||||
- 14 bit 灰度图像,`ratio=1/2/3` 近损编码。
|
||||
- 16 bit 灰度图像,`ratio=0` 无损编码。
|
||||
- 默认尺寸 `6144 x 256` 图像。
|
||||
- 最大行宽 `6144` 图像。
|
||||
- 高度最大值 `4096` 的边界测试。
|
||||
- 最小合法尺寸 `16 x 16`。
|
||||
- 连续 10 幅图像输入吞吐测试。
|
||||
- 输入 FIFO 暂停测试:`ififo_empty` 和 `ififo_alempty` 拉高场景。
|
||||
- 输出缓冲接近满导致输入暂停测试。
|
||||
- 条带多 frame 码流 CharLS 解码兼容性测试。
|
||||
- 条带多 frame 码流 libjpeg 参考库解码兼容性测试。
|
||||
- 小尺寸连续多图像冒烟测试:在同一输入流中连续送入多个 SOF 图像,检查每幅
|
||||
原始图像的输出起始 sideband、`SOI...EOI` frame 数量和参考解码结果;该冒烟
|
||||
不替代正式连续 10 幅默认尺寸吞吐测试。
|
||||
- 动态 `NEAR>0` 条带多 frame 冒烟测试:使用非零 `ratio` 触发后续条带近损编码,
|
||||
参考库解码必须成功,像素比较按 near-lossless 允许误差范围统计并报告。
|
||||
- 200 MPixel/s 性能测试:默认尺寸 `6144 x 256`、至少 10 幅代表性灰度图像,
|
||||
覆盖平滑、渐变、噪声、边缘和纹理场景;`ratio=1/2/3` 三组均需测试,任一组
|
||||
不达标则该性能项 FAIL;具体图像清单在验证计划中维护。
|
||||
阶段性可执行入口为 `fpga/sim/run_jls_throughput_regression.ps1`,该脚本使用
|
||||
`tb_jpeg_ls_encoder_top_run_smoke` 的 `+CHECK_THROUGHPUT=1` 模式,并把统计结果
|
||||
写入 `tools/jls_compat/out/rtl_throughput_stats.csv`。完整回归阶段仍必须结合
|
||||
CharLS 和 jpeg.org/libjpeg 参考解码验证码流兼容性。
|
||||
|
||||
验证报告必须记录:
|
||||
|
||||
- 每幅图像的配置尺寸、实际生效尺寸、`PIX_WIDTH` 和 `ratio`。
|
||||
- 每个条带 frame 的 `NEAR`、累计实际输出 bit 数、累计目标 bit 数。
|
||||
- 每幅图像的最终输出字节数、实际压缩比和目标压缩比偏差。
|
||||
- 每个条带 frame 的最大像素误差和每幅图像的最大像素误差。
|
||||
- 输入暂停周期数、输出缓冲最大水位。
|
||||
|
||||
仿真断言和检查项:
|
||||
|
||||
- 以下检查必须由 testbench、monitor、scoreboard 或验证脚本实现,不得依赖 RTL
|
||||
设计文件中的仿真专用分支;RTL 仿真和综合应使用同一套设计逻辑。
|
||||
- 若 `ofifo_full=1` 时 `ofifo_wr=1`,仿真报错。
|
||||
- 若内部输出缓冲 overflow,仿真报错。
|
||||
- 若连续 10 帧性能测试在排除上游 `ififo_empty=1` 周期后仍低于
|
||||
200 MPixel/s,仿真报错。
|
||||
- 若运行时尺寸配置非法,记录 warning,并回退默认尺寸。
|
||||
- 若完整回归阶段 CharLS 和 libjpeg 参考库解码结果不一致,仿真或验证脚本记录
|
||||
compatibility FAIL。
|
||||
- 仿真脚本不得只依赖仿真器进程退出码判断 PASS;必须同时检查日志中的
|
||||
`$fatal`/`** Fatal` 和非零 `Errors:` 汇总,避免 QuestaSim 在 `quit` 后返回 0
|
||||
时误报通过。
|
||||
|
||||
### 9.4 测试数据格式
|
||||
|
||||
- 输入测试数据使用 big-endian raw 像素文件。
|
||||
- `PIX_WIDTH=8` 时,每个像素按 1 byte 存储。
|
||||
- `PIX_WIDTH=10/12/14/16` 时,每个像素按 16 bit big-endian word 存储,高位
|
||||
补 0;压缩比目标仍按实际 `PIX_WIDTH` bit 计算。
|
||||
- 仿真脚本负责将 raw 输入文件转换为 FIFO word。
|
||||
- RTL 输入 FIFO 总线仍按 3.3 节定义,像素数值低位对齐,保留位为 0。
|
||||
- RTL 输出保存为 `.rtljls` 字节文件,用 CharLS 和 libjpeg 参考库解码验证。
|
||||
|
||||
### 9.5 固定测试图像集
|
||||
|
||||
- 固定测试图像必须作为仓库文件长期保存,回归和仿真默认直接读取这些文件,
|
||||
不允许在每次测试时重新生成随机图像。
|
||||
- 如需保留图像生成脚本,只能作为显式维护工具使用;测试入口不得隐式重建图像。
|
||||
- 固定测试图像使用标准二进制 PGM(`P5`)格式。
|
||||
- `16 bit` PGM 像素按 big-endian word 存储。
|
||||
- 当前固定测试图像均为无符号像素,命名中的 `s=0`;若后续扩展到有符号图像,
|
||||
则 `s=1`。
|
||||
- 固定测试图像命名规则为
|
||||
`<name>-w<w>-h<h>-s<s>-b<b>.pgm`,其中 `w` 为宽度像素数、`h` 为高度像素数、
|
||||
`s` 为符号标志(`0` 无符号,`1` 有符号)、`b` 为像素位宽。
|
||||
- CharLS 参考压缩码流命名规则为
|
||||
`<name>-w<w>-h<h>-s<s>-b<b>-r<r>.charlsjls`。
|
||||
- libjpeg 参考压缩码流命名规则为
|
||||
`<name>-w<w>-h<h>-s<s>-b<b>-r<r>.libjls`。
|
||||
- 上述命名中的 `r` 对应 RTL 的 `ratio` 配置值。
|
||||
- CharLS 参考压缩码流文件统一保存到 `img/reference/charls` 目录。
|
||||
- CharLS 参考压缩码流文件内容必须为纯 JPEG-LS interchange codestream,
|
||||
即从 `SOI` 开始到 `EOI` 结束,不允许在 `.charlsjls` 文件中保留 SPIFF
|
||||
包裹头;若第三方编码器默认输出 SPIFF 容器,参考生成脚本必须先剥离外层 SPIFF,
|
||||
再保存内部 `SOI..EOI` 码流。
|
||||
- libjpeg 参考压缩码流文件统一保存到 `img/reference/libjpeg` 目录。
|
||||
|
||||
### 9.6 扩展真实纹理图像
|
||||
|
||||
- `./img` 根目录中现有 4 幅原始图像作为真实纹理源,文件如下:
|
||||
- `omaha-w256-h256-b8-r0.img`
|
||||
- `sena-w256-h256-b8-r0.img`
|
||||
- `sensin-w256-h256-b8-r0.img`
|
||||
- `sinan-w256-h256-b8-r0.img`
|
||||
- 上述文件均为 `256 x 256 x 8 bit` raw 图像,每个文件大小固定为 `65536` byte。
|
||||
- 这 4 个 `.img` 文件仅作为维护性重建输入保留,不作为回归测试时直接读取的固定
|
||||
PGM 图像。
|
||||
- 第一版固定测试集中,需要将这 4 幅图像扩展为 `6144 x 256 x 16 bit` 标准 PGM。
|
||||
- 扩展方法为沿宽度方向重复复制原始 `256 x 256` 图像,直到覆盖完整的 `6144`
|
||||
列;如果复制后超过目标宽度,则裁剪多余列。
|
||||
- 扩展过程中保持原始行序和列序不变,不做插值、不做镜像、不做重排。
|
||||
- 原始 `8 bit` 像素值按线性比例扩展到目标 `16 bit` 无符号像素范围;
|
||||
`0x00 -> 0x0000`,`0xFF -> 0xFFFF`,即目标像素值等于 `raw8 * 257`
|
||||
(等价于 `(raw8 << 8) | raw8`),而不是仅放入低 `8 bit`。
|
||||
- 之前“低 `8 bit` 直写、高 `8 bit` 清零”的扩展方式已废止,不得继续用于真实纹理图像生成、
|
||||
参考码流生成或回归验证。
|
||||
- 扩展后的图像保存到 `img/patterns` 目录,作为固定测试图像集的一部分。
|
||||
- 扩展图像命名为 `*-w6144-h256-s0-b16.pgm`。
|
||||
|
||||
### 9.7 人工图案测试图像
|
||||
|
||||
- 人工图案图像保存到 `img/patterns` 目录。
|
||||
- 上述 4 幅真实纹理扩展图也放在 `img/patterns` 目录,与人工图案统一管理。
|
||||
- 第一版人工图案统一采用 `6144 x 256 x 16 bit`、无符号、标准 PGM。
|
||||
- 条带类和周期类图案默认空间周期为 `256` 像素。
|
||||
- 棋盘图案的单元尺寸固定为 `32 x 32` 像素。
|
||||
- 噪声图像必须使用固定随机种子,保证每次维护性重建时图像内容完全一致;
|
||||
第一版使用种子 `1`。
|
||||
- 点目标图像使用黑色背景,仅在四个角点和几何中心放置 `1x1` 白点。
|
||||
- 几何中心坐标定义为 `(3072, 128)`。
|
||||
- 需要固化以下人工图案:
|
||||
- `horizontal_stripes`:横向条带,像素值随 `y` 方向在 `0..65535` 间均匀变化。
|
||||
- `vertical_stripes`:纵向条带,像素值随 `x` 方向在 `0..65535` 间均匀变化。
|
||||
- `sine_stripes`:正弦条带,沿主变化方向按正弦规律在 `0..65535` 间变化。
|
||||
- `sawtooth_stripes`:锯齿条带,沿主变化方向按锯齿规律在 `0..65535` 间变化。
|
||||
- `diagonal_stripes`:对角线条带,按 `x+y` 相位在 `0..65535` 间周期变化。
|
||||
- `anti_diagonal_stripes`:反对角线条带,按 `x-y` 相位在 `0..65535` 间周期变化。
|
||||
- `concentric_stripes`:同心圆条带,相对图像中心按半径周期变化。
|
||||
- `checkerboard`:棋盘图案,黑白两色分别取 `0` 和 `65535`。
|
||||
- `noise_uniform_seed1`:均匀噪声图像,像素值在 `0..65535` 间无符号均匀分布。
|
||||
- `point_targets`:黑底点目标图像,点位于四角和中心,点值为 `65535`。
|
||||
- `white`:纯白图像,所有像素值均为 `65535`。
|
||||
- `black`:纯黑图像,所有像素值均为 `0`。
|
||||
- `diagonal_gradient`:对角线渐变图像,按全图归一化坐标从 `0` 线性渐变到
|
||||
`65535`。
|
||||
|
||||
## 10. 综合实现
|
||||
|
||||
采用 Vivado 进行综合验证,保证 RTL 可综合,并报告资源使用情况和综合后 Fmax。
|
||||
综合相关文件放在 `fpga/synthesis`。
|
||||
|
||||
目标 FPGA part 确认为 `xc7vx690tffg1761-2`。
|
||||
|
||||
Vivado quick synthesis 脚本需要保留在工程中,但在所有 RTL 模块完整实现前不作为
|
||||
自动推进步骤运行,避免过长综合时间影响迭代效率;仅在用户明确要求或完整模块
|
||||
集成后运行,用于确认可综合性、资源利用率趋势和初步 250 MHz 时序风险。quick
|
||||
synthesis 报告不替代最终综合实现报告。
|
||||
quick synthesis 脚本必须读取 `fpga/verilog/jpeg_ls_rtl.f` 中的完整 RTL 编译清单,
|
||||
不得使用早期手写子集产生顶层综合结论。
|
||||
|
||||
第一版暂不设置 LUT、FF、BRAM、DSP 的硬性资源上限;资源占用以 Vivado 综合报告
|
||||
为准,并在评审时结合 `OUT_BUF_BYTES` 等参数进行调整。
|
||||
|
||||
本轮 quick synthesis 阶段性结果:目标 part 为 `xc7vx690tffg1761-2`,
|
||||
约束周期 4.000 ns,`jpeg_ls_encoder_top` WNS 为 -0.615 ns,TNS 为 -175.754 ns,
|
||||
失败端点 537 个;按 4.615 ns 近似估算,OOC 综合层面的等效频率约为
|
||||
216.7 MHz,该结果不替代实现后 Fmax。资源使用为 LUT 22895、寄存器 6308、
|
||||
BRAM tile 3.5、DSP 14。最差路径仍为 `context_update_i/s1_near_scale_reg[6]`
|
||||
到 `context_update_i/s2_B_delta_reg/PCIN[*]` 的 DSP48E1 PCIN 路径,数据路径延迟
|
||||
3.557 ns,其中逻辑约占 86.889%、布线约占 13.111%。全量负 slack 路径已导出到
|
||||
`fpga/synthesis/quick_synth_reports/jpeg_ls_encoder_top_timing_violations_all.rpt`,
|
||||
分类 CSV 已导出到同目录;当前 537 条负 slack 路径中,260 条包含 DSP48,277 条为
|
||||
不含 DSP 且逻辑级数大于 1 的路径。已保留的非 DSP 优化包括:`jls_context_model`
|
||||
结果二级槽写使能去除下游 ready 依赖,`jls_scan_ctrl` 提前注册
|
||||
`enc_row_last_pixel` 以切断 `strip_width` 到 `jls_neighbor_provider.Rd` 的行尾判断路径,
|
||||
以及 `jls_regular_error_quantizer` 在 `STATE_IDLE` 接收下一像素、到 `STATE_FINISH`
|
||||
再等待输出槽的 ready 解耦。手动把 `jls_context_update` 的 33x8 乘法拆成高/低半字
|
||||
partial product 的试验曾导致 WNS 恶化到 -1.468 ns,已回退。
|
||||
|
||||
## 11. 实现计划
|
||||
|
||||
详细长期工作计划见 `docs/jls_work_plan.md`。本文档中的阶段和里程碑为需求级约束,
|
||||
`docs/jls_work_plan.md` 用于维护执行顺序、当前状态、阻塞项和自动推进策略。
|
||||
|
||||
| 阶段 | 内容 | 里程碑 |
|
||||
| --- | --- | --- |
|
||||
| 1 | 需求评审与 CharLS/libjpeg 兼容性实验 | 确认条带多 frame 方案 |
|
||||
| 2 | 架构设计与模块接口细化 | RTL 模块接口冻结 |
|
||||
| 3 | 核心模块 RTL 实现 | 各模块单元测试通过 |
|
||||
| 4 | 顶层集成与码流验证 | CharLS 和 libjpeg 参考库可解码输出码流 |
|
||||
| 5 | 动态 `NEAR` 调优与性能测试 | 压缩比统计和误差报告完成 |
|
||||
| 6 | 综合与时序优化 | 250 MHz 目标评估完成 |
|
||||
|
||||
## 12. 风险与对策
|
||||
|
||||
| 风险 | 影响 | 对策 |
|
||||
| --- | --- | --- |
|
||||
| 单 frame 多 scan 条带标准兼容性不足 | CharLS 或其它标准解码器不能解码 | 已改为每条带独立 JPEG-LS frame;保留兼容性探针防止回退 |
|
||||
| 输出接口带宽不足 | 内部输出缓冲满,输入被暂停 | 明确端到端吞吐受输出限制;输出缓冲参数化 |
|
||||
| 250 MHz 时序不收敛 | 达不到 200 MPixel/s 连续输入吞吐 | 高流水线实现、拆分长组合路径、寄存器切分上下文表和 bit packer 路径 |
|
||||
| 动态 `NEAR` 控制效果不足 | 压缩比偏差超过预期 | 先实现简单步进,再参考专利优化累计偏差控制 |
|
||||
| LSE/header 生成复杂 | 增加控制状态和验证工作 | 独立 `jls_header_writer` 模块并使用 CharLS 与 libjpeg 参考库做码流验证 |
|
||||
| run mode 实现错误 | 压缩效率下降或码流错误 | 单独建立 run mode 单元测试和边界样例 |
|
||||
|
||||
## 13. 交付物
|
||||
|
||||
1. SystemVerilog encoder RTL 代码。
|
||||
2. QuestaSim 测试平台和测试用例。
|
||||
3. CharLS 与 libjpeg 参考库兼容性实验和参考验证脚本。
|
||||
4. Vivado 综合脚本和约束文件。
|
||||
5. 验证报告。
|
||||
6. 使用文档。
|
||||
7. 标准可追溯说明文档:`docs/jls_traceability.md`,用于记录关键处理过程对应
|
||||
的标准名称、章节、图、表、伪代码位置、RTL 代码片段、变量对照和示例说明。
|
||||
8. 长期工作计划与验证计划:`docs/jls_work_plan.md`、`docs/jls_verification_plan.md`。
|
||||
9. Mermaid 算法流水流程图:`docs/jls_pipeline_mermaid.md`,用于记录当前 RTL
|
||||
实现的流水环节、输入输出、处理内容以及标准章节/伪代码对应关系。
|
||||
|
||||
---
|
||||
|
||||
文档版本:V1.1
|
||||
|
||||
更新日期:2026-04-15
|
||||
|
||||
目标芯片:Xilinx Virtex-7 XC7V690T
|
||||
|
||||
目标频率:250 MHz
|
||||
|
||||
峰值输入吞吐:250 MPixel/s
|
||||
294
fpga/srs/jpeg_ls_design.drawio
Normal file
294
fpga/srs/jpeg_ls_design.drawio
Normal file
@@ -0,0 +1,294 @@
|
||||
<mxfile host="app.diagrams.net" modified="2026-04-13T00:00:00.000Z" agent="Codex" version="24.7.17" type="device">
|
||||
<diagram id="jpeg-ls-architecture" name="软件框图">
|
||||
<mxGraphModel dx="1800" dy="1100" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1800" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="title_arch" value="JPEG-LS FPGA Encoder 软件框图" style="text;html=1;strokeColor=none;fillColor=none;fontSize=24;fontStyle=1;align=center;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="500" y="30" width="800" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="cfg" value="运行时配置<br>cfg_pic_col/cfg_pic_row<br>ratio<br>SOF 时采样" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="90" width="210" height="90" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ififo" value="输入 FIFO<br>ceil(PIX_WIDTH/8)*9<br>SOF + 像素低位对齐<br>同步读:rd 后下一拍有效" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="240" width="230" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="input_ctrl" value="jls_input_ctrl<br>SOF 检测<br>尺寸/ratio 锁存<br>empty/alempty 读控制<br>输出缓冲满时暂停输入" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="350" y="230" width="240" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="scan_ctrl" value="jls_scan_ctrl<br>行列计数<br>SCAN_ROWS 条带划分<br>scan 边界控制<br>上下文重置触发" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="230" width="220" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="header" value="jls_header_writer<br>SOI/SOF55/LSE/SOS/EOI<br>每 scan 写 NEAR<br>LSE 策略可按兼容性调整" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="960" y="110" width="230" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="lse_table" value="LSE/阈值常量表<br>PIX_WIDTH + NEAR<br>默认 MAXVAL/T1/T2/T3/RESET" style="shape=cylinder3d;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#f8cecc;strokeColor=#b85450;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="1220" y="110" width="230" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="line_buf" value="line buffer / 重建像素缓存<br>存编码端重建值<br>支持 Ra/Rb/Rc/Rd 访问<br>BRAM/LUTRAM/SRL 混合" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="420" width="250" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="predictor" value="jls_predictor<br>MED 预测<br>边界像素处理<br>流水寄存器切分" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="450" width="220" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="mode" value="模式判定<br>regular / run mode<br>使用 case / 状态机<br>复杂条件拆多拍" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="610" width="220" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="context" value="jls_context_model<br>A/B/C/N 统计表<br>bypass/forwarding<br>禁止读旧 context" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="610" width="250" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="runmode" value="jls_run_mode<br>run 检测<br>run 长度编码<br>中断样本处理" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="760" width="250" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="golomb" value="jls_golomb_encoder<br>误差映射<br>Golomb-Rice 编码<br>极端长码可多周期" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="980" y="610" width="230" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="packer" value="jls_bit_packer<br>bit 打包<br>字节边界补齐<br>marker/zero-bit stuffing" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1280" y="610" width="240" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="near" value="jls_near_ctrl<br>scan 级 NEAR<br>累计目标 bit / 实际 bit<br>0..31 钳位" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="980" y="380" width="230" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="outbuf" value="jls_output_buffer<br>OUT_BUF_BYTES=8192<br>AFULL_MARGIN=256 需估算<br>只随字节流保留 ofifo[8]" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1280" y="380" width="240" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="ofifo" value="输出 FIFO<br>ofifo_wdata[8:0]<br>[8]=原图 SOI 开始标志<br>[7:0]=标准 JPEG-LS 字节流" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1560" y="400" width="220" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="verify" value="验证参考<br>CharLS / CharLS-JS<br>解码 .jls<br>误差和压缩比报告" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=14;arcSize=8;dashed=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="1560" y="610" width="220" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="note1" value="高主频约束<br>250 MHz 主时钟<br>ratio=1/2/3 需达 200 MPixel/s<br>复杂逻辑拆多拍,不牺牲主频" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="760" width="240" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="note2" value="复位策略<br>控制状态必须复位<br>纯数据流水寄存器可不复位<br>valid 保护无效数据" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="610" width="240" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_cfg_in" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="cfg" target="input_ctrl">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_ififo_in" value="pixel stream" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="ififo" target="input_ctrl">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_input_scan" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="input_ctrl" target="scan_ctrl">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_scan_header" value="frame/scan control" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="scan_ctrl" target="header">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_lse_header" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="lse_table" target="header">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_header_out" value="markers" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="header" target="outbuf">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_scan_pred" value="pixels + coords" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="scan_ctrl" target="predictor">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_line_pred" value="Ra/Rb/Rc/Rd" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="line_buf" target="predictor">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_pred_mode" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="predictor" target="mode">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_mode_context" value="regular" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="mode" target="context">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_mode_run" value="run" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="mode" target="runmode">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_context_golomb" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="context" target="golomb">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_run_golomb" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="runmode" target="golomb">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_golomb_packer" value="variable bits" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="golomb" target="packer">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_packer_outbuf" value="bytes" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="packer" target="outbuf">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_outbuf_ofifo" value="9 bit" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="outbuf" target="ofifo">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_outbuf_near" value="byte count" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="outbuf" target="near">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_scan_near" value="scan done" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="scan_ctrl" target="near">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_near_header" value="NEAR" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="near" target="header">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_near_context" value="NEAR" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="near" target="context">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_recon_line" value="reconstructed pixels" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="golomb" target="line_buf">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_ofifo_verify" value=".jls" style="endArrow=block;html=1;rounded=0;dashed=1;" edge="1" parent="1" source="ofifo" target="verify">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="jpeg-ls-workflow" name="工作流程">
|
||||
<mxGraphModel dx="1600" dy="1400" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1600" pageHeight="1400" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="title_flow" value="JPEG-LS Encoder 工作流程" style="text;html=1;strokeColor=none;fillColor=none;fontSize=24;fontStyle=1;align=center;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="30" width="800" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_reset" value="复位 / idle<br>控制状态复位<br>数据流水由 valid 保护" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="100" width="200" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_wait" value="等待输入 SOF=1<br>SOF=0 时继续等待" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="100" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_sample" value="采样配置<br>cfg_pic_col/cfg_pic_row/ratio<br>配置帧内保持不变" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="100" width="240" height="90" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_valid" value="尺寸是否合法?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="990" y="95" width="170" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_default" value="使用默认尺寸<br>6144 x 256<br>记录 warning" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1240" y="80" width="220" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_init" value="初始化帧状态<br>active 尺寸<br>NEAR=0<br>scan_index=0" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="250" width="240" height="90" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_header" value="输出帧/scan 头<br>SOI/SOF55<br>LSE 默认参数<br>SOS 写当前 NEAR" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="390" width="240" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_scan_reset" value="scan 开始<br>重置上下文/行缓存边界<br>必要暂停计入吞吐" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="390" width="250" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_read_ready" value="可读输入?<br>empty=0<br>输出缓冲有余量" style="rhombus;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="1000" y="385" width="190" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_pause" value="暂停 ififo_rd<br>等待 empty 解除或缓冲释放<br>内部暂停计入吞吐" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1270" y="400" width="250" height="90" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_pipe" value="读取像素并进入流水<br>MED 预测<br>regular/run 判定<br>context bypass/forwarding" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="570" width="260" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_entropy" value="熵编码流水<br>误差映射<br>Golomb-Rice<br>极端长码可多周期" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="700" y="570" width="240" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_pack" value="bit packer<br>字节打包<br>marker/zero-bit stuffing<br>写入内部输出缓冲" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1030" y="570" width="260" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_update_recon" value="更新重建像素历史<br>line buffer 使用重建值<br>context 统计写回" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="700" y="760" width="260" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_scan_done" value="当前 scan 完成?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="1040" y="760" width="190" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_align" value="scan 收尾<br>补齐到字节边界<br>统计实际输出 bit" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1280" y="750" width="230" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_ratio" value="ratio 是否为 0?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="940" width="180" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_near_fixed" value="NEAR 保持 0<br>无损模式<br>只报告吞吐" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="500" y="950" width="200" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_near_update" value="动态更新 NEAR<br>比较累计实际 bit 与目标 bit<br>钳位 0..31<br>下一 scan 生效" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1010" y="930" width="260" height="110" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_more_scan" value="还有 scan?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="760" y="1120" width="180" height="100" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_eoi" value="输出 EOI<br>完成当前原始图像<br>输出流按帧顺序排队" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;arcSize=8;" vertex="1" parent="1">
|
||||
<mxGeometry x="1010" y="1130" width="230" height="90" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="f_next" value="前级不忙则可接收下一帧<br>ofifo[8] 在新原图 SOI 首字节置 1" style="ellipse;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="1290" y="1135" width="250" height="85" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_reset_wait" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_reset" target="f_wait">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_wait_sample" value="SOF=1" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_wait" target="f_sample">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_sample_valid" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_sample" target="f_valid">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_valid_default" value="否" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_valid" target="f_default">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_valid_init" value="是" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_valid" target="f_init">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_default_init" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_default" target="f_init">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_init_header" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_init" target="f_header">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_header_scan_reset" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_header" target="f_scan_reset">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_scan_read" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_scan_reset" target="f_read_ready">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_read_pause" value="否" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_read_ready" target="f_pause">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_pause_read" value="重试" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_pause" target="f_read_ready">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_read_pipe" value="是" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_read_ready" target="f_pipe">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_pipe_entropy" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_pipe" target="f_entropy">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_entropy_pack" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_entropy" target="f_pack">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_pack_update" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_pack" target="f_update_recon">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_update_done" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_update_recon" target="f_scan_done">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_not_done" value="否" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_scan_done" target="f_read_ready">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_done_align" value="是" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_scan_done" target="f_align">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_align_ratio" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_align" target="f_ratio">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_ratio_fixed" value="是" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_ratio" target="f_near_fixed">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_ratio_update" value="否" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_ratio" target="f_near_update">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_fixed_more" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_near_fixed" target="f_more_scan">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_update_more" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_near_update" target="f_more_scan">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_more_header" value="是" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_more_scan" target="f_header">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_more_eoi" value="否" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_more_scan" target="f_eoi">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_eoi_next" value="" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_eoi" target="f_next">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="fe_next_wait" value="下一帧" style="endArrow=block;html=1;rounded=0;strokeWidth=2;" edge="1" parent="1" source="f_next" target="f_wait">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
Reference in New Issue
Block a user