Verilog 简易单周期CPU

目录

 本实验包含:

 简易结构图:

各部件代码或实现:

控制器:

寄存器堆:

ALU:

数据存储器:

指令存储器:

CPU:

tp(仿真文件):

 仿真结果:

 单周期CPU压缩包下载


 本实验包含:

        指令存储器和数据存储器的ip核调用,控制器,寄存器堆,ALU,单周期CPU的实现。

 简易结构图:

各部件代码或实现:

控制器:

控制器有13条指令,需要可以再加,照着之前格式注释加就行了,对于同RAM相关的指令未测试

R:
 指令  [31:26]   [25:21]   [20:16]  [15:11] [10:6]  [5:0] 功能
add000000rsrtrd000000100000寄存器加
sub000000rsrtrd000000100010寄存器减
and000000rsrtrd000000100100寄存器与
or000000rsrtrd000000100101寄存器或
nor000000rsrtrd000000100111寄存器或非
sll000000rs000000rdsa000000逻辑左移
srl000000rs000000rdsa000010 逻辑右移
sra000000rs000000rdsa100111算术右移
I:
指令 [31:26] [25:21] [20:16] [15:0] 功能
addi001000rsrtimmediate立即数加
lw100011rsrtimmediate取字数据
sw101011rsrtimmediate存字数据
beq000100rsrtimmediate相等转移
J:
指令[31:26][25:21][20:16][15;0]功能
j0000100000000000immediate转移

输入:op,func
输出:MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst

//
//创建日期:2022/12/19 10:46:36
//设计名称:控制器
//课程名称:Controler
//说明: 
//输入:op,func
//输出:MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst
//依赖项:
//      
//版次:
//版本0.01-文件已创建
//其他注释:
//
//
module Controler(op,func,MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst);
    input [5:0] op;
    input [5:0] func;
    output MemtoReg;
    output MemWrite;
    output Branch;
    output [11:0] ALUOP;
    output ALUSrc;
    output RegWrite;
    output RegDst;
    reg MemtoReg,MemWrite,Branch,ALUSrc,RegWrite,RegDst;
    reg [11:0] ALUOP;
    //    R:
    //    指令	[31:26]	[25:21]	[20:16]	[15:11]	[10:6]	[5:0]	功能
    //    add	000000	   rs	 rt	       rd	000000	100000	寄存器加
    //    sub	000000	   rs	 rt	       rd	000000	100010	寄存器减
    //    and	000000	   rs	 rt	       rd	000000	100100	寄存器与
    //    or	000000	   rs	 rt	       rd	000000	100101	寄存器或
    //    nor	000000	   rs	 rt	       rd	000000	100111	寄存器或非
    //    sll	000000	   rs  000000	   rd	  sa	000000	逻辑左移
    //    srl	000000	   rs  000000	   rd	  sa	000010	逻辑右移
    //    sra	000000	   rs  000000	   rd	  sa	000011	算术右移
    //I:
    //    指令	[31:26]	[25:21]	[20:16]	[15:0]	功能
    //    addi	001000	  rs	rt    immediate	立即数加
    //    lw	100011	  rs	rt	  immediate	取字数据
    //    sw	101011	  rs	rt	  immediate	存字数据
    //    beq	000100	  rs	rt	  immediate	相等转移
    //J:
    //    指令	[31:26] [25:21] [20:16]  [15:0]     功能
    //    j 	000010	00000	00000	 immediate	转移

    always @(*)
    begin
        case(op)
            6'b000000://寄存器操作
            begin
                MemtoReg=0;//输出ALU的输出
                MemWrite=0;//数据存储器不写入
                Branch=0;//正常PC
                ALUSrc=0;//ALU输入2选择寄存器输出
                RegWrite=1;//寄存器写入
                RegDst=1;//有rd
                case(func)  //控制ALU操作
                    6'b100000:// 寄存器加
                        ALUOP=12'b010000000000;
                    6'b100010:// 寄存器减
                        ALUOP=12'b100000000000;
                    6'b100100:// 寄存器与
                        ALUOP=12'b000010000000;
                    6'b100101:// 寄存器或
                        ALUOP=12'b000000100000;
                    6'b100111:// 寄存器或非
                        ALUOP=12'b000001000000;
                    6'b100100:// 逻辑左移
                        ALUOP=12'b000000001000;
                    6'b100101:// 逻辑右移
                        ALUOP=12'b000000000100;
                    6'b100111:// 算术右移
                        ALUOP=12'b000000000010;
                    default:ALUOP=12'b010000000000;
                endcase
            end
            6'b001000:// 立即数加
            begin
                MemtoReg=0;//输出ALU结果
                MemWrite=0;//数据存储器不写入
                Branch=0;//正常PC
                ALUOP=12'b010000000000;//ALU加操作
                ALUSrc=1;//数据2选择立即数输出
                RegWrite=1;//寄存器写入
                RegDst=0;//无rd选择rt
            end
            6'b100011:// 取字数据
            begin
                MemtoReg=1;//输出数据存储器结果
                MemWrite=0;//数据存储器不写入
                Branch=0;//正常PC
                ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
                ALUSrc=1;//数据2随意
                RegWrite=1;//寄存器写入
                RegDst=0;//无rd选择rt
            end
            6'b101011:// 存字数据
            begin
                MemtoReg=1;//输出随意
                MemWrite=1;//数据存储器写入
                Branch=0;//正常PC
                ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
                ALUSrc=1;//数据2随意
                RegWrite=0;//寄存器不写入
                RegDst=0;//不写入随意
            end
            6'b000100:// 相等转移
            begin
                MemtoReg=1;//输出随意
                MemWrite=0;//数据存储器不写入
                Branch=1;//PC可能改变
                ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
                ALUSrc=0;//ALU输入2选择寄存器输出
                RegWrite=0;//寄存器不写入
                RegDst=0;//不写入随意
            end
            6'b000010://跳转
            begin
                MemtoReg=1;//输出随意
                MemWrite=0;//数据存储器不写入
                Branch=1;//PC可能改变
                ALUOP=12'b000000000000;//ALU无操作,输出第一个输入
                ALUSrc=0;//数据2选择寄存器输出
                RegWrite=0;//寄存器不写入
                RegDst=0;//不写入随意
            end
            default:
            begin
                MemtoReg=0;
                MemWrite=0;
                Branch=0;
                ALUOP = 12'b000000000000;//ALU无操作,输出第一个输入
                ALUSrc=0;
                RegWrite=1;
                RegDst=1;
            end
        endcase
    end
endmodule

寄存器堆:

采用之前的寄存器堆(短版)代码,没有初始化,不影响使用,需要的话加上就行

//
//
//创建日期:2022/10/16 21:37:00
//设计名称:寄存器堆
//课程名称:regfile
//说明:
// 实现 32 个寄存器, 其中 0 号寄存器读出的值恒为 0,
// 寄存器堆为异步读同步写, 
// 共有 1 个写端口和 2 个读端口
//依赖项:
//      
//版次:
//版本0.01-文件已创建
//其他注释:
//
 
module regfile(
input clk,  // 时钟
input wen,  // 写使能
input [4 :0] raddr1,    // 读地址1
input [4 :0] raddr2,    // 读地址2
input [4 :0] waddr,     // 写地址
input [31:0] wdata,     // 写数据
output reg [31:0] rdata1,   // 读到的数据1
output reg [31:0] rdata2,   // 读到的数据2
input [4 :0] test_addr,     // 测试读端口
output reg [31:0] test_data // 测试输出
); 
reg [31:0] rf[31:0];  // 定义32个32位的寄存器
always @(posedge clk) // 时钟上升沿
begin
    if (wen)    // 如果写使能wen为1则写入寄存器
        begin
           rf[waddr] <= wdata;
        end
end
 
//读端口 1
always @(*)
begin
    if (raddr1==5'd0)
        rdata1 <= 32'd0;
    else
        rdata1 <= rf[raddr1];
end
//读端口 2
always @(*)
begin
    if (raddr2==5'd0)
        rdata2 <= 32'd0;
    else
        rdata2 <= rf[raddr2];
end
//测试读端口
always @(*)
begin
    if (test_addr==5'd0)
        test_data <= 32'd0;
    else
        test_data <= rf[test_addr];
end
endmodule

ALU:

对照之前的ALU增加了比较相等的输出,用于PC的跳转,采用独热编码,相当于13种简易运算。

//
//创建日期:2022/11/6 20:06:00
//设计名称:ALU算术逻辑单元
//课程名称:alu
//说明: 
//输入:   [11:0] alu_control;  // ALU控制信号
//        [31:0] alu_src1;     // ALU操作数1
//        [31:0] alu_src2;     // ALU操作数2
//输出:   [31:0] alu_result;   // ALU结果
//          Equal  两个输入是否相等
//依赖项:
//      
//版次:
//版本0.01-文件已创建
//其他注释:
//
//
module alu(alu_control,alu_src1,alu_src2,alu_result,Equal);
    input  [11:0] alu_control;  // ALU控制信号
    input  [31:0] alu_src1;     // ALU操作数1
    input  [31:0] alu_src2;     // ALU操作数2
    output [31:0] alu_result;   // ALU结果
    output Equal;   //相等
    wire Equal;
    reg [31:0] alu_result;
    // 控制信号为独热编码
    assign Equal = alu_src1==alu_src2;
    always @(*)
    begin
        case(alu_control)   // 下面的1,2指操作数1,操作数2
            12'b000000000001:alu_result<=alu_src1<<16;         // 高位加载       1
            12'b000000000010:alu_result<=alu_src1>>>alu_src2;         // 算术右移       2
            12'b000000000100:alu_result<=alu_src1>>alu_src2; // 逻辑右移      4
            12'b000000001000:alu_result<=alu_src1<<alu_src2; // 逻辑左移      8
            12'b000000010000:alu_result<=alu_src1^alu_src2; // 按位异或    16
            12'b000000100000:alu_result<=alu_src1|alu_src2;// 按位或    32
            12'b000001000000:alu_result<=~(alu_src1|alu_src2); // 按位或非       64
            12'b000010000000:alu_result<=alu_src1&alu_src2; // 按位与       128
            12'b000100000000:alu_result<=alu_src1<alu_src2?32'd1:32'd0;// 无符号比较,小于置位  256
            12'b001000000000:alu_result<=$signed(alu_src1)<$signed(alu_src2)?32'd1:32'd0;// 有符号比较,小于置位  512
            12'b010000000000:alu_result<=alu_src1+alu_src2;// 1加     1024
            12'b100000000000:alu_result<=alu_src1-alu_src2;// 1减     2048
            default: alu_result<=alu_src1;
        endcase
    end
endmodule

数据存储器:

采用IP核实现:

没有测试,功能或许有问题

         

 

指令存储器:

采用IP核实现:

 

 

 

 第四张图的ROM.coe数据如下:

memory_initialization_radix=2;
memory_initialization_vector=
00100000000000010000000000001000
00100000000000100000000000000010
00100000000000110000000000000000
00000000010000110001100000100000
00010000001000110000000000000111
00001000000000000000000000000011

这是一段测试用的指令段,具体功能在tp文件种有注释

这个文件什么名字和位置都可以,后缀是.coe就行。

CPU:

//
//创建日期:2022/12/19 16:32:56
//设计名称:CPU
//课程名称:CPU
//说明: 
//调用各个部件,进行运算
//依赖项:
//      控制器,寄存器,ALU
//版次:
//版本0.01-文件已创建
//其他注释:

module CPU(clk);
    input clk;
    // PC
    reg [7:0] PC=8'd0;//PC从第0条指令开始
    wire[31:0] SignImm;//指令后16位扩展结果
    wire PCSrc;//是否跳转
    always@(posedge clk)//上升沿
    begin
        if (PCSrc == 0)
            PC = PC+1;
        else
            PC = SignImm[7:0];
	end
    // 指令存储器
    wire [31:0] instructions;//指令存储器输出
    ROM_D IROM(
        .a(PC),//地址
        .spo(instructions));//指令输出
    wire[5:0] op,func;//控制器输入
    wire[4:0] rs,rt,rd;//三个寄存器地址
    assign op = instructions[31:26];
    assign func = instructions[5:0];
    assign rs = instructions[25:21];
    assign rt = instructions[20:16];
    assign rd = instructions[15:11];
    assign SignImm = {{(16){instructions[15]}},instructions[15:0]};
    // 控制器
    wire MemtoReg,MemWrite,Branch,ALUSrc,RegWrite,RegDst;//控制器输出控制信号
    wire[11:0] ALUOP;//ALU所做的操作
    Controler Contr(op,func,MemtoReg,MemWrite,Branch,ALUOP,ALUSrc,RegWrite,RegDst);
    // 寄存器堆
    wire[31:0] R1,R2,WriteBackData;//寄存器输出和数据输入
    wire[4:0] reg_w;//寄存器写地址
    assign reg_w = RegDst?rd:rt;
    regfile regfile_(clk,RegWrite,rs,rt,reg_w,WriteBackData,R1,R2);
    // ALU
    wire[31:0] srcB,ALUResult;//ALU第二个数据输入和数据输出
    wire Equal;//输入是否相等
    assign srcB = ALUSrc?SignImm:R2;
    alu ALU(ALUOP,R1,srcB,ALUResult,Equal);
    assign PCSrc = Branch&Equal;
    // 数据存储器
    wire [31:0] ReadData;//数据存储器输出
    data_RAM DRM(
        .clka  (clk          ),
        .wea   (MemWrite      ),
        .addra (ALUResult[7:0]),
        .dina  (R2            ),
        .douta (ReadData      ));
    assign WriteBackData = MemWrite?ReadData:ALUResult;
endmodule

tp(仿真文件):

就一个clk和CPU的调用,所用指令段的注释。

`timescale 1ns / 1ps

//001000 00000 00001 0000000000001000       第0个寄存器和8相加存入第1个寄存器
//001000 00000 00010 0000000000000010       第0个寄存器和2相加存入第2个寄存器
//001000 00000 00011 0000000000000000       第0个寄存器和0相加存入第3个寄存器
//000000 00010 00011 00011 00000 100000     第3个寄存器和第2个寄存器相加,结果存入第3个寄存器
//000100 00001 00011 0000000000000111       第1个寄存器和第3个相等转移到7
//000010 00000 00000 0000000000000011       转移到3
//相当于以下程序:
// reg[1] = 8
// reg[2] = 2
// reg[3] = 0
//M: reg[3] = reg[3]+reg[2]
// if reg[1] == reg[3]: goto N
// goto M
//N:
module tp;
    reg clk=0;
    CPU cpu_(clk);
    always #10 clk = ~clk;
endmodule

 仿真结果:

 

 

 

 

 单周期CPU压缩包下载

开了动态调分,初始积分是0.

  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值