diff --git a/README.md b/README.md index 3813f64..ba69453 100644 --- a/README.md +++ b/README.md @@ -69,18 +69,18 @@ risc-v/ 表中的 `opcode` 是控制器使用的五位字段 `IR[6:2]`,不是包含最低两位的 7 位原始 opcode。 因此它与标准 RISC-V 指令的低 7 位 opcode 相差右移两位。 -| 指令类别 | opcode | 说明 | -| ----------------------------------------------- | -----: | ----------------------------------------------------------------------------------- | -| R 型 | `0x0c` | add/sub/and/or/xor/slt/sltu/sll/srl/sra | -| M 扩展(R 型) | `0x0c` | `funct7=0000001`:mul/mulh/mulhsu/mulhu、divu(`funct3=101`)、remu(`funct3=111`) | -| I 型 ALU | `0x04` | addi/andi/ori/xori/slti/sltiu/slli/srli/srai | -| `lui`(扩展) | `0x0d` | 加载高位立即数,`rd = imm[31:12] << 12` | -| `lw` | `0x00` | `funct3=010` | -| `sw` / `sb` | `0x08` | `funct3=010` / `000` | -| `beq` / `bne` / `blt` / `bge` / `bltu` / `bgeu` | `0x18` | `funct3=000` / `001` / `100` / `101` / `110` / `111` | -| `jal` | `0x1b` | J 型立即数 | -| `jalr` | `0x19` | `funct3=000` | -| 系统类 | `0x1c` | `ecall`、`URET`、CSRRSI、CSRRCI | +| 指令类别 | opcode | 说明 | +| ----------------------------------------------------------- | -------: | ----------------------------------------------------------------------------------------- | +| R 型 | `0x0c` | add/sub/and/or/xor/slt/sltu/sll/srl/sra | +| M 扩展(R 型) | `0x0c` | `funct7=0000001`:mul/mulh/mulhsu/mulhu、divu(`funct3=101`)、remu(`funct3=111`) | +| I 型 ALU | `0x04` | addi/andi/ori/xori/slti/sltiu/slli/srli/srai | +| `lui`(扩展) | `0x0d` | 加载高位立即数,`rd = imm[31:12] << 12` | +| `lw` | `0x00` | `funct3=010` | +| `sw` / `sb` | `0x08` | `funct3=010` / `000` | +| `beq` / `bne` / `blt` / `bge` / `bltu` / `bgeu` | `0x18` | `funct3=000` / `001` / `100` / `101` / `110` / `111` | +| `jal` | `0x1b` | J 型立即数 | +| `jalr` | `0x19` | `funct3=000` | +| 系统类 | `0x1c` | `ecall`、`URET`、CSRRSI、CSRRCI | `ecall` 和 `URET` 都是 `opcode=0x1c、funct3=0`,由 `IR[21]` 区分: `IR[21]=0` 是 `ecall`,`IR[21]=1` 是 `URET`。这一点来自原控制器中的 `IR21` 分支逻辑。 @@ -91,13 +91,13 @@ risc-v/ 这些地址都在 4 KB 数据 RAM(`0x0000`–`0x0FFC`)之外,因此不会与 RAM 冲突。 每行的字节偏移都按**字**对齐译码(同一 32 位寄存器内任意字节偏移都命中)。 -| 地址 | 外设 | 写 | 读 | -| ---------------------- | -------------- | ---------------------------------------------------------------------------- | -------------------------- | -| `0x0000_1000` | LED 数据寄存器 | `sw` 写全字;`sb` 按 `data_wstrb_o` 只改对应字节通道,`led_valid_o` 拉高一拍 | `lw` 返回 LED 寄存器当前值 | -| `0x0000_1004` | 七段数码管 | `sw`/`sb` 写 8 位十六进制数(低 4 位 = 最右边那个数码管) | `lw` 读回 | -| `0x0000_1100`+ | 鼠标寄存器组 | STATUS / DATA / ACK / CTRL / INPUT / TIME / FRAME / EVCNT / LEVEL / MAGIC | 同左(DATA 读无副作用) | -| `0x0000_1140`+ | 显示控制器 | CTRL(光标可见、背景色)/ CURSOR(列、行) | 同左(另含 MAGIC 自检值) | -| `0x0000_2000`–`0x27FF` | 显存 | 40 列 × 30 行、每格 1 字节(字形 + 颜色),写端口接到板级顶层的双口 RAM | `lw` 组合读回 | +| 地址 | 外设 | 写 | 读 | +| --------------------------- | -------------- | ------------------------------------------------------------------------------------ | ---------------------------- | +| `0x0000_1000` | LED 数据寄存器 | `sw` 写全字;`sb` 按 `data_wstrb_o` 只改对应字节通道,`led_valid_o` 拉高一拍 | `lw` 返回 LED 寄存器当前值 | +| `0x0000_1004` | 七段数码管 | `sw`/`sb` 写 8 位十六进制数(低 4 位 = 最右边那个数码管) | `lw` 读回 | +| `0x0000_1100`+ | 鼠标寄存器组 | STATUS / DATA / ACK / CTRL / INPUT / TIME / FRAME / EVCNT / LEVEL / MAGIC | 同左(DATA 读无副作用) | +| `0x0000_1140`+ | 显示控制器 | CTRL(光标可见、背景色)/ CURSOR(列、行) | 同左(另含 MAGIC 自检值) | +| `0x0000_2000`–`0x27FF` | 显存 | 40 列 × 30 行、每格 1 字节(字形 + 颜色),写端口接到板级顶层的双口 RAM | `lw` 组合读回 | 其中 `LEVEL`(`0x1120`)是一个**软件中断**寄存器:写 1 会拉起 `irq_i[1]`,用来让程序 "跳到关卡入口";`MAGIC`(`0xCAFE0001`/`0xCAFE0002`)可以读来自检 MMIO 是否活着。 @@ -147,34 +147,34 @@ risc-v/ ## 文件与模块划分 -| 文件 | 模块 | 职责 | -| --------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------- | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_redirect_int_bpb.v` | `cpu21_riscv_redirect_int_bpb` | 顶层:五级流水寄存器、子模块例化、PC/IF-ID/ID-EX 控制、对外输出 | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_alu.v` | `cpu21_riscv_alu` | 组合 ALU(加减/移位/逻辑/比较,不做乘除) | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_muldiv.v` | `cpu21_riscv_muldiv` | 多周期乘除法单元:32 拍移位迭代,mul/mulh/mulhsu/mulhu/divu/remu | -| `pipelined-cpu/srcs/rtl/cpu21_bpb_8.v` | `cpu21_bpb_8` | 8 项全相联分支目标缓冲(2 位饱和计数器 + 近似 LRU) | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_decoder.v` | `cpu21_riscv_decoder` | ID 级组合译码器(操作码`IR[6:2]`) | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_regfile.v` | `cpu21_riscv_regfile` | 寄存器堆,`x0` 恒为 0,同周期 WB 写优先旁路 | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_forward_unit.v` | `cpu21_riscv_forward_unit` | EX 级前递网络(EX/MEM 优先于 MEM/WB) | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_store_unit.v` | `cpu21_riscv_store_unit` | EX 级存储数据对齐:`sw`/`sb` 的写数据与字节写掩码 | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_branch_unit.v` | `cpu21_riscv_branch_unit` | EX 级控制流裁决:分支方向/目标、JAL/JALR 重定向 | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_hazard_unit.v` | `cpu21_riscv_hazard_unit` | load-use 冒险、停顿(stall)与冲刷(flush)判定 | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_irq_ctrl.v` | `cpu21_riscv_irq_ctrl` | 中断采样与优先级、`ustatus`/`uepc` CSR、嵌套返回栈 | -| `pipelined-cpu/srcs/rtl/cpu21_riscv_perf_counters.v` | `cpu21_riscv_perf_counters` | 周期/停顿/气泡/分支/预测成功率等统计计数器 | -| `pipelined-cpu/srcs/rtl/cpu21_mmio.v` | `cpu21_mmio` | MMIO 中枢:LED、七段数码管、鼠标寄存器组 + 事件 FIFO + 中断、显示控制器、显存窗口 | -| `pipelined-cpu/srcs/rtl/cpu21_vga.v` | `cpu21_vga` | 640x480@60 显示控制器:按"格子"扫描,8x8 字模放大 2 倍填满 16x16 的格子 | -| `pipelined-cpu/srcs/rtl/cpu21_seg7.v` | `cpu21_seg7` | 板载 8 位数码管动态扫描驱动(共阳极,位选/段选低有效) | -| `pipelined-cpu/srcs/rtl/cpu21_pointer.v` | `cpu21_pointer` | 把 5 向按键变成"鼠标"事件(去抖 + 事件排队,单位 1/8 格) | -| `pipelined-cpu/srcs/rtl/cpu21_ps2_mouse.v` | `cpu21_ps2_mouse` | 可选的真鼠标:PS/2 接收(11 位帧 + 奇校验 + 3 字节包解析),只实现接收 | -| `pipelined-cpu/srcs/board/cpu21_board_top.v` | `cpu21_board_top` | 板级顶层:时钟分频、复位同步、片内 ROM/RAM、显存双口 RAM、VGA/数码管/鼠标/中断连线 | -| `pipelined-cpu/srcs/board/cpu21_saolei_rom.vh` | — | 扫雷程序的 ROM 初始化(由`saolei/tools/build.ps1` 生成) | -| `pipelined-cpu/srcs/constrs/cpu21_board_top.xdc` | — | Nexys4DDR 引脚约束 + 分频时钟(`create_generated_clock`) | -| `pipelined-cpu/srcs/board/cpu21_board_rom.vh` | — | 片内 ROM 内容(生成文件,`rom[i] = 32'h…;`) | -| `pipelined-cpu/srcs/tb/tb_board_top.v` | `tb_board_top` | 板级顶层的 RTL 仿真(观察 LED 跑马灯与写入指示) | -| `pipelined-cpu/srcs/tb/tb_no_intr.v` | `tb_no_intr` | 无中断测试平台(指令集/MMIO 测试,默认加载 benchmark 镜像) | -| `pipelined-cpu/srcs/tb/tb_cpu21_riscv_redirect_int_bpb.v` | `tb_cpu21_riscv_redirect_int_bpb` | 中断与分支预测测试平台(默认加载中断测试镜像) | -| `pipelined-cpu/tools/rv_asm.py` | — | 迷你汇编器:`.asm` → 机器码 hex(`.lst` 带反汇编清单) | -| `pipelined-cpu/tools/hex2vh.py` | — | hex →`pipelined-cpu/srcs/board/cpu21_board_rom.vh`(`rom[i] = 32'h…;` 初始化语句) | +| 文件 | 模块 | 职责 | +| ----------------------------------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------- | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_redirect_int_bpb.v` | `cpu21_riscv_redirect_int_bpb` | 顶层:五级流水寄存器、子模块例化、PC/IF-ID/ID-EX 控制、对外输出 | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_alu.v` | `cpu21_riscv_alu` | 组合 ALU(加减/移位/逻辑/比较,不做乘除) | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_muldiv.v` | `cpu21_riscv_muldiv` | 多周期乘除法单元:32 拍移位迭代,mul/mulh/mulhsu/mulhu/divu/remu | +| `pipelined-cpu/srcs/rtl/cpu21_bpb_8.v` | `cpu21_bpb_8` | 8 项全相联分支目标缓冲(2 位饱和计数器 + 近似 LRU) | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_decoder.v` | `cpu21_riscv_decoder` | ID 级组合译码器(操作码`IR[6:2]`) | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_regfile.v` | `cpu21_riscv_regfile` | 寄存器堆,`x0` 恒为 0,同周期 WB 写优先旁路 | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_forward_unit.v` | `cpu21_riscv_forward_unit` | EX 级前递网络(EX/MEM 优先于 MEM/WB) | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_store_unit.v` | `cpu21_riscv_store_unit` | EX 级存储数据对齐:`sw`/`sb` 的写数据与字节写掩码 | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_branch_unit.v` | `cpu21_riscv_branch_unit` | EX 级控制流裁决:分支方向/目标、JAL/JALR 重定向 | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_hazard_unit.v` | `cpu21_riscv_hazard_unit` | load-use 冒险、停顿(stall)与冲刷(flush)判定 | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_irq_ctrl.v` | `cpu21_riscv_irq_ctrl` | 中断采样与优先级、`ustatus`/`uepc` CSR、嵌套返回栈 | +| `pipelined-cpu/srcs/rtl/cpu21_riscv_perf_counters.v` | `cpu21_riscv_perf_counters` | 周期/停顿/气泡/分支/预测成功率等统计计数器 | +| `pipelined-cpu/srcs/rtl/cpu21_mmio.v` | `cpu21_mmio` | MMIO 中枢:LED、七段数码管、鼠标寄存器组 + 事件 FIFO + 中断、显示控制器、显存窗口 | +| `pipelined-cpu/srcs/rtl/cpu21_vga.v` | `cpu21_vga` | 640x480@60 显示控制器:按"格子"扫描,8x8 字模放大 2 倍填满 16x16 的格子 | +| `pipelined-cpu/srcs/rtl/cpu21_seg7.v` | `cpu21_seg7` | 板载 8 位数码管动态扫描驱动(共阳极,位选/段选低有效) | +| `pipelined-cpu/srcs/rtl/cpu21_pointer.v` | `cpu21_pointer` | 把 5 向按键变成"鼠标"事件(去抖 + 事件排队,单位 1/8 格) | +| `pipelined-cpu/srcs/rtl/cpu21_ps2_mouse.v` | `cpu21_ps2_mouse` | 可选的真鼠标:PS/2 接收(11 位帧 + 奇校验 + 3 字节包解析),只实现接收 | +| `pipelined-cpu/srcs/board/cpu21_board_top.v` | `cpu21_board_top` | 板级顶层:时钟分频、复位同步、片内 ROM/RAM、显存双口 RAM、VGA/数码管/鼠标/中断连线 | +| `pipelined-cpu/srcs/board/cpu21_saolei_rom.vh` | — | 扫雷程序的 ROM 初始化(由`saolei/tools/build.ps1` 生成) | +| `pipelined-cpu/srcs/constrs/cpu21_board_top.xdc` | — | Nexys4DDR 引脚约束 + 分频时钟(`create_generated_clock`) | +| `pipelined-cpu/srcs/board/cpu21_board_rom.vh` | — | 片内 ROM 内容(生成文件,`rom[i] = 32'h…;`) | +| `pipelined-cpu/srcs/tb/tb_board_top.v` | `tb_board_top` | 板级顶层的 RTL 仿真(观察 LED 跑马灯与写入指示) | +| `pipelined-cpu/srcs/tb/tb_no_intr.v` | `tb_no_intr` | 无中断测试平台(指令集/MMIO 测试,默认加载 benchmark 镜像) | +| `pipelined-cpu/srcs/tb/tb_cpu21_riscv_redirect_int_bpb.v` | `tb_cpu21_riscv_redirect_int_bpb` | 中断与分支预测测试平台(默认加载中断测试镜像) | +| `pipelined-cpu/tools/rv_asm.py` | — | 迷你汇编器:`.asm` → 机器码 hex(`.lst` 带反汇编清单) | +| `pipelined-cpu/tools/hex2vh.py` | — | hex →`pipelined-cpu/srcs/board/cpu21_board_rom.vh`(`rom[i] = 32'h…;` 初始化语句) | 拆分只调整了模块边界与文件组织,端口、时序与行为完全等价:使用同一 ROM 程序 在 xsim 下对拆分前后逐周期对比,波形输出与最终统计(周期、停顿、气泡、分支 @@ -276,14 +276,14 @@ BPB/中断观测值)。如果直接把它设为实现顶层,这些端口会 ### 引脚分配(`cpu21_board_top.xdc`) -| 端口 | 引脚 | 板上元件 | 说明 | -| ------------- | ----------- | ------------------------- | ------------------------------------------------------------------- | -| `clk100` | E3 | 100 MHz 晶振 | 经 `CPU_DIV` 分频后给 CPU(默认 50 MHz) | -| `rst_n` | C12 | 按键 CPU_RESETN(低有效) | 异步置位、与 CPU 时钟同步释放 | +| 端口 | 引脚 | 板上元件 | 说明 | +| --------------- | ----------- | ------------------------- | ----------------------------------------------------------------------- | +| `clk100` | E3 | 100 MHz 晶振 | 经`CPU_DIV` 分频后给 CPU(默认 50 MHz) | +| `rst_n` | C12 | 按键 CPU_RESETN(低有效) | 异步置位、与 CPU 时钟同步释放 | | `go` | N17 | 按键 BTNC | 对应原电路“继续运行”(`ecall` 停机后恢复执行) | -| `irq_sw[2:0]` | J15/L16/M13 | 拨码开关 SW0–SW2 | 三路中断源,拨动即触发(内部同步并锁存) | -| `led[15:0]` | H17…V11 | LED0–LED15 | `LED[2:0]` = 三路中断指示(锁存,ISR 返回后熄灭),`LED[15:3]` 熄灭 | -| `led_we` | R12 | LED16_B | MMIO 写入指示,每写一次拉长约 0.34 s @50 MHz | +| `irq_sw[2:0]` | J15/L16/M13 | 拨码开关 SW0–SW2 | 三路中断源,拨动即触发(内部同步并锁存) | +| `led[15:0]` | H17…V11 | LED0–LED15 | `LED[2:0]` = 三路中断指示(锁存,ISR 返回后熄灭),`LED[15:3]` 熄灭 | +| `led_we` | R12 | LED16_B | MMIO 写入指示,每写一次拉长约 0.34 s @50 MHz | ### 时钟:分频比怎么选(`CLK_DIV` / `CLK_DIV_INTRUPT`) @@ -297,11 +297,11 @@ BPB/中断观测值)。如果直接把它设为实现顶层,这些端口会 因此在 `cpu21_board_top` 里保留一个参数化的分频器 `CLK_DIV`,默认取 **2(50 MHz, 周期 20 ns)**,既比原来的 16 分频快 8 倍,又留出充足余量: -| 配置 | CPU 时钟 | 实测 WNS(xc7a100tcsg324-1) | 说明 | -| ------------ | -------- | ---------------------------- | ------------------------------------- | -| `CLK_DIV=1` | 100 MHz | -1.1 ns ✗ | 违例路径与乘除法无关(分支/中断/BPB) | -| `CLK_DIV=2` | 50 MHz | **+5.1 ns** ✓ | 默认,余量约 25% | -| `CLK_DIV=16` | 6.25 MHz | +6.1 ns ✓ | 改造前的设置,现在没必要了 | +| 配置 | CPU 时钟 | 实测 WNS(xc7a100tcsg324-1) | 说明 | +| -------------- | -------- | ---------------------------- | ------------------------------------- | +| `CLK_DIV=1` | 100 MHz | -1.1 ns ✗ | 违例路径与乘除法无关(分支/中断/BPB) | +| `CLK_DIV=2` | 50 MHz | **+5.1 ns** ✓ | 默认,余量约 25% | +| `CLK_DIV=16` | 6.25 MHz | +6.1 ns ✓ | 改造前的设置,现在没必要了 | 分频后的时钟在综合/实现时由 Vivado 自动插入 BUFG 走全局时钟网络(RTL 里不例化 `BUFG` 原语,这样在不认识 Xilinx 原语的仿真器里也能直接仿真)。XDC 中必须用 @@ -327,13 +327,13 @@ create_generated_clock -name cpu_clk -source [get_ports { clk100 }] \ ### 分频与刷新率一览(想改速度看这里) -| 想改什么 | 改哪里 | 当前值 / 换算 | -| -------------------------- | ----------------------------------------------- | -------------------------------------------------------- | -| CPU 主频(程序快慢) | 参数 `CLK_DIV` | 2 → 50 MHz(`100 MHz / CLK_DIV`) | -| 中断程序的 CPU 主频 | 参数 `CLK_DIV_INTRUPT`(只在该 ROM 宏下生效) | 32 → 3.125 MHz;每个数值约 10 ms × (`CLK_DIV_INTRUPT`/2) | -| 数码管扫描刷新率 | 顶层 `SEG_REFRESH_DIV`(自动跟随 `CPU_DIV`) | `100000 / CPU_DIV` → 每步 1 ms、每位 125 Hz | -| LED16_B 写入指示点亮时长 | `led_we_cnt` 的装载值 `24'hFF_FFFF` | 约 0.34 s @50 MHz(`0xFFFFFF / f_cpu`) | -| 中断程序每个数值的停留时间 | `tools/adapt_intrupt_ccab.py` 的 `DELAY_NEG_HI` | `0xFFFC0` → 约 10 ms @50 MHz | +| 想改什么 | 改哪里 | 当前值 / 换算 | +| -------------------------- | --------------------------------------------------- | ------------------------------------------------------------ | +| CPU 主频(程序快慢) | 参数`CLK_DIV` | 2 → 50 MHz(`100 MHz / CLK_DIV`) | +| 中断程序的 CPU 主频 | 参数`CLK_DIV_INTRUPT`(只在该 ROM 宏下生效) | 32 → 3.125 MHz;每个数值约 10 ms × (`CLK_DIV_INTRUPT`/2) | +| 数码管扫描刷新率 | 顶层`SEG_REFRESH_DIV`(自动跟随 `CPU_DIV`) | `100000 / CPU_DIV` → 每步 1 ms、每位 125 Hz | +| LED16_B 写入指示点亮时长 | `led_we_cnt` 的装载值 `24'hFF_FFFF` | 约 0.34 s @50 MHz(`0xFFFFFF / f_cpu`) | +| 中断程序每个数值的停留时间 | `tools/adapt_intrupt_ccab.py` 的 `DELAY_NEG_HI` | `0xFFFC0` → 约 10 ms @50 MHz | - **数码管**:`SEG_REFRESH_DIV = 100000 / CPU_DIV` 保证“每步 1 ms、每位数码管 125 Hz”与主频无关(不这样缩放的话,主频降 4 倍时全屏刷新只剩 31 Hz,能看到 @@ -364,12 +364,12 @@ create_generated_clock -name cpu_clk -source [get_ports { clk100 }] \ 板级顶层用一条 `` `ifdef `` 链决定 ROM 里固化哪个程序(连带决定中断入口地址), `create_project.tcl` 里的两个开关就是给这条链用的: -| 宏(`sources_1` 的 Verilog Define) | ROM 文件 | 中断入口 `IRQ1/2/3` | 说明 | -| ----------------------------------- | ------------------------------------ | --------------------------- | ------------------------------------------ | +| 宏(`sources_1` 的 Verilog Define) | ROM 文件 | 中断入口`IRQ1/2/3` | 说明 | +| ------------------------------------- | -------------------------------------- | --------------------------------- | -------------------------------------------- | | `SAOLEI_ROM`(优先级最高) | `srcs/board/cpu21_saolei_rom.vh` | `0x100` / `0x200` / `0x300` | 纯 C 扫雷(`saolei/tools/build.ps1` 生成) | -| `RISC_V_INTRUPT_CCAB_ROM` | `srcs/board/risc-v-intrupt-ccab.vh` | `0x0AC` / `0x1E4` / `0x308` | 课程中断综合测试程序(当前默认) | -| `BOARD_ROM_FAST` | `srcs/board/cpu21_board_rom_fast.vh` | `0x100` / `0x200` / `0x300` | 仿真专用:跑马灯延时改小(综合不用) | -| 都不定义 | `srcs/board/cpu21_board_rom.vh` | `0x100` / `0x200` / `0x300` | 上板跑马灯 demo(默认) | +| `RISC_V_INTRUPT_CCAB_ROM` | `srcs/board/risc-v-intrupt-ccab.vh` | `0x0AC` / `0x1E4` / `0x308` | 课程中断综合测试程序(当前默认) | +| `BOARD_ROM_FAST` | `srcs/board/cpu21_board_rom_fast.vh` | `0x100` / `0x200` / `0x300` | 仿真专用:跑马灯延时改小(综合不用) | +| 都不定义 | `srcs/board/cpu21_board_rom.vh` | `0x100` / `0x200` / `0x300` | 上板跑马灯 demo(默认) | 同一时间只应定义一个(`ifdef` 链按上表顺序取第一个命中的)。**中断入口必须和 ROM 里 ISR 的起点一致**,所以换程序时宏与入口是一起换的:`cpu21_board_top.v` @@ -389,7 +389,6 @@ ROM 里 ISR 的起点一致**,所以换程序时宏与入口是一起换的: ``` 换回跑马灯就是 `set_property verilog_define {} [get_filesets sources_1]`。 - 2. **一键重建**:改 `create_project.tcl` 里的 `use_intrupt_ccab` / `use_saolei` 两个开关(同一时间只开一个),重新 `source create_project.tcl`。 3. **命令行仿真**:`xvlog` 与 `xelab` 都要带同一个 `-d`,并用 `-i` 指向头文件目录: @@ -399,7 +398,6 @@ ROM 里 ISR 的起点一致**,所以换程序时宏与入口是一起换的: srcs/rtl/*.v srcs/board/cpu21_board_top.v 你的tb.v xelab -top 你的tb -snapshot s -d RISC_V_INTRUPT_CCAB_ROM ``` - 4. **注意**:这些宏只影响“综合用”的 `sources_1`。跑 `tb_no_intr` / `tb_cpu21_riscv_redirect_int_bpb` 时,程序来自测试平台自己探测的 `srcs/rom/*.hex`,与宏无关。 @@ -460,10 +458,10 @@ xsim board_sim -tclbatch run_quit.tcl 每步之间用软件循环延时约 20 ms(50 MHz 下)。仓库里同时提供了两份 ROM 初始化 文件,由 `BOARD_ROM_FAST` 宏选择(综合流程不会定义该宏): -| 文件 | 用途 | 每步耗时 | -| -------------------------------------------------- | ------------------------------ | -------- | +| 文件 | 用途 | 每步耗时 | +| ---------------------------------------------------- | ------------------------------ | -------- | | `pipelined-cpu/srcs/board/cpu21_board_rom.vh` | 综合/上板(默认) | 约 20 ms | -| `pipelined-cpu/srcs/board/cpu21_board_rom_fast.vh` | 仅仿真:一次跑完整个跑马灯序列 | 2.6 µs | +| `pipelined-cpu/srcs/board/cpu21_board_rom_fast.vh` | 仅仿真:一次跑完整个跑马灯序列 | 2.6 µs | ```powershell # 快速版仿真:编译时加上 -d BOARD_ROM_FAST(xvlog 与 xelab 都要带) @@ -495,12 +493,12 @@ Vivado 工程 `pipelined-cpu/pipelined-cpu.xpr` 被 `.gitignore` 排除,需要 `xc7a100tcsg324-1` 上的实现结果(乘除法改为多周期单元、`CLK_DIV=2` = 50 MHz): -| 项目 | 结果 | -| -------- | -------------------------------------------------------------------------------------------- | -| 综合 | `synth_design Complete!` | +| 项目 | 结果 | +| -------- | -------------------------------------------------------------------------------------------------- | +| 综合 | `synth_design Complete!` | | 实现 | `route_design Complete!`、`write_bitstream Complete!`,`WNS = +5.109 ns`(无 Failed Timing) | | 资源 | LUT 3420 (5.39%)、FF 2507、**DSP 0**(组合乘法器已消失)、IOB 23 (10.95%) | -| bit 文件 | `pipelined-cpu/pipelined-cpu.runs/impl_1/cpu21_board_top.bit` | +| bit 文件 | `pipelined-cpu/pipelined-cpu.runs/impl_1/cpu21_board_top.bit` | 对比改造前(组合乘除法 + `CLK_DIV=16`):LUT 5400 → 3420、DSP 12 → 0、 CPU 时钟 6.25 MHz → 50 MHz(快 8 倍),并且乘除法不再位于关键路径上。 @@ -561,11 +559,11 @@ cd ..\pipelined-cpu 板上操作: -| 板子上 | 作用 | -| ------------------------- | ---------------------------------------------------- | -| BTNU / BTND / BTNL / BTNR | 光标 上 / 下 / 左 / 右 | -| BTNC | 左键:开始界面确认 / 关卡里开格 | -| SW3 拨上 + BTNC | 插旗 / 取消旗 | +| 板子上 | 作用 | +| ------------------------- | ---------------------------------------------------------- | +| BTNU / BTND / BTNL / BTNR | 光标 上 / 下 / 左 / 右 | +| BTNC | 左键:开始界面确认 / 关卡里开格 | +| SW3 拨上 + BTNC | 插旗 / 取消旗 | | SW0 / SW1 / SW2 | **别动**,它们会 OR 进外部中断线,一拨就可能触发中断 | 开始界面的光标默认停在 START 按钮上,按 BTNC 进关卡;关卡里把光标移到盘面**左上角那个黄格** @@ -633,12 +631,12 @@ powershell -ExecutionPolicy Bypass -File tools\run_regress.ps1 期望结果(2026-09,多周期乘除法 + `CLK_DIV=2`): -| 测试 | 期望 | -| -------------------------------------------------- | ---------------------------------------------------------------------------- | -| muldiv_test / isa_test / lui_test / mmio_test | 13 / 24 / 4 / 5 个 LED 值全部匹配 | +| 测试 | 期望 | +| -------------------------------------------------- | ------------------------------------------------------------------------------ | +| muldiv_test / isa_test / lui_test / mmio_test | 13 / 24 / 4 / 5 个 LED 值全部匹配 | | tb_no_intr(benchmark,5560 周期) | `stalls=1528 bubbles=1830 cond_taken=639 uncond=71 pred_ok=687 pred_fail=80` | | tb_cpu21_riscv_redirect_int_bpb(中断,6003 周期) | `stalls=963 bubbles=1205 cond_taken=547 uncond=28 pred_ok=557 pred_fail=87` | -| 板级(快速 ROM) | 跑马灯`0001 → … → 8000` 循环,每步约 2.6 µs | +| 板级(快速 ROM) | 跑马灯`0001 → … → 8000` 循环,每步约 2.6 µs | ## 工程分享(Tcl 一键重建) diff --git a/pipelined-cpu/srcs/board/cpu21_board_top.v b/pipelined-cpu/srcs/board/cpu21_board_top.v index 0e55cce..93e822d 100644 --- a/pipelined-cpu/srcs/board/cpu21_board_top.v +++ b/pipelined-cpu/srcs/board/cpu21_board_top.v @@ -31,449 +31,427 @@ // 注意:ROM_WORDS / RAM_WORDS 需为 2 的幂(默认 1024,对应地址位 [11:2])。 // ----------------------------------------------------------------------------- module cpu21_board_top #( - parameter [31:0] LED_ADDR = 32'h0000_1000, - parameter ROM_WORDS = 8192, - parameter RAM_WORDS = 1024, - parameter [31:0] USTATUS_INIT = 32'h0000_0001, - // 板载 100 MHz 的分频比(1 = 直用 100 MHz,2 = 50 MHz,…)。 - // 乘除法改成多周期单元后,原来 ~94 ns 的组合乘法/除法已经不在关键路径上, - // 实测(xc7a100tcsg324-1): - // CLK_DIV=1(100 MHz):WNS = -1.1 ns,违例路径是 EX 级的 - // 分支判决/中断保存 → BPB 更新,与乘除法无关(逻辑只占 ~3 ns, - // 7~8 ns 都是布线); - // CLK_DIV=2( 50 MHz):WNS ≈ +8 ns,余量充足。 - // 因此默认取 2,既比原来的 16 分频快 8 倍,又能保证时序收敛。 - parameter integer CLK_DIV = 2, - // 中断综合测试程序(RISC_V_INTRUPT_CCAB_ROM)专用的 CPU 分频比。 - // 该程序每次显示之间的延时常量是按 50 MHz 调的:50 MHz 下每个数值只停留 - // 约 10 ms,数码管上根本读不出来。停留时间与分频比成正比,例如: - // 8 → 12.5 MHz(每个数值约 40 ms)、16 → 6.25 MHz(约 80 ms)、 - // 32 → 3.125 MHz(约 160 ms)、64 → 1.5625 MHz(约 320 ms)。 - // 取大于 2 的值只是把实际时钟变慢,XDC 的 cpu_clk 仍按最坏情况 50 MHz 约束, - // 所以不会掩盖时序违例(约束偏严)。 - parameter integer CLK_DIV_INTRUPT = 32, - // 鼠标事件源:0 = 板上 5 向按键(免外设,默认);1 = PS/2 鼠标(Pmod JA) - parameter integer USE_PS2_MOUSE = 0, - // 5 向按键去抖的采样周期(CPU 周期数):上板默认 50000(1 ms @50 MHz)。 - // 仿真里可以传一个小值,让"按一下"在几十微秒内就被识别。 - parameter integer POINTER_SAMPLE_DIV = 50000 - ) ( - input wire clk100, // E3 - input wire rst_n, // C12:CPU_RESETN,低有效 - input wire go, // N17:BTNC(同时用作鼠标左键) - input wire [ 2:0] irq_sw, // SW[2:0]:原来的 3 路中断源(保持兼容) - input wire btnu, // M18:光标上 - input wire btnd, // P18:光标下 - input wire btnl, // P17:光标左 - input wire btnr, // M17:光标右 - input wire sw_flag, // R15:SW[3],插旗模式(软件读 INPUT 寄存器) - output wire [15:0] led, // LED[15:0] - output wire led_we, // LED16_B:MMIO 写入指示 - // 七段数码管(共阳极:位选/段选都是低有效) - output wire [ 7:0] an, - output wire [ 6:0] seg, - output wire dp, - // VGA - output wire [ 3:0] vga_r, - output wire [ 3:0] vga_g, - output wire [ 3:0] vga_b, - output wire vga_hs, - output wire vga_vs, - // PS/2(只有 USE_PS2_MOUSE=1 时才用) - input wire ps2_clk, - input wire ps2_data - ); - localparam ROM_AW = $clog2(ROM_WORDS); - localparam RAM_AW = $clog2(RAM_WORDS); + parameter [31:0] LED_ADDR = 32'h0000_1000, + parameter ROM_WORDS = 8192, + parameter RAM_WORDS = 1024, + parameter [31:0] USTATUS_INIT = 32'h0000_0001, + // 板载 100 MHz 的分频比(1 = 直用 100 MHz,2 = 50 MHz,…)。 + // 乘除法改成多周期单元后,原来 ~94 ns 的组合乘法/除法已经不在关键路径上, + // 实测(xc7a100tcsg324-1): + // CLK_DIV=1(100 MHz):WNS = -1.1 ns,违例路径是 EX 级的 + // 分支判决/中断保存 → BPB 更新,与乘除法无关(逻辑只占 ~3 ns, + // 7~8 ns 都是布线); + // CLK_DIV=2( 50 MHz):WNS ≈ +8 ns,余量充足。 + // 因此默认取 2,既比原来的 16 分频快 8 倍,又能保证时序收敛。 + parameter integer CLK_DIV = 2, + // 中断综合测试程序(RISC_V_INTRUPT_CCAB_ROM)专用的 CPU 分频比。 + // 该程序每次显示之间的延时常量是按 50 MHz 调的:50 MHz 下每个数值只停留 + // 约 10 ms,数码管上根本读不出来。停留时间与分频比成正比,例如: + // 8 → 12.5 MHz(每个数值约 40 ms)、16 → 6.25 MHz(约 80 ms)、 + // 32 → 3.125 MHz(约 160 ms)、64 → 1.5625 MHz(约 320 ms)。 + // 取大于 2 的值只是把实际时钟变慢,XDC 的 cpu_clk 仍按最坏情况 50 MHz 约束, + // 所以不会掩盖时序违例(约束偏严)。 + parameter integer CLK_DIV_INTRUPT = 32, + // 鼠标事件源:0 = 板上 5 向按键(免外设,默认);1 = PS/2 鼠标(Pmod JA) + parameter integer USE_PS2_MOUSE = 0, + // 5 向按键去抖的采样周期(CPU 周期数):上板默认 50000(1 ms @50 MHz)。 + // 仿真里可以传一个小值,让"按一下"在几十微秒内就被识别。 + parameter integer POINTER_SAMPLE_DIV = 50000 +) ( + input wire clk100, // E3 + input wire rst_n, // C12:CPU_RESETN,低有效 + input wire go, // N17:BTNC(同时用作鼠标左键) + input wire [ 2:0] irq_sw, // SW[2:0]:原来的 3 路中断源(保持兼容) + input wire btnu, // M18:光标上 + input wire btnd, // P18:光标下 + input wire btnl, // P17:光标左 + input wire btnr, // M17:光标右 + input wire sw_flag, // R15:SW[3],插旗模式(软件读 INPUT 寄存器) + output wire [15:0] led, // LED[15:0] + output wire led_we, // LED16_B:MMIO 写入指示 + // 七段数码管(共阳极:位选/段选都是低有效) + output wire [ 7:0] an, + output wire [ 6:0] seg, + output wire dp, + // VGA + output wire [ 3:0] vga_r, + output wire [ 3:0] vga_g, + output wire [ 3:0] vga_b, + output wire vga_hs, + output wire vga_vs, + // PS/2(只有 USE_PS2_MOUSE=1 时才用) + input wire ps2_clk, + input wire ps2_data +); + localparam ROM_AW = $clog2(ROM_WORDS); + localparam RAM_AW = $clog2(RAM_WORDS); - // CPU 时钟实际用的分频比:中断综合测试程序用更慢的 CLK_DIV_INTRUPT, - // 其余程序用 CLK_DIV。两者必须都是偶数(保证 50% 占空比)。 + // CPU 时钟实际用的分频比:中断综合测试程序用更慢的 CLK_DIV_INTRUPT, + // 其余程序用 CLK_DIV。两者必须都是偶数(保证 50% 占空比)。 `ifdef RISC_V_INTRUPT_CCAB_ROM - localparam integer CPU_DIV = CLK_DIV_INTRUPT; - `elsif RISC_V_INTRUPT_SLLSB_ROM - localparam integer CPU_DIV = CLK_DIV_INTRUPT; + localparam integer CPU_DIV = CLK_DIV_INTRUPT; +`elsif RISC_V_INTRUPT_SLLSB_ROM + localparam integer CPU_DIV = CLK_DIV_INTRUPT; `else - localparam integer CPU_DIV = CLK_DIV; + localparam integer CPU_DIV = CLK_DIV; `endif - // 数码管扫描分频:目标是“每位数码管约 125 Hz 刷新”(即每步 1 ms),与 CPU - // 时钟频率无关。每步时间 = REFRESH_DIV / f_cpu,而 f_cpu = 100 MHz / CPU_DIV, - // 所以 REFRESH_DIV = 1 ms × f_cpu = 100000 / CPU_DIV: - // CPU_DIV = 2( 50 MHz)-> 50000(每步 1 ms,每位数码管 125 Hz) - // CPU_DIV = 8(12.5 MHz)-> 12500(同上) - // 例:CPU_DIV = 32(3.125 MHz)-> 3125(每步仍是 1 ms)。 - // 不这样缩放的话,CPU 降频时扫描会按同样比例变慢,肉眼能看到闪烁。 - localparam integer SEG_REFRESH_DIV = 100000 / CPU_DIV; + // 数码管扫描分频:目标是“每位数码管约 125 Hz 刷新”(即每步 1 ms),与 CPU + // 时钟频率无关。每步时间 = REFRESH_DIV / f_cpu,而 f_cpu = 100 MHz / CPU_DIV, + // 所以 REFRESH_DIV = 1 ms × f_cpu = 100000 / CPU_DIV: + // CPU_DIV = 2( 50 MHz)-> 50000(每步 1 ms,每位数码管 125 Hz) + // CPU_DIV = 8(12.5 MHz)-> 12500(同上) + // 例:CPU_DIV = 32(3.125 MHz)-> 3125(每步仍是 1 ms)。 + // 不这样缩放的话,CPU 降频时扫描会按同样比例变慢,肉眼能看到闪烁。 + localparam integer SEG_REFRESH_DIV = 100000 / CPU_DIV; - wire arst = ~rst_n; // 异步复位(高有效) + wire arst = ~rst_n; // 异步复位(高有效) - // --------------------------------------------------------------------------- - // 时钟:100 MHz / CPU_DIV 给 CPU。默认 50 MHz(CLK_DIV=2);跑中断综合测试 - // 程序时用更慢的 CLK_DIV_INTRUPT(见该参数说明),让数码管上的数值停留更久。 - // - // 乘除法已经是 cpu21_riscv_muldiv 里的多周期单元,关键路径上不再有组合的 - // 32x32 乘法/除法;剩下的违例路径是 EX 级“分支判决/中断保存 → BPB 更新”, - // 与乘除法无关,实测 100 MHz 下 WNS = -1.1 ns,50 MHz 下余量约 +8 ns。 - // 分频后的时钟由 Vivado 自动插 BUFG;XDC 里用 create_generated_clock 声明。 - // XDC 按最坏情况固定成 -divide_by 2(50 MHz),所以这里把实际时钟变慢属于 - // “约束偏严”,不会掩盖时序违例。 - // - // 中断综合测试程序会用更慢的 CPU_DIV(见 CLK_DIV_INTRUPT):程序里的延时常量 - // 按 50 MHz 调好,50 MHz 下每个数值只停留约 10 ms,读数根本看不清; - // 停留时间与分频比成正比,具体见 CLK_DIV_INTRUPT 的说明。 - // 注意:VGA 的 25 MHz 像素节拍也是从这个 CPU 时钟分频出来的,CPU 降频时 - // VGA 行场时序会跟着变慢(超出 VGA 规范)。中断测试程序不用 VGA,无影响。 - // --------------------------------------------------------------------------- - reg [15:0] clk_cnt; - reg clk_div; + // --------------------------------------------------------------------------- + // 时钟:100 MHz / CPU_DIV 给 CPU。默认 50 MHz(CLK_DIV=2);跑中断综合测试 + // 程序时用更慢的 CLK_DIV_INTRUPT(见该参数说明),让数码管上的数值停留更久。 + // + // 乘除法已经是 cpu21_riscv_muldiv 里的多周期单元,关键路径上不再有组合的 + // 32x32 乘法/除法;剩下的违例路径是 EX 级“分支判决/中断保存 → BPB 更新”, + // 与乘除法无关,实测 100 MHz 下 WNS = -1.1 ns,50 MHz 下余量约 +8 ns。 + // 分频后的时钟由 Vivado 自动插 BUFG;XDC 里用 create_generated_clock 声明。 + // XDC 按最坏情况固定成 -divide_by 2(50 MHz),所以这里把实际时钟变慢属于 + // “约束偏严”,不会掩盖时序违例。 + // + // 中断综合测试程序会用更慢的 CPU_DIV(见 CLK_DIV_INTRUPT):程序里的延时常量 + // 按 50 MHz 调好,50 MHz 下每个数值只停留约 10 ms,读数根本看不清; + // 停留时间与分频比成正比,具体见 CLK_DIV_INTRUPT 的说明。 + // 注意:VGA 的 25 MHz 像素节拍也是从这个 CPU 时钟分频出来的,CPU 降频时 + // VGA 行场时序会跟着变慢(超出 VGA 规范)。中断测试程序不用 VGA,无影响。 + // --------------------------------------------------------------------------- + reg [15:0] clk_cnt; + reg clk_div; - always @(posedge clk100 or posedge arst) begin - if (arst) begin - clk_cnt <= 16'd0; - clk_div <= 1'b0; - end - else if (clk_cnt == (CPU_DIV / 2 - 1)) begin - clk_cnt <= 16'd0; - clk_div <= ~clk_div; - end - else begin - clk_cnt <= clk_cnt + 16'd1; - end + always @(posedge clk100 or posedge arst) begin + if (arst) begin + clk_cnt <= 16'd0; + clk_div <= 1'b0; + end else if (clk_cnt == (CPU_DIV / 2 - 1)) begin + clk_cnt <= 16'd0; + clk_div <= ~clk_div; + end else begin + clk_cnt <= clk_cnt + 16'd1; end + end - wire clk_cpu = clk_div; + wire clk_cpu = clk_div; - // --------------------------------------------------------------------------- - // 复位同步器:按键异步置位、释放与 CPU 时钟同步 - // --------------------------------------------------------------------------- - reg [2:0] rst_sync_q; + // --------------------------------------------------------------------------- + // 复位同步器:按键异步置位、释放与 CPU 时钟同步 + // --------------------------------------------------------------------------- + reg [2:0] rst_sync_q; - always @(posedge clk_cpu or posedge arst) begin - if (arst) - rst_sync_q <= 3'b111; - else - rst_sync_q <= {rst_sync_q[1:0], 1'b0}; - end + always @(posedge clk_cpu or posedge arst) begin + if (arst) rst_sync_q <= 3'b111; + else rst_sync_q <= {rst_sync_q[1:0], 1'b0}; + end - wire reset = rst_sync_q[2]; + wire reset = rst_sync_q[2]; - // CPU 接口连线(先声明:后面的 ROM/RAM 逻辑与例化都要用到) - wire [31:0] instr_addr; - wire [31:0] data_addr; - wire [31:0] data_wdata; - wire [ 3:0] data_wstrb; - wire data_we; - wire [31:0] led_data; // LED_ADDR 写入值,同时作为七段数码管显示数据 - wire led_valid; - // 扫雷扩展外设的连线(先声明,例化在下面) - wire [31:0] disp_ctrl, disp_cursor; // 显示控制器(CPU 内部 MMIO 驱动) - wire [31:0] seg_data; // 保留的独立数码管 MMIO 数据 - wire seg_valid; - wire fb_we; // 显存写端口 - wire [ 9:0] fb_waddr; - wire [31:0] fb_wdata; - wire [ 3:0] fb_wstrb; - wire [ 9:0] fb_raddr; // 显存读端口(VGA) - wire mouse_irq, level_irq; // 鼠标事件中断 / 软件中断(关卡入口) - wire [1:0] irq_level; // 当前正在服务的中断级别(0 = 不在中断里,1/2/3 = 在 ISR 里) - wire frame_tick; - wire [15:0] sw_vec = {12'b0, sw_flag, irq_sw}; - // 中断连线:SW0 与鼠标共用一个入口,SW1 与"关卡入口"共用一个入口。 - // 中断线对应关系(必须与 saolei/sw/linker.ld、mmio.h 的约定一致): - // irq_vec[0] = IRQ1 -> 入口 0x100 = 关卡(游戏),由 LEVEL 软件中断拉起 - // irq_vec[1] = IRQ2 -> 入口 0x200 = 鼠标读取,由事件 FIFO 非空拉起 - // irq_vec[2] = IRQ3 -> 入口 0x300 = 备用 - // (原来 mouse 接在 [0]、level 接在 [1],正好对调:第一个鼠标事件会跳进关卡 - // 入口把棋盘画出来,而鼠标 ISR 永不执行,FIFO 不弹空、中断线恒高 —— 于是 - // 只能收到一次事件。拨码开关 SW[2:0] 仍按位 OR 进来,兼容原中断测试程序。) - wire [2:0] irq_vec = {irq_sw[2], (mouse_irq | irq_sw[1]), (level_irq | irq_sw[0])}; + // CPU 接口连线(先声明:后面的 ROM/RAM 逻辑与例化都要用到) + wire [31:0] instr_addr; + wire [31:0] data_addr; + wire [31:0] data_wdata; + wire [ 3:0] data_wstrb; + wire data_we; + wire [31:0] led_data; // LED_ADDR 写入值,同时作为七段数码管显示数据 + wire led_valid; + // 扫雷扩展外设的连线(先声明,例化在下面) + wire [31:0] disp_ctrl, disp_cursor; // 显示控制器(CPU 内部 MMIO 驱动) + wire [31:0] seg_data; // 保留的独立数码管 MMIO 数据 + wire seg_valid; + wire fb_we; // 显存写端口 + wire [ 9:0] fb_waddr; + wire [31:0] fb_wdata; + wire [ 3:0] fb_wstrb; + wire [ 9:0] fb_raddr; // 显存读端口(VGA) + wire mouse_irq, level_irq; // 鼠标事件中断 / 软件中断(关卡入口) + wire [1:0] irq_level; // 当前正在服务的中断级别(0 = 不在中断里,1/2/3 = 在 ISR 里) + wire frame_tick; + wire [15:0] sw_vec = {12'b0, sw_flag, irq_sw}; + // 中断连线:SW0 与鼠标共用一个入口,SW1 与"关卡入口"共用一个入口。 + // 中断线对应关系(必须与 saolei/sw/linker.ld、mmio.h 的约定一致): + // irq_vec[0] = IRQ1 -> 入口 0x100 = 关卡(游戏),由 LEVEL 软件中断拉起 + // irq_vec[1] = IRQ2 -> 入口 0x200 = 鼠标读取,由事件 FIFO 非空拉起 + // irq_vec[2] = IRQ3 -> 入口 0x300 = 备用 + // (原来 mouse 接在 [0]、level 接在 [1],正好对调:第一个鼠标事件会跳进关卡 + // 入口把棋盘画出来,而鼠标 ISR 永不执行,FIFO 不弹空、中断线恒高 —— 于是 + // 只能收到一次事件。拨码开关 SW[2:0] 仍按位 OR 进来,兼容原中断测试程序。) + wire [2:0] irq_vec = {irq_sw[2], (mouse_irq | irq_sw[1]), (level_irq | irq_sw[0])}; - // --------------------------------------------------------------------------- - // 指令 ROM:组合读(未用到的地址填 NOP) - // --------------------------------------------------------------------------- - reg [31:0] rom[0:ROM_WORDS-1]; - integer i; + // --------------------------------------------------------------------------- + // 指令 ROM:组合读(未用到的地址填 NOP) + // --------------------------------------------------------------------------- + reg [31:0] rom[0:ROM_WORDS-1]; + integer i; - initial begin - for (i = 0; i < ROM_WORDS; i = i + 1) - rom[i] = 32'h0000_0013; // NOP 填充 + initial begin + for (i = 0; i < ROM_WORDS; i = i + 1) rom[i] = 32'h0000_0013; // NOP 填充 `ifdef SAOLEI_ROM - // 扫雷程序(由 saolei/tools/build.ps1 生成的 cpu21_saolei_rom.vh)。 - // 综合/仿真时定义宏 SAOLEI_ROM 即可切换到这个程序;不定义就是下面的跑马灯。 -`include "cpu21_saolei_rom.vh" + // 扫雷程序(由 saolei/tools/build.ps1 生成的 cpu21_saolei_rom.vh)。 + // 综合/仿真时定义宏 SAOLEI_ROM 即可切换到这个程序;不定义就是下面的跑马灯。 + `include "cpu21_saolei_rom.vh" - `elsif RISC_V_INTRUPT_CCAB_ROM - // 中断综合测试程序:三个中断入口由镜像中的实际标签位置决定。 -`include "risc-v-intrupt-ccab.vh" - `elsif RISC_V_INTRUPT_SLLSB_ROM - // 课程新版中断测试(附加 SLL/SB/BLTU),ISR 入口 0x0AC / 0x240 / 0x3E8。 -`include "risc-v-intrupt-sllsb.vh" - `elsif BOARD_ROM_FAST - // 仿真专用:把演示程序的延时改小的版本(综合流程不会用到) -`include "cpu21_board_rom_fast.vh" +`elsif RISC_V_INTRUPT_CCAB_ROM + // 中断综合测试程序:三个中断入口由镜像中的实际标签位置决定。 + `include "risc-v-intrupt-ccab.vh" +`elsif RISC_V_INTRUPT_SLLSB_ROM + // 课程新版中断测试(附加 SLL/SB/BLTU),ISR 入口 0x0AC / 0x240 / 0x3E8。 + `include "risc-v-intrupt-sllsb.vh" +`elsif BOARD_ROM_FAST + // 仿真专用:把演示程序的延时改小的版本(综合流程不会用到) + `include "cpu21_board_rom_fast.vh" `else -`include "cpu21_board_rom.vh" + `include "cpu21_board_rom.vh" `endif - end + end - // --------------------------------------------------------------------------- - // 数据 RAM:字节写使能 + 组合读 - // --------------------------------------------------------------------------- - reg [31:0] ram[0:RAM_WORDS-1]; - integer j; + // --------------------------------------------------------------------------- + // 数据 RAM:字节写使能 + 组合读 + // --------------------------------------------------------------------------- + reg [31:0] ram[0:RAM_WORDS-1]; + integer j; - initial begin - for (j = 0; j < RAM_WORDS; j = j + 1) - ram[j] = 32'b0; + initial begin + for (j = 0; j < RAM_WORDS; j = j + 1) ram[j] = 32'b0; + end + + wire [ROM_AW+1:2] rom_index = instr_addr[ROM_AW+1:2]; + wire [RAM_AW+1:2] ram_index = data_addr[RAM_AW+1:2]; + wire ram_sel = (data_addr[31:RAM_AW+2] == 0); + + wire [31:0] instr_word = rom[rom_index]; + wire [31:0] data_rdata = ram_sel ? ram[ram_index] : 32'b0; + + always @(posedge clk_cpu) begin + if (ram_sel && data_we) begin + if (data_wstrb[0]) ram[ram_index][7:0] <= data_wdata[7:0]; + if (data_wstrb[1]) ram[ram_index][15:8] <= data_wdata[15:8]; + if (data_wstrb[2]) ram[ram_index][23:16] <= data_wdata[23:16]; + if (data_wstrb[3]) ram[ram_index][31:24] <= data_wdata[31:24]; end + end - wire [ROM_AW+1:2] rom_index = instr_addr[ROM_AW+1:2]; - wire [RAM_AW+1:2] ram_index = data_addr[RAM_AW+1:2]; - wire ram_sel = (data_addr[31:RAM_AW+2] == 0); - - wire [31:0] instr_word = rom[rom_index]; - wire [31:0] data_rdata = ram_sel ? ram[ram_index] : 32'b0; - - always @(posedge clk_cpu) begin - if (ram_sel && data_we) begin - if (data_wstrb[0]) - ram[ram_index][7:0] <= data_wdata[7:0]; - if (data_wstrb[1]) - ram[ram_index][15:8] <= data_wdata[15:8]; - if (data_wstrb[2]) - ram[ram_index][23:16] <= data_wdata[23:16]; - if (data_wstrb[3]) - ram[ram_index][31:24] <= data_wdata[31:24]; - end - end - - // --------------------------------------------------------------------------- - // 处理器:只连接上板需要的端口,调试端口留空(不产生 I/O) - // --------------------------------------------------------------------------- - cpu21_riscv_redirect_int_bpb #( - .LED_ADDR (LED_ADDR), - .USTATUS_INIT(USTATUS_INIT), - // 中断入口必须与所选 ROM 镜像中的 ISR 起点一致。 + // --------------------------------------------------------------------------- + // 处理器:只连接上板需要的端口,调试端口留空(不产生 I/O) + // --------------------------------------------------------------------------- + cpu21_riscv_redirect_int_bpb #( + .LED_ADDR (LED_ADDR), + .USTATUS_INIT(USTATUS_INIT), + // 中断入口必须与所选 ROM 镜像中的 ISR 起点一致。 `ifdef RISC_V_INTRUPT_CCAB_ROM - // risc-v-intrupt-ccab.hex:字 43/121/194 - .IRQ1_VECTOR (32'h0000_00AC), - .IRQ2_VECTOR (32'h0000_01E4), - .IRQ3_VECTOR (32'h0000_0308) - `elsif RISC_V_INTRUPT_SLLSB_ROM - // risc-v-intrupt-sllsb.hex:字 43/144/250(加了 SLL/SB/BLTU 后 ISR2/3 后移) - .IRQ1_VECTOR (32'h0000_00AC), - .IRQ2_VECTOR (32'h0000_0240), - .IRQ3_VECTOR (32'h0000_03E8) + // risc-v-intrupt-ccab.hex:字 43/121/194 + .IRQ1_VECTOR (32'h0000_00AC), + .IRQ2_VECTOR (32'h0000_01E4), + .IRQ3_VECTOR (32'h0000_0308) +`elsif RISC_V_INTRUPT_SLLSB_ROM + // risc-v-intrupt-sllsb.hex:字 43/144/250(加了 SLL/SB/BLTU 后 ISR2/3 后移) + .IRQ1_VECTOR (32'h0000_00AC), + .IRQ2_VECTOR (32'h0000_0240), + .IRQ3_VECTOR (32'h0000_03E8) `else - // 扫雷程序:linker.ld 中固定的 0x100/0x200/0x300 - .IRQ1_VECTOR (32'h0000_0100), - .IRQ2_VECTOR (32'h0000_0200), - .IRQ3_VECTOR (32'h0000_0300) + // 扫雷程序:linker.ld 中固定的 0x100/0x200/0x300 + .IRQ1_VECTOR (32'h0000_0100), + .IRQ2_VECTOR (32'h0000_0200), + .IRQ3_VECTOR (32'h0000_0300) `endif - ) u_cpu ( - .clk (clk_cpu), - .reset (reset), - .instr_i (instr_word), - .data_rdata_i(data_rdata), - .irq_i (irq_vec), - .go_i (go), + ) u_cpu ( + .clk (clk_cpu), + .reset (reset), + .instr_i (instr_word), + .data_rdata_i(data_rdata), + .irq_i (irq_vec), + .go_i (go), - .instr_addr_o(instr_addr), - .data_addr_o (data_addr), - .data_wdata_o(data_wdata), - .data_wstrb_o(data_wstrb), - .data_we_o (data_we), + .instr_addr_o(instr_addr), + .data_addr_o (data_addr), + .data_wdata_o(data_wdata), + .data_wstrb_o(data_wstrb), + .data_we_o (data_we), - .led_data_o (led_data), - .led_valid_o(led_valid), + .led_data_o (led_data), + .led_valid_o(led_valid), - // 扫雷扩展外设 - .seg_data_o (seg_data), - .seg_valid_o (seg_valid), - .fb_we_o (fb_we), - .fb_waddr_o (fb_waddr), - .fb_wdata_o (fb_wdata), - .fb_wstrb_o (fb_wstrb), - .fb_rdata_i (fb_rdata), - .disp_ctrl_o (disp_ctrl), - .disp_cursor_o (disp_cursor), - .mouse_ev_valid_i (ev_valid), - .mouse_dx_i (ev_dx), - .mouse_dy_i (ev_dy), - .mouse_btn_i (ev_btn), - .sw_i (sw_vec), - .frame_tick_i (frame_tick), - .mouse_irq_o (mouse_irq), - .level_irq_o (level_irq), - // 中断服务级别,供板上的中断指示 LED 使用(见下面 LED 那一段) - .irq_current_level_o(irq_level) - ); + // 扫雷扩展外设 + .seg_data_o (seg_data), + .seg_valid_o (seg_valid), + .fb_we_o (fb_we), + .fb_waddr_o (fb_waddr), + .fb_wdata_o (fb_wdata), + .fb_wstrb_o (fb_wstrb), + .fb_rdata_i (fb_rdata), + .disp_ctrl_o (disp_ctrl), + .disp_cursor_o (disp_cursor), + .mouse_ev_valid_i (ev_valid), + .mouse_dx_i (ev_dx), + .mouse_dy_i (ev_dy), + .mouse_btn_i (ev_btn), + .sw_i (sw_vec), + .frame_tick_i (frame_tick), + .mouse_irq_o (mouse_irq), + .level_irq_o (level_irq), + // 中断服务级别,供板上的中断指示 LED 使用(见下面 LED 那一段) + .irq_current_level_o(irq_level) + ); - // --------------------------------------------------------------------------- - // 板载 LED:三路中断指示;十六进制数据改由七段数码管显示。 - // - // 第 k 路中断从"请求出现"开始点亮,一直亮到它的 ISR 执行完 uret(中断返回) - // 之后才熄灭: - // 置位:irq_vec[k] 的上升沿。中断控制器内部也是按上升沿响应中断的 - // (cpu21_riscv_irq_ctrl 里的 irq_event),两者行为一致;开关一直 - // 接通不会重复点亮,只有新的上升沿才会重新置位。 - // 清零:服务级别 irq_level 从 k+1 **降下来**,说明第 k+1 级的中断已经返回。 - // 注意必须判断“下降”:级别从 1 升到 2 是深层中断抢占,此时第 1 级 - // 的中断还在服务中,LED 不能熄。中断可以嵌套,返回时按级别逐层降 - // 下来,因此每一路都在自己的 ISR 结束时熄灭。 - // --------------------------------------------------------------------------- - reg [2:0] irq_req_q; // 中断请求打一拍,用于取上升沿 - reg [1:0] irq_level_q; // 服务级别打一拍,用于检测"返回" - reg [2:0] irq_led_q; // 三路中断指示 + // --------------------------------------------------------------------------- + // 板载 LED:三路中断指示;十六进制数据改由七段数码管显示。 + // + // 第 k 路中断从"请求出现"开始点亮,一直亮到它的 ISR 执行完 uret(中断返回) + // 之后才熄灭: + // 置位:irq_vec[k] 的上升沿。中断控制器内部也是按上升沿响应中断的 + // (cpu21_riscv_irq_ctrl 里的 irq_event),两者行为一致;开关一直 + // 接通不会重复点亮,只有新的上升沿才会重新置位。 + // 清零:服务级别 irq_level 从 k+1 **降下来**,说明第 k+1 级的中断已经返回。 + // 注意必须判断“下降”:级别从 1 升到 2 是深层中断抢占,此时第 1 级 + // 的中断还在服务中,LED 不能熄。中断可以嵌套,返回时按级别逐层降 + // 下来,因此每一路都在自己的 ISR 结束时熄灭。 + // --------------------------------------------------------------------------- + reg [2:0] irq_req_q; // 中断请求打一拍,用于取上升沿 + reg [1:0] irq_level_q; // 服务级别打一拍,用于检测"返回" + reg [2:0] irq_led_q; // 三路中断指示 - wire isr_ret0 = (irq_level_q == 2'd1) && (irq_level < irq_level_q); - wire isr_ret1 = (irq_level_q == 2'd2) && (irq_level < irq_level_q); - wire isr_ret2 = (irq_level_q == 2'd3) && (irq_level < irq_level_q); + wire isr_ret0 = (irq_level_q == 2'd1) && (irq_level < irq_level_q); + wire isr_ret1 = (irq_level_q == 2'd2) && (irq_level < irq_level_q); + wire isr_ret2 = (irq_level_q == 2'd3) && (irq_level < irq_level_q); - always @(posedge clk_cpu or posedge arst) begin - if (arst) begin - irq_req_q <= 3'b000; - irq_level_q <= 2'd0; - irq_led_q <= 3'b000; - end - else begin - irq_req_q <= irq_vec; - irq_level_q <= irq_level; - // 请求上升沿 -> 点亮;对应级别的 ISR 返回 -> 熄灭 - irq_led_q[0] <= (irq_vec[0] & ~irq_req_q[0]) | (irq_led_q[0] & ~isr_ret0); - irq_led_q[1] <= (irq_vec[1] & ~irq_req_q[1]) | (irq_led_q[1] & ~isr_ret1); - irq_led_q[2] <= (irq_vec[2] & ~irq_req_q[2]) | (irq_led_q[2] & ~isr_ret2); - end + always @(posedge clk_cpu or posedge arst) begin + if (arst) begin + irq_req_q <= 3'b000; + irq_level_q <= 2'd0; + irq_led_q <= 3'b000; + end else begin + irq_req_q <= irq_vec; + irq_level_q <= irq_level; + // 请求上升沿 -> 点亮;对应级别的 ISR 返回 -> 熄灭 + irq_led_q[0] <= (irq_vec[0] & ~irq_req_q[0]) | (irq_led_q[0] & ~isr_ret0); + irq_led_q[1] <= (irq_vec[1] & ~irq_req_q[1]) | (irq_led_q[1] & ~isr_ret1); + irq_led_q[2] <= (irq_vec[2] & ~irq_req_q[2]) | (irq_led_q[2] & ~isr_ret2); end + end - assign led = {{13{1'b0}}, irq_led_q}; + assign led = {{13{1'b0}}, irq_led_q}; - reg [23:0] led_we_cnt; + reg [23:0] led_we_cnt; - always @(posedge clk_cpu or posedge arst) begin - if (arst) - led_we_cnt <= 24'd0; - else if (led_valid) - led_we_cnt <= 24'hFF_FFFF; // 约 0.34 s @50 MHz - // (12.5 MHz 下约 1.36 s) - else if (led_we_cnt != 24'd0) - led_we_cnt <= led_we_cnt - 24'd1; + always @(posedge clk_cpu or posedge arst) begin + if (arst) led_we_cnt <= 24'd0; + else if (led_valid) led_we_cnt <= 24'hFF_FFFF; // 约 0.34 s @50 MHz + // (12.5 MHz 下约 1.36 s) + else if (led_we_cnt != 24'd0) led_we_cnt <= led_we_cnt - 24'd1; + end + + assign led_we = (led_we_cnt != 24'd0); + + // =========================================================================== + // 扫雷外设:显存 + VGA + 七段数码管 + 鼠标事件源 + 中断连线 + // + // 显存是一块 2400 字节的双口 RAM(40x30 格,每格 2 字节):CPU 通过 MMIO 的 + // fb_* 写端口写入,VGA 用另一个读端口组合读出。两者同处 clk_cpu 域(VGA 的 + // 25 MHz 像素节拍由使能信号产生,不是独立时钟),因此没有跨时钟域问题。 + // =========================================================================== + localparam integer FB_WORDS = 600; // 600 字 = 2400 字节,40x30 格每格 2 字节 + + + // ---- 显存 ---- + reg [31:0] fb[0:FB_WORDS-1]; + integer k; + + initial begin + for (k = 0; k < FB_WORDS; k = k + 1) fb[k] = 32'b0; + end + + always @(posedge clk_cpu) begin + if (fb_we) begin + if (fb_wstrb[0]) fb[fb_waddr][7:0] <= fb_wdata[7:0]; + if (fb_wstrb[1]) fb[fb_waddr][15:8] <= fb_wdata[15:8]; + if (fb_wstrb[2]) fb[fb_waddr][23:16] <= fb_wdata[23:16]; + if (fb_wstrb[3]) fb[fb_waddr][31:24] <= fb_wdata[31:24]; end + end - assign led_we = (led_we_cnt != 24'd0); + wire [31:0] fb_rdata = fb[fb_raddr]; - // =========================================================================== - // 扫雷外设:显存 + VGA + 七段数码管 + 鼠标事件源 + 中断连线 - // - // 显存是一块 1200 字节的双口 RAM(40x30 格,每格 1 字节):CPU 通过 MMIO 的 - // fb_* 写端口写入,VGA 用另一个读端口组合读出。两者同处 clk_cpu 域(VGA 的 - // 25 MHz 像素节拍由使能信号产生,不是独立时钟),因此没有跨时钟域问题。 - // =========================================================================== - localparam integer FB_WORDS = 300; // 300 字 = 1200 字节 + // ---- VGA 像素节拍:clk_cpu 二分频 => 25 MHz ---- + reg px_q; + always @(posedge clk_cpu or posedge arst) begin + if (arst) px_q <= 1'b0; + else px_q <= ~px_q; + end + wire px_tick = ~px_q; + cpu21_vga u_vga ( + .clk (clk_cpu), + .reset (reset), + .tick (px_tick), + .fb_raddr_o (fb_raddr), + .fb_word_i (fb_rdata), + .ctrl_i (disp_ctrl), + .cursor_i (disp_cursor), + .vga_r (vga_r), + .vga_g (vga_g), + .vga_b (vga_b), + .vga_hs (vga_hs), + .vga_vs (vga_vs), + .frame_tick_o(frame_tick) + ); - // ---- 显存 ---- - reg [31:0] fb[0:FB_WORDS-1]; - integer k; + // ---- 七段数码管(显示程序写入 LED_ADDR 的 8 位十六进制数)---- + // 扫描分频按 CPU 时钟频率缩放,保持每位数码管约 125 Hz 刷新(不闪烁)。 + cpu21_seg7 #( + .REFRESH_DIV(SEG_REFRESH_DIV) + ) u_seg7 ( + .clk (clk_cpu), + .reset (reset), + .seg_data_i(led_data), + .an_en_i (8'hFF), + .an_o (an), + .seg_o (seg), + .dp_o (dp) + ); - initial begin - for (k = 0; k < FB_WORDS; k = k + 1) - fb[k] = 32'b0; + // ---- 鼠标事件源 ---- + wire ev_valid; + wire [7:0] ev_dx, ev_dy; + wire [4:0] ev_btn; + wire [4:0] btn_vec = {go, btnu, btnd, btnl, btnr}; // {BTNC, BTNU, BTND, BTNL, BTNR} + + generate + if (USE_PS2_MOUSE != 0) begin : g_ps2 + cpu21_ps2_mouse u_ps2 ( + .clk (clk_cpu), + .reset (reset), + .ps2_clk_i (ps2_clk), + .ps2_clk_oe_o (), + .ps2_data_i (ps2_data), + .ps2_data_oe_o(), + .ev_valid_o (ev_valid), + .ev_dx_o (ev_dx), + .ev_dy_o (ev_dy), + .ev_btn_o (ev_btn), + .rx_count_o () + ); + end else begin : g_btn + cpu21_pointer #( + .SAMPLE_DIV(POINTER_SAMPLE_DIV) + ) u_ptr ( + .clk (clk_cpu), + .reset (reset), + .btn_i (btn_vec), + .ev_valid_o(ev_valid), + .ev_dx_o (ev_dx), + .ev_dy_o (ev_dy), + .ev_btn_o (ev_btn) + ); end - - always @(posedge clk_cpu) begin - if (fb_we) begin - if (fb_wstrb[0]) - fb[fb_waddr][7:0] <= fb_wdata[7:0]; - if (fb_wstrb[1]) - fb[fb_waddr][15:8] <= fb_wdata[15:8]; - if (fb_wstrb[2]) - fb[fb_waddr][23:16] <= fb_wdata[23:16]; - if (fb_wstrb[3]) - fb[fb_waddr][31:24] <= fb_wdata[31:24]; - end - end - - wire [31:0] fb_rdata = fb[fb_raddr]; - - // ---- VGA 像素节拍:clk_cpu 二分频 => 25 MHz ---- - reg px_q; - always @(posedge clk_cpu or posedge arst) begin - if (arst) - px_q <= 1'b0; - else - px_q <= ~px_q; - end - wire px_tick = ~px_q; - - cpu21_vga u_vga ( - .clk (clk_cpu), - .reset (reset), - .tick (px_tick), - .fb_raddr_o (fb_raddr), - .fb_word_i (fb_rdata), - .ctrl_i (disp_ctrl), - .cursor_i (disp_cursor), - .vga_r (vga_r), - .vga_g (vga_g), - .vga_b (vga_b), - .vga_hs (vga_hs), - .vga_vs (vga_vs), - .frame_tick_o(frame_tick) - ); - - // ---- 七段数码管(显示程序写入 LED_ADDR 的 8 位十六进制数)---- - // 扫描分频按 CPU 时钟频率缩放,保持每位数码管约 125 Hz 刷新(不闪烁)。 - cpu21_seg7 #( - .REFRESH_DIV(SEG_REFRESH_DIV) - ) u_seg7 ( - .clk (clk_cpu), - .reset (reset), - .seg_data_i(led_data), - .an_en_i (8'hFF), - .an_o (an), - .seg_o (seg), - .dp_o (dp) - ); - - // ---- 鼠标事件源 ---- - wire ev_valid; - wire [7:0] ev_dx, ev_dy; - wire [4:0] ev_btn; - wire [4:0] btn_vec = {go, btnu, btnd, btnl, btnr}; // {BTNC, BTNU, BTND, BTNL, BTNR} - - generate - if (USE_PS2_MOUSE != 0) begin : g_ps2 - cpu21_ps2_mouse u_ps2 ( - .clk (clk_cpu), - .reset (reset), - .ps2_clk_i (ps2_clk), - .ps2_clk_oe_o (), - .ps2_data_i (ps2_data), - .ps2_data_oe_o(), - .ev_valid_o (ev_valid), - .ev_dx_o (ev_dx), - .ev_dy_o (ev_dy), - .ev_btn_o (ev_btn), - .rx_count_o () - ); - end - else begin : g_btn - cpu21_pointer #( - .SAMPLE_DIV(POINTER_SAMPLE_DIV) - ) u_ptr ( - .clk (clk_cpu), - .reset (reset), - .btn_i (btn_vec), - .ev_valid_o(ev_valid), - .ev_dx_o (ev_dx), - .ev_dy_o (ev_dy), - .ev_btn_o (ev_btn) - ); - end - endgenerate + endgenerate endmodule diff --git a/pipelined-cpu/srcs/board/cpu21_saolei_rom.vh b/pipelined-cpu/srcs/board/cpu21_saolei_rom.vh index ca8b4fc..bf6f7de 100644 --- a/pipelined-cpu/srcs/board/cpu21_saolei_rom.vh +++ b/pipelined-cpu/srcs/board/cpu21_saolei_rom.vh @@ -1,9 +1,9 @@ // 由 tools/elf2hex.py 生成,请勿手工编辑 - // 源文件:D:\Desktop\risc-v-cpu\saolei\build\saolei.bin(986 个字,其余填 NOP) + // 源文件:D:\Xilinx\Project\risc-v\saolei\build\saolei.bin(1116 个字,其余填 NOP) rom[0] = 32'h00001137; rom[1] = 32'hFFC10113; rom[2] = 32'h000012B7; - rom[3] = 32'hE3028293; + rom[3] = 32'h03428293; rom[4] = 32'h00028067; rom[5] = 32'h00000013; rom[6] = 32'h00000013; @@ -82,7 +82,7 @@ rom[79] = 32'h03012C23; rom[80] = 32'h03112E23; rom[81] = 32'h0040E073; - rom[82] = 32'h2C1000EF; + rom[82] = 32'h4C5000EF; rom[83] = 32'h03C12883; rom[84] = 32'h03812803; rom[85] = 32'h03412783; @@ -130,7 +130,7 @@ rom[127] = 32'h00000013; rom[128] = 32'hFF810113; rom[129] = 32'h00112023; - rom[130] = 32'h4A1000EF; + rom[130] = 32'h6A9000EF; rom[131] = 32'h00012083; rom[132] = 32'h00810113; rom[133] = 32'h00200073; @@ -194,928 +194,928 @@ rom[191] = 32'h00000013; rom[192] = 32'h00200073; rom[193] = 32'h00000793; - rom[194] = 32'h59C00713; + rom[194] = 32'h5A400713; rom[195] = 32'h00E7E463; rom[196] = 32'h00008067; rom[197] = 32'h0007A023; rom[198] = 32'h00478793; rom[199] = 32'hFF1FF06F; - rom[200] = 32'h0055D793; - rom[201] = 32'h00279793; - rom[202] = 32'h00F50533; - rom[203] = 32'h00052503; - rom[204] = 32'h00B55533; - rom[205] = 32'h00157513; - rom[206] = 32'h00008067; - rom[207] = 32'h0055D793; - rom[208] = 32'h00279793; - rom[209] = 32'h00F50533; - rom[210] = 32'h00100793; - rom[211] = 32'h00B797B3; - rom[212] = 32'h00052583; - rom[213] = 32'h00F5E5B3; - rom[214] = 32'h00B52023; - rom[215] = 32'h00008067; - rom[216] = 32'h41802783; - rom[217] = 32'h41402703; - rom[218] = 32'h01F7F793; - rom[219] = 32'h00879793; - rom[220] = 32'h01F77713; - rom[221] = 32'h00E7E7B3; - rom[222] = 32'h00001737; - rom[223] = 32'h14F72223; - rom[224] = 32'h00008067; - rom[225] = 32'h41402783; - rom[226] = 32'h00F585B3; - rom[227] = 32'h01C00793; - rom[228] = 32'h00B7D463; - rom[229] = 32'h00078593; - rom[230] = 32'h00B00793; - rom[231] = 32'h00F5D463; - rom[232] = 32'h00078593; - rom[233] = 32'h41802783; - rom[234] = 32'h00A78533; - rom[235] = 32'h01700793; - rom[236] = 32'h00A7D463; - rom[237] = 32'h00078513; - rom[238] = 32'h00600793; - rom[239] = 32'h00F55463; - rom[240] = 32'h00078513; - rom[241] = 32'h40A02C23; - rom[242] = 32'h40B02A23; - rom[243] = 32'hF95FF06F; - rom[244] = 32'h41402783; - rom[245] = 32'h00F585B3; - rom[246] = 32'h02700793; - rom[247] = 32'h02B7D863; - rom[248] = 32'h00078593; - rom[249] = 32'h41802783; - rom[250] = 32'h00A787B3; - rom[251] = 32'h01D00513; - rom[252] = 32'h00F54863; - rom[253] = 32'hFFF7C513; - rom[254] = 32'h41F55513; - rom[255] = 32'h00A7F533; - rom[256] = 32'h40A02C23; - rom[257] = 32'h40B02A23; - rom[258] = 32'hF59FF06F; - rom[259] = 32'hFFF5C793; - rom[260] = 32'h41F7D793; - rom[261] = 32'h00F5F5B3; - rom[262] = 32'hFCDFF06F; - rom[263] = 32'hFF010113; - rom[264] = 32'h000027B7; - rom[265] = 32'h00112623; - rom[266] = 32'h00812423; - rom[267] = 32'h4B078713; - rom[268] = 32'h00078023; - rom[269] = 32'h00178793; - rom[270] = 32'hFEE79CE3; - rom[271] = 32'h000027B7; - rom[272] = 32'h00002737; - rom[273] = 32'h0FF78793; - rom[274] = 32'h04B00693; - rom[275] = 32'h10B70713; - rom[276] = 32'h00D78023; - rom[277] = 32'h04D78823; - rom[278] = 32'h00278793; - rom[279] = 32'hFEE79AE3; - rom[280] = 32'h000027B7; - rom[281] = 32'h00002737; - rom[282] = 32'h30978793; - rom[283] = 32'h06E00693; - rom[284] = 32'h02F00613; - rom[285] = 32'h30F70713; - rom[286] = 32'h00D78023; - rom[287] = 32'h02C78423; - rom[288] = 32'h04D78823; - rom[289] = 32'h00178793; - rom[290] = 32'hFEE798E3; - rom[291] = 32'h000027B7; - rom[292] = 32'h00002737; - rom[293] = 32'h3CC78793; - rom[294] = 32'h03E00693; - rom[295] = 32'h3DC70713; - rom[296] = 32'h00D78023; - rom[297] = 32'h00178793; - rom[298] = 32'hFEE79CE3; - rom[299] = 32'h00100413; - rom[300] = 32'h000017B7; - rom[301] = 32'h1487A023; - rom[302] = 32'h01400713; - rom[303] = 32'h40E02C23; - rom[304] = 32'h01300713; - rom[305] = 32'h40E02A23; - rom[306] = 32'hE99FF0EF; - rom[307] = 32'h000017B7; - rom[308] = 32'h0087A023; - rom[309] = 32'h00C12083; - rom[310] = 32'h00812403; - rom[311] = 32'h0007A223; - rom[312] = 32'h01010113; - rom[313] = 32'h00008067; - rom[314] = 32'h41802783; - rom[315] = 32'h00F00713; - rom[316] = 32'h00000513; - rom[317] = 32'hFF978793; - rom[318] = 32'h00F76863; - rom[319] = 32'h41402503; - rom[320] = 32'hFF450513; - rom[321] = 32'h01053513; - rom[322] = 32'h00008067; - rom[323] = 32'hFD010113; - rom[324] = 32'h02112623; - rom[325] = 32'h02812423; - rom[326] = 32'h02912223; - rom[327] = 32'h03212023; - rom[328] = 32'h01312E23; - rom[329] = 32'h01412C23; - rom[330] = 32'hFC1FF0EF; - rom[331] = 32'h0A050063; - rom[332] = 32'h41802983; - rom[333] = 32'h41402483; - rom[334] = 32'hFF998593; - rom[335] = 32'h00459593; - rom[336] = 32'hFF448793; - rom[337] = 32'h00F585B3; - rom[338] = 32'h45000513; - rom[339] = 32'h00B12623; - rom[340] = 32'hDD1FF0EF; - rom[341] = 32'h06051C63; - rom[342] = 32'h00C12583; - rom[343] = 32'h43000513; - rom[344] = 32'hDC1FF0EF; - rom[345] = 32'h000027B7; - rom[346] = 32'h00F484B3; - rom[347] = 32'h02800793; - rom[348] = 32'h02F989B3; - rom[349] = 32'h42802403; - rom[350] = 32'h00C12583; - rom[351] = 32'h013484B3; - rom[352] = 32'h06050663; - rom[353] = 32'h0055D793; - rom[354] = 32'h00279793; - rom[355] = 32'h43000913; - rom[356] = 32'h012787B3; - rom[357] = 32'h0007A683; - rom[358] = 32'h00100713; - rom[359] = 32'h00B71733; - rom[360] = 32'hFFF74713; - rom[361] = 32'h00E6F733; - rom[362] = 32'h00E7A023; - rom[363] = 32'hFFF40793; - rom[364] = 32'h42F02423; - rom[365] = 32'h07900713; - rom[366] = 32'h00E48023; - rom[367] = 32'h02800713; - rom[368] = 32'h40F707B3; - rom[369] = 32'h00001737; - rom[370] = 32'h00F72023; - rom[371] = 32'h02C12083; - rom[372] = 32'h02812403; - rom[373] = 32'h02412483; - rom[374] = 32'h02012903; - rom[375] = 32'h01C12983; - rom[376] = 32'h01812A03; - rom[377] = 32'h03010113; - rom[378] = 32'h00008067; - rom[379] = 32'h43000513; - rom[380] = 32'hD4DFF0EF; - rom[381] = 32'h00140793; - rom[382] = 32'h42F02423; - rom[383] = 32'h06A00713; - rom[384] = 32'hFB9FF06F; - rom[385] = 32'hFA010113; - rom[386] = 32'h04912A23; - rom[387] = 32'h00855713; - rom[388] = 32'h01055793; - rom[389] = 32'h0FF57493; - rom[390] = 32'h04112E23; - rom[391] = 32'h04812C23; - rom[392] = 32'h05212823; - rom[393] = 32'h05312623; - rom[394] = 32'h05412423; - rom[395] = 32'h05512223; - rom[396] = 32'h05612023; - rom[397] = 32'h03712E23; - rom[398] = 32'h03812C23; - rom[399] = 32'h03912A23; - rom[400] = 32'h03A12823; - rom[401] = 32'h03B12623; - rom[402] = 32'h08057513; - rom[403] = 32'h00050463; - rom[404] = 32'hF0048493; - rom[405] = 32'h0FF77413; - rom[406] = 32'h08077713; - rom[407] = 32'h00070463; - rom[408] = 32'hF0040413; - rom[409] = 32'h00001737; - rom[410] = 32'h11072703; - rom[411] = 32'h0017F693; - rom[412] = 32'h4A068663; - rom[413] = 32'h41802403; - rom[414] = 32'h00802783; - rom[415] = 32'h06079463; - rom[416] = 32'h01400793; - rom[417] = 32'h02F41263; - rom[418] = 32'h41402783; - rom[419] = 32'h00500713; - rom[420] = 32'hFEF78793; - rom[421] = 32'h00F76A63; - rom[422] = 32'h00100793; - rom[423] = 32'h00F02423; - rom[424] = 32'h00001737; - rom[425] = 32'h12F72023; - rom[426] = 32'h05C12083; - rom[427] = 32'h05812403; - rom[428] = 32'h05412483; - rom[429] = 32'h05012903; - rom[430] = 32'h04C12983; - rom[431] = 32'h04812A03; - rom[432] = 32'h04412A83; - rom[433] = 32'h04012B03; - rom[434] = 32'h03C12B83; - rom[435] = 32'h03812C03; - rom[436] = 32'h03412C83; - rom[437] = 32'h03012D03; - rom[438] = 32'h02C12D83; - rom[439] = 32'h06010113; - rom[440] = 32'h00008067; - rom[441] = 32'h00600793; - rom[442] = 32'h00F41E63; - rom[443] = 32'h41402683; - rom[444] = 32'h00B00793; - rom[445] = 32'h00F69863; - rom[446] = 32'h00100713; - rom[447] = 32'h00E02223; - rom[448] = 32'hFA9FF06F; - rom[449] = 32'h00977793; - rom[450] = 32'h04078063; - rom[451] = 32'h05812403; - rom[452] = 32'h05C12083; - rom[453] = 32'h05412483; - rom[454] = 32'h05012903; - rom[455] = 32'h04C12983; - rom[456] = 32'h04812A03; - rom[457] = 32'h04412A83; - rom[458] = 32'h04012B03; - rom[459] = 32'h03C12B83; - rom[460] = 32'h03812C03; - rom[461] = 32'h03412C83; - rom[462] = 32'h03012D03; - rom[463] = 32'h02C12D83; - rom[464] = 32'h06010113; - rom[465] = 32'hDC9FF06F; - rom[466] = 32'hDA1FF0EF; - rom[467] = 32'h00050493; - rom[468] = 32'hF4050CE3; - rom[469] = 32'h41402783; - rom[470] = 32'hFF940413; - rom[471] = 32'h00441413; - rom[472] = 32'hFF478793; - rom[473] = 32'h00F40433; - rom[474] = 32'h00040593; - rom[475] = 32'h43000513; - rom[476] = 32'hBB1FF0EF; - rom[477] = 32'hF2051AE3; - rom[478] = 32'h42002D03; - rom[479] = 32'h080D1A63; - rom[480] = 32'h00445B13; - rom[481] = 32'h41C659B7; - rom[482] = 32'h00003A37; - rom[483] = 32'h47000793; - rom[484] = 32'h00F47B93; - rom[485] = 32'hE6D98993; - rom[486] = 32'h039A0A13; - rom[487] = 32'h00F12023; - rom[488] = 32'h02800C13; - rom[489] = 32'h001B0C93; - rom[490] = 32'h41C02783; - rom[491] = 32'h033787B3; - rom[492] = 32'h014787B3; - rom[493] = 32'h40F02E23; - rom[494] = 32'h0107D793; - rom[495] = 32'h0FF7F593; - rom[496] = 32'h0045D713; - rom[497] = 32'h00170693; - rom[498] = 32'h0166EE63; - rom[499] = 32'h00ECEC63; - rom[500] = 32'h00F7F793; - rom[501] = 32'h00178713; - rom[502] = 32'h01776663; - rom[503] = 32'h001B8713; - rom[504] = 32'hFCF774E3; - rom[505] = 32'h00012503; - rom[506] = 32'h00B12223; - rom[507] = 32'hB35FF0EF; - rom[508] = 32'hFA051CE3; - rom[509] = 32'h00412583; - rom[510] = 32'h00012503; - rom[511] = 32'h001D0D13; - rom[512] = 32'hB3DFF0EF; - rom[513] = 32'hFB8D12E3; - rom[514] = 32'h00100793; - rom[515] = 32'h42F02023; - rom[516] = 32'h00040593; - rom[517] = 32'h45000513; - rom[518] = 32'hB09FF0EF; - rom[519] = 32'hE80516E3; - rom[520] = 32'h00040593; - rom[521] = 32'h43000513; - rom[522] = 32'hAF9FF0EF; - rom[523] = 32'h00050A93; - rom[524] = 32'hE6051CE3; - rom[525] = 32'h00040593; - rom[526] = 32'h47000513; - rom[527] = 32'hAE5FF0EF; - rom[528] = 32'h00050993; - rom[529] = 32'h0A050463; - rom[530] = 32'h00445493; - rom[531] = 32'h02800B13; - rom[532] = 32'h00748493; - rom[533] = 32'h036484B3; - rom[534] = 32'h000029B7; - rom[535] = 32'h00C98993; - rom[536] = 32'h00F47793; - rom[537] = 32'h013787B3; - rom[538] = 32'h47000A13; - rom[539] = 32'h43000913; - rom[540] = 32'h04B00C13; - rom[541] = 32'h04C00C93; - rom[542] = 32'h10000B93; - rom[543] = 32'h00F484B3; - rom[544] = 32'h000A8593; - rom[545] = 32'h000A0513; - rom[546] = 32'hA99FF0EF; - rom[547] = 32'h00050663; - rom[548] = 32'h03541663; - rom[549] = 32'h01948023; - rom[550] = 32'h001A8A93; - rom[551] = 32'hFF7A92E3; - rom[552] = 32'h0000E7B7; - rom[553] = 32'h00001737; - rom[554] = 32'hEAD78793; - rom[555] = 32'h00F72023; + rom[200] = 32'h00151513; + rom[201] = 32'h000027B7; + rom[202] = 32'h00F507B3; + rom[203] = 32'h03F5F593; + rom[204] = 32'h00B78023; + rom[205] = 32'h000027B7; + rom[206] = 32'h00178793; + rom[207] = 32'h00F50533; + rom[208] = 32'h00C50023; + rom[209] = 32'h00008067; + rom[210] = 32'h0055D793; + rom[211] = 32'h00279793; + rom[212] = 32'h00F50533; + rom[213] = 32'h00052503; + rom[214] = 32'h00B55533; + rom[215] = 32'h00157513; + rom[216] = 32'h00008067; + rom[217] = 32'h0055D793; + rom[218] = 32'h00279793; + rom[219] = 32'h00F50533; + rom[220] = 32'h00100793; + rom[221] = 32'h00B797B3; + rom[222] = 32'h00052583; + rom[223] = 32'h00F5E5B3; + rom[224] = 32'h00B52023; + rom[225] = 32'h00008067; + rom[226] = 32'h02800793; + rom[227] = 32'h00750513; + rom[228] = 32'h02F50533; + rom[229] = 32'h00C58793; + rom[230] = 32'h00060593; + rom[231] = 32'h00068613; + rom[232] = 32'h00F50533; + rom[233] = 32'hF7DFF06F; + rom[234] = 32'hFE010113; + rom[235] = 32'h00812C23; + rom[236] = 32'h00112E23; + rom[237] = 32'h00000513; + rom[238] = 32'h4B000413; + rom[239] = 32'h00000613; + rom[240] = 32'h00000593; + rom[241] = 32'h00A12623; + rom[242] = 32'hF59FF0EF; + rom[243] = 32'h00C12503; + rom[244] = 32'h00150513; + rom[245] = 32'hFE8514E3; + rom[246] = 32'h01C12083; + rom[247] = 32'h01812403; + rom[248] = 32'h02010113; + rom[249] = 32'h00008067; + rom[250] = 32'h41802783; + rom[251] = 32'h41402703; + rom[252] = 32'h01F7F793; + rom[253] = 32'h00879793; + rom[254] = 32'h01F77713; + rom[255] = 32'h00E7E7B3; + rom[256] = 32'h00001737; + rom[257] = 32'h14F72223; + rom[258] = 32'h00008067; + rom[259] = 32'h41402783; + rom[260] = 32'h00F585B3; + rom[261] = 32'h01C00793; + rom[262] = 32'h00B7D463; + rom[263] = 32'h00078593; + rom[264] = 32'h00B00793; + rom[265] = 32'h00F5D463; + rom[266] = 32'h00078593; + rom[267] = 32'h41802783; + rom[268] = 32'h00A78533; + rom[269] = 32'h01700793; + rom[270] = 32'h00A7D463; + rom[271] = 32'h00078513; + rom[272] = 32'h00600793; + rom[273] = 32'h00F55463; + rom[274] = 32'h00078513; + rom[275] = 32'h40A02C23; + rom[276] = 32'h40B02A23; + rom[277] = 32'hF95FF06F; + rom[278] = 32'h41402783; + rom[279] = 32'h00F585B3; + rom[280] = 32'h02700793; + rom[281] = 32'h02B7D863; + rom[282] = 32'h00078593; + rom[283] = 32'h41802783; + rom[284] = 32'h00A787B3; + rom[285] = 32'h01D00513; + rom[286] = 32'h00F54863; + rom[287] = 32'hFFF7C513; + rom[288] = 32'h41F55513; + rom[289] = 32'h00A7F533; + rom[290] = 32'h40A02C23; + rom[291] = 32'h40B02A23; + rom[292] = 32'hF59FF06F; + rom[293] = 32'hFFF5C793; + rom[294] = 32'h41F7D793; + rom[295] = 32'h00F5F5B3; + rom[296] = 32'hFCDFF06F; + rom[297] = 32'h41802783; + rom[298] = 32'h00F00713; + rom[299] = 32'h00000513; + rom[300] = 32'hFF978793; + rom[301] = 32'h00F76863; + rom[302] = 32'h41402503; + rom[303] = 32'hFF450513; + rom[304] = 32'h01053513; + rom[305] = 32'h00008067; + rom[306] = 32'hFF010113; + rom[307] = 32'h00812423; + rom[308] = 32'h00912223; + rom[309] = 32'h00112623; + rom[310] = 32'hED1FF0EF; + rom[311] = 32'h000027B7; + rom[312] = 32'h01C00593; + rom[313] = 32'h20B78223; + rom[314] = 32'h00078713; + rom[315] = 32'h00400793; + rom[316] = 32'h20F702A3; + rom[317] = 32'h01800693; + rom[318] = 32'h20D70323; + rom[319] = 32'h20F703A3; + rom[320] = 32'h01D00613; + rom[321] = 32'h20C70423; + rom[322] = 32'h20F704A3; + rom[323] = 32'h00070693; + rom[324] = 32'h01400713; + rom[325] = 32'h20E68523; + rom[326] = 32'h20F685A3; + rom[327] = 32'h02200513; + rom[328] = 32'h20A68623; + rom[329] = 32'h20F686A3; + rom[330] = 32'h42002783; + rom[331] = 32'h00002837; + rom[332] = 32'h48E80223; + rom[333] = 32'h00F037B3; + rom[334] = 32'h00678793; + rom[335] = 32'h48F802A3; + rom[336] = 32'h01000713; + rom[337] = 32'h48E80323; + rom[338] = 32'h48F803A3; + rom[339] = 32'h48A80423; + rom[340] = 32'h48F804A3; + rom[341] = 32'h00080513; + rom[342] = 32'h02800813; + rom[343] = 32'h49050523; + rom[344] = 32'h48F505A3; + rom[345] = 32'h42002783; + rom[346] = 32'h52C50023; + rom[347] = 32'h00050613; + rom[348] = 32'hFFF78793; + rom[349] = 32'h00F037B3; + rom[350] = 32'h00678793; + rom[351] = 32'h52F500A3; + rom[352] = 32'h01E00513; + rom[353] = 32'h52A60123; + rom[354] = 32'h52F601A3; + rom[355] = 32'h00060513; + rom[356] = 32'h02100613; + rom[357] = 32'h52C50223; + rom[358] = 32'h52F502A3; + rom[359] = 32'h52B50323; + rom[360] = 32'h52F503A3; + rom[361] = 32'h52E50423; + rom[362] = 32'h00050593; + rom[363] = 32'h52F504A3; + rom[364] = 32'h01B00513; + rom[365] = 32'h52A58523; + rom[366] = 32'h52F585A3; + rom[367] = 32'h42002783; + rom[368] = 32'h00058693; + rom[369] = 32'h01700593; + rom[370] = 32'hFFE78793; + rom[371] = 32'h00F037B3; + rom[372] = 32'h5CB68223; + rom[373] = 32'h00678793; + rom[374] = 32'h5CF682A3; + rom[375] = 32'h5CE68323; + rom[376] = 32'h5CF683A3; + rom[377] = 32'h5CC68423; + rom[378] = 32'h00068713; + rom[379] = 32'h5CF684A3; + rom[380] = 32'h01300693; + rom[381] = 32'h5CD70523; + rom[382] = 32'h5CF705A3; + rom[383] = 32'h30900413; + rom[384] = 32'h30F00493; + rom[385] = 32'h00040513; + rom[386] = 32'h00600613; + rom[387] = 32'h00E00593; + rom[388] = 32'hD11FF0EF; + rom[389] = 32'h02840513; + rom[390] = 32'h00200613; + rom[391] = 32'h00F00593; + rom[392] = 32'hD01FF0EF; + rom[393] = 32'h05040513; + rom[394] = 32'h00600613; + rom[395] = 32'h00E00593; + rom[396] = 32'h00140413; + rom[397] = 32'hCEDFF0EF; + rom[398] = 32'hFC9416E3; + rom[399] = 32'h000027B7; + rom[400] = 32'h02200713; + rom[401] = 32'h66E78123; + rom[402] = 32'h660781A3; + rom[403] = 32'h00078713; + rom[404] = 32'h02300793; + rom[405] = 32'h66F70223; + rom[406] = 32'h660702A3; + rom[407] = 32'h01000693; + rom[408] = 32'h66D70323; + rom[409] = 32'h660703A3; + rom[410] = 32'h02100693; + rom[411] = 32'h66D70423; + rom[412] = 32'h660704A3; + rom[413] = 32'h66F70523; + rom[414] = 32'h660705A3; + rom[415] = 32'h3CC00413; + rom[416] = 32'h3DC00493; + rom[417] = 32'h00040513; + rom[418] = 32'h00300613; + rom[419] = 32'h00E00593; + rom[420] = 32'h00140413; + rom[421] = 32'hC8DFF0EF; + rom[422] = 32'hFE9416E3; + rom[423] = 32'h00100413; + rom[424] = 32'h000017B7; + rom[425] = 32'h1487A023; + rom[426] = 32'h01400713; + rom[427] = 32'h40E02C23; + rom[428] = 32'h01300713; + rom[429] = 32'h40E02A23; + rom[430] = 32'hD31FF0EF; + rom[431] = 32'h000017B7; + rom[432] = 32'h0087A023; + rom[433] = 32'h00C12083; + rom[434] = 32'h00812403; + rom[435] = 32'h0007A223; + rom[436] = 32'h00412483; + rom[437] = 32'h01010113; + rom[438] = 32'h00008067; + rom[439] = 32'hFD010113; + rom[440] = 32'h02112623; + rom[441] = 32'h02812423; + rom[442] = 32'h02912223; + rom[443] = 32'h03212023; + rom[444] = 32'h01312E23; + rom[445] = 32'h01412C23; + rom[446] = 32'hDADFF0EF; + rom[447] = 32'h08050C63; + rom[448] = 32'h41802483; + rom[449] = 32'h41402903; + rom[450] = 32'hFF948493; + rom[451] = 32'h00449593; + rom[452] = 32'hFF490913; + rom[453] = 32'h012585B3; + rom[454] = 32'h45800513; + rom[455] = 32'h00B12623; + rom[456] = 32'hC29FF0EF; + rom[457] = 32'h06051863; + rom[458] = 32'h00C12583; + rom[459] = 32'h43800513; + rom[460] = 32'hC19FF0EF; + rom[461] = 32'h43002403; + rom[462] = 32'h00C12583; + rom[463] = 32'h06050C63; + rom[464] = 32'h0055D793; + rom[465] = 32'h00279793; + rom[466] = 32'h43800993; + rom[467] = 32'h013787B3; + rom[468] = 32'h0007A683; + rom[469] = 32'h00100713; + rom[470] = 32'h00B71733; + rom[471] = 32'hFFF74713; + rom[472] = 32'h00E6F733; + rom[473] = 32'hFFF40413; + rom[474] = 32'h00E7A023; + rom[475] = 32'h42802823; + rom[476] = 32'h00700693; + rom[477] = 32'h00900613; + rom[478] = 32'h00090593; + rom[479] = 32'h00048513; + rom[480] = 32'hC09FF0EF; + rom[481] = 32'h42402783; + rom[482] = 32'h00001737; + rom[483] = 32'h408787B3; + rom[484] = 32'h00F72023; + rom[485] = 32'h02C12083; + rom[486] = 32'h02812403; + rom[487] = 32'h02412483; + rom[488] = 32'h02012903; + rom[489] = 32'h01C12983; + rom[490] = 32'h01812A03; + rom[491] = 32'h03010113; + rom[492] = 32'h00008067; + rom[493] = 32'h43800513; + rom[494] = 32'hBADFF0EF; + rom[495] = 32'h00140413; + rom[496] = 32'h42802823; + rom[497] = 32'h00600693; + rom[498] = 32'h00A00613; + rom[499] = 32'hFADFF06F; + rom[500] = 32'hFA010113; + rom[501] = 32'h04912A23; + rom[502] = 32'h00855713; + rom[503] = 32'h01055793; + rom[504] = 32'h0FF57493; + rom[505] = 32'h04112E23; + rom[506] = 32'h04812C23; + rom[507] = 32'h05212823; + rom[508] = 32'h05312623; + rom[509] = 32'h05412423; + rom[510] = 32'h05512223; + rom[511] = 32'h05612023; + rom[512] = 32'h03712E23; + rom[513] = 32'h03812C23; + rom[514] = 32'h03912A23; + rom[515] = 32'h03A12823; + rom[516] = 32'h03B12623; + rom[517] = 32'h08057513; + rom[518] = 32'h00050463; + rom[519] = 32'hF0048493; + rom[520] = 32'h0FF77413; + rom[521] = 32'h08077713; + rom[522] = 32'h00070463; + rom[523] = 32'hF0040413; + rom[524] = 32'h00001737; + rom[525] = 32'h11072703; + rom[526] = 32'h0017F693; + rom[527] = 32'h4E068263; + rom[528] = 32'h41802403; + rom[529] = 32'h00802783; + rom[530] = 32'h0E079A63; + rom[531] = 32'h00E00793; + rom[532] = 32'h04F41263; + rom[533] = 32'h42002023; + rom[534] = 32'h05812403; + rom[535] = 32'h05C12083; + rom[536] = 32'h05412483; + rom[537] = 32'h05012903; + rom[538] = 32'h04C12983; + rom[539] = 32'h04812A03; + rom[540] = 32'h04412A83; + rom[541] = 32'h04012B03; + rom[542] = 32'h03C12B83; + rom[543] = 32'h03812C03; + rom[544] = 32'h03412C83; + rom[545] = 32'h03012D03; + rom[546] = 32'h02C12D83; + rom[547] = 32'h06010113; + rom[548] = 32'hC39FF06F; + rom[549] = 32'h01000793; + rom[550] = 32'h00F41863; + rom[551] = 32'h00100713; + rom[552] = 32'h42E02023; + rom[553] = 32'hFB5FF06F; + rom[554] = 32'h01200793; + rom[555] = 32'h00F41663; rom[556] = 32'h00200713; - rom[557] = 32'h42E02223; - rom[558] = 32'hDF1FF06F; - rom[559] = 32'h000A8593; - rom[560] = 32'h00090513; - rom[561] = 32'hA5DFF0EF; - rom[562] = 32'hFC0518E3; - rom[563] = 32'h004AD793; - rom[564] = 32'h00778793; - rom[565] = 32'h036787B3; - rom[566] = 32'h00FAF713; - rom[567] = 32'h01370733; - rom[568] = 32'h00E787B3; - rom[569] = 32'h01878023; - rom[570] = 32'hFB1FF06F; - rom[571] = 32'h00C00A93; - rom[572] = 32'h45000793; - rom[573] = 32'h008AA023; - rom[574] = 32'h000A8C13; - rom[575] = 32'h00000B93; - rom[576] = 32'h00F12023; - rom[577] = 32'h0FF00D13; - rom[578] = 32'h000C2903; - rom[579] = 32'h00012503; - rom[580] = 32'h001B8B93; - rom[581] = 32'h00090593; - rom[582] = 32'hA09FF0EF; - rom[583] = 32'h00050413; - rom[584] = 32'h18051263; - rom[585] = 32'h00012503; - rom[586] = 32'h42C02D83; - rom[587] = 32'h00090593; - rom[588] = 32'hA0DFF0EF; - rom[589] = 32'h00495713; - rom[590] = 32'h001D8D93; - rom[591] = 32'h43B02623; - rom[592] = 32'h00170893; - rom[593] = 32'h00E03DB3; - rom[594] = 32'h00F00793; - rom[595] = 32'h00F97913; - rom[596] = 32'h41B70DB3; - rom[597] = 32'h0117F463; - rom[598] = 32'h00078893; - rom[599] = 32'h01203833; - rom[600] = 32'h00190313; - rom[601] = 32'h00F00793; - rom[602] = 32'h41090B33; - rom[603] = 32'h0067F463; - rom[604] = 32'h00078313; - rom[605] = 32'h000D8693; - rom[606] = 32'h06D8EA63; - rom[607] = 32'h40D70E33; - rom[608] = 32'h00469613; - rom[609] = 32'h000B0793; - rom[610] = 32'h0580006F; - rom[611] = 32'h00F91463; - rom[612] = 32'h040E0663; - rom[613] = 32'h00F605B3; - rom[614] = 32'h00F12423; - rom[615] = 32'h47000513; - rom[616] = 32'h01C12E23; - rom[617] = 32'h00D12C23; - rom[618] = 32'h00612A23; - rom[619] = 32'h01112823; - rom[620] = 32'h00E12623; - rom[621] = 32'h00C12223; - rom[622] = 32'h969FF0EF; - rom[623] = 32'h01C12E03; - rom[624] = 32'h01812683; - rom[625] = 32'h01412303; - rom[626] = 32'h01012883; - rom[627] = 32'h00C12703; - rom[628] = 32'h00812783; - rom[629] = 32'h00412603; - rom[630] = 32'h00A40433; - rom[631] = 32'h00178793; - rom[632] = 32'hFAF376E3; - rom[633] = 32'h00168693; - rom[634] = 32'hF91FF06F; - rom[635] = 32'h00100693; - rom[636] = 32'h00040793; - rom[637] = 32'h04D40063; - rom[638] = 32'h00200693; - rom[639] = 32'h02D40C63; - rom[640] = 32'h00400693; - rom[641] = 32'h00300613; - rom[642] = 32'h00068793; - rom[643] = 32'h02C40463; - rom[644] = 32'h00500593; - rom[645] = 32'h00058793; - rom[646] = 32'h00D40E63; - rom[647] = 32'h00600693; - rom[648] = 32'h00068793; - rom[649] = 32'h00B40863; - rom[650] = 32'h00060793; - rom[651] = 32'h00D40463; - rom[652] = 32'h00700793; - rom[653] = 32'h02800613; - rom[654] = 32'h00770693; - rom[655] = 32'h02C686B3; - rom[656] = 32'h00002637; - rom[657] = 32'h00C60613; - rom[658] = 32'h00C90633; - rom[659] = 32'h00479793; - rom[660] = 32'h0087E7B3; - rom[661] = 32'h00C686B3; - rom[662] = 32'h00F68023; - rom[663] = 32'h04041463; - rom[664] = 32'h05B8E263; - rom[665] = 32'h40ED85B3; - rom[666] = 32'h004D9613; - rom[667] = 32'h000B0793; - rom[668] = 32'h0280006F; - rom[669] = 32'h01279463; - rom[670] = 32'h00058E63; - rom[671] = 32'h009D6C63; - rom[672] = 32'h00249693; - rom[673] = 32'h00DA86B3; - rom[674] = 32'h00F60533; - rom[675] = 32'h00A6A023; - rom[676] = 32'h00148493; - rom[677] = 32'h00178793; - rom[678] = 32'hFCF37EE3; - rom[679] = 32'h001D8D93; - rom[680] = 32'hFC1FF06F; - rom[681] = 32'h004C0C13; - rom[682] = 32'hE69BE0E3; - rom[683] = 32'h42C02703; - rom[684] = 32'h0D800793; - rom[685] = 32'hBEF71AE3; - rom[686] = 32'h00002437; - rom[687] = 32'h47000A13; - rom[688] = 32'h02800913; - rom[689] = 32'h00C40413; - rom[690] = 32'h06A00A93; - rom[691] = 32'h10000493; - rom[692] = 32'h00098593; - rom[693] = 32'h000A0513; - rom[694] = 32'h849FF0EF; - rom[695] = 32'h02050063; - rom[696] = 32'h0049D793; - rom[697] = 32'h00778793; - rom[698] = 32'h032787B3; - rom[699] = 32'h00F9F713; - rom[700] = 32'h00870733; - rom[701] = 32'h00E787B3; - rom[702] = 32'h01578023; - rom[703] = 32'h00198993; - rom[704] = 32'hFC9998E3; - rom[705] = 32'h0000F7B7; - rom[706] = 32'h00001737; - rom[707] = 32'h00D78793; - rom[708] = 32'h00F72023; - rom[709] = 32'h00100713; - rom[710] = 32'hD9DFF06F; - rom[711] = 32'h0027F793; - rom[712] = 32'h00078863; - rom[713] = 32'h00802783; - rom[714] = 32'hB80780E3; - rom[715] = 32'hBE1FF06F; - rom[716] = 32'h41002783; - rom[717] = 32'h00700A13; - rom[718] = 32'h00F484B3; - rom[719] = 32'h40C02783; - rom[720] = 32'h40902823; - rom[721] = 32'h00F40433; - rom[722] = 32'h40802623; - rom[723] = 32'h029A4E63; - rom[724] = 32'hFF900A13; - rom[725] = 32'h0544CE63; - rom[726] = 32'h00700493; - rom[727] = 32'h0684CE63; - rom[728] = 32'hFF900493; - rom[729] = 32'hB49452E3; - rom[730] = 32'h00802783; - rom[731] = 32'h00000593; - rom[732] = 32'hFFF00513; - rom[733] = 32'h08078663; - rom[734] = 32'h80DFF0EF; - rom[735] = 32'h00840413; - rom[736] = 32'h40802623; - rom[737] = 32'hFE1FF06F; - rom[738] = 32'h00802783; - rom[739] = 32'h00100593; - rom[740] = 32'h00000513; - rom[741] = 32'h00078A63; - rom[742] = 32'hFECFF0EF; - rom[743] = 32'hFF848493; - rom[744] = 32'h40902823; - rom[745] = 32'hFA9FF06F; - rom[746] = 32'h829FF0EF; - rom[747] = 32'hFF1FF06F; - rom[748] = 32'h00802783; - rom[749] = 32'hFFF00593; - rom[750] = 32'h00000513; - rom[751] = 32'h00078A63; - rom[752] = 32'hFC4FF0EF; - rom[753] = 32'h00848493; - rom[754] = 32'h40902823; - rom[755] = 32'hF89FF06F; - rom[756] = 32'h801FF0EF; - rom[757] = 32'hFF1FF06F; - rom[758] = 32'h00802783; - rom[759] = 32'h00000593; - rom[760] = 32'h00100513; - rom[761] = 32'h00078A63; - rom[762] = 32'hF9CFF0EF; - rom[763] = 32'hFF840413; - rom[764] = 32'h40802623; - rom[765] = 32'hF69FF06F; - rom[766] = 32'hFD8FF0EF; - rom[767] = 32'hFF1FF06F; - rom[768] = 32'hFD0FF0EF; - rom[769] = 32'hF79FF06F; - rom[770] = 32'hFE010113; - rom[771] = 32'h00112E23; - rom[772] = 32'h00812C23; - rom[773] = 32'h00912A23; - rom[774] = 32'h01212823; - rom[775] = 32'h01312623; - rom[776] = 32'h01412423; - rom[777] = 32'h01512223; - rom[778] = 32'h01612023; - rom[779] = 32'h00000793; - rom[780] = 32'h47000613; - rom[781] = 32'h45000693; - rom[782] = 32'h43000713; - rom[783] = 32'h02000593; - rom[784] = 32'h00C78533; - rom[785] = 32'h00052023; - rom[786] = 32'h00D78533; - rom[787] = 32'h00052023; - rom[788] = 32'h00E78533; - rom[789] = 32'h00052023; - rom[790] = 32'h00478793; - rom[791] = 32'hFEB792E3; - rom[792] = 32'h42002623; - rom[793] = 32'h42002423; - rom[794] = 32'h42002023; - rom[795] = 32'h40002823; - rom[796] = 32'h00F00713; - rom[797] = 32'h40002623; - rom[798] = 32'h40E02C23; - rom[799] = 32'h01400713; - rom[800] = 32'h40E02A23; - rom[801] = 32'h000027B7; - rom[802] = 32'h42002223; - rom[803] = 32'h00002223; - rom[804] = 32'h4B078713; - rom[805] = 32'h00078023; - rom[806] = 32'h00178793; - rom[807] = 32'hFEE79CE3; - rom[808] = 32'h000027B7; - rom[809] = 32'h00002737; - rom[810] = 32'h0FB78793; - rom[811] = 32'h03F00693; - rom[812] = 32'h10D70713; - rom[813] = 32'h00D78023; - rom[814] = 32'h2AD78423; - rom[815] = 32'h00178793; - rom[816] = 32'hFEE79AE3; - rom[817] = 32'h000027B7; - rom[818] = 32'h00002737; - rom[819] = 32'h0FB78793; - rom[820] = 32'h03F00693; - rom[821] = 32'h3CB70713; - rom[822] = 32'h00D78023; - rom[823] = 32'h00D788A3; - rom[824] = 32'h02878793; - rom[825] = 32'hFEE79AE3; - rom[826] = 32'h000027B7; - rom[827] = 32'h000026B7; - rom[828] = 32'h12478793; - rom[829] = 32'h07900613; - rom[830] = 32'h01000593; - rom[831] = 32'h3A468693; - rom[832] = 32'h00000713; - rom[833] = 32'h00E78533; - rom[834] = 32'h00C50023; - rom[835] = 32'h00170713; - rom[836] = 32'hFEB71AE3; - rom[837] = 32'h02878793; - rom[838] = 32'hFED794E3; - rom[839] = 32'h000027B7; - rom[840] = 32'h06E00713; - rom[841] = 32'h0EE78DA3; - rom[842] = 32'h000017B7; - rom[843] = 32'h01100713; - rom[844] = 32'h14E7A023; - rom[845] = 32'hE2CFF0EF; - rom[846] = 32'h00001737; - rom[847] = 32'h02800793; - rom[848] = 32'h00F72023; - rom[849] = 32'h00F72223; - rom[850] = 32'h11870993; - rom[851] = 32'h49C00A13; - rom[852] = 32'h00100B13; - rom[853] = 32'h00402783; - rom[854] = 32'h02078C63; - rom[855] = 32'h01812403; - rom[856] = 32'h000017B7; - rom[857] = 32'h1207A023; - rom[858] = 32'h01C12083; - rom[859] = 32'h01412483; - rom[860] = 32'h01012903; - rom[861] = 32'h00C12983; - rom[862] = 32'h00812A03; - rom[863] = 32'h00412A83; - rom[864] = 32'h00012B03; - rom[865] = 32'h00002423; - rom[866] = 32'h02010113; - rom[867] = 32'hE90FF06F; - rom[868] = 32'h49802683; - rom[869] = 32'h49402783; - rom[870] = 32'h42402703; - rom[871] = 32'h04F68063; - rom[872] = 32'h49802783; - rom[873] = 32'h00279793; - rom[874] = 32'h00FA07B3; - rom[875] = 32'h0007A503; - rom[876] = 32'h49802783; - rom[877] = 32'h00178793; - rom[878] = 32'h03F7F793; - rom[879] = 32'h48F02C23; - rom[880] = 32'h00071663; - rom[881] = 32'h841FF0EF; - rom[882] = 32'hF8DFF06F; - rom[883] = 32'h00F51793; - rom[884] = 32'hF807D2E3; - rom[885] = 32'h01602223; - rom[886] = 32'hF7DFF06F; - rom[887] = 32'hF6070CE3; - rom[888] = 32'h0009A783; - rom[889] = 32'h01F7F793; - rom[890] = 32'hF60796E3; - rom[891] = 32'h00002783; - rom[892] = 32'h0017C613; - rom[893] = 32'h00C02023; - rom[894] = 32'h00100693; - rom[895] = 32'h02D78263; - rom[896] = 32'h00400793; - rom[897] = 32'h00D71463; - rom[898] = 32'h00200793; - rom[899] = 32'h00479793; - rom[900] = 32'h0017E793; - rom[901] = 32'h00001737; - rom[902] = 32'h14F72023; - rom[903] = 32'hF39FF06F; - rom[904] = 32'h000017B7; - rom[905] = 32'h01100713; - rom[906] = 32'h14E7A023; - rom[907] = 32'hF29FF06F; - rom[908] = 32'hFF010113; - rom[909] = 32'h00112623; - rom[910] = 32'h00812423; - rom[911] = 32'h00912223; - rom[912] = 32'h01212023; - rom[913] = 32'hCC0FF0EF; - rom[914] = 32'h000017B7; - rom[915] = 32'h1147A783; - rom[916] = 32'h0017E793; - rom[917] = 32'h40F02E23; - rom[918] = 32'h000017B7; - rom[919] = 32'h00100713; - rom[920] = 32'h10E7A623; - rom[921] = 32'h1207A023; - rom[922] = 32'h00002423; - rom[923] = 32'hDB0FF0EF; - rom[924] = 32'h49C00493; - rom[925] = 32'h49802703; - rom[926] = 32'h49402783; - rom[927] = 32'hFEF70CE3; - rom[928] = 32'h49802783; - rom[929] = 32'h00279793; - rom[930] = 32'h00F487B3; - rom[931] = 32'h0007A503; - rom[932] = 32'h49802783; - rom[933] = 32'h00178793; - rom[934] = 32'h03F7F793; - rom[935] = 32'h48F02C23; - rom[936] = 32'hF64FF0EF; - rom[937] = 32'hFD1FF06F; - rom[938] = 32'hFD010113; - rom[939] = 32'h03212223; - rom[940] = 32'h03312023; - rom[941] = 32'h01512C23; - rom[942] = 32'h00001937; - rom[943] = 32'h000019B7; - rom[944] = 32'h01412E23; - rom[945] = 32'h01612A23; - rom[946] = 32'h01712823; - rom[947] = 32'h02812623; - rom[948] = 32'h02912423; - rom[949] = 32'h01812623; - rom[950] = 32'h10090913; - rom[951] = 32'h10498993; - rom[952] = 32'h49C00A93; - rom[953] = 32'h00092403; - rom[954] = 32'h00147413; - rom[955] = 32'h02041863; - rom[956] = 32'h02C12403; - rom[957] = 32'h02812483; - rom[958] = 32'h02412903; - rom[959] = 32'h02012983; - rom[960] = 32'h01C12A03; - rom[961] = 32'h01812A83; - rom[962] = 32'h01412B03; - rom[963] = 32'h01012B83; - rom[964] = 32'h00C12C03; - rom[965] = 32'h03010113; - rom[966] = 32'h00008067; - rom[967] = 32'h0009AC03; - rom[968] = 32'h49402403; - rom[969] = 32'h49802483; - rom[970] = 32'h00140413; - rom[971] = 32'h03F47413; - rom[972] = 32'h02848463; - rom[973] = 32'h49402483; - rom[974] = 32'h00249493; - rom[975] = 32'h009A84B3; - rom[976] = 32'h0184A023; - rom[977] = 32'h48802A23; - rom[978] = 32'h00001437; - rom[979] = 32'h00100493; - rom[980] = 32'h10942423; - rom[981] = 32'hF91FF06F; - rom[982] = 32'h49002403; - rom[983] = 32'h00140413; - rom[984] = 32'h48802823; - rom[985] = 32'hFE5FF06F; - rom[986] = 32'h00000013; - rom[987] = 32'h00000013; - rom[988] = 32'h00000013; - rom[989] = 32'h00000013; - rom[990] = 32'h00000013; - rom[991] = 32'h00000013; - rom[992] = 32'h00000013; - rom[993] = 32'h00000013; - rom[994] = 32'h00000013; - rom[995] = 32'h00000013; - rom[996] = 32'h00000013; - rom[997] = 32'h00000013; - rom[998] = 32'h00000013; - rom[999] = 32'h00000013; - rom[1000] = 32'h00000013; - rom[1001] = 32'h00000013; - rom[1002] = 32'h00000013; - rom[1003] = 32'h00000013; - rom[1004] = 32'h00000013; - rom[1005] = 32'h00000013; - rom[1006] = 32'h00000013; - rom[1007] = 32'h00000013; - rom[1008] = 32'h00000013; - rom[1009] = 32'h00000013; - rom[1010] = 32'h00000013; - rom[1011] = 32'h00000013; - rom[1012] = 32'h00000013; - rom[1013] = 32'h00000013; - rom[1014] = 32'h00000013; - rom[1015] = 32'h00000013; - rom[1016] = 32'h00000013; - rom[1017] = 32'h00000013; - rom[1018] = 32'h00000013; - rom[1019] = 32'h00000013; - rom[1020] = 32'h00000013; - rom[1021] = 32'h00000013; - rom[1022] = 32'h00000013; - rom[1023] = 32'h00000013; - rom[1024] = 32'h00000013; - rom[1025] = 32'h00000013; - rom[1026] = 32'h00000013; - rom[1027] = 32'h00000013; - rom[1028] = 32'h00000013; - rom[1029] = 32'h00000013; - rom[1030] = 32'h00000013; - rom[1031] = 32'h00000013; - rom[1032] = 32'h00000013; - rom[1033] = 32'h00000013; - rom[1034] = 32'h00000013; - rom[1035] = 32'h00000013; - rom[1036] = 32'h00000013; - rom[1037] = 32'h00000013; - rom[1038] = 32'h00000013; - rom[1039] = 32'h00000013; - rom[1040] = 32'h00000013; - rom[1041] = 32'h00000013; - rom[1042] = 32'h00000013; - rom[1043] = 32'h00000013; - rom[1044] = 32'h00000013; - rom[1045] = 32'h00000013; - rom[1046] = 32'h00000013; - rom[1047] = 32'h00000013; - rom[1048] = 32'h00000013; - rom[1049] = 32'h00000013; - rom[1050] = 32'h00000013; - rom[1051] = 32'h00000013; - rom[1052] = 32'h00000013; - rom[1053] = 32'h00000013; - rom[1054] = 32'h00000013; - rom[1055] = 32'h00000013; - rom[1056] = 32'h00000013; - rom[1057] = 32'h00000013; - rom[1058] = 32'h00000013; - rom[1059] = 32'h00000013; - rom[1060] = 32'h00000013; - rom[1061] = 32'h00000013; - rom[1062] = 32'h00000013; - rom[1063] = 32'h00000013; - rom[1064] = 32'h00000013; - rom[1065] = 32'h00000013; - rom[1066] = 32'h00000013; - rom[1067] = 32'h00000013; - rom[1068] = 32'h00000013; - rom[1069] = 32'h00000013; - rom[1070] = 32'h00000013; - rom[1071] = 32'h00000013; - rom[1072] = 32'h00000013; - rom[1073] = 32'h00000013; - rom[1074] = 32'h00000013; - rom[1075] = 32'h00000013; - rom[1076] = 32'h00000013; - rom[1077] = 32'h00000013; - rom[1078] = 32'h00000013; - rom[1079] = 32'h00000013; - rom[1080] = 32'h00000013; - rom[1081] = 32'h00000013; - rom[1082] = 32'h00000013; - rom[1083] = 32'h00000013; - rom[1084] = 32'h00000013; - rom[1085] = 32'h00000013; - rom[1086] = 32'h00000013; - rom[1087] = 32'h00000013; - rom[1088] = 32'h00000013; - rom[1089] = 32'h00000013; - rom[1090] = 32'h00000013; - rom[1091] = 32'h00000013; - rom[1092] = 32'h00000013; - rom[1093] = 32'h00000013; - rom[1094] = 32'h00000013; - rom[1095] = 32'h00000013; - rom[1096] = 32'h00000013; - rom[1097] = 32'h00000013; - rom[1098] = 32'h00000013; - rom[1099] = 32'h00000013; - rom[1100] = 32'h00000013; - rom[1101] = 32'h00000013; - rom[1102] = 32'h00000013; - rom[1103] = 32'h00000013; - rom[1104] = 32'h00000013; - rom[1105] = 32'h00000013; - rom[1106] = 32'h00000013; - rom[1107] = 32'h00000013; - rom[1108] = 32'h00000013; - rom[1109] = 32'h00000013; - rom[1110] = 32'h00000013; - rom[1111] = 32'h00000013; - rom[1112] = 32'h00000013; - rom[1113] = 32'h00000013; - rom[1114] = 32'h00000013; - rom[1115] = 32'h00000013; + rom[557] = 32'hFEDFF06F; + rom[558] = 32'h01400793; + rom[559] = 32'h04F41263; + rom[560] = 32'h41402783; + rom[561] = 32'h00500713; + rom[562] = 32'hFEF78793; + rom[563] = 32'h02F76A63; + rom[564] = 32'h00100793; + rom[565] = 32'h00F02423; + rom[566] = 32'h42002783; + rom[567] = 32'h00078A63; + rom[568] = 32'h00200713; + rom[569] = 32'h03C00413; + rom[570] = 32'h00E78463; + rom[571] = 32'h02800413; + rom[572] = 32'h42802223; + rom[573] = 32'h00100713; + rom[574] = 32'h000017B7; + rom[575] = 32'h12E7A023; + rom[576] = 32'h05C12083; + rom[577] = 32'h05812403; + rom[578] = 32'h05412483; + rom[579] = 32'h05012903; + rom[580] = 32'h04C12983; + rom[581] = 32'h04812A03; + rom[582] = 32'h04412A83; + rom[583] = 32'h04012B03; + rom[584] = 32'h03C12B83; + rom[585] = 32'h03812C03; + rom[586] = 32'h03412C83; + rom[587] = 32'h03012D03; + rom[588] = 32'h02C12D83; + rom[589] = 32'h06010113; + rom[590] = 32'h00008067; + rom[591] = 32'h00600793; + rom[592] = 32'h00F41E63; + rom[593] = 32'h41402683; + rom[594] = 32'h00B00793; + rom[595] = 32'h00F69863; + rom[596] = 32'h00100713; + rom[597] = 32'h00E02223; + rom[598] = 32'hFA9FF06F; + rom[599] = 32'h00977793; + rom[600] = 32'h04078063; + rom[601] = 32'h05812403; + rom[602] = 32'h05C12083; + rom[603] = 32'h05412483; + rom[604] = 32'h05012903; + rom[605] = 32'h04C12983; + rom[606] = 32'h04812A03; + rom[607] = 32'h04412A83; + rom[608] = 32'h04012B03; + rom[609] = 32'h03C12B83; + rom[610] = 32'h03812C03; + rom[611] = 32'h03412C83; + rom[612] = 32'h03012D03; + rom[613] = 32'h02C12D83; + rom[614] = 32'h06010113; + rom[615] = 32'hD41FF06F; + rom[616] = 32'hB05FF0EF; + rom[617] = 32'h00050493; + rom[618] = 32'hF4050CE3; + rom[619] = 32'h41402783; + rom[620] = 32'hFF940413; + rom[621] = 32'h00441413; + rom[622] = 32'hFF478793; + rom[623] = 32'h00F40433; + rom[624] = 32'h00040593; + rom[625] = 32'h43800513; + rom[626] = 32'h981FF0EF; + rom[627] = 32'hF2051AE3; + rom[628] = 32'h42802D03; + rom[629] = 32'h020D1C63; + rom[630] = 32'h00445B13; + rom[631] = 32'h41C659B7; + rom[632] = 32'h00003A37; + rom[633] = 32'h47800793; + rom[634] = 32'h00F47B93; + rom[635] = 32'hE6D98993; + rom[636] = 32'h039A0A13; + rom[637] = 32'h00F12423; + rom[638] = 32'h001B0C93; + rom[639] = 32'h42402783; + rom[640] = 32'h0AFD6263; + rom[641] = 32'h00100793; + rom[642] = 32'h42F02423; + rom[643] = 32'h00040593; + rom[644] = 32'h45800513; + rom[645] = 32'h935FF0EF; + rom[646] = 32'hEE0514E3; + rom[647] = 32'h00040593; + rom[648] = 32'h43800513; + rom[649] = 32'h925FF0EF; + rom[650] = 32'h00050993; + rom[651] = 32'hEC051AE3; + rom[652] = 32'h00040593; + rom[653] = 32'h47800513; + rom[654] = 32'h911FF0EF; + rom[655] = 32'h00050A13; + rom[656] = 32'h0E050463; + rom[657] = 32'h47800A93; + rom[658] = 32'h43800913; + rom[659] = 32'h00F47493; + rom[660] = 32'h00445A13; + rom[661] = 32'h00098593; + rom[662] = 32'h000A8513; + rom[663] = 32'h8EDFF0EF; + rom[664] = 32'h00050E63; + rom[665] = 32'h0B341063; + rom[666] = 32'h00400693; + rom[667] = 32'h00C00613; + rom[668] = 32'h00048593; + rom[669] = 32'h000A0513; + rom[670] = 32'h911FF0EF; + rom[671] = 32'h00198993; + rom[672] = 32'h10000793; + rom[673] = 32'hFCF998E3; + rom[674] = 32'h0000E7B7; + rom[675] = 32'h00001737; + rom[676] = 32'hEAD78793; + rom[677] = 32'h00F72023; + rom[678] = 32'h00200713; + rom[679] = 32'h42E02623; + rom[680] = 32'hE61FF06F; + rom[681] = 32'h41C02783; + rom[682] = 32'h033787B3; + rom[683] = 32'h014787B3; + rom[684] = 32'h40F02E23; + rom[685] = 32'h0107D793; + rom[686] = 32'h0FF7F593; + rom[687] = 32'h0045D713; + rom[688] = 32'h00170693; + rom[689] = 32'h0166EE63; + rom[690] = 32'h00ECEC63; + rom[691] = 32'h00F7F793; + rom[692] = 32'h00178713; + rom[693] = 32'h01776663; + rom[694] = 32'h001B8713; + rom[695] = 32'hF2F770E3; + rom[696] = 32'h00812503; + rom[697] = 32'h00B12623; + rom[698] = 32'h861FF0EF; + rom[699] = 32'hF00518E3; + rom[700] = 32'h00C12583; + rom[701] = 32'h00812503; + rom[702] = 32'h001D0D13; + rom[703] = 32'h869FF0EF; + rom[704] = 32'hEFDFF06F; + rom[705] = 32'h00098593; + rom[706] = 32'h00090513; + rom[707] = 32'h83DFF0EF; + rom[708] = 32'hF60516E3; + rom[709] = 32'h00400693; + rom[710] = 32'h00B00613; + rom[711] = 32'h00F9F593; + rom[712] = 32'h0049D513; + rom[713] = 32'hF55FF06F; + rom[714] = 32'h00C00913; + rom[715] = 32'h45800793; + rom[716] = 32'h00892023; + rom[717] = 32'h00090C13; + rom[718] = 32'h00000B93; + rom[719] = 32'h00F12623; + rom[720] = 32'h000C2C83; + rom[721] = 32'h00C12503; + rom[722] = 32'h001B8B93; + rom[723] = 32'h000C8593; + rom[724] = 32'hFF8FF0EF; + rom[725] = 32'h00050413; + rom[726] = 32'h16051263; + rom[727] = 32'h43402D83; + rom[728] = 32'h00C12503; + rom[729] = 32'h000C8593; + rom[730] = 32'h004CDD13; + rom[731] = 32'hFF8FF0EF; + rom[732] = 32'h001D8D93; + rom[733] = 32'h43B02A23; + rom[734] = 32'h01A03733; + rom[735] = 32'h001D0313; + rom[736] = 32'h00F00793; + rom[737] = 32'h00FCFC93; + rom[738] = 32'h40ED09B3; + rom[739] = 32'h0067F463; + rom[740] = 32'h00078313; + rom[741] = 32'h01903B33; + rom[742] = 32'h416C87B3; + rom[743] = 32'h00F12423; + rom[744] = 32'h001C8B13; + rom[745] = 32'h00F00793; + rom[746] = 32'h0167F463; + rom[747] = 32'h00078B13; + rom[748] = 32'h00098793; + rom[749] = 32'h04F36E63; + rom[750] = 32'h00812D83; + rom[751] = 32'h40FD0633; + rom[752] = 32'h00479693; + rom[753] = 32'h0400006F; + rom[754] = 32'h01BC9463; + rom[755] = 32'h02060A63; + rom[756] = 32'h00F12C23; + rom[757] = 32'h01B685B3; + rom[758] = 32'h47800513; + rom[759] = 32'h00C12E23; + rom[760] = 32'h00612A23; + rom[761] = 32'h00D12823; + rom[762] = 32'hF60FF0EF; + rom[763] = 32'h01C12603; + rom[764] = 32'h01812783; + rom[765] = 32'h01412303; + rom[766] = 32'h01012683; + rom[767] = 32'h00A40433; + rom[768] = 32'h001D8D93; + rom[769] = 32'hFDBB72E3; + rom[770] = 32'h00178793; + rom[771] = 32'hFA9FF06F; + rom[772] = 32'h00100793; + rom[773] = 32'h00040693; + rom[774] = 32'h04F40063; + rom[775] = 32'h00200793; + rom[776] = 32'h02F40C63; + rom[777] = 32'h00400793; + rom[778] = 32'h00300613; + rom[779] = 32'h00078693; + rom[780] = 32'h02C40463; + rom[781] = 32'h00500593; + rom[782] = 32'h00058693; + rom[783] = 32'h00F40E63; + rom[784] = 32'h00600793; + rom[785] = 32'h00078693; + rom[786] = 32'h00B40863; + rom[787] = 32'h00060693; + rom[788] = 32'h00F40463; + rom[789] = 32'h00700693; + rom[790] = 32'h00040613; + rom[791] = 32'h000C8593; + rom[792] = 32'h000D0513; + rom[793] = 32'h00612823; + rom[794] = 32'hF20FF0EF; + rom[795] = 32'h04041863; + rom[796] = 32'h01012303; + rom[797] = 32'h05336463; + rom[798] = 32'h00812783; + rom[799] = 32'h41A985B3; + rom[800] = 32'h00499613; + rom[801] = 32'h02C0006F; + rom[802] = 32'h01979463; + rom[803] = 32'h02058063; + rom[804] = 32'h0FF00713; + rom[805] = 32'h00976C63; + rom[806] = 32'h00249693; + rom[807] = 32'h00D906B3; + rom[808] = 32'h00C78533; + rom[809] = 32'h00A6A023; + rom[810] = 32'h00148493; + rom[811] = 32'h00178793; + rom[812] = 32'hFCFB7CE3; + rom[813] = 32'h00198993; + rom[814] = 32'hFBDFF06F; + rom[815] = 32'h004C0C13; + rom[816] = 32'hE89BE0E3; + rom[817] = 32'h42402783; + rom[818] = 32'h43402703; + rom[819] = 32'h10000413; + rom[820] = 32'h40F407B3; + rom[821] = 32'hC2E796E3; + rom[822] = 32'h47800A93; + rom[823] = 32'h000A0593; + rom[824] = 32'h000A8513; + rom[825] = 32'hE64FF0EF; + rom[826] = 32'h00050C63; + rom[827] = 32'h00600693; + rom[828] = 32'h00A00613; + rom[829] = 32'h00FA7593; + rom[830] = 32'h004A5513; + rom[831] = 32'hE8CFF0EF; + rom[832] = 32'h001A0A13; + rom[833] = 32'hFC8A1CE3; + rom[834] = 32'h0000F7B7; + rom[835] = 32'h00001737; + rom[836] = 32'h00D78793; + rom[837] = 32'h00F72023; + rom[838] = 32'h00100713; + rom[839] = 32'hD81FF06F; + rom[840] = 32'h0027F793; + rom[841] = 32'h00078863; + rom[842] = 32'h00802783; + rom[843] = 32'hBC078AE3; + rom[844] = 32'hC35FF06F; + rom[845] = 32'h41002783; + rom[846] = 32'h00700A13; + rom[847] = 32'h00F484B3; + rom[848] = 32'h40C02783; + rom[849] = 32'h40902823; + rom[850] = 32'h00F40433; + rom[851] = 32'h40802623; + rom[852] = 32'h029A4E63; + rom[853] = 32'hFF900A13; + rom[854] = 32'h0544CE63; + rom[855] = 32'h00700493; + rom[856] = 32'h0684CE63; + rom[857] = 32'hFF900493; + rom[858] = 32'hB8945CE3; + rom[859] = 32'h00802783; + rom[860] = 32'h00000593; + rom[861] = 32'hFFF00513; + rom[862] = 32'h08078663; + rom[863] = 32'hE90FF0EF; + rom[864] = 32'h00840413; + rom[865] = 32'h40802623; + rom[866] = 32'hFE1FF06F; + rom[867] = 32'h00802783; + rom[868] = 32'h00100593; + rom[869] = 32'h00000513; + rom[870] = 32'h00078A63; + rom[871] = 32'hE70FF0EF; + rom[872] = 32'hFF848493; + rom[873] = 32'h40902823; + rom[874] = 32'hFA9FF06F; + rom[875] = 32'hEACFF0EF; + rom[876] = 32'hFF1FF06F; + rom[877] = 32'h00802783; + rom[878] = 32'hFFF00593; + rom[879] = 32'h00000513; + rom[880] = 32'h00078A63; + rom[881] = 32'hE48FF0EF; + rom[882] = 32'h00848493; + rom[883] = 32'h40902823; + rom[884] = 32'hF89FF06F; + rom[885] = 32'hE84FF0EF; + rom[886] = 32'hFF1FF06F; + rom[887] = 32'h00802783; + rom[888] = 32'h00000593; + rom[889] = 32'h00100513; + rom[890] = 32'h00078A63; + rom[891] = 32'hE20FF0EF; + rom[892] = 32'hFF840413; + rom[893] = 32'h40802623; + rom[894] = 32'hF69FF06F; + rom[895] = 32'hE5CFF0EF; + rom[896] = 32'hFF1FF06F; + rom[897] = 32'hE54FF0EF; + rom[898] = 32'hF79FF06F; + rom[899] = 32'hFE010113; + rom[900] = 32'h00112E23; + rom[901] = 32'h00812C23; + rom[902] = 32'h00912A23; + rom[903] = 32'h01212823; + rom[904] = 32'h01312623; + rom[905] = 32'h01412423; + rom[906] = 32'h01512223; + rom[907] = 32'h01612023; + rom[908] = 32'h00000793; + rom[909] = 32'h47800613; + rom[910] = 32'h45800693; + rom[911] = 32'h43800713; + rom[912] = 32'h02000593; + rom[913] = 32'h00C78533; + rom[914] = 32'h00052023; + rom[915] = 32'h00D78533; + rom[916] = 32'h00052023; + rom[917] = 32'h00E78533; + rom[918] = 32'h00052023; + rom[919] = 32'h00478793; + rom[920] = 32'hFEB792E3; + rom[921] = 32'h42002A23; + rom[922] = 32'h42002823; + rom[923] = 32'h42002423; + rom[924] = 32'h40002823; + rom[925] = 32'h40002623; + rom[926] = 32'h00F00713; + rom[927] = 32'h40E02C23; + rom[928] = 32'h01400713; + rom[929] = 32'h42002623; + rom[930] = 32'h00002223; + rom[931] = 32'h40E02A23; + rom[932] = 32'h0FB00913; + rom[933] = 32'hD14FF0EF; + rom[934] = 32'h10D00993; + rom[935] = 32'h00090513; + rom[936] = 32'h00300613; + rom[937] = 32'h00F00593; + rom[938] = 32'hC78FF0EF; + rom[939] = 32'h2A890513; + rom[940] = 32'h00300613; + rom[941] = 32'h00F00593; + rom[942] = 32'h00190913; + rom[943] = 32'hC64FF0EF; + rom[944] = 32'hFD391EE3; + rom[945] = 32'h0FB00913; + rom[946] = 32'h3CB00993; + rom[947] = 32'h00090513; + rom[948] = 32'h00300613; + rom[949] = 32'h00F00593; + rom[950] = 32'hC48FF0EF; + rom[951] = 32'h01190513; + rom[952] = 32'h00300613; + rom[953] = 32'h00F00593; + rom[954] = 32'h02890913; + rom[955] = 32'hC34FF0EF; + rom[956] = 32'hFD391EE3; + rom[957] = 32'h00000913; + rom[958] = 32'h01000993; + rom[959] = 32'h00000A13; + rom[960] = 32'h000A0593; + rom[961] = 32'h00700693; + rom[962] = 32'h00900613; + rom[963] = 32'h00090513; + rom[964] = 32'h001A0A13; + rom[965] = 32'hC74FF0EF; + rom[966] = 32'hFF3A14E3; + rom[967] = 32'h00190913; + rom[968] = 32'hFD491EE3; + rom[969] = 32'h000027B7; + rom[970] = 32'h00E00713; + rom[971] = 32'h1EE78B23; + rom[972] = 32'h00600713; + rom[973] = 32'h1EE78BA3; + rom[974] = 32'h00100913; + rom[975] = 32'h000017B7; + rom[976] = 32'h1527A023; + rom[977] = 32'hCA4FF0EF; + rom[978] = 32'h42402683; + rom[979] = 32'h00001737; + rom[980] = 32'h00D72023; + rom[981] = 32'h42402703; + rom[982] = 32'h000017B7; + rom[983] = 32'h00E7A223; + rom[984] = 32'h11878A13; + rom[985] = 32'h4A400A93; + rom[986] = 32'h00402783; + rom[987] = 32'h02078C63; + rom[988] = 32'h01812403; + rom[989] = 32'h000017B7; + rom[990] = 32'h1207A023; + rom[991] = 32'h01C12083; + rom[992] = 32'h01412483; + rom[993] = 32'h01012903; + rom[994] = 32'h00C12983; + rom[995] = 32'h00812A03; + rom[996] = 32'h00412A83; + rom[997] = 32'h00012B03; + rom[998] = 32'h00002423; + rom[999] = 32'h02010113; + rom[1000] = 32'hD28FF06F; + rom[1001] = 32'h4A002683; + rom[1002] = 32'h49C02783; + rom[1003] = 32'h42C02703; + rom[1004] = 32'h04F68063; + rom[1005] = 32'h4A002783; + rom[1006] = 32'h00279793; + rom[1007] = 32'h00FA87B3; + rom[1008] = 32'h0007A503; + rom[1009] = 32'h4A002783; + rom[1010] = 32'h00178793; + rom[1011] = 32'h03F7F793; + rom[1012] = 32'h4AF02023; + rom[1013] = 32'h00071663; + rom[1014] = 32'hFF8FF0EF; + rom[1015] = 32'hF8DFF06F; + rom[1016] = 32'h00F51793; + rom[1017] = 32'hF807D2E3; + rom[1018] = 32'h01202223; + rom[1019] = 32'hF7DFF06F; + rom[1020] = 32'hF6070CE3; + rom[1021] = 32'h000A2783; + rom[1022] = 32'h01F7F793; + rom[1023] = 32'hF60796E3; + rom[1024] = 32'h00002783; + rom[1025] = 32'h0017C613; + rom[1026] = 32'h00C02023; + rom[1027] = 32'h00100693; + rom[1028] = 32'h00D78C63; + rom[1029] = 32'h00400793; + rom[1030] = 32'h00D71463; + rom[1031] = 32'h00200793; + rom[1032] = 32'h00479793; + rom[1033] = 32'h0017E793; + rom[1034] = 32'h00001737; + rom[1035] = 32'h14F72023; + rom[1036] = 32'hF39FF06F; + rom[1037] = 32'hFF010113; + rom[1038] = 32'h00112623; + rom[1039] = 32'h00812423; + rom[1040] = 32'h00912223; + rom[1041] = 32'h01212023; + rom[1042] = 32'hABCFF0EF; + rom[1043] = 32'h000017B7; + rom[1044] = 32'h1147A783; + rom[1045] = 32'h0017E793; + rom[1046] = 32'h40F02E23; + rom[1047] = 32'h00100793; + rom[1048] = 32'h42F02023; + rom[1049] = 32'h00001737; + rom[1050] = 32'h10F72623; + rom[1051] = 32'h12072023; + rom[1052] = 32'h00002423; + rom[1053] = 32'hC54FF0EF; + rom[1054] = 32'h4A400493; + rom[1055] = 32'h4A002703; + rom[1056] = 32'h49C02783; + rom[1057] = 32'hFEF70CE3; + rom[1058] = 32'h4A002783; + rom[1059] = 32'h00279793; + rom[1060] = 32'h00F487B3; + rom[1061] = 32'h0007A503; + rom[1062] = 32'h4A002783; + rom[1063] = 32'h00178793; + rom[1064] = 32'h03F7F793; + rom[1065] = 32'h4AF02023; + rom[1066] = 32'hF28FF0EF; + rom[1067] = 32'hFD1FF06F; + rom[1068] = 32'hFD010113; + rom[1069] = 32'h03212223; + rom[1070] = 32'h03312023; + rom[1071] = 32'h01512C23; + rom[1072] = 32'h00001937; + rom[1073] = 32'h000019B7; + rom[1074] = 32'h01412E23; + rom[1075] = 32'h01612A23; + rom[1076] = 32'h01712823; + rom[1077] = 32'h02812623; + rom[1078] = 32'h02912423; + rom[1079] = 32'h01812623; + rom[1080] = 32'h10090913; + rom[1081] = 32'h10498993; + rom[1082] = 32'h4A400A93; + rom[1083] = 32'h00092403; + rom[1084] = 32'h00147413; + rom[1085] = 32'h02041863; + rom[1086] = 32'h02C12403; + rom[1087] = 32'h02812483; + rom[1088] = 32'h02412903; + rom[1089] = 32'h02012983; + rom[1090] = 32'h01C12A03; + rom[1091] = 32'h01812A83; + rom[1092] = 32'h01412B03; + rom[1093] = 32'h01012B83; + rom[1094] = 32'h00C12C03; + rom[1095] = 32'h03010113; + rom[1096] = 32'h00008067; + rom[1097] = 32'h0009AC03; + rom[1098] = 32'h49C02403; + rom[1099] = 32'h4A002483; + rom[1100] = 32'h00140413; + rom[1101] = 32'h03F47413; + rom[1102] = 32'h02848463; + rom[1103] = 32'h49C02483; + rom[1104] = 32'h00249493; + rom[1105] = 32'h009A84B3; + rom[1106] = 32'h0184A023; + rom[1107] = 32'h48802E23; + rom[1108] = 32'h00001437; + rom[1109] = 32'h00100493; + rom[1110] = 32'h10942423; + rom[1111] = 32'hF91FF06F; + rom[1112] = 32'h49802403; + rom[1113] = 32'h00140413; + rom[1114] = 32'h48802C23; + rom[1115] = 32'hFE5FF06F; rom[1116] = 32'h00000013; rom[1117] = 32'h00000013; rom[1118] = 32'h00000013; diff --git a/pipelined-cpu/srcs/rtl/cpu21_mmio.v b/pipelined-cpu/srcs/rtl/cpu21_mmio.v index a8b3a13..61aaf65 100644 --- a/pipelined-cpu/srcs/rtl/cpu21_mmio.v +++ b/pipelined-cpu/srcs/rtl/cpu21_mmio.v @@ -11,7 +11,7 @@ // 0x0000_1004 七段数码管:8 位十六进制数(每 4 位一个数码管,低 4 位 = 最右) // 0x0000_1100 + 4*k 鼠标寄存器组(见下) // 0x0000_1140 + 4*k 显示控制器寄存器(见下) -// 0x0000_2000 - 0x27FF 显存窗口:40x30 格、每格 1 字节(只用到前 1200 字节) +// 0x0000_2000 - 0x2FFF 显存窗口:40x30 格、每格 2 字节(共 2400 字节) // // 鼠标寄存器(基址 0x1100): // +0x00 STATUS RO [0] FIFO 非空 [5:1] 项数 [6] 中断使能 [7] FIFO 满 @@ -41,272 +41,241 @@ // 以后要增加外设(UART、SD 卡等)时只需在这里扩展地址译码。 // ----------------------------------------------------------------------------- module cpu21_mmio #( - parameter [31:0] LED_ADDR = 32'h0000_1000, - parameter integer FB_WORDS = 300, - parameter integer FIFO_DEPTH = 16 - ) ( - input wire clk, - input wire reset, - // MEM 级的访存请求(来自 EX/MEM 流水寄存器) - input wire mem_valid_i, - input wire mem_write_i, - input wire mem_read_i, - input wire [31:0] addr_i, - input wire [31:0] wdata_i, - input wire [ 3:0] wstrb_i, - // MMIO 读回 - output wire [31:0] rdata_o, - output wire rdata_hit_o, - // LED 外设(原样保留) - output reg [31:0] led_data_o, - output reg led_valid_o, - // 七段数码管:8 位十六进制数 - output reg [31:0] seg_data_o, - output reg seg_valid_o, - // 显存写端口(板级顶层的双口 RAM) - output wire fb_we_o, - output wire [ 9:0] fb_waddr_o, - output wire [31:0] fb_wdata_o, - output wire [ 3:0] fb_wstrb_o, - input wire [31:0] fb_rdata_i, - // 显示控制器寄存器(给 VGA 用) - output wire [31:0] disp_ctrl_o, - output wire [31:0] disp_cursor_o, - // 鼠标事件源(来自板级顶层:按键去抖 / PS/2 解析) - input wire mouse_ev_valid_i, - input wire [ 7:0] mouse_dx_i, - input wire [ 7:0] mouse_dy_i, - input wire [ 4:0] mouse_btn_i, - input wire [15:0] sw_i, - input wire frame_tick_i, - // 中断 - output wire mouse_irq_o, - output wire level_irq_o - ); - // --------------------------------------------------------------------------- - // 地址译码(都按"字"对齐:同一 32 位寄存器内的任意字节偏移都算命中) - // --------------------------------------------------------------------------- - localparam [31:0] SEG_ADDR = 32'h0000_1004; - localparam [31:0] MOUSE_BASE = 32'h0000_1100; - localparam [31:0] DISP_BASE = 32'h0000_1140; - localparam integer FIFO_AW = 4; - localparam [FIFO_AW:0] FIFO_FULL_V = FIFO_DEPTH[FIFO_AW:0]; + parameter [31:0] LED_ADDR = 32'h0000_1000, + parameter integer FB_WORDS = 300, + parameter integer FIFO_DEPTH = 16 +) ( + input wire clk, + input wire reset, + // MEM 级的访存请求(来自 EX/MEM 流水寄存器) + input wire mem_valid_i, + input wire mem_write_i, + input wire mem_read_i, + input wire [31:0] addr_i, + input wire [31:0] wdata_i, + input wire [ 3:0] wstrb_i, + // MMIO 读回 + output wire [31:0] rdata_o, + output wire rdata_hit_o, + // LED 外设(原样保留) + output reg [31:0] led_data_o, + output reg led_valid_o, + // 七段数码管:8 位十六进制数 + output reg [31:0] seg_data_o, + output reg seg_valid_o, + // 显存写端口(板级顶层的双口 RAM) + output wire fb_we_o, + output wire [ 9:0] fb_waddr_o, + output wire [31:0] fb_wdata_o, + output wire [ 3:0] fb_wstrb_o, + input wire [31:0] fb_rdata_i, + // 显示控制器寄存器(给 VGA 用) + output wire [31:0] disp_ctrl_o, + output wire [31:0] disp_cursor_o, + // 鼠标事件源(来自板级顶层:按键去抖 / PS/2 解析) + input wire mouse_ev_valid_i, + input wire [ 7:0] mouse_dx_i, + input wire [ 7:0] mouse_dy_i, + input wire [ 4:0] mouse_btn_i, + input wire [15:0] sw_i, + input wire frame_tick_i, + // 中断 + output wire mouse_irq_o, + output wire level_irq_o +); + // --------------------------------------------------------------------------- + // 地址译码(都按"字"对齐:同一 32 位寄存器内的任意字节偏移都算命中) + // --------------------------------------------------------------------------- + localparam [31:0] SEG_ADDR = 32'h0000_1004; + localparam [31:0] MOUSE_BASE = 32'h0000_1100; + localparam [31:0] DISP_BASE = 32'h0000_1140; + localparam integer FIFO_AW = 4; + localparam [FIFO_AW:0] FIFO_FULL_V = FIFO_DEPTH[FIFO_AW:0]; - wire sel_led = (addr_i[31:2] == LED_ADDR[31:2]); - wire sel_seg = (addr_i[31:2] == SEG_ADDR[31:2]); - wire sel_mouse = (addr_i[31:8] == MOUSE_BASE[31:8]) && (addr_i[7:6] == 2'b00); - wire sel_disp = (addr_i[31:8] == DISP_BASE[31:8]) && (addr_i[7:6] == 2'b01); - // 显存窗口 0x2000 - 0x27FF:bit13=1、bit12=0、bit11=0,高位全 0 - // (原来写成 addr[12] && !addr[11],要求 bit12=1 —— 那是 0x1000-0x17FF, - // 于是 0x2000+ 的读写全都不命中、而鼠标/显示寄存器写反而落进了显存) - wire sel_fb = (addr_i[31:14] == 18'd0) && addr_i[13] && !addr_i[12] && !addr_i[11]; + wire sel_led = (addr_i[31:2] == LED_ADDR[31:2]); + wire sel_seg = (addr_i[31:2] == SEG_ADDR[31:2]); + wire sel_mouse = (addr_i[31:8] == MOUSE_BASE[31:8]) && (addr_i[7:6] == 2'b00); + wire sel_disp = (addr_i[31:8] == DISP_BASE[31:8]) && (addr_i[7:6] == 2'b01); + // 显存窗口 0x2000 - 0x2FFF:共 600 个字(每格两个字节)。 + wire sel_fb = (addr_i[31:12] == 20'h00002); - wire [3:0] midx = addr_i[5:2]; - wire [3:0] didx = addr_i[5:2]; - wire [9:0] fb_widx = addr_i[10:2]; - wire fb_ok = (fb_widx < FB_WORDS); + wire [3:0] midx = addr_i[5:2]; + wire [3:0] didx = addr_i[5:2]; + wire [9:0] fb_widx = addr_i[11:2]; + wire fb_ok = (fb_widx < FB_WORDS); - wire led_wr = mem_valid_i && mem_write_i && sel_led; - wire led_rd = mem_valid_i && mem_read_i && sel_led; - wire seg_wr = mem_valid_i && mem_write_i && sel_seg; - wire seg_rd = mem_valid_i && mem_read_i && sel_seg; - wire mo_wr = mem_valid_i && mem_write_i && sel_mouse; - wire mo_rd = mem_valid_i && mem_read_i && sel_mouse; - wire dp_wr = mem_valid_i && mem_write_i && sel_disp; - wire dp_rd = mem_valid_i && mem_read_i && sel_disp; - wire fb_wr = mem_valid_i && mem_write_i && sel_fb && fb_ok; - wire fb_rd = mem_valid_i && mem_read_i && sel_fb && fb_ok; + wire led_wr = mem_valid_i && mem_write_i && sel_led; + wire led_rd = mem_valid_i && mem_read_i && sel_led; + wire seg_wr = mem_valid_i && mem_write_i && sel_seg; + wire seg_rd = mem_valid_i && mem_read_i && sel_seg; + wire mo_wr = mem_valid_i && mem_write_i && sel_mouse; + wire mo_rd = mem_valid_i && mem_read_i && sel_mouse; + wire dp_wr = mem_valid_i && mem_write_i && sel_disp; + wire dp_rd = mem_valid_i && mem_read_i && sel_disp; + wire fb_wr = mem_valid_i && mem_write_i && sel_fb && fb_ok; + wire fb_rd = mem_valid_i && mem_read_i && sel_fb && fb_ok; - assign fb_we_o = fb_wr; - assign fb_waddr_o = fb_widx; - assign fb_wdata_o = wdata_i; - assign fb_wstrb_o = wstrb_i; + assign fb_we_o = fb_wr; + assign fb_waddr_o = fb_widx; + assign fb_wdata_o = wdata_i; + assign fb_wstrb_o = wstrb_i; - assign rdata_hit_o = led_rd | seg_rd | mo_rd | dp_rd | fb_rd; + assign rdata_hit_o = led_rd | seg_rd | mo_rd | dp_rd | fb_rd; - // 字节写合并:sw 改 4 字节、sb 只改 1 字节(与 RAM 的字节写语义一致) - function [31:0] merge_bytes; - input [31:0] new_v; - input [31:0] old_v; - input [ 3:0] strb; - begin - merge_bytes[7:0] = strb[0] ? new_v[7:0] : old_v[7:0]; - merge_bytes[15:8] = strb[1] ? new_v[15:8] : old_v[15:8]; - merge_bytes[23:16] = strb[2] ? new_v[23:16] : old_v[23:16]; - merge_bytes[31:24] = strb[3] ? new_v[31:24] : old_v[31:24]; - end - endfunction - - // --------------------------------------------------------------------------- - // LED:保持原有语义(led_valid_o 只拉高一拍) - // --------------------------------------------------------------------------- - always @(posedge clk or posedge reset) begin - if (reset) begin - led_data_o <= 32'b0; - led_valid_o <= 1'b0; - end - else begin - led_valid_o <= 1'b0; - if (led_wr) begin - led_data_o <= merge_bytes(wdata_i, led_data_o, wstrb_i); - led_valid_o <= 1'b1; - end - end + // 字节写合并:sw 改 4 字节、sb 只改 1 字节(与 RAM 的字节写语义一致) + function [31:0] merge_bytes; + input [31:0] new_v; + input [31:0] old_v; + input [3:0] strb; + begin + merge_bytes[7:0] = strb[0] ? new_v[7:0] : old_v[7:0]; + merge_bytes[15:8] = strb[1] ? new_v[15:8] : old_v[15:8]; + merge_bytes[23:16] = strb[2] ? new_v[23:16] : old_v[23:16]; + merge_bytes[31:24] = strb[3] ? new_v[31:24] : old_v[31:24]; end + endfunction - // --------------------------------------------------------------------------- - // 七段数码管:8 位十六进制数(低 4 位 = 最右边那个数码管) - // --------------------------------------------------------------------------- - always @(posedge clk or posedge reset) begin - if (reset) begin - seg_data_o <= 32'b0; - seg_valid_o <= 1'b0; - end - else begin - seg_valid_o <= 1'b0; - if (seg_wr) begin - seg_data_o <= merge_bytes(wdata_i, seg_data_o, wstrb_i); - seg_valid_o <= 1'b1; - end - end + // --------------------------------------------------------------------------- + // LED:保持原有语义(led_valid_o 只拉高一拍) + // --------------------------------------------------------------------------- + always @(posedge clk or posedge reset) begin + if (reset) begin + led_data_o <= 32'b0; + led_valid_o <= 1'b0; + end else begin + led_valid_o <= 1'b0; + if (led_wr) begin + led_data_o <= merge_bytes(wdata_i, led_data_o, wstrb_i); + led_valid_o <= 1'b1; + end end + end - // --------------------------------------------------------------------------- - // 显示控制器寄存器(显存本体在板级顶层) - // --------------------------------------------------------------------------- - reg [31:0] disp_ctrl_q, disp_cursor_q; - - assign disp_ctrl_o = disp_ctrl_q; - assign disp_cursor_o = disp_cursor_q; - - // --------------------------------------------------------------------------- - // 鼠标:事件 FIFO + 寄存器 + 中断 - // --------------------------------------------------------------------------- - reg [31:0] fifo [0:FIFO_DEPTH-1]; - reg [FIFO_AW-1:0] wr_ptr_q, rd_ptr_q; - reg [FIFO_AW:0] cnt_q; - reg [31:0] mctrl_q, time_q, frame_q, evcnt_q; - reg level_q; - - wire fifo_empty = (cnt_q == {FIFO_AW+1{1'b0}}); - wire fifo_full = (cnt_q == FIFO_FULL_V); - wire [31:0] fifo_head = fifo[rd_ptr_q]; - wire irq_en = mctrl_q[0]; - - assign mouse_irq_o = irq_en && !fifo_empty; - assign level_irq_o = level_q; - - wire push = mouse_ev_valid_i && !fifo_full; - wire pop = mo_wr && (midx == 4'd2) && !fifo_empty; - - always @(posedge clk or posedge reset) begin - if (reset) begin - mctrl_q <= 32'h0000_0001; // 鼠标中断默认打开 - time_q <= 32'd0; - frame_q <= 32'd0; - evcnt_q <= 32'd0; - level_q <= 1'b0; - wr_ptr_q <= {FIFO_AW{1'b0}}; - rd_ptr_q <= {FIFO_AW{1'b0}}; - cnt_q <= {(FIFO_AW+1){1'b0}}; - disp_ctrl_q <= 32'h0000_0001; // 光标可见,背景色 0 - disp_cursor_q <= 32'h0000_0000; - end - else begin - time_q <= time_q + 32'd1; - if (frame_tick_i) - frame_q <= frame_q + 32'd1; - - if (push) begin - fifo[wr_ptr_q] <= {11'b0, mouse_btn_i, mouse_dy_i, mouse_dx_i}; - wr_ptr_q <= wr_ptr_q + 1'b1; - evcnt_q <= evcnt_q + 32'd1; - end - if (pop) - rd_ptr_q <= rd_ptr_q + 1'b1; - cnt_q <= cnt_q + (push ? 1'b1 : 1'b0) - (pop ? 1'b1 : 1'b0); - - // 鼠标寄存器:CTRL(3) / LEVEL(8) - if (mo_wr) begin - case (midx) - 4'd3: - mctrl_q <= merge_bytes(wdata_i, mctrl_q, wstrb_i); - 4'd8: - level_q <= wdata_i[0]; - default: - ; - endcase - end - - // 显示控制器:CTRL(0) / CURSOR(1) - if (dp_wr) begin - case (didx) - 4'd0: - disp_ctrl_q <= merge_bytes(wdata_i, disp_ctrl_q, wstrb_i); - 4'd1: - disp_cursor_q <= merge_bytes(wdata_i, disp_cursor_q, wstrb_i); - default: - ; - endcase - end - end + // --------------------------------------------------------------------------- + // 七段数码管:8 位十六进制数(低 4 位 = 最右边那个数码管) + // --------------------------------------------------------------------------- + always @(posedge clk or posedge reset) begin + if (reset) begin + seg_data_o <= 32'b0; + seg_valid_o <= 1'b0; + end else begin + seg_valid_o <= 1'b0; + if (seg_wr) begin + seg_data_o <= merge_bytes(wdata_i, seg_data_o, wstrb_i); + seg_valid_o <= 1'b1; + end end + end - // --------------------------------------------------------------------------- - // 读数据(组合,与"指令存储器组合读/数据存储器组合读"的时序一致) - // --------------------------------------------------------------------------- - reg [31:0] rdata_mux; + // --------------------------------------------------------------------------- + // 显示控制器寄存器(显存本体在板级顶层) + // --------------------------------------------------------------------------- + reg [31:0] disp_ctrl_q, disp_cursor_q; - always @* begin - rdata_mux = 32'b0; - if (led_rd) begin - rdata_mux = led_data_o; - end - else if (seg_rd) begin - rdata_mux = seg_data_o; - end - else if (fb_rd) begin - rdata_mux = fb_rdata_i; - end - else if (mo_rd) begin - case (midx) - 4'd0: - rdata_mux = {24'b0, fifo_full, irq_en, cnt_q[4:0], !fifo_empty}; - 4'd1: - rdata_mux = fifo_head; - 4'd3: - rdata_mux = mctrl_q; - 4'd4: - rdata_mux = {11'b0, mouse_btn_i, sw_i}; - 4'd5: - rdata_mux = time_q; - 4'd6: - rdata_mux = frame_q; - 4'd7: - rdata_mux = evcnt_q; - 4'd8: - rdata_mux = {31'b0, level_q}; - 4'd9: - rdata_mux = 32'hCAFE_0002; - default: - rdata_mux = 32'b0; - endcase - end - else if (dp_rd) begin - case (didx) - 4'd0: - rdata_mux = disp_ctrl_q; - 4'd1: - rdata_mux = disp_cursor_q; - 4'd2: - rdata_mux = 32'hCAFE_0001; - default: - rdata_mux = 32'b0; - endcase - end + assign disp_ctrl_o = disp_ctrl_q; + assign disp_cursor_o = disp_cursor_q; + + // --------------------------------------------------------------------------- + // 鼠标:事件 FIFO + 寄存器 + 中断 + // --------------------------------------------------------------------------- + reg [31:0] fifo[0:FIFO_DEPTH-1]; + reg [FIFO_AW-1:0] wr_ptr_q, rd_ptr_q; + reg [FIFO_AW:0] cnt_q; + reg [31:0] mctrl_q, time_q, frame_q, evcnt_q; + reg level_q; + + wire fifo_empty = (cnt_q == {FIFO_AW + 1{1'b0}}); + wire fifo_full = (cnt_q == FIFO_FULL_V); + wire [31:0] fifo_head = fifo[rd_ptr_q]; + wire irq_en = mctrl_q[0]; + + assign mouse_irq_o = irq_en && !fifo_empty; + assign level_irq_o = level_q; + + wire push = mouse_ev_valid_i && !fifo_full; + wire pop = mo_wr && (midx == 4'd2) && !fifo_empty; + + always @(posedge clk or posedge reset) begin + if (reset) begin + mctrl_q <= 32'h0000_0001; // 鼠标中断默认打开 + time_q <= 32'd0; + frame_q <= 32'd0; + evcnt_q <= 32'd0; + level_q <= 1'b0; + wr_ptr_q <= {FIFO_AW{1'b0}}; + rd_ptr_q <= {FIFO_AW{1'b0}}; + cnt_q <= {(FIFO_AW + 1) {1'b0}}; + disp_ctrl_q <= 32'h0000_0001; // 光标可见,背景色 0 + disp_cursor_q <= 32'h0000_0000; + end else begin + time_q <= time_q + 32'd1; + if (frame_tick_i) frame_q <= frame_q + 32'd1; + + if (push) begin + fifo[wr_ptr_q] <= {11'b0, mouse_btn_i, mouse_dy_i, mouse_dx_i}; + wr_ptr_q <= wr_ptr_q + 1'b1; + evcnt_q <= evcnt_q + 32'd1; + end + if (pop) rd_ptr_q <= rd_ptr_q + 1'b1; + cnt_q <= cnt_q + (push ? 1'b1 : 1'b0) - (pop ? 1'b1 : 1'b0); + + // 鼠标寄存器:CTRL(3) / LEVEL(8) + if (mo_wr) begin + case (midx) + 4'd3: mctrl_q <= merge_bytes(wdata_i, mctrl_q, wstrb_i); + 4'd8: level_q <= wdata_i[0]; + default: ; + endcase + end + + // 显示控制器:CTRL(0) / CURSOR(1) + if (dp_wr) begin + case (didx) + 4'd0: disp_ctrl_q <= merge_bytes(wdata_i, disp_ctrl_q, wstrb_i); + 4'd1: disp_cursor_q <= merge_bytes(wdata_i, disp_cursor_q, wstrb_i); + default: ; + endcase + end end + end - assign rdata_o = rdata_mux; + // --------------------------------------------------------------------------- + // 读数据(组合,与"指令存储器组合读/数据存储器组合读"的时序一致) + // --------------------------------------------------------------------------- + reg [31:0] rdata_mux; + + always @* begin + rdata_mux = 32'b0; + if (led_rd) begin + rdata_mux = led_data_o; + end else if (seg_rd) begin + rdata_mux = seg_data_o; + end else if (fb_rd) begin + rdata_mux = fb_rdata_i; + end else if (mo_rd) begin + case (midx) + 4'd0: rdata_mux = {24'b0, fifo_full, irq_en, cnt_q[4:0], !fifo_empty}; + 4'd1: rdata_mux = fifo_head; + 4'd3: rdata_mux = mctrl_q; + 4'd4: rdata_mux = {11'b0, mouse_btn_i, sw_i}; + 4'd5: rdata_mux = time_q; + 4'd6: rdata_mux = frame_q; + 4'd7: rdata_mux = evcnt_q; + 4'd8: rdata_mux = {31'b0, level_q}; + 4'd9: rdata_mux = 32'hCAFE_0002; + default: rdata_mux = 32'b0; + endcase + end else if (dp_rd) begin + case (didx) + 4'd0: rdata_mux = disp_ctrl_q; + 4'd1: rdata_mux = disp_cursor_q; + 4'd2: rdata_mux = 32'hCAFE_0001; + default: rdata_mux = 32'b0; + endcase + end + end + + assign rdata_o = rdata_mux; endmodule `default_nettype wire diff --git a/pipelined-cpu/srcs/rtl/cpu21_vga.v b/pipelined-cpu/srcs/rtl/cpu21_vga.v index 1e23999..7bb4a38 100644 --- a/pipelined-cpu/srcs/rtl/cpu21_vga.v +++ b/pipelined-cpu/srcs/rtl/cpu21_vga.v @@ -4,7 +4,7 @@ // ----------------------------------------------------------------------------- // cpu21_vga —— 640x480@60 的"格子"显示控制器(显存端口接板级顶层的双口 RAM)。 // -// CPU 不直接操作像素:它只通过 MMIO 往显示缓冲区里写"每格 1 字节"(字形 + 颜色), +// CPU 不直接操作像素:它只通过 MMIO 往显示缓冲区里写"每格 2 字节"(字形 + 颜色), // 本模块按像素扫描把格子展开成画面(8x8 字模放大 2 倍填满 16x16 的格子)。 // 这样一格只要 1 次字节写,刷屏开销极小。 // @@ -18,218 +18,308 @@ // (CTRL[0] 控制显示与否)。缓冲区字节的 bit7 在本模块中不使用(保留)。 // ----------------------------------------------------------------------------- module cpu21_vga #( - parameter integer H_VISIBLE = 640, - parameter integer H_FP = 16, - parameter integer H_SYNC = 96, - parameter integer H_BP = 48, - parameter integer V_VISIBLE = 480, - parameter integer V_FP = 10, - parameter integer V_SYNC = 2, - parameter integer V_BP = 33, - parameter integer COLS = 40, - parameter integer ROWS = 30 - ) ( - input wire clk, - input wire reset, - input wire tick, // 25 MHz 像素使能(每 2 个 clk 一拍) - // 显示缓冲区读端口 - output wire [ 9:0] fb_raddr_o, - input wire [31:0] fb_word_i, - // 控制 - input wire [31:0] ctrl_i, - input wire [31:0] cursor_i, - // VGA 输出 - output reg [ 3:0] vga_r, - output reg [ 3:0] vga_g, - output reg [ 3:0] vga_b, - output reg vga_hs, - output reg vga_vs, - output reg frame_tick_o - ); + parameter integer H_VISIBLE = 640, + parameter integer H_FP = 16, + parameter integer H_SYNC = 96, + parameter integer H_BP = 48, + parameter integer V_VISIBLE = 480, + parameter integer V_FP = 10, + parameter integer V_SYNC = 2, + parameter integer V_BP = 33, + parameter integer COLS = 40, + parameter integer ROWS = 30 +) ( + input wire clk, + input wire reset, + input wire tick, // 25 MHz 像素使能(每 2 个 clk 一拍) + // 显示缓冲区读端口 + output wire [ 9:0] fb_raddr_o, + input wire [31:0] fb_word_i, + // 控制 + input wire [31:0] ctrl_i, + input wire [31:0] cursor_i, + // VGA 输出 + output reg [ 3:0] vga_r, + output reg [ 3:0] vga_g, + output reg [ 3:0] vga_b, + output reg vga_hs, + output reg vga_vs, + output reg frame_tick_o +); - localparam integer H_TOTAL = H_VISIBLE + H_FP + H_SYNC + H_BP; // 800 - localparam integer V_TOTAL = V_VISIBLE + V_FP + V_SYNC + V_BP; // 525 + localparam integer H_TOTAL = H_VISIBLE + H_FP + H_SYNC + H_BP; // 800 + localparam integer V_TOTAL = V_VISIBLE + V_FP + V_SYNC + V_BP; // 525 - // --------------------------------------------------------------------------- - // 扫描计数 - // --------------------------------------------------------------------------- - reg [9:0] hx, vy; + // --------------------------------------------------------------------------- + // 扫描计数 + // --------------------------------------------------------------------------- + reg [9:0] hx, vy; - always @(posedge clk or posedge reset) begin - if (reset) begin - hx <= 10'd0; - vy <= 10'd0; - end - else if (tick) begin - if (hx == H_TOTAL - 1) begin - hx <= 10'd0; - vy <= (vy == V_TOTAL - 1) ? 10'd0 : (vy + 10'd1); - end - else begin - hx <= hx + 10'd1; - end - end + always @(posedge clk or posedge reset) begin + if (reset) begin + hx <= 10'd0; + vy <= 10'd0; + end else if (tick) begin + if (hx == H_TOTAL - 1) begin + hx <= 10'd0; + vy <= (vy == V_TOTAL - 1) ? 10'd0 : (vy + 10'd1); + end else begin + hx <= hx + 10'd1; + end end + end - wire de = (hx < H_VISIBLE) && (vy < V_VISIBLE); + wire de = (hx < H_VISIBLE) && (vy < V_VISIBLE); - // 同步信号在 tick 上寄存输出 - wire hs_n = ~((hx >= (H_VISIBLE + H_FP)) && (hx < (H_VISIBLE + H_FP + H_SYNC))); - wire vs_n = ~((vy >= (V_VISIBLE + V_FP)) && (vy < (V_VISIBLE + V_FP + V_SYNC))); + // 同步信号在 tick 上寄存输出 + wire hs_n = ~((hx >= (H_VISIBLE + H_FP)) && (hx < (H_VISIBLE + H_FP + H_SYNC))); + wire vs_n = ~((vy >= (V_VISIBLE + V_FP)) && (vy < (V_VISIBLE + V_FP + V_SYNC))); - // --------------------------------------------------------------------------- - // 格子索引与缓冲区读出 - // --------------------------------------------------------------------------- - wire [5:0] ccol = hx[9:4]; // 0..39 - wire [4:0] crow = vy[8:4]; // 0..29 - wire [10:0] cidx = (crow << 5) + (crow << 3) + ccol; // row*40 + col + // --------------------------------------------------------------------------- + // 格子索引与缓冲区读出 + // --------------------------------------------------------------------------- + wire [5:0] ccol = hx[9:4]; // 0..39 + wire [4:0] crow = vy[8:4]; // 0..29 + wire [10:0] cidx = (crow << 5) + (crow << 3) + ccol; // row*40 + col - assign fb_raddr_o = cidx[10:2]; // 字地址(1 字 = 4 格) + assign fb_raddr_o = cidx[10:1]; // 字地址(1 字 = 2 格) - wire [1:0] lane = cidx[1:0]; - wire [31:0] cell_word = fb_word_i; - wire [7:0] cell_byte = cell_word >> {lane, 3'b000}; + wire [ 1:0] lane = {cidx[0], 1'b0}; + wire [ 1:0] color_lane = lane + 2'd1; + wire [31:0] cell_word = fb_word_i; + wire [ 7:0] glyph_byte = cell_word >> {lane, 3'b000}; + wire [ 7:0] color_byte = cell_word >> {color_lane, 3'b000}; - wire [3:0] glyph = cell_byte[3:0]; - wire [2:0] gcolor = cell_byte[6:4]; - // 全局背景色(字模点为 0 时显示的颜色) - wire [2:0] bgcolor = ctrl_i[7:4]; + wire [ 5:0] glyph = glyph_byte[5:0]; + wire [ 2:0] gcolor = color_byte[2:0]; + // 全局背景色(字模点为 0 时显示的颜色) + wire [ 2:0] bgcolor = ctrl_i[7:4]; - // --------------------------------------------------------------------------- - // 8x8 字模(bit7 = 最左像素),放大 2 倍填满 16x16 的格子 - // --------------------------------------------------------------------------- - wire [2:0] fx = hx[3:1]; - wire [2:0] fy = vy[3:1]; + // --------------------------------------------------------------------------- + // 8x8 字模(bit7 = 最左像素),放大 2 倍填满 16x16 的格子;字形编号 0..63。 + // --------------------------------------------------------------------------- + wire [ 2:0] fx = hx[3:1]; + wire [ 2:0] fy = vy[3:1]; - function [7:0] font_row; - input [3:0] g; - input [2:0] r; - begin - case (g) - 4'd0: - font_row = 8'h00; // 空白 - 4'd1: - font_row = (r == 3'd0) ? 8'h18 : (r == 3'd1) ? 8'h38 : (r == 3'd2) ? 8'h18 : + function [7:0] font_row; + input [5:0] g; + input [2:0] r; + begin + case (g) + 6'd0: font_row = 8'h00; // 空白 + 6'd1: + font_row = (r == 3'd0) ? 8'h18 : (r == 3'd1) ? 8'h38 : (r == 3'd2) ? 8'h18 : (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 : (r == 3'd6) ? 8'h7E : 8'h00; // 1 - 4'd2: - font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 : + 6'd2: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 : (r == 3'd3) ? 8'h0C : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h30 : (r == 3'd6) ? 8'h7E : 8'h00; // 2 - 4'd3: - font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 : + 6'd3: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 : (r == 3'd3) ? 8'h1C : (r == 3'd4) ? 8'h06 : (r == 3'd5) ? 8'h66 : (r == 3'd6) ? 8'h3C : 8'h00; // 3 - 4'd4: - font_row = (r == 3'd0) ? 8'h0C : (r == 3'd1) ? 8'h1C : (r == 3'd2) ? 8'h3C : + 6'd4: + font_row = (r == 3'd0) ? 8'h0C : (r == 3'd1) ? 8'h1C : (r == 3'd2) ? 8'h3C : (r == 3'd3) ? 8'h6C : (r == 3'd4) ? 8'h7E : (r == 3'd5) ? 8'h0C : (r == 3'd6) ? 8'h0C : 8'h00; // 4 - 4'd5: - font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h7C : + 6'd5: + font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h7C : (r == 3'd3) ? 8'h06 : (r == 3'd4) ? 8'h06 : (r == 3'd5) ? 8'h66 : (r == 3'd6) ? 8'h3C : 8'h00; // 5 - 4'd6: - font_row = (r == 3'd0) ? 8'h1C : (r == 3'd1) ? 8'h30 : (r == 3'd2) ? 8'h60 : + 6'd6: + font_row = (r == 3'd0) ? 8'h1C : (r == 3'd1) ? 8'h30 : (r == 3'd2) ? 8'h60 : (r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : (r == 3'd6) ? 8'h3C : 8'h00; // 6 - 4'd7: - font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h0C : + 6'd7: + font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h0C : (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 : (r == 3'd6) ? 8'h18 : 8'h00; // 7 - 4'd8: - font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + 6'd8: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : (r == 3'd3) ? 8'h3C : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : (r == 3'd6) ? 8'h3C : 8'h00; // 8 - 4'd9: - font_row = (r == 3'd0) ? 8'hFF : (r == 3'd1) ? 8'h81 : (r == 3'd2) ? 8'hBD : + 6'd9: + font_row = (r == 3'd0) ? 8'hFF : (r == 3'd1) ? 8'h81 : (r == 3'd2) ? 8'hBD : (r == 3'd3) ? 8'hA5 : (r == 3'd4) ? 8'hA5 : (r == 3'd5) ? 8'hBD : (r == 3'd6) ? 8'h81 : 8'hFF; // 未揭开的方块 - 4'd10: - font_row = (r == 3'd0) ? 8'h40 : (r == 3'd1) ? 8'h70 : (r == 3'd2) ? 8'h78 : + 6'd10: + font_row = (r == 3'd0) ? 8'h40 : (r == 3'd1) ? 8'h70 : (r == 3'd2) ? 8'h78 : (r == 3'd3) ? 8'h70 : (r == 3'd4) ? 8'h40 : (r == 3'd5) ? 8'h40 : (r == 3'd6) ? 8'h40 : 8'h00; // 旗 - 4'd11: - font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h7E : (r == 3'd2) ? 8'hFF : + 6'd11: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h7E : (r == 3'd2) ? 8'hFF : (r == 3'd3) ? 8'hFF : (r == 3'd4) ? 8'hFF : (r == 3'd5) ? 8'hFF : (r == 3'd6) ? 8'h7E : 8'h3C; // 雷 - 4'd12: - font_row = (r == 3'd0) ? 8'h81 : (r == 3'd1) ? 8'h42 : (r == 3'd2) ? 8'h24 : + 6'd12: + font_row = (r == 3'd0) ? 8'h81 : (r == 3'd1) ? 8'h42 : (r == 3'd2) ? 8'h24 : (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h24 : (r == 3'd6) ? 8'h42 : 8'h81; // 爆炸 - 4'd13: - font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 : + 6'd13: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 : (r == 3'd3) ? 8'h0C : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h00 : (r == 3'd6) ? 8'h18 : 8'h00; // 问号 - 4'd14: - font_row = (r == 3'd3) ? 8'hFF : (r == 3'd4) ? 8'hFF : 8'h00; // 横线 - 4'd15: - font_row = 8'hFF; // 实心 - default: - font_row = 8'h00; - endcase - end - endfunction - - wire [7:0] frow = font_row(glyph, fy); - wire glyph_px = frow[3'd7 - fx]; // 1 = 画字模点 - - // --------------------------------------------------------------------------- - // 光标框:黄色、常亮、2 像素宽 - // 原来是 1 像素浅灰 + 闪动(blink 周期约 1.3 s):在白色未揭开格上几乎看不清, - // 而且截图有一半概率正好截到"灭"的那个相位。改成黄色常亮 2 像素后, - // VGA 上和图里都能一眼看到指针。想改回闪动:把 blink_q 加回来, - // 再在 cursor_box 里与上 blink 即可。 - // --------------------------------------------------------------------------- - wire cursor_here = (cursor_i[4:0] == ccol) && (cursor_i[12:8] == crow); - wire on_border = (hx[3:0] < 4'd2) || (hx[3:0] > 4'd13) || - (vy[3:0] < 4'd2) || (vy[3:0] > 4'd13); - wire cursor_box = cursor_here && ctrl_i[0] && on_border; - - // --------------------------------------------------------------------------- - // 颜色(3 位调色板 -> 4:4:4 RGB) - // --------------------------------------------------------------------------- - function [11:0] pal; - input [2:0] c; - begin - case (c) - 3'd0: - pal = {4'h0, 4'h0, 4'h0}; // 黑 - 3'd1: - pal = {4'h0, 4'h0, 4'hA}; // 深蓝 - 3'd2: - pal = {4'h0, 4'hA, 4'h0}; // 绿 - 3'd3: - pal = {4'h0, 4'hA, 4'hA}; // 青 - 3'd4: - pal = {4'hA, 4'h0, 4'h0}; // 红 - 3'd5: - pal = {4'hA, 4'h0, 4'hA}; // 洋红 - 3'd6: - pal = {4'hA, 4'hA, 4'h0}; // 黄 - default: - pal = {4'hA, 4'hA, 4'hA}; // 浅灰 - endcase - end - endfunction - - wire [2:0] px_color = glyph_px ? gcolor : bgcolor; - wire [2:0] px_final = cursor_box ? 3'd6 : px_color; // 6 = 黄,光标框 - wire [11:0] px_rgb = de ? pal(px_final) : 12'h000; - - always @(posedge clk or posedge reset) begin - if (reset) begin - {vga_r, vga_g, vga_b} <= 12'h000; - vga_hs <= 1'b1; - vga_vs <= 1'b1; - frame_tick_o <= 1'b0; - end - else if (tick) begin - {vga_r, vga_g, vga_b} <= px_rgb; - vga_hs <= hs_n; - vga_vs <= vs_n; - frame_tick_o <= (hx == H_TOTAL - 1) && (vy == V_TOTAL - 1); - end + 6'd14: font_row = (r == 3'd3) ? 8'hFF : (r == 3'd4) ? 8'hFF : 8'h00; // 横线 + 6'd15: font_row = 8'hFF; // 实心 + 6'd16: + font_row = (r == 3'd0) ? 8'h18 : (r == 3'd1) ? 8'h3C : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h7E : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h66 : 8'h00; // A + 6'd17: + font_row = (r == 3'd0) ? 8'h7C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h7C : 8'h00; // B + 6'd18: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h60 : + (r == 3'd3) ? 8'h60 : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h3C : 8'h00; // C + 6'd19: + font_row = (r == 3'd0) ? 8'h78 : (r == 3'd1) ? 8'h6C : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h6C : + (r == 3'd6) ? 8'h78 : 8'h00; // D + 6'd20: + font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 : + (r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 : + (r == 3'd6) ? 8'h7E : 8'h00; // E + 6'd21: + font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 : + (r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 : + (r == 3'd6) ? 8'h60 : 8'h00; // F + 6'd22: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h60 : + (r == 3'd3) ? 8'h6E : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h3E : 8'h00; // G + 6'd23: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h7E : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h66 : 8'h00; // H + 6'd24: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h18 : (r == 3'd2) ? 8'h18 : + (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 : + (r == 3'd6) ? 8'h3C : 8'h00; // I + 6'd25: + font_row = (r == 3'd0) ? 8'h1E : (r == 3'd1) ? 8'h0C : (r == 3'd2) ? 8'h0C : + (r == 3'd3) ? 8'h0C : (r == 3'd4) ? 8'h0C : (r == 3'd5) ? 8'h6C : + (r == 3'd6) ? 8'h38 : 8'h00; // J + 6'd26: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h6C : (r == 3'd2) ? 8'h78 : + (r == 3'd3) ? 8'h70 : (r == 3'd4) ? 8'h78 : (r == 3'd5) ? 8'h6C : + (r == 3'd6) ? 8'h66 : 8'h00; // K + 6'd27: + font_row = (r == 3'd0) ? 8'h60 : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 : + (r == 3'd3) ? 8'h60 : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 : + (r == 3'd6) ? 8'h7E : 8'h00; // L + 6'd28: + font_row = (r == 3'd0) ? 8'h63 : (r == 3'd1) ? 8'h77 : (r == 3'd2) ? 8'h7F : + (r == 3'd3) ? 8'h6B : (r == 3'd4) ? 8'h63 : (r == 3'd5) ? 8'h63 : + (r == 3'd6) ? 8'h63 : 8'h00; // M + 6'd29: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h76 : (r == 3'd2) ? 8'h7E : + (r == 3'd3) ? 8'h6E : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h66 : 8'h00; // N + 6'd30: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h3C : 8'h00; // O + 6'd31: + font_row = (r == 3'd0) ? 8'h7C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 : + (r == 3'd6) ? 8'h60 : 8'h00; // P + 6'd32: + font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h6E : (r == 3'd5) ? 8'h3C : + (r == 3'd6) ? 8'h0E : 8'h00; // Q + 6'd33: + font_row = (r == 3'd0) ? 8'h7C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h78 : (r == 3'd5) ? 8'h6C : + (r == 3'd6) ? 8'h66 : 8'h00; // R + 6'd34: + font_row = (r == 3'd0) ? 8'h3E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 : + (r == 3'd3) ? 8'h3C : (r == 3'd4) ? 8'h06 : (r == 3'd5) ? 8'h06 : + (r == 3'd6) ? 8'h7C : 8'h00; // S + 6'd35: + font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h18 : (r == 3'd2) ? 8'h18 : + (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 : + (r == 3'd6) ? 8'h18 : 8'h00; // T + 6'd36: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h3C : 8'h00; // U + 6'd37: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 : + (r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h3C : + (r == 3'd6) ? 8'h18 : 8'h00; // V + 6'd38: + font_row = (r == 3'd0) ? 8'h63 : (r == 3'd1) ? 8'h63 : (r == 3'd2) ? 8'h63 : + (r == 3'd3) ? 8'h6B : (r == 3'd4) ? 8'h7F : (r == 3'd5) ? 8'h77 : + (r == 3'd6) ? 8'h63 : 8'h00; // W + 6'd39: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h3C : + (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h3C : (r == 3'd5) ? 8'h66 : + (r == 3'd6) ? 8'h66 : 8'h00; // X + 6'd40: + font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h3C : + (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 : + (r == 3'd6) ? 8'h18 : 8'h00; // Y + 6'd41: + font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h06 : (r == 3'd2) ? 8'h0C : + (r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h30 : (r == 3'd5) ? 8'h60 : + (r == 3'd6) ? 8'h7E : 8'h00; // Z + default: font_row = 8'h00; + endcase end + endfunction + + wire [7:0] frow = font_row(glyph, fy); + wire glyph_px = frow[3'd7-fx]; // 1 = 画字模点 + + // --------------------------------------------------------------------------- + // 光标框:黄色、常亮、2 像素宽 + // 原来是 1 像素浅灰 + 闪动(blink 周期约 1.3 s):在白色未揭开格上几乎看不清, + // 而且截图有一半概率正好截到"灭"的那个相位。改成黄色常亮 2 像素后, + // VGA 上和图里都能一眼看到指针。想改回闪动:把 blink_q 加回来, + // 再在 cursor_box 里与上 blink 即可。 + // --------------------------------------------------------------------------- + wire cursor_here = (cursor_i[4:0] == ccol) && (cursor_i[12:8] == crow); + wire on_border = (hx[3:0] < 4'd2) || (hx[3:0] > 4'd13) || (vy[3:0] < 4'd2) || (vy[3:0] > 4'd13); + wire cursor_box = cursor_here && ctrl_i[0] && on_border; + + // --------------------------------------------------------------------------- + // 颜色(3 位调色板 -> 4:4:4 RGB) + // --------------------------------------------------------------------------- + function [11:0] pal; + input [2:0] c; + begin + case (c) + 3'd0: pal = {4'h0, 4'h0, 4'h0}; // 黑 + 3'd1: pal = {4'h0, 4'h0, 4'hA}; // 深蓝 + 3'd2: pal = {4'h0, 4'hA, 4'h0}; // 绿 + 3'd3: pal = {4'h0, 4'hA, 4'hA}; // 青 + 3'd4: pal = {4'hA, 4'h0, 4'h0}; // 红 + 3'd5: pal = {4'hA, 4'h0, 4'hA}; // 洋红 + 3'd6: pal = {4'hA, 4'hA, 4'h0}; // 黄 + default: pal = {4'hA, 4'hA, 4'hA}; // 浅灰 + endcase + end + endfunction + + wire [ 2:0] px_color = glyph_px ? gcolor : bgcolor; + wire [ 2:0] px_final = cursor_box ? 3'd6 : px_color; // 6 = 黄,光标框 + wire [11:0] px_rgb = de ? pal(px_final) : 12'h000; + + always @(posedge clk or posedge reset) begin + if (reset) begin + {vga_r, vga_g, vga_b} <= 12'h000; + vga_hs <= 1'b1; + vga_vs <= 1'b1; + frame_tick_o <= 1'b0; + end else if (tick) begin + {vga_r, vga_g, vga_b} <= px_rgb; + vga_hs <= hs_n; + vga_vs <= vs_n; + frame_tick_o <= (hx == H_TOTAL - 1) && (vy == V_TOTAL - 1); + end + end endmodule diff --git a/saolei/README.md b/saolei/README.md index 90d6483..10596c4 100644 --- a/saolei/README.md +++ b/saolei/README.md @@ -126,13 +126,14 @@ powershell -ExecutionPolicy Bypass -File tools\build.ps1 | `0x0000_1004` | 七段数码管:8 位十六进制数(低 4 位 = 最右) | | `0x0000_1100+` | 鼠标:STATUS / DATA / ACK / CTRL / INPUT / TIME / FRAME / EVCNT / LEVEL / MAGIC | | `0x0000_1140+` | 显示控制器:CTRL(光标可见、背景色)/ CURSOR(列、行)/ MAGIC | -| `0x0000_2000-0x27FF` | 显存:40 列 × 30 行、每格 1 字节(只用到前 1200 字节) | +| `0x0000_2000-0x2FFF` | 显存:40 列 × 30 行、每格 2 字节(共 2400 字节) | `LEVEL` 是**软件中断**寄存器:写 1 拉起 `irq_i[1]`(关卡入口),关卡返回前写 0 清掉, 否则下次点"开始"没有新的上升沿。`MAGIC`(`0xCAFE0001/2`)可以读来自检 MMIO 是否活着。 -格子编码 1 字节 = `[3:0] 字形 [6:4] 颜色 [7] 保留`;字形 0 空白、1..8 数字、9 未揭开、 -10 旗、11 雷、12 爆炸、13 问号、14 横线、15 实心;颜色是 3 位调色板。 +格子编码为两个字节:第一个字节低 6 位是字形编号,第二个字节低 3 位是颜色;字形 0 空白、 +1..8 数字、9 未揭开、10 旗、11 雷、12 爆炸、13 问号、14 横线、15 实心、16..41 为 A-Z; +颜色是 3 位调色板。 ## 5. 怎么跑起来 @@ -164,11 +165,11 @@ Pmod PS2 插在 JA + 一个 PS/2 鼠标)。`cpu21_ps2_mouse.v` 只实现了** ## 6. 验证状态(说实话) -| 部分 | 状态 | -| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | -| C 工具链链路 | **已实测**:编译/链接/ISA 检查/hex 生成/入口地址逐条核对 全部通过 | -| `saolei.c` / `isr.c` / `start.c` / `linker.ld` | 逻辑对着 RTL 写;**未在仿真器/硬件上跑过** | -| `cpu21_mmio.v` 扩展、`cpu21_vga.v`、`cpu21_seg7.v`、`cpu21_pointer.v`、板级顶层、XDC | **未综合、未上板** | +| 部分 | 状态 | +| ------------------------------------------------------------------------------------ | ------------------------------------------------------ | +| C 工具链链路 | 本次修改后未验证:当前环境缺少 RISC-V 交叉编译器 | +| `saolei.c` / `isr.c` / `start.c` / `linker.ld` | 本机 GCC 语法检查通过;目标 ISA 构建待工具链恢复后执行 | +| `cpu21_mmio.v` 扩展、`cpu21_vga.v`、`cpu21_seg7.v`、`cpu21_pointer.v`、板级顶层、XDC | `xvlog` 编译通过;未综合、未上板 | 建议验证顺序:① 跑 `pipelined-cpu/tools/run_regress.ps1` 确认原来的跑马灯/中断/指令 测试仍全 PASS;② 定义 `SAOLEI_ROM` 跑行为仿真,看有没有往 `0x2000` 起的显存写字节、 @@ -176,9 +177,7 @@ Pmod PS2 插在 JA + 一个 PS/2 鼠标)。`cpu21_ps2_mouse.v` 只实现了** ## 7. 已知可改进项 -- **屏幕上没有字母**:字模是 4 位字形(0-15),所以"开始"是绿色按钮条 + 光标框而不是 - "START" 字样。要显示文字就把格子编码扩成 5 位字形(`mmio.h` 的 `CELL()` 与 - `cpu21_vga.v` 的字模表各改一处,颜色降到 3 位)。 -- 棋盘固定 16×16、40 雷(16 是 2 的幂,索引全用移位,一次除法都不用);要改大小就改 - `saolei.c` 顶部的 `BW/BH/NMINES`。 +- **文字显示**:显存现在每格占 2 字节,字形编号扩展到 6 位,RTL 内置 A-Z 和数字/游戏 + 符号字模,开始界面显示 `MINES`、`EASY`、`NORMAL`、`HARD`、`START`。 +- 棋盘固定 16×16,开始界面可选 20/40/60 雷(16 是 2 的幂,索引全用移位,一次除法都不用)。 - `run_regress.ps1` 里还没有扫雷的自动测试项。 diff --git a/saolei/sw/mmio.h b/saolei/sw/mmio.h index aa65ec0..81be772 100644 --- a/saolei/sw/mmio.h +++ b/saolei/sw/mmio.h @@ -24,7 +24,7 @@ * 0x0000_1140 + 0x00 DISP_CTRL [0] 光标可见 [6:4] 背景色 * 0x0000_1140 + 0x04 DISP_CURSOR [5:0] 列 [13:8] 行 * 0x0000_1140 + 0x08 DISP_MAGIC 0xCAFE0001 - * 0x0000_2000 - 0x0000_27FF 显存:40 列 x 30 行,每格 1 字节,共 1200 字节 + * 0x0000_2000 - 0x0000_2FFF 显存:40 列 x 30 行,每格 2 字节,共 2400 字节 * * 鼠标事件单位:1/8 格(按键一次 = 8 = 移动一格;PS/2 鼠标用原始计数)。 * 左键点击 -> 事件的 btn 位 0 置 1;右键(PS/2)-> 位 1。 @@ -69,13 +69,15 @@ #define REG_R(a) (*(volatile unsigned *)((unsigned)(a))) #define REG_W(a) (*(volatile unsigned *)((unsigned)(a))) -/* 显存按字节写(只能 sb,不能 lb —— 这颗核没有 lb/lbu) */ -static inline void fb_write(unsigned idx, unsigned val) +/* 显存按字节写(只能 sb,不能 lb —— 这颗核没有 lb/lbu)。每个格子占两个字节。 */ +static inline void fb_write_cell(unsigned idx, unsigned glyph, unsigned color) { - *(volatile unsigned char *)(FB_BASE + idx) = (unsigned char)(val & 0xFFu); + unsigned addr = FB_BASE + (idx << 1); + *(volatile unsigned char *)addr = (unsigned char)(glyph & 0x3Fu); + *(volatile unsigned char *)(addr + 1u) = (unsigned char)(color & 0x07u); } -/* ---- 格子编码:1 字节 = [3:0] 字形 [6:4] 颜色 [7] 保留 ---- */ +/* ---- 格子编码:两个字节 = 字形[5:0] + 颜色[2:0] ---- */ #define G_BLANK 0u /* 空 */ #define G_N1 1u /* 数字 1..8 = 1..8 */ #define G_COVER 9u /* 未揭开 */ @@ -86,6 +88,34 @@ static inline void fb_write(unsigned idx, unsigned val) #define G_BAR 14u /* 横线 */ #define G_SOLID 15u /* 实心 */ +/* 大写字母字形编号 16..41,供菜单文字使用。 */ +#define G_A 16u +#define G_B 17u +#define G_C 18u +#define G_D 19u +#define G_E 20u +#define G_F 21u +#define G_G 22u +#define G_H 23u +#define G_I 24u +#define G_J 25u +#define G_K 26u +#define G_L 27u +#define G_M 28u +#define G_N 29u +#define G_O 30u +#define G_P 31u +#define G_Q 32u +#define G_R 33u +#define G_S 34u +#define G_T 35u +#define G_U 36u +#define G_V 37u +#define G_W 38u +#define G_X 39u +#define G_Y 40u +#define G_Z 41u + #define C_BLACK 0u #define C_BLUE 1u #define C_GREEN 2u @@ -95,8 +125,6 @@ static inline void fb_write(unsigned idx, unsigned val) #define C_YELLOW 6u #define C_GRAY 7u -#define CELL(g, c) ((unsigned)((g) | ((c) << 4))) - /* ---- 软件事件环形队列:中断服务程序(isr.c)生产,主循环(saolei.c)消费 ---- */ #define EVQ_SIZE 64u #define EVQ_MASK (EVQ_SIZE - 1u) diff --git a/saolei/sw/saolei.c b/saolei/sw/saolei.c index 9984e4a..669f9c8 100644 --- a/saolei/sw/saolei.c +++ b/saolei/sw/saolei.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- * saolei.c —— 纯 C 扫雷(RV32IM 子集:只用这颗核实现了的指令) * - * 显示:把每个格子写成显存里的 1 个字节(MMIO 0x2000 起) + * 显示:把每个格子写成显存里的 2 个字节(MMIO 0x2000 起) * 输入:鼠标事件(中断驱动)——中断里搬到软件队列,主循环在下面处理 * * 针对这颗 CPU 的硬约束(很重要,改代码时别踩): @@ -13,15 +13,14 @@ * 所以本文件所有索引运算都用"2 的幂 + 移位/掩码",一次除法都不用。 * 4) 没有 fence/ebreak 等;中断返回是 uret(在 isr.c 里)。 * - * 棋盘:16 x 16,40 颗雷(16 是 2 的幂 => 索引全用移位,颜色/字形查表也不用除法) + * 棋盘:16 x 16,雷数可选 20/40/60(16 是 2 的幂 => 索引全用移位) * 网格:40 列 x 30 行,棋盘居中放在 (行 7..22, 列 12..27) * ---------------------------------------------------------------------------*/ #include "mmio.h" -#define BW 16u /* 棋盘宽(格) */ -#define BH 16u /* 棋盘高(格) */ -#define NCELLS (BW * BH) /* 256 */ -#define NMINES 40u +#define BW 16u /* 棋盘宽(格) */ +#define BH 16u /* 棋盘高(格) */ +#define NCELLS (BW * BH) /* 256 */ #define BM_WORDS (NCELLS / 32u) /* 8 */ #define BOARD_C0 12u /* 棋盘左上角在网格里的列 */ @@ -42,6 +41,8 @@ static unsigned opened_cnt; static unsigned flags_cnt; static unsigned g_state; static unsigned g_first_done; +static unsigned g_mines; +static unsigned g_difficulty; static unsigned rnd_state; static unsigned cur_r, cur_c; /* 光标所在的网格格 */ static int acc_x, acc_y; /* 指针累积量(1/8 格,有符号) */ @@ -67,7 +68,7 @@ static void bclr(unsigned *bm, unsigned i) static void draw_cell(unsigned gr, unsigned gc, unsigned glyph, unsigned color) { - fb_write(gr * GRID_COLS + gc, CELL(glyph, color)); + fb_write_cell(gr * GRID_COLS + gc, glyph, color); } /* 把棋盘格 (r,c) 画出来 */ @@ -118,6 +119,15 @@ static unsigned rnd_next(void) return rnd_state >> 16; } +static unsigned difficulty_mines(unsigned difficulty) +{ + if (difficulty == 0u) + return 20u; + if (difficulty == 2u) + return 60u; + return 40u; +} + /* ============================ 画面 ============================ */ static void clear_screen(void) @@ -125,7 +135,7 @@ static void clear_screen(void) unsigned i; for (i = 0u; i < (GRID_COLS * GRID_ROWS); i = i + 1u) { - fb_write(i, 0u); + fb_write_cell(i, G_BLANK, C_BLACK); } } @@ -278,7 +288,7 @@ static void reveal_at(unsigned i) } } - if (opened_cnt == (NCELLS - NMINES)) + if (opened_cnt == (NCELLS - g_mines)) win(); } @@ -288,7 +298,7 @@ static void place_mines(unsigned safe) unsigned sr = safe >> 4; unsigned sc = safe & 15u; - while (placed < NMINES) + while (placed < g_mines) { i = rnd_next() & 255u; /* NCELLS = 256,正好 2 的幂,不需要取模 */ r = i >> 4; @@ -347,7 +357,7 @@ static void toggle_flag(void) flags_cnt = flags_cnt + 1u; draw_tile(r, c, G_FLAG, C_YELLOW); } - REG_W(LED_ADDR) = NMINES - flags_cnt; + REG_W(LED_ADDR) = g_mines - flags_cnt; } /* ============================ 鼠标事件 ============================ */ @@ -385,6 +395,11 @@ static unsigned g_exit; /* 关卡内请求返回 */ #define START_R 20u #define START_C0 17u #define START_C1 22u +#define DIFF_EASY_R 14u +#define DIFF_NORMAL_R 16u +#define DIFF_HARD_R 18u + +static void draw_start_screen(void); /* 背景用:光标可以在整个画面上移动 */ static void move_cursor_screen(int dr, int dc) @@ -420,10 +435,29 @@ static void handle_event(unsigned ev) { /* 左键 */ if (g_in_level == 0u) { + if (cur_r == DIFF_EASY_R) + { + g_difficulty = 0u; + draw_start_screen(); + return; + } + if (cur_r == DIFF_NORMAL_R) + { + g_difficulty = 1u; + draw_start_screen(); + return; + } + if (cur_r == DIFF_HARD_R) + { + g_difficulty = 2u; + draw_start_screen(); + return; + } /* 背景:点到"开始"按钮 -> 拉起软件中断,跳到 IRQ1 里的关卡程序 */ if ((cur_r == START_R) && (cur_c >= START_C0) && (cur_c <= START_C1)) { g_in_level = 1u; /* 关卡程序返回时自己清 0 */ + g_mines = difficulty_mines(g_difficulty); REG_W(REG_LEVEL) = 1u; } } @@ -490,24 +524,55 @@ static void handle_event(unsigned ev) * ========================================================================== */ static void draw_start_screen(void) { - unsigned i; + unsigned i, selected_color; clear_screen(); - /* 标题区:两排雷图案,纯图形(字模里没有字母;要显示文字就得扩字模,见 README) */ - for (i = 0u; i < 6u; i = i + 1u) - { - draw_cell(6u, 15u + i * 2u, G_MINE, C_RED); - draw_cell(8u, 15u + i * 2u, G_MINE, C_RED); - } + /* 标题和难度菜单使用 RTL 字模中的大写字母。 */ + draw_cell(6u, 18u, G_M, C_RED); + draw_cell(6u, 19u, G_I, C_RED); + draw_cell(6u, 20u, G_N, C_RED); + draw_cell(6u, 21u, G_E, C_RED); + draw_cell(6u, 22u, G_S, C_RED); - /* "开始"按钮:绿色实心条,上下各一条黄线框住它 */ + selected_color = C_YELLOW; + if (g_difficulty != 0u) + selected_color = C_GRAY; + draw_cell(DIFF_EASY_R, 18u, G_E, selected_color); + draw_cell(DIFF_EASY_R, 19u, G_A, selected_color); + draw_cell(DIFF_EASY_R, 20u, G_S, selected_color); + draw_cell(DIFF_EASY_R, 21u, G_Y, selected_color); + + selected_color = C_YELLOW; + if (g_difficulty != 1u) + selected_color = C_GRAY; + draw_cell(DIFF_NORMAL_R, 16u, G_N, selected_color); + draw_cell(DIFF_NORMAL_R, 17u, G_O, selected_color); + draw_cell(DIFF_NORMAL_R, 18u, G_R, selected_color); + draw_cell(DIFF_NORMAL_R, 19u, G_M, selected_color); + draw_cell(DIFF_NORMAL_R, 20u, G_A, selected_color); + draw_cell(DIFF_NORMAL_R, 21u, G_L, selected_color); + + selected_color = C_YELLOW; + if (g_difficulty != 2u) + selected_color = C_GRAY; + draw_cell(DIFF_HARD_R, 18u, G_H, selected_color); + draw_cell(DIFF_HARD_R, 19u, G_A, selected_color); + draw_cell(DIFF_HARD_R, 20u, G_R, selected_color); + draw_cell(DIFF_HARD_R, 21u, G_D, selected_color); + + /* "START" 按钮:绿色实心条,上下各一条黄线框住它。 */ for (i = START_C0; i <= START_C1; i = i + 1u) { draw_cell(START_R - 1u, i, G_BAR, C_YELLOW); draw_cell(START_R, i, G_SOLID, C_GREEN); draw_cell(START_R + 1u, i, G_BAR, C_YELLOW); } + draw_cell(START_R, 17u, G_S, C_BLACK); + draw_cell(START_R, 18u, G_T, C_BLACK); + draw_cell(START_R, 19u, G_A, C_BLACK); + draw_cell(START_R, 20u, G_R, C_BLACK); + draw_cell(START_R, 21u, G_T, C_BLACK); /* 下方提示条 */ for (i = 12u; i <= 27u; i = i + 1u) @@ -561,10 +626,10 @@ void level_main(void) draw_frame(); draw_all_covered(); draw_cell(RET_R, RET_C, G_BAR, C_YELLOW); /* 左上角黄格 = 返回 */ - set_bg(C_BLUE); + set_bg(C_BLACK); update_cursor_reg(); - REG_W(LED_ADDR) = NMINES; - REG_W(REG_SEG) = NMINES; /* 数码管显示剩余雷数 */ + REG_W(LED_ADDR) = g_mines; + REG_W(REG_SEG) = g_mines; /* 数码管显示剩余雷数 */ /* ---- 关卡主循环 ---- */ while (g_exit == 0u) @@ -595,7 +660,7 @@ void level_main(void) } else { - set_bg(C_BLUE); + set_bg(C_BLACK); } } } @@ -615,6 +680,7 @@ int main(void) crt_zero_bss(); /* 清 .bss(上电 RAM 本来就是 0,保险起见) */ rnd_state = REG_R(REG_TIME) | 1u; /* 用自由计数器当随机种子 */ + g_difficulty = 1u; /* 默认普通:40 颗雷 */ REG_W(REG_MCTRL) = 1u; /* 打开鼠标中断(IRQ2,入口 0x200) */ REG_W(REG_LEVEL) = 0u; /* 清关卡软中断 */ diff --git a/saolei/tools/build.ps1 b/saolei/tools/build.ps1 index da7dc7a..9516dd6 100644 --- a/saolei/tools/build.ps1 +++ b/saolei/tools/build.ps1 @@ -58,6 +58,11 @@ $OBJDUMP = $Prefix + 'objdump' $OBJCOPY = $Prefix + 'objcopy' $SIZE = $Prefix + 'size' +$Python = 'py' +if (-not (Get-Command $Python -ErrorAction SilentlyContinue)) { + $Python = 'python' +} + Write-Output "工具链前缀: $Prefix" # ---------------------------------------------------------------- 编译参数 @@ -139,7 +144,7 @@ Write-Output "反汇编清单: $lst" $isaOk = $true if (-not $SkipIsaCheck) { Write-Output "" - & py (Join-Path $PSScriptRoot 'check_isa.py') $lst + & $Python (Join-Path $PSScriptRoot 'check_isa.py') $lst if ($LASTEXITCODE -ne 0) { $isaOk = $false } } @@ -149,7 +154,7 @@ $hex = Join-Path $build 'saolei.hex' $vh = Join-Path $root '..\pipelined-cpu\srcs\board\cpu21_saolei_rom.vh' & $OBJCOPY -O binary $elf $bin -& py (Join-Path $PSScriptRoot 'elf2hex.py') $bin $hex $RomWords $vh +& $Python (Join-Path $PSScriptRoot 'elf2hex.py') $bin $hex $RomWords $vh # ---------------------------------------------------------------- 汇总 Write-Output ""