x264_scan8 的理解

本文详细解析了H.264编码中亮度和色度块的4x4扫描顺序,通过具体代码展示了如何利用x264_scan8数组实现高效的数据访问,并节省内存空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上代码及注释
#define X264_SCAN8_SIZE (6*8) //!< 扫描表的尺寸
#define X264_SCAN8_0 (4+1*8) //!< 扫描表第一个扫描序(即亮度的首扫描序)

static const int x264_scan8[16+2*4+3] =
{
    /* Luma */
    4+1*8, 5+1*8, 4+2*8, 5+2*8,
    6+1*8, 7+1*8, 6+2*8, 7+2*8,
    4+3*8, 5+3*8, 4+4*8, 5+4*8,
    6+3*8, 7+3*8, 6+4*8, 7+4*8,

    /* Cb */
    1+1*8, 2+1*8,
    1+2*8, 2+2*8,

    /* Cr */
    1+4*8, 2+4*8,
    1+5*8, 2+5*8,

    /* Luma DC */
    4+5*8,

    /* Chroma DC */
    5+5*8, 6+5*8
};
/*
   0 1 2 3 4 5 6 7
 0
 1   B B   L L L L
 2   B B   L L L L
 3         L L L L
 4   R R   L L L L
 5   R R   DyDuDv
*/ // B -- Cb; R -- Cr; L -- Luma; Dy -- Luma DC; Du -- Cb DC; Dv -- Cr DC

 

x264_scan8是一个存放着4x4亮度块及色度块扫描序的数组,其内存存储方式如下所示:

其中,每一个小方格代表着一个4x4块,方格中的数字则是对应块的序号。

根据代码中对x264_scan8这个数组的赋值不难得到上图,其中,红色方块代表的是亮度块,绿色块和蓝色块分别代表两个色度块,而三个橙色块则依次代表亮度、两个色度的DC块。

为什么要这么做呢?我们知道,在进行帧内预测,帧间运动矢量预测的时候,需要使用到当前块的left块和top块,在CAVLC编码过程中,也需要知道当前块的left块和top块的non_zero_count,故由上图可以看到,空出来的部分可以用于存储前述所需的left块和top块的相关参数,起到便于访问和节省内存的作用。

看下面这个例子:

void x264_mb_predict_mv_16x16( x264_t *h, int i_list, int i_ref, int16_t mvp[2] )
{
    int     i_refa = h->mb.cache.ref[i_list][X264_SCAN8_0 - 1];		//!< a块参考帧序号
    int16_t *mv_a  = h->mb.cache.mv[i_list][X264_SCAN8_0 - 1];		//!< a块的运动矢量
    int     i_refb = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8];		//!< b块参考帧序号
    int16_t *mv_b  = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8];		//!< b块的运动矢量
    int     i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 + 4];	//!< c块参考帧序号
    int16_t *mv_c  = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 + 4];	//!< c块的运动矢量

    int i_count;

    if( i_refc == -2 )
    {
        i_refc = h->mb.cache.ref[i_list][X264_SCAN8_0 - 8 - 1];
        mv_c   = h->mb.cache.mv[i_list][X264_SCAN8_0 - 8 - 1];
    }

    i_count = 0;
    if( i_refa == i_ref ) i_count++;
    if( i_refb == i_ref ) i_count++;
    if( i_refc == i_ref ) i_count++;

    if( i_count > 1 )
        x264_median_mv( mvp, mv_a, mv_b, mv_c );
    else if( i_count == 1 )
    {
        if( i_refa == i_ref )
            *(uint32_t*)mvp = *(uint32_t*)mv_a;
        else if( i_refb == i_ref )
            *(uint32_t*)mvp = *(uint32_t*)mv_b;
        else
            *(uint32_t*)mvp = *(uint32_t*)mv_c;
    }
    else if( i_refb == -2 && i_refc == -2 && i_refa != -2 )
        *(uint32_t*)mvp = *(uint32_t*)mv_a;
    else
        x264_median_mv( mvp, mv_a, mv_b, mv_c );
}


其中,a块,b块,c块分别是当前宏块左、上、右上邻块,结合x264_scan8的赋值及上图不难分析出上述结论。

 

(转载请注明出处。)


``` #-------------------------------------------------------------- # Read Design #-------------------------------------------------------------- read_netlist ./lib/saed32nm.v read_netlist ./lib/pll.v read_verilog ../../subsys_a/DC/results/core_a_master_scan.v read_verilog ../../subsys_a/DC/results/core_a_slaver_scan.v read_verilog ../../subsys_a/DC/results/subsys_a_syn.v read_verilog ../../subsys_b/DC/results/core_b_scan.v read_verilog ../../subsys_b/DC/results/subsys_b_scan.v read_verilog ../../subsys_c/DC/results/subsys_c_scan.v read_verilog ./results/top_scan.v run_build top #-------------------------------------------------------------- # Run Design Rule Checks #-------------------------------------------------------------- add_clocks 0 ate_clk3 -shift add_clocks 0 pipe_clk -shift add_clocks 0 ref_clk -shift add_clocks 1 rst_n3 add_scan_enables 1 scan_en3 add_scan_enables 1 SCAN_EN add_pi_constraints 0 SPC_DISABLE add_pi_constraints 1 rst_n add_pi_constraints 1 rst_n1 add_pi_constraints 1 rst_n2 add_pi_constraints 1 rst_n3 add_pi_constraints 0 SCAN_EN add_pi_constraints 0 scan_en1 add_pi_constraints 0 scan_en2 add_pi_constraints 0 scan_en3 add_pi_constraints 0 subsys_a1_TM0_0 add_pi_constraints 1 subsys_a1_TM1_0 add_pi_constraints 0 subsys_a1_TM2_0 add_pi_constraints 0 subsys_a1_TM0_1 add_pi_constraints 1 subsys_a1_TM1_1 add_pi_constraints 0 subsys_a1_TM2_1 add_pi_constraints 0 subsys_a2_TM0_0 add_pi_constraints 1 subsys_a2_TM1_0 add_pi_constraints 0 subsys_a2_TM2_0 add_pi_constraints 0 subsys_a2_TM0_1 add_pi_constraints 1 subsys_a2_TM1_1 add_pi_constraints 0 subsys_a2_TM2_1 add_pi_constraints 0 subsys_b_TM0 add_pi_constraints 0 subsys_b_TM1 add_pi_constraints 1 subsys_b_TM2 add_pi_constraints 0 subsys_c_TM0 add_pi_constraints 1 subsys_c_TM1 add_pi_constraints 0 subsys_c_TM2 add_pi_constraints 0 SCAN_TM0 add_pi_constraints 0 SCAN_TM1 add_pi_constraints 0 SCAN_TM2 add_pi_constraints 0 subsys_a1_OCC_EN add_pi_constraints 0 subsys_a1_OCC_BYPASS add_pi_constraints 0 subsys_a1_OCC_RESET add_pi_constraints 0 subsys_a2_OCC_EN add_pi_constraints 0 subsys_a2_OCC_BYPASS add_pi_constraints 0 subsys_a2_OCC_RESET add_pi_constraints 1 subsys_b_OCC_EN add_pi_constraints 1 subsys_b_OCC_BYPASS add_pi_constraints 0 subsys_b_OCC_RESET add_pi_constraints 0 subsys_c_OCC_EN add_pi_constraints 0 subsys_c_OCC_BYPASS add_pi_constraints 0 subsys_c_OCC_RESET add_pi_constraints 0 OCC_EN add_pi_constraints 0 OCC_BYPASS add_pi_constraints 0 OCC_RESET add_pi_constraints 0 ate_clk add_pi_constraints 0 ate_clk1 add_pi_constraints 0 ate_clk2 add_scan_chains C1 subsys_b_SCAN_IN_0 subsys_b_SCAN_OUT_0 add_scan_chains C2 subsys_b_SCAN_IN_1 subsys_b_SCAN_OUT_1 add_scan_chains C3 subsys_b_SCAN_IN_2 subsys_b_SCAN_OUT_2 add_scan_chains C4 subsys_b_SCAN_IN_3 subsys_b_SCAN_OUT_3 add_scan_chains C5 subsys_b_SCAN_IN_4 subsys_b_SCAN_OUT_4 add_scan_chains C6 subsys_b_SCAN_IN_5 subsys_b_SCAN_OUT_5 add_scan_chains C7 subsys_b_SCAN_IN_6 subsys_b_SCAN_OUT_6 add_scan_chains C8 subsys_b_SCAN_IN_7 subsys_b_SCAN_OUT_7 add_scan_chains C9 subsys_b_SCAN_IN_8 subsys_b_SCAN_OUT_8 add_scan_chains SPC_OCC subsys_b_SPC_IN subsys_b_SPC_OUT set_faults -model stuck write_drc_file ./stilgen/subsys_b/temp_subsys_b.spf -generic_captures -replace exit```这是tmax的tcl脚本描述功能以及添加不同part之间的注释,并说明移植时需要修改的地方
最新发布
04-09
<think>好的,我现在需要分析用户提供的TCL脚本,并解释其功能、各部分的作用,以及在移植时需要修改的地方。首先,我得仔细阅读脚本,理解每一部分在做什么。这个脚本看起来是用于TMAX工具,进行扫描链插入和设计规则检查(DRC)的配置。 首先,用户提供的脚本分为几个部分,首先是读取网表文件,然后运行构建,接着是设计规则检查的配置,添加时钟、扫描使能、输入约束,设置扫描链,最后写入DRC文件并退出。我需要逐一分析每个部分的功能。 在“Read Design”部分,有多个read_netlist和read_verilog命令,这些是加载库文件和设计模块的步骤。路径中的文件可能涉及不同的子系统,如subsys_a、subsys_b等。这里需要注意文件路径是否正确,移植时可能需要调整路径。 接下来是run_build top,应该是构建顶层的设计。这里需要确认顶层模块名称是否为“top”,移植时可能需要更改。 然后是设计规则检查部分,有很多add_clocks和add_scan_enables命令。时钟信号如ate_clk3、pipe_clk等被设置为不同的相位。扫描使能信号如scan_en3和SCAN_EN被启用。这些信号可能需要根据具体设计调整,尤其是时钟名称和扫描使能的控制信号。 接着是大量的add_pi_constraints命令,设置输入端口约束。例如,将某些信号固定为0或1。比如rst_n3设置为1,而SCAN_EN设置为0。这些约束需要根据设计的复位和扫描使能逻辑来调整,尤其是不同子系统中的TM信号和OCC(On-Chip Clock Controller)相关信号。 添加扫描链的部分,使用add_scan_chains定义多个链,如C1到C9,以及SPC_OCC链。每个链指定了输入和输出端口。移植时,需要确保这些端口名称和数量与实际设计中的扫描链结构一致,尤其是子系统subsys_b中的扫描链连接是否正确。 最后,设置故障模型为stuck,写入DRC文件,并退出。生成的SPF文件路径可能需要根据项目结构修改。 在移植时,需要修改的地方可能包括:文件路径是否正确,顶层模块名称是否匹配,时钟和复位信号的名称,扫描使能和约束条件是否符合新设计,扫描链的定义是否与新设计的扫描结构一致,以及生成的SPF文件的输出路径是否正确。此外,不同子系统的TM和OCC信号约束可能需要根据新设计的配置进行调整。 需要注意的是,如果子系统结构发生变化,比如subsys_b被替换或重命名,对应的扫描链端口和约束也需要相应更新。同时,时钟配置和扫描使能信号的有效电平可能因设计而异,必须验证这些设置是否适用于新环境。 总结来说,这个脚本主要用于配置TMAX工具进行扫描测试相关的设计规则检查和生成测试协议文件。在移植到其他项目时,需要根据新设计的层次结构、信号名称、扫描链配置以及文件路径进行相应的调整,确保所有约束和配置正确反映新设计的需求。</think>以下是该TMAX TCL脚本的逐段功能解析及移植注意事项: --- ### 一、代码结构解析 #### 1. 设计读取部分 (`# Read Design`) ```tcl read_netlist ./lib/saed32nm.v # 读取工艺库文件 read_netlist ./lib/pll.v # 读取PLL模块网表 read_verilog ../../subsys_a/DC/... # 读取子系统A/B/C的综合后网表 run_build top # 构建顶层模块"top" ``` - **功能**:加载工艺库、IP核和子系统网表,构建完整设计层次 - **移植修改点**: - 调整工艺库路径 `./lib/saed32nm.v` 和IP路径 `./lib/pll.v` - 核对子系统网表路径(如 `subsys_a/DC/...`) --- #### 2. 设计规则检查配置 (`# Run Design Rule Checks`) **(1) 时钟定义** ```tcl add_clocks 0 ate_clk3 -shift # 定义移位时钟(低电平有效) add_clocks 1 rst_n3 # 定义复位信号(高电平有效) ``` - **功能**:声明时钟域和复位信号时序约束 - **移植修改点**:根据新设计时钟树名称修改 `ate_clk3`, `pipe_clk` 等 **(2) 扫描使能配置** ```tcl add_scan_enables 1 scan_en3 # 激活扫描使能信号 ``` - **功能**:控制扫描模式切换信号 - **移植修改点**:确认新设计扫描使能信号名称(如 `scan_en3`) **(3) 输入约束** ```tcl add_pi_constraints 0 SPC_DISABLE # 固定SPC禁用信号为低电平 add_pi_constraints 1 rst_n # 固定复位信号为高电平 ``` - **功能**:设置输入端口静态值以符合测试模式要求 - **移植修改点**:检查新设计控制信号(如 `SPC_DISABLE`, `TMx_x` 等) **(4) 扫描链定义** ```tcl add_scan_chains C1 subsys_b_SCAN_IN_0 subsys_b_SCAN_OUT_0 add_scan_chains SPC_OCC subsys_b_SPC_IN subsys_b_SPC_OUT ``` - **功能**:定义扫描链的输入/输出端口连接关系 - **移植修改点**:必须完全匹配新设计的扫描链接口名称 --- #### 3. 输出生成 ```tcl set_faults -model stuck # 设置故障模型为固定型故障 write_drc_file ./stilgen/... # 生成STIL格式测试协议 ``` - **功能**:生成用于ATE的测试向量 - **移植修改点**:调整输出路径 `./stilgen/subsys_b/` --- ### 二、关键移植注意事项 1. **层次结构匹配**: - 确认顶层模块名 `top` 与新设计一致 - 检查所有子系统路径(如 `subsys_a`, `subsys_b`)是否有效 2. **信号命名一致性**: - 扫描链端口(`SCAN_IN_x`, `SCAN_OUT_x`) - 测试模式信号(`TM0`, `TM1`, `TM2`) - 时钟复位信号(`ate_clk3`, `rst_n3`) 3. **OCC配置验证**: ```tcl add_pi_constraints 0 subsys_a1_OCC_EN # 关闭子系统A1的OCC add_pi_constraints 1 subsys_b_OCC_BYPASS # 使能子系统B的OCC旁路 ``` - 需根据新设计的时钟控制策略调整OCC约束 4. **工艺库适配**: - 替换 `saed32nm.v` 为新工艺库文件 - 验证PLL接口与目标工艺兼容性 --- ### 三、典型修改示例 原始代码: ```tcl read_verilog ../../subsys_b/DC/results/core_b_scan.v ``` 移植修改: ```tcl read_verilog ../../new_subsys/DC/outputs/new_core_scan.v ``` --- ### 四、验证建议 1. 运行 `run_build` 后检查层次结构报告 2. 使用 `check_drc` 命令验证约束完整性 3. 对比生成的SPF文件与设计规格书 通过以上修改和验证步骤,可确保该脚本适配到新设计环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值