Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ef3960553 | ||
|
|
e44680a114 |
@@ -13,11 +13,15 @@
|
||||
# 说明文档:cpu21_riscv_redirect_int_bpb说明.md
|
||||
#
|
||||
# 用法:
|
||||
# 1) 建议先删掉本目录下的 pipelined-cpu.xpr,以及 *.runs / *.sim / *.cache /
|
||||
# *.hw / *.gen / *.ip_user_files 等生成目录(不删会在下面报错提示);
|
||||
# 2) 在 Vivado Tcl Shell 里执行: source create_project.tcl
|
||||
# 1) 在 Vivado Tcl Shell 里执行: source create_project.tcl
|
||||
# 或命令行: 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/ 下,不会被搬动)。
|
||||
# 4) 若提示 .xpr 删不掉,说明有 Vivado(含 Hardware Manager)正开着那个工程,
|
||||
# 关掉它再跑一遍即可。
|
||||
#
|
||||
# 脚本用 [info script] 定位自身目录,所以整个文件夹拷到任何路径都能直接用。
|
||||
# 若想用 Vivado 自动生成的版本,见说明文档“工程分享”一节。
|
||||
@@ -47,11 +51,63 @@ if {[llength $missing] > 0} {
|
||||
return 1
|
||||
}
|
||||
|
||||
if {[file exists "$origin_dir/$proj_name.xpr"]} {
|
||||
puts "ERROR: 工程已存在:$origin_dir/$proj_name.xpr"
|
||||
puts " 请先删除 .xpr(以及 *.runs / *.sim 等生成目录)后重跑本脚本。"
|
||||
# ---------------------------------------------------------------- 清理旧工程
|
||||
# 一键重建:先删掉旧工程和所有生成目录。工程完全由 srcs/ + 本脚本决定,
|
||||
# 所以删掉不会丢任何源文件;不想自动清理就把 clean_first 改成 0。
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------- 建工程
|
||||
# 只用 -part 建工程,**不依赖"板卡文件"**:Vivado 默认不带 Nexys4DDR 的 board 文件,
|
||||
@@ -61,7 +117,8 @@ if {[file exists "$origin_dir/$proj_name.xpr"]} {
|
||||
# create_project $proj_name $origin_dir -part $part_name \
|
||||
# -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 初始化
|
||||
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} \
|
||||
[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 +147,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 +166,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 +216,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)}
|
||||
|
||||
@@ -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
|
||||
@@ -86,6 +86,9 @@ module cpu21_board_top #(
|
||||
// CPU 时钟实际用的分频比:中断综合测试程序用更慢的 CLK_DIV_INTRUPT,
|
||||
// 其余程序用 CLK_DIV。两者必须都是偶数(保证 50% 占空比)。
|
||||
`ifdef RISC_V_INTRUPT_CCAB_ROM
|
||||
|
||||
localparam integer CPU_DIV = CLK_DIV_INTRUPT;
|
||||
`elsif RISC_V_INTRUPT_SLLSB_ROM
|
||||
localparam integer CPU_DIV = CLK_DIV_INTRUPT;
|
||||
`else
|
||||
localparam integer CPU_DIV = CLK_DIV;
|
||||
@@ -126,10 +129,12 @@ module cpu21_board_top #(
|
||||
if (arst) begin
|
||||
clk_cnt <= 16'd0;
|
||||
clk_div <= 1'b0;
|
||||
end else if (clk_cnt == (CPU_DIV / 2 - 1)) begin
|
||||
end
|
||||
else if (clk_cnt == (CPU_DIV / 2 - 1)) begin
|
||||
clk_cnt <= 16'd0;
|
||||
clk_div <= ~clk_div;
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
clk_cnt <= clk_cnt + 16'd1;
|
||||
end
|
||||
end
|
||||
@@ -142,8 +147,10 @@ module cpu21_board_top #(
|
||||
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};
|
||||
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];
|
||||
@@ -179,7 +186,8 @@ module cpu21_board_top #(
|
||||
integer i;
|
||||
|
||||
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
|
||||
// 扫雷程序(由 saolei/tools/build.ps1 生成的 cpu21_saolei_rom.vh)。
|
||||
// 综合/仿真时定义宏 SAOLEI_ROM 即可切换到这个程序;不定义就是下面的跑马灯。
|
||||
@@ -187,6 +195,9 @@ module cpu21_board_top #(
|
||||
`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"
|
||||
@@ -203,7 +214,8 @@ module cpu21_board_top #(
|
||||
integer j;
|
||||
|
||||
initial begin
|
||||
for (j = 0; j < RAM_WORDS; j = j + 1) ram[j] = 32'b0;
|
||||
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];
|
||||
@@ -215,10 +227,14 @@ module cpu21_board_top #(
|
||||
|
||||
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];
|
||||
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
|
||||
|
||||
@@ -234,6 +250,11 @@ module cpu21_board_top #(
|
||||
.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),
|
||||
@@ -305,7 +326,8 @@ module cpu21_board_top #(
|
||||
irq_req_q <= 3'b000;
|
||||
irq_level_q <= 2'd0;
|
||||
irq_led_q <= 3'b000;
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
irq_req_q <= irq_vec;
|
||||
irq_level_q <= irq_level;
|
||||
// 请求上升沿 -> 点亮;对应级别的 ISR 返回 -> 熄灭
|
||||
@@ -320,10 +342,13 @@ module cpu21_board_top #(
|
||||
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
|
||||
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;
|
||||
else if (led_we_cnt != 24'd0)
|
||||
led_we_cnt <= led_we_cnt - 24'd1;
|
||||
end
|
||||
|
||||
assign led_we = (led_we_cnt != 24'd0);
|
||||
@@ -343,15 +368,20 @@ module cpu21_board_top #(
|
||||
integer k;
|
||||
|
||||
initial begin
|
||||
for (k = 0; k < FB_WORDS; k = k + 1) fb[k] = 32'b0;
|
||||
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];
|
||||
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
|
||||
|
||||
@@ -360,8 +390,10 @@ module cpu21_board_top #(
|
||||
// ---- 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;
|
||||
if (arst)
|
||||
px_q <= 1'b0;
|
||||
else
|
||||
px_q <= ~px_q;
|
||||
end
|
||||
wire px_tick = ~px_q;
|
||||
|
||||
@@ -416,7 +448,8 @@ module cpu21_board_top #(
|
||||
.ev_btn_o (ev_btn),
|
||||
.rx_count_o ()
|
||||
);
|
||||
end else begin : g_btn
|
||||
end
|
||||
else begin : g_btn
|
||||
cpu21_pointer #(
|
||||
.SAMPLE_DIV(50000)
|
||||
) u_ptr (
|
||||
|
||||
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