基于MIPS指令集的单周期处理器设计

(完整程序获取见文章末尾)

一、项目概述
  1. 设计题目
    设数组存有8个任意字符,将其按顺序拼接得到一个双字(64位),对此双字进行循环左移4位。计算新得到的8个字符中,每个字符中1的个数,并对应存储成新的数组。
  2. 设计内容
    (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)  //依次判断字符的每个位是否为1count[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置1beq  $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置0loop3: sllv $t7, $s0, $t1  #$t7存放1左移j位的结果lb $t8, 0($t6) #将new_array[i]存入$t8的低8位and $t7, $t7, $t8  beq $t7, $zero, elseaddi $s2, $s2, 1   #count++else:   sb $s2,0($t5)  #将计数结果存入内存的count[i]对应的位置上addi $t1, $t1, 1 #j++addi $a3, $zero, 7slt $t9, $a3, $t1#若j > 7,则$t9置1beq $t9, $zero, loop3 addi $t0, $t0, 1  #i++addi $a3, $zero, 7slt $t5, $a3, $t0 #若i<8,则$t5置1beq $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, 7slt $t5, $a3, $t0  #若i<8,则$t5置1beq $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置1beq  $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置0loop3: sllv $t7, $s0, $t1  #$t7存放1左移j位的结果lb $t8, 0($t6) #将new_array[i]存入$t8的低8位and $t7, $t7, $t8  beq $t7, $zero, elseaddi $s2, $s2, 1   #count++else:   sb $s2,0($t5)  #将计数结果存入内存的count[i]对应的位置上addi $t1, $t1, 1 #j++addi $a3, $zero, 7slt $t9, $a3, $t1#若j > 7,则$t9置1beq $t9, $zero, loop3 addi $t0, $t0, 1  #i++addi $a3, $zero, 7slt $t5, $a3, $t0 #若i<8,则$t5置1beq $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为异步低电平复位信号beginif(!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@(*)beginif(instr == 32'hffff_ffff)begin:for_loopinteger 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]);endelse ;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)  beginif(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@(*)
beginif(opcode == 6'b0) //R型指令begincase(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 endelse 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@(*)begincase(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,rtAND: 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
initialforever #5 clk = !clk;
initial
begin$dumpfile("test.vcd");$dumpvars(0,test);
end
endmodule

在ISE中进行仿真,得到的结果如下图所示:




根据仿真结果可知,数据存储的的[7:0]存储着原字符数组,而[15:8]被写入了经过循环移位后的新字符数组,[23:16]被写入了新字符数组中每个字符中的1的个数,且数据与C语言程序运行结果一致,因此可认为设计的单周期处理器实现了要求的功能。

六、易出错的地方
  1. 为了便于仿真时观察实验结果,在许多模块中加入了不可综合的语句,若要进行综合,并将程序烧录进FPGA中则需要删除这些不可综合的语句。
  2. 一般的设计处理器的流程是先确定需要哪些指令,在根据分析每条指令的数据通路、控制通路,如下图所示

    而在本实验中是根据具体的问题要求来设计指令集,汇编程序要用到哪些指令,在微处理器中就考虑哪些指令。
  3. 使用对内存初始化函数readmemh(16进制数据)时,要注意的是数据文件(txt)需要在项目文件夹中,否则就要写出文件的全路径,还需注意的是全路径要用"/“符号,而windows下用的是”"。
  4. 可能要用到的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

基于MIPS指令集的单周期处理器设计相关推荐

  1. 基于 RICS-V 架构的单周期处理器设计(含所有格式指令)—— 逻辑部件概述

    文章目录 一.概述 二.原理图 2.1 ALU 2.1.1 ALU 操作控制信号生成部件 2.1.2 ALU 逻辑计算部件 2.1.3 ALU 整体逻辑 2.2 寄存器 2.2.1 Reg 整体逻辑 ...

  2. 基于 RICS-V 架构的单周期处理器设计(含所有格式指令)—— 控制信号选取及代码结构分析

    文章目录 一.概述 二.设计过程 2.1 选取指令 2.2 指令功能简述 2.3 设计过程概述 2.4 扩展码取值 2.5 三种 ALU 操作信号 2.5.1 操作信号取值 2.5.1 操作信号编码 ...

  3. 基于RICS-V的单周期处理器设计

    基于RICS-V的单周期处理器设计 文章目录 基于RICS-V的单周期处理器设计 1.概述 2.原理图 3.各个模块 3.1.ALU 3.2.立即数扩展器 3.3.取指令器 3.4.译码器 3.5.寄 ...

  4. 基于 RICS-V 架构的单周期 38 条指令处理器设计(含源码及实验报告)

    一.概述   之前有专门的写过两篇博文来介绍基于 RICS-V 架构的单周期九条指令处理器设计,并提供了相关的代码结构介绍,之后我又对其进行了拓展,且修补了之前源码中存在的一些小问题,并将指令集从九条 ...

  5. 从零开始设计RISC-V处理器——单周期处理器的设计

    系列文章目录 (一)从零开始设计RISC-V处理器--指令系统 (二)从零开始设计RISC-V处理器--单周期处理器的设计 (三)从零开始设计RISC-V处理器--单周期处理器的仿真 (四)从零开始设 ...

  6. 【Computer Organization笔记10】单周期CPU设计:基于7条MIPS指令的数据通路

    本次笔记内容: P19 计算机组成原理(19) P20 计算机组成原理(20) 本节课对应幻灯片: 组成原理24 singlecycle.pptx 基于上节课的7条MIPS指令的数据通路,分别针对7条 ...

  7. 31条指令单周期cpu设计(Verilog)-(二)总体设计

    目录 31条指令单周期cpu设计(Verilog)-(一)相关软件 31条指令单周期cpu设计(Verilog)-(二)总体设计 31条指令单周期cpu设计(Verilog)-(三)指令分析      ...

  8. 计算机原理与结构 实验3《单周期微处理器设计》

    实验3<单周期微处理器设计> 一.实验目的 掌握:如何采用Verilog设计时序逻辑电路: 掌握:利用Quartus II 设计CPU的基本原理核方法: 掌握:指令系统的设计与实现方法. ...

  9. Risc-V单周期CPU设计思考

    Risc-V单周期CPU设计思考 今年学校课程改革,计算机组成课开始教学Risc-V,写单周期CPU的时候发现网上好像大多都是MIPS的CPU设计,所以就把自己关于设计Verilog的一些思路整理出来 ...

  10. 计算机组成原理实验单周期处理,计算机组成原理实验实验报告-单周期cpu设计...

    计算机组成原理实验实验报告-单周期cpu设计 (16页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 计算机组成原理实验计算机组成原理实验 ...

最新文章

  1. 工业相机帧率与曝光时间的关系
  2. MAC软件下载比较好的三个第三方网站
  3. python中国余数定理_Python实现的中国剩余定理算法示例
  4. 超越 一切还刚刚开始
  5. 又见斐波那契~矩阵快速幂入门题
  6. Linux/Documentations: Kernel Livepatching
  7. App Crash 详解
  8. 欧拉项目(python练习)problem 45
  9. 爬虫抓取新浪微博数据
  10. QQ查询信息接口php源码,免登录获取QQ用户信息API接口源码
  11. windbg 查看结构体_windbg常见命令
  12. 深度学习:GAN 对抗网络原理详细解析(零基础必看)
  13. 大学计算机基础教程实验答案,大学计算机基础试验教程习题参考答案
  14. redit mysql_这就是Reddit十年来的成就
  15. 电脑快捷键【Crtl】
  16. foreign key() references 字段名(字段名)详细用法
  17. 《生活,是很好玩的》读书日记
  18. Arcgis js api 点聚合
  19. 针对WIN10安卓模拟器蓝屏的解决办法
  20. 《机器学习》笔记:引言

热门文章

  1. linux 中cat用法
  2. 11x 程序员专属 TapTap 代码编辑器主题
  3. 【HAOI2009】【毛毛虫】【树形dp】
  4. DNS云学堂 | 行车不规范亲人两行泪,NS不规范运维两行泪
  5. Stc8A Air720D联调,问题(已解决)
  6. 解析dex2oat的实现
  7. 机器学习sklearn(13)层次聚类
  8. Linux下go环境安装、环境配置并执行第一个go程序
  9. 计算机主板自动重启,电脑自动重启频繁是主板的问题吗
  10. 苹果cookie是打开还是关闭_关闭手机广告的几个操作