今天是来龙芯的第四十五天,从PMON开始学习,现在对MIPS的体系结构,有了简单的了解。从这周开始吧,打算每周将所学的知识点进行总结,都将发表在我的博客上
面。希望这个远景能够达成吧。给自己先定个 小目标,每周写一篇博客,作为自己的只是积累,都知道没有量变又怎么会有质变呢。一个人的改变是需要时间的!!!
都知道现在的处理器体系结构主要分为三种,一种 众所周知的intel的x86结构,还有就是ARM体系结构。这两种类型的处理器是市场上主要流行的处理器。起始从计算机的发展
历史来看,还有一种体系结构,那就是MIPS体系结构,只不过现在在国际上这种结构的处理器很少。几乎不被大家所知道。而龙芯就是采用这种架构的cpu处理器厂商。从发展
至今,MIPS体系结构和其他两种相比,现在有着先天的不足,那就是整个体系内的生体建设。上至顶层的应用软件,下至底层的bios和驱动软件,都缺少在这个平台上面的支
持。因此对于龙芯而言,想要发展自己的cpu体系内的一系列产品,这些软件的支持是必不可少的。所以龙芯的发展道路还很长,很艰难。
来到这边开始做底层的bios,现在国内bios也在发生巨大的变革。由传统bios逐渐转型到UEFI这个主流社区。所有的操作系统都在向 这方面转,当然龙芯也不例外。因此我也开
始了 UEFI的道路,也不知到这条路有多长,能走多远。是否现在的所做所学能够能为将来自己吃饭的本事还是个未知。但是既然来了就做好现在手里的任务吧,一边做这个一
边学习kernel的东西。相信自己一定能够成为自己心中的样子。
(如果哪里有错误,希望评论指正,共同学习,谢谢!)
现在将这段时间所学的内容做个简要的总结吧:
【1】MIPS中通用的32个处理器及功能如下:
编号 名称 功能
0 zero 恒为0的寄存器,一般用来初始化别的寄存器
1 at 被汇编器所保留,用来处理超过32位的long long型的数据
2-3 v0-v1 用来存放函数的返回值
4-7 a0-a3 存放函数的入参
8-15 t0-t7 存放函数中需要保留的临时变量
16-23 s0-s7 存放需要保留的调用栈的信息,当调用子函数的时候,存放需要保留的上下文的信息
24-25 t8-t9 额外供保留临时变量的寄存器
26-27 k0-k1 给操作系统内核使用的
28 gp 存放全局指针
29 sp 存放栈指针
30 fp 存放指向栈帧的指针
31 ra 存放还数返回地址的的寄存器,一般bal和j指令后面的地址将会被保留到ra寄存器内
【2】mips汇编中常用的指令:
(1)mips指令中字段的命名:
op(6bit):指令的基本操作 称为操作码
rs(5bit):第一源操作数寄存器
rt(5bit):第二源操作数寄存器
rd(5bit):存放结果的目的寄存器
shamt(5bit):偏移量
funct(6bit):功能码
(2)mips指令类型:
R型: op rs rt rd funct
I型: op rs rt immediate(12bit)
J型:op immediate(16bit)
R型指令:
add(求和) add $1, $2, $3 寄存器寻址方式 $1=$2+$3 寄存器2和寄存器3的值加起来赋值给寄存器1
sub(求差) sub $1, $2, $3 $1=$2-$3
and(与) and $1, $2, $3 $1=$2&$3
or(或) or $1, $2, $3 $1=$2|$3
nor(异或) nor $1, $2, $3
slt(三目运算) slt $1, $2, $3 if($2<$3) $1=1 else $1=0
sltu(无符号三目运算) sltu $1, $2, $3 三个寄存器内的数都是无符号的
sll(循环左移) sll $1, $2, 10 $1=$2<<10
srl(循环右移) srl $1, $2, 10 $1=$2>>10
sra(保留符号位的循环左移) sra $1, $2, 10 $1=$2<<10(符号位保留)
sllv sllv $1, $2, $3 $1=$2<<$3
srlv srlv $1, $2, $3 $1=$2>>$3
Ih Ih $1, 10($2) 基址寻址
Sh Sh $1, 10($2) 基址寻址
lb Ib $1, 10($2) 基址寻址
ll Il $1, 10($2) 基址寻址
sc sc $1, 10($2) 基址寻址
以上五个指令的具体实现还不是很清楚,欢迎各位大神给出指点!
div/divu div des, src1, src2 des=src1/src2(表示无符号的数)
abs abs des, src des=|src|src的绝对值给des
mul mul des, src1, src2 des=src1*src2
seq/seq(u) seq des, src1, src2 if(src1==src2) des=1 else des=0
sgt sgt des, src1, src2 if(src1>src2) des=1 else des=0
sle sle des, src1,src2 if(src1<=src2) des=1 else des=0
slt slt des, src1,src2 if(src1<src2) des=1 else des=0
I型指令:
addi(求和) addi $1, $2, 10 $1=$2+10
subi(求差) subi $1, $2, 10 $1=$2-10
andi(与) addi $1, $2, 10 $1=$2&10
ori(或) ori $1, $2, 10 $1=$2|10
lui lui $1, 100 将100加载到$1寄存器的高16bit
lw lw $1, 10($2) 加载$2寄存器开始偏移10字节的地址的内容到$1寄存器
sw sw $1, 10($2) 保存$1的内容到$2寄存器开始偏移10字节的地址上
beq beq $1, $2, 10 if($1==$2) goto 10(lable 10 的位置)
bne bne $1, $2, 10 if($1!=$2) goto 10
slti slti $1, $2., 10 if($2<10) $1=1 else $1=0
sltiu sltiu $1, $2, 10 10为无符号的数
J型指令:
j j lable 跳转到lable处
jar j $1 跳转到$1寄存器存储的地址处
jal jal lable1 跳转到lable1标签处
合成指令:
b 跳转
b和 下面的其中一个或者下面一个以及z(zero)所构成的指令均为跳转指令:例如beq/beqz
eq 相等
ne 不等
ge 大于等于
gt 大于
le 小于等于
lt 小于
伪指令:
.globl __start 设置全局标签
lable: 设置局部标签lable
.ascii s 符合ascii码组成的字符串
.asciiz s like .ascii, null-terminated
.word w1, w2 一个字长(32bit)的数据w1 w2
.half h1, h2 半字节长(16bit)的数据
.byte b1,b2 一个字节的数据
.float f1, f2 32-bit single precision floating point numbers f1, f2, . . .
.double d1, d2 64-bit double precision floating point numbers d1, d2, . . .
.space n n zero bytes
.set push 保存所有设置
.set pop 重新保存设置
.set reorde 允许编译器优化指令,对代码进行优化排序
.set noreorde 不允许编译器优化指令,对代码进行优化排序
.set at/noat 使用/不是用at寄存器
.set mips 0 支持原来的ISA级别(小心使用)
.set mips 3 下面的指令是mips64指令,兼容mips32的指令
.set volatile/novolatile 处在volatile区内的所有存取指令都不会被移动位置
.align 7 .align区内的代码必须使用2的7次方字节大小的内存空间
【3】MIPS架构特点
(1)独立的指令缓存和数据缓存
(2)每个指令的执行都分为五个阶段及五条流水线
(3)所有指令都一样长32bit这就是为什么mips指令的二进制文件要比同样x86的二进制文件大的原因
(4)无条件码
(5)三操作数指令(算数/逻辑操作不想要指明内存地址)
(6)没有字节或者半字节运算
(7)没有专门的栈支持
(8)最小子程序支持,跳转指令的限制(b上下64k内,J上下64M内)
【4】MIPS指令的五条流水线
IF:取指,从指令缓存I-cache中取出指令
RD:读寄存器,从指令中源寄存器或者cpu中的某一个寄存器中读取内容
ALU:算数逻辑单元,在一个时钟周期内完成算法或逻辑操作
MEM:指令从数据缓存中读写内存变量
WB:写回,将操作完成的值写回到寄存器中