COpre——MIPS汇编指令与机器码、内存
在笔者进行COpre中MIPS部分的学习时,对于MIPS指令及其机器码转换,MIPS对应的内存计算等等感到十分头痛,这一篇文章主要目的是零碎的记录一些知识。
一. 数制
在计组学习中最常用到的数值即为二进制(binary/BIN)和十六进制(hexadecimal/HEX),例如MIPS汇编指令机器码用二进制表示,而计算机内存的表示通常为十六进制。一位十六进制数相当于四位二进制数。一位二进制数通常又称为比特位(bit),关联出计算机系统中经典的换算关系。
在32位系统中:
- 1字节(byte)=8比特位(bit) 计算机中最小的寻址单位即为字节/B
- 1个字(word)=4字节(byte)=32bits 即一个字就是32位,同样64位系统中一个字是64位
- 1KB=1024B 计算机中K的概念是2^10即1024
- 1MB=1024KB
- 1G=1024MB
二. 浅析MIPS架构
MIPS是一种经典的RISC架构,具有精简的指令集,32位定长指令,五级流水线,延迟槽,32个通用寄存器等特点。这里我们主要谈及32位定长指令、32个通用寄存器、指令集等内容,其他的部分会在日后涉及。这里需要特殊说明的是我们的MIPS是32位系统
1.32位定长编码
定长指令的优点是简化指令解析,减少解析时间。但同样的,由于指令为定长32位,这对于内存是不友好的。我们在写MIPS汇编程序时,编写的每一行指令代码均为32位,四个字节,一个字。这里指令具体的分为R型、I型、J型指令

R型指令(register type)
R型指令用于寄存器之间的操作,常用于算术运算、逻辑操作和寄存器之间的数据传输,如add,sub.and.or等。
I型指令(immediate type)
I型指令用于立即数(常数)与寄存器之间的操作,通常用于家在常熟、内存读写、分支跳转等操作。例如,addi,lw,sw,beq等指令
J型指令(jump type)
J型指令用于无条件跳转到目标地址,常用于函数调用、循环跳转等控制流程的修改。例如,j,jar指令。
对于以上指令,我们只需要记住他们都占32位,4个字节,其他的具体用法详见《MIPS-C指令集》。
2.32个通用寄存器
MIPS寄存器是32位寄存器,每个部分的功能如图所示

需要注意的是,每个寄存器既可以用名字表示,也可以用编号表示,如**$to<==>$8**。
3.特殊寄存器
1. HI(high)与LO(low)
HI与LO是MIPS中用于处理乘除法的特殊寄存器,在MIPS汇编指令中,乘除法指令的结果最多为64位,夫需要设置特殊寄存器进行保存。在乘法中,HI保存高32位,LO保存低32位;在除法中HI保存余数,LO保存商。
2.PC程序计数器
PC(program counter)程序计数器,是计算机系统中的一个寄存器,用于存储下一条指令的地址。程序计数器指向执行中的指令的内存地址,当处理器执行完当前指令后会自动将程序计数器的值增加,使其指向下一条指令的地址。具体地,在MIPS汇编指令中,每执行完一条指令 PC=PC+4,这是由于在MIPS中每一条指令所占的内存空间都是4个字节。程序计数器的初始值一般为程序的入口地址(首条指令的地址 最常见的为0x0000_3000)。同时分支指令也可以使程序计数器进行跳转。总的来说,PC相当于程序运行中的内存监控,通过PC可以了解程序的流程。
| |
三.COpre中提供的部分题目具体分析
1.下列指令中需要在立即数后拼接两位0的是
| |
在立即数后拼接两位0,即将原立即数向左移动两位,立即数4,代表着按4对齐。在beq中,立即数n的意义是跳转到第n条指令,而实际操作中,一条指令占用四字节,地址访存的话需要跳转4n字节,所以需要拼接两位0。
2.与上一题类似的beq计算next立即数
| |
功能分析:beq:相等时跳转,bne:不相等时跳转,在此题目中,当$t0与$t1不相等时跳转到next标签,我们之前在《MIPS-C》中发现了bne的C代码
| |
可以知道,无论如何PC计数器都会+4,即向前迈出一条指令,这里next可以增加移动的指令数,在此题目中,可以发现,跳转到next标签需要跳两条语句,故next==1.此题的原型为表示16进制的八位机器码(32位二进制==8位十六进制,用电脑内置的计算器即可将首先得到的32位机器码转换为8位十六进制)。关于机器码只需要进行查表即可。
3.下列操作过程中,需要将立即数进行符号扩展的是
| |
**通过R,I,J指令的结构可知,立即数通常是没有32位的,在有些指令中为26位,在有些指令中为16位。**而在ALU运算及读写存储等等操作都需要32位,所以需要将立即数拓展到32位,MIPS指令手册规定了每条指令的拓展方式(符号扩展/0扩展)。
4.下列操作过程中,需要将立即数无符号扩展的是
| |
以上两题均可以通过查英文版MIPS指令解决(MIPS-C过于简略),只需要查看Operation一栏
5.下列指令中属于R型的是
| |
需要注意的是:不是所有j开头的指令都是J型,jarl为R型指令,最好分辨的是I型指令,在指令当中有立即数
查表时分表R、I、J型指令的方法:看32位数据分割,
- R:6+5+5+5++5+6
- I:6+5+5+16
- J: 6+26
6.汇编代码流程分析
1.例一jal-jr
程序结束时 a2=0x00003001
jal指令用于跳转到目标地址,并将jal指令的下一条指令的地址存储到ra中,jr用于跳转到一个寄存器中存储的目标地址
| |
2.例二bne指令
程序结束时 a2=2
| |
7.load-store指令功能测试
| |
小端存储:数据的低位放在低地址,高位放在高地址;大端存储相反,这里面第一离谱的事情是li是MIPS扩展指令,而不是汇编指令,这导致我在MIPS指令集中查无此人。li扩展指令的含义为为寄存器赋值
| |
内存中每个单元只能存储一个字节,这导致初始时的a0被分成四个部分存储。
易混淆点:物理地址与内存地址
内存地址是对内存单元的编号(可以理解为门牌号),计算机中最小的寻址单位即内存单元为1byte,物理地址是真实的物理内存的地址
我们以上提及的0x1000与0x1001都是指内存地址(计算机中常用16进制表示内存地址),每两个内存地址之间的物理地址差异为一个字节。将以上内存地址与物理地址可以用图画联系起来,在每一个门牌号下都有一个大小为1byte的空间。
| |
8.跳转指令范围
- j指令只有26位用于存储到跳转的地址,那么j指令能够跳转到的代码范围有多大?
| |
- jr指令可以跳转的代码范围有多大?
| |
- beq指令可以跳转的代码范围有多大?
| |
由此可以知道 在operation部分出现|0^2意味着左移位两位,代表的是指令
9.数据溢出
| |
addi指令中,immediate是一个有符号的16位数,即原数最多15位,但是0x8165是16位数。