MIPS指令R I J三种格式
op
操作码opcode
rs
第一个源寄存器编号
rt
第二个源寄存器编号
rd
目的寄存器编号
shamt
移位位数
funct
功能码
MIPS五种寻址方式
立即数寻址
操作数为指令自身中的常数立即数
代码语言:javascript复制addi r2,r1,1
r2=r1 1
寄存器寻址
操作数为寄存器中的值
代码语言:javascript复制add r2,r1,r0
r2=r1 r0
基址寻址
以基址寄存器中的值和立即数常数之和作为地址,该地址指向的内存的值作为操作数
代码语言:javascript复制lw r2,8(r1)
r2=M[r1 8]
PC相对寻址
以PC程序计数器和指令中常数之和作为地址,即16位地址左移2位(即乘以4)与PC计数器相加
代码语言:javascript复制beq r2,r1,label
如果r2==r1则程序跳到label处
伪直接寻址
跳转地址由指令中26位地址左移两位(即乘以4)与PC计数器的高4位相连所组成
代码语言:javascript复制j label
WinMIPS64汇编指令
助记
从内存中加载数据
lb
lb rd,imm(rs)
基址偏移寻址,加载一个字节8位,rd=M[rs imm]
lbu
lbu rd,imm(rs)
基址偏移寻址,加载一个无符号字节8位,rd=M[rs imm]
lh
lh rd,imm(rs)
基址偏移寻址,加载一个半字16位,rd=M[rs imm]
lhu
lhu rd,imm(rs)
基址偏移寻址,加载一个无符号半字16位,rd=M[rs imm]
lw
lw rd,imm(rs)
基址偏移寻址,加载一个字32位,rd=M[rs imm]
lwu
lwu rd,imm(rs)
基址偏移寻址,加载一个无符号字32位,rd=M[rs imm]
ld
ld rd,imm(rs)
基址偏移寻址,加载一个64位,rd=M[rs imm]
l.d
l.d freg,imm(rs)
基址偏移寻址,加载一个64位浮点数,freg=M[rs imm]
lui
lui reg,imm
英文原文是这个load upper half of register immediate,我也不是很懂@_@
存储数据到内存
sb
sb rs,imm(rd)
基址偏移寻址,存储一个字节8位,M[rd imm]=rs
sh
sh rs,imm(rd)
基址偏移寻址,存储一个半字16位,M[rd imm]=rs
sw
sw rs,imm(rd)
基址偏移寻址,存储一个字32位,M[rd imm]=rs
sd
sd rs,imm(rd)
基址偏移寻址,存储一个64位,M[rd imm]=rs
s.d
s.d freg,imm(rd)
基址偏移寻址,存储一个64位浮点数,M[rd imm]=freg
算术运算
daddi
daddi rd,rs,imm
立即数寻址,加法操作,rd=rs imm
daddui
daddi rd,rs,imm
立即数寻址,无符号加法操作,rd=rs imm
dadd
dadd rd,rs,rt
寄存器寻址,加法操作,rd=rs rt
daddu
daddu rd,rs,rt
寄存器寻址,无符号加法操作,rd=rs rt
dsub
dsub rd,rs,rt
寄存器寻址,减法操作,rd=rs-rt
dsubu
dsubu rd,rs,rt
寄存器寻址,无符号减法操作,rd=rs-rt
dmul
dmul rd,rs,rt
寄存器寻址,乘法操作,rd=rs*rt
dmulu
dmulu rd,rs,rt
寄存器寻址,无符号乘法操作,rd=rs*rt
ddiv
ddiv rd,rs,rt
寄存器寻址,除法操作,rd=rs/rt
ddivu
ddivu rd,rs,rt
寄存器寻址,无符号除法操作,rd=rs/rt
add.d
add.d freg1,freg2,freg3
寄存器寻址,浮点数加法,freg1=freg2 freg3
sub.d
sub.d freg1,freg2,freg3
寄存器寻址,浮点数减法,freg1=freg2-freg3
mul.d
mul.d freg1,freg2,freg3
寄存器寻址,浮点数乘法,freg1=freg2*freg3
div.d
div.d freg1,freg2,freg3
寄存器寻址,浮点数除法,freg1=freg2/freg3
逻辑运算
and
and rd,rs,rt
寄存器寻址,与操作,rd=rs&rt
or
or rd,rs,rt
寄存器寻址,或操作,rd=rs|rt
xor
xor rd,rs,rt
寄存器寻址,异或操作,rd=rs^rt
andi
andi rd,rs,imm
立即数寻址,与操作,rd=rs&imm
ori
ori rd,rs,imm
立即数寻址,或操作,rd=rs|imm
xori
andi rd,rs,imm
立即数寻址,异或操作,rd=rs^imm
置位
slt
slt rd,rs,rt
寄存器寻址,如果rs<rt那么rd=1,否则rd=0
sltu
sltu rd,rs,rt
寄存器寻址,无符号比较,如果rs<rt那么rd=1,否则rd=0
slti
slti rd,rs,imm
立即数寻址,如果rs<imm那么rd=1,否则rd=0
sltiu
sltiu rd,rs,imm
立即数寻址,无符号比较,如果rs<imm那么rd=1,否则rd=0
分支
beq
beq rs,rt,label
PC相对寻址,如果rs==rt,那么程序跳转到label
bne
bne rs,rt,label
PC相对寻址,如果rs!=rt,那么程序跳转到label
beqz
beqz rs,label
PC相对寻址,如果rs==0,那么程序跳转到label
bnez
bnez rs,label
PC相对寻址,如果rs!=0,那么程序跳转到label
跳转
j
j label
伪直接寻址,程序直接跳转到label
jr
jr rs
伪直接寻址,程序直接跳转到rs中的地址
jal
jal label
伪直接寻址,程序直接跳转到label并保存程序当前下一条指令地址到r31
jalr
jalr rs
伪直接寻址,程序直接跳转到rs中的地址并保存程序当前下一条指令地址到r31
移位
为什么没有算术左移,因为算术左移和逻辑左移效果一样,都是右边补0,但是逻辑右移和算术右移不一样,逻辑右移左边直接补0,而算术右移左边需要补符号位,即负数补1,非负数补0
dsll
dsll rd,rs,imm
立即数寻址,逻辑左移,rd=rs<<imm
dsrl
dsrl rd,rs,imm
立即数寻址,逻辑右移,rd=rs>>imm
dsra
dsra rd,rs,imm
立即数寻址,算术右移,rd=rs>>imm
dsllv
dsllv rd,rs,rt
寄存器寻址,逻辑左移,rd=rs<<rt
dsrlv
dsrlv rd,rs,rt
寄存器寻址,逻辑右移,rd=rs>>rt
dsrav
dsrav rd,rs,rt
寄存器寻址,算术左移,rd=rs<<rt
移动
movz
movz rd,rs,rt
寄存器寻址,如果rt==0那么rd=rs
movn
movn rd,rs,rt
寄存器寻址,如果rt!=0那么rd=rs
mov.d
mov.d freg1,freg2
寄存器寻址,freg1=freg2
mtcl
mtcl rs,freg
寄存器寻址,freg=rs
mfcl
mfcl rd,freg
寄存器寻址,rd=freg
其他
halt
halt
程序结束
nop
nop
没有操作
cvt.d.l
cvt.d.l freg,freg
convert 64-bit integer to a double FP format
cvt..l.d
cvt.l.d freg,freg
convert double FP to a 64-bit integer format
c.lt.d
c.lt.d freg,freg
set FP flag if less than
c.le.d
c.le.d freg,freg
set FP flag if less than or equal to
c.eq.d
c.eq.d freg,freg
set FP flag if equal to
bclf
bclf label
branch to address if FP flag is FALSE
bclt
bclt label
branch to address if FP flag is TRUE
终端交互
内存映射
CONTROL: .word 0x10000 DATA: .word 0x10008
WinMIPS64 模拟器支持内存映射 IO 模型,用于写入 或 从 WinMIPS64 终端读取。
要写入终端:
- 将内存地址设置为要写入的值
DATA
- 将适当的值写入内存地址
CONTROL
要从终端读取:
- 将适当的值写入内存地址
CONTROL
- 从内存地址读取输入
DATA
CONTROL | 用法 |
---|---|
写入操作 | |
1 | 设置为输出的无符号整数DATA |
2 | 设置为输出的有符号整数DATA |
3 | 设置为输出的浮点值DATA |
4 | 设置为用于输出的字符串的内存地址DATA |
5 | 设置为像素的坐标、坐标和 RGB 颜色(分别使用字节、字节和 word32 存储)DATA 5xDATA 4yDATA |
读取操作 | |
8 | 从终端/键盘读取(整数或浮点值)DATA |
9 | 从中读取一个字节,没有字符被回显DATA |
其他操作 | |
6 | 清除终端屏幕 |
7 | 清除图形屏幕 |
示例①输出hello world
代码语言:javascript复制 .data
CONTROL: .word32 0x10000
DATA: .word32 0x10008
mes: .asciiz "Hello World!n"
.text
daddi r1,r0,mes
lw r2,DATA(r0)
sd r1,0(r2)
daddi r1,r0,4
lw r2,CONTROL(r0)
sd r1,0(r2)
halt
示例②读取两个数计算乘积
代码语言:javascript复制 .data
CONTROL: .word32 0x10000
DATA: .word32 0x10008
cue1: .asciiz "please enter two numbers:n"
cue2: .asciiz "results:n"
cue3: .asciiz "warning: result overflown"
.text
daddi r1,r0,cue1 # please enter two numbers
lw r2,DATA(r0)
sd r1,0(r2)
daddi r1,r0,4
lw r2,CONTROL(r0)
sd r1,0(r2)
daddi r1,r0,8 # r3=a
lw r2,CONTROL(r0)
sd r1,0(r2)
lw r2,DATA(r0)
lw r3,0(r2)
daddi r1,r0,8 # r4=b
lw r2,CONTROL(r0)
sd r1,0(r2)
lw r2,DATA(r0)
lw r4,0(r2)
dadd r5,r0,r0 # r5=0 for r5=a*b
daddi r1,r0,32
loop: andi r2,r4,1 # r4[-1]
beq r2,r0,zero # r4[-1]==1?
dadd r5,r5,r3
zero: dsll r3,r3,1
dsra r4,r4,1
daddi r1,r1,-1
bne r1,r0,loop
daddi r1,r0,cue2 # results
lw r2,DATA(r0)
sd r1,0(r2)
daddi r1,r0,4
lw r2,CONTROL(r0)
sd r1,0(r2)
lw r2,DATA(r0) # output a*b
sd r5,0(r2)
daddi r1,r0,2
lw r2,CONTROL(r0)
sd r1,0(r2)
dsra r1,r5,16 # r1=r5[0:31]
dsra r1,r1,16
beq r1,r0,end
daddi r1,r0,cue3 # output overflow
lw r2,DATA(r0)
sd r1,0(r2)
daddi r1,r0,4
lw r2,CONTROL(r0)
sd r1,0(r2)
end: halt