Compare commits
2
Commits
f7844b7b1c
...
4ef3960553
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ef3960553 | ||
|
|
e44680a114 |
@@ -13,11 +13,15 @@
|
|||||||
# 说明文档:cpu21_riscv_redirect_int_bpb说明.md
|
# 说明文档:cpu21_riscv_redirect_int_bpb说明.md
|
||||||
#
|
#
|
||||||
# 用法:
|
# 用法:
|
||||||
# 1) 建议先删掉本目录下的 pipelined-cpu.xpr,以及 *.runs / *.sim / *.cache /
|
# 1) 在 Vivado Tcl Shell 里执行: source create_project.tcl
|
||||||
# *.hw / *.gen / *.ip_user_files 等生成目录(不删会在下面报错提示);
|
|
||||||
# 2) 在 Vivado Tcl Shell 里执行: source create_project.tcl
|
|
||||||
# 或命令行: vivado -mode batch -source create_project.tcl -log create.log
|
# 或命令行: vivado -mode batch -source create_project.tcl -log create.log
|
||||||
|
# 2) 脚本会**先自动清理旧工程**再新建:只删生成物(*.xpr / *.srcs / *.runs /
|
||||||
|
# *.sim / *.cache / *.hw / *.gen / *.ip_user_files / .Xil / xsim.dir /
|
||||||
|
# vivado*.jou|log|str / webtalk.*),srcs/、tools/、programs/ 一律不动。
|
||||||
|
# 不想自动清理(比如想在旧工程上追加设置)就把下面的 clean_first 改成 0。
|
||||||
# 3) 工程就地创建:pipelined-cpu.xpr(源文件仍在 srcs/ 下,不会被搬动)。
|
# 3) 工程就地创建:pipelined-cpu.xpr(源文件仍在 srcs/ 下,不会被搬动)。
|
||||||
|
# 4) 若提示 .xpr 删不掉,说明有 Vivado(含 Hardware Manager)正开着那个工程,
|
||||||
|
# 关掉它再跑一遍即可。
|
||||||
#
|
#
|
||||||
# 脚本用 [info script] 定位自身目录,所以整个文件夹拷到任何路径都能直接用。
|
# 脚本用 [info script] 定位自身目录,所以整个文件夹拷到任何路径都能直接用。
|
||||||
# 若想用 Vivado 自动生成的版本,见说明文档“工程分享”一节。
|
# 若想用 Vivado 自动生成的版本,见说明文档“工程分享”一节。
|
||||||
@@ -47,10 +51,62 @@ if {[llength $missing] > 0} {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if {[file exists "$origin_dir/$proj_name.xpr"]} {
|
# ---------------------------------------------------------------- 清理旧工程
|
||||||
puts "ERROR: 工程已存在:$origin_dir/$proj_name.xpr"
|
# 一键重建:先删掉旧工程和所有生成目录。工程完全由 srcs/ + 本脚本决定,
|
||||||
puts " 请先删除 .xpr(以及 *.runs / *.sim 等生成目录)后重跑本脚本。"
|
# 所以删掉不会丢任何源文件;不想自动清理就把 clean_first 改成 0。
|
||||||
return 1
|
set clean_first 1
|
||||||
|
|
||||||
|
if {$clean_first} {
|
||||||
|
# 必须删掉的工程目录:任何一个删不掉都不能继续(否则 Vivado 会拒绝建工程)
|
||||||
|
set proj_items [list \
|
||||||
|
"$origin_dir/$proj_name.xpr" \
|
||||||
|
"$origin_dir/$proj_name.srcs" \
|
||||||
|
"$origin_dir/$proj_name.runs" \
|
||||||
|
"$origin_dir/$proj_name.sim" \
|
||||||
|
"$origin_dir/$proj_name.cache" \
|
||||||
|
"$origin_dir/$proj_name.hw" \
|
||||||
|
"$origin_dir/$proj_name.gen" \
|
||||||
|
"$origin_dir/$proj_name.ip_user_files" \
|
||||||
|
"$origin_dir/$proj_name.lpr" \
|
||||||
|
"$origin_dir/.Xil"]
|
||||||
|
# 顺带清掉的杂项:删不掉也无所谓(本进程自己会占着 vivado.jou / .log / .str)
|
||||||
|
set junk_items [list \
|
||||||
|
"$origin_dir/xsim.dir" \
|
||||||
|
"$origin_dir/webtalk.jou" \
|
||||||
|
"$origin_dir/webtalk.log" \
|
||||||
|
"$origin_dir/usage_statistics_webtalk.html" \
|
||||||
|
"$origin_dir/usage_statistics_webtalk.xml"]
|
||||||
|
foreach pat {vivado*.jou vivado*.log vivado*.str} {
|
||||||
|
foreach f [glob -nocomplain "$origin_dir/$pat"] { lappend junk_items $f }
|
||||||
|
}
|
||||||
|
|
||||||
|
set blocked {}
|
||||||
|
set removed 0
|
||||||
|
foreach {group items} [list proj $proj_items junk $junk_items] {
|
||||||
|
foreach d $items {
|
||||||
|
if {![file exists $d]} { continue }
|
||||||
|
if {[catch {file delete -force $d} err]} {
|
||||||
|
puts " WARNING: 删不掉 [file tail $d]($err)"
|
||||||
|
if {$group eq "proj"} { lappend blocked [file tail $d] }
|
||||||
|
} else {
|
||||||
|
puts " 已删除:[file tail $d]"
|
||||||
|
incr removed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts "旧工程清理完成(删除 $removed 项)"
|
||||||
|
if {[llength $blocked] > 0} {
|
||||||
|
puts "ERROR: 这些工程目录删不掉:$blocked"
|
||||||
|
puts " 它们正被另一个 Vivado(GUI / Hardware Manager)占用。"
|
||||||
|
puts " 请关闭 Vivado 后重跑本脚本。"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if {[file exists "$origin_dir/$proj_name.xpr"] || [file exists "$origin_dir/$proj_name.runs"]} {
|
||||||
|
puts "ERROR: 工程已存在且 clean_first = 0:$origin_dir/$proj_name.xpr"
|
||||||
|
puts " 请先删除它,或把 clean_first 改成 1 让脚本自动清理。"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------- 建工程
|
# ---------------------------------------------------------------- 建工程
|
||||||
@@ -61,7 +117,8 @@ if {[file exists "$origin_dir/$proj_name.xpr"]} {
|
|||||||
# create_project $proj_name $origin_dir -part $part_name \
|
# create_project $proj_name $origin_dir -part $part_name \
|
||||||
# -board_part digilentinc.com:nexys4ddr:part0:1.1
|
# -board_part digilentinc.com:nexys4ddr:part0:1.1
|
||||||
# (那样工程会记上板卡,别人没装板卡文件就打不开了,所以默认不这么写。)
|
# (那样工程会记上板卡,别人没装板卡文件就打不开了,所以默认不这么写。)
|
||||||
create_project $proj_name $origin_dir -part $part_name
|
# -force:万一还有残留目录(例如被占用的 .runs)也能覆盖,不至于卡死。
|
||||||
|
create_project $proj_name $origin_dir -part $part_name -force
|
||||||
|
|
||||||
# 设计源文件:处理器 RTL + 板级顶层 + 片内 ROM 初始化
|
# 设计源文件:处理器 RTL + 板级顶层 + 片内 ROM 初始化
|
||||||
add_files -norecurse -fileset sources_1 [glob "$origin_dir/srcs/rtl/*.v"]
|
add_files -norecurse -fileset sources_1 [glob "$origin_dir/srcs/rtl/*.v"]
|
||||||
@@ -71,9 +128,14 @@ add_files -norecurse -fileset sources_1 [list \
|
|||||||
set_property file_type {Verilog Header} \
|
set_property file_type {Verilog Header} \
|
||||||
[get_files "$origin_dir/srcs/board/cpu21_board_rom.vh"]
|
[get_files "$origin_dir/srcs/board/cpu21_board_rom.vh"]
|
||||||
|
|
||||||
# 默认跑哪个内置程序:中断测试程序优先,其次是扫雷,最后是走马灯 demo。
|
# 默认跑哪个内置程序(同一时间只应启用一个):
|
||||||
# 修改下面两个开关即可切换板上程序;同一时间只应启用一个。
|
# use_intrupt_sllsb = 1 -> 课程新版「多级中断测试 + 附加 SLL/SB/BLTU」
|
||||||
set use_intrupt_ccab 1
|
# (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
|
set use_saolei 0
|
||||||
|
|
||||||
# 中断测试程序的 ROM 初始化。
|
# 中断测试程序的 ROM 初始化。
|
||||||
@@ -85,6 +147,15 @@ if {[file exists $intrupt_ccab_rom]} {
|
|||||||
puts "NOTE: 还没有 $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 生成,可能还不存在)。
|
# 扫雷程序的 ROM 初始化(由 saolei/tools/build.ps1 生成,可能还不存在)。
|
||||||
# 综合/仿真时定义宏 SAOLEI_ROM 就会用它替换上面的跑马灯 ROM。
|
# 综合/仿真时定义宏 SAOLEI_ROM 就会用它替换上面的跑马灯 ROM。
|
||||||
set saolei_rom "$origin_dir/srcs/board/cpu21_saolei_rom.vh"
|
set saolei_rom "$origin_dir/srcs/board/cpu21_saolei_rom.vh"
|
||||||
@@ -95,9 +166,12 @@ if {[file exists $saolei_rom]} {
|
|||||||
puts "NOTE: 还没有 $saolei_rom —— 需要先跑 saolei/tools/build.ps1 生成"
|
puts "NOTE: 还没有 $saolei_rom —— 需要先跑 saolei/tools/build.ps1 生成"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 关键:sources_1 定义 SAOLEI_ROM,cpu21_board_top.v 里的 `ifdef 链才会用扫雷 ROM
|
# 关键:sources_1 里定义对应宏,cpu21_board_top.v 的 `ifdef 链才会选中那个 ROM
|
||||||
# (该宏只影响综合用的 sources_1,仿真 fileset 仍各自用 tb 自带的 ROM)
|
# (宏只影响综合用的 sources_1;仿真 fileset 仍各自用 tb 自带的 ROM)
|
||||||
if {$use_intrupt_ccab && [file exists $intrupt_ccab_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]
|
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"
|
puts "NOTE: sources_1 已定义 RISC_V_INTRUPT_CCAB_ROM —— 上板跑 risc-v-intrupt-ccab"
|
||||||
} elseif {$use_saolei && [file exists $saolei_rom]} {
|
} elseif {$use_saolei && [file exists $saolei_rom]} {
|
||||||
@@ -142,7 +216,9 @@ foreach fs {sim_1 sim_2} {
|
|||||||
# ---------------------------------------------------------------- 结果汇总
|
# ---------------------------------------------------------------- 结果汇总
|
||||||
puts "工程已创建:$origin_dir/$proj_name.xpr"
|
puts "工程已创建:$origin_dir/$proj_name.xpr"
|
||||||
puts " sources_1 顶层 = cpu21_board_top(上板:时钟分频 + 片内 ROM/RAM + 引脚)"
|
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)}
|
set selected_program {risc-v-intrupt-ccab (RISC_V_INTRUPT_CCAB_ROM)}
|
||||||
} elseif {$use_saolei && [file exists $saolei_rom]} {
|
} elseif {$use_saolei && [file exists $saolei_rom]} {
|
||||||
set selected_program {扫雷 (SAOLEI_ROM)}
|
set selected_program {扫雷 (SAOLEI_ROM)}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -31,405 +31,438 @@
|
|||||||
// 注意:ROM_WORDS / RAM_WORDS 需为 2 的幂(默认 1024,对应地址位 [11:2])。
|
// 注意:ROM_WORDS / RAM_WORDS 需为 2 的幂(默认 1024,对应地址位 [11:2])。
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
module cpu21_board_top #(
|
module cpu21_board_top #(
|
||||||
parameter [31:0] LED_ADDR = 32'h0000_1000,
|
parameter [31:0] LED_ADDR = 32'h0000_1000,
|
||||||
parameter ROM_WORDS = 8192,
|
parameter ROM_WORDS = 8192,
|
||||||
parameter RAM_WORDS = 1024,
|
parameter RAM_WORDS = 1024,
|
||||||
parameter [31:0] USTATUS_INIT = 32'h0000_0001,
|
parameter [31:0] USTATUS_INIT = 32'h0000_0001,
|
||||||
// 板载 100 MHz 的分频比(1 = 直用 100 MHz,2 = 50 MHz,…)。
|
// 板载 100 MHz 的分频比(1 = 直用 100 MHz,2 = 50 MHz,…)。
|
||||||
// 乘除法改成多周期单元后,原来 ~94 ns 的组合乘法/除法已经不在关键路径上,
|
// 乘除法改成多周期单元后,原来 ~94 ns 的组合乘法/除法已经不在关键路径上,
|
||||||
// 实测(xc7a100tcsg324-1):
|
// 实测(xc7a100tcsg324-1):
|
||||||
// CLK_DIV=1(100 MHz):WNS = -1.1 ns,违例路径是 EX 级的
|
// CLK_DIV=1(100 MHz):WNS = -1.1 ns,违例路径是 EX 级的
|
||||||
// 分支判决/中断保存 → BPB 更新,与乘除法无关(逻辑只占 ~3 ns,
|
// 分支判决/中断保存 → BPB 更新,与乘除法无关(逻辑只占 ~3 ns,
|
||||||
// 7~8 ns 都是布线);
|
// 7~8 ns 都是布线);
|
||||||
// CLK_DIV=2( 50 MHz):WNS ≈ +8 ns,余量充足。
|
// CLK_DIV=2( 50 MHz):WNS ≈ +8 ns,余量充足。
|
||||||
// 因此默认取 2,既比原来的 16 分频快 8 倍,又能保证时序收敛。
|
// 因此默认取 2,既比原来的 16 分频快 8 倍,又能保证时序收敛。
|
||||||
parameter integer CLK_DIV = 2,
|
parameter integer CLK_DIV = 2,
|
||||||
// 中断综合测试程序(RISC_V_INTRUPT_CCAB_ROM)专用的 CPU 分频比。
|
// 中断综合测试程序(RISC_V_INTRUPT_CCAB_ROM)专用的 CPU 分频比。
|
||||||
// 该程序每次显示之间的延时常量是按 50 MHz 调的:50 MHz 下每个数值只停留
|
// 该程序每次显示之间的延时常量是按 50 MHz 调的:50 MHz 下每个数值只停留
|
||||||
// 约 10 ms,数码管上根本读不出来。停留时间与分频比成正比,例如:
|
// 约 10 ms,数码管上根本读不出来。停留时间与分频比成正比,例如:
|
||||||
// 8 → 12.5 MHz(每个数值约 40 ms)、16 → 6.25 MHz(约 80 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)。
|
// 32 → 3.125 MHz(约 160 ms)、64 → 1.5625 MHz(约 320 ms)。
|
||||||
// 取大于 2 的值只是把实际时钟变慢,XDC 的 cpu_clk 仍按最坏情况 50 MHz 约束,
|
// 取大于 2 的值只是把实际时钟变慢,XDC 的 cpu_clk 仍按最坏情况 50 MHz 约束,
|
||||||
// 所以不会掩盖时序违例(约束偏严)。
|
// 所以不会掩盖时序违例(约束偏严)。
|
||||||
parameter integer CLK_DIV_INTRUPT = 32,
|
parameter integer CLK_DIV_INTRUPT = 32,
|
||||||
// 鼠标事件源:0 = 板上 5 向按键(免外设,默认);1 = PS/2 鼠标(Pmod JA)
|
// 鼠标事件源:0 = 板上 5 向按键(免外设,默认);1 = PS/2 鼠标(Pmod JA)
|
||||||
parameter integer USE_PS2_MOUSE = 0
|
parameter integer USE_PS2_MOUSE = 0
|
||||||
) (
|
) (
|
||||||
input wire clk100, // E3
|
input wire clk100, // E3
|
||||||
input wire rst_n, // C12:CPU_RESETN,低有效
|
input wire rst_n, // C12:CPU_RESETN,低有效
|
||||||
input wire go, // N17:BTNC(同时用作鼠标左键)
|
input wire go, // N17:BTNC(同时用作鼠标左键)
|
||||||
input wire [ 2:0] irq_sw, // SW[2:0]:原来的 3 路中断源(保持兼容)
|
input wire [ 2:0] irq_sw, // SW[2:0]:原来的 3 路中断源(保持兼容)
|
||||||
input wire btnu, // M18:光标上
|
input wire btnu, // M18:光标上
|
||||||
input wire btnd, // P18:光标下
|
input wire btnd, // P18:光标下
|
||||||
input wire btnl, // P17:光标左
|
input wire btnl, // P17:光标左
|
||||||
input wire btnr, // M17:光标右
|
input wire btnr, // M17:光标右
|
||||||
input wire sw_flag, // R15:SW[3],插旗模式(软件读 INPUT 寄存器)
|
input wire sw_flag, // R15:SW[3],插旗模式(软件读 INPUT 寄存器)
|
||||||
output wire [15:0] led, // LED[15:0]
|
output wire [15:0] led, // LED[15:0]
|
||||||
output wire led_we, // LED16_B:MMIO 写入指示
|
output wire led_we, // LED16_B:MMIO 写入指示
|
||||||
// 七段数码管(共阳极:位选/段选都是低有效)
|
// 七段数码管(共阳极:位选/段选都是低有效)
|
||||||
output wire [ 7:0] an,
|
output wire [ 7:0] an,
|
||||||
output wire [ 6:0] seg,
|
output wire [ 6:0] seg,
|
||||||
output wire dp,
|
output wire dp,
|
||||||
// VGA
|
// VGA
|
||||||
output wire [ 3:0] vga_r,
|
output wire [ 3:0] vga_r,
|
||||||
output wire [ 3:0] vga_g,
|
output wire [ 3:0] vga_g,
|
||||||
output wire [ 3:0] vga_b,
|
output wire [ 3:0] vga_b,
|
||||||
output wire vga_hs,
|
output wire vga_hs,
|
||||||
output wire vga_vs,
|
output wire vga_vs,
|
||||||
// PS/2(只有 USE_PS2_MOUSE=1 时才用)
|
// PS/2(只有 USE_PS2_MOUSE=1 时才用)
|
||||||
input wire ps2_clk,
|
input wire ps2_clk,
|
||||||
input wire ps2_data
|
input wire ps2_data
|
||||||
);
|
);
|
||||||
localparam ROM_AW = $clog2(ROM_WORDS);
|
localparam ROM_AW = $clog2(ROM_WORDS);
|
||||||
localparam RAM_AW = $clog2(RAM_WORDS);
|
localparam RAM_AW = $clog2(RAM_WORDS);
|
||||||
|
|
||||||
// CPU 时钟实际用的分频比:中断综合测试程序用更慢的 CLK_DIV_INTRUPT,
|
// CPU 时钟实际用的分频比:中断综合测试程序用更慢的 CLK_DIV_INTRUPT,
|
||||||
// 其余程序用 CLK_DIV。两者必须都是偶数(保证 50% 占空比)。
|
// 其余程序用 CLK_DIV。两者必须都是偶数(保证 50% 占空比)。
|
||||||
`ifdef RISC_V_INTRUPT_CCAB_ROM
|
`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
|
`else
|
||||||
localparam integer CPU_DIV = CLK_DIV;
|
localparam integer CPU_DIV = CLK_DIV;
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
// 数码管扫描分频:目标是“每位数码管约 125 Hz 刷新”(即每步 1 ms),与 CPU
|
// 数码管扫描分频:目标是“每位数码管约 125 Hz 刷新”(即每步 1 ms),与 CPU
|
||||||
// 时钟频率无关。每步时间 = REFRESH_DIV / f_cpu,而 f_cpu = 100 MHz / CPU_DIV,
|
// 时钟频率无关。每步时间 = REFRESH_DIV / f_cpu,而 f_cpu = 100 MHz / CPU_DIV,
|
||||||
// 所以 REFRESH_DIV = 1 ms × f_cpu = 100000 / CPU_DIV:
|
// 所以 REFRESH_DIV = 1 ms × f_cpu = 100000 / CPU_DIV:
|
||||||
// CPU_DIV = 2( 50 MHz)-> 50000(每步 1 ms,每位数码管 125 Hz)
|
// CPU_DIV = 2( 50 MHz)-> 50000(每步 1 ms,每位数码管 125 Hz)
|
||||||
// CPU_DIV = 8(12.5 MHz)-> 12500(同上)
|
// CPU_DIV = 8(12.5 MHz)-> 12500(同上)
|
||||||
// 例:CPU_DIV = 32(3.125 MHz)-> 3125(每步仍是 1 ms)。
|
// 例:CPU_DIV = 32(3.125 MHz)-> 3125(每步仍是 1 ms)。
|
||||||
// 不这样缩放的话,CPU 降频时扫描会按同样比例变慢,肉眼能看到闪烁。
|
// 不这样缩放的话,CPU 降频时扫描会按同样比例变慢,肉眼能看到闪烁。
|
||||||
localparam integer SEG_REFRESH_DIV = 100000 / CPU_DIV;
|
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);跑中断综合测试
|
// 时钟:100 MHz / CPU_DIV 给 CPU。默认 50 MHz(CLK_DIV=2);跑中断综合测试
|
||||||
// 程序时用更慢的 CLK_DIV_INTRUPT(见该参数说明),让数码管上的数值停留更久。
|
// 程序时用更慢的 CLK_DIV_INTRUPT(见该参数说明),让数码管上的数值停留更久。
|
||||||
//
|
//
|
||||||
// 乘除法已经是 cpu21_riscv_muldiv 里的多周期单元,关键路径上不再有组合的
|
// 乘除法已经是 cpu21_riscv_muldiv 里的多周期单元,关键路径上不再有组合的
|
||||||
// 32x32 乘法/除法;剩下的违例路径是 EX 级“分支判决/中断保存 → BPB 更新”,
|
// 32x32 乘法/除法;剩下的违例路径是 EX 级“分支判决/中断保存 → BPB 更新”,
|
||||||
// 与乘除法无关,实测 100 MHz 下 WNS = -1.1 ns,50 MHz 下余量约 +8 ns。
|
// 与乘除法无关,实测 100 MHz 下 WNS = -1.1 ns,50 MHz 下余量约 +8 ns。
|
||||||
// 分频后的时钟由 Vivado 自动插 BUFG;XDC 里用 create_generated_clock 声明。
|
// 分频后的时钟由 Vivado 自动插 BUFG;XDC 里用 create_generated_clock 声明。
|
||||||
// XDC 按最坏情况固定成 -divide_by 2(50 MHz),所以这里把实际时钟变慢属于
|
// XDC 按最坏情况固定成 -divide_by 2(50 MHz),所以这里把实际时钟变慢属于
|
||||||
// “约束偏严”,不会掩盖时序违例。
|
// “约束偏严”,不会掩盖时序违例。
|
||||||
//
|
//
|
||||||
// 中断综合测试程序会用更慢的 CPU_DIV(见 CLK_DIV_INTRUPT):程序里的延时常量
|
// 中断综合测试程序会用更慢的 CPU_DIV(见 CLK_DIV_INTRUPT):程序里的延时常量
|
||||||
// 按 50 MHz 调好,50 MHz 下每个数值只停留约 10 ms,读数根本看不清;
|
// 按 50 MHz 调好,50 MHz 下每个数值只停留约 10 ms,读数根本看不清;
|
||||||
// 停留时间与分频比成正比,具体见 CLK_DIV_INTRUPT 的说明。
|
// 停留时间与分频比成正比,具体见 CLK_DIV_INTRUPT 的说明。
|
||||||
// 注意:VGA 的 25 MHz 像素节拍也是从这个 CPU 时钟分频出来的,CPU 降频时
|
// 注意:VGA 的 25 MHz 像素节拍也是从这个 CPU 时钟分频出来的,CPU 降频时
|
||||||
// VGA 行场时序会跟着变慢(超出 VGA 规范)。中断测试程序不用 VGA,无影响。
|
// VGA 行场时序会跟着变慢(超出 VGA 规范)。中断测试程序不用 VGA,无影响。
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
reg [15:0] clk_cnt;
|
reg [15:0] clk_cnt;
|
||||||
reg clk_div;
|
reg clk_div;
|
||||||
|
|
||||||
always @(posedge clk100 or posedge arst) begin
|
always @(posedge clk100 or posedge arst) begin
|
||||||
if (arst) begin
|
if (arst) begin
|
||||||
clk_cnt <= 16'd0;
|
clk_cnt <= 16'd0;
|
||||||
clk_div <= 1'b0;
|
clk_div <= 1'b0;
|
||||||
end else if (clk_cnt == (CPU_DIV / 2 - 1)) begin
|
end
|
||||||
clk_cnt <= 16'd0;
|
else if (clk_cnt == (CPU_DIV / 2 - 1)) begin
|
||||||
clk_div <= ~clk_div;
|
clk_cnt <= 16'd0;
|
||||||
end else begin
|
clk_div <= ~clk_div;
|
||||||
clk_cnt <= clk_cnt + 16'd1;
|
end
|
||||||
|
else begin
|
||||||
|
clk_cnt <= clk_cnt + 16'd1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
wire clk_cpu = clk_div;
|
wire clk_cpu = clk_div;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 复位同步器:按键异步置位、释放与 CPU 时钟同步
|
// 复位同步器:按键异步置位、释放与 CPU 时钟同步
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
reg [2:0] rst_sync_q;
|
reg [2:0] rst_sync_q;
|
||||||
|
|
||||||
always @(posedge clk_cpu or posedge arst) begin
|
always @(posedge clk_cpu or posedge arst) begin
|
||||||
if (arst) rst_sync_q <= 3'b111;
|
if (arst)
|
||||||
else rst_sync_q <= {rst_sync_q[1:0], 1'b0};
|
rst_sync_q <= 3'b111;
|
||||||
end
|
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 逻辑与例化都要用到)
|
// CPU 接口连线(先声明:后面的 ROM/RAM 逻辑与例化都要用到)
|
||||||
wire [31:0] instr_addr;
|
wire [31:0] instr_addr;
|
||||||
wire [31:0] data_addr;
|
wire [31:0] data_addr;
|
||||||
wire [31:0] data_wdata;
|
wire [31:0] data_wdata;
|
||||||
wire [ 3:0] data_wstrb;
|
wire [ 3:0] data_wstrb;
|
||||||
wire data_we;
|
wire data_we;
|
||||||
wire [31:0] led_data; // LED_ADDR 写入值,同时作为七段数码管显示数据
|
wire [31:0] led_data; // LED_ADDR 写入值,同时作为七段数码管显示数据
|
||||||
wire led_valid;
|
wire led_valid;
|
||||||
// 扫雷扩展外设的连线(先声明,例化在下面)
|
// 扫雷扩展外设的连线(先声明,例化在下面)
|
||||||
wire [31:0] disp_ctrl, disp_cursor; // 显示控制器(CPU 内部 MMIO 驱动)
|
wire [31:0] disp_ctrl, disp_cursor; // 显示控制器(CPU 内部 MMIO 驱动)
|
||||||
wire [31:0] seg_data; // 保留的独立数码管 MMIO 数据
|
wire [31:0] seg_data; // 保留的独立数码管 MMIO 数据
|
||||||
wire seg_valid;
|
wire seg_valid;
|
||||||
wire fb_we; // 显存写端口
|
wire fb_we; // 显存写端口
|
||||||
wire [ 9:0] fb_waddr;
|
wire [ 9:0] fb_waddr;
|
||||||
wire [31:0] fb_wdata;
|
wire [31:0] fb_wdata;
|
||||||
wire [ 3:0] fb_wstrb;
|
wire [ 3:0] fb_wstrb;
|
||||||
wire [ 9:0] fb_raddr; // 显存读端口(VGA)
|
wire [ 9:0] fb_raddr; // 显存读端口(VGA)
|
||||||
wire mouse_irq, level_irq; // 鼠标事件中断 / 软件中断(关卡入口)
|
wire mouse_irq, level_irq; // 鼠标事件中断 / 软件中断(关卡入口)
|
||||||
wire [1:0] irq_level; // 当前正在服务的中断级别(0 = 不在中断里,1/2/3 = 在 ISR 里)
|
wire [1:0] irq_level; // 当前正在服务的中断级别(0 = 不在中断里,1/2/3 = 在 ISR 里)
|
||||||
wire frame_tick;
|
wire frame_tick;
|
||||||
wire [15:0] sw_vec = {12'b0, sw_flag, irq_sw};
|
wire [15:0] sw_vec = {12'b0, sw_flag, irq_sw};
|
||||||
// 中断连线:SW0 与鼠标共用一个入口,SW1 与"关卡入口"共用一个入口。
|
// 中断连线:SW0 与鼠标共用一个入口,SW1 与"关卡入口"共用一个入口。
|
||||||
wire [2:0] irq_vec = {irq_sw[2], (level_irq | irq_sw[1]), (mouse_irq | irq_sw[0])};
|
wire [2:0] irq_vec = {irq_sw[2], (level_irq | irq_sw[1]), (mouse_irq | irq_sw[0])};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 指令 ROM:组合读(未用到的地址填 NOP)
|
// 指令 ROM:组合读(未用到的地址填 NOP)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
reg [31:0] rom[0:ROM_WORDS-1];
|
reg [31:0] rom[0:ROM_WORDS-1];
|
||||||
integer i;
|
integer i;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
for (i = 0; i < ROM_WORDS; i = i + 1) rom[i] = 32'h0000_0013; // NOP 填充
|
for (i = 0; i < ROM_WORDS; i = i + 1)
|
||||||
|
rom[i] = 32'h0000_0013; // NOP 填充
|
||||||
`ifdef SAOLEI_ROM
|
`ifdef SAOLEI_ROM
|
||||||
// 扫雷程序(由 saolei/tools/build.ps1 生成的 cpu21_saolei_rom.vh)。
|
// 扫雷程序(由 saolei/tools/build.ps1 生成的 cpu21_saolei_rom.vh)。
|
||||||
// 综合/仿真时定义宏 SAOLEI_ROM 即可切换到这个程序;不定义就是下面的跑马灯。
|
// 综合/仿真时定义宏 SAOLEI_ROM 即可切换到这个程序;不定义就是下面的跑马灯。
|
||||||
`include "cpu21_saolei_rom.vh"
|
`include "cpu21_saolei_rom.vh"
|
||||||
`elsif RISC_V_INTRUPT_CCAB_ROM
|
`elsif RISC_V_INTRUPT_CCAB_ROM
|
||||||
// 中断综合测试程序:三个中断入口由镜像中的实际标签位置决定。
|
// 中断综合测试程序:三个中断入口由镜像中的实际标签位置决定。
|
||||||
`include "risc-v-intrupt-ccab.vh"
|
`include "risc-v-intrupt-ccab.vh"
|
||||||
`elsif BOARD_ROM_FAST
|
`elsif RISC_V_INTRUPT_SLLSB_ROM
|
||||||
// 仿真专用:把演示程序的延时改小的版本(综合流程不会用到)
|
// 课程新版中断测试(附加 SLL/SB/BLTU),ISR 入口 0x0AC / 0x240 / 0x3E8。
|
||||||
`include "cpu21_board_rom_fast.vh"
|
`include "risc-v-intrupt-sllsb.vh"
|
||||||
|
`elsif BOARD_ROM_FAST
|
||||||
|
// 仿真专用:把演示程序的延时改小的版本(综合流程不会用到)
|
||||||
|
`include "cpu21_board_rom_fast.vh"
|
||||||
`else
|
`else
|
||||||
`include "cpu21_board_rom.vh"
|
`include "cpu21_board_rom.vh"
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 数据 RAM:字节写使能 + 组合读
|
// 数据 RAM:字节写使能 + 组合读
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
reg [31:0] ram[0:RAM_WORDS-1];
|
reg [31:0] ram[0:RAM_WORDS-1];
|
||||||
integer j;
|
integer j;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
for (j = 0; j < RAM_WORDS; j = j + 1) ram[j] = 32'b0;
|
for (j = 0; j < RAM_WORDS; j = j + 1)
|
||||||
end
|
ram[j] = 32'b0;
|
||||||
|
|
||||||
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
|
||||||
end
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
wire [ROM_AW+1:2] rom_index = instr_addr[ROM_AW+1:2];
|
||||||
// 处理器:只连接上板需要的端口,调试端口留空(不产生 I/O)
|
wire [RAM_AW+1:2] ram_index = data_addr[RAM_AW+1:2];
|
||||||
// ---------------------------------------------------------------------------
|
wire ram_sel = (data_addr[31:RAM_AW+2] == 0);
|
||||||
cpu21_riscv_redirect_int_bpb #(
|
|
||||||
.LED_ADDR (LED_ADDR),
|
wire [31:0] instr_word = rom[rom_index];
|
||||||
.USTATUS_INIT(USTATUS_INIT),
|
wire [31:0] data_rdata = ram_sel ? ram[ram_index] : 32'b0;
|
||||||
// 中断入口必须与所选 ROM 镜像中的 ISR 起点一致。
|
|
||||||
|
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
|
`ifdef RISC_V_INTRUPT_CCAB_ROM
|
||||||
// risc-v-intrupt-ccab.hex:字 43/121/194
|
// risc-v-intrupt-ccab.hex:字 43/121/194
|
||||||
.IRQ1_VECTOR (32'h0000_00AC),
|
.IRQ1_VECTOR (32'h0000_00AC),
|
||||||
.IRQ2_VECTOR (32'h0000_01E4),
|
.IRQ2_VECTOR (32'h0000_01E4),
|
||||||
.IRQ3_VECTOR (32'h0000_0308)
|
.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
|
`else
|
||||||
// 扫雷程序:linker.ld 中固定的 0x100/0x200/0x300
|
// 扫雷程序:linker.ld 中固定的 0x100/0x200/0x300
|
||||||
.IRQ1_VECTOR (32'h0000_0100),
|
.IRQ1_VECTOR (32'h0000_0100),
|
||||||
.IRQ2_VECTOR (32'h0000_0200),
|
.IRQ2_VECTOR (32'h0000_0200),
|
||||||
.IRQ3_VECTOR (32'h0000_0300)
|
.IRQ3_VECTOR (32'h0000_0300)
|
||||||
`endif
|
`endif
|
||||||
) u_cpu (
|
) u_cpu (
|
||||||
.clk (clk_cpu),
|
.clk (clk_cpu),
|
||||||
.reset (reset),
|
.reset (reset),
|
||||||
.instr_i (instr_word),
|
.instr_i (instr_word),
|
||||||
.data_rdata_i(data_rdata),
|
.data_rdata_i(data_rdata),
|
||||||
.irq_i (irq_vec),
|
.irq_i (irq_vec),
|
||||||
.go_i (go),
|
.go_i (go),
|
||||||
|
|
||||||
.instr_addr_o(instr_addr),
|
.instr_addr_o(instr_addr),
|
||||||
.data_addr_o (data_addr),
|
.data_addr_o (data_addr),
|
||||||
.data_wdata_o(data_wdata),
|
.data_wdata_o(data_wdata),
|
||||||
.data_wstrb_o(data_wstrb),
|
.data_wstrb_o(data_wstrb),
|
||||||
.data_we_o (data_we),
|
.data_we_o (data_we),
|
||||||
|
|
||||||
.led_data_o (led_data),
|
.led_data_o (led_data),
|
||||||
.led_valid_o(led_valid),
|
.led_valid_o(led_valid),
|
||||||
|
|
||||||
// 扫雷扩展外设
|
// 扫雷扩展外设
|
||||||
.seg_data_o (seg_data),
|
.seg_data_o (seg_data),
|
||||||
.seg_valid_o (seg_valid),
|
.seg_valid_o (seg_valid),
|
||||||
.fb_we_o (fb_we),
|
.fb_we_o (fb_we),
|
||||||
.fb_waddr_o (fb_waddr),
|
.fb_waddr_o (fb_waddr),
|
||||||
.fb_wdata_o (fb_wdata),
|
.fb_wdata_o (fb_wdata),
|
||||||
.fb_wstrb_o (fb_wstrb),
|
.fb_wstrb_o (fb_wstrb),
|
||||||
.fb_rdata_i (fb_rdata),
|
.fb_rdata_i (fb_rdata),
|
||||||
.disp_ctrl_o (disp_ctrl),
|
.disp_ctrl_o (disp_ctrl),
|
||||||
.disp_cursor_o (disp_cursor),
|
.disp_cursor_o (disp_cursor),
|
||||||
.mouse_ev_valid_i (ev_valid),
|
.mouse_ev_valid_i (ev_valid),
|
||||||
.mouse_dx_i (ev_dx),
|
.mouse_dx_i (ev_dx),
|
||||||
.mouse_dy_i (ev_dy),
|
.mouse_dy_i (ev_dy),
|
||||||
.mouse_btn_i (ev_btn),
|
.mouse_btn_i (ev_btn),
|
||||||
.sw_i (sw_vec),
|
.sw_i (sw_vec),
|
||||||
.frame_tick_i (frame_tick),
|
.frame_tick_i (frame_tick),
|
||||||
.mouse_irq_o (mouse_irq),
|
.mouse_irq_o (mouse_irq),
|
||||||
.level_irq_o (level_irq),
|
.level_irq_o (level_irq),
|
||||||
// 中断服务级别,供板上的中断指示 LED 使用(见下面 LED 那一段)
|
// 中断服务级别,供板上的中断指示 LED 使用(见下面 LED 那一段)
|
||||||
.irq_current_level_o(irq_level)
|
.irq_current_level_o(irq_level)
|
||||||
);
|
);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 板载 LED:三路中断指示;十六进制数据改由七段数码管显示。
|
// 板载 LED:三路中断指示;十六进制数据改由七段数码管显示。
|
||||||
//
|
//
|
||||||
// 第 k 路中断从"请求出现"开始点亮,一直亮到它的 ISR 执行完 uret(中断返回)
|
// 第 k 路中断从"请求出现"开始点亮,一直亮到它的 ISR 执行完 uret(中断返回)
|
||||||
// 之后才熄灭:
|
// 之后才熄灭:
|
||||||
// 置位:irq_vec[k] 的上升沿。中断控制器内部也是按上升沿响应中断的
|
// 置位:irq_vec[k] 的上升沿。中断控制器内部也是按上升沿响应中断的
|
||||||
// (cpu21_riscv_irq_ctrl 里的 irq_event),两者行为一致;开关一直
|
// (cpu21_riscv_irq_ctrl 里的 irq_event),两者行为一致;开关一直
|
||||||
// 接通不会重复点亮,只有新的上升沿才会重新置位。
|
// 接通不会重复点亮,只有新的上升沿才会重新置位。
|
||||||
// 清零:服务级别 irq_level 从 k+1 **降下来**,说明第 k+1 级的中断已经返回。
|
// 清零:服务级别 irq_level 从 k+1 **降下来**,说明第 k+1 级的中断已经返回。
|
||||||
// 注意必须判断“下降”:级别从 1 升到 2 是深层中断抢占,此时第 1 级
|
// 注意必须判断“下降”:级别从 1 升到 2 是深层中断抢占,此时第 1 级
|
||||||
// 的中断还在服务中,LED 不能熄。中断可以嵌套,返回时按级别逐层降
|
// 的中断还在服务中,LED 不能熄。中断可以嵌套,返回时按级别逐层降
|
||||||
// 下来,因此每一路都在自己的 ISR 结束时熄灭。
|
// 下来,因此每一路都在自己的 ISR 结束时熄灭。
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
reg [2:0] irq_req_q; // 中断请求打一拍,用于取上升沿
|
reg [2:0] irq_req_q; // 中断请求打一拍,用于取上升沿
|
||||||
reg [1:0] irq_level_q; // 服务级别打一拍,用于检测"返回"
|
reg [1:0] irq_level_q; // 服务级别打一拍,用于检测"返回"
|
||||||
reg [2:0] irq_led_q; // 三路中断指示
|
reg [2:0] irq_led_q; // 三路中断指示
|
||||||
|
|
||||||
wire isr_ret0 = (irq_level_q == 2'd1) && (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_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_ret2 = (irq_level_q == 2'd3) && (irq_level < irq_level_q);
|
||||||
|
|
||||||
always @(posedge clk_cpu or posedge arst) begin
|
always @(posedge clk_cpu or posedge arst) begin
|
||||||
if (arst) begin
|
if (arst) begin
|
||||||
irq_req_q <= 3'b000;
|
irq_req_q <= 3'b000;
|
||||||
irq_level_q <= 2'd0;
|
irq_level_q <= 2'd0;
|
||||||
irq_led_q <= 3'b000;
|
irq_led_q <= 3'b000;
|
||||||
end else begin
|
end
|
||||||
irq_req_q <= irq_vec;
|
else begin
|
||||||
irq_level_q <= irq_level;
|
irq_req_q <= irq_vec;
|
||||||
// 请求上升沿 -> 点亮;对应级别的 ISR 返回 -> 熄灭
|
irq_level_q <= irq_level;
|
||||||
irq_led_q[0] <= (irq_vec[0] & ~irq_req_q[0]) | (irq_led_q[0] & ~isr_ret0);
|
// 请求上升沿 -> 点亮;对应级别的 ISR 返回 -> 熄灭
|
||||||
irq_led_q[1] <= (irq_vec[1] & ~irq_req_q[1]) | (irq_led_q[1] & ~isr_ret1);
|
irq_led_q[0] <= (irq_vec[0] & ~irq_req_q[0]) | (irq_led_q[0] & ~isr_ret0);
|
||||||
irq_led_q[2] <= (irq_vec[2] & ~irq_req_q[2]) | (irq_led_q[2] & ~isr_ret2);
|
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
|
||||||
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
|
always @(posedge clk_cpu or posedge arst) begin
|
||||||
if (arst) led_we_cnt <= 24'd0;
|
if (arst)
|
||||||
else if (led_valid) led_we_cnt <= 24'hFF_FFFF; // 约 0.34 s @50 MHz
|
led_we_cnt <= 24'd0;
|
||||||
// (12.5 MHz 下约 1.36 s)
|
else if (led_valid)
|
||||||
else if (led_we_cnt != 24'd0) led_we_cnt <= led_we_cnt - 24'd1;
|
led_we_cnt <= 24'hFF_FFFF; // 约 0.34 s @50 MHz
|
||||||
end
|
// (12.5 MHz 下约 1.36 s)
|
||||||
|
else if (led_we_cnt != 24'd0)
|
||||||
assign led_we = (led_we_cnt != 24'd0);
|
led_we_cnt <= led_we_cnt - 24'd1;
|
||||||
|
|
||||||
// ===========================================================================
|
|
||||||
// 扫雷外设:显存 + 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];
|
|
||||||
end
|
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;
|
// 扫雷外设:显存 + VGA + 七段数码管 + 鼠标事件源 + 中断连线
|
||||||
always @(posedge clk_cpu or posedge arst) begin
|
//
|
||||||
if (arst) px_q <= 1'b0;
|
// 显存是一块 1200 字节的双口 RAM(40x30 格,每格 1 字节):CPU 通过 MMIO 的
|
||||||
else px_q <= ~px_q;
|
// fb_* 写端口写入,VGA 用另一个读端口组合读出。两者同处 clk_cpu 域(VGA 的
|
||||||
end
|
// 25 MHz 像素节拍由使能信号产生,不是独立时钟),因此没有跨时钟域问题。
|
||||||
wire px_tick = ~px_q;
|
// ===========================================================================
|
||||||
|
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 刷新(不闪烁)。
|
reg [31:0] fb[0:FB_WORDS-1];
|
||||||
cpu21_seg7 #(
|
integer k;
|
||||||
.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
|
||||||
wire ev_valid;
|
for (k = 0; k < FB_WORDS; k = k + 1)
|
||||||
wire [7:0] ev_dx, ev_dy;
|
fb[k] = 32'b0;
|
||||||
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
|
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
|
endmodule
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||||
Reference in New Issue
Block a user