【计算机组成原理】单周期CPU设计与实现-单指令 CPU

(Verilog)单周期CPU设计

单周期CPU设计与实现原理分析

设计和实现一个支持加法指令的单周期 CPU。要求该加法指令(表示为 add r1,r2,
r3)格式约定如下:
采用寄存器寻址,r1,r2,r3 为寄存器编号,r1 和 r2 存放两个源操作数,r3
为目标寄存器,其功能为[r1] + [r2] -> r3;
指令字长 16 位,操作码和地址码字段分配如下所示:

OpCoder1r2r3

PC模块

module PC(clk,rst,y);
input clk,rst;
output y;
reg[7:0] y;
initial y = 0;
always@(posedge clk or negedge rst)begin
    if(!rst)
        y = 0;
    else
        y = y + 1;
end
endmodule

InsMemory

module InsMemory(Addr,Ins);
input[7:0] Addr;
output Ins;
reg[15:0] Ins;

reg [15:0]unit[8'd255:0];//25616位存储单元
integer i,j;
initial begin
    for(i=0;i<256;i=i+1)begin
        j = i % 5;
        unit[i][2:0] = j+2;
        unit[i][5:3] = j+1;
        unit[i][8:6] = j;
        unit[i][15:9] = i%3;
    end
end
always@(*)begin
     Ins = unit[Addr];
 end 
endmodule

RegFile

module RegFile(
    clk,    //  时钟信号
    RegRW,  //读写信号,为1时写入(上升沿有效),为0时,读数据,
    read_reg1,//要读出数据1的地址
    read_reg2,//要读出数据2的地址
    write_reg,//要写入数据的地址
    write_data,//要写入的数据
    reg1,//要读出的数据1
    reg2//要读出的数据2
    );
    input clk,RegRW;
    input[2:0] read_reg1,read_reg2,write_reg;
    input[15:0] write_data;
    output[15:0] reg1,reg2;
    
    integer i;
    reg[15:0] regfile[7:0];//816位的寄存器
    initial begin
        for(i=0;i<8;i=i+1)
            regfile[i] = 2*i+1;
    end
    always@(posedge clk)begin
        if(RegRW == 1)
            regfile[write_reg] = write_data;
    end
    
    assign reg1 = regfile[read_reg1];
    assign reg2 = regfile[read_reg2];
endmodule

DataMemory

module DataMemory(
    DataRW,//读写信号,当为1时,写入;0时,读出
    DAddr, //读或写的地址
    DataIn,//要写入的数据
    DataOut,//要读出的数据

    );
    input DataRW;
    input[5:0] DAddr;
    input[15:0] DataIn;
    output reg[15:0] DataOut;
   
    reg [15:0] memory[6'd63:0];//6416位存储单元
    integer i;
    initial begin
        for(i=0;i<64;i=i+1)
            memory[i] = i*i;
    end
    always@(*)begin
        if(DataRW)
            memory[DAddr] = DataIn;
         else
            DataOut = memory[DAddr];
    end

endmodule

ALU

module ALU(
    alu_op, //ALU操作控制
    A,      //操作数A
    B,      //操作数B
    result  //运算结果
    );
    input[2:0] alu_op;
    input[15:0] A,B;
    output reg[15:0]result;
    
    always@(*)begin
        case(alu_op)
            3'b000 : result = A+B;
            3'b001 : result = A-B;
            3'b010 : result = A * B;
            3'b011 : result = A / B;
            3'b100 : result = A & B;
            3'b101 : result = A | B;
            3'b110 : result = A ^ B;
            3'b111 : result = A << B;
            default:result = 0;
        endcase
    end
endmodule

ControlUnit

module ControlUnit(
    input[5:0] op, //op操作符
    output reg RegOut,//二路选择器,为1时,输出r1,否则输出r3
    output reg M2Reg,//二路选择器,为1时,输出Mem[addr],否则输出[r1]+[r2]
    output reg RegRW,//寄存器堆读写信号,为1时写入,为0时,读出
    output reg DataMemRW,//数据存储器读写信号,为1时写入,为0时,读出
    output reg[2:0] alu_op//ALU的操作控制信号
    );
    initial begin 
        RegOut = 0;
        M2Reg = 0;
        RegRW = 0;
        DataMemRW = 0;
        alu_op = 0;
    end
    always@(*)begin
        case(op)
            //LDA   取数
            6'b000000:begin
                RegOut = 1;
                M2Reg  = 1;
                RegRW  = 1;
                DataMemRW = 0;
                alu_op = 0;
            end
            
            //ADD   加法
            6'b000001:begin
                RegOut = 0;
                M2Reg  = 0;
                RegRW  = 1;
                DataMemRW = 0;
                alu_op = 0;
            end
            
            //STA   存数
            6'b000010:begin
                RegOut = 0;
                M2Reg  = 0;
                RegRW  = 0;
                DataMemRW = 1;
                alu_op = 0;
            end
            
            
        endcase
    end
endmodule

二路选择器

由于不受时钟信号控制,始终会将r1,r2寄存器中的数据作为ALU的操作数输入,将r1寄存器的数据作为DataMemory的要写入的数据,将DataMemory中地址为addr中的数据读出。当要将数据写入寄存器堆时,要有个3线二路选择器,决定是将从数据存储器中读出的数据写入r1,还是将[r1]+[r2]的结果送入r3。由于要写入的数据有可能是从数据寄存器中读出的数据,也有可能是[r1]+[r2]的结果,所以要有个16线二路选择器决定要写入的数据

module Multiplexer3(
    control,//选择信号,当为1时,输出in1,当为0时,输出in0
    in1,
    in0,
    out
    );
    input control;
    input[2:0] in1,in0;
    output[2:0]out;
    assign out = control == 1 ? in1 : in0;
endmodule
module Multiplexer16(
    control, //选择信号,当为1时,输出in1,当为0时,输出in0
    in1,
    in0,
    out
    );
    input control;
    input[15:0] in1,in0;
    output[15:0] out;
    
    assign out = control ? in1:in0;
endmodule

顶层模块

module SignleCPU(
    input clk,
    input rst,
    output[5:0]op,
    output[2:0] r1,
    output[2:0] r2,
    output[2:0] r3,
    output[5:0]addr,
    output[15:0]ReadData1,
    output[15:0]ReadData2,
    output[15:0]WriteData
    );
    wire[15:0] Ins,DataOut,result;
    wire[7:0]InsAddress;
    wire[2:0] WriteReg,alu_op;
    wire RegOut,M2Reg,RegRW,DataMemRW;
    
    PC pc(clk,rst,InsAddress);
    
    InsMemory insmemory(InsAddress,Ins);
    assign op = Ins[15:9];
    assign r1 = Ins[8:6];
    assign r2 = Ins[5:3];
    assign r3 = Ins[2:0];
    assign addr = Ins[5:0];
    
    RegFile regfile(clk,RegRW,r1,r2,WriteReg,WriteData,ReadData1,ReadData2);
    
    ControlUnit cu(op,RegOut,M2Reg,RegRW,DataMemRW,alu_op);
    
    DataMemory datamem(DataMemRW,addr,ReadData1,DataOut);
    
    ALU alu(alu_op,ReadData1,ReadData2,result);
    
    Multiplexer3 mul3(RegOut,r1,r3,WriteReg);
    Multiplexer16 mul16(M2Reg,DataOut,result,WriteData);
endmodule

Test模块

module Test();
    reg clk,rst;
    wire[2:0] r1,r2,r3;
    wire[5:0]addr;
    wire[15:0] ReadData1,ReadData2,WriteData;
    wire[5:0] op;
    SignleCPU f(clk,rst,op,r1,r2,r3,addr,ReadData1,ReadData2,WriteData);
    initial begin
        clk = 0;rst = 1;
        #40 $stop;
    end
    always #5 clk = ~clk;
endmodule

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码
Github
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 16
    点赞
  • 119
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值