参考资料:
http://xenyinzen.wikidot.com/code-research:pmon:start-functions
https://wenku.baidu.com/view/013ba5f9700abb68a982fb3a.html?sxts=1535682681686&pn=1
因为项目需要在裸机阶段访问到512M以上的物理地址,根据参考手册需要设置TLB进行访问,所以对PMON中TLB初始化的代码段进行了一些探究和简单注释,以便后面需要的时候参考。
TLB的作用是将虚拟地址映射到物理地址,所以需要配置他们的对应关系。
##两个关键寄存器
EntryHi寄存器存放地址入口,也就是需要转换的虚拟地址;EntryLo寄存器存放出口地址,也就是虚拟地址映射到的物理地址。下面是这两个寄存器的具体描述。关于TLB的初始化就是根据这两个寄存器的描述进行配置。
##ls1c中TLB初始化代码注释
ls1c中是将虚拟地址的0xc0000000开始的1G空间映射到物理地址的0xc0000000中,页面大小设置为16M。
LEAF(CPU_TLBInit)
li a3, 0 # First TLB index.
li a2, PG_SIZE_16M
MTC0 a2, COP_0_TLB_PG_MASK # All pages are 16Mb.
1:
and a2, a0, PG_SVPN //PG_SVPN=0xfffff000,所以这里是取a0地址的高20位,舍弃低12位的偏移地址(如果给的地址低位不为零的话),因为后面的EntryHi寄存器需要高位作为虚拟地址
MTC0 a2, COP_0_TLB_HI # Set up entry high.
move a2, a0 //再给a2赋值0xc0000000,但是貌似下一句就重新赋值了
srl a2, a0, PG_SHIFT //PG_SHIFT=6,所以这里是将a0的值逻辑右移6位赋值给a2,a2=0x03000000(这里右移6位目的是将地址高位与EntryLo寄存器的PFN位对齐。需要参考寄存器的定义)
and a2, a2, PG_FRAME //PG_FRAME=0x3fffffc0,这里取a2的值第29-6位,其余位置0,这里实际上a2的值不变(因为EntryLo寄存器的29-6位是PFN,即页帧号,其中29-16位一般作为页帧号的一部分直接写0,不是实际的物理页帧号)
ori a2, PG_IOPAGE //PG_IOPAGE=0x00000017,这里将a2值的第0、1、2、5位置1,所以a2=0x03000017(0000 0011 0000 0000 0000 0000 0001 0111),(这里置1的几位参考寄存器定义,置1表示可用,所以必须这么做)
MTC0 a2, COP_0_TLB_LO0 # Set up entry low0. //将a2赋值给EntryLo0寄存器,设置第一个出口物理地址
addu a2, (0x01000000 >> PG_SHIFT) //0x01000000是16M,右移6位后是0x00040000,这里的a2=0x03040017 (这里为什么要将0x01000000右移6位同样是根据EntryLo寄存器的格式来的,右移六位后,在寄存器的PFN中,代表的同样是0x01000000=16M)
MTC0 a2, COP_0_TLB_LO1 # Set up entry low1. //a2赋值给EntryLo1,设置第二个出口物理地址
mtc0 a3, COP_0_TLB_INDEX # Set the index. //设置页号
addiu a3, 1 //页号加1,为下次循环准备
li a2, 0x02000000 //a2=0x02000000(32M)
subu a1, a2 //a1=0x40000000(1G),所以这里是将1G的空间每次递减,当1G地址空间设置完毕后即可退出
nop
tlbwi # Write the TLB //写TLB索引号
bgtz a1, 1b //当a1的值大于0的时候,跳转回上一个1处,否则循环结束
addu a0, a2 # Step address 32Mb. //跳转指令结束后,还会执行下一条指令,所以有的地方跳转指令后跟一个nop,这里利用这个特点将虚拟地址空间累加32M,准备下一次的条目设置
jr ra //循环结束后返回
nop
END(CPU_TLBInit)