基于MIPS指令集的单周期处理器设计
(完整程序获取见文章末尾)
一、项目概述
- 设计题目
设数组存有8个任意字符,将其按顺序拼接得到一个双字(64位),对此双字进行循环左移4位。计算新得到的8个字符中,每个字符中1的个数,并对应存储成新的数组。 - 设计内容
(1)按设计题目采用C语言实现并验证,给出验证结果。
(2)将验证过的C程序转化为MIPS汇编程序,并转化为机器码。
(3)面向该汇编程序采用的指令集,采用Verilog分别实现为单周期处理器。
(4)采用Verilog设计上述处理器的验证环境,并在仿真器上验证,最终给出验证波形图。
(5)每种处理器的实现要求按照top-down的设计方法,进行模块划分。
(6)设计结果要求充分考虑成本、性能及存储器存储空间优化。
二、C语言代码及测试结果
根据设计题目的要求设计可C语言代码如下:
//预处理命令
#include <stdio.h>
//主函数
int main(void){
int i,j ;
char array[8] = "abcdefgh";
char new_array[8];
char count[8]; //为了编汇编程序时统一使用lb/sb指令,将count也定义位char型
//进行数组的循环移位操作
for(i = 0;i<7;i++){
new_array[i] = array[i]<<4 | array[i+1]>>4;
}//由于字符型是8位的,因此左移四位时,高4位被舍去,低4位补0,右移4位时也类似
new_array[7] = array[7]<<4 | array[0]>>4; //对于循环左移,最右侧的字符需要特殊处理
//计算循环移位后的新字符中每个字符中“1”的个数
for(i = 0;i<8;i++){
//依次判断每个字符的1的个数
count[i] = 0;
for(j = 0;j < 8;j++){
if((new_array[i] & 1<<j) != 0) //依次判断字符的每个位是否为1
count[i]++;
}
printf("array[%d] = %x, new_array[%d] = %x, count[%d] = %d\n",i,
array[i],i,(unsigned char)new_array[i],i,count[i]); //不希望编译这条语句时可以使用条件编译指令
}
return 0;
}
程序运行结果如下:
一个字符为8位,对字符数组进行4位的循环左移,若将字符表示为16进制,则可看为循环左移1位,根据上述运行结果可知,C语言程序实现了题目的要求。
三、汇编代码及机器码
根据C语言编写MIPS汇编程序如下所示:
add $t0,$zero,$zero #寄存器$t0代表变量i,并初始化为0
add $t1,$zero,$zero #寄存器$t1代表变量j,并初始化为0
addi $t2,$zero,0#寄存器$t2存储着字符数组array的基地址0
addi $t3,$zero,8 #寄存器$t3存储着字符数组new_array的基地址8
addi $t4,$zero,16 #寄存器$t4存储着int数组count的基地址16
addi $s0, $zero, 1 #$s0存放常数1
addi $s1, $zero, 4 #$s1存放常数4
#对数组array进行循环移位得到新的数组new_array
loop1: add $t5, $t0, $t2 #将array[i]的地址放入$t5中
addi $t6, $t5, 1 #将array[i+1]的地址放入$t6中
add $t7, $t0,$t3 #将new_array[i]的地址放入$t7中
lb $t8, 0($t5) #将array[i]存入$t8的低8位
lb $t5, 0($t6) #将array[i+1]存入$t5的低8位
sllv $t8, $t8, $s1 #将array[i]逻辑左移4位后放入$t8中
srlv $t5, $t5, $s1 #将array[i+1]逻辑右移4位后放入$t5中
or $t5, $t5, $t8 #将移位后的array[i]和array[i+1]按位或后放入$t5中
sb $t5, 0($t7) #将$t5的低8位放入内存中new_array[i]位置上
addi $t0, $t0, 1 # i++
addi $a3, $zero, 6
slt $t5, $a3,$t0 #若6 < i即i > =7,则$t5置1
beq $t5, $zero,loop1 #若i <7,则继续循环
lb $t5, 7($t2) #将array[7]从内存中取出,放入$t5的低8位
lb $t6, 0($t2) #将array[0]从内存中取出,放入$t6的低8位
sllv $t5, $t5, $s1
srlv $t6, $t6, $s1
or $t5, $t5, $t6
sb $t5, 7($t3) #存入new_array[7]的值
#计算新数组new_array中每个字符的1的个数,并存入数组count
add $t0,$zero,$zero #前一次循环中i的值被改变,现在要重新置0
loop2: add $t5, $t0, $t4 #将count[i]的地址放入$t5中
add $t6, $t0, $t3 #将new_array[i]的地址放入$t6中
add $s2, $zero, $zero #$s2寄存器暂时存放计数结果
add $t1, $zero, $zero #每次进入循环前将j置0
loop3: sllv $t7, $s0, $t1 #$t7存放1左移j位的结果
lb $t8, 0($t6) #将new_array[i]存入$t8的低8位
and $t7, $t7, $t8
beq $t7, $zero, else
addi $s2, $s2, 1 #count++
else: sb $s2,0($t5) #将计数结果存入内存的count[i]对应的位置上
addi $t1, $t1, 1 #j++
addi $a3, $zero, 7
slt $t9, $a3, $t1#若j > 7,则$t9置1
beq $t9, $zero, loop3
addi $t0, $t0, 1 #i++
addi $a3, $zero, 7
slt $t5, $a3, $t0 #若i<8,则$t5置1
beq $t5, $zero, loop2
为了能在MARS仿真器上运行上述MIPS汇编代码,需对汇编代码进行更改:将数组首地址更改为可访问的数据段,并加入将”a,b,c,d,e,f,g,h”存入内存中的汇编语言,具体修改内容如下:
add $t0,$zero,$zero #寄存器$t0代表变量i,并初始化为0
add $t1,$zero,$zero #寄存器$t1代表变量j,并初始化为0
addi $t2,$zero,0x10010000 #寄存器$t2存储着字符数组array的基地址0
addi $t3,$zero,0x10010008 #寄存器$t3存储着字符数组new_array的基地址8
addi $t4,$zero,0x10010010 #寄存器$t4存储着int数组count的基地址16
addi $s0, $zero, 1 #$s0存放常数1
addi $s1, $zero, 4 #$s1存放常数4
#依次将"a,b,c,d,e,f,g,h"存入数组array中
addi $a0, $zero, 0x61 #"a"的ASCII码
loop: add $t5, $t0, $t2 #将array[i]的地址放入$t5中
add $t6, $a0, $t0 #要存入array[i]的字符
sb $t6, 0($t5) #依次将"a,b,c,d,e,f,g,h"存入array[i]中
addi $t0, $t0, 1 #i++
addi $a3, $zero, 7
slt $t5, $a3, $t0 #若i<8,则$t5置1
beq $t5, $zero, loop
#对数组array进行循环移位得到新的数组new_array
add $t0,$zero,$zero #前一次循环改变了i的值,再次进入循环后重新将i置0
loop1: add $t5, $t0, $t2 #将array[i]的地址放入$t5中
addi $t6, $t5, 1 #将array[i+1]的地址放入$t6中
add $t7, $t0,$t3 #将new_array[i]的地址放入$t7中
lb $t8, 0($t5) #将array[i]存入$t8的低8位
lb $t5, 0($t6) #将array[i+1]存入$t5的低8位
sllv $t8, $t8, $s1 #将array[i]逻辑左移4位后放入$t8中
srlv $t5, $t5, $s1 #将array[i+1]逻辑右移4位后放入$t5中
or $t5, $t5, $t8 #将移位后的array[i]和array[i+1]按位或后放入$t5中
sb $t5, 0($t7) #将$t5的低8位放入内存中new_array[i]位置上
addi $t0, $t0, 1 # i++
addi $a3, $zero, 6
slt $t5, $a3,$t0 #若6 < i即i > =7,则$t5置1
beq $t5, $zero,loop1 #若i <7,则继续循环
lb $t5, 7($t2) #将array[7]从内存中取出,放入$t5的低8位
lb $t6, 0($t2) #将array[0]从内存中取出,放入$t6的低8位
sllv $t5, $t5, $s1
srlv $t6, $t6, $s1
or $t5, $t5, $t6
sb $t5, 7($t3) #存入new_array[7]的值
#计算新数组new_array中每个字符的1的个数,并存入数组count
add $t0,$zero,$zero #前一次循环中i的值被改变,现在要重新置0
loop2: add $t5, $t0, $t4 #将count[i]的地址放入$t5中
add $t6, $t0, $t3 #将new_array[i]的地址放入$t6中
add $s2, $zero, $zero #$s2寄存器暂时存放计数结果
add $t1, $zero, $zero #每次进入循环前将j置0
loop3: sllv $t7, $s0, $t1 #$t7存放1左移j位的结果
lb $t8, 0($t6) #将new_array[i]存入$t8的低8位
and $t7, $t7, $t8
beq $t7, $zero, else
addi $s2, $s2, 1 #count++
else: sb $s2,0($t5) #将计数结果存入内存的count[i]对应的位置上
addi $t1, $t1, 1 #j++
addi $a3, $zero, 7
slt $t9, $a3, $t1#若j > 7,则$t9置1
beq $t9, $zero, loop3
addi $t0, $t0, 1 #i++
addi $a3, $zero, 7
slt $t5, $a3, $t0 #若i<8,则$t5置1
beq $t5, $zero, loop2
在Mars中运行汇编代码结果如下:
根据以上运行结果可知,编写的汇编程序实现了要求的功能。再将汇编语言转化位机器码,如下图所示:
存入的最后一条指令是ffff_ffff,是自定义的停机指令,当遇到停机指令时pc不再更新,数据存储器和寄存器堆也不能写入数据。
四、指令集描述
根据汇编语言文件可知,包含的指令有:
(1)数据传输指令:
指令 特点
sb I型,opcode:101000(从高位到低位),将寄存器的低八位存入内存
lb I型,opcode:100000,将内存中一个字节放入寄存器低8位
(2)逻辑指令:
指令 含义
sllv R型,funct:000100,sllv $t1, $t2, $t3 $t1 = $t2 << $t3
srlv R型,funct:000110,srlv $t1, $t2, $t3 $t1 = $t2 >> $t3
or R型,funct:100101, 两个源寄存器按位或,结果存入目标
寄存器
and R型,funct:100100,两个源寄存器按位与,结果存入目标寄存器
(3)算术指令:
指令 含义
add R型,funct:100000,两个源寄存器相加,结果放入目标寄存器
addi I型,opcode:001000,源寄存器与立即数相加,结果放入目标寄存器
(4)跳转/转移/比较指令:
指令 含义
beq I型,opcode:000100,比较两个寄存器的值若相等则PC指针跳转到相应位置
slt R型,funct:101010,slt $1, $2, $3,if ($2 < $3),$1 = 1;else $1 = 0;
五、单周期处理器设计
5.1模块示意图与模块代码
5.1.1程序计数器pc
pc中存储着当前指令地址,在本指令集中除了遇到BEQ指令有效的情况是,pc都是每过一个周期加1,模块示意图如下:
adress_in[31:0]为输入pc的新地址
adress_out[31:0]为当前pc输出
clk为时钟
rst为复位信号
PC模块的Verilog代码如下:
`include "define.v"
//程序计数器模块
module pc(input clk,rst,pc_en,
input [`BUS_WIDTH-1:0] address_in,
output reg [`BUS_WIDTH-1:0] address_out);
always@(posedge clk or negedge rst) //rst为异步低电平复位信号
begin
if(!rst) address_out <= 32'b0;
else if(!pc_en) ; //运行到停机指令时,pc_en=0,pc不再更新
else address_out <= address_in;
end
endmodule
5.1.2寄存器堆模块
本寄存器组拥有32位寄存器,每一个寄存器为32位,寄存器中存放着数据,通过输入的指令取出指定数据进行相应的操作,模块示意图如下:
ra[5:0]为第一个读出寄存器的地址
rb[5:0]为第二个读出寄存器的地址
rw[5:0]为写入寄存器的地址
reg_wr为寄存器写使能信号
wr_data[31:0]为写入寄存器的数据
bus_a[31:0]为寄存器的第一个输出数据
bus_b[31:0]为寄存器的第二个输出数据
寄存器堆模块的Verilog代码如下:
`include "define.v"
//寄存器堆模块
module reg_file (input clk,reg_wr,input [`BUS_WIDTH-1:0] wr_data,
input [`REG_WIDTH-1:0] ra, rb, rw,
output [`BUS_WIDTH-1:0] bus_a, bus_b);
reg [`BUS_WIDTH-1:0] rom [`BUS_WIDTH-1:0]; //寄存器堆存储结构32x32
assign bus_a = rom[ra];
assign bus_b = rom[rb];
initial
$readmemh("0.txt",rom,0,31); //寄存器堆初始化为0,便于仿真,无法综合
always@(posedge clk)
if(reg_wr)
rom[rw] <= wr_data;
else ;
endmodule
5.1.3数据存储器模块
数据存储器模块存储数据,以字节为存储单位。其模块示意图如下:
数据存储器模块存储数据,以字节为存储单位。其模块示意图如下:
data_in[31:0]为输入数据
clk为时钟信号
wr_en为写使能信号
data_out[31:0]为数据输出信号
数据存储器模块的Verilog代码如下:
`include "define.v"
module data_mem (
input clk, wr_en,
input [`BUS_WIDTH-1:0] adr,instr,
input [`BUS_WIDTH-1:0] data_in,
output [`BUS_WIDTH-1:0] data_out
);
reg [`BYTE-1:0] rom [`DATA_MEM-1:0];
/*当停机时在控制台输出数据存储器中的数据
来观察是否实现功能*/
always@(*)
begin
if(instr == 32'hffff_ffff)
begin:for_loop
integer i ;
for(i=0;i< 24;i = i+4)
$display("data_mem[%2d]=%h,data_mem[%2d]=%h,data_mem[%2d]=%h,data_mem[%2d]=%h\n"
,i,rom[i],i+1,rom[i+1],i+2,rom[i+2],i+3,rom[i+3]);
end
else ;
end
initial
begin
$readmemh("ascii.txt",rom,0,7);
end
assign data_out = {{24{1'b0}},rom[adr]};
/*由于用到的数据传输指令只有lb和sb
因此在读出数据时输出的高24位置0
写入数据时只取输入数据的低8位*/
always@(posedge clk)
begin
if(wr_en)
rom[adr] <= data_in[`BYTE-1:0];
else ;
end
endmodule
5.1.4指令存储器
指令存储器存放指令,以字为储存单位。其模块示意图如下:
address_in[31:0]为输入指令11存储器的地址
instr[31:0]输出的指令
指令存储器模块的Verilog代码如下:
`include "define.v"
//指令存储器模块
module instr_mem( input [`BUS_WIDTH-1:0] address_in,
output [`BUS_WIDTH-1:0] instr);
//指令寄存器按字寻址,最小单元是一个字
reg [`BUS_WIDTH-1:0] rom [`INSTR-1:0];
initial
$readmemh("instru_hex.txt",rom); //将指令存入指令寄存器
assign instr = rom[address_in[`BUS_WIDTH-1:2]];
//输入的地址是按字节编址时的地址,而指令存储器实质上以字为单位,因此输入地址低两位要舍去
endmodule
5.1.5符号扩展模块
符号扩展模块的功能是将一个16位立即数进行有符号扩展,其模块示意图如下:
imm16[15:0]为输入的16位立即数
imm32[31:0]为输出的32为立即数
符号扩展模块的Verilog代码如下:
`include "define.v"
//符号扩展模块
module sign_ext(input [15:0] imm16,
output [`BUS_WIDTH-1:0] imm32);
assign imm32 = {{16{imm16[15]}},imm16}; //将16位立即数进行有符号扩展到32位
endmodule
5.1.6控制模块
控制模块实现的功能是根据指令中的opcode和funct位得到各个部件的控制信号。其模块示意图如下:
opcode是MIPS指令的操作码
funct是MIPS的R型指令的功能码
alu_ctr是alu的控制信号
reg_dst是决定写入寄存器是rd还是rt的信号
reg_wr是寄存器写使能信号
alu_src是决定alu第二个操作数是来源于寄存器还是立即数的信号
mem_wr是数据存储器写使能信号
mem_to_reg是决定写入寄存器的数据是来源于alu还是存储器的信号
控制模块的Verilog代码如下:
`include "define.v"
//控制器模块
module control(input [5:0] opcode,funct,output reg [2:0] alu_ctr,
output pc_en,reg_dst,reg_wr,alu_src,mem_wr,mem_to_reg);
//当遇到停机指令ffff_ffff时,pc_en = 0
assign pc_en = !((opcode == 6'b111111) && (funct == 6'b111111));
//reg_dst代表的是往寄存器堆中写入数据是写入rd还是rt寄存器的控制信号,对于R型指令写入rd,对于I型指令写入rt
assign reg_dst = (opcode == 6'b0);
//reg_wr代表的是寄存器堆的写使能信号,在设计的指令集中所有R型指令均可写入寄存器堆,I型指令中lb和addi可写入
assign reg_wr = (opcode == 6'b0) | (opcode == `LB) | (opcode == `ADDI);
//alu_src代表控制ALU第二个操作数来源的信号,对于R型指令,BEQ指令,第二个操作数为busb,对于I型指令,第二个操作数为立即数
assign alu_src = (opcode == 6'b0 | opcode == `BEQ);
//mem_wr代表数据存储器写入使能信号,在设计的指令集中只有sb指令可以写入存储器
assign mem_wr = (opcode == `SB);
//mem_to_reg决定写入寄存器的数据是来源与数据存储器还是alu,只有在lb指令时数据来源于存储器
assign mem_to_reg = (opcode != `LB);
//alu_ctr是决定alu做何种运算的控制信号
always@(*)
begin
if(opcode == 6'b0) //R型指令
begin
case(funct)
`SLLV: alu_ctr = 3'd1;
`SRLV: alu_ctr = 3'd2;
`OR: alu_ctr = 3'd4;
`AND: alu_ctr = 3'd3;
`ADD: alu_ctr = 3'd0;
`SLT: alu_ctr = 3'd6;
default: alu_ctr = 3'd0;
endcase
end
else if(opcode == `BEQ) alu_ctr = 3'd5; //在I型指令中只有BEQ不是作加法运算
else alu_ctr = 3'd0;
end
endmodule
5.1.7 ALU模块
ALU模块是运算单元,基于本指令集的处理器的ALU至少要实现加法,逻辑左、右移,按位与、或,“是否相等比较(beq)”这6种运算。其模块示意图如下:
in_a[31:0]为alu的第一个操作数
in_b[31:0]为alu的第二个操作数
alu_ctr[2:0]决定alu做何种运算
branch为分支跳转语句生效的标志信号
result[31:0]是alu的运算结果
ALU模块的Verilog代码如下:
`include "define.v"
//运算器模块
module alu(input [`BUS_WIDTH-1:0] in_a,in_b,
input [2:0] alu_ctr, //至少要实现6种运算
output branch, //分支跳转标志
output reg [`BUS_WIDTH-1:0] result);
parameter ADD = 3'd0, SLL = 3'd1, SRL = 3'd2, AND = 3'd3, OR = 3'd4, EQ = 3'd5, SLT = 3'd6;
assign branch = (alu_ctr == EQ) & (in_a == in_b);
//当alu_ctr=EQ,且两个操作数相等时,说明beq指令生效
always@(*)
begin
case(alu_ctr)
ADD: result = in_a + in_b;
SLL: result = in_b << in_a; //在仿真时发现汇编指令sllv $1,$2,$3分别对应于rd,rt,rs
SRL: result = in_b >> in_a; //而一般的R型指令的对应关系为rd,rs,rt
AND: result = in_a & in_b;
OR: result = in_a | in_b;
SLT: result = (in_a < in_b) ? 32'b1 : 32'b0;
default: result = 32'b0;
endcase
end
endmodule
5.1.8 其他模块
除了上述主要模块以外,还有一些简单的小模块,其Verilog代码如下:
//对一些常用的常量进行宏定义
`define BUS_WIDTH 32 //定义总线位宽位32
`define INSTR 50 //定义指令存储器大小为50,可存储50条32位指令
`define DATA_MEM 24 //定义数据存储期大小为24,可存储24个字节
`define REG_WIDTH 5 //寄存器堆共有32个,需要的地址线为5位
`define BYTE 8
`define SB 6'b101000
`define LB 6'b100000
`define SLLV 6'b000100
`define SRLV 6'b000110
`define OR 6'b100101
`define AND 6'b101000
`define ADD 6'b100000
`define ADDI 6'b001000
`define BEQ 6'b000100
`define SLT 6'b101010
//输入数据位宽为5的2选1选择器
module mux_5(input [4:0] rd, rt,
input sel,output [4:0] rw);
assign rw = sel ? rd : rt;
endmodule
//位宽为32的2选1选择器
module mux_32(input [31:0] rd, rt,
input sel,output [31:0] rw);
assign rw = sel ? rd : rt;
endmodule
各个模块的连接示意图如下所示:
根据模块连接图,可写出顶层模块如下所示:
`include "define.v"
`include "mux_32.v"
`include "pc.v"
`include "instr_mem.v"
`include "mux_5.v"
`include "alu.v"
`include "sign_ext.v"
`include "reg_file.v"
`include "data_mem.v"
`include "control.v"
module top(input clk,rst);
wire branch,reg_dst,alu_src,reg_wr,mem_to_reg,mem_wr,pc_en;
wire [`BUS_WIDTH-1:0] new_pc,pc,instr,operand2,imm32,result,bus_a,bus_b,reg_data,mem_out;
wire [2:0] alu_ctr;
wire [4:0] rw;
pc pc_i(.clk(clk),.rst(rst),.address_in(new_pc),.address_out(pc),.pc_en(pc_en)); //输出pc
instr_mem inst_mem_i(.address_in(pc),.instr(instr)); //取值
sign_ext sign_ext_i(.imm16(instr[15:0]),.imm32(imm32)); //立即数符号扩展
mux_32 mux_1(.rd(pc+32'd4+imm32*4),.rt(pc+32'd4),.sel(branch),.rw(new_pc)); //得到下一pc
mux_5 mux_2(.rd(instr[15:11]),.rt(instr[20:16]),.rw(rw),.sel(reg_dst)); //确定写寄存器
mux_32 mux_4(.rd(result),.rt(mem_out),.rw(reg_data),.sel(mem_to_reg)); //确定寄存器堆写入数据的来源
reg_file reg_file_i(.bus_a(bus_a),.bus_b(bus_b),.clk(clk),.reg_wr(reg_wr),
.wr_data(reg_data),.rw(rw),.ra(instr[25:21]),.rb(instr[20:16])); //寄存器堆写入与读出
mux_32 mux_3(.rd(bus_b),.rt(imm32),.rw(operand2),.sel(alu_src)); //确定ALU第二个操作数
alu alu_i(.in_a(bus_a),.in_b(operand2),.alu_ctr(alu_ctr),.branch(branch),.result(result)); //alu计算
data_mem data_mem_i(.data_in(bus_b),.clk(clk),.wr_en(mem_wr),.adr(result),.data_out(mem_out),.instr(instr));
//数据寄存器的写入与读出
control control_i(.opcode(instr[31:26]),.funct(instr[5:0]),.alu_ctr(alu_ctr),.pc_en(pc_en), //控制信号产生
.reg_dst(reg_dst),.reg_wr(reg_wr),.alu_src(alu_src),.mem_wr(mem_wr),.mem_to_reg(mem_to_reg));
endmodule
5.2 仿真验证
由于在编写数据存储器和指令存储器模块时,已经利用$readmemh系统函数将其初始化,所以testbench中只需要加入时钟信号即可编写testbench如下:
`timescale 100ns/1ns
`include "top.v"
module test;
reg clk = 1'b0, rst = 1'b1; //信号定义
top top_i(.clk(clk),.rst(rst));//待测模块实例化
initial
begin
#1 rst = 1'b0;
#1 rst = 1'b1;
#10000 $finish;
end
initial
forever #5 clk = !clk;
initial
begin
$dumpfile("test.vcd");
$dumpvars(0,test);
end
endmodule
在ISE中进行仿真,得到的结果如下图所示:
根据仿真结果可知,数据存储的的[7:0]存储着原字符数组,而[15:8]被写入了经过循环移位后的新字符数组,[23:16]被写入了新字符数组中每个字符中的1的个数,且数据与C语言程序运行结果一致,因此可认为设计的单周期处理器实现了要求的功能。
六、易出错的地方
- 为了便于仿真时观察实验结果,在许多模块中加入了不可综合的语句,若要进行综合,并将程序烧录进FPGA中则需要删除这些不可综合的语句。
- 一般的设计处理器的流程是先确定需要哪些指令,在根据分析每条指令的数据通路、控制通路,如下图所示
而在本实验中是根据具体的问题要求来设计指令集,汇编程序要用到哪些指令,在微处理器中就考虑哪些指令。 - 使用对内存初始化函数readmemh(16进制数据)时,要注意的是数据文件(txt)需要在项目文件夹中,否则就要写出文件的全路径,还需注意的是全路径要用"/“符号,而windows下用的是”"。
- 可能要用到的MIPS指令集知识
一般来说,R型指令的汇编语言和机器码的对应关系为:
add $1, $2, $3 其中$1,$2,$3分别对应机器码的rd,rs,rt位置,
而sllv与srlv指令有些特殊,其对应关系为:
sllv $1, $2, $2 其中$1,$2,$3分别对应机器码的rd,rt,rs位置。
七、完整程序下载
https://download.csdn.net/download/qq_45439159/13119543