当前位置 : 主页 > 编程语言 > 其它开发 >

编写单周期mips的主机

来源:互联网 收集:自由互联 发布时间:2022-05-30
使用语言 我们接下来将使用verilog语言编写一个单周期的mips,话不多说让我们开始吧 编写指令 为了确保好上手,我们将有选择性的只完成mips中的八条指令 mips的指令格式形式主要为 •I
使用语言

我们接下来将使用verilog语言编写一个单周期的mips,话不多说让我们开始吧

编写指令

为了确保好上手,我们将有选择性的只完成mips中的八条指令

mips的指令格式形式主要为

•Instruction Syntax is rigid:

op dst, src1, src2

–1 operator, 3 operands

•op = operation name (“operator”)

•dst = register getting result (“destination”)

•src1 = first register for operation (“source 1”)

src2 = second register for operation (“source 2

实现的指令

addu

subu :主要实现寄存器内两数的加减

lw

sw :image-20220513130338181

beq:•Branch If Equal (beq)

–beq reg1,reg2,label

–If value in reg1 = value in reg2, go to label

jump:•Jump (j)

–j label

ori:

lui

 

指令格式

其中包括i-format , j-format,r-format

三种格式

•I-Format: instructions with immediates, lw/sw (offset is immediate), and beq/bne

–But not the shift instructions

•J-Format: j and jal

–But not jr

•R-Format: all other instructions

•It will soon become clear why the instructions have been partitioned in this way

r指令的格式

image-20220513131127181

addu的rformat格式

image-20220513131247706

i-format

image-20220513131338166

在这里插入图片描述

 

datapath

下面我们就开始写不同组件部分

ext(移位extender)

作为一个移位器,主要是用来对外界输入的immediate进行移位,根据输入的extop选项决定进行符号扩展还是0扩展,扩展好变成32位以后,进入下一步的运算,在我们所列的八条指令中,所有i指令的都会需要用到移位器进行运算 而(beq,jump指令会在ifu内置的移位器中完成操作,我们不作考虑)

module ext(imm16,imm32,ExtOp);
 input [15:0]imm16;
 input [1:0]ExtOp;
 output reg[31:0]imm32;
 
 //set ZERO,SIGN,LUI
 parameter ZERO=2'b00;
 parameter SIGN=2'b01;
 parameter LUI=2'b10;
 
 //two conditions
 always@(*)begin
   case(ExtOp)
     ZERO:imm32={16'b0,imm16};
     SIGN:imm32={{16{imm16[15]}},imm16};
     LUI: imm32= {imm16,16'b0};
   endcase
 end
endmodule

 

alu

接下来便是十分重要的累加器alu了,alu承担了大部分运算的功能与职责

alu主要用aluctr接受信号

可以执行 add sub or lui

四种操作

因为addu subu ori lui 最后的输出操作是输入到aluout去

而执行lw和sw的时候则需要addr进行访存,因此我们还需要一个输出端口addr

另外还需要产生一个zero信号来供pc判断是否beq的条件相等

module alu(busA,busB,ALUctr,zero,Alu_out,Addr);
 input [31:0]busA,busB;
 input [1:0]ALUctr;
 
 output [31:0]zero,Addr;
 output reg[31:0]Alu_out;
 
 //set ADD,SUB,OR,Lui
 parameter ADD=2'b00;
 parameter SUB=2'b01;
 parameter OR=2'b10;
 parameter LUI=2'b11;
 
 //three conditions
 always@(*)begin
   case(ALUctr)
     ADD:begin
       Alu_out=busA+busB;
     end
     SUB:begin
       Alu_out=busA-busB;
     end
     OR:begin
       Alu_out=busA|busB;
     end
     LUI:begin
       Alu_out=busB;
     end
   endcase
 end
 
 assign zero=Alu_out;
 assign Addr=Alu_out;
endmodule

 

mux 选择器

写一个用三次即可

这里不多加赘述

 

ifu instruction fetch unit

ifu是最为复杂的一个部件

在其中内置一个ext 我们主要将会用它来beq和jump的扩展,同时也会进行下一轮指令的选择

信号

ifu接受npc_sel的信号用来判定是否为j指令或beq指令,zero判断j指令的条件

接受clk作为时钟周期

用rst接受是否初始化的标志,在读取玩数据后,以instruction作为输出

存取指令

手下那我们需要知道,在ifu中的指令存取次奥那等是大端序,也就是说第一个位置放的是最大位数的数

因为pc在运行的时候每次运行

都要加4,这是因为每条指令会占四个格子

我们所有的操作也是在+4以后进行的

jump操作因为特定的只有26位,但又因为我们是需要直接跳到指令的头部进行操作,因此必须是四的倍数,所以我们直接移两位

从操作的逻辑中很明显我们也能看出来实现beq操作的时候的相对位移值也必须是4的倍数,这样更节约空间!!!!!

module ifu(nPC_sel,zero,clk,rst,instruction,j_sel,jValue);
 input clk,rst;
 input [1:0]nPC_sel;
 input [31:0]zero;
 input j_sel;
 input [25:0]jValue;
 output [31:0]instruction;
 
 reg [31:0]pc;
 reg [7:0]im[1023:0];
 reg [31:0]pcnew;
 wire [31:0]temp,t0,t1;
 wire [15:0]imm16;
 reg [31:0]extout;
 
 //give instruction a value
 assign instruction={im[pc[9:0]],im[pc[9:0]+1],im[pc[9:0]+2],im[pc[9:0]+3]};
 
 assign imm16=instruction[15:0];
 
 //set extout value
 assign temp={{16{imm16[15]}},imm16};
 
 
 //j condition
 always@(*)begin
   if(j_sel==1)begin
     extout={pc[31:28],jValue[25:0],2'b0};
   end
     if(j_sel==0)begin
     extout=temp[31:0]<<2;
   end
 end
   
 //set pcnew
 assign t0=pc+4;
 assign t1=t0+extout;
 
 always@(*)
 begin
   if(nPC_sel==2'b00)begin
     pcnew=t0;
   end
   else if(nPC_sel==2'b01)begin
     pcnew=extout;
   end
   else if(nPC_sel==2'b10)begin
     if(zero==0)begin
       pcnew=t1;
     end
   else begin
     pcnew=t0;
   end
   end
 end
 
 //reset
 always@(posedge clk,posedge rst)
 begin
   if(rst) pc=32'h0000_3000;
     else if(j_sel==0)pc=pcnew;
     else if(j_sel==1)pc=extout;
 end
 
endmodule
datamemory

内存部分的写法事实上和ifu类似

都涉及到数据的存储和提取

另外由于内存我们只需要1kb

所以我们仅仅需要地址线Addr的后10位表示地址的值就可以了

为了初始化内存数据我们设置在nedgedge rst的时候初始化所有内存的值

因为内存存储的时候是小端序,所以我们倒过来存储

module dm(Data_in,MemWr,Addr,clk,rst,Data_out);
 input [31:0]Data_in,Addr;
 input clk,rst,MemWr;
 output reg[31:0]Data_out;
 
 reg [7:0]DataMem[1023:0];
 wire [9:0]pointer;
 assign pointer=Addr[9:0];
 //reset
 integer i;
 always@(negedge rst)begin
   for(i=0;i<1024;i=i+1)
   DataMem[i]=0;
 end
 
 
 always@(posedge clk)begin
   //store word
   if(MemWr==1)begin
       DataMem[pointer+3]<=Data_in[31:24];
       DataMem[pointer+2]<=Data_in[23:16];
       DataMem[pointer+1]<=Data_in[15:8];
     DataMem[pointer]<=Data_in[7:0];
   end
 end
 
 always@(negedge clk)begin
   //load word
 if(MemWr==0)begin
     Data_out<={DataMem[pointer+3],DataMem[pointer+2],DataMem[pointer+1],DataMem[pointer]};
 end
end
endmodule

 

寄存器

在上升流的时候初始化缓存

module gpr(RegWr,ra,rb,rw,busW,clk,rst,busA,busB,Data_in);
input clk,rst,RegWr;
input [31:0]busW;
input [4:0]ra,rb,rw;
output [31:0]busA,busB,Data_in;
 
reg [31:0]regi[31:0];
 
//reset
integer i;
always@(posedge rst)
begin
  if(rst)
    for(i=0;i<32;i=i+1)
    regi[i]=0;
  end
   
//set busA & busB
assign busA=regi[ra];
assign busB=regi[rb];
assign Data_in=busB;
 
//Register write in
always@(posedge clk)begin
  if(RegWr)begin
    regi[rw]<=busW;
    regi[0]<=0;
  end
end
endmodule

 

控制单元

控制单元主要接受信号,然后依据给定的信号来完成输出

module ctrl(instruction,RegDst,RegWr,ExtOp,nPC_sel,ALUctr,MemtoReg,MemWr,ALUSrc,j_sel);
 input [31:0]instruction;
 output reg [1:0]ExtOp,ALUctr,nPC_sel;
 output reg RegDst,RegWr,MemtoReg,MemWr,ALUSrc,j_sel;
 
 initial begin
   nPC_sel=0;
   RegDst=0;
   RegWr=0;
   ExtOp=0;
   nPC_sel=0;
   ALUctr=0;
   MemtoReg=0;
   MemWr=0;
   ALUSrc=0;
   j_sel=0;
end

always@(*)begin
 //R-type
 if(instruction[31:26]==6'b000000)
   begin
     //ADDU
     if(instruction[5:0]==6'b100001)
       begin
         nPC_sel=2'b00;
         RegDst=1'b1;
         RegWr=1'b1;
         ExtOp=2'b00;
         ALUSrc=1'b0;
         ALUctr=2'b00;
         MemWr=1'b0;
         MemtoReg=1'b0;
         j_sel=1'b0;
     end
     //SUBU
     else if(instruction[5:0]==6'b100011)
       begin
         nPC_sel=2'b00;
         RegDst=1'b1;
         RegWr=1'b1;
         ExtOp=2'b00;
         ALUSrc=1'b0;
         ALUctr=2'b01;
         MemWr=1'b0;
         MemtoReg=1'b0;
         j_sel=1'b0;
       end
     end
     //ORI
   else if(instruction[31:26]==6'b001101)
     begin
       nPC_sel=2'b00;
         RegDst=1'b0;
         RegWr=1'b1;
         ExtOp=2'b00;
         ALUSrc=1'b1;
         ALUctr=2'b10;
         MemWr=1'b0;
         MemtoReg=1'b0;
         j_sel=1'b0;
       end
     //LW
   else if(instruction[31:26]==6'b100011)
     begin
       nPC_sel=2'b00;
         RegDst=1'b0;
         RegWr=1'b1;
         ExtOp=2'b01;
         ALUSrc=1'b1;
         ALUctr=2'b00;
         MemWr=1'b0;
         MemtoReg=1'b1;
         j_sel=1'b0;
       end
       //SW
     else if(instruction[31:26]==6'b101011)
       begin
         nPC_sel=2'b00;
         RegDst=1'b0;
         RegWr=1'b0;
         ExtOp=2'b01;
         ALUSrc=1'b1;
         ALUctr=2'b00;
         MemWr=1'b1;
         MemtoReg=1'b0;
         j_sel=1'b0;
       end
       //BEQ
     else if(instruction[31:26]==6'b000100)
       begin
         nPC_sel=2'b10;
         RegDst=1'b0;
         RegWr=1'b0;
         ExtOp=2'b01;
         ALUSrc=1'b0;
         ALUctr=2'b01;
         MemWr=1'b0;
         MemtoReg=1'b0;
         j_sel=1'b0;
       end
       //LUI
     else if(instruction[31:26]==6'b001111)
       begin
         nPC_sel=2'b00;
         RegDst=1'b0;
         RegWr=1'b1;
         ExtOp=2'b10;
         ALUSrc=1'b1;
         ALUctr=2'b11;
         MemWr=1'b0;
         MemtoReg=1'b0;
         j_sel=1'b0;
     end
   //J
    else if(instruction[31:26]==6'b000010)
      begin
         nPC_sel=2'b01;
         RegDst=1'b0;
         RegWr=1'b0;
         ExtOp=2'b01;
         ALUSrc=1'b0;
         ALUctr=2'b01;
         MemWr=1'b0;
         MemtoReg=1'b1;
         j_sel=1'b1;
   end
 end
endmodule
 

 

上一篇:查看SO KO 执行程序相关信息命令
下一篇:没有了
网友评论