紫光同创PGL22G开发平台试用连载(5)基于紫光同创PGL22GFPGA设计一个32位CPU

千年一叹 提交于 周二, 10/20/2020
紫光同创PGL22G开发平台试用连载(5)基于紫光同创PGL22GFPGA设计一个32位CPU

  基于PGL122G FPGA  设计32位CPU,提供的灵活性允许根据需要开启或禁止处理器、IP内核以及软件平台的高级功能,并且可以对许多独立参数进行精细调整,直到在软件一级满足应用的要求。此外,利用建模工具可以识别任何性能关键的软件功能并将其分流至适当的硬件加速器或协处理器来完成。基于 FPGA 的五级流水线 CPU 的总体结构模型,实现了取指IF、指令译码ID、指令执行EXE、存储MEM,取指周期设计了PC寄存器和指令存储器,实现了取指令功能;译码周期设计了控制器CU、寄存器堆等部件,完成了20条指令的译码功能;指令执行周期主要对运算器ALU的设计,实现了对数据的运算操作;存储周期完成了数据存储器的设计,用于存储周期的读写操作;结果写回周期,通过设计多路器,实现将正确的结果写回到目的寄存器中。

32位CPU内核结构:寄存器组(①)、NVIC(②)、中断和异常(③)、储存器映射(④)、总线接口(⑤)、调试支持(⑥)、指令集。

 

   32位CPU结构:

  可配置处理系统的配置(或定制)的层面包括:

  处理器配置:

  •乘法器、除法器、浮点单元以及其它。
  •指令或数据缓冲配置。
  •协处理器或硬件加速器。

  系统配置
  •I/O外设选择、定制、DMA选择。
  •存储器外设选择、定制。

  应用配置

  •RTOS选择、定制。
  •应用库/中间件定制

      

 控制器设计

module CtrlUnit(

        input [31:0] instr,

        input [31:0] rdata1, rdata2,

        input [31:0] pc,ram_data,hi,lo,alu_r,cop_data,mul_out,

        input [31:0] exc_addr,

        input clk,

        output mtc0,eret,teq_exc,

        output reg [2:0] mdu,

        output reg reg_wena,

        output ram_wena,

        

        output reg [3:0] cause,

        output [4:0] rs,rt,rd,waddr,

        output reg [31:0] wdata,reg_data,

        output [31:0] ram_addr,

        output reg [31:0] pc_in,

        

        output reg [31:0] alu_a,alu_b,

        output reg [3:0] alu_op

        );

    

    

    //******MIPS-55*********//

    parameter   //SPECIAL OP LIST   5-0

                ADDU    =   6'b100001,

                SUBU    =   6'b100011,

                ADD     =   6'b100000,

                SUB     =   6'b100010,

                AND     =   6'b100100,

                OR      =   6'b100101,

                XOR     =   6'b100110,

                NOR     =   6'b100111,

                SLT     =   6'b101010,

                SLTU    =   6'b101011,

                SRL     =   6'b000010,

                SRA     =   6'b000011,

                SLL     =   6'b000000,

                SLLV    =   6'b000100,

                SRLV    =   6'b000110,

                SRAV    =   6'b000111,

                JR      =   6'b001000,

                JALR    =   6'b001001,

                MULT    =    6'b011000,

                MULTU   =   6'b011001,

                DIV     =   6'b011010,

                DIVU    =   6'b011011,

                MFHI    =   6'b010000,

                MFLO    =   6'b010010,

                MTHI    =   6'b010001,

                MTLO    =   6'b010011,

                BREAK   =   6'b001101,

                SYSCALL =   6'b001100,

                TEQ     =   6'b110100,

                //SPECIAL 2 func

                CLZ        =   6'b100000,

                MUL        =   6'b000010,

                //REGIMM OP LIST 20-16

                BLTZ    =   5'b00000,

                BGEZ    =   5'b00001,

                //COP0 OP LIST

                ERET    =   6'b011000,  //5-0&&25TH=1

                MFC0    =   5'b00000,   //20-16

                MTC0    =   5'b00100,

                //OPCODE FIELD  31-26

                ADDI    =   6'b001000,

                ADDIU   =   6'b001001,

                ANDI    =   6'b001100,

                ORI     =   6'b001101,

                XORI    =   6'b001110,

                LW      =   6'b100011,

                SW      =   6'b101011,

                BEQ     =   6'b000100,

                BNE     =   6'b000101,

                BLEZ    =   6'b000110,

                BGTZ    =   6'b000111,

                SLTI    =   6'b001010,

                SLTIU   =   6'b001011,

                LUI     =   6'b001111,

                J       =   6'b000010,

                JAL     =   6'b000011,

                LB      =   6'b100000,//    Load Byte Function=6'h24    

                LBU     =   6'b100100,//    1Load Byte Unsigned

                LH      =   6'b100001,//    Load high

                LHU     =   6'b100101,//    Load High Unsigned

                SB      =   6'b101000,//    Send Byte

                SH      =   6'b101001,//    Send High

                

                SPECIAL =   6'b000000,

                SPECIAL2=    6'b011100,

                REGIMM  =   6'b000001,

                COP0    =   6'b010000;  

    //ALU OPCODE                

    parameter   _ADDU   =   4'b0000;    //r=a+b unsigned

    parameter   _ADD    =   4'b0010;    //r=a+b signed

    parameter   _SUBU   =   4'b0001;    //r=a-b unsigned

    parameter   _SUB    =   4'b0011;    //r=a-b signed

    parameter   _AND    =   4'b0100;    //r=a&b

    parameter   _OR     =   4'b0101;    //r=a|b

    parameter   _XOR    =   4'b0110;    //r=a^b

    parameter   _NOR    =   4'b0111;    //r=~(a|b)

    

    parameter   _LUI    =   4'b1000;    //r={b[15:0],16'b0}

    parameter   _SLT    =   4'b1011;    //r=(a-b<0)?1:0 signed

    parameter   _SLTU   =   4'b1010;    //r=(a-b<0)?1:0 unsigned

    parameter   _SRA    =   4'b1100;    //r=b>>>a

    parameter   _SLL    =   4'b1110;    //r=b<<a

    parameter   _SRL    =   4'b1101;    //r=b>>a

    

    parameter    _SYSCALL=   4'b1000,

                _BREAK    =   4'b1001,

                _TEQ    =   4'b1101;

            

    wire [5:0]  op        =  instr[31:26];

    assign         rs        =  instr[25:21];

    assign         rt        =  instr[20:16];

    assign        rd        =  instr[15:11];

    wire [5:0]  func    =  instr[5:0];

    

    wire [4:0]  shamt   =  instr[10:6];

    wire [15:0] imm     =  instr[15:0];

    wire [25:0] addr    =  instr[25:0];

    

    parameter   SIGN    =   1'b1;

    parameter   UNSIGN  =   1'b0;

    wire     imm_sign    =   (op==ANDI||op==ORI||op==XORI)?UNSIGN:SIGN;

    

    wire [31:0] shamt_ext        =   {27'b0,shamt};

    wire [31:0] imm_ext            =   imm_sign?{{(16){imm[15]}},imm}:{16'b0,imm};

    reg  [31:0] load_data,clz_data;

    

    assign    waddr    =    (op==SPECIAL||op==SPECIAL2)?    rd:    (op==JAL)    ?5'b11111:rt;

    

    always@(*)begin

        case(op)

            SB:     reg_data    =   {24'b0,rdata2[7:0]};

            SH:     reg_data    =   {16'b0,rdata2[15:0]};

            SW:     reg_data    =   rdata2;

            default:reg_data    =    rdata2;

        endcase

        

        case(op)

            LB:     load_data   =   {{24{ram_data[7]}},ram_data[7:0]};

            LBU:    load_data   =   {24'b0,ram_data[7:0]};

            LH:     load_data   =   {{16{ram_data[15]}},ram_data[15:0]};

            LHU:    load_data   =   {16'b0,ram_data[15:0]};

            LW:     load_data   =   ram_data;

            default:load_data   =   ram_data;

        endcase

        

        if(op==SPECIAL)

            case(func)

                SYSCALL:cause    =    _SYSCALL;

                BREAK:    cause    =    _BREAK;

                TEQ:    cause    =    _TEQ;

                default:cause    =    5'b0;

            endcase

        else             cause    =    5'b0;

        

        /*

            1    mult

            2    multu

            3    div    

            4    divu

            5    mthi

            6    mtlo

            7    mul

        */

        

        if(op==SPECIAL)

            case(func)

                MULT:    mdu        =    3'h1;

                MULTU:    mdu        =    3'h2;

                DIV:    mdu        =    3'h3;

                DIVU:    mdu        =    3'h4;

                MTHI:    mdu        =    3'h5;

                MTLO:    mdu        =    3'h6;

                default:mdu        =    3'h0;

            endcase

        else             mdu        =    3'h0;

    end

    

    wire [31:0] npc                =   pc+4;

    

    wire [31:0] pc_branch        =   npc    +    {{(14){imm[15]}},imm,2'b00};

    wire [31:0] pc_jmp            =    {npc[31:28],addr,2'b00};

    assign    ram_addr    =   rdata1  +   imm_ext;

    assign    eret        =    op==COP0 && func==ERET;

    wire    mfc0        =    op==COP0 && rs==MFC0;

    assign    mtc0        =    op==COP0 && rs==MTC0;

    assign    teq_exc        =    rdata1==rdata2;

    

    parameter   ENA     =   1'b1;

    parameter   DIS     =   1'b0;

            

    wire mem_load   =   op==LB || op==LH || op==LBU || op==LHU || op==LW;

    assign ram_wena =   op==SW || op==SH || op==SB;

    

    integer i;    

    

    always@(*)begin

        

        case(op)

            SPECIAL: case(func)

                MULTU,

                DIV,

                DIVU,

                JR,

                MTHI,

                MTLO,

                BREAK,

                SYSCALL:reg_wena    =   DIS;

                default:reg_wena    =   ENA;    

            endcase

            COP0:       reg_wena    =   rs==MFC0?ENA:DIS;

            SPECIAL2,

            LB,

            LBU,

            LH,

            LHU,

            ADDI,

            ADDIU,

            ANDI,

            ORI,

            XORI,

            LW,

            SLTI,

            SLTIU,

            LUI,

            JAL:        reg_wena    =   ENA;            

            default:    reg_wena    =   DIS;

        endcase

        

        case(op)

            SPECIAL:case(func)

                JALR:    wdata   =   npc;

                MFHI:   wdata   =   hi;

                MFLO:   wdata   =   lo;

                default:wdata   =   alu_r;

            endcase

            SPECIAL2:begin

                if(func==CLZ) casez(rdata1)

                    32'b1???????????????????????????????:   wdata   =       32'h0;

                    32'b01??????????????????????????????:   wdata   =       32'h1;

                    32'b001?????????????????????????????:   wdata   =       32'h2;

                    32'b0001????????????????????????????:   wdata   =       32'h3;

                    32'b00001???????????????????????????:   wdata   =       32'h4;

                    32'b000001??????????????????????????:   wdata   =       32'h5;

                    32'b0000001?????????????????????????:   wdata   =       32'h6;

                    32'b00000001????????????????????????:   wdata   =       32'h7;

                    32'b000000001???????????????????????:   wdata   =       32'h8;

                    32'b0000000001??????????????????????:   wdata   =       32'h9;

                    32'b00000000001?????????????????????:   wdata   =       32'ha;

                    32'b000000000001????????????????????:   wdata   =       32'hb;

                    32'b0000000000001???????????????????:   wdata   =       32'hc;

                    32'b00000000000001??????????????????:   wdata   =       32'hd;

                    32'b000000000000001?????????????????:   wdata   =       32'he;

                    32'b0000000000000001????????????????:   wdata   =       32'hf;

                    32'b00000000000000001???????????????:   wdata   =       32'h10;

                    32'b000000000000000001??????????????:   wdata   =       32'h11;

                    32'b0000000000000000001?????????????:   wdata   =       32'h12;

                    32'b00000000000000000001????????????:   wdata   =       32'h13;

                    32'b000000000000000000001???????????:   wdata   =       32'h14;

                    32'b0000000000000000000001??????????:   wdata   =       32'h15;

                    32'b00000000000000000000001?????????:   wdata   =       32'h16;

                    32'b000000000000000000000001????????:   wdata   =       32'h17;

                    32'b0000000000000000000000001???????:   wdata   =       32'h18;

                    32'b00000000000000000000000001??????:   wdata   =       32'h19;

                    32'b000000000000000000000000001?????:   wdata   =       32'h1a;

                    32'b0000000000000000000000000001????:   wdata   =       32'h1b;

                    32'b00000000000000000000000000001???:   wdata   =       32'h1c;

                    32'b000000000000000000000000000001??:   wdata   =       32'h1d;

                    32'b0000000000000000000000000000001?:   wdata   =       32'h1e;

                    32'b00000000000000000000000000000001:   wdata   =        32'h1f;

                    32'b00000000000000000000000000000000:    wdata   =       32'h20;

                endcase

                 else if(func==MUL)    wdata    =    mul_out;

                 else                wdata   =   alu_r;

            end

            JAL:                    wdata   =   npc;

            LW,LB,LH,LBU,LHU:        wdata   =   load_data;

            COP0:    if(rs==MFC0)    wdata   =   cop_data;

                    else            wdata   =   alu_r;

            default:                wdata   =   alu_r;

        endcase

        //Below is OK

        

        case(op)

            SPECIAL: case(func)

                SLL,

                SRL,

                SRA:begin

                    alu_a   =   shamt_ext;

                    alu_b   =   rdata2;

                end

                default:begin

                    alu_a   =   rdata1;

                    alu_b   =   rdata2;

                end

            endcase

            ADDI,

            ADDIU,

            ANDI,

            ORI,

            XORI,

            SLTI,

            SLTIU,

            LUI:begin

                    alu_a   =   rdata1;

                    alu_b   =   imm_ext;

            end

            default:begin

                    alu_a   =   rdata1;

                    alu_b   =   rdata2;

            end

        endcase

        

        //PC Source     

        case(op)

            SPECIAL: case(func)

                SYSCALL,

                TEQ,

                BREAK:  pc_in  =   exc_addr;

                JALR,

                JR:     pc_in  =   rdata1;   

                default:pc_in  =   npc;

            endcase

            COP0: case(func)

                ERET:   pc_in  =   exc_addr;

                default:pc_in  =   npc;

            endcase

            REGIMM: case(rt)

                BLTZ:if(rdata1[31])

                        pc_in  =   pc_branch;

                    else

                        pc_in  =   npc;

                BGEZ:if(!rdata1[31])

                        pc_in  =   pc_branch;

                    else

                        pc_in  =   npc;

                default:pc_in  =   npc;

            endcase

            J,

            JAL:        pc_in  =   pc_jmp;

            BEQ:if(rdata1==rdata2)

                        pc_in  =   pc_branch;

                else    pc_in  =   npc;

            BNE:if(rdata1!=rdata2)

                        pc_in  =   pc_branch;

                else    pc_in  =   npc;

            BLEZ:if(rdata1[31] || rdata1==32'b0)

                        pc_in  =   pc_branch;

                else    pc_in  =   npc;

            BGTZ:if(!rdata1[31] && rdata1!=32'b0)

                        pc_in  =   pc_branch;

                else    pc_in  =   npc;

            default:    pc_in  =   npc;

        endcase

            

        case(op)

            SPECIAL:case(func)

                ADDU:       alu_op  =   _ADDU;

                SUBU:       alu_op  =   _SUBU;

                ADD:        alu_op  =   _ADD;

                SUB:        alu_op  =   _SUB;

                AND:        alu_op  =   _AND;

                OR:         alu_op  =   _OR;

                XOR:        alu_op  =   _XOR;

                NOR:        alu_op  =   _NOR;

                SLT:        alu_op  =   _SLT;

                SRL:        alu_op  =   _SRL;

                SLL:        alu_op  =   _SLL;

                SRA:        alu_op  =   _SRA;

                SLTU:       alu_op  =   _SLTU;

                SRLV:       alu_op  =   _SRL;

                SLLV:       alu_op  =   _SLL;

                SRAV:       alu_op  =   _SRA;

                default:    alu_op  =   _ADDU;

            endcase

            ORI:            alu_op  =   _OR;

            XORI:           alu_op  =   _XOR;

            BEQ:            alu_op  =   _SUBU;

            BNE:            alu_op  =   _SUBU;

            ANDI:           alu_op  =   _AND;

            ADDIU:          alu_op  =   _ADDU;

            ADDI:           alu_op  =   _ADD;

            SLTI:           alu_op  =   _SLT;

            SLTIU:          alu_op  =   _SLTU;

            LUI:            alu_op  =   _LUI;

            default:        alu_op  =   _ADDU;

        endcase

        

    end

endmodule

PC寄存器设计

    input clk,

    input rst,

    input ena,

    input [31:0] data_in,

    output [31:0] data_out

    );

    

    reg [31:0] data=32'b0;

 

    always @(posedge clk or posedge rst) begin

        if(rst) data<=32'h00400000;        //reset key

        else begin

            if(ena) data<=data_in;        //enable ,input

        end

    end

    

    assign data_out    =   data;

    

Endmodule

 

Regfiles设计

module RegFiles(

        input clk,

        input rst,

        input we,

        input [4:0] raddr1,

        input [4:0] raddr2,

        input [4:0] waddr,

        input [31:0] wdata,

        output [31:0] rdata1,

        output [31:0] rdata2

        );

    

    reg [31:0] data [0:31];

    

    always@(posedge clk or posedge rst) begin

        if(rst)  for(i=0;i<32;i=i+1) begin

            data[i]<=32'b0;

        end

        else begin

            if(we&&waddr!=5'b0) data[waddr]<=wdata;

        end

    end

    

Endmodule

 

ALU设计

module alu(

        input [31:0] a,        //OP1

        input [31:0] b,        //OP2

        input [3:0] aluc,    //controller

        output [31:0] r,    //result

        output zero,

        output carry,

        output negative,

        output overflow);

        

    parameter Addu    =    4'b0000;    //r=a+b unsigned

    parameter Add    =    4'b0010;    //r=a+b signed

    parameter Subu    =    4'b0001;    //r=a-b unsigned

    parameter Sub    =    4'b0011;    //r=a-b signed

    parameter And    =    4'b0100;    //r=a&b

    parameter Or    =    4'b0101;    //r=a|b

    parameter Xor    =    4'b0110;    //r=a^b

    parameter Nor    =    4'b0111;    //r=~(a|b)

    parameter Lui1    =    4'b1000;    //r={b[15:0],16'b0}

    parameter Lui2    =    4'b1001;    //r={b[15:0],16'b0}

    parameter Slt    =    4'b1011;    //r=(a-b<0)?1:0 signed

    parameter Sltu    =    4'b1010;    //r=(a-b<0)?1:0 unsigned

    parameter Sra    =    4'b1100;    //r=b>>>a

    parameter Sll    =    4'b1110;    //r=b<<a

    parameter Srl    =    4'b1101;    //r=b>>a

    

    parameter bits=31;

    parameter ENABLE=1,DISABLE=0;

    

    reg [32:0] result;

    wire signed [31:0] sa=a,sb=b;

    

    always@(*)begin

        case(aluc)

            Addu: begin

                result=a+b;

            end

            Subu: begin

                result=a-b;

            end

            Add: begin

                result=sa+sb;

            end

            Sub: begin

                result=sa-sb;

            end

            Sra: begin

                if(a==0) {result[31:0],result[32]}={b,1'b0};

                else {result[31:0],result[32]}=sb>>>(a-1);

            end

            Srl: begin

                if(a==0) {result[31:0],result[32]}={b,1'b0};

                else {result[31:0],result[32]}=b>>(a-1);

            end

            Sll: begin

                result=b<<a;

            end

            And: begin

                result=a&b;

            end

            Or: begin

                result=a|b;

            end

            Xor: begin

                result=a^b;

            end

            Nor: begin

                result=~(a|b);

            end

            Sltu: begin

                result=a<b?1:0;

            end

            Slt: begin

                result=sa<sb?1:0;

            end

            Lui1,Lui2: result = {b[15:0], 16'b0};

            default:

                result=a+b;

        endcase

    end

    

    assign r=result[31:0];

    assign carry = result[32];

    assign zero=(r==32'b0)?1:0;

    assign negative=result[31];

    assign overflow=result[32];

Endmodule

 

RAM设计

module ram(

        input clk,

        input wena,

        input [8:0] addr,

        input [31:0] data_in,

        output [31:0] data_out

        );

    

    reg [31:0] state [0:512];

    always@(posedge clk) begin

        if(wena) begin

            if(addr!=0) state[addr]<=data_in;

        end

    end 

 

    assign data_out=state[addr];endmodule

 Pango Design Suite 仿真

仿真

 

相关文章

Digi-Key