基础条件回顾:
完成了一个带有段寄存器的基于MIPS的多周期CPU,现有u-boot代码以及差分测试框架,以成功运行u-boot为目标
实用工具积累:
2020-3-6:
mips-linux-gnu-objdump -d u-boot | less
——定位u-boot运行结果出错的pc、instr
交叉编译的话需要用对应的编译器,比如:aarch64-linux-gnu-objdump -d build/kernel8.elf
因为本机使用的是mips和linux-gnu的交叉编译器,所以需要使用这样的命令才能反汇编。
-d
参数表示反汇编需要执行指令的section(-D 表示反汇编全部section)
|
在linux中称为管道,可以把上一条命令的结果作为下一条命令的参数,在此处就是将反汇编的文件作为了less的参数
less
命令可以随意浏览文件, 在查看之前不会加载整个文件,进入文件后可以/something 搜索指定内容somthing
& 表示任务在后台执行
&& 表示前一条命令执行成功时,才执行后一条命令
| 表示管道,上一条命令的输出,作为下一条命令参数
|| 表示上一条命令执行失败后,才执行下一条命令
2020-3-10
Error : bfc00500: 40087801 mfc0 t0,$15,1
$pc: 0xbfc0051c $hi: 0x00000000 $lo: 0x00000000
$ninstr: 00000000 $instr: 40086000
$0 :0x00000000 $at:0x00000000 $v0:0x00000000 $v1:0x00000000
$a0:0x00000000 $a1:0x00000000 $a2:0x00000000 $a3:0x00000000
$t0:0x10400000 $t1:0x00000000 $t2:0x00000000 $t3:0x00000000
$t4:0x00000000 $t5:0x00000000 $t6:0x00000000 $t7:0x00000000
$s0:0x00000000 $s1:0x00000000 $s2:0x00000000 $s3:0x00000000
$s4:0x00000000 $s5:0x00000000 $s6:0x00000000 $s7:0x00000000
$t8:0x00000000 $t9:0x00000000 $k0:0x00000000 $k1:0x00000000
$gp:0x00000000 $sp:0x00000000 $fp:0x00000000 $ra:0x00000000
==============nemu status end===============
cycle 53: gpr[8]: nemu:10400000 <> dut:00000000
CP0 的 15 号寄存器: Processor Identification,主要是company和processor设计信息.
val s0_value = Mux1H(Array(
(cp0_addr === "b111000".U) -> base.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1000000".U) -> badvaddr.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1001000".U) -> count0.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1001001".U) -> count1.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1011000".U ) -> compare.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1100000".U) -> status.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1101000".U ) -> cause.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b1110000".U ) -> epc.asTypeOf(UInt(conf.xprlen.W)),
(cp0_addr === "b10000111".U ) -> prid)
))
当初设计没有考虑Pid寄存器,直接置0了,所以现在在Mux1H()后面加上。(为什么我用二进制?好像当初switch结构一直失败报错?)后面的写如操作也要补上
Error:bfc0051c: 40086000 mfc0 t0,c0_status
==============nemu registers================
$pc: 0xbfc0051c $hi: 0x00000000 $lo: 0x00000000
$ninstr: 00000000 $instr: 40086000
$0 :0x00000000 $at:0x00000000 $v0:0x00000000 $v1:0x00000000
$a0:0x00000000 $a1:0x00000000 $a2:0x00000000 $a3:0x00000000
$t0:0x10400000 $t1:0x00000000 $t2:0x00000000 $t3:0x00000000
$t4:0x00000000 $t5:0x00000000 $t6:0x00000000 $t7:0x00000000
$s0:0x00000000 $s1:0x00000000 $s2:0x00000000 $s3:0x00000000
$s4:0x00000000 $s5:0x00000000 $s6:0x00000000 $s7:0x00000000
$t8:0x00000000 $t9:0x00000000 $k0:0x00000000 $k1:0x00000000
$gp:0x00000000 $sp:0x00000000 $fp:0x00000000 $ra:0x00000000
==============nemu status end===============
cycle 53: gpr[8]: nemu:10400000 <> dut:00000000
c0_status的初始值应该为10400000,之前设计的除了BEV置1其他全为0,
按MIPS_Vol手册重新初始化,加入CU字段。
在scala语言中,class的init()方法不会默认调用(之前一直以为自动调用,所以status的初始值一直为0)
when(reset.toBool){
cause.init()
status.init()
}
Error:bfc00538: 40088000 mfc0 t0,c0_config
$pc: 0xbfc00538 $hi: 0x00000000 $lo: 0x00000000
$ninstr: 00000000 $instr: 40088000
$0 :0x00000000 $at:0x00400004 $v0:0x00000000 $v1:0x00000000
$a0:0x00000000 $a1:0x00000000 $a2:0x00000000 $a3:0x00000000
$t0:0x80000080 $t1:0x00000000 $t2:0x00000000 $t3:0x00000000
$t4:0x00000000 $t5:0x00000000 $t6:0x00000000 $t7:0x00000000
$s0:0x00000000 $s1:0x00000000 $s2:0x00000000 $s3:0x00000000
$s4:0x00000000 $s5:0x00000000 $s6:0x00000000 $s7:0x00000000
$t8:0x00000000 $t9:0x00000000 $k0:0x00000000 $k1:0x00000000
$gp:0x00000000 $sp:0x00000000 $fp:0x00000000 $ra:0x00000000
==============nemu status end===============
cycle 104: gpr[8]: nemu:80000080 <> dut:00000000
CP0 的config寄存器之前也没加入,查询手册加入,并且按照80000080初始化赋值
9:7位为MT位,表示MMU的类型,此处为1,即standrd TLB
按照prid方式补充
Error bfc00544: 40088001 mfc0 t0,c0_config1
==============nemu registers================
$pc: 0xbfc00544 $hi: 0x00000000 $lo: 0x00000000
$ninstr: 00000000 $instr: 40088001
$0 :0x00000000 $at:0x00400004 $v0:0x00000000 $v1:0x00000000
$a0:0x00000000 $a1:0x00000000 $a2:0x00000000 $a3:0x00000000
$t0:0x7e9b4d80 $t1:0x00000000 $t2:0x00000000 $t3:0x00000000
$t4:0x00000000 $t5:0x00000000 $t6:0x00000000 $t7:0x00000000
$s0:0x00000000 $s1:0x00000000 $s2:0x00000000 $s3:0x00000000
$s4:0x00000000 $s5:0x00000000 $s6:0x00000000 $s7:0x00000000
$t8:0x00000000 $t9:0x00000000 $k0:0x00000000 $k1:0x00000000
$gp:0x00000000 $sp:0x00000000 $fp:0x00000000 $ra:0x00000000
==============nemu status end===============
cycle 126: gpr[8]: nemu:7e9b4d80 <> dut:00000000
看来config1也需要加入,同上
config1主要规定了cache的配置参数,以及mips16/64,FPU,EJTAG等是否implemented。
其中 TLB entries 最多可支持64组.
我们来计算一下,MIPS32 processor的cache容量范围
$Cache capacity = sets per way * line size *associativity $(line_size 最高位均为reserved)
I
c
a
c
h
e
=
[
0
,
64
∗
4
∗
2
,
4096
∗
128
∗
8
]
=
[
0
,
2
10
,
2
22
]
=
[
0
,
1
k
B
,
4
M
B
]
Icache = [0 , 64*4*2,4096*128*8] = [0,2^{10},2^{22} ] = [0,1kB,4MB]
Icache=[0,64∗4∗2,4096∗128∗8]=[0,210,222]=[0,1kB,4MB]
D
c
a
c
h
e
=
[
0
,
64
∗
4
∗
2
,
4096
∗
128
∗
8
]
=
[
0
,
2
10
,
2
22
]
=
[
0
,
1
k
B
,
4
M
B
]
Dcache = [0 , 64*4*2,4096*128*8] = [0,2^{10},2^{22} ]= [0,1kB,4MB]
Dcache=[0,64∗4∗2,4096∗128∗8]=[0,210,222]=[0,1kB,4MB]
如果line_size最高位也可以使用,那么最大值为现在的两倍.
再来看看u-boot的初始配置,根据上面的"7e9b4d80"
0 111111 010 011 011 010 011 011 0 0 0 0 0 0 0
TLB Entries | I/Dcache size |
---|---|
64 | 25683 = 2^11 *3 = 6KB |
到此u-boot的基本配置结束了,进入了qemu的小黑框,下一步开始处理cache和TLB相关的异常和中断