文章目錄
- 一、子產品和設計風格
-
- 1. 子產品
- 2. 描述設計的四種風格
-
- (1)資料流風格
- (2)行為風格
- (3)結構風格描述
- (4)混合設計風格的描述
- 二、各種子產品的示例和testbench
-
- (1)一位加法器
- (2)16位計數器
- (3)3-8譯碼器
- (4)可複位寄存器
- (5)(帶參數)二選一多選器
- (6)四選一多選器
- (7)寄存器堆示例(計算機組成原理)
- (8)ALU示例1(計算機組成原理)
- (9)ALU示例2(計算機組成原理)
一、子產品和設計風格
1. 子產品
- verilog中的基本描述機關是子產品
- 子產品的描述包括以下兩個部分
- 某個設計的功能或結構
- 子產品與其他外部子產品的通信端口
- 描述子產品的方法
- 使用開關原語、門級原語等,對設計的結構進行描述
- 使用連續指派語句(assign)對設計的資料流進行描述
- 使用過程性結構(always、initial等)對設計的時序行為進行描述
- 在子產品内可以引用另一個子產品
2. 描述設計的四種風格
(1)資料流風格
- 使用資料流風格對設計進行模組化的基本機制是采用連續指派語句
assgin
- 文法:
assign [delay] LHS_net = RHS_expression;
- 右邊表達式的使用的操作數無論何時發生變化,右值都将被重新計算,并在指定的延遲後賦予左邊的線網類型變量。如果沒有規定延時,預設延時為0
- 可以把這了解為一個連接配接的導線,導線右邊任意時刻的變化都會傳遞到左邊
(2)行為風格
- 設計的行為功能通過以下過程性結構進行描述
-
語句:此語句内僅在程式最初運作一次initial
-
語句:此語句總是在循環執行中always
-
- 所有的
和initial
語句都在0時刻并發執行always
- 隻有變量類型能在這兩種語句中被指派。這種類型的變量資料在被指派前保持原有值不變。
- 可以把這了解為一個時序部件,需要時鐘信号控制
- 這種風格比較抽象
(3)結構風格描述
- 在verilog中,可以用以下四種構造對電路結構進行描述
- 内建門級原語(基元):在門級描述電路(如
、and
、xor
等内建基元門)or
- 開關級原語(基元):在半導體級描述電路
- 使用者定義的原語(基元):在門級描述電路
- 子產品執行個體:建立層次結構描述電路
- 内建門級原語(基元):在門級描述電路(如
- 用線網可以連接配接各個基元和子產品
- 這個層面上,有點像畫電路圖,最貼近底層
(4)混合設計風格的描述
- 在子產品中,結構的構造和行為的構造可以自由混合
- 子產品描述中可以包括
- 門示執行個體的引用 (觸發always和initial)
- 子產品執行個體的引用
- 連續指派語句assign(觸發always和initial)
- always語句、initial語句(驅動門和開關)
- 其他語句
二、各種子產品的示例和testbench
(1)一位加法器
- 子產品
module add1(a,b,cin,sum,cout);
input a,b,cin;
output sum,cout;
wire q = a&b;
wire g = a^b;
//assign {cout,sum} = a + b + cin;
assign sum = cin ^ g;
assign cout = cin & g | q;
endmodule
- testbench
module add1_tb;
reg a,b,cin;
wire sum,cout;
initial begin
a = 1'b0; b = 1'b0; cin = 1'b0; #100
a = 1'b0; b = 1'b0; cin = 1'b1; #100
a = 1'b0; b = 1'b1; cin = 1'b0; #100
a = 1'b0; b = 1'b1; cin = 1'b1; #100
a = 1'b1; b = 1'b0; cin = 1'b0; #100
a = 1'b1; b = 1'b0; cin = 1'b1; #100
a = 1'b1; b = 1'b1; cin = 1'b0; #100
a = 1'b1; b = 1'b1; cin = 1'b1;
end
add1 myAdd1(
.a(a),
.b(b),
.cin(cin),
.sum(sum),
.cout(cout)
);
endmodule
(2)16位計數器
- 子產品
module counter16(clk,reset,d);
input clk,reset;
output reg[0:3] d;
always@(posedge clk)
if(reset)
d <= 0;
else
d <= d+1;
endmodule
- testbench
`timescale 1ns/1ns
module counter16_tb;
reg clk,rst;
wire[3:0] out;
integer i;
initial begin
i = 0;
clk = 1'b0;
rst = 1'b1;
#100
rst = 1'b0;
end
always begin
#10
clk = ~clk;
i = i+1;
if(i == 10) begin
rst = ~rst;
i = 0;
end
end
counter16 myCounter(clk,rst,out);
endmodule
(3)3-8譯碼器
- 子產品
module dec3_8(a,y);
input [2:0] a;
output[7:0] y;
assign y[0] = (a==3'b000);
assign y[1] = (a==3'b001);
assign y[2] = (a==3'b010);
assign y[3] = (a==3'b011);
assign y[4] = (a==3'b100);
assign y[5] = (a==3'b101);
assign y[6] = (a==3'b110);
assign y[7] = (a==3'b111);
endmodule
/*-----------------其他實作方式------------------
1. 使用case語句
module dec3_8(a,y);
input [2:0] a;
output[7:0] y;
reg[7:0] yy;
assign y = yy; //yy在always塊種被指派,必須是reg型變量
always@(a) begin //電平觸發,a變化就會觸發執行
case(a)
3'b000: yy = 8'b0000_0001;
3'b001: yy = 8'b0000_0010;
3'b010: yy = 8'b0000_0100;
3'b011: yy = 8'b0000_1000;
3'b100: yy = 8'b0001_0000;
3'b101: yy = 8'b0010_0000;
3'b110: yy = 8'b0100_0000;
3'b111: yy = 8'b1000_0000;
endcase
end
endmodule
2. 行為抽象級别更高
module dec3_8(a,y);
input[2:0] a;
output[7:0] y;
assign y = 1<<a;
endmodule
*/
- testbench
module dec3_8_tb;
reg[2:0] s;
wire[7:0] y;
initial begin
s = 3'b0;
end
always #10 s=s+1;
dec3_8 dec(
.a(s),
.y(y)
);
endmodule
(4)可複位寄存器
- 子產品
//可複位寄存器
module floper(clk,rst,d,q);
input clk,rst;
input[3:0] d;
output reg[3:0] q;
always @(posedge clk or negedge rst)
if(!rst)
q <= 4'b0;
else
q <= d;
endmodule
- testbench
module floper_tb;
reg clk,rst;
reg[3:0] d;
wire[3:0] q;
initial begin
clk = 1'b0;
rst = 1'b0;
d = 4'b1010;
#30 rst = 1'b1; //30ns後取消複位,這時正好clk上升沿,直接寫入1010
end
initial #60 d = 4'b0101; //60ns後寫入值改變,此時clk是下降沿不寫,等到70ns時寫入0101
always #10 clk = ~clk;
floper f(
.clk(clk),
.rst(rst),
.d(d),
.q(q)
);
endmodule
(5)(帶參數)二選一多選器
- 子產品
module mux2(a,b,s,y);
input s;
input [7:0]a,b;
output[7:0]y;
assign y = (s==0)?a:b;
endmodule
/*------------ 帶位寬參數的寫法------------------
module mux2_para #(parameter WIDTH=8)(a,b,s,y);
input s;
input[WIDTH-1:0] a,b;
output[WIDTH-1:0] y;
assign y = (s==0) ? a:b;
endmodule
*/
- testbench
`timescale 1ns/1ns
module mux2_tb;
reg clk;
reg[7:0] a,b;
wire[7:0] out;
initial begin
a = 8'b0;
b = 8'b1111_1111;
clk = 1'b0;
end
always #10 clk=~clk;
mux2 myMux2(
.a(a),
.b(b),
.s(clk),
.y(out)
);
endmodule
(6)四選一多選器
- 子產品
module mux4(d0,d1,d2,d3,s,y);
input[3:0] d0,d1,d2,d3;
input[1:0] s;
output[3:0] y;
wire[3:0] low,high;
//先選出低位為s[0]的
mux2 lowmux(d0,d1,s[0],low);
mux2 highmux(d2,d3,s[0],high);
//再選出高位為s[1]的
mux2 finalmux(low,high,s[1],y);
endmodule
- testbench
module mux4_tb;
integer i;
reg[1:0] s;
reg[3:0] i0,i1,i2,i3;
wire[3:0] out;
initial begin
i0 = 4'b0;
i1 = 4'b0101;
i2 = 4'b1010;
i3 = 4'b1111;
i = 0;
s = 2'b0;
end
always begin
#10
i = i + 1;
if(i > 3)
i = 0;
s = i;
end
mux4 myMux4(
.d0(i0),
.d1(i1),
.d2(i2),
.d3(i3),
.s(s),
.y(out)
);
endmodule
(7)寄存器堆示例(計算機組成原理)
- 子產品
module regFile(clk,reset,s,wEn,din,dout);
input clk,reset,wEn; //時鐘,複位,寫使能
input[1:0] s; //從regFile的四個機關中選擇
input[7:0] din;
output[7:0] dout;
reg[7:0] R[0:3]; //regFile的存儲空間,4個位元組
assign dout = R[s]; //把R[s]連接配接到dout,内部信号傳出來通常用assign,非時序電路,用=
always @(posedge clk or negedge reset)
begin
if(!reset) begin
R[0] <= 0; //給寄存器寫值,這是時序電路,用<=
R[1] <= 1;
R[2] <= 2;
R[3] <= 3;
end
else if (wEn)
R[s] <= din;
end
endmodule
- testbench
module regFile_tb;
reg clk,rst,wEn;
reg[1:0] s;
reg[7:0] in;
wire[7:0] out;
initial begin
rst = 1'b0;
wEn = 1'b0;
clk = 1'b0;
s = 2'b0;
in = 8'b1111_1111;
end
always #10 clk = ~clk;
always @(posedge clk) begin
in = in+1;
s = in % 4;
//從第四個clk上升沿開始寫入資料,由于讀是非時序電路assign,寫是時序電路<=,每次都是讀出舊資料,寫入新資料(下個周期讀出)
if(in>=4) begin
rst = 1'b1;
wEn = 1'b1;
end
end
regFile rf(
.clk(clk),
.reset(rst),
.s(s),
.wEn(wEn),
.din(in),
.dout(out)
);
endmodule
(8)ALU示例1(計算機組成原理)
- 子產品
module ALU_1(op,A,B,result);
input[2:0] op;
input[7:0] A,B;
output[7:0] result;
reg[7:0] result;
always @(op or A or B) begin
if(op == 3'b000) result = A+B;
else if(op == 3'b001) result = A-B;
else if(op == 3'b010) result = A&B;
else if(op == 3'b011) result = A|B;
else if(op == 3'b100) result = ~A;
else result = 8'b0;
end
endmodule
- testbench
module ALU_1_tb;
reg[7:0] A,B;
reg[2:0] op;
wire[7:0] res;
initial begin
A = 8'b1010_1010;
B = 8'b0101_0101;
op = 3'b0;
end
always #10 op = op+1;
ALU_1 alu(
.op(op),
.A(A),
.B(B),
.result(res)
);
endmodule
(9)ALU示例2(計算機組成原理)
- 子產品
module ALU_2(op,A,B,ci,result,co);
input[2:0] op;
input[7:0] A,B;
input ci;
output[7:0] result;
output co;
reg[7:0] result;
reg co;
always @(op or A or B) begin
case(op)
3'd0: {co,result} = A + B;
3'd1: {co,result} = A + B + ci;
3'd2: {co,result} = A - B - ci;
3'd3: result = A & B;
3'd4: result = A | B;
3'd5: result = A ^ B;
3'd6: result = ~A;
default: begin
co = 0;
result = 8'd0;
end
endcase
end
endmodule
- testbench
module ALU_2_tb;
reg[7:0] A,B;
reg[2:0] op;
reg ci;
wire[7:0] res;
wire co;
initial begin
A = 8'b1010_1010;
B = 8'b0101_0101;
ci = 1;
op = 0;
end
always #10 op = op+1;
ALU_2 alu(
.op(op),
.A(A),
.B(B),
.ci(ci),
.result(res),
.co(co)
);
endmodule