龙芯pmon汇编学习
MIPS指令集中:
mtc0 - move to c0 和
mfc0 - move from c0
cfc0 - copy from c0
ctc0 - copy to c0呢?
//uart
https://www.cnblogs.com/blogernice/articles/9850920.html
https://blog.csdn.net/qq543716996/article/details/105219398
//勤为本start.s分析
https://blog.csdn.net/caogos/article/details/78984158
//两个是同一个博客,但解释了循环点a0为何没有自加问题
https://blog.csdn.net/cs_yf/article/details/82288935?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.control&dist_request_id=1328626.20999.16154320787743117&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.control
https://blog.csdn.net/cs_yf/article/details/83154622?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-12.control&dist_request_id=1328627.43.16152959946833501&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-12.control
//
good
MIPS CPU一般采用双相相关联存储器实现TLB,即每个TLB表项包含一对相邻的虚拟地址页(虚拟地址空间上连续)对应两个单独的物理地址(物理地址空间上可以不连续)。
该表项表示将虚拟地址0xe000 0000开始的128MB虚拟地址空间,映射到从0x4000 0000开始的64MB物理地址空间,以及从0x4400 0000开始的64MB物理地址空间,每个物理地址段后面的标志位(C2DVG)表示映射模式。
https://www.cnblogs.com/justin-y-lin/p/13818045.html
https://www.cnblogs.com/Melles/p/10714224.html
http://blog.chinaunix.net/uid-26694208-id-4219768.html
存在问题:
用户太、核心态?
#define PT_ENTRY_NULL ((pt_entry_t *) 0)
#define PG_WIRED 0x80000000 /* SW */
#define PG_RO 0x40000000 /* SW */
#define PG_SVPN 0xfffff000 /* Software page no mask */
#define PG_HVPN 0xffffe000 /* Hardware page no mask */
#define PG_ODDPG 0x00001000 /* Odd even pte entry */
#define PG_ASID 0x000000ff /* Address space ID */
#define PG_G 0x00000001 /* HW */
#define PG_V 0x00000002
#define PG_NV 0x00000000
#define PG_M 0x00000004
#define PG_ATTR 0x0000003f
#define PG_UNCACHED 0x00000010
#define PG_CACHED 0x00000018
#define PG_CACHEMODE 0x00000038
#define PG_ROPAGE (PG_V | PG_RO | PG_CACHED) /* Write protected */
#define PG_RWPAGE (PG_V | PG_M | PG_CACHED) /* Not wr-prot not clean */
#define PG_CWPAGE (PG_V | PG_CACHED) /* Not wr-prot but clean */
#define PG_IOPAGE (PG_G | PG_V | PG_M | PG_UNCACHED)
#define PG_FRAME 0x3fffffc0
#define PG_SHIFT 6
#define pfn_is_ext(x) ((x) & 0x3c000000)
#define vad_to_pfn(x) (((unsigned)(x) >> PG_SHIFT) & PG_FRAME)
#define vad_to_pfn64(x) (((quad_t)(x) >> PG_SHIFT) & PG_FRAME)
#define pfn_to_pad(x) (((x) & PG_FRAME) << PG_SHIFT)
#define vad_to_vpn(x) ((unsigned)(x) & PG_SVPN)
#define vpn_to_vad(x) ((x) & PG_SVPN)
/* User viritual to pte page entry */
#define uvtopte(adr) (((adr) >> PGSHIFT) & (NPTEPG -1))
#define PG_SIZE_4K 0x00000000
#define PG_SIZE_16K 0x00006000
#define PG_SIZE_64K 0x0001e000
#define PG_SIZE_256K 0x0007e000
#define PG_SIZE_1M 0x001fe000
#define PG_SIZE_4M 0x007fe000
#define PG_SIZE_16M 0x01ffe000
#if defined(RM9000)
#define PG_SIZE_64M 0x07ffe000
#define PG_SIZE_256M 0x1fffe000
#endif
##ls1c中TLB初始化代码注释
##ls1c中是将虚拟地址的0xc0000000开始的1G空间映射到物理地址的0xc000 0000中,页面大小设置为16M
##0xc000 0000 以上的物理空间为ddr空间,所以此处映射的是ddr空间。
##为何这段空间要映射?因位mips规定该段地址必须要进行映射才能去使用。。
/*****************
函数功能:建立映射表,启用MMU
******************/
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,为下次循环准备
#上述映射了两个16M即32M的物理地址,所以下次循环物理地址将偏移32M
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,准备下一次的条目设置
/*******************************************************************
#此处重点,因为分支延时槽的原因吓一跳指令也会执行。 其实此处也可以写成这样。
# addu a0, a2
# bgtz a1, 1b
# nop
********************************************************************/
jr ra //循环结束后返回
nop
END(CPU_TLBInit)