MIPS架构初探
MIPS基础
什么是MIPS?
MIPS(无互锁流水线微处理器)是一种精简(RISC)指令系统结构(ISA),起源于Stanford大学John Hennessy教授的研究成果
- MIPS版本
- MIPS I
- MIPS II
- MIPS III
- MIPS I
- MIPS IV
- PIPS V
- MIPS 32/64
- MIPS可选扩展
- MIPS-3D 在3D处理时的可扩展选项
- MDMX
- MIPS16e
- MIPSMT
CISC(Complex Instruction Set Computer)复杂指令计算机。Interl的X86、AMD的K5、K6未该类型
RISC(Reduced Instruction Set Computer)精简指令计算机。Acron公司的ARM、IBM的PowerPC、MIPS公司的MIPS为该类型
MIPS结构的基本特点
- 优先选取一些使用频率最高的简单指令,以及一些很有用但不复杂的指令
- 指令长度固定,格式种类少,个字段划分比较一致,各字段功能比较规整
- 只有存数,取数,访问存储器,其余指令的操作都是在寄存器之间进行
- CPU中通常寄存器数量较多
假如有一个4字节的数据为0x12 34 56 78
(十进制:305419896,0x12为高字节,0x78为低字节),若将其存放于地址0x4000 8000
中
内存地址 | 0x4000 8000(低地址) | 0x4000 8001 | 0x4000 8002 | 0x4000 8003(高地址) |
---|---|---|---|---|
大端模式 | 0x12(高字节) | 0x34 | 0x56 | 0x78(低字节) |
小端模式 | 0x78(低字节) | 0x56 | 0x34 | 0x12(高字节) |
mips : big-endian的mips架构
mipsel : little-endian的mips架构
MIPS应用领域
计算机、电视机、龙芯芯片、摄像头、路由器 …
MIPS汇编
MIPS寄存器
register | Assembly name | Comment |
---|---|---|
r0 | $zero | Always 0 |
r1 | $at | Reserved for assembler |
r2 - r3 | %v0 - $v1 | Stores results |
r4 - r7 | $a0 - $a3 | Stores arguments,参数超过4个才会存放到栈上 |
r8 - r15 | $t0 - $t7 | Temporaries,not saved |
r16 - r23 | $s0 - $s7 | Contents saved for use later |
r24 - r25 | $t8 - $t8 | More temporaries,not saved |
r26 - r27 | $k0 - $k1 | Reserved by operating system。 给中断使用 |
r28 | $gp | Global pointer |
r29 | $sp | Stack pointer。栈 |
r30 | $fp | Frame pointer。栈 |
r31 | $ra | Return address |
$f0 - $f3 | - | Floating point return values |
$f4 - $f10 | - | Temporary registers,not preserved by subprograms |
$12 - $f14 | - | First two arguments to subprograms,not preserved by subprograms |
$16 - $f18 | - | More temporary registers,not preserved by subprograms |
$f20 - $31 | - | Saved registers,preserved by subprograms |
一般情况下,32位处理器中每个寄存器的大小是32位,即4字节
MIPS五级流水线
- 取指令 : 将指令从指令Cache中取出,并计算下一条指令的地址
- 读操作数及转移: 根据指令从寄存器中读出操作数,同时若为转移指令,满足转移条件时设置PC
- 执行: 根据指令进行计算,若为存取类指令,则计算地址
- 访问存储器: 若为存取类指令,对进行数据Cache进行读写
- 写结果: 将执行或存取的结果写回寄存器
MIPS指令集
- R格式指令为纯寄存器指令,所有的操作数(除移位外)均保存在寄存器中,Op字段均为0,使用funct字段区分指令
- I格式指令为带立即数的指令,最多使用两个寄存器,同时包括了load/store指令使用Op字段区分指令
- J格式指令为长跳转指令,仅有一个立即数操作数。使用Op字段区分指令
MIPS环境搭建
- 操作系统 : Ubuntu x64
- MISP IDE : MARS 4.5 (运行方式 java -jar mars.jar)
- 在线网站 : https://rivoire.cs.sonoma.edu/cs351/wemips/
- 交叉编译 : misp-linux-gnu*
- 模拟环境 : qemu (最好是到github搜索qemu,通过官方文档给定的步骤进行安装)
MISP交叉编译链接工具
gcc-mips-linux-gnu
sudo apt-get install linux-libc-dev-mips-cross
sudo apt-get install libc6-mips-cross libc6-dev-mips-cross
sudo apt-get install binutils-mips-linux-gnu gcc-mips-linux-gnu
sudo apt-get install g++-mips-linux-gnu
gcc-mipsel-linux-gnu
sudo apt-get install linux-libc-dev-mipsel-cross
sudo apt-get install libc6-mipsel-cross libc6-dev-mipsel-cross
sudo apt-get install binutils-mipsel-linux-gnu gcc-mipsel-linux-gnu
sudo apt-get install g++-mipsel-linux-gnu
Qemu安装
安装系统模式
sudo apt-get install qemu
安装用户模式
sudo apt-get install qemu-user-static
编译并运行MIPS
通过 MARS 编译并运行 mips程序
.data
myStr: .asciiz "hello\n"
.text
li $v0,4 ;载入立即数
la $a0,myStr ;载入地址
syscall ;系统调用,$v0中存储的就是系统调用值
.data
message: .asciiz "Hi, everybody.\nMy name is MIPS.\n"
.text
main:
jal displayMessage ;跳转指令,1、跳转displayMessage地址,同时把下一条指令的地址写入到 $ra寄存器
addi $s0,$zero,5
li $v0,1
add $a0,$zero,$s0
syscall
li $v0,10 ;系统调用,退出
syscall
displayMessage:
li $v0,4
la $a0,message
syscall
jr $ra ;跳转到 $ra地址的位置
.data
newline: .asciiz "\n"
.text
main:
addi $s0,$zero,10
jal increaseMyRegister
# print a new line
li $v0,4
la $a0,newline
syscall
#pirnt value
li $v0,1
move $a0,$s0
syscall
li $v0,10
syscall
increaseMyRegister:
addi $sp,$sp,-4
sw $s0,0($sp) # 提升栈, 获取参数 10
addi $s0,$s0,30
#print new value in function
li $v0,1
move $a0,$s0
syscall
lw $s0,0($sp)
addi $sp,$sp,4 # 恢复栈
jr $ra
# 效果,输出 40 50
静态交叉编译MIPS程序
编写C源代码 hello.c
#include<stdio.h>
int main(void)
{
printf("hello\n");
return 0;
}
静态链接编译 (这里使用大端的进行编译)
mipsel-linux-gnu-gcc hello.c -o hello --static
qemu模拟运行 (使用大端的进行运行)
qemu-mipsel ./hello
动态链接编译 (小端编译)
mips-linux-gnu-gcc hello.c -o hello
qemu模拟运行,需要指定动态链接库 (小端运行)
qemu-mips -L /usr/mips-linux-gnu ./hello