CPU部件实现之ALU、寄存器堆、PC、RAM

系统硬件综合设计-多周期CPU的设计与实现

计算机组成原理 实验五 单周期CPU设计与实现——十条指令CPU

ALU和寄存器堆

一、实验目的:

理解和掌握CPU中的算术逻辑运算部件(ALU)和寄存器堆(Register File)的工作原理,并使用Verilog和ModelSim进行设计和仿真。

二、实验内容:

  1. 使用Verilog完成ALU的设计,并编写测试仿真文件验证其正确性。要求:
     ALU支持16位的加、减、与、或以及移位运算。
  2. 使用Verilog完成通用寄存器堆的设计,并编写测试仿真文件验证其正确性。要求:
    寄存器堆包含8个16位的寄存器;
    寄存器堆有两个读端口和一个写端口。

三、 源代码

MyALU.v

module ALU(
    input wire [15:0] A_1, //操作数1
    input wire [15:0] A_2,  //操作数2
    input wire [3:0] OP,  //操作码
    output [15:0] result,//  结果
    //status[0:3] //0: zero, 1: carry, 2: negative, 3: overflow
    //output reg [3:0] status
    output zero,
    output carry,
    output negative,
    output overflow
);

    wire signed [15:0] tmpX = A_1, tmpY = A_2;
    reg [16:0] res_T = 17'b0;//??????????16??17???????
    always@* begin
        case(OP)
            3'b000: 
                res_T = A_1 + A_2;
            3'b001:
                res_T = A_1 -A_2;
            3'b010:
                res_T = A_1 & A_2;
            3'b011:
                res_T = A_1 | A_2;
            3'b100:
                res_T = A_1 >> A_2;
            3'b101:
                res_T = A_1 << A_2;
            default:
                res_T = 16'b1111111111111111; 
        endcase
    end
    assign ans = res_T[15:0];
    assign zero = res_T == 16'b0 ? 0 : 1; //判断是否等于0
    assign negative = res_T[15];            //判断是否为负数
    assign overflow = res_T[16];             //判断是否溢出
    
endmodule

MyALU_tb.v

module MyALU_tb();
    reg [15:0] inData_1, inData_2;
    reg [3:0]  OP [0:7];
    wire [15:0] result;
    wire zero, carry, negative, overflow;
    
    initial begin
        inData_1 = 16'b0101010101010101;//21845
        inData_2 = 16'b1010101010101010;//43690
		    
        #10  OP[0] = 3'b000;
        #10  OP[1] = 3'b001;
        #10  OP[2] = 3'b010;
        #10  OP[3] = 3'b011;
        #10  OP[4] = 3'b100;
        #10  OP[5] = 3'b101;
        
		    #100 $stop;
    end
	
    
    ALU test1(
        .A_1(inData_1), .A_2(inData_2),
        .OP( OP[0]),
        .result(result),
        .zero(zero),
        .carry(carry),
        .negative(negative),
        .overflow(overflow)
    );
	
	ALU test2(
        .A_1(inData_1), .A_2(inData_2),
        .OP( OP[1]),
        .result(result),
        .zero(zero),
        .carry(carry),
        .negative(negative),
        .overflow(overflow)
    );
	
	ALU test3(
        .A_1(inData_1), .A_2(inData_2),
        .OP( OP[2]),
        .result(result),
        .zero(zero),
        .carry(carry),
        .negative(negative),
        .overflow(overflow)
    );
	
	ALU test4(
        .A_1(inData_1), .A_2(inData_2),
        .OP( OP[3]),
        .result(result),
        .zero(zero),
        .carry(carry),
        .negative(negative),
        .overflow(overflow)
    );
	
	ALU test5(
        .A_1(inData_1), .A_2(inData_2),
        .OP( OP[4]),
        .result(result),
        .zero(zero),
        .carry(carry),
        .negative(negative),
        .overflow(overflow)
    );
	
	ALU test6(
        .A_1(inData_1), .A_2(inData_2),
        .OP( OP[5]),
        .result(result),
        .zero(zero),
        .carry(carry),
        .negative(negative),
        .overflow(overflow)
    );
	
endmodule

在这里插入图片描述
registerBank.v

module registerBank(
    input [2:0] addrA,addrB,inAddr,
    output wire[15:0] outA,outB,
    input wire[15:0] inData,
    input clk,WE
);

    reg[15:0] regs[0:7];
  
    assign outA = regs[addrA];
    assign outB = regs[addrB];
  
    always@(negedge clk)begin
        if( WE == 1 )
            regs[inAddr] = inData;
    end
endmodule

registerBank_tb.v

module registerBank_tb();
  parameter CYCLE = 2;
  
	reg [2:0] addrA, addrB, inAddr;
	wire [15:0] outA, outB;
	reg [15:0] inData;
	reg clk, WE;
 
	initial begin
    clk = 1'b0;
    //WE = 1'b0;
  end
  
  always #(CYCLE/2) clk = ~ clk;
  always #(CYCLE/2) WE = ~ WE;
  
	initial begin
    
    //assign WE = 1'b0;
    assign WE = 1'b1;
    assign inData = 16'h35A1;
    assign inAddr = 3'b010;
    assign addrA = 3'b010;
    assign addrB = 3'b100;
    
    #(CYCLE*1) 
    assign WE = 1'b1;
    assign inData = 16'h1234;
    assign inAddr = 3'b001;
    assign addrA = 3'b000;
    assign addrB = 3'b001;
    
    #(CYCLE*2)
    assign WE = 1'b0;
    assign inData = 16'h65df;
    assign inAddr = 3'b101;
    assign addrA = 3'b101;
    assign addrB = 3'b010;
    
    #(CYCLE*3)
    assign WE = 1'b1;
    assign inData = 16'h12ce;
    assign inAddr = 3'b100;
    assign addrA = 3'b100;
    assign addrB = 3'b011;
    
    #(CYCLE*2)
    assign WE = 1'b1;
    assign inData = 16'hefd3;
    assign inAddr = 3'b110;
    assign addrA = 3'b011;
    assign addrB = 3'b110;
    
    #(CYCLE*5)
    $stop;
	end
  
  registerBank reg_file(
	.clk(clk), .WE(WE),
    .addrA(addrA), .addrB(addrB), .inData(inData),
    .inAddr(inAddr),
    .outA(outA), .outB(outB)
  );
endmodule

在这里插入图片描述

PC和半导体存储器RAM

一、实验目的:

理解和掌握CPU中程序计数器PC和半导体存储器RAM的工作原理,并使用Verilog和ModelSim进行设计和仿真。

二、实验内容:

  1. 使用Verilog完成程序计数器PC的设计,要求:
     PC为8位计数器
  2. 使用Verilog完成数据存储器的设计,并编写测试仿真文件验证其正确性。要求:
     存储字长16位,存储容量1K字节;
     一根读写控制信号线控制读写,低电平有效。

三、源代码

PC.v

module MyPC(
    input clk, 
    input rst,
    output [7:0] PC
);
    reg [7:0] pc_T = 8'b0;
    
    always @(posedge clk or posedge rst) begin
        if(rst)
            pc_T = 8'b0;//8'b01011010;
        else
            pc_T = pc_T + 1'b1;
    end
    assign PC = pc_T;
endmodule

PC_tb.v

module MyPC_tb();
    reg clk;
    reg rst = 1'b0;
    wire [7:0] initAddr = 8'b10000000;
    wire [7:0] pcAddr;
     
    //wire [9:0] cnt = 10'd0;
    
    always #60 assign rst = ~rst;//if(cnt%0==100) clk = ~clk;
    //assign cnt = cnt + 1'd1; 
        initial begin
		    #0
		        assign clk = 1'b1;
				//assign rst = 1'b0;
			  #10
			      assign clk = 1'b0;
			  #20
			      assign clk = ~clk;
			   #30
			       assign clk = 1'b1;
			   #40
			       assign clk = 1'b0;
			   #50
			       assign clk = ~clk;
				/*
			#50
				assign clk = 1'b0;
			#100 clk = ~clk;
			*/
			#100 $stop;
        end
    MyPC pc1(
        .clk(clk),
        .rst(rst),
        //.initAddr(initAddr),
        .PC(PC)
    );

endmodule

在这里插入图片描述
RAM.v

module  MyRAM #( parameter DATA_WIDTH = 16,DEPTH = 1024)(
    //input;
    input    wire    clk,
    input    wire    WE, //write low enable;
    input    wire    [clogb2(DEPTH)-1:0] address,
    input    wire    [DATA_WIDTH-1:0] dataIn,
    //output;
    output   wire     [DATA_WIDTH-1:0] dataOut     
);

function integer clogb2 (input integer depth);
begin
    for (clogb2=0; depth>1; clogb2=clogb2+1) 
        depth = depth >>1;                          
end
endfunction 

(* ramstyle = "M9K" *) reg [DATA_WIDTH-1:0] memory[0:DEPTH-1];
reg [clogb2(DEPTH)-1:0] address_reg;
//read;

always @(posedge clk ) begin
    address_reg <= address;
end //always

assign dataOut = memory[address_reg];
//write;

always @(posedge clk ) begin
    if(~WE) begin
        memory[address] <= dataIn;
    end
end //always

endmodule

RAM_tb.v

`timescale 1ns/1ns
module MyRAM_tb ();
parameter CYCLE = 8;
parameter ADDR_WIDTH = 10;
parameter DATA_WIDTH = 16;

reg clk;
reg WE;
reg [ADDR_WIDTH-1:0] address;
reg [DATA_WIDTH-1:0] dataIn;

wire [DATA_WIDTH-1:0] dataOut;


MyRAM  tb_u1(
    .clk                (clk),
    .WE              (WE),
    .address          (address),
    .dataIn             (dataIn),
    .dataOut                (dataOut)
);

initial begin
    clk = 1'b0;
end
always #(CYCLE/2) clk = ~ clk;
always #(CYCLE/2) WE = ~ WE;

initial begin
    WE = 1'b1;
    address = 10'd0;
    dataIn = 0;
    
    #(CYCLE*2)      
    WE = 1'b0;
    address = 10'd1;
    dataIn = 16'habcc;
    
    #(CYCLE*3)      
    WE = 1'b0;
    address = 10'd2;
    dataIn = 16'hbbdd;
    
    #(CYCLE*4)      
    WE = 1'b0;
    address = 10'd3;
    dataIn = 16'hccee;//
    
    #(CYCLE*5)      
    WE = 1'b0;
    address = 10'd4;
    dataIn = 16'h1234;
    
    #(CYCLE*6)      
    WE = 1'b0;
    address = 10'd1;
    dataIn = 16'h568f;
    
    //#(CYCLE*100) 
    //$stop;
    
    #(CYCLE*7)      
    WE = 1'b0;
    address = 10'd2;
    dataIn = 16'h568e;
    
    #(CYCLE*8) 
    WE = 1'b0;
    address = 8'd3;
    dataIn = 16'h568c;
    
    #(CYCLE*9) 
    WE = 1'b0;
    address = 10'd4;
    dataIn = 16'h568a;
    
    #(CYCLE*10)
    $stop;
   
end

endmodule

后记

既来之 则赞之
若有疑问,欢迎评论
本文仅供参考,务必独立思考

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值