当前位置: 代码网 > 科技>电脑产品>CPU > Verilog 简易单周期CPU

Verilog 简易单周期CPU

2024年08月01日 CPU 我要评论
单周期CPU的实现,指令存储器和数据存储器的ip核调用,控制器,寄存器堆,ALU。对照之前的ALU增加了比较相等的输出,用于PC的跳转,采用独热编码,相当于13种简易运算。控制器有13条指令,需要可以再加,照着之前格式注释加就行了,对于同RAM相关的指令未测试。采用之前的寄存器堆(短版)代码,没有初始化,不影响使用,需要的话加上就行。就一个clk和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.

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com