From e44680a114b40901a1d49421d35d77254d6a8671 Mon Sep 17 00:00:00 2001 From: Alex-create-beep <2965312221@qq.com> Date: Sat, 19 Sep 2026 16:09:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(board):=20=E6=96=B0=E5=A2=9E=E8=AF=BE?= =?UTF-8?q?=E7=A8=8B=E6=96=B0=E7=89=88=E4=B8=AD=E6=96=AD=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=B8=8A=E6=9D=BF=EF=BC=88=E5=A4=9A=E7=BA=A7=E4=B8=AD=E6=96=AD?= =?UTF-8?q?=20+=20=E9=99=84=E5=8A=A0=20SLL/SB/BLTU=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - programs/risc-v-intrupt-sllsb.asm/.hex: 课程原始程序(344 字,hex 已去掉 Logisim 的 v2.0 raw 头),保留原文件以便追溯 - tools/adapt_intrupt_sllsb.py: 把它适配到本 CPU 上板(只改 ROM 内容,地址不变) - 课程用 addi a7,zero,34 + ecall 显示,本 CPU 里那是空操作 -> 每条显示点原地换成 一次调用:主程序 jal ra,DISP_DLY;ISR 用 add a7,a0,zero + jal a0,DISP_DLY_ISR (三个 ISR 都没保存 ra,所以 ISR 版把链接寄存器放 a0、显示值放 a7) - DISP_DLY / DISP_DLY_ISR 各 8 条,追加在 uret 之后,中断入口 0x0AC/0x240/0x3E8 不变 - 返回地址存 sp+256(越过 ISR 最多 192 字节的栈区),嵌套中断也破坏不了 - 脚本自带跳转目标自检(曾发现 ISR 侧 jal 偏移少算一条指令的问题) - srcs/board/cpu21_board_top.v: 新增 RISC_V_INTRUPT_SLLSB_ROM 分支(ROM 选择、 CPU 分频用 CLK_DIV_INTRUPT、中断向量 0x0AC/0x240/0x3E8) - srcs/board/risc-v-intrupt-sllsb.vh: 生成的 ROM 初始化(1024 字,程序 360 字) - create_project.tcl: 新增 use_intrupt_sllsb 开关(默认 1,已把 ccab 置 0) 实测:Vivado 2020.2 建工程 + 综合通过(sources_1 verilog_define = RISC_V_INTRUPT_SLLSB_ROM,synth_design Complete! 100%) --- pipelined-cpu/create_project.tcl | 33 +- .../programs/risc-v-intrupt-sllsb.asm | 477 ++++++++ .../programs/risc-v-intrupt-sllsb.hex | 344 ++++++ pipelined-cpu/srcs/board/cpu21_board_top.v | 743 ++++++------ .../srcs/board/risc-v-intrupt-sllsb.vh | 1026 +++++++++++++++++ pipelined-cpu/tools/adapt_intrupt_sllsb.py | 222 ++++ 6 files changed, 2483 insertions(+), 362 deletions(-) create mode 100644 pipelined-cpu/programs/risc-v-intrupt-sllsb.asm create mode 100644 pipelined-cpu/programs/risc-v-intrupt-sllsb.hex create mode 100644 pipelined-cpu/srcs/board/risc-v-intrupt-sllsb.vh create mode 100644 pipelined-cpu/tools/adapt_intrupt_sllsb.py diff --git a/pipelined-cpu/create_project.tcl b/pipelined-cpu/create_project.tcl index 97d95a1..bbd81e4 100644 --- a/pipelined-cpu/create_project.tcl +++ b/pipelined-cpu/create_project.tcl @@ -71,9 +71,14 @@ add_files -norecurse -fileset sources_1 [list \ set_property file_type {Verilog Header} \ [get_files "$origin_dir/srcs/board/cpu21_board_rom.vh"] -# 默认跑哪个内置程序:中断测试程序优先,其次是扫雷,最后是走马灯 demo。 -# 修改下面两个开关即可切换板上程序;同一时间只应启用一个。 -set use_intrupt_ccab 1 +# 默认跑哪个内置程序(同一时间只应启用一个): +# use_intrupt_sllsb = 1 -> 课程新版「多级中断测试 + 附加 SLL/SB/BLTU」 +# (programs/risc-v-intrupt-sllsb.asm / .hex) +# use_intrupt_ccab = 1 -> 上一版中断测试(programs/risc-v-intrupt-ccab.*) +# use_saolei = 1 -> 扫雷(saolei/tools/build.ps1 生成) +# 三个都为 0 -> 走马灯 demo +set use_intrupt_sllsb 1 +set use_intrupt_ccab 0 set use_saolei 0 # 中断测试程序的 ROM 初始化。 @@ -85,6 +90,15 @@ if {[file exists $intrupt_ccab_rom]} { puts "NOTE: 还没有 $intrupt_ccab_rom" } +# 课程新版中断测试(附加 SLL/SB/BLTU)的 ROM 初始化。 +set intrupt_sllsb_rom "$origin_dir/srcs/board/risc-v-intrupt-sllsb.vh" +if {[file exists $intrupt_sllsb_rom]} { + add_files -norecurse -fileset sources_1 [list $intrupt_sllsb_rom] + set_property file_type {Verilog Header} [get_files $intrupt_sllsb_rom] +} else { + puts "NOTE: 还没有 $intrupt_sllsb_rom(用 tools/hex2vh.py 生成)" +} + # 扫雷程序的 ROM 初始化(由 saolei/tools/build.ps1 生成,可能还不存在)。 # 综合/仿真时定义宏 SAOLEI_ROM 就会用它替换上面的跑马灯 ROM。 set saolei_rom "$origin_dir/srcs/board/cpu21_saolei_rom.vh" @@ -95,9 +109,12 @@ if {[file exists $saolei_rom]} { puts "NOTE: 还没有 $saolei_rom —— 需要先跑 saolei/tools/build.ps1 生成" } -# 关键:sources_1 定义 SAOLEI_ROM,cpu21_board_top.v 里的 `ifdef 链才会用扫雷 ROM -# (该宏只影响综合用的 sources_1,仿真 fileset 仍各自用 tb 自带的 ROM) -if {$use_intrupt_ccab && [file exists $intrupt_ccab_rom]} { +# 关键:sources_1 里定义对应宏,cpu21_board_top.v 的 `ifdef 链才会选中那个 ROM +# (宏只影响综合用的 sources_1;仿真 fileset 仍各自用 tb 自带的 ROM) +if {$use_intrupt_sllsb && [file exists $intrupt_sllsb_rom]} { + set_property verilog_define {RISC_V_INTRUPT_SLLSB_ROM} [get_filesets sources_1] + puts "NOTE: sources_1 已定义 RISC_V_INTRUPT_SLLSB_ROM —— 上板跑「中断测试 + SLL/SB/BLTU」" +} elseif {$use_intrupt_ccab && [file exists $intrupt_ccab_rom]} { set_property verilog_define {RISC_V_INTRUPT_CCAB_ROM} [get_filesets sources_1] puts "NOTE: sources_1 已定义 RISC_V_INTRUPT_CCAB_ROM —— 上板跑 risc-v-intrupt-ccab" } elseif {$use_saolei && [file exists $saolei_rom]} { @@ -142,7 +159,9 @@ foreach fs {sim_1 sim_2} { # ---------------------------------------------------------------- 结果汇总 puts "工程已创建:$origin_dir/$proj_name.xpr" puts " sources_1 顶层 = cpu21_board_top(上板:时钟分频 + 片内 ROM/RAM + 引脚)" -if {$use_intrupt_ccab && [file exists $intrupt_ccab_rom]} { +if {$use_intrupt_sllsb && [file exists $intrupt_sllsb_rom]} { + set selected_program {risc-v-intrupt-sllsb (RISC_V_INTRUPT_SLLSB_ROM) 中断+SLL/SB/BLTU} +} elseif {$use_intrupt_ccab && [file exists $intrupt_ccab_rom]} { set selected_program {risc-v-intrupt-ccab (RISC_V_INTRUPT_CCAB_ROM)} } elseif {$use_saolei && [file exists $saolei_rom]} { set selected_program {扫雷 (SAOLEI_ROM)} diff --git a/pipelined-cpu/programs/risc-v-intrupt-sllsb.asm b/pipelined-cpu/programs/risc-v-intrupt-sllsb.asm new file mode 100644 index 0000000..03c449c --- /dev/null +++ b/pipelined-cpu/programs/risc-v-intrupt-sllsb.asm @@ -0,0 +1,477 @@ +.text +addi sp, zero, 2000 #�ڴ��ջ��ʼ�� + +############################################################# +#�����Ʋ�?,����addi,andi,slli,srli,srai,or,ori,nor,ecall LED�������Ʒ�ʽ������ʾ���� +############################################################# + +.text +START: + +addi s0,zero,1 +slli s3, s0, 31 # s3=0x80000000 +srai s3, s3, 31 # s3=0xFFFFFFFF +add s0,zero,zero # s0=0 +addi s2,zero,12 + +addi s6,zero,8 #�����Ƽ��� +zmd_loop: + +addi s0, s0, 1 #������һ�������Ƶ��� +andi s0, s0, 15 + +####################################### +addi t0,zero,8 +addi t1,zero,1 +left: + +slli s3, s3, 4 #���������� +or s3, s3, s0 + +add a0,zero,s3 # display s3 +addi a7,zero,34 # system call for LED display +ecall # display + +sub t0,t0,t1 +bne t0,zero,left +####################################### + +addi s0, s0, 1 #������һ�������Ƶ��� +addi t6,zero,15 +and s0, s0, t6 +slli s0, s0, 28 + +addi t0,zero,8 +addi t1,zero,1 + +zmd_right: + +srli s3, s3, 4 #���������� +or s3, s3, s0 + +add a0,zero,s3 # display s3 +addi a7,zero,34 # system call for LED display +ecall # display + +sub t0,t0,t1 +bne t0,zero,zmd_right +srli s0, s0, 28 +####################################### + +sub s6,s6,t1 +beq s6,zero, exit +j zmd_loop + +exit: + +add t0,zero,zero +xori t0,t0,-1 #test nor ori +slli t0,t0,16 +ori t0,t0,-1 + +add a0,zero,t0 # display t0 +addi a7,zero,34 # system call for LED display +ecall # display + +j START # loop forever + + +#InteruptProgram1: +############################################################################################# +# exceptoin 1 +# ʹ��?s6? s5?s4?s3?s0?a0?a7 +############################################################################################# + +################# �����ֳ� +InteruptProgram1:sw a7, 0(sp) +addi sp, sp, 4 +sw a0, 0(sp) +addi sp, sp, 4 +sw s0, 0(sp) +addi sp, sp, 4 +sw s3, 0(sp) +addi sp, sp, 4 +sw s4, 0(sp) +addi sp, sp, 4 +sw s5, 0(sp) +addi sp, sp, 4 +sw s6, 0(sp) +addi sp, sp, 4 + +csrrsi s6,0x41,0 #s6=uepc +sw s6, 0(sp) #uepcѹջ���� +addi sp, sp, 4 + + +################# ���ж� + sw t0,0(sp) + addi sp,sp,4 + sw t1,0(sp) + addi sp,sp,4 + sw t2,0(sp) + addi sp,sp,4 + sw t3,0(sp) + addi sp,sp,4 + sw t4,0(sp) + addi sp,sp,4 + sw t5,0(sp) + addi sp,sp,4 + sw t6,0(sp) + addi sp,sp,4 + sw s1,0(sp) + addi sp,sp,4 + sw s2,0(sp) + addi sp,sp,4 +csrrsi zero,0x4,1 #ustatus.MIE=1 + +################# �жϷ��� +addi s6,zero,1 #�ж�?1,2,3 ��ͬ�жϺ���ʾֵ��һ�� +addi s4,zero,3 #ѭ��������ʼֵ +addi s5,zero,1 #�������ۼ�ֵ + +IntLoop1: +add s0,zero,s6 + +IntLeftShift1: + +slli s0, s0, 4 +or s3,s0,s4 +add a0,zero,s3 #display s0 +addi a7,zero,34 # display hex +ecall + +bne s0, zero, IntLeftShift1 +sub s4,s4,s5 #ѭ�������ݼ� +bne s4, zero, IntLoop1 + +################# ���ж� +csrrci zero,0x4,1 #ustatus.MIE=0 +############### ����ָ�� ����(SLL/SB/BLTU ֮һ) ############### + addi t0,zero,1 + addi t1,zero,3 + addi s1,zero,0x8 + slli s1,s1,8 + addi s1,s1,0x76 + add a0,zero,s1 + addi a7,zero,34 + ecall + addi t3,zero,8 +sll_branch: + sll s1,s1,t0 + sll s1,s1,t1 + add a0,zero,s1 + addi a7,zero,34 + ecall + addi t3,t3,-1 + bne t3,zero,sll_branch + addi sp,sp,-4 + lw s2,0(sp) + addi sp,sp,-4 + lw s1,0(sp) + addi sp,sp,-4 + lw t6,0(sp) + addi sp,sp,-4 + lw t5,0(sp) + addi sp,sp,-4 + lw t4,0(sp) + addi sp,sp,-4 + lw t3,0(sp) + addi sp,sp,-4 + lw t2,0(sp) + addi sp,sp,-4 + lw t1,0(sp) + addi sp,sp,-4 + lw t0,0(sp) + +################# �ָ��ֳ� +addi sp, sp, -4 +lw s6, 0(sp) + +csrrw zero,0x41,s6 #uepc=s6 + +addi sp, sp, -4 +lw s6, 0(sp) +addi sp, sp, -4 +lw s5, 0(sp) +addi sp, sp, -4 +lw s4, 0(sp) +addi sp, sp, -4 +lw s3, 0(sp) +addi sp, sp, -4 +lw s0, 0(sp) +addi sp, sp, -4 +lw a0, 0(sp) +addi sp, sp, -4 +lw a7, 0(sp) + +################ �жϷ��� +uret #ͬ�����жϣ�uepc-->pc + + +#InteruptProgram2: +############################################################################################# +# exceptoin 2 +# ʹ��?s6? s5?s4?s3?s0?a0?a7 +############################################################################################# + +################# �����ֳ� +InteruptProgram2:sw a7, 0(sp) +addi sp, sp, 4 +sw a0, 0(sp) +addi sp, sp, 4 +sw s0, 0(sp) +addi sp, sp, 4 +sw s3, 0(sp) +addi sp, sp, 4 +sw s4, 0(sp) +addi sp, sp, 4 +sw s5, 0(sp) +addi sp, sp, 4 +sw s6, 0(sp) +addi sp, sp, 4 + +csrrsi s6,0x41,0 #s6=uepc +sw s6, 0(sp) #uepcѹջ���� +addi sp, sp, 4 + + +################# ���ж� + sw t0,0(sp) + addi sp,sp,4 + sw t1,0(sp) + addi sp,sp,4 + sw t2,0(sp) + addi sp,sp,4 + sw t3,0(sp) + addi sp,sp,4 + sw t4,0(sp) + addi sp,sp,4 + sw t5,0(sp) + addi sp,sp,4 + sw t6,0(sp) + addi sp,sp,4 + sw s1,0(sp) + addi sp,sp,4 + sw s2,0(sp) + addi sp,sp,4 +csrrsi zero,0x4,1 #ustatus.MIE=1 + +################# �жϷ��� + +addi s6,zero,2 #�ж�?1,2,3 ��ͬ�жϺ���ʾֵ��һ�� + +addi s4,zero,3 #ѭ��������ʼֵ +addi s5,zero,1 #�������ۼ�ֵ + +IntLoop2: +add s0,zero,s6 + +IntLeftShift2: + + +slli s0, s0, 4 +or s3,s0,s4 +add a0,zero,s3 #display s0 +addi a7,zero,34 # display hex +ecall + +bne s0, zero, IntLeftShift2 +sub s4,s4,s5 #ѭ�������ݼ� +bne s4, zero, IntLoop2 + +################# ���ж� +csrrci zero,0x4,1 #ustatus.MIE=0 +############### ����ָ�� ����(SLL/SB/BLTU ֮һ) ############### + addi t1,zero,0 + addi t3,zero,32 + addi s1,zero,0x00 + addi s2,zero,0x01 +sb_store: + sb s1,0(t1) + add a0,zero,s1 + addi a7,zero,34 + ecall + add s1,s1,s2 + addi t1,t1,1 + addi t3,t3,-1 + bne t3,zero,sb_store + addi t3,zero,8 + addi t1,zero,0 +sb_branch: + lw s1,0(t1) + add a0,zero,s1 + addi a7,zero,34 + ecall + addi t1,t1,4 + addi t3,t3,-1 + bne t3,zero,sb_branch + addi sp,sp,-4 + lw s2,0(sp) + addi sp,sp,-4 + lw s1,0(sp) + addi sp,sp,-4 + lw t6,0(sp) + addi sp,sp,-4 + lw t5,0(sp) + addi sp,sp,-4 + lw t4,0(sp) + addi sp,sp,-4 + lw t3,0(sp) + addi sp,sp,-4 + lw t2,0(sp) + addi sp,sp,-4 + lw t1,0(sp) + addi sp,sp,-4 + lw t0,0(sp) + +################# �ָ��ֳ� + + +addi sp, sp, -4 +lw s6, 0(sp) +csrrw zero,0x41,s6 #uepc=s6 + +addi sp, sp, -4 +lw s6, 0(sp) +addi sp, sp, -4 +lw s5, 0(sp) +addi sp, sp, -4 +lw s4, 0(sp) +addi sp, sp, -4 +lw s3, 0(sp) +addi sp, sp, -4 +lw s0, 0(sp) +addi sp, sp, -4 +lw a0, 0(sp) +addi sp, sp, -4 +lw a7, 0(sp) + +################ �жϷ��� +uret #ͬ�����жϣ�uepc-->pc + + +#InteruptProgram3: +############################################################################################# +# exceptoin 3 +# ʹ��?s6? s5?s4?s3?s0?a0?a7 +############################################################################################# + + +################# �����ֳ� +InteruptProgram3:sw a7, 0(sp) +addi sp, sp, 4 +sw a0, 0(sp) +addi sp, sp, 4 +sw s0, 0(sp) +addi sp, sp, 4 +sw s3, 0(sp) +addi sp, sp, 4 +sw s4, 0(sp) +addi sp, sp, 4 +sw s5, 0(sp) +addi sp, sp, 4 +sw s6, 0(sp) +addi sp, sp, 4 + +csrrsi s6,0x41,0 #s6=uepc +sw s6, 0(sp) #uepcѹջ���� +addi sp, sp, 4 + + +################# ���ж� + sw t0,0(sp) + addi sp,sp,4 + sw t1,0(sp) + addi sp,sp,4 + sw t2,0(sp) + addi sp,sp,4 + sw t3,0(sp) + addi sp,sp,4 + sw t4,0(sp) + addi sp,sp,4 + sw t5,0(sp) + addi sp,sp,4 + sw t6,0(sp) + addi sp,sp,4 + sw s1,0(sp) + addi sp,sp,4 + sw s2,0(sp) + addi sp,sp,4 +csrrsi zero,0x4,1 #ustatus.MIE=1 + +################# �жϷ��� +addi s6,zero,3 #�ж�?1,2,3 ��ͬ�жϺ���ʾֵ��һ�� +addi s4,zero,3 #ѭ��������ʼֵ +addi s5,zero,1 #�������ۼ�ֵ + +IntLoop3: +add s0,zero,s6 + +IntLeftShift3: + +slli s0, s0, 4 +or s3,s0,s4 +add a0,zero,s3 #display s0 +addi a7,zero,34 # display hex +ecall + +bne s0, zero, IntLeftShift3 +sub s4,s4,s5 #ѭ�������ݼ� +bne s4, zero, IntLoop3 + +################# ���ж� +csrrci zero,0x4,1 #ustatus.MIE=0 +############### ����ָ�� ����(SLL/SB/BLTU ֮һ) ############### + addi s1,zero,-15 +bltu_branch: + add a0,zero,s1 + addi a7,zero,34 + ecall + addi s1,s1,1 + bltu zero,s1,bltu_branch + add a0,zero,s1 + addi a7,zero,34 + ecall + addi sp,sp,-4 + lw s2,0(sp) + addi sp,sp,-4 + lw s1,0(sp) + addi sp,sp,-4 + lw t6,0(sp) + addi sp,sp,-4 + lw t5,0(sp) + addi sp,sp,-4 + lw t4,0(sp) + addi sp,sp,-4 + lw t3,0(sp) + addi sp,sp,-4 + lw t2,0(sp) + addi sp,sp,-4 + lw t1,0(sp) + addi sp,sp,-4 + lw t0,0(sp) + +################# �ָ��ֳ� + +addi sp, sp, -4 +lw s6, 0(sp) +csrrw zero,0x41,s6 #uepc=s6 + +addi sp, sp, -4 +lw s6, 0(sp) +addi sp, sp, -4 +lw s5, 0(sp) +addi sp, sp, -4 +lw s4, 0(sp) +addi sp, sp, -4 +lw s3, 0(sp) +addi sp, sp, -4 +lw s0, 0(sp) +addi sp, sp, -4 +lw a0, 0(sp) +addi sp, sp, -4 +lw a7, 0(sp) + +################ �жϷ��� +uret #ͬ�����жϣ�uepc-->pc + diff --git a/pipelined-cpu/programs/risc-v-intrupt-sllsb.hex b/pipelined-cpu/programs/risc-v-intrupt-sllsb.hex new file mode 100644 index 0000000..e3c4003 --- /dev/null +++ b/pipelined-cpu/programs/risc-v-intrupt-sllsb.hex @@ -0,0 +1,344 @@ +7d000113 +00100413 +01f41993 +41f9d993 +00000433 +00c00913 +00800b13 +00140413 +00f47413 +00800293 +00100313 +00499993 +0089e9b3 +01300533 +02200893 +00000073 +406282b3 +fe0294e3 +00140413 +00f00f93 +01f47433 +01c41413 +00800293 +00100313 +0049d993 +0089e9b3 +01300533 +02200893 +00000073 +406282b3 +fe0294e3 +01c45413 +406b0b33 +000b0463 +f95ff06f +000002b3 +fff2c293 +01029293 +fff2e293 +00500533 +02200893 +00000073 +f5dff06f +01112023 +00410113 +00a12023 +00410113 +00812023 +00410113 +01312023 +00410113 +01412023 +00410113 +01512023 +00410113 +01612023 +00410113 +04106b73 +01612023 +00410113 +00512023 +00410113 +00612023 +00410113 +00712023 +00410113 +01c12023 +00410113 +01d12023 +00410113 +01e12023 +00410113 +01f12023 +00410113 +00912023 +00410113 +01212023 +00410113 +0040e073 +00100b13 +00300a13 +00100a93 +01600433 +00441413 +014469b3 +01300533 +02200893 +00000073 +fe0416e3 +415a0a33 +fe0a10e3 +0040f073 +00100293 +00300313 +00800493 +00849493 +07648493 +00900533 +02200893 +00000073 +00800e13 +005494b3 +006494b3 +00900533 +02200893 +00000073 +fffe0e13 +fe0e14e3 +ffc10113 +00012903 +ffc10113 +00012483 +ffc10113 +00012f83 +ffc10113 +00012f03 +ffc10113 +00012e83 +ffc10113 +00012e03 +ffc10113 +00012383 +ffc10113 +00012303 +ffc10113 +00012283 +ffc10113 +00012b03 +041b1073 +ffc10113 +00012b03 +ffc10113 +00012a83 +ffc10113 +00012a03 +ffc10113 +00012983 +ffc10113 +00012403 +ffc10113 +00012503 +ffc10113 +00012883 +00200073 +01112023 +00410113 +00a12023 +00410113 +00812023 +00410113 +01312023 +00410113 +01412023 +00410113 +01512023 +00410113 +01612023 +00410113 +04106b73 +01612023 +00410113 +00512023 +00410113 +00612023 +00410113 +00712023 +00410113 +01c12023 +00410113 +01d12023 +00410113 +01e12023 +00410113 +01f12023 +00410113 +00912023 +00410113 +01212023 +00410113 +0040e073 +00200b13 +00300a13 +00100a93 +01600433 +00441413 +014469b3 +01300533 +02200893 +00000073 +fe0416e3 +415a0a33 +fe0a10e3 +0040f073 +00000313 +02000e13 +00000493 +00100913 +00930023 +00900533 +02200893 +00000073 +012484b3 +00130313 +fffe0e13 +fe0e12e3 +00800e13 +00000313 +00032483 +00900533 +02200893 +00000073 +00430313 +fffe0e13 +fe0e14e3 +ffc10113 +00012903 +ffc10113 +00012483 +ffc10113 +00012f83 +ffc10113 +00012f03 +ffc10113 +00012e83 +ffc10113 +00012e03 +ffc10113 +00012383 +ffc10113 +00012303 +ffc10113 +00012283 +ffc10113 +00012b03 +041b1073 +ffc10113 +00012b03 +ffc10113 +00012a83 +ffc10113 +00012a03 +ffc10113 +00012983 +ffc10113 +00012403 +ffc10113 +00012503 +ffc10113 +00012883 +00200073 +01112023 +00410113 +00a12023 +00410113 +00812023 +00410113 +01312023 +00410113 +01412023 +00410113 +01512023 +00410113 +01612023 +00410113 +04106b73 +01612023 +00410113 +00512023 +00410113 +00612023 +00410113 +00712023 +00410113 +01c12023 +00410113 +01d12023 +00410113 +01e12023 +00410113 +01f12023 +00410113 +00912023 +00410113 +01212023 +00410113 +0040e073 +00300b13 +00300a13 +00100a93 +01600433 +00441413 +014469b3 +01300533 +02200893 +00000073 +fe0416e3 +415a0a33 +fe0a10e3 +0040f073 +ff100493 +00900533 +02200893 +00000073 +00148493 +fe9068e3 +00900533 +02200893 +00000073 +ffc10113 +00012903 +ffc10113 +00012483 +ffc10113 +00012f83 +ffc10113 +00012f03 +ffc10113 +00012e83 +ffc10113 +00012e03 +ffc10113 +00012383 +ffc10113 +00012303 +ffc10113 +00012283 +ffc10113 +00012b03 +041b1073 +ffc10113 +00012b03 +ffc10113 +00012a83 +ffc10113 +00012a03 +ffc10113 +00012983 +ffc10113 +00012403 +ffc10113 +00012503 +ffc10113 +00012883 +00200073 diff --git a/pipelined-cpu/srcs/board/cpu21_board_top.v b/pipelined-cpu/srcs/board/cpu21_board_top.v index 8896001..80848d5 100644 --- a/pipelined-cpu/srcs/board/cpu21_board_top.v +++ b/pipelined-cpu/srcs/board/cpu21_board_top.v @@ -31,405 +31,438 @@ // 注意: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 -) ( - 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 + ) ( + 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; + + 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; + 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 - 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 与"关卡入口"共用一个入口。 - wire [2:0] irq_vec = {irq_sw[2], (level_irq | irq_sw[1]), (mouse_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 与"关卡入口"共用一个入口。 + wire [2:0] irq_vec = {irq_sw[2], (level_irq | irq_sw[1]), (mouse_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" -`elsif RISC_V_INTRUPT_CCAB_ROM - // 中断综合测试程序:三个中断入口由镜像中的实际标签位置决定。 - `include "risc-v-intrupt-ccab.vh" -`elsif BOARD_ROM_FAST - // 仿真专用:把演示程序的延时改小的版本(综合流程不会用到) - `include "cpu21_board_rom_fast.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" `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; - 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]; + initial begin + for (j = 0; j < RAM_WORDS; j = j + 1) + ram[j] = 32'b0; end - end - // --------------------------------------------------------------------------- - // 处理器:只连接上板需要的端口,调试端口留空(不产生 I/O) - // --------------------------------------------------------------------------- - cpu21_riscv_redirect_int_bpb #( - .LED_ADDR (LED_ADDR), - .USTATUS_INIT(USTATUS_INIT), - // 中断入口必须与所选 ROM 镜像中的 ISR 起点一致。 + 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 起点一致。 `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) + // 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); + 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 - 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; - end - - assign led_we = (led_we_cnt != 24'd0); - - // =========================================================================== - // 扫雷外设:显存 + VGA + 七段数码管 + 鼠标事件源 + 中断连线 - // - // 显存是一块 1200 字节的双口 RAM(40x30 格,每格 1 字节):CPU 通过 MMIO 的 - // fb_* 写端口写入,VGA 用另一个读端口组合读出。两者同处 clk_cpu 域(VGA 的 - // 25 MHz 像素节拍由使能信号产生,不是独立时钟),因此没有跨时钟域问题。 - // =========================================================================== - localparam integer FB_WORDS = 300; // 300 字 = 1200 字节 - - - // ---- 显存 ---- - 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]; + 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 - end - wire [31:0] fb_rdata = fb[fb_raddr]; + assign led_we = (led_we_cnt != 24'd0); - // ---- 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; + // =========================================================================== + // 扫雷外设:显存 + VGA + 七段数码管 + 鼠标事件源 + 中断连线 + // + // 显存是一块 1200 字节的双口 RAM(40x30 格,每格 1 字节):CPU 通过 MMIO 的 + // fb_* 写端口写入,VGA 用另一个读端口组合读出。两者同处 clk_cpu 域(VGA 的 + // 25 MHz 像素节拍由使能信号产生,不是独立时钟),因此没有跨时钟域问题。 + // =========================================================================== + localparam integer FB_WORDS = 300; // 300 字 = 1200 字节 - 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) - ); + // ---- 显存 ---- + reg [31:0] fb[0:FB_WORDS-1]; + integer k; - // ---- 鼠标事件源 ---- - 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(50000) - ) 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) - ); + initial begin + for (k = 0; k < FB_WORDS; k = k + 1) + fb[k] = 32'b0; end - endgenerate + + 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(50000) + ) 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 endmodule diff --git a/pipelined-cpu/srcs/board/risc-v-intrupt-sllsb.vh b/pipelined-cpu/srcs/board/risc-v-intrupt-sllsb.vh new file mode 100644 index 0000000..d4897ab --- /dev/null +++ b/pipelined-cpu/srcs/board/risc-v-intrupt-sllsb.vh @@ -0,0 +1,1026 @@ + // generated by tools/adapt_intrupt_sllsb.py - do not edit by hand + // source: programs\risc-v-intrupt-sllsb.hex (360 words, remaining entries filled with NOP) + rom[0] = 32'h7D000113; + rom[1] = 32'h00100413; + rom[2] = 32'h01F41993; + rom[3] = 32'h41F9D993; + rom[4] = 32'h00000433; + rom[5] = 32'h00C00913; + rom[6] = 32'h00800B13; + rom[7] = 32'h00140413; + rom[8] = 32'h00F47413; + rom[9] = 32'h00800293; + rom[10] = 32'h00100313; + rom[11] = 32'h00499993; + rom[12] = 32'h0089E9B3; + rom[13] = 32'h01300533; + rom[14] = 32'h528000EF; + rom[15] = 32'h00000013; + rom[16] = 32'h406282B3; + rom[17] = 32'hFE0294E3; + rom[18] = 32'h00140413; + rom[19] = 32'h00F00F93; + rom[20] = 32'h01F47433; + rom[21] = 32'h01C41413; + rom[22] = 32'h00800293; + rom[23] = 32'h00100313; + rom[24] = 32'h0049D993; + rom[25] = 32'h0089E9B3; + rom[26] = 32'h01300533; + rom[27] = 32'h4F4000EF; + rom[28] = 32'h00000013; + rom[29] = 32'h406282B3; + rom[30] = 32'hFE0294E3; + rom[31] = 32'h01C45413; + rom[32] = 32'h406B0B33; + rom[33] = 32'h000B0463; + rom[34] = 32'hF95FF06F; + rom[35] = 32'h000002B3; + rom[36] = 32'hFFF2C293; + rom[37] = 32'h01029293; + rom[38] = 32'hFFF2E293; + rom[39] = 32'h00500533; + rom[40] = 32'h4C0000EF; + rom[41] = 32'h00000013; + rom[42] = 32'hF5DFF06F; + rom[43] = 32'h01112023; + rom[44] = 32'h00410113; + rom[45] = 32'h00A12023; + rom[46] = 32'h00410113; + rom[47] = 32'h00812023; + rom[48] = 32'h00410113; + rom[49] = 32'h01312023; + rom[50] = 32'h00410113; + rom[51] = 32'h01412023; + rom[52] = 32'h00410113; + rom[53] = 32'h01512023; + rom[54] = 32'h00410113; + rom[55] = 32'h01612023; + rom[56] = 32'h00410113; + rom[57] = 32'h04106B73; + rom[58] = 32'h01612023; + rom[59] = 32'h00410113; + rom[60] = 32'h00512023; + rom[61] = 32'h00410113; + rom[62] = 32'h00612023; + rom[63] = 32'h00410113; + rom[64] = 32'h00712023; + rom[65] = 32'h00410113; + rom[66] = 32'h01C12023; + rom[67] = 32'h00410113; + rom[68] = 32'h01D12023; + rom[69] = 32'h00410113; + rom[70] = 32'h01E12023; + rom[71] = 32'h00410113; + rom[72] = 32'h01F12023; + rom[73] = 32'h00410113; + rom[74] = 32'h00912023; + rom[75] = 32'h00410113; + rom[76] = 32'h01212023; + rom[77] = 32'h00410113; + rom[78] = 32'h0040E073; + rom[79] = 32'h00100B13; + rom[80] = 32'h00300A13; + rom[81] = 32'h00100A93; + rom[82] = 32'h01600433; + rom[83] = 32'h00441413; + rom[84] = 32'h014469B3; + rom[85] = 32'h01300533; + rom[86] = 32'h000508B3; + rom[87] = 32'h4240056F; + rom[88] = 32'hFE0416E3; + rom[89] = 32'h415A0A33; + rom[90] = 32'hFE0A10E3; + rom[91] = 32'h0040F073; + rom[92] = 32'h00100293; + rom[93] = 32'h00300313; + rom[94] = 32'h00800493; + rom[95] = 32'h00849493; + rom[96] = 32'h07648493; + rom[97] = 32'h00900533; + rom[98] = 32'h000508B3; + rom[99] = 32'h3F40056F; + rom[100] = 32'h00800E13; + rom[101] = 32'h005494B3; + rom[102] = 32'h006494B3; + rom[103] = 32'h00900533; + rom[104] = 32'h000508B3; + rom[105] = 32'h3DC0056F; + rom[106] = 32'hFFFE0E13; + rom[107] = 32'hFE0E14E3; + rom[108] = 32'hFFC10113; + rom[109] = 32'h00012903; + rom[110] = 32'hFFC10113; + rom[111] = 32'h00012483; + rom[112] = 32'hFFC10113; + rom[113] = 32'h00012F83; + rom[114] = 32'hFFC10113; + rom[115] = 32'h00012F03; + rom[116] = 32'hFFC10113; + rom[117] = 32'h00012E83; + rom[118] = 32'hFFC10113; + rom[119] = 32'h00012E03; + rom[120] = 32'hFFC10113; + rom[121] = 32'h00012383; + rom[122] = 32'hFFC10113; + rom[123] = 32'h00012303; + rom[124] = 32'hFFC10113; + rom[125] = 32'h00012283; + rom[126] = 32'hFFC10113; + rom[127] = 32'h00012B03; + rom[128] = 32'h041B1073; + rom[129] = 32'hFFC10113; + rom[130] = 32'h00012B03; + rom[131] = 32'hFFC10113; + rom[132] = 32'h00012A83; + rom[133] = 32'hFFC10113; + rom[134] = 32'h00012A03; + rom[135] = 32'hFFC10113; + rom[136] = 32'h00012983; + rom[137] = 32'hFFC10113; + rom[138] = 32'h00012403; + rom[139] = 32'hFFC10113; + rom[140] = 32'h00012503; + rom[141] = 32'hFFC10113; + rom[142] = 32'h00012883; + rom[143] = 32'h00200073; + rom[144] = 32'h01112023; + rom[145] = 32'h00410113; + rom[146] = 32'h00A12023; + rom[147] = 32'h00410113; + rom[148] = 32'h00812023; + rom[149] = 32'h00410113; + rom[150] = 32'h01312023; + rom[151] = 32'h00410113; + rom[152] = 32'h01412023; + rom[153] = 32'h00410113; + rom[154] = 32'h01512023; + rom[155] = 32'h00410113; + rom[156] = 32'h01612023; + rom[157] = 32'h00410113; + rom[158] = 32'h04106B73; + rom[159] = 32'h01612023; + rom[160] = 32'h00410113; + rom[161] = 32'h00512023; + rom[162] = 32'h00410113; + rom[163] = 32'h00612023; + rom[164] = 32'h00410113; + rom[165] = 32'h00712023; + rom[166] = 32'h00410113; + rom[167] = 32'h01C12023; + rom[168] = 32'h00410113; + rom[169] = 32'h01D12023; + rom[170] = 32'h00410113; + rom[171] = 32'h01E12023; + rom[172] = 32'h00410113; + rom[173] = 32'h01F12023; + rom[174] = 32'h00410113; + rom[175] = 32'h00912023; + rom[176] = 32'h00410113; + rom[177] = 32'h01212023; + rom[178] = 32'h00410113; + rom[179] = 32'h0040E073; + rom[180] = 32'h00200B13; + rom[181] = 32'h00300A13; + rom[182] = 32'h00100A93; + rom[183] = 32'h01600433; + rom[184] = 32'h00441413; + rom[185] = 32'h014469B3; + rom[186] = 32'h01300533; + rom[187] = 32'h000508B3; + rom[188] = 32'h2900056F; + rom[189] = 32'hFE0416E3; + rom[190] = 32'h415A0A33; + rom[191] = 32'hFE0A10E3; + rom[192] = 32'h0040F073; + rom[193] = 32'h00000313; + rom[194] = 32'h02000E13; + rom[195] = 32'h00000493; + rom[196] = 32'h00100913; + rom[197] = 32'h00930023; + rom[198] = 32'h00900533; + rom[199] = 32'h000508B3; + rom[200] = 32'h2600056F; + rom[201] = 32'h012484B3; + rom[202] = 32'h00130313; + rom[203] = 32'hFFFE0E13; + rom[204] = 32'hFE0E12E3; + rom[205] = 32'h00800E13; + rom[206] = 32'h00000313; + rom[207] = 32'h00032483; + rom[208] = 32'h00900533; + rom[209] = 32'h000508B3; + rom[210] = 32'h2380056F; + rom[211] = 32'h00430313; + rom[212] = 32'hFFFE0E13; + rom[213] = 32'hFE0E14E3; + rom[214] = 32'hFFC10113; + rom[215] = 32'h00012903; + rom[216] = 32'hFFC10113; + rom[217] = 32'h00012483; + rom[218] = 32'hFFC10113; + rom[219] = 32'h00012F83; + rom[220] = 32'hFFC10113; + rom[221] = 32'h00012F03; + rom[222] = 32'hFFC10113; + rom[223] = 32'h00012E83; + rom[224] = 32'hFFC10113; + rom[225] = 32'h00012E03; + rom[226] = 32'hFFC10113; + rom[227] = 32'h00012383; + rom[228] = 32'hFFC10113; + rom[229] = 32'h00012303; + rom[230] = 32'hFFC10113; + rom[231] = 32'h00012283; + rom[232] = 32'hFFC10113; + rom[233] = 32'h00012B03; + rom[234] = 32'h041B1073; + rom[235] = 32'hFFC10113; + rom[236] = 32'h00012B03; + rom[237] = 32'hFFC10113; + rom[238] = 32'h00012A83; + rom[239] = 32'hFFC10113; + rom[240] = 32'h00012A03; + rom[241] = 32'hFFC10113; + rom[242] = 32'h00012983; + rom[243] = 32'hFFC10113; + rom[244] = 32'h00012403; + rom[245] = 32'hFFC10113; + rom[246] = 32'h00012503; + rom[247] = 32'hFFC10113; + rom[248] = 32'h00012883; + rom[249] = 32'h00200073; + rom[250] = 32'h01112023; + rom[251] = 32'h00410113; + rom[252] = 32'h00A12023; + rom[253] = 32'h00410113; + rom[254] = 32'h00812023; + rom[255] = 32'h00410113; + rom[256] = 32'h01312023; + rom[257] = 32'h00410113; + rom[258] = 32'h01412023; + rom[259] = 32'h00410113; + rom[260] = 32'h01512023; + rom[261] = 32'h00410113; + rom[262] = 32'h01612023; + rom[263] = 32'h00410113; + rom[264] = 32'h04106B73; + rom[265] = 32'h01612023; + rom[266] = 32'h00410113; + rom[267] = 32'h00512023; + rom[268] = 32'h00410113; + rom[269] = 32'h00612023; + rom[270] = 32'h00410113; + rom[271] = 32'h00712023; + rom[272] = 32'h00410113; + rom[273] = 32'h01C12023; + rom[274] = 32'h00410113; + rom[275] = 32'h01D12023; + rom[276] = 32'h00410113; + rom[277] = 32'h01E12023; + rom[278] = 32'h00410113; + rom[279] = 32'h01F12023; + rom[280] = 32'h00410113; + rom[281] = 32'h00912023; + rom[282] = 32'h00410113; + rom[283] = 32'h01212023; + rom[284] = 32'h00410113; + rom[285] = 32'h0040E073; + rom[286] = 32'h00300B13; + rom[287] = 32'h00300A13; + rom[288] = 32'h00100A93; + rom[289] = 32'h01600433; + rom[290] = 32'h00441413; + rom[291] = 32'h014469B3; + rom[292] = 32'h01300533; + rom[293] = 32'h000508B3; + rom[294] = 32'h0E80056F; + rom[295] = 32'hFE0416E3; + rom[296] = 32'h415A0A33; + rom[297] = 32'hFE0A10E3; + rom[298] = 32'h0040F073; + rom[299] = 32'hFF100493; + rom[300] = 32'h00900533; + rom[301] = 32'h000508B3; + rom[302] = 32'h0C80056F; + rom[303] = 32'h00148493; + rom[304] = 32'hFE9068E3; + rom[305] = 32'h00900533; + rom[306] = 32'h000508B3; + rom[307] = 32'h0B40056F; + rom[308] = 32'hFFC10113; + rom[309] = 32'h00012903; + rom[310] = 32'hFFC10113; + rom[311] = 32'h00012483; + rom[312] = 32'hFFC10113; + rom[313] = 32'h00012F83; + rom[314] = 32'hFFC10113; + rom[315] = 32'h00012F03; + rom[316] = 32'hFFC10113; + rom[317] = 32'h00012E83; + rom[318] = 32'hFFC10113; + rom[319] = 32'h00012E03; + rom[320] = 32'hFFC10113; + rom[321] = 32'h00012383; + rom[322] = 32'hFFC10113; + rom[323] = 32'h00012303; + rom[324] = 32'hFFC10113; + rom[325] = 32'h00012283; + rom[326] = 32'hFFC10113; + rom[327] = 32'h00012B03; + rom[328] = 32'h041B1073; + rom[329] = 32'hFFC10113; + rom[330] = 32'h00012B03; + rom[331] = 32'hFFC10113; + rom[332] = 32'h00012A83; + rom[333] = 32'hFFC10113; + rom[334] = 32'h00012A03; + rom[335] = 32'hFFC10113; + rom[336] = 32'h00012983; + rom[337] = 32'hFFC10113; + rom[338] = 32'h00012403; + rom[339] = 32'hFFC10113; + rom[340] = 32'h00012503; + rom[341] = 32'hFFC10113; + rom[342] = 32'h00012883; + rom[343] = 32'h00200073; + rom[344] = 32'h10112023; + rom[345] = 32'h000018B7; + rom[346] = 32'h00A8A023; + rom[347] = 32'hFFFC03B7; + rom[348] = 32'h00138393; + rom[349] = 32'hFE03CEE3; + rom[350] = 32'h10012083; + rom[351] = 32'h00008067; + rom[352] = 32'h10A12023; + rom[353] = 32'h00001537; + rom[354] = 32'h01152023; + rom[355] = 32'hFFFC03B7; + rom[356] = 32'h00138393; + rom[357] = 32'hFE03CEE3; + rom[358] = 32'h10012503; + rom[359] = 32'h00050067; + rom[360] = 32'h00000013; + rom[361] = 32'h00000013; + rom[362] = 32'h00000013; + rom[363] = 32'h00000013; + rom[364] = 32'h00000013; + rom[365] = 32'h00000013; + rom[366] = 32'h00000013; + rom[367] = 32'h00000013; + rom[368] = 32'h00000013; + rom[369] = 32'h00000013; + rom[370] = 32'h00000013; + rom[371] = 32'h00000013; + rom[372] = 32'h00000013; + rom[373] = 32'h00000013; + rom[374] = 32'h00000013; + rom[375] = 32'h00000013; + rom[376] = 32'h00000013; + rom[377] = 32'h00000013; + rom[378] = 32'h00000013; + rom[379] = 32'h00000013; + rom[380] = 32'h00000013; + rom[381] = 32'h00000013; + rom[382] = 32'h00000013; + rom[383] = 32'h00000013; + rom[384] = 32'h00000013; + rom[385] = 32'h00000013; + rom[386] = 32'h00000013; + rom[387] = 32'h00000013; + rom[388] = 32'h00000013; + rom[389] = 32'h00000013; + rom[390] = 32'h00000013; + rom[391] = 32'h00000013; + rom[392] = 32'h00000013; + rom[393] = 32'h00000013; + rom[394] = 32'h00000013; + rom[395] = 32'h00000013; + rom[396] = 32'h00000013; + rom[397] = 32'h00000013; + rom[398] = 32'h00000013; + rom[399] = 32'h00000013; + rom[400] = 32'h00000013; + rom[401] = 32'h00000013; + rom[402] = 32'h00000013; + rom[403] = 32'h00000013; + rom[404] = 32'h00000013; + rom[405] = 32'h00000013; + rom[406] = 32'h00000013; + rom[407] = 32'h00000013; + rom[408] = 32'h00000013; + rom[409] = 32'h00000013; + rom[410] = 32'h00000013; + rom[411] = 32'h00000013; + rom[412] = 32'h00000013; + rom[413] = 32'h00000013; + rom[414] = 32'h00000013; + rom[415] = 32'h00000013; + rom[416] = 32'h00000013; + rom[417] = 32'h00000013; + rom[418] = 32'h00000013; + rom[419] = 32'h00000013; + rom[420] = 32'h00000013; + rom[421] = 32'h00000013; + rom[422] = 32'h00000013; + rom[423] = 32'h00000013; + rom[424] = 32'h00000013; + rom[425] = 32'h00000013; + rom[426] = 32'h00000013; + rom[427] = 32'h00000013; + rom[428] = 32'h00000013; + rom[429] = 32'h00000013; + rom[430] = 32'h00000013; + rom[431] = 32'h00000013; + rom[432] = 32'h00000013; + rom[433] = 32'h00000013; + rom[434] = 32'h00000013; + rom[435] = 32'h00000013; + rom[436] = 32'h00000013; + rom[437] = 32'h00000013; + rom[438] = 32'h00000013; + rom[439] = 32'h00000013; + rom[440] = 32'h00000013; + rom[441] = 32'h00000013; + rom[442] = 32'h00000013; + rom[443] = 32'h00000013; + rom[444] = 32'h00000013; + rom[445] = 32'h00000013; + rom[446] = 32'h00000013; + rom[447] = 32'h00000013; + rom[448] = 32'h00000013; + rom[449] = 32'h00000013; + rom[450] = 32'h00000013; + rom[451] = 32'h00000013; + rom[452] = 32'h00000013; + rom[453] = 32'h00000013; + rom[454] = 32'h00000013; + rom[455] = 32'h00000013; + rom[456] = 32'h00000013; + rom[457] = 32'h00000013; + rom[458] = 32'h00000013; + rom[459] = 32'h00000013; + rom[460] = 32'h00000013; + rom[461] = 32'h00000013; + rom[462] = 32'h00000013; + rom[463] = 32'h00000013; + rom[464] = 32'h00000013; + rom[465] = 32'h00000013; + rom[466] = 32'h00000013; + rom[467] = 32'h00000013; + rom[468] = 32'h00000013; + rom[469] = 32'h00000013; + rom[470] = 32'h00000013; + rom[471] = 32'h00000013; + rom[472] = 32'h00000013; + rom[473] = 32'h00000013; + rom[474] = 32'h00000013; + rom[475] = 32'h00000013; + rom[476] = 32'h00000013; + rom[477] = 32'h00000013; + rom[478] = 32'h00000013; + rom[479] = 32'h00000013; + rom[480] = 32'h00000013; + rom[481] = 32'h00000013; + rom[482] = 32'h00000013; + rom[483] = 32'h00000013; + rom[484] = 32'h00000013; + rom[485] = 32'h00000013; + rom[486] = 32'h00000013; + rom[487] = 32'h00000013; + rom[488] = 32'h00000013; + rom[489] = 32'h00000013; + rom[490] = 32'h00000013; + rom[491] = 32'h00000013; + rom[492] = 32'h00000013; + rom[493] = 32'h00000013; + rom[494] = 32'h00000013; + rom[495] = 32'h00000013; + rom[496] = 32'h00000013; + rom[497] = 32'h00000013; + rom[498] = 32'h00000013; + rom[499] = 32'h00000013; + rom[500] = 32'h00000013; + rom[501] = 32'h00000013; + rom[502] = 32'h00000013; + rom[503] = 32'h00000013; + rom[504] = 32'h00000013; + rom[505] = 32'h00000013; + rom[506] = 32'h00000013; + rom[507] = 32'h00000013; + rom[508] = 32'h00000013; + rom[509] = 32'h00000013; + rom[510] = 32'h00000013; + rom[511] = 32'h00000013; + rom[512] = 32'h00000013; + rom[513] = 32'h00000013; + rom[514] = 32'h00000013; + rom[515] = 32'h00000013; + rom[516] = 32'h00000013; + rom[517] = 32'h00000013; + rom[518] = 32'h00000013; + rom[519] = 32'h00000013; + rom[520] = 32'h00000013; + rom[521] = 32'h00000013; + rom[522] = 32'h00000013; + rom[523] = 32'h00000013; + rom[524] = 32'h00000013; + rom[525] = 32'h00000013; + rom[526] = 32'h00000013; + rom[527] = 32'h00000013; + rom[528] = 32'h00000013; + rom[529] = 32'h00000013; + rom[530] = 32'h00000013; + rom[531] = 32'h00000013; + rom[532] = 32'h00000013; + rom[533] = 32'h00000013; + rom[534] = 32'h00000013; + rom[535] = 32'h00000013; + rom[536] = 32'h00000013; + rom[537] = 32'h00000013; + rom[538] = 32'h00000013; + rom[539] = 32'h00000013; + rom[540] = 32'h00000013; + rom[541] = 32'h00000013; + rom[542] = 32'h00000013; + rom[543] = 32'h00000013; + rom[544] = 32'h00000013; + rom[545] = 32'h00000013; + rom[546] = 32'h00000013; + rom[547] = 32'h00000013; + rom[548] = 32'h00000013; + rom[549] = 32'h00000013; + rom[550] = 32'h00000013; + rom[551] = 32'h00000013; + rom[552] = 32'h00000013; + rom[553] = 32'h00000013; + rom[554] = 32'h00000013; + rom[555] = 32'h00000013; + rom[556] = 32'h00000013; + rom[557] = 32'h00000013; + rom[558] = 32'h00000013; + rom[559] = 32'h00000013; + rom[560] = 32'h00000013; + rom[561] = 32'h00000013; + rom[562] = 32'h00000013; + rom[563] = 32'h00000013; + rom[564] = 32'h00000013; + rom[565] = 32'h00000013; + rom[566] = 32'h00000013; + rom[567] = 32'h00000013; + rom[568] = 32'h00000013; + rom[569] = 32'h00000013; + rom[570] = 32'h00000013; + rom[571] = 32'h00000013; + rom[572] = 32'h00000013; + rom[573] = 32'h00000013; + rom[574] = 32'h00000013; + rom[575] = 32'h00000013; + rom[576] = 32'h00000013; + rom[577] = 32'h00000013; + rom[578] = 32'h00000013; + rom[579] = 32'h00000013; + rom[580] = 32'h00000013; + rom[581] = 32'h00000013; + rom[582] = 32'h00000013; + rom[583] = 32'h00000013; + rom[584] = 32'h00000013; + rom[585] = 32'h00000013; + rom[586] = 32'h00000013; + rom[587] = 32'h00000013; + rom[588] = 32'h00000013; + rom[589] = 32'h00000013; + rom[590] = 32'h00000013; + rom[591] = 32'h00000013; + rom[592] = 32'h00000013; + rom[593] = 32'h00000013; + rom[594] = 32'h00000013; + rom[595] = 32'h00000013; + rom[596] = 32'h00000013; + rom[597] = 32'h00000013; + rom[598] = 32'h00000013; + rom[599] = 32'h00000013; + rom[600] = 32'h00000013; + rom[601] = 32'h00000013; + rom[602] = 32'h00000013; + rom[603] = 32'h00000013; + rom[604] = 32'h00000013; + rom[605] = 32'h00000013; + rom[606] = 32'h00000013; + rom[607] = 32'h00000013; + rom[608] = 32'h00000013; + rom[609] = 32'h00000013; + rom[610] = 32'h00000013; + rom[611] = 32'h00000013; + rom[612] = 32'h00000013; + rom[613] = 32'h00000013; + rom[614] = 32'h00000013; + rom[615] = 32'h00000013; + rom[616] = 32'h00000013; + rom[617] = 32'h00000013; + rom[618] = 32'h00000013; + rom[619] = 32'h00000013; + rom[620] = 32'h00000013; + rom[621] = 32'h00000013; + rom[622] = 32'h00000013; + rom[623] = 32'h00000013; + rom[624] = 32'h00000013; + rom[625] = 32'h00000013; + rom[626] = 32'h00000013; + rom[627] = 32'h00000013; + rom[628] = 32'h00000013; + rom[629] = 32'h00000013; + rom[630] = 32'h00000013; + rom[631] = 32'h00000013; + rom[632] = 32'h00000013; + rom[633] = 32'h00000013; + rom[634] = 32'h00000013; + rom[635] = 32'h00000013; + rom[636] = 32'h00000013; + rom[637] = 32'h00000013; + rom[638] = 32'h00000013; + rom[639] = 32'h00000013; + rom[640] = 32'h00000013; + rom[641] = 32'h00000013; + rom[642] = 32'h00000013; + rom[643] = 32'h00000013; + rom[644] = 32'h00000013; + rom[645] = 32'h00000013; + rom[646] = 32'h00000013; + rom[647] = 32'h00000013; + rom[648] = 32'h00000013; + rom[649] = 32'h00000013; + rom[650] = 32'h00000013; + rom[651] = 32'h00000013; + rom[652] = 32'h00000013; + rom[653] = 32'h00000013; + rom[654] = 32'h00000013; + rom[655] = 32'h00000013; + rom[656] = 32'h00000013; + rom[657] = 32'h00000013; + rom[658] = 32'h00000013; + rom[659] = 32'h00000013; + rom[660] = 32'h00000013; + rom[661] = 32'h00000013; + rom[662] = 32'h00000013; + rom[663] = 32'h00000013; + rom[664] = 32'h00000013; + rom[665] = 32'h00000013; + rom[666] = 32'h00000013; + rom[667] = 32'h00000013; + rom[668] = 32'h00000013; + rom[669] = 32'h00000013; + rom[670] = 32'h00000013; + rom[671] = 32'h00000013; + rom[672] = 32'h00000013; + rom[673] = 32'h00000013; + rom[674] = 32'h00000013; + rom[675] = 32'h00000013; + rom[676] = 32'h00000013; + rom[677] = 32'h00000013; + rom[678] = 32'h00000013; + rom[679] = 32'h00000013; + rom[680] = 32'h00000013; + rom[681] = 32'h00000013; + rom[682] = 32'h00000013; + rom[683] = 32'h00000013; + rom[684] = 32'h00000013; + rom[685] = 32'h00000013; + rom[686] = 32'h00000013; + rom[687] = 32'h00000013; + rom[688] = 32'h00000013; + rom[689] = 32'h00000013; + rom[690] = 32'h00000013; + rom[691] = 32'h00000013; + rom[692] = 32'h00000013; + rom[693] = 32'h00000013; + rom[694] = 32'h00000013; + rom[695] = 32'h00000013; + rom[696] = 32'h00000013; + rom[697] = 32'h00000013; + rom[698] = 32'h00000013; + rom[699] = 32'h00000013; + rom[700] = 32'h00000013; + rom[701] = 32'h00000013; + rom[702] = 32'h00000013; + rom[703] = 32'h00000013; + rom[704] = 32'h00000013; + rom[705] = 32'h00000013; + rom[706] = 32'h00000013; + rom[707] = 32'h00000013; + rom[708] = 32'h00000013; + rom[709] = 32'h00000013; + rom[710] = 32'h00000013; + rom[711] = 32'h00000013; + rom[712] = 32'h00000013; + rom[713] = 32'h00000013; + rom[714] = 32'h00000013; + rom[715] = 32'h00000013; + rom[716] = 32'h00000013; + rom[717] = 32'h00000013; + rom[718] = 32'h00000013; + rom[719] = 32'h00000013; + rom[720] = 32'h00000013; + rom[721] = 32'h00000013; + rom[722] = 32'h00000013; + rom[723] = 32'h00000013; + rom[724] = 32'h00000013; + rom[725] = 32'h00000013; + rom[726] = 32'h00000013; + rom[727] = 32'h00000013; + rom[728] = 32'h00000013; + rom[729] = 32'h00000013; + rom[730] = 32'h00000013; + rom[731] = 32'h00000013; + rom[732] = 32'h00000013; + rom[733] = 32'h00000013; + rom[734] = 32'h00000013; + rom[735] = 32'h00000013; + rom[736] = 32'h00000013; + rom[737] = 32'h00000013; + rom[738] = 32'h00000013; + rom[739] = 32'h00000013; + rom[740] = 32'h00000013; + rom[741] = 32'h00000013; + rom[742] = 32'h00000013; + rom[743] = 32'h00000013; + rom[744] = 32'h00000013; + rom[745] = 32'h00000013; + rom[746] = 32'h00000013; + rom[747] = 32'h00000013; + rom[748] = 32'h00000013; + rom[749] = 32'h00000013; + rom[750] = 32'h00000013; + rom[751] = 32'h00000013; + rom[752] = 32'h00000013; + rom[753] = 32'h00000013; + rom[754] = 32'h00000013; + rom[755] = 32'h00000013; + rom[756] = 32'h00000013; + rom[757] = 32'h00000013; + rom[758] = 32'h00000013; + rom[759] = 32'h00000013; + rom[760] = 32'h00000013; + rom[761] = 32'h00000013; + rom[762] = 32'h00000013; + rom[763] = 32'h00000013; + rom[764] = 32'h00000013; + rom[765] = 32'h00000013; + rom[766] = 32'h00000013; + rom[767] = 32'h00000013; + rom[768] = 32'h00000013; + rom[769] = 32'h00000013; + rom[770] = 32'h00000013; + rom[771] = 32'h00000013; + rom[772] = 32'h00000013; + rom[773] = 32'h00000013; + rom[774] = 32'h00000013; + rom[775] = 32'h00000013; + rom[776] = 32'h00000013; + rom[777] = 32'h00000013; + rom[778] = 32'h00000013; + rom[779] = 32'h00000013; + rom[780] = 32'h00000013; + rom[781] = 32'h00000013; + rom[782] = 32'h00000013; + rom[783] = 32'h00000013; + rom[784] = 32'h00000013; + rom[785] = 32'h00000013; + rom[786] = 32'h00000013; + rom[787] = 32'h00000013; + rom[788] = 32'h00000013; + rom[789] = 32'h00000013; + rom[790] = 32'h00000013; + rom[791] = 32'h00000013; + rom[792] = 32'h00000013; + rom[793] = 32'h00000013; + rom[794] = 32'h00000013; + rom[795] = 32'h00000013; + rom[796] = 32'h00000013; + rom[797] = 32'h00000013; + rom[798] = 32'h00000013; + rom[799] = 32'h00000013; + rom[800] = 32'h00000013; + rom[801] = 32'h00000013; + rom[802] = 32'h00000013; + rom[803] = 32'h00000013; + rom[804] = 32'h00000013; + rom[805] = 32'h00000013; + rom[806] = 32'h00000013; + rom[807] = 32'h00000013; + rom[808] = 32'h00000013; + rom[809] = 32'h00000013; + rom[810] = 32'h00000013; + rom[811] = 32'h00000013; + rom[812] = 32'h00000013; + rom[813] = 32'h00000013; + rom[814] = 32'h00000013; + rom[815] = 32'h00000013; + rom[816] = 32'h00000013; + rom[817] = 32'h00000013; + rom[818] = 32'h00000013; + rom[819] = 32'h00000013; + rom[820] = 32'h00000013; + rom[821] = 32'h00000013; + rom[822] = 32'h00000013; + rom[823] = 32'h00000013; + rom[824] = 32'h00000013; + rom[825] = 32'h00000013; + rom[826] = 32'h00000013; + rom[827] = 32'h00000013; + rom[828] = 32'h00000013; + rom[829] = 32'h00000013; + rom[830] = 32'h00000013; + rom[831] = 32'h00000013; + rom[832] = 32'h00000013; + rom[833] = 32'h00000013; + rom[834] = 32'h00000013; + rom[835] = 32'h00000013; + rom[836] = 32'h00000013; + rom[837] = 32'h00000013; + rom[838] = 32'h00000013; + rom[839] = 32'h00000013; + rom[840] = 32'h00000013; + rom[841] = 32'h00000013; + rom[842] = 32'h00000013; + rom[843] = 32'h00000013; + rom[844] = 32'h00000013; + rom[845] = 32'h00000013; + rom[846] = 32'h00000013; + rom[847] = 32'h00000013; + rom[848] = 32'h00000013; + rom[849] = 32'h00000013; + rom[850] = 32'h00000013; + rom[851] = 32'h00000013; + rom[852] = 32'h00000013; + rom[853] = 32'h00000013; + rom[854] = 32'h00000013; + rom[855] = 32'h00000013; + rom[856] = 32'h00000013; + rom[857] = 32'h00000013; + rom[858] = 32'h00000013; + rom[859] = 32'h00000013; + rom[860] = 32'h00000013; + rom[861] = 32'h00000013; + rom[862] = 32'h00000013; + rom[863] = 32'h00000013; + rom[864] = 32'h00000013; + rom[865] = 32'h00000013; + rom[866] = 32'h00000013; + rom[867] = 32'h00000013; + rom[868] = 32'h00000013; + rom[869] = 32'h00000013; + rom[870] = 32'h00000013; + rom[871] = 32'h00000013; + rom[872] = 32'h00000013; + rom[873] = 32'h00000013; + rom[874] = 32'h00000013; + rom[875] = 32'h00000013; + rom[876] = 32'h00000013; + rom[877] = 32'h00000013; + rom[878] = 32'h00000013; + rom[879] = 32'h00000013; + rom[880] = 32'h00000013; + rom[881] = 32'h00000013; + rom[882] = 32'h00000013; + rom[883] = 32'h00000013; + rom[884] = 32'h00000013; + rom[885] = 32'h00000013; + rom[886] = 32'h00000013; + rom[887] = 32'h00000013; + rom[888] = 32'h00000013; + rom[889] = 32'h00000013; + rom[890] = 32'h00000013; + rom[891] = 32'h00000013; + rom[892] = 32'h00000013; + rom[893] = 32'h00000013; + rom[894] = 32'h00000013; + rom[895] = 32'h00000013; + rom[896] = 32'h00000013; + rom[897] = 32'h00000013; + rom[898] = 32'h00000013; + rom[899] = 32'h00000013; + rom[900] = 32'h00000013; + rom[901] = 32'h00000013; + rom[902] = 32'h00000013; + rom[903] = 32'h00000013; + rom[904] = 32'h00000013; + rom[905] = 32'h00000013; + rom[906] = 32'h00000013; + rom[907] = 32'h00000013; + rom[908] = 32'h00000013; + rom[909] = 32'h00000013; + rom[910] = 32'h00000013; + rom[911] = 32'h00000013; + rom[912] = 32'h00000013; + rom[913] = 32'h00000013; + rom[914] = 32'h00000013; + rom[915] = 32'h00000013; + rom[916] = 32'h00000013; + rom[917] = 32'h00000013; + rom[918] = 32'h00000013; + rom[919] = 32'h00000013; + rom[920] = 32'h00000013; + rom[921] = 32'h00000013; + rom[922] = 32'h00000013; + rom[923] = 32'h00000013; + rom[924] = 32'h00000013; + rom[925] = 32'h00000013; + rom[926] = 32'h00000013; + rom[927] = 32'h00000013; + rom[928] = 32'h00000013; + rom[929] = 32'h00000013; + rom[930] = 32'h00000013; + rom[931] = 32'h00000013; + rom[932] = 32'h00000013; + rom[933] = 32'h00000013; + rom[934] = 32'h00000013; + rom[935] = 32'h00000013; + rom[936] = 32'h00000013; + rom[937] = 32'h00000013; + rom[938] = 32'h00000013; + rom[939] = 32'h00000013; + rom[940] = 32'h00000013; + rom[941] = 32'h00000013; + rom[942] = 32'h00000013; + rom[943] = 32'h00000013; + rom[944] = 32'h00000013; + rom[945] = 32'h00000013; + rom[946] = 32'h00000013; + rom[947] = 32'h00000013; + rom[948] = 32'h00000013; + rom[949] = 32'h00000013; + rom[950] = 32'h00000013; + rom[951] = 32'h00000013; + rom[952] = 32'h00000013; + rom[953] = 32'h00000013; + rom[954] = 32'h00000013; + rom[955] = 32'h00000013; + rom[956] = 32'h00000013; + rom[957] = 32'h00000013; + rom[958] = 32'h00000013; + rom[959] = 32'h00000013; + rom[960] = 32'h00000013; + rom[961] = 32'h00000013; + rom[962] = 32'h00000013; + rom[963] = 32'h00000013; + rom[964] = 32'h00000013; + rom[965] = 32'h00000013; + rom[966] = 32'h00000013; + rom[967] = 32'h00000013; + rom[968] = 32'h00000013; + rom[969] = 32'h00000013; + rom[970] = 32'h00000013; + rom[971] = 32'h00000013; + rom[972] = 32'h00000013; + rom[973] = 32'h00000013; + rom[974] = 32'h00000013; + rom[975] = 32'h00000013; + rom[976] = 32'h00000013; + rom[977] = 32'h00000013; + rom[978] = 32'h00000013; + rom[979] = 32'h00000013; + rom[980] = 32'h00000013; + rom[981] = 32'h00000013; + rom[982] = 32'h00000013; + rom[983] = 32'h00000013; + rom[984] = 32'h00000013; + rom[985] = 32'h00000013; + 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; diff --git a/pipelined-cpu/tools/adapt_intrupt_sllsb.py b/pipelined-cpu/tools/adapt_intrupt_sllsb.py new file mode 100644 index 0000000..1377171 --- /dev/null +++ b/pipelined-cpu/tools/adapt_intrupt_sllsb.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python3 +"""把课程新版中断测试(EPC 内存堆栈保护 + 附加 SLL/SB/BLTU)适配到本 CPU 上板运行。 + +输入:programs/risc-v-intrupt-sllsb.hex + 课程的原始镜像(344 字,已去掉 Logisim 的 "v2.0 raw" 头) +输出:<输出.vh> 供 cpu21_board_top.v 里 `include 的 ROM 初始化(RISC_V_INTRUPT_SLLSB_ROM) + [输出_adapted.hex] 可选:适配后的镜像本身(方便人工对比/仿真) + +只改 ROM 内容,不改 CPU 语义,**所有指令地址保持不变**,因此顶层的 +IRQ1/2/3_VECTOR = 0x0AC / 0x240 / 0x3E8 不用动。 + +改了什么 +-------- +课程程序用 "addi a7,zero,34" + "ecall" 显示(`ecall` 的服务号 34 是原 Logisim +电路的历史"显示"调用;本 CPU 把它保留为空操作,LED/数码管不会有任何反应)。 +这里把每条显示点**原地换成一次调用**(仍然是 2 字换 2 字): + + * 主程序(字 0..42): "jal ra,DISP_DLY" + "nop" + * 三个 ISR(字 >= 43): "add a7,a0,zero" + "jal a0,DISP_DLY_ISR" + +两个显示例程(各 8 条)追加在程序末尾(最后一条 uret 之后),所以入口地址不变。 + +为什么 ISR 版不用 ra +-------------------- +三个 ISR 的现场都保存/恢复 a7 与 a0,但**都没有保存 ra**(它们原来的显示是 +ecall,不需要 ra)。若 ISR 里用 `jal ra,...`,ra 会被写成 ISR 内部地址;恰好 +中断落在主程序 DISP_DLY 末尾的 `jalr zero,0(ra)` 上时,返回后会跳到 ISR 内部, +一路执行到 ISR 结尾的 `csrrci zero,0x4,1`,把 MIE 永久清零(表现就是"跑一阵子 +之后拨开关再也不响应")。所以 ISR 版把链接寄存器放 a0、显示值放 a7。 + +为什么返回地址存在 sp+256 +------------------------ +本程序的 ISR 是"先加 sp 再存"的向上增长栈,一层最多 48 字节,最多嵌套 4 层共 +192 字节,所以 [sp, sp+192) 是中断随时会写到的区域。返回地址放在 sp+256(越过 +这个区域)后,中断(含嵌套)打断显示延时也破坏不了它。 + +用法 +---- + py tools/adapt_intrupt_sllsb.py programs/risc-v-intrupt-sllsb.hex \ + srcs/board/risc-v-intrupt-sllsb.vh [programs/risc-v-intrupt-sllsb-adapted.hex] +""" + +import sys + +NOP = 0x00000013 +ECALL = 0x00000073 + +ZERO, RA, SP, T2, A0, A7 = 0, 1, 2, 7, 10, 17 + +LED_ADDR_HI = 1 # lui a7, 1 -> a7 = 0x1000(LED_ADDR / 数码管) +# 延时计数初值为负、向上数到 0(约 2 拍一轮): +# 0xFFFC0000 -> 0x40000 = 262144 轮 ≈ 52 万拍 ≈ 10 ms @50 MHz +# @3.125 MHz(CLK_DIV_INTRUPT=32)时约 160 ms,肉眼看得很清楚 +DELAY_NEG_HI = 0xFFFC0 + +LINK_SLOT = 256 # 链接寄存器保存位置,必须 > ISR 最大栈用量(4x48=192) +ISR1_WORD = 43 # 字 43 起是三个 ISR(主程序在它之前) +ROM_WORDS = 1024 # 与 cpu21_board_top 的 hex2vh 约定一致(ROM 深度 8192 也够) + + +# ---------------------------------------------------------------- 编码 +def enc_i(imm, rs1, f3, rd, op=0x13): + return ((imm & 0xFFF) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | op + + +def enc_s(imm, rs2, rs1, f3): + imm &= 0xFFF + return (((imm >> 5) << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) + | ((imm & 0x1F) << 7) | 0x23) + + +def enc_b(imm, rs2, rs1, f3): + imm &= 0x1FFF + return ((((imm >> 12) & 1) << 31) | (((imm >> 5) & 0x3F) << 25) + | (rs2 << 20) | (rs1 << 15) | (f3 << 12) + | (((imm >> 1) & 0xF) << 8) | (((imm >> 11) & 1) << 7) | 0x63) + + +def enc_u(imm, rd): + return ((imm & 0xFFFFF) << 12) | (rd << 7) | 0x37 + + +def enc_j(imm, rd): + imm &= 0x1FFFFF + return ((((imm >> 20) & 1) << 31) | (((imm >> 1) & 0x3FF) << 21) + | (((imm >> 11) & 1) << 20) | (((imm >> 12) & 0xFF) << 12) + | (rd << 7) | 0x6F) + + +def enc_r(f7, rs2, rs1, f3, rd): + return ((f7 << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) + | (rd << 7) | 0x33) + + +DISP_LUI = enc_u(LED_ADDR_HI, A7) # lui a7, 1 +DISP_SW = enc_s(0, A0, A7, 2) # sw a0, 0(a7) +SHOW_SITE = enc_i(34, ZERO, 0, A7) # addi a7, zero, 34 <- 课程程序的"显示"点 +SW_A7_0SP = enc_s(0, A7, SP, 2) # sw a7, 0(sp) <- ISR 入口第一条 + + +def disp_dly(): + """主程序用:显示 a0,延时约 10 ms,链接在 ra(8 条)。""" + return [ + enc_s(LINK_SLOT, RA, SP, 2), # sw ra, 256(sp) + DISP_LUI, # lui a7, 1 + DISP_SW, # sw a0, 0(a7) + enc_u(DELAY_NEG_HI, T2), # lui t2, 0xFFFC0 + enc_i(1, T2, 0, T2), # addi t2, t2, 1 + enc_b(-4, ZERO, T2, 4), # blt t2, zero, -4 + enc_i(LINK_SLOT, SP, 2, RA, 0x03), # lw ra, 256(sp) + enc_i(0, RA, 0, ZERO, 0x67), # jalr zero, ra, 0 + ] + + +def disp_dly_isr(): + """ISR 用:显示 a7,链接在 a0,完全不碰 ra(8 条)。""" + return [ + enc_s(LINK_SLOT, A0, SP, 2), # sw a0, 256(sp) + enc_u(LED_ADDR_HI, A0), # lui a0, 1 + enc_s(0, A7, A0, 2), # sw a7, 0(a0) + enc_u(DELAY_NEG_HI, T2), # lui t2, 0xFFFC0 + enc_i(1, T2, 0, T2), # addi t2, t2, 1 + enc_b(-4, ZERO, T2, 4), # blt t2, zero, -4 + enc_i(LINK_SLOT, SP, 2, A0, 0x03), # lw a0, 256(sp) + enc_i(0, A0, 0, ZERO, 0x67), # jalr zero, a0, 0 + ] + + +def read_hex(path): + words = [] + with open(path, encoding="ascii") as f: + for line in f: + line = line.split("//")[0].strip() + if not line or line.lower().startswith("v2.0"): + continue # 容忍 Logisim 的 "v2.0 raw" 头 + words.append(int(line, 16)) + return words + + +def main(): + if len(sys.argv) < 3: + raise SystemExit(__doc__) + src, dst_vh = sys.argv[1], sys.argv[2] + dst_hex = sys.argv[3] if len(sys.argv) > 3 else None + + w = read_hex(src) + print("源程序 %d 字" % len(w)) + + # ---- 自检:三个 ISR 入口必须还是 sw a7,0(sp) ---- + entries = [i for i, x in enumerate(w) if x == SW_A7_0SP] + print("ISR 入口候选(sw a7,0(sp))字号 = %s" % entries) + if entries != [43, 144, 250]: + print("警告:ISR 入口与预期 [43, 144, 250] 不一致,请核对顶层 IRQ_VECTOR!") + + # ---- 例程地址(追加在程序末尾,入口地址因此不变)---- + n = len(w) + dly_addr = n * 4 + dly_isr_addr = (n + 8) * 4 + + # ---- 逐条替换显示点 ---- + patched_main = patched_isr = 0 + i = 0 + while i < n - 1: + if w[i] == SHOW_SITE and w[i + 1] == ECALL: + if i < ISR1_WORD: + w[i] = enc_j(dly_addr - i * 4, RA) # jal ra, DISP_DLY + w[i + 1] = NOP + patched_main += 1 + else: + w[i] = enc_r(0, 0, A0, 0, A7) # add a7, a0, zero + # 注意:jal 落在 w[i+1],所以偏移必须按 (i+1) 算,否则会跳过例程首条 + w[i + 1] = enc_j(dly_isr_addr - (i + 1) * 4, A0) # jal a0, DISP_DLY_ISR + patched_isr += 1 + i += 2 + else: + i += 1 + print("显示点替换:主程序 %d 处、ISR %d 处" % (patched_main, patched_isr)) + + # ---- 自检:每个显示调用的跳转目标必须正好落在例程首字 ---- + def jal_target(word, addr): + imm = (((word >> 31) & 1) << 20) | (((word >> 21) & 0x3FF) << 1) \ + | (((word >> 20) & 1) << 11) | (((word >> 12) & 0xFF) << 12) + if imm & (1 << 20): + imm -= (1 << 21) + return addr + imm + + bad = [] + for i in range(n - 1): + if w[i] == enc_r(0, 0, A0, 0, A7) and (w[i + 1] & 0x7F) == 0x6F: + if jal_target(w[i + 1], (i + 1) * 4) != dly_isr_addr: + bad.append(i) + if (w[i] & 0x7F) == 0x6F and ((w[i] >> 7) & 0x1F) == RA and w[i + 1] == NOP: + if jal_target(w[i], i * 4) != dly_addr: + bad.append(i) + if bad: + raise SystemExit("自检失败:字 %s 的跳转目标不对" % bad) + print("自检通过:所有显示调用都精确跳到例程首字(DISP_DLY 0x%X / ISR 0x%X)" + % (dly_addr, dly_isr_addr)) + + w += disp_dly() + disp_dly_isr() + print("追加 DISP_DLY @字 %d (0x%X)、DISP_DLY_ISR @字 %d (0x%X)" + % (n, dly_addr, n + 8, dly_isr_addr)) + + # ---- 写 .vh(与 tools/hex2vh.py 的格式一致)---- + if len(w) > ROM_WORDS: + raise SystemExit("程序 %d 字,超过 %d 字上限" % (len(w), ROM_WORDS)) + with open(dst_vh, "w", encoding="utf-8") as f: + f.write(" // generated by tools/adapt_intrupt_sllsb.py - do not edit by hand\n") + f.write(" // source: %s (%d words, remaining entries filled with NOP)\n" + % (src, len(w))) + for a in range(ROM_WORDS): + f.write(" rom[%d] = 32'h%08X;\n" % (a, w[a] if a < len(w) else NOP)) + print("已生成 %s(%d 个字)" % (dst_vh, ROM_WORDS)) + + if dst_hex: + with open(dst_hex, "w", encoding="ascii") as f: + for x in w: + f.write("%08X\n" % x) + print("已生成 %s(适配后的镜像)" % dst_hex) + + +main()