天天看点

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

  1. 指令分析

指令分析是第一步:MIPS指令集一共有三种指令。

R型(寄存器型):由Op(6位,下同)操作码,Rs(5),Rt(5),Rd(5),shamt(5)移位位,func(6)功能码组成

I型(立即数型):由Op(6),Rs(5),Rt(5),imm16(16)16位立即数组成

J型(跳转型):由Op(6),imm26(26)26位立即数组成

下面是我选的一部分指令的分析

助记符 指令格式 示例 示例含义 操作及解释
R-型 op rs rt rd shamt func 操作 解释
Addu 000000 rs rt rd 100001 addu $1,$2,$3 $1=$2+$3 (rd)<-(rs)+(rt);rs=$2,rt=$3,rd=$1
Subu 000000 rs rt rd 100011 subu $1,$2,$3 $1=$2-$3 (rd)<-(rs)-(rt);rs=$2,rt=$3,rd=$1
or 000000 rs rt rd 100101 or   $1,$2,$4 $1=$2|$3 (rd)<-(rs)|(rt);rs=$2,rt=$3,rd=$1
sltu 000000 rs rt rd 101011 sltu $1,$2,$3 If($2<$3) $1=1else$1=0 if(rs<rt)rd=1else rd=0;rs=$2,rt=$3,rd=$1
syscall 000000 rs rt rd
I-型 Op rs rt immediate 示例 示例含义 操作及解释
Addiu 001001 Rs Rt immediate Addiu $1,$2,10 $1=$2+10 (rt)<-(rs)+(sign-extend)immediate,rt=$1,rs=$2
Andi 001100 Rs Rt immediate Andi   $1,$2,10 $1=$2&10 (rt)<-(rs)&(zero-extend)immediate,rt=$1,rs=$2
Lw 100011 Rs Rt immediate Lw $1,10($2) $1=Memory[$2+10] (rt)<-Memory(rs)+(sign_extend)offset),rt=$1,rs=$2
Sw 101011 Rs Rt immediate Sw $1,10($2) MeMORY[$2+10]=$1 Memory[(rs)+(sign_extend)offset]<-(rt),rt=$1,rs=$2
Beq 000100 Rs Re immediate Beq $1,$2,40 If($1=$2) goto PC+4+40 If((rt)=(rs))then (PC)<-(PC)+((sign_extend)offset<<2),rs=$1,rt=$2
J-型 op address 示例 示例含义 操作及解释
Jal 000011 address Jal 10000 $31=PC+4 goto 10000 ($31)<-(PC)+4;(PC)<-((zero_extend)address<<2),address=10000/4

2.基本数据通路设计

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. 注意:此处NPC和PC合二为一成为PC

运行流程:pc开始->指令存储器->取指令->控制器->分析指令->得到操作的控制信号->发送到各个器件

取完指令之后->IR送寄存器组->选择通路->送到ALU进行计算->进行后续操作。

1.时序模块设计与仿真

(1)原理图
基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚
  1. H_RUN输入引脚,L_STEP输入引脚,时序控制信号。
H_RUN L_STEP 功能
X 时序电路不输出节拍信号
低变高 时序电路仅输出一组节拍信号,供单步调试用。
1 1 时序电路输出连续节拍信号
  1. CLK输入引脚,主时钟信号。
  2. RST1输入引脚,主复位控制信号,低电平复位。
  • 输出引脚

共4个节拍信号T1、T2、T3、T4。

(3)仿真图
基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

  1. 寄存器堆模块

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚

clkread是寄存器堆的读时钟,clkwr是寄存器堆的写时钟,Reset是寄存器堆的复位信号,Regwr是寄存器堆的读写控制信号,高电平写,低电平读,RA[4..0]寄存器堆端口的输入端,RB[4..0]寄存器堆端口的输入端,RW[4..0]是寄存器堆的输出端,BusW[31..0]是寄存器堆的输入端,readnum[4..0]是寄存器堆的输入端,j是jal型指令的控制信号。

  • 输出引脚

BusA[31..0]和BusB[31..0]是寄存器堆的通道输出端,readdata[31..0]是读取寄存器内容的输出端。

  1. 仿真
    基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. 数据存储器ROM和程序存储器RAM模块

(1)原理图

ROM

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

RAM

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚

address是RAM存储器的地址输入端口,clock是RAM存取器的读写时钟控制信号。

data[31..0]是RAM存储器的数据输入端口,wren是读写控制信号,高电平写,低电平读,address[7..0]是RAM存储器的地址输入端口,clock是RAM存储器的读写时钟控制信号。

  • 输出引脚

q[31..0]是RAM和ROM存储器的数据输出端口。

(3)仿真图

ROM

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

RAM

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

3.ALU运算部件

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚

A[31..0]和B[31..0]是运算器的输入端,ALUop[2..0]是运算器的控制信号

  • 输出引脚

 ALUout[31..0]是运算器输出结果,zero是做减法时,结果为零时发出的信号

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. PC程序计数器

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚

reset是重置运算器的控制信号,enable是运算器的使能信号,clk是时钟脉冲信号,PCop[1..0]是控制控制PC进行不同操作的信号,imm26[25..0]是传输的立即数,zero是ALU做减法时零标志位,beq是进行beq操作时发出的信号

  • 输出引脚

PCout[31..0]输出下条指令的地址,PC4用于Jal操作时,下条指令地址的输出。

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. MUX多路选择器

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚

A0[31..0]、A1[31..0]、A2[31..0]、A3[31..0]是四个数据输入端,S是控制选择的控制信号。

  • 输出引脚

Y[31..0]是数据输出端。

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. EXT拓展电路

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

(2)功能

  • 输入引脚

imm16[15..0]是16立即数数据输入输入端,Extop是控制ext拓展器进行符号拓展或者零拓展的控制信号。

  • 输出引脚

Extout[31..0]是数据输出端,是拓展后输出的数值。

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. 控制器的设计

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

  1. 功能
  • 输入引脚

op[5..0]和func[5..0]是数据输入端,决定控制信号。

  • 输出引脚

ALUop[2..0]、PCop[1..0]、MUX_alub、MUX_busw[1..0]、MUX_rw[1..0]、extop、Regwr、DMwr、Beq、halt、j是数据输出端,分别控制ALU的操作,控制PC做不同的指令跳转,控制进入alu的线路,busw的输出端,控制不同信号的读写功能,拓展

仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v
  1. 完整数据通路设计
  1. 各模块的连接分析
指令 PC Im RF EXT ALU DM
输入引脚 PCin Imm26 Imaddr RA RB RW BusW Imm16 BusA BusB Dmaddr Dmin
subu PC.pcout PC.pcout IR[25:21] IR[20:16] IR[15:11] ALU.aluout RF.BusA RF.BusB
addiu PC.pcout PC.pcout IR[25:21] IR[20:16] ALU.aluout IR[15:0] RF.BusA EXT.extout
beq PC.pcout IR[25:0] PC.pcout IR[25:21] IR[20:16] RF.BusA RF.BusB
lw PC.pcout PC.pcout IR[25:21] IR[20:16] DM.dmout IR[15:0] RF.BusA EXT.extout ALU.aluout
sw PC.pcout PC.pcout IR[25:21] IR[20:16] IR[15:0] RF.BusA EXT.extout ALU.aluout RF.BusB
jal PC.pcout IR[25:0] PC.pcout 0x1F PC.pc4
合并 PC.pcout IR[25:0] PC.pcout IR[25:21] IR[20:16] 0:IR[15:11] 1:IR[20:16] 2:OX1F 0:ALU.aluout 1:DM.dmout 2:PC.pc4 IR[15:0] RF.BusA 0:RF.BusB 1:EXT.extout ALU.aluout RF.BusB
  1. 控制信号分析
Regwr DMwr Beq halt EXtop MUX_alub ALU_op J PCop MUX_busw MUX_RW
addu 1 000 10 00 00
subu 1 001 10 00 00
sltu 1 100 10 00 00
or 1 010 10 00 00
syscall 1 000 10 00 00
addiu 1 1 1 000 10 00 01
lw 1 1 1 000 10 01 01
sw 1 1 1 000 10 01 01
beq 1 1 1 001 00 01 01
andi 1 1 1 011 10 00 01
jal 1 000 1 01 10 10
addu+subu+sltu+or+addiu+lw+andi+jal sw beq halt addiu+lw+sw+beq+andi addiu+lw+sw+bqe+andi 000:addu+syscall+addiu+lw+sw+andi+jal,001:subu+beq,010:or,011:andi,100:sltu jal 10:addu+subu+sltu+or+syscall+addiu+lw+sw+andi,00:beq,01:jal 00:addu+subu+sltu+or+syscal+addiu,01:lw+sw+beq,10:jal 00:addu+subu+sltu+or+syscall+sw,01addiu+sw+lw+andi+beq,10:jal

1、测试程序

       为了验证CPU的正确性,编写了表6.1测试程序,其中的寄存器编码、立即数、地址等指令格式中的信息必须具体化。

表6.1  测试程序

序号 汇编语言 操作码 地址码 16进制机器编码 功能
Op function
1 addu $s0,$zero,$zero 000000 100001 00008021 $s0=$zero+$zero
2 addiu $s1,$zero,5 001001 4 24110005   $s1=$zero+5
3 subu $s2,$s1,$s0 000000 100001 8 02309023   $s2=$s1-$s0
4 or $s3,$s1,$s2 000000 100101 12 02329825   $s3=$s1|$s2
5 lw $s4,4($s0) 100011 16 8e140004   $s4=memory[$s0+4]
6 sltu $s5,$s1,$s2 000000 101011 18 0232a82b   If($s1<$s2)$s5=1else$s5=0
7 sw $s6,8($s0) 101011 24 ae160008   Memory[($s0+8)/4]=$s6
8 andi $s7,$s0,5 001100 28 32170005   $s7=$s0&5
9 beq $s1,$s2,4 000100 32 12320004 If($s1=$s2)pc=pc+4+16else pc=pc+4
10 Jal 9 000011 40 0c000009 Pc=36
11 syscall 000000 001100 36 0000000c Halt

2、仿真图

测试程序的仿真结果如图6.1所示。

基于MIPS指令集单周期CPU设计与实现——硬布线式alut.vcontroll.v EXT.vMUX2.vMUX4_r.v MUX4.v pcall.v RegisterFile.v

图6.1 程序运行仿真图

从仿真图可见,程序运行完全正确,执行停机指令HALT时,指令不再跳转。

alut.v

module alut(A,B,ALUop,ALUout,zero);

input [31:0] A,B;

input [2:0] ALUop;

output [31:0] ALUout;

output zero;

reg [31:0] res;

assign zero=(res==0)?1:0;

assign ALUout=res;

always @*

begin

case(ALUop)

3'b000:res<=A+B;

3'b001:res<=A-B;

3'b010:res<=A|B;

3'b011:res<=A&B;

3'b100:res<=A<B?1:0;

endcase

end

Endmodule

controll.v

module Controll(op,func,ALUop,PCop,MUX_alub,MUX_busw,MUX_rw,extop,Regwr,DMwr,Beq,halt,j);

input [5:0] op;

input [5:0] func;

output Regwr,DMwr,Beq,halt,extop,MUX_alub,j;

output [1:0] PCop,MUX_busw,MUX_rw;

output [2:0] ALUop;

//R

wire addu   = (op == 6'b000000 & func == 6'b100001)?1:0;

wire subu   = (op == 6'b000000 & func == 6'b100011)?1:0;

wire Or     = (op == 6'b000000 & func == 6'b100101)?1:0;

wire sltu   = (op == 6'b000000 & func == 6'b101011)?1:0;

wire syscall= (op == 6'b000000 & func == 6'b001100)?1:0;

//I

wire addiu= (op == 6'b001001)?1:0;

wire andi = (op == 6'b001100)?1:0;

wire lw   = (op == 6'b100011)?1:0;

wire sw   = (op == 6'b101011)?1:0;

wire beq  = (op == 6'b000100)?1:0;

//J

wire jal  = (op == 6'b000011)?1:0;

assign Regwr=addu | subu | Or | sltu | addiu | lw | andi | jal;

assign DMwr=sw;

assign Beq=beq;

assign halt=syscall;

assign extop=addiu | lw | sw | andi;

assign MUX_alub=addiu | lw | sw | andi;

assign j=jal;

assign ALUop[2]=sltu;

assign ALUop[1]=Or | andi;

assign ALUop[0]=subu | andi | beq;

assign PCop[1]=addu | subu | Or | sltu | syscall | addiu | andi | lw | sw;

assign PCop[0]=jal;

assign MUX_busw[1]=beq | jal ;

assign MUX_busw[0]=lw | sw;

assign MUX_rw[1]=jal;

assign MUX_rw[0]=addiu | andi | lw | sw | beq ;

endmodule

 EXT.v

module EXT(imm16,Extop,Extout);

 input [15:0] imm16;

 input  Extop;

 output reg [31:0] Extout;

  always @(imm16 or Extop)

      if(Extop)

if(~imm16[15])

begin

Extout<={{16{1'b0}},imm16[15:0]};

end

else

begin

Extout<={{16{imm16[15]}},imm16[15:0]};

end

endmodule

MUX2.v

module MUX2(A0,A1,S,Y);

    input [31:0]A0,A1;

    input S;

    output [31:0]Y;

    function [31:0]select;

        input [31:0]A0,A1;

        input S;

        case(S)

            1'b0:select=A0;

            1'b1:select=A1;

        endcase

    endfunction

    assign Y = select(A0,A1,S);

Endmodule

MUX4_r.v

module MUX4_r (A0, A1, A2, A3, S, Y);

    input [4:0] A0, A1, A3;

 input [1:0] A2;

    input [1:0] S;

    output [4:0] Y;

    function [31:0] select;

        input [4:0] A0, A1, A3;

  input [1:0] A2;

        input [1:0] S;

            case(S)

                2'b00: select = A0;

                2'b01: select = A1;

                2'b10: select = A2;

                2'b11: select = A3;

            endcase

    endfunction

    assign Y = select (A0, A1, A2, A3, S);

endmodule

 MUX4.v

module MUX4 (A0, A1, A2, A3, S, Y);

    input [31:0] A0, A1, A2, A3;

    input [1:0] S;

    output [31:0] Y;

    function [31:0] select;

        input [31:0] A0, A1, A2, A3;

        input [1:0] S;

            case(S)

                2'b00: select = A0;

                2'b01: select = A1;

                2'b10: select = A2;

                2'b11: select = A3;

            endcase

    endfunction

    assign Y = select (A0, A1, A2, A3, S);

endmodule

 pcall.v

module pcall(reset,enable,clk,PCop,imm26,zero,beq,PCout,PC4);

 input enable,reset,clk,zero,beq;

 input [1:0] PCop;

 input [25:0] imm26;

 output reg [31:0]  PC4;

 output  reg[31:0]  PCout;

  initial

    begin

 PCout<=32'h00000000;

 end

  always @(posedge clk or posedge reset )

begin

   if (reset)

   begin

PCout<=32'h00000000;

end

 else

   if (enable)

if(PCop==2'b00&&beq&&zero)

begin

PCout<=PCout+32'h00000004+{{16{imm26[15]}},imm26[15:0],2'b00};

end

else if(PCop==2'b01)

begin

PC4<=PCout+32'h00000004;

PCout<={PCout[31:28],imm26,2'b00};

end

else if(PCop==2'b10)

begin

PCout<=PCout+32'h00000004;

end

else

begin

PCout<=PCout+32'h00000004;

end

end

endmodule

 RegisterFile.v

module RegisterFile(clkread,clkwr,Reset,RegWr,RA,RB,RW,BusW,BusA,BusB,readnum,readdata,j);

input clkread,clkwr,Reset,RegWr,j;

input [4:0] RA,RB,RW,readnum;

input [31:0] BusW;

output reg [31:0] BusA,BusB;

output  [31:0] readdata;

reg [31:0] regfile[31:0];

integer i;

initial

 begin

   regfile[0]=32'h00000000;

  end

 assign readdata=regfile[readnum];

 always @(posedge clkwr or posedge Reset)

   begin

    if (Reset)

         begin

        for (i=1;i<=31;i=i+1)

     regfile[i]<=0;

      end

    else

        begin

   if (RegWr)

 if(j)

 begin

 regfile[31]<=BusW;

 end

 else

 begin

       regfile[RW]<=BusW;

    end

     end

  end

  always @(posedge clkread)

  begin

       BusA<=regfile[RA];

       BusB<=regfile[RB];

  end

endmodule

继续阅读