天天看點

CPU部件實作之ALU、寄存器堆、PC、RAMALU和寄存器堆PC和半導體存儲器RAM後記

系統硬體綜合設計-多周期CPU的設計與實作

計算機組成原理 實驗五 單周期CPU設計與實作——十條指令CPU

文章目錄

  • ALU和寄存器堆
    • 一、實驗目的:
    • 二、實驗内容:
    • 三、 源代碼
  • PC和半導體存儲器RAM
    • 一、實驗目的:
    • 二、實驗内容:
    • 三、源代碼
  • 後記

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???????
    [email protected]* 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
           
CPU部件實作之ALU、寄存器堆、PC、RAMALU和寄存器堆PC和半導體存儲器RAM後記

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];
  
    [email protected](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
           
CPU部件實作之ALU、寄存器堆、PC、RAMALU和寄存器堆PC和半導體存儲器RAM後記

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
           
CPU部件實作之ALU、寄存器堆、PC、RAMALU和寄存器堆PC和半導體存儲器RAM後記

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
           

後記

既來之 則贊之

若有疑問,歡迎評論

本文僅供參考,務必獨立思考