简介:一份面向高校软件工程、电子信息类课程选修与FPGA入门实践的课程大作业文档,聚焦数字系统设计中的PARWAN处理器架构分析与CONTROL-SECTION状态机实现,适合需要完成同类实验报告、课程设计或复习VHDL开发流程的学生参考。文档围绕处理器运算、控制、寻址三部分展开,梳理PC、MAR、ALU、SR、IR与CONTROLLER的协作关系,并给出CONTROL-SECTION状态机的VHDL设计思路、Spartan3E XC3S500E芯片下的工程创建、测试文件编写及后仿结果说明,配有仿真截图与总结,便于对照理解状态迁移和取址、运算阶段的控制信号变化。资源包仅含1个doc文件,约763KB,轻量便于下载查阅。已有553人学习,可作为课程作业模板、实验过程记录和FPGA数字系统设计入门参考。
1. FPGA 数字系统设计大作业的真实难点:PARWAN 架构综述与状态机后仿
翻到这份 FPGA 数字系统设计大作业的第三页,多数人的第一反应是把 VHDL 敲完就收工,结果交上去才发现扣分点根本不在代码能不能编译——而是架构综述写成了流水账,后仿截图和代码里的状态对不上号。这份材料把 PARWAN 处理器的三段式数据通路、CONTROL-SECTION 状态机的状态划分、Spartan3E XC3S500E 上的工程搭建步骤、仿真验证流程,按“目的—原理—步骤—结果”四段整理清楚了,是一份可以直接照着复现的课程作业模板。适合正在做 FPGA 开发入门课设、需要交一份带后仿结果的数字系统设计报告的人,也适合已经写过状态机但说不清“为什么控制字要打一拍”的熟手回头补课。
2. PARWAN 数据通路拆解:运算、控制、寻址三段靠一根时钟串起来
先看教材那张结构图:左边一堆运算部件,中间是控制逻辑,右边是寻址和数据搬移。这个划分看起来只是排版,实际决定了后面状态机怎么写、控制字怎么分。把三段边界想清楚,状态转移图基本就自动浮出来了;反过来,如果一上来就抄状态机模板,写完一定会在“这个周期到底该拉高哪根使能”上卡住。
2.1 运算段、控制段、寻址段的边界怎么划
运算段的职责很单一:ALU 做算术逻辑运算,SHU 做移位,SR 记录本次运算的状态标志(零标志、进位、溢出这类)。这一段不关心数据从哪来、结果往哪去,只要求输入在时钟沿前稳定、输出在沿后有效。所以它的设计重点是组合逻辑延迟和标志位的采样时机,而不是时序控制。
寻址段负责把地址送到存储器、把数据取回来。PC 保存当前指令地址,MAR 保存本次访问的内存地址,两者容易被混为一谈——PC 是“下一条指令在哪”,MAR 是“这一拍要访问哪个单元”,前者由控制段决定自增还是装载,后者是每个访存周期都要重新填的寄存器。ADBUS 把地址送出去,数据总线把取回的内容送进 IR 或参与运算,这条路径上的每个寄存器都有自己的使能信号。
控制段夹在中间,是唯一同时看到指令内容、状态标志和外部启动信号的部件。它输出一组控制字,决定这一拍谁能写、谁能读、ALU 做什么操作。PARWAN 的整体节奏就是“控制段发令 → 寻址段取指取数 → 运算段计算 → 控制段根据结果决定下一步”,形成一个闭环。架构综述要写的就是这条闭环,而不是把每个部件的名字罗列一遍。
提示:写架构综述时,先把三段各自的输入输出列清楚,再说明段与段之间靠哪几根信号握手,最后落一句整体节奏。三段话就能写完,比堆砌术语得分高。
2.2 PC、MAR、IR、SR、ALU 的信号职责与握手
把这五个部件放在一张表里对照,比看结构图快得多。下面这张表是按教材结构图整理的,实际写报告时可以直接改成自己版本的命名:
| 部件 | 所属段 | 输入来源 | 输出去向 | 关键使能 | 时序要求 |
|---|---|---|---|---|---|
| PC | 寻址 | 控制段(自增/装载) | MAR、地址总线 | pc_inc / pc_load | 时钟沿更新 |
| MAR | 寻址 | PC 或 IR 的地址字段 | 地址总线 ADBUS | mar_load | 沿前稳定 |
| IR | 寻址 | 数据总线 | 控制段译码 | ir_load | 取指周期末装载 |
| SR | 运算 | ALU 标志输出 | 控制段条件判断 | sr_load | 与 ALU 结果同拍 |
| ALU | 运算 | 累加器、数据总线 | 累加器、SR | alu_op | 纯组合,延迟要算进周期 |
这张表里最容易被忽略的是 SR 的采样时机。ALU 是组合逻辑,结果在输入变化后的传播延迟之后才稳定,如果 SR 和累加器在同一个时钟沿采样,而 ALU 的输入恰好也在这个沿变化,采到的就是旧值或者毛刺。常见做法是让 ALU 的输入来自寄存器输出,这样整个组合路径在一个周期内稳定,SR 在下一个沿采样就没有歧义。这一点在综合后的时序报告里会体现为组合路径延迟,如果超过时钟周期,后仿就会看到标志位错拍。
另一个坑是把 PC 的自增和 MAR 的装载放到同一个状态里做。逻辑上没问题,但要注意 pc_inc 拉高的那一拍,PC 的新值要到下一个沿才生效,而 MAR 装的是 PC 的当前值——如果两个动作写反了顺序,取到的就是下一条指令的地址,仿真波形上表现为指令序列整体偏移一条。这种错误在前仿里往往看不出来,因为功能上“看起来”还在跑,只是结果全错。
2.3 一条指令走完的闭环:控制、取址、运算、写回
把一次完整的指令执行拆成状态,PARWAN 这类教学处理器的典型节奏是:空闲等待启动 → 送指令地址 → 取指令 → 指令装入 IR → 送操作数地址 → 取操作数 → 执行运算 → 写回结果 → 结束回到空闲。九个状态,每个状态一拍,控制字在状态内保持不变。
这个节奏的关键在于“每个状态只做一件事”。比如送指令地址这个状态,只做 PC 值送 MAR、PC 自增两件事;取指令状态只拉高存储器读使能;指令装入状态只拉高 IR 装载。如果把两件事塞进一个状态,控制字会变成多路同时有效,后仿波形上很难判断哪根信号先到,出问题也不好定位。
写回阶段要注意累加器和 SR 的更新顺序。运算结果在 ALU 输出端稳定后,写回使能拉高的那一拍才把它打进累加器,SR 同步记录标志。如果状态机在运算状态就拉高写回使能,打进累加器的可能是上一拍的结果。这类问题在波形上表现为“结果慢一拍”,但只要在状态转移表里把输出列对齐到状态,就不会写错。
3. CONTROL-SECTION 状态机落地:9 个状态的划分与三段式 VHDL 写法
状态机是这份大作业的核心交付物。教材给的是时序图和状态说明,落到 VHDL 要解决三个问题:状态怎么划分、用哪种写法、输出怎么和状态对齐。这三件事想清楚,代码量其实不大,一百多行就能写完;想不清楚,改到半夜也对不上波形。
3.1 把教材时序图翻译成状态转移表
拿到时序图别急着写 case,先在纸上画一张状态转移表,四列:当前状态、转移条件、次状态、该状态下有效的控制字。这张表是后面写代码和写报告的共同依据,也是排查问题的对照物。
| 当前状态 | 转移条件 | 次状态 | 有效控制字 |
|---|---|---|---|
| ST_IDLE | start='1' | ST_INST_ADDR | 无 |
| ST_IDLE | start='0' | ST_IDLE | 无 |
| ST_INST_ADDR | 无条件 | ST_INST_FETCH | pc_inc、mar_load |
| ST_INST_FETCH | 无条件 | ST_INST_LOAD | mem_read |
| ST_INST_LOAD | 无条件 | ST_OP_ADDR | ir_load |
| ST_OP_ADDR | 无条件 | ST_OP_FETCH | mar_load |
| ST_OP_FETCH | 无条件 | ST_ALU_OP | mem_read |
| ST_ALU_OP | 无条件 | ST_STORE | acc_load、sr_load、alu_op |
| ST_STORE | 无条件 | ST_END | acc_load |
| ST_END | 无条件 | ST_IDLE | 无 |
表里只有 ST_IDLE 有分支条件,其余都是无条件推进。这种“一条直线”的状态机在教学处理器里很常见,因为每个状态固定一拍,不存在等待握手的问题。真正需要条件分支的是遇到跳转指令或者零标志判断的时候,那时要在 ST_ALU_OP 之后加一个分支状态,根据 z_flag 决定回 ST_IDLE 还是回到取指。写报告时把这一点补一句,说明扩展方向,比只交一条直线更能体现理解。
状态命名建议直接用自己的前缀,别照抄教材缩写。原因很实际:后面仿真波形里要认状态,名字短、有规律,看波形时一眼能对上;名字如果和教材完全一样,反而容易和别人的代码混淆,答辩时说不清哪部分是自己写的。
3.2 两段式、三段式与状态编码:Spartan3E 上的取舍
状态机写法有三种常见形态。单进程写法把所有逻辑塞进一个时序进程,代码短,但次态和输出混在一起,改一个输出要动整个进程,排查时没法单独看次态。两段式把状态寄存和次态组合分开,输出仍然放在时序进程里,比单进程清楚。三段式再加一个独立的输出寄存进程,输出只跟状态走,毛刺被时钟沿滤掉。
对 Spartan3E 这种规模的器件,三段式的面积代价可以忽略——状态只有九个,多几个触发器不影响资源占用,但对后仿的友好程度差别很大。两段式里输出由组合逻辑产生,后仿会因为布线延迟出现毛刺,波形上看着像“控制字闪了一下”,答辩时很难解释。三段式把输出打一拍,毛刺被挡在寄存器前面,后仿波形干净,和功能仿真的差异只剩一个周期的固定延迟。
状态编码上,二进制编码在 Spartan3E 的查找表结构里占资源少,九个状态四位就够;独热码在触发器资源充足的器件上时序更好,但这里只有九个状态,优势不明显。综合工具默认会对状态机重新编码,如果报告里要贴波形截图,建议显式指定编码方式,避免综合后的状态值和仿真里的对不上——这是后面排查章节要展开的一个坑。
3.3 三段式状态机的 VHDL 实现与逐段说明
下面这份代码对应上面的状态转移表,三段结构分得很清楚。省略号部分按自己教材的信号名补全即可:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity par_control_unit is port ( clk : in std_logic; rst : in std_logic; -- 高有效异步复位 start : in std_logic; -- 启动一次指令周期 z_flag : in std_logic; -- ALU 零标志,预留分支用 pc_inc : out std_logic; mar_load : out std_logic; mem_read : out std_logic; ir_load : out std_logic; acc_load : out std_logic; sr_load : out std_logic; alu_op : out std_logic_vector(1 downto 0); state_dbg : out std_logic_vector(3 downto 0) -- 送仿真观察,也可接板载 LED ); end entity par_control_unit; architecture rtl of par_control_unit is -- 状态编码按声明顺序从 0 开始,state_dbg 的值可以直接对照 type state_t is (ST_IDLE, ST_INST_ADDR, ST_INST_FETCH, ST_INST_LOAD, ST_OP_ADDR, ST_OP_FETCH, ST_ALU_OP, ST_STORE, ST_END); signal cur_state : state_t := ST_IDLE; signal nxt_state : state_t := ST_IDLE; begin -- 第 1 段:状态寄存器,异步复位、同步翻转 p_state : process (clk, rst) begin if rst = '1' then cur_state <= ST_IDLE; elsif rising_edge(clk) then cur_state <= nxt_state; end if; end process; -- 第 2 段:次态组合逻辑,只决定下一拍去哪,不碰输出 p_next : process (cur_state, start) begin nxt_state <= cur_state; -- 默认保持,避免推断锁存器 case cur_state is when ST_IDLE => if start = '1' then nxt_state <= ST_INST_ADDR; end if; when ST_INST_ADDR => nxt_state <= ST_INST_FETCH; when ST_INST_FETCH => nxt_state <= ST_INST_LOAD; when ST_INST_LOAD => nxt_state <= ST_OP_ADDR; when ST_OP_ADDR => nxt_state <= ST_OP_FETCH; when ST_OP_FETCH => nxt_state <= ST_ALU_OP; when ST_ALU_OP => nxt_state <= ST_STORE; when ST_STORE => nxt_state <= ST_END; when ST_END => nxt_state <= ST_IDLE; when others => nxt_state <= ST_IDLE; end case; end process; -- 第 3 段:输出寄存,控制字跟随次态,输出的上升沿与状态跳转同拍 p_out : process (clk, rst) begin if rst = '1' then pc_inc <= '0'; mar_load <= '0'; mem_read <= '0'; ir_load <= '0'; acc_load <= '0'; sr_load <= '0'; alu_op <= "00"; elsif rising_edge(clk) then -- 先全部清零,再按次态置位,杜绝上一拍的控制字残留 pc_inc <= '0'; mar_load <= '0'; mem_read <= '0'; ir_load <= '0'; acc_load <= '0'; sr_load <= '0'; alu_op <= "00"; case nxt_state is when ST_INST_ADDR => pc_inc <= '1'; mar_load <= '1'; when ST_INST_FETCH => mem_read <= '1'; when ST_INST_LOAD => ir_load <= '1'; when ST_OP_ADDR => mar_load <= '1'; when ST_OP_FETCH => mem_read <= '1'; when ST_ALU_OP => acc_load <= '1'; sr_load <= '1'; alu_op <= "01"; when ST_STORE => acc_load <= '1'; when others => null; end case; end if; end process; -- 状态导出:state_t'pos 给出状态序号,四位足够表示 0~8 state_dbg <= std_logic_vector(to_unsigned(state_t'pos(cur_state), state_dbg'length)); end architecture rtl;三段各自的职责和参数含义需要说清楚。第一段只做一件事:时钟沿把次态灌进当前态,复位时强制回 ST_IDLE,复位极性选高有效是因为开发板按键通常上拉、按下为低,取反接进来更直观。第二段是纯组合逻辑,进程敏感表里只放状态和输入,开头那句默认赋值是关键,少了它综合工具会推断出锁存器。第三段输出用的是次态而不是当前态,这样控制字和状态跳转在同一拍生效,波形上看到的状态值变化和控制字变化是对齐的,报告里贴图更清楚。
alu_op 的两位编码要和自己 ALU 的接口对上,示例里 “01” 只是占位。实际改的时候,把 ALU 支持的操作列一张小表,编码填进去,别在代码里散落魔数。state_dbg 这根线强烈建议留着,它既能接仿真波形,也能在板子上接 LED 或者逻辑分析仪,跑实测的时候比盲猜快得多。
4. Spartan3E XC3S500E 工程配置:从建工程到综合报告的三个必看数字
代码写完只是完成一半,工程配置错了,综合能过但下载到板子上不跑,或者跑起来行为诡异。这一章按“建工程—写约束—看报告”的顺序走一遍,每个环节给出该填的参数和该核对的项。
4.1 新建工程:XC3S500E-4FG320 这几个参数填在哪
打开开发工具,文件菜单里新建工程,弹出对话框分三页。第一页填工程名和存放路径,路径里不要有中文和空格,这是老工具的通病,路径带空格会在综合阶段报找不到文件的错误,而且报错信息不会指向路径,排查起来很浪费时间。
第二页是器件参数,这一页填错后面全白搭。按输入资料给的型号对应填写:
| 参数项 | 应填值 | 说明 |
|---|---|---|
| 器件族 | Spartan3E | 与开发板芯片系列一致 |
| 器件型号 | XC3S500E | 50 万门规模,教学板常见选型 |
| 封装 | FG320 | 320 脚细间距球栅封装 |
| 速度等级 | 与板卡标称一致 | 常见为 -4,按板子丝印或原理图确认 |
| 综合工具 | XST | 工具自带,无需额外配置 |
| 仿真器 | ISim | 与工程配套,支持后仿 |
第三页确认信息后完成创建。速度等级这一项容易被随手选,选快了时序报告好看但实际跑不起来,选慢了资源浪费。判断方法很简单:看板卡原理图或者芯片丝印,上面印的完整型号里带速度等级后缀,照着填就行。
工程建完,新建源文件时注意类型选 VHDL Module 而不是 VHDL Test Bench,测试平台单独建一个文件。输入资料里给的做法是先建测试平台再关联,顺序反过来也行,但关联文件这一步别漏,否则仿真时找不到被测实体,报错信息是“entity not found”,看着像代码写错了,其实是工程没配对。
4.2 UCF 约束:时钟、复位与几个观察引脚的分配
约束文件决定信号落到哪个物理引脚,也决定时序分析的准确性。最少要写三组:时钟、复位、观察输出。下面这段只是语法示例,引脚编号必须照自己板卡的原理图逐个改,直接抄会烧不进配置或者信号乱跑:
# 时钟:周期约束必须写,否则时序报告里的频率是估算值 NET "clk" LOC = "C9" | IOSTANDARD = LVCMOS33 | PERIOD = 20 ns; # 复位:按键输入,注意上下拉配置与按键电路一致 NET "rst" LOC = "D18" | IOSTANDARD = LVCMOS33; # 状态观察:接四个 LED 或者排针,跑实测时看状态跳转 NET "state_dbg<0>" LOC = "F12" | IOSTANDARD = LVCMOS33; NET "state_dbg<1>" LOC = "F11" | IOSTANDARD = LVCMOS33; NET "state_dbg<2>" LOC = "E11" | IOSTANDARD = LVCMOS33; NET "state_dbg<3>" LOC = "E12" | IOSTANDARD = LVCMOS33; # 控制字引出,方便逻辑分析仪抓时序 NET "mem_read" LOC = "G13" | IOSTANDARD = LVCMOS33;PERIOD 的数值要和测试平台里的时钟周期一致。仿真里给 20 ns,约束里也写 20 ns,两边不一致时后仿时序报告会给出错误的裕量,看着通过实际超频。复位信号的上下拉配置要与板上按键电路匹配,按键一端接地、另一端上拉的电路,输入默认是高电平,按下变低,代码里如果按高有效复位就要取反,这一处不一致会导致上电后状态机一直锁在复位里,波形上表现为所有输出恒为零。
4.3 综合与实现报告里必须先看的三个数字
综合跑完会生成一堆报告,不用全看,三个数字决定这份设计能不能交:
第一个是查找表占用。Spartan3E 的 XC3S500E 有四千多个 slice、九千多个触发器,九个状态的状态机加几个寄存器,占用应该很小。如果报告里 LUT 数量异常高,通常是次态进程里写了复杂的条件判断,或者输出进程里出现了没必要的比较逻辑,回头精简 case 分支即可。
第二个是最大频率。时序报告里会给出最小周期和对应的最大频率,这个数字要明显高于约束里写的时钟频率,留出余量。如果刚好卡在临界值,说明组合路径太长,重点查 ALU 那条路径和状态译码逻辑,必要时把输出再打一拍。
第三个是未约束路径数量。报告里会列出没有时序约束覆盖的路径,数量不为零说明 UCF 漏了信号,最常见的是观察用的输出引脚没写约束。这些路径不参与时序分析,实际跑起来可能是稳定的,也可能在温度变化时出问题,交作业前补全约束比事后解释省事。
注意:综合警告里的“latch inferred”和“signal has no load”两类必须清零。前者意味着组合进程有分支没覆盖,后者意味着有信号写了没用上,通常是连线和端口名拼错。
5. 后仿真对不上波形的 5 个排查点:从全 X 到状态跑飞
后仿真是这份作业最容易翻车的环节。功能仿真跑得通,加了布局布线延迟之后就各种异常,波形上看不出所以然。下面五条是按发生频率排的,每条按现象、原因、解决三段写,遇到问题时从上往下对照。
5.1 波形整段是 U 或 X:复位与初值没覆盖到
现象:打开波形窗口,状态信号和大部分输出从头到尾都是 U 或者 X,偶尔有几段跳变但看不出规律。
原因有两个层面。一是测试平台里的信号声明时没给初值,VHDL 里 std_logic 默认是 U,时钟信号如果是 U,取反之后还是 U,时钟永远不起振。二是复位进程只复位了状态寄存器,输出寄存器在复位分支里漏写,导致复位释放后输出仍然是 U,直到某个状态把它置位。
解决:测试平台里所有输入信号声明时给初值,时钟信号写:= '0';复位进程里把每一个输出都列进复位分支,哪怕某个输出在初始状态就是零也要显式赋值。复位保持时间给足五个时钟周期,让所有内部寄存器落定再释放。改完之后重新跑,波形上应该能看到复位期间所有信号为确定的低电平。
5.2 前仿对后仿错:delta 延迟与组合输出毛刺
现象:功能仿真波形干净,每个状态的控制字方方正正;后仿真里控制字出现窄脉冲,偶尔还有一两纳秒的尖峰,累加器采到的值和预期差一拍。
原因:功能仿真不建模布线延迟,组合逻辑的输出在输入变化的同一时刻跳变,看起来完美。后仿真里每根线都有延迟,组合输出的多个输入不同时到达,输出就会出现毛刺。如果这个毛刺正好落在下游寄存器的时钟沿附近,就会被采进去。
解决:把输出改成寄存器输出,也就是三段式里的第三段,毛刺被挡在寄存器前面,下游看到的永远是稳定的整拍信号。测试平台的采样点也调整一下,用rising_edge(clk)触发而不是用wait for卡时间点,避免采在跳变瞬间。改完后再看后仿波形,控制字的边沿应该干净,最多整体延迟一个周期。
5.3 状态跑飞、编码对不上:综合器重编码
现象:后仿波形里状态信号的值和代码里的枚举顺序对不上,比如代码里 ST_INST_ADDR 是 1,波形上却是 5;或者状态在几个非法值之间跳。
原因:综合工具默认对状态机做重新编码,选它认为面积或速度更优的方案,枚举顺序和实际编码不再一一对应。如果测试平台或者观察逻辑里硬编码了状态值做判断,就会全部错位。另一种情况是状态机综合时被优化掉了部分状态,说明有状态不可达,通常是转移条件写错。
解决:两种情况都先在报告里确认。看综合报告的 state machine 部分,会列出实际使用的编码;如果报告和预期差太多,在信号上显式指定编码属性,强制按二进制或者顺序码实现。测试平台里判断状态时,用导出的 state_dbg 数值比对,别用枚举名硬编码,或者干脆在测试平台里重新声明一份相同的枚举类型做类型转换。
5.4 综合报 latch 与多驱动:次态进程的两个默认值
现象:综合警告里出现 latch inferred,或者报某个信号有多个驱动源,实现阶段直接失败。
原因:latch 来自组合进程,if 或者 case 没有覆盖所有分支,工具为了保持输出不变就推断出锁存器。多驱动来自同一个信号在两个进程里都被赋值,最常见的是把输出既写在次态进程里,又写在输出进程里。
解决:组合进程开头先给默认赋值,case 结尾加when others,两条一起用基本能消灭 latch。多驱动要看综合报告的驱动源列表,把重复赋值的那个删掉,输出的赋值只留在一个进程里。修完重新综合,这两类警告必须为零再往下走。
5.5 仿真卡住不动:wait 语句与时钟源
现象:仿真跑了很久进度条不动,或者波形上时间轴停住,所有信号保持初始值。
原因:测试平台里某个进程没有 wait 语句,或者 wait 的条件永远不会满足。比如等待一个由被测逻辑产生的信号,而被测逻辑自己也需要时钟才能动,两者互相等待就死锁了。另一种是时钟进程写成了clk <= not clk after 10 ns;放在敏感表进程里,形成零延迟振荡,仿真器直接挂掉。
解决:时钟产生语句放在进程外,用并发赋值,进程里只放激励。每个进程至少有一个 wait 或者敏感表,纯组合的激励进程结尾加wait;让它挂起而不是无限循环。仿真时间设一个上限,比如跑够二十个时钟周期就自动结束,避免跑飞之后一直占着机器。
6. 把波形变成回归:给状态机加自检断言的三个动作
波形截图是给老师看的,断言是给自己看的。手动比对波形这件事,做第一遍还行,改一次代码重新跑就要重看一遍,改到第五版基本靠运气。我后来的做法是把关键判断写成断言,让仿真器自己报错。
第一个动作,在测试平台里加状态合法性检查。用 state_dbg 的数值判断,超出 0 到 8 就报失败:
-- 状态合法性 + 关键控制字自检,跑仿真时自动报错 chk : process (clk) begin if rising_edge(clk) then if rst = '0' and state_dbg > "1000" then assert false report "状态机进入非法编码,检查次态进程的 when others 分支" severity failure; end if; -- ST_ALU_OP 的序号是 6,这一拍 acc_load 必须为高 if state_dbg = "0110" and acc_load /= '1' then assert false report "ALU_OP 状态下 acc_load 未拉高,控制字表与状态机不一致" severity error; end if; end if; end process;第二个动作,把仿真日志沉淀下来。跑仿真的命令行输出重定向到文件,用 grep 抓 ERROR 和 FATAL,出现就返回非零退出码:
#!/usr/bin/env bash # 一键回归:编译 -> 跑仿真 -> 检查日志,任一环节出错就中断 set -e fuse -incremental -prj par_control_unit_tb.prj -o tb.exe par_control_unit_tb ./tb.exe -tclbatch run_all.tcl > sim.log 2>&1 if grep -qE "ERROR|FATAL|Failure" sim.log; then echo "回归失败,详见 sim.log" exit 1 fi echo "回归通过:状态序列与控制字自检均无异常"第三个动作,保存波形配置文件。把关心的信号加进波形窗口,存成配置文件,下次跑仿真时用命令行加载,不用每次重新拖信号。这一步看着琐碎,但改代码之后重新打开波形只要几秒,比重新找信号快得多。
这三件事做完,一份作业的验证闭环才算合上。材料里给的后仿截图是结果,断言和回归脚本是可复现的过程,报告里把两者都放上去,说明的不只是“跑通了”,而是“我怎么知道它跑通了”。
血泪经验是有一年赶截止时间,改完状态机只看了前仿就交,后仿波形没重跑,结果答辩现场打开波形发现状态和代码对不上,当场翻车。从那以后我每次交这种带状态机的作业,都强制走一遍自检断言加日志 grep 的流程,跑完看输出里那行“回归通过”才敢合上电脑。希望帮到你。
本文还有配套的精品资源,点击获取