多周期非流水CPU实现

一、实验内容

1. 处理器功能

本实验的任务是设计一个简单的RISC处理器,该处理器是在给定的指令集(与MIPS32类似)下构建的,支持12条指令。假定存储器分为数据缓冲存储器和指令缓冲存储器,且都可以在一个时钟周期内完成一次同步存取操作,时钟信号和CPU相同。处理器的指令字长为32位,包含32个32位通用寄存器R0~R31,1个32位的指令寄存器IR和1个32位的程序计数器PC,1个256×32位指令缓冲存储器,1个256×32位的数据缓冲存储器。

2. 指令系统定义

处理器所支持的指令包括 LWSWADDSUBSLLANDORXORSLTMOVZBNEJ

其中仅有 LW和 SW是字访存指令,所有的存储器访问都通过这两条指令完成;ADDSUBSLLANDORXORSLTMOVZ是运算指令,他们都在处理器内部完成;BNE是分支跳转指令,根据寄存器的内容进行相对跳转;J是无条件转移指令。

二、实验环境

Vivado 集成开发环境

龙芯 Artix-7 实验平台

三、设计思想

1. CPU接口信号定义

信号名

位数

方向

来源/去向

意义

clk

1

Input

输入

clock, 100MHz

resetn

1

Input

输入

复位,active low

debug_wb_pc

32

Output

输出

当前正在执行指令的PC

debug_wb_rf_wen

1

Output

寄存器组

当前通用寄存器组的写使能信号

debug_wb_rf_addr

5

Output

寄存器组

当前通用寄存器组写回的寄存器编号

debug_wb_rf_wdata

32

Output

寄存器组

当前指令需要写回的数据

 

2. 处理器的设计方案

 (1)指令格式设计

处理器是一个简单的RISC处理器,该处理器是在给定的指令集(与MIPS32类似)下构建的,支持12条指令。所支持的指令包括 LW,SW,ADD,SUB,SLL, AND,OR,XOR,SLT,MOVZ,BNE,J。

其中仅有 LW和 SW是字访存指令,所有的存储器访问都通过这两条指令完成;ADD、SUB、SLL、AND、OR、XOR、SLT、MOVZ是运算指令,他们都在处理器内部完成;BNE是分支跳转指令,根据寄存器的内容进行相对跳转;J是无条件转移指令。

类型

助记符号

指令格式

指令功能

运算

ADD RD,RS,RT

000000

RS

RT

RD

00000100000

 

[RD]←[RS] + [RT]

SUB RD,RS,RT

 

000000

RS

RT

RD

00000100010

 

[RD]←[RS] - [RT]

AND RD,RS,RT

 

000000

RS

RT

RD

00000100100

 

[RD]←[RS] & [RT]

OR RD,RS,RT

 

000000

RS

RT

RD

00000100101

 

[RD]←[RS] | [RT]

XOR RD,RS,RT

 

000000

RS

RT

RD

00000100110

 

[RD]←[RS]⊕[RT]

SLT RD,RS,RT

 

000000

RS

RT

RD

00000101010

 

[RD]←[RS]<[RT]?1:0

MOVZ RD,RS,RT

 

000000

RS

RT

RD

00000001010

 

if ([RT] == 0) then [RD]←[RS]

SLL RD,RT,sa

 

000000

00000

RT

RD

sa

000000

 

[RD]←[RT]<<sa

访存

SW RT,offset(base)

101011

base

RT

offset

 

Mem[[base] + offset] ← [RT]

LW RT,offset(base)

100011

base

RT

offset

 

 

[RT] ←Mem[[base] + offset]

跳转

BNE RS,RT,offset

000101

RS

RT

offset

 

PC←([RS] != [RT]) ? [sign_extend(offset) << 2 + NPC] : NPC

J target

000010

instr_index

 

 

PC←(NPC[31:28]) ## (instr_index << 2)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

关于汇编指令的说明:

rs意味着source register,rd意味着destination register;

rt有时(如运算指令)意味着第二个source register,有时(如访存指令)意味着target (source/destination) register;

我们使用 [rs] 表示寄存器 rs的内容;

另外,所有算数运算指令都执行有符号运算。

序号

指令

取指令周期(IF)

指令译码/读寄存器周期(ID)

执行/有效地址计算周期(EX)

存储器访问/分支完成周期(MEM)

写回周期(WB)

1

ADD RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`ADD

 

r_wdata←F;

we←1’b1;

2

SUB RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`SUB

 

r_wdata←F;

we←1’b1;

3

AND RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`AND

 

r_wdata←F;

we←1’b1;

4

OR RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`OR

 

r_wdata←F;

we←1’b1;

5

XOR RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`XOR

 

r_wdata←F;

we←1’b1;

6

SLT RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`SLT

 

r_wdata←F;

we←1’b1;

7

MOVZ RD,RS,RT

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11];

A←rdata1

B←rdata2

Card=`MOVZ

 

r_wdata←F;

we←1’b1;

8

SLL RD,RT,sa

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

r_waddr←IR[15:11]; Imm←IR[10:6];

A←Imm

B←rdata2

Card=`SLL

(F=B<<Imm)

 

r_wdata←F;

we←1’b1;

9

SW RT,offset(base)

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

Imm←IR[15:0];

A←rdata1

B←Imm

Card=`ADD

ram_addr←F;

ram_wdata←rdata2

ram_wen←1’b1;

 

10

LW RT,offset(base)

IR←IMem[PC] PC←PC+1

raddr1←IR[25:21];      raddr2←5’b0;

Imm←IR[15:0];

r_waddr←IR[20:16];

A←rdata1

B←Imm

Card=`ADD

ram_addr←F;

 

r_wdata=ram_rdata;

we=1’b1;

 

11

BNE RS,RT,offset

IR←IMem[PC]

PC←PC+1

raddr1←IR[25:21];      raddr2←IR[20:16];

Imm←IR[15:0];

A←rdata1;

B←rdata2;

Card=`SUB

if(!Zero) A←Imm<<2

B←PC

Card=`ADD

if(!Zero)

PC←F

 

12

J target

IR←IMem[PC]

PC←PC+1

Imm←IR[25:0];

 

 

PC←{PC[31:26],Imm<<2}

(2)处理器结构设计框图及功能描述

9db7cbc3fcf34e3095bd6d671db4cc18.png

该CPU为非流水简单CPU。指令执行分为5个周期完成,分别为取指、译码、执行、访存、写回。给定时钟信号和复位信号,处理器可自动执行指令系统规定的12种指令编写的程序,当复位信号为零时,CPU进行初始化。在取指周期,PC送至instr_mem并读出当前指令内容,之后PC加4送NPC;译码阶段,根据当前指令进行译码,得到立即数值送Imm,得到存操作数的通用寄存器号r_addr1和r_addr2,得到目的寄存器的寄存器号。在执行阶段,分别将对应的操作数赋给ALU的A和B,并给出对应的Card选择ALU的操作。在访存阶段,给ram_addr、ram_wen和ram_wdata赋值,其中完成跳转指令的NPC计算(有条件跳转根据执行周期生成的Zero条件码进行计算)。在写回阶段,为r_wdata和we赋值,并更新PC。

 

(3)各模块输入输出接口信号定义

模块名称及功能:

ALU

完成算数和逻辑运算

信号名

位数

方向

来源/去向

意义

A

32

IN

Rdata1

操作数1

B

32

IN

Rdata2

操作数2

Cin

1

IN

赋0

低位进位

Card

5

IN

control_unit

操作选择

F

32

OUT

register

结果

Cout

1

OUT

state

运算产生的进位

Zero

1

OUT

state

零标志位

 

模块名称及功能:

Register通用寄存器组

存储常用的操作数

信号名

位数

方向

来源/去向

意义

clk

1

IN

IN

时钟信号

raddr1

5

IN

control_unit

寄存器堆读地址1

raddr2

5

IN

control_unit

寄存器堆读地址2

we

1

IN

control_unit

寄存器堆写使能

waddr

5

IN

control_unit

寄存器堆写地址

wdata

32

IN

control_unit

寄存器堆写数据

rdata1

32

OUT

ALU

寄存器堆读返回数据1

rdata2

32

OUT

ALU

寄存器堆读返回数据2

 

模块名称及功能:

指令存储器instr_mem

存储程序的指令,只读,不可写

信号名

位数

方向

来源/去向

意义

ram_addr

32

IN

PC

当前指令的地址

ram_rdata

32

OUT

IR

读取当前指令

 

模块名称及功能:

数据存储器data_mem

存储数据,可读可写,同步读异步写

信号名

位数

方向

来源/去向

意义

clk

1

IN

IN

时钟信号

ram_wen

1

IN

control_unit

同步 RAM 写使能,置位时写入

ram_addr

32

IN

control_unit

同步 RAM 地址信号,表示读/写地址

ram_wdata

32

IN

control_unit

同步 RAM 写数据信号,表示写入数据

ram_rdata

32

OUT

Register

同步 RAM 读数据信号,表示读出数据

        以上表格不够可加页

四、实验设计

1. 各模块的详细设计

(1)ALU

完成算逻运算,含数据通路,为组合逻辑单元

`define ADD     5'b00001

`define ADDS    5'b00010

`define SUB     5'b00011

`define SUBS    5'b00100

`define SUB_A   5'b00101

`define SUBS_A  5'b00110

`define SAME_A  5'b00111

`define SAME_B  5'b01000

`define NOT_A   5'b01001

`define NOT_B   5'b01010

`define OR      5'b01011

`define AND     5'b01100

`define XNOR    5'b01101

`define XOR     5'b01110

`define NAND    5'b01111

`define ZERO    5'b00000

`define SLT     5'b10000

`define MOVZ    5'b10001

`define SLL     5'b10010



module alu(

    input [31:0] A,

    input [31:0] B,

    input Cin,

    input [4:0] Card,

    output [31:0] F,

    output Cout,

    output Zero

    );

    wire [32:0]    add_result;

    wire [32:0]    adds_result;

    wire [32:0]    sub_result;

    wire [32:0]    subs_result;

    wire [32:0]    sub_a_result;

    wire [32:0]    subs_a_result;

    wire [32:0]    same_a_result;

    wire [32:0]    same_b_result;

    wire [32:0]    not_a_result;

    wire [32:0]    not_b_result;

    wire [32:0]    or_result;

    wire [32:0]    and_result;

    wire [32:0]    xnor_result;

    wire [32:0]    xor_result;

    wire [32:0]    nand_result;

    wire [32:0]    zero_result;

    wire [32:0]    slt_result;

    wire [32:0]    movz_result;

    wire [32:0]    sll_result;

   

    assign    add_result=A+B;

    assign    adds_result=A+B+Cin;

    assign    sub_result=A-B;

    assign    subs_result=A-B-Cin;

    assign    sub_a_result=B-A;

    assign    subs_a_result=B-A-Cin;

    assign    same_a_result=A;

    assign    same_b_result=B;

    assign    not_a_result=~A;

    assign    not_b_result=~B;

    assign    or_result=A|B;

    assign    and_result=A&B;

    assign    xnor_result=~(A^B);

    assign    xor_result=A^B;

    assign    nand_result=~(A&B);

    assign    zero_result=0;

    assign    slt_result=(A<B)?32'h1:32'h0;

    assign    movz_result=(B == 32'h0)?A:B;

    assign    sll_result=B << A[4:0]; // 左移B的位数由A的低5位指定;

   

    assign  F   =   ({32{Card == `ADD}}  & add_result)  |

                    ({32{Card == `SUB}}  & sub_result)  |

                    ({32{Card == `ADDS}}  & adds_result)  |

                    ({32{Card == `SUBS}} & subs_result) |

                    ({32{Card == `SUB_A}}  & sub_a_result)  |

                    ({32{Card == `SUBS_A}}  & subs_a_result)  |

                    ({32{Card == `SAME_A}}  & same_a_result)  |

                    ({32{Card == `SAME_B}}  & same_b_result)  |

                    ({32{Card == `NOT_A}}  & not_a_result)  |

                    ({32{Card == `NOT_B}}  & not_b_result)  |

                    ({32{Card == `OR}}  & or_result)  |

                    ({32{Card == `AND}}  & and_result)  |

                    ({32{Card == `XNOR}}  & xnor_result)  |

                    ({32{Card == `XOR}}  & xor_result)  |

                    ({32{Card == `NAND}}  & nand_result)  |

                    ({32{Card == `ZERO}}  & zero_result)|

                    ({32{Card == `SLT}}  & slt_result)  |

                    ({32{Card == `MOVZ}}  & movz_result)  |

                    ({32{Card == `SLL}}  & sll_result);

      

    assign  Cout =  (Card == `ADD) ? add_result[32] :

                    (Card == `ADDS) ? adds_result[32] :

                    (Card == `SUB) ? sub_result[32] :

                    (Card == `SUBS) ? subs_result[32] :

                    (Card == `SUB_A) ? sub_a_result[32] :

                    (Card == `SUBS_A) ? subs_a_result[32] :

                    1'b0;

    assign  Zero =  (F == 32'h0);

endmodule

(2)寄存器堆

存取常用操作数

module register(

    input clk,

    input [4:0] raddr1,

    output [31:0] rdata1,

    input [4:0] raddr2,

    output [31:0] rdata2,

    input we,

    input [4:0] waddr,

    input [31:0] wdata

    );

    //采用寄存器数组的形式进行描述

    reg [31:0] regts[0:31];

   

    //初始化

   initial begin
        $readmemh("reg_data.txt",regts);
    end
   

    //写操作

    always @(negedge clk ) begin

        if(we) begin

            regts[waddr] <= wdata;

        end

    end

   

    //读操作

    assign rdata1 = regts[raddr1];

    assign rdata2 = regts[raddr2];

   

   

endmodule

(3)指令存储器

存指令程序

module instr_mem(

    input [31:0] addr,

    output [31:0] data

    );

    reg [31:0] instr [255:0];

    initial begin

        $readmemh("inst_data.txt",instr);

    end

    assign data=instr[addr/4];

endmodule

(4)数据存储器

module data_mem(

    input clk,

    input we,

    input [31:0] addr,

    input [31:0] w_data,

    output [31:0] data

    );

    reg [31:0] dmem [255:0];

    initial begin

        $readmemh("data_data.txt",dmem);

    end

    assign data=dmem[addr/4];

    always @(posedge clk)begin

        if(we) dmem[addr/4]<=w_data;

    end

endmodule

 

 

2. 系统的详细设计

CPU指令执行分五个阶段:取指IF、译码ID、执行EX、访存MEM、写回WB。采用更新当前状态进行控制,根据不同的状态标记采取不同的操作。

`define Add     6'b100000

`define Sub     6'b100010

`define And     6'b100100

`define Or      6'b100101

`define Xor     6'b100110

`define Slt     6'b101010

`define Movz    6'b001010

`define Sll     5'b000000



`define OP      6'b000000

`define SW      6'b101011

`define LW      6'b100011

`define BNE     6'b000101

`define J       6'b000010



`define IF      3'b000

`define ID      3'b001

`define EX      3'b010

`define MEM     3'b011

`define WB      3'b100





module cpu (

    input clk,

    input resetn,

    output [31:0] debug_wb_pc,

    output debug_wb_rf_wen,

    output [4:0] debug_wb_rf_addr,

    output [31:0] debug_wb_rf_wdata

);

  (* MARK_DEBUG="true" *)reg ram_wen, we, opcode_valid;

  (* MARK_DEBUG="true" *)reg [2:0] state,next_state;

  (* MARK_DEBUG="true" *)reg [4:0] Card, raddr1, raddr2, r_waddr;

  //(* MARK_DEBUG="true" *)reg [15:0] ram_addr;

  (* MARK_DEBUG="true" *)reg [31:0] r_wdata,ram_addr, ram_wdata,  A,B,Imm, PC,NPC;

  (* MARK_DEBUG="true" *)wire [31:0] rdata1,rdata2,F,ram_rdata,IR;

  (* MARK_DEBUG="true" *)wire Zero;



  //通用寄存器组

  register register (

      .clk(clk),

      .raddr1(raddr1),

      .rdata1(rdata1),

      .raddr2(raddr2),

      .rdata2(rdata2),

      .we(we),

      .waddr(r_waddr),

      .wdata(r_wdata)

  );



  //ALU

  alu alu (

      .A(A),

      .B(B),

      .Cin(1'b0),

      .Card(Card),

      .F(F),

      .Cout(Cout),

      .Zero(Zero)

  );



//  // 指令存储器

//  block_mem instr_mem (

//      .clka (clk),

//      .wea  (1'b0),   // 指令存储器只读

//      .addra(PC[15:0]/4),

//      .dina (32'h0),  // 写入0,因为这是只读存储器

//      .douta(IR)

//  );

//  // 数据存储器

//  block_mem1 data_mem (

//      .clka (clk),

//      .wea  (ram_wen),

//      .addra(ram_addr),

//      .dina (ram_wdata),

//      .douta(ram_rdata)

//  );

    instr_mem instr_mem(

        .addr(PC),

        .data(IR)

    );

    data_mem data_mem(

      .clk (clk),

      .we  (ram_wen),

      .addr(ram_addr),

      .w_data (ram_wdata),

      .data(ram_rdata)

    );

    always @(posedge clk or negedge resetn) begin

        if (!resetn) begin

            PC<=32'h0;

            state <= `IF; // 初始状态为取指阶段

        end else begin

            state <= next_state; // 使用下一个状态

            //if(state==`WB)PC<=NPC;

        end

    end

  always @(*) begin

        case (state)

            `IF:begin

                //if (opcode_valid) begin

                NPC=PC+4;

                case(IR[31:26])

                    `OP:begin

                        raddr1=IR[25:21];

                        raddr2=IR[20:16];

                        r_waddr=IR[15:11];

                        if(IR[5:0]==`Sll)Imm=IR[10:6];

                    end

                    `SW,`BNE:begin

                        raddr1=IR[25:21];

                        raddr2=IR[20:16];

                        Imm=IR[15:0];

                    end

                    `LW:begin

                        raddr1=IR[25:21];

                        raddr2=5'b0;

                        r_waddr=IR[20:16];

                        Imm=IR[15:0];

                    end

                    `J:begin

                        Imm=IR[25:0];

                    end

                endcase

                next_state = `ID; // 解码

            end

            `ID:begin

                //type

                case(IR[31:26])

                    `OP:begin

                        A=rdata1;

                        B=rdata2;

                        case(IR[5:0])

                        `Add:begin

                            Card=`ADD;

                        end

                        `Sub:begin

                            Card=`SUB;

                        end

                        `And:begin

                            Card=`AND;

                        end

                        `Or:begin

                            Card=`OR;

                        end

                        `Xor:begin

                            Card=`XOR;

                        end

                        `Slt:begin

                            Card=`SLT;

                        end

                        `Movz:begin

                            Card=`MOVZ;

                        end

                        `Sll:begin

                            A=Imm;

                            Card=`SLL;

                        end

                        endcase

                    end

                    `SW,`LW:begin

                        A=rdata1;

                        B=Imm;

                        Card=`ADD;

                    end

                    `BNE:begin

                        A=rdata1;

                        B=rdata2;

                        Card=`SUB;

                    end

                endcase

                next_state = `EX;

            end

            `EX:begin

                //type

                case(IR[31:26])

                    `SW:begin

                        ram_addr=F;

                        ram_wdata=rdata2;

                        ram_wen=1'b1;

                    end

                    `LW:begin

                        ram_addr=F;

                    end

                    `BNE:begin

                        if(!Zero)NPC=NPC+(Imm<<2);

                    end

                    `J:begin

                        NPC={NPC[31:26],Imm<<2};

                    end

                endcase

                next_state = `MEM;

            end

            `MEM:begin

                case(IR[31:26])

                    `OP:begin

                        r_wdata=F;

                        we=1'b1;

                    end

                    `LW:begin

                        r_wdata=ram_rdata;

                        we=1'b1;

                    end

                endcase

                ram_wen=1'b0;

                next_state = `WB;

            end

            `WB:begin

                //type

                PC=NPC;

                we=1'b0;

                next_state = `IF;

            end

        endcase

    end



  // 调试信息

  assign debug_wb_pc = PC;//32'bX;

  assign debug_wb_rf_wen = we;

  assign debug_wb_rf_addr = r_waddr;//32'bX;

  assign debug_wb_rf_wdata =r_wdata;// 32'bX;





endmodule

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值