MIPS指令的CPU實現:ALU設計

Miracle_Mountain發表於2021-05-29

設計CPU的第一步,設計一個簡單的邏輯運算單元ALU。
使用Vivado軟體程式設計,利用FPGA開發板NEXYS,同時對Verilog語言也有一定要求。

一、實驗內容

  1. 如圖,ALU接受兩個N位的輸入,得到N位的輸出,通過控制訊號F決定運算功能。

  2. 將ALU的輸出結構與七段數碼管顯示模組連線,使用實驗配置的NEXYS4開發板。
    結構如下:
  3. 編寫頂層模組top連線上述模組。
  4. 模擬,編寫約束檔案,生成二進位制檔案,在開發板上驗證。

整體難度不大,主要任務就是編寫ALU和top,以及約束檔案。
但是這學期之前在摸魚,這個小實驗都沒認真弄好。。。地基打不好,CPU肯定寫不出來啊。

二、RTL級的部分Verilog程式碼,也是重點部分

ALU.v

真的很簡單,方法兩種,一種是always邏輯,一種是assign邏輯。

  1. always:
module ALU(
    input wire [31:0] A,
    input wire[31:0] B,
    input wire [2:0] OP, // 輸入用wire
    output reg [31:0] F //輸出用暫存器reg
    );
    always @(*) begin
        case(OP)
            3'b000: begin F <= A + B; end //這裡實際上連進位都沒有考慮
            3'b001: begin F <= A - B; end
            3'b010: begin F <= A & B; end
            3'b011: begin F <= A | B; end
            3'b100: begin F <= ~A; end
            3'b101: begin F <= A<B; end
            default:  begin F <= 0; end
        endcase
    end
endmodule
  1. assign:

assign相當於連線,一般是將一個變數的值不間斷地賦值給另一個變數,所以賦值的型別應用wire。

module ALU(
    input wire [31:0] A,
    input wire[31:0] B,
    input wire [2:0] OP,
    output wire [31:0] F
    );
    assign F = (OP == 3'b000) ? A + B:
                (OP == 3'b001) ? A - B:
                (OP == 3'b010) ? A & B:
                (OP == 3'b011) ? A | B:
                (OP == 3'b100) ? ~A:
                (OP == 3'b101) ? A < B:
                32'b0;
endmodule

數碼管顯示模組display.v和seg7.v(實驗提供)

  1. display.v
module display(
    input wire clk,reset,
    input wire [31:0]s,
    output wire [6:0]seg,
    output reg [7:0]ans
    );
    reg [20:0]count;
    reg [4:0]digit; 
    always@(posedge clk,posedge reset)
    if(reset)  
        count = 0;
    else 
        count = count + 1;
       
    always @(posedge clk)
    case(count[20:18])
        0:begin
            ans = 8'b11111110;
            digit = s[3:0];
        end
        1:begin
            ans = 8'b11111101;
            digit = s[7:4];
        end
        2:begin
            ans = 8'b11111011;
            digit =s[11:8];
        end
        3:begin
            ans = 8'b11110111;
            digit = s[15:12];
        end
         4:begin
             ans = 8'b11101111;
             digit = s[19:16];
         end
         5:begin
             ans = 8'b11011111;
             digit = s[23:20];
         end
         6:begin
             ans = 8'b10111111;
             digit =s[27:24];
         end
         7:begin
             ans = 8'b01111111;
             digit = s[31:28];
         end
    endcase
    
    seg7 U4(.din(digit),.dout(seg));
endmodule
  1. seg7.v
module seg7(
    input wire [3:0]din,
    output reg [6:0]dout
    );
 
    always@(*)
    case(din)
        5'h0:dout = 7'b000_0001;
        5'h1:dout = 7'b100_1111;
        5'h2:dout = 7'b001_0010;
        5'h3:dout = 7'b000_0110;
        5'h4:dout = 7'b100_1100;
        5'h5:dout = 7'b010_0100;
        5'h6:dout = 7'b010_0000;
        5'h7:dout = 7'b000_1111;
        5'h8:dout = 7'b000_0000;
        5'h9:dout = 7'b000_0100;
        5'ha:dout = 7'b000_1000;
        5'hb:dout = 7'b110_0000;
        5'hc:dout = 7'b011_0001;
        5'hd:dout = 7'b100_0010;
        5'he:dout = 7'b011_0000;
        5'hf:dout = 7'b011_1000;
        default:dout = 7'b111_1111;        
    endcase
    
endmodule

top.v

module top(
    input wire clk, rst,
    output wire[6:0] seg,
    output wire[7:0] ans,
    input wire [2:0] op,
    input wire [7:0] num_1
    );
    wire [31:0] f; // f從ALU傳給display
    ALU U1(.A({24'b0,num_1}),.B(32'h1),.OP(op),.F(f)); // 輸入a為8位擴充至32位,b為固定值32'h1

    display U2(.clk(clk),.reset(rst),.s(f),.ans(ans),.seg(seg));
endmodule

三、存在的問題

  1. 模擬測試中得不到結果,但是下到板子上以後能正常執行

模擬的 testbench 檔案:

module test();
    reg [7:0] num_1;
    reg [2:0] op;
    wire [6:0]seg;
    wire [7:0]ans;
    reg clk,rst;

    always #25 clk = ~clk;

    initial begin
        clk = 1;
        rst = 0;
        num_1 = 8'h 11;
        op = 3'b 111;
        # 100 op = 3'b 000;
        # 100 op = 3'b 001;
        # 100 op = 3'b 010;
        # 100 op = 3'b 011;
        # 100 op = 3'b 100;
        # 100 op = 3'b 101;
    end
    
    top x(
    .clk(clk),
    .rst(rst),
    .seg(seg),
    .ans(ans),
    .num_1(num_1),
    .op(op)
    );
    
endmodule

程式寫入開發板:

相關文章