設計CPU的第一步,設計一個簡單的邏輯運算單元ALU。
使用Vivado軟體程式設計,利用FPGA開發板NEXYS,同時對Verilog語言也有一定要求。
一、實驗內容
- 如圖,ALU接受兩個N位的輸入,得到N位的輸出,通過控制訊號F決定運算功能。
- 將ALU的輸出結構與七段數碼管顯示模組連線,使用實驗配置的NEXYS4開發板。
結構如下:
- 編寫頂層模組top連線上述模組。
- 模擬,編寫約束檔案,生成二進位制檔案,在開發板上驗證。
整體難度不大,主要任務就是編寫ALU和top,以及約束檔案。
但是這學期之前在摸魚,這個小實驗都沒認真弄好。。。地基打不好,CPU肯定寫不出來啊。
二、RTL級的部分Verilog程式碼,也是重點部分
ALU.v
真的很簡單,方法兩種,一種是always邏輯,一種是assign邏輯。
- 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
- 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(實驗提供)
- 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
- 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
三、存在的問題
- 模擬測試中得不到結果,但是下到板子上以後能正常執行
模擬的 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
程式寫入開發板: