基于MIPS指令集单周期CPU设计与实现——硬布线式

  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

0

100001

addu $1,$2,$3

$1=$2+$3

(rd)<-(rs)+(rt);rs=$2,rt=$3,rd=$1

Subu

000000

rs

rt

rd

0

100011

subu $1,$2,$3

$1=$2-$3

(rd)<-(rs)-(rt);rs=$2,rt=$3,rd=$1

or

000000

rs

rt

rd

0

100101

or   $1,$2,$4

$1=$2|$3

(rd)<-(rs)|(rt);rs=$2,rt=$3,rd=$1

sltu

000000

rs

rt

rd

0

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

0

 

 

 

 

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设计与实现——硬布线式

  1. 注意:此处NPC和PC合二为一成为PC

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

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

1.时序模块设计与仿真

(1)原理图基于MIPS指令集单周期CPU设计与实现——硬布线式

 

(2)功能

  • 输入引脚
  1. H_RUN输入引脚,L_STEP输入引脚,时序控制信号。

H_RUN

L_STEP

功能

X

0

时序电路不输出节拍信号

0

低变高

时序电路仅输出一组节拍信号,供单步调试用。

1

1

时序电路输出连续节拍信号

  1. CLK输入引脚,主时钟信号。
  2. RST1输入引脚,主复位控制信号,低电平复位。
  • 输出引脚

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

(3)仿真图基于MIPS指令集单周期CPU设计与实现——硬布线式

 

  1. 寄存器堆模块

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式

 

(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设计与实现——硬布线式

 

  1. 数据存储器ROM和程序存储器RAM模块

(1)原理图

ROM

基于MIPS指令集单周期CPU设计与实现——硬布线式

RAM

基于MIPS指令集单周期CPU设计与实现——硬布线式

(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设计与实现——硬布线式

RAM

基于MIPS指令集单周期CPU设计与实现——硬布线式

3.ALU运算部件

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式

(2)功能

  • 输入引脚

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

  • 输出引脚

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

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式

  1. PC程序计数器

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式

(2)功能

  • 输入引脚

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

  • 输出引脚

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

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式

  1. MUX多路选择器

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式

(2)功能

  • 输入引脚

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

  • 输出引脚

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

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式

  1. EXT拓展电路

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式

(2)功能

  • 输入引脚

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

  • 输出引脚

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

(3)仿真

基于MIPS指令集单周期CPU设计与实现——硬布线式

  1. 控制器的设计

(1)原理图

基于MIPS指令集单周期CPU设计与实现——硬布线式

  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设计与实现——硬布线式

  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 0 0 0 0 0 000 0 10 00 00
subu 1 0 0 0 0 0 001 0 10 00 00
sltu 1 0 0 0 0 0 100 0 10 00 00
or 1 0 0 0 0 0 010 0 10 00 00
syscall 0 0 0 1 0 0 000 0 10 00 00
addiu 1 0 0 0 1 1 000 0 10 00 01
lw 1 0 0 0 1 1 000 0 10 01 01
sw 0 1 0 0 1 1 000 0 10 01 01
beq 0 0 1 0 1 1 001 0 00 01 01
andi 1 0 0 0 1 1 011 0 10 00 01
jal 1 0 0 0 0 0 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

0

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设计与实现——硬布线式

 

图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