1.Verilog語言設(shè)計思想和可綜合特性
例:用Verilog設(shè)計模256(8bits)計數(shù)器
(a)可綜合程序描述方式
(b)常見的錯誤描述方式
同時Verilog的電路描述方式具有多樣性,這也決定了對于電路設(shè)計的多樣性。
例:用Verilog設(shè)計數(shù)字多路選擇器
(a)采用真值表形式的代碼
(b)采用邏輯表達式形式的代碼
(c)采用結(jié)構(gòu)性描述的代碼
2.Verilog組合邏輯電路
組合電路的特點是:電路中任意時刻的穩(wěn)態(tài)輸出僅僅取決于該時刻的輸入,而與電路原來的狀態(tài)無關(guān)。
組合電路的設(shè)計需要從以下幾個方面考慮:
- 所用的邏輯器件數(shù)目最少,器件的種類最少,且器件之間的連線最簡單。這樣的電路稱“最小化"電路;
- 其次,為了滿足速度要求,應(yīng)使級數(shù)盡量少,以減少門電路的延遲;電路的功耗應(yīng)盡可能的小,工作時穩(wěn)定可靠。
描述組合邏輯電路有四種方式:結(jié)構(gòu)描述、邏輯代數(shù)、真值表、抽象描述。
例如:設(shè)計一個3個裁判的表決電路,當(dāng)兩個或兩個以上裁判同意時,判決器輸出"1",否則輸出"0" 。
方法1:真值表方式
真值表是對電路功能最直接和簡單的描述方式。根據(jù)電路的功能,可以通過真值表直接建立起輸出與輸入之間的邏輯關(guān)系。本例有三個輸入端A、B、C和一個輸出端OUT 。
A | B | C | OUT |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 |
1 | 0 | 0 | 0 |
0 | 1 | 1 | 1 |
1 | 0 | 1 | 1 |
1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 |
在Verilog中,可以使用“case”語句對電路進行描述性設(shè)計,根據(jù)上表設(shè)計:
方法2:邏輯代數(shù)方式
對于組合電路的另一種表達方法是邏輯代數(shù)方法。主要思想是將真值表用卡諾圖表示,然后化簡電路,得出邏輯函數(shù)表達式。
通過對卡諾圖的化簡,可以得到組合電路邏輯輸出與輸入之間的邏輯函數(shù)表達式:
根據(jù)邏輯函數(shù)表達式可以很方便寫出采用邏輯代數(shù)描述方式的Verilog:
module desingn(OUT,A,B,C);
output OUT;
input A,B,C;
assign OUT = (A&B) | (B&C) | (A&C);
endmodule
方法3:結(jié)構(gòu)描述方式
結(jié)構(gòu)性描述方式是對電路最直接的表示,早期的數(shù)字電路設(shè)計通常采用的原理圖設(shè)計實際上就是一種結(jié)構(gòu)性描述方式。
module desingn(OUT,A,B,C):
output OUT;
input A,B,C;
and U1(w1,A,B);
and U2(w2,B,C);
and U3(w3,A,C);
or U4(OUT,w1,w2,w3);
endmodule
方法4:抽象描述方式
Verilog還提供了采用抽象描述進行電路設(shè)計的方法,可以直接從電路功能出發(fā),編寫代碼。例如判決器設(shè)計,將三個輸入的判決相加,當(dāng)判決成功時相加器之和大于1 , 即表示投票成功。
module desingn(OUT,A,B,C);
output OUT;
input A,B,C;
wire [1:0} sum;
reg OUT;
assign sum = A + B + C;
always@(sum)
if(sum > 1)
OUT = 1;
else
OUT = 0;
endmodule
2.1 數(shù)字加法器
數(shù)字加法器是最為常用的一種數(shù)字運算邏輯,被廣泛用于計算機、通信和多媒體數(shù)字集成電路中
例如:2輸入1bit信號全加器??紤]了來自低位的進位那么該運算就為全加運算,實現(xiàn)全加運算的電路稱為全加器。
代數(shù)邏輯表示為:
對應(yīng)的電路如下:
Verilog可以用不同的描述方式寫出一位全加器,其綜合電路是相同的,只是描述風(fēng)格不同。
(1)利用連續(xù)賦值語句實現(xiàn)
module one_bit_fulladder(SUM, C_OUT, A, B, C_IN);
input A, B, C_IN;
output Sum, C_OUT;
assign SUM = (A ^ B) ^ C_IN;
assign C_OUT = (A & B) | ((A ^ B) & C_IN);
endmodule
(2)利用行為描述實現(xiàn)
module one_bit_fulladder(SUM, C_OUT, A, B, C_IN);
input A, B, C_IN;
output SUM, C_OUT;
assign {C_OUT,SUM} = A + B + C_IN;
endmodule
采用行為描述可以提高設(shè)計的效率,對于一個典型的多位加法器的行為描述設(shè)計,僅需改變代碼中輸入和輸出信號的位寬即可,例如一個2輸入8bits 加法器:
例:4位超前進位加法器
超前進位加法器是一種高速加法器,每級進位由附加的組合電路產(chǎn)生,高位的運算不需等待低位運算完成,因此可以提高運算速度。
根據(jù)對于輸入信號位寬為N的全加器,其進位信號是:
輸出的加法結(jié)果是
超前進位標(biāo)志信號是
進位產(chǎn)生函數(shù)是
進位傳輸函數(shù)是
上述公式中N為加法器位數(shù),在4位加法器中,N=4。由式可以推出各級進位信號表達式,并構(gòu)成快速進位邏輯電路。
4位超前進位加法器的電路圖如下
4位超前進位加法器的Verilog代碼:
2.2 數(shù)據(jù)比較器
數(shù)據(jù)比較器是用來對兩個二進制數(shù)的大小進行比較,或檢測是否相等的邏輯電路。數(shù)據(jù)比較器包含兩個部分:一是比較兩個數(shù)的大??;二是檢測兩個數(shù)是否一致。
例:4位數(shù)值比較器
多位數(shù)值比較器的比較過程是由高位到底位逐位進行比較,而且只有在高位相等時,才進行低位比較。4位數(shù)值比較器中進行A3A2A1A0和B3B2B1B0的比較時,應(yīng)首先比較最高位A3和B3。如果A3>B3,那么不管其它幾位數(shù)為何值,結(jié)果為A>B;若A3<B3,為A< B。如果A3=B3,就必須通過比較低一位A2和B2來判斷A和B的大小。如果A2=B2,還必須通過比較更低一位A1和B1來判斷,直到最后一位的比較。如果完全相等,則由前一級結(jié)果C(級聯(lián)輸入)確定。
module four_bits_comp(F, A, B,C);
parameter comp_width = 4;
output [2:0] F;
input [comp_width-1:0] A;
input [comp_width-1:0] B;
ref [2:0] F;
always@(A or B or C)
if(A>B)
F = 3'b100;
else if(A<B)
F = 3'b001;
else
F = C;
endmodule
2.3 數(shù)據(jù)選擇器
數(shù)據(jù)選擇器又稱多路選擇器(Multiplexer,簡稱MUX),它有n位地址輸入、2n位數(shù)據(jù)輸入,1位數(shù)據(jù)輸出。每次在輸入地址的控制下,從多路輸入數(shù)據(jù)中選擇一路輸出,其功能類似于一個單刀多擲開關(guān),如圖:
例,8選1數(shù)據(jù)選擇器
8選1數(shù)據(jù)選擇器可以由多個2選1選擇器組成:
(1)多個2選1數(shù)據(jù)選擇器的結(jié)構(gòu)級描述
module mux8to1(d_out, d_in, sel);
output d_out;
input[7:0] d_in;
input [2:0] sel;
wire[3:0] w1;
wire[1:0] w2;
assign w1 = sel[0] ? {d_in[7], d_in[5], d_in[3], d_in[1]} : {d_in[6], d_in[4], d_in[2], d_in[0]};
assign w2 = sel[1] ? {w1[3], w1[1]} : {w1[2], w1[0]};
assign d_out = sel[2] ? w2[1] : w2[0];
endmodule
(2) 抽象描述方式
對于多路選擇器的設(shè)計,可以通過“case”語句進行設(shè)計。
2.4 數(shù)字編碼器
用文字、符號或數(shù)碼表示特定對象的過程稱為編碼。在數(shù)字電路中用二進制代碼表示有關(guān)的信號稱為二進制編碼。實現(xiàn)編碼操作的電路叫做編碼器。
例:3位二進制8-3線編碼器
用n位二進制代碼對N=2n個一般信號進行編碼的電路,叫做二進制編碼器。
例如n=3,可以對8個一般信號進行編碼。這種編碼器有一個特點:任何時刻只允許輸入一個有效信號,不允許同時出現(xiàn)兩個或兩個以上的有效信號。
如下框圖:
真值表:
module 8to3(F, I);
output [2:0] F;
input [7:0} I;
reg [2:0] F;
always@(I)
case(I):
8'b00000001:F=3'b000;
8'b00000010:F=3'b001;
8'b00000100:F=3'b010;
8'b00001000:F=3'b011;
8'b00010000:F=3'b100;
8'b00100000:F=3'b101;
8'b01000000:F=3'b110;
8'b10000000:F=3'b111;
default: F= 3'bx;
endcase
endmodule
例:8線-3線優(yōu)先編碼器
二進制編碼器電路要求任何時刻只有一個輸入有效,若同時有兩個或更多個輸入信號有效時,將造成輸出混亂狀態(tài),因此在使用過程中有一定局限性。為了克服對于輸入信號的要求,一種方法是采用優(yōu)先編碼器。優(yōu)先編碼器允許多個輸入信號同時有效,但它只按其中優(yōu)先級別最高的有效輸入信號編碼,對級別低的輸入信號不予理睬。
功能表:
例:二進制轉(zhuǎn)化十進制8421 BCD編碼器
將十進制數(shù)0、1、2、3、4、5、6、7、8、9等十個信號編成二進制代碼的電路叫做二進制轉(zhuǎn)化十進制編碼器。它的輸入是代表0-9這10個數(shù)字的狀態(tài)信息,有效信號為1(即某信號為1時,則表示要對它進行編碼),輸出是相應(yīng)的BCD碼,因此也稱10線一4線編碼器。它和二進制編碼器特點一樣,任何時刻只允許輸入一個有效信號。
例:8421BCD十進制余3編碼器
和8421BCD編碼一樣,余3碼是也一種BCD編碼,這種編碼的特點是,余3碼作十進制加法運算的時候,若2數(shù)之和是10,正好等于二進制數(shù)的16,于是便從高位自動產(chǎn)生進位信號,因此可以使用余3碼。
余3碼編碼表:
2.5 數(shù)字譯碼器
譯碼是編碼的逆過程,它將二進制代碼所表示的信息翻譯成相應(yīng)的狀態(tài)信息。實現(xiàn)譯碼功能的電路成為譯碼器。
圖是2線-4線譯碼器的邏輯電路及邏輯符號。圖中A1,A0為地址輸入端,A1為高位。非Y0 - 非Y3為狀態(tài)信號輸出端,"非"表示低點平有效。E為使能端(或稱選通控制端),低電平有效。當(dāng)E = 0時,允許譯碼器工作,非Y0 - 非Y3中只允許一個為有效電平輸出;當(dāng)E = 1時,禁制譯碼器工作,所有輸出均為高電平。
一般使能端有兩個用途:一是可以引入選通脈沖,以抑制冒險脈沖的發(fā)生;二是可以用來擴展輸入變量數(shù)(功能擴展)。
2.6 奇偶校驗器
奇偶校驗器的功能是檢測數(shù)據(jù)中包含"1"的個數(shù)是奇數(shù)還是偶數(shù)。在計算機和一些數(shù)字通信系統(tǒng)中,常用奇偶校驗器來檢查數(shù)據(jù)傳輸和數(shù)碼記錄中是否存在錯誤。
奇偶校驗包含兩種方式:奇校驗和偶校驗。奇校驗保證傳輸數(shù)據(jù)和校驗位中"1"的總數(shù)為奇數(shù)。如果數(shù)據(jù)中包含奇數(shù)個"1",則校驗位置“0" ,如果數(shù)據(jù)中包含偶數(shù)個"1",則校驗位置"1"。偶校驗保證傳輸數(shù)據(jù)和校驗位中"1"的總數(shù)為偶數(shù)。如果數(shù)據(jù)中包含奇數(shù)個"1",則校驗位置"1",如果數(shù)據(jù)中包含偶數(shù)個"1",則校驗位置"0" 。
奇偶校驗只能檢測部分傳輸錯誤,它不能確定錯誤發(fā)生在哪位或哪幾位,所以不能進行錯誤校正。當(dāng)數(shù)據(jù)發(fā)生錯誤時只能重新發(fā)送數(shù)據(jù)。
例:8bits奇偶校驗器
8bits奇偶校驗器的原理圖如圖所示:
圖中,校驗器的輸入b0 - b7由7bits數(shù)據(jù)和1 bit校驗位組成。FOD為判奇輸出,F(xiàn)EV為判偶輸出。當(dāng)采用奇校驗時,FOD = 1,FEV = 0;當(dāng)采用偶校驗時,F(xiàn)OD=O, FEV = 1。
3.時序電路
與組合邏輯電路不同,時序邏輯電路的輸出不僅與當(dāng)前時刻輸入變量的取值有關(guān),而且與電路的原狀態(tài),即與過去的輸入情況有關(guān)。
時序邏輯電路有兩個特點:
(1)時序邏輯電路包括組合邏輯電路和存儲電路兩部分,存儲電路具有記憶功能,通常山觸發(fā)器組成;
(2)存儲電路的狀態(tài)反饋到組合邏輯電路輸入端,與外部輸入信號共同決定組合邏輯電路的輸出。
同步時序電路設(shè)計流程:
例:用verilog設(shè)計一個"111"的序列檢測器,當(dāng)輸入三個或三個以上“ 1 "時,電路輸出為1,否則為0。
(1)狀態(tài)轉(zhuǎn)移圖方法
S0:初始狀態(tài),表示電路還沒有收到一個有效的1。
S1:表示電路收到了一個1。
S2:表示電路收到了連續(xù)兩個1。
S3:表示電路收到了連續(xù)三個1。
電路圖:
module check(z, x, clk);
parameter s0 = 2'b00, s1 = 2'b01, s2 = 2'b10, s3 = 2'b11;
output z;
input x, clk;
reg[1:0} state, next_state;
reg z;
always@(posedge clk)
case(state)
s0:if(x)
begin
next_state <= s1;
z = 0;
end
else
begin
next_state <= s0;
z = 0;
end
s1:if(x)
begin
next_state <= s2;
z = 0;
end
else
begin
next_state <= s0;
z = 0;
end
s2:if(x)
begin
next_state <= s3;
z = 1;
end
else
begin
next_state <= s0;
z = 0;
end
s0:if(x)
begin
next_state <= s3;
z = 0;
end
else
begin
next_state <= s0;
z = 0;
end
endcase
always@(posedge clk)
state <= next_state;
endmodule
(2)基于狀態(tài)化簡的結(jié)構(gòu)性描述方法
對狀態(tài)轉(zhuǎn)移圖化簡,僅剩三個狀態(tài),需要兩位二進制表示,即需要兩個D觸發(fā)器儲存狀態(tài)。設(shè)Q1表示高位寄存器的輸出,Q0表示低位寄存器的輸出。將狀態(tài)的跳轉(zhuǎn)以及輸出Z用卡諾圖表的形式示出,如下:由卡諾圖可以得出電路的輸出方程和狀態(tài)方程:
Q1n+1 = Q1
Q0n+1 = X
Z = Q1Q0X
//D觸發(fā)器模塊
module DFF(Q, D, clk);
output Q;
input D, clk;
reg Q;
always@(posedge clk)
Q <= D;
endmodule
//序列檢測模塊
module check(z, x, clk);
output z;
input x,clk;
wire w1,w2;
DFF U1(.clk(clk), .D(x), .Q(w1));
DFF U2(.clk(clk), .D(w1), .Q(w2));
assign z = x&w1&w2;
endmodule
(3)Verilog HDL抽象性描述方法
在Verilog中還可以對電路進行抽象的描述。實現(xiàn)序列“111"的檢測,可以使用一個三位的移位寄存器,將輸出x作為移位寄存器的輸出,當(dāng)寄存器中為111時,輸出Z為1。
module check(z, x, clk);
output z;
input x,clk;
reg[2:0] q;
reg z;
always@(posedge clk)
q <= {q[1:0], x};
always@(posedge clk)
if(q == 3'b111)
z = 1;
else
z = 0;
endmodule
3.1 觸發(fā)器
觸發(fā)器是時序電路的最基本電路單元,主要有D觸發(fā)器、JK觸發(fā)器、 T觸發(fā)器和RS觸發(fā)器等。根據(jù)功能要求的不同 , 觸發(fā)器還具有置位、復(fù)位、使能、選擇等功能。
3.1.1 簡單的D觸發(fā)器
clk | D | Qn | Qn+1 |
---|---|---|---|
0 | x | 0 | 0 |
0 | x | 1 | 1 |
1 | x | 0 | 0 |
1 | x | 1 | 1 |
↑ | 0 | 0 | 0 |
↑ | 0 | 1 | 0 |
↑ | 1 | 0 | 1 |
↑ | 1 | 1 | 1 |
module DFF(Q, D, clk);
output Q;
input D, clk;
reg Q;
always@(posedge clk)
Q <= D;
endmodule
輸入端的數(shù)據(jù)D在時鐘clk的上升沿被送入觸發(fā)器,使得Q=D。其特征方程可描述為Qn+1 = Dn。
3.1.2 帶復(fù)位端(清零端)D觸發(fā)器:
同步清0的觸發(fā)器:
module DFF_rst(q, clk, rst_n, d);
output q;
input clk,rst_n,d;
reg q;
always@(posedge clk)
if(!rst_n)
q<=0;
else
q<=d;
endmodule
異步清0的觸發(fā)器:
module DFF_rst(q, clk, rst_n, d);
output q;
input clk,srst_n,d;
reg q;
always@(posedge clk or rst_n)
if(!rst_n)
q<=0;
else
q<=d;
endmodule
3.1.3 復(fù)雜功能D觸發(fā)器
同步清0,置1和異步清0,置1共同在一個觸發(fā)器的復(fù)雜D觸發(fā)器。
module DFF(q, qb, clk, rst_n1, set1, rst_n2, set2, data_in);
output q, qb;
input clk, rst_n1,rst_n2, set1,set2, data_in;
reg q,qb;
always@(posedge clk)
if(!rst_n1)
q<=0;
else
q<=data_in;
always@(posedge clk or rst_n2)
if(!rst_n2)
q<=0;
else
q<=data_in;
endmodule
3.1.4 T觸發(fā)器
T觸發(fā)器的邏輯符號如下,T觸發(fā)器的功能:當(dāng)時鐘的有效邊沿到來時,如果T=1,則觸發(fā)器翻轉(zhuǎn);如果T=0,則觸發(fā)器的狀態(tài)保持不變。R為復(fù)位端,異步復(fù)位,低電平有效。
module TFF(d, t, clk, rst_n);
output d;
input t, clk, rst_n;
reg d;
always@(posedge clk or rst_n)
if(!rst_n)
d <= 1'b0;
else if(t)
d <= ~d;
endmodule
3.2 計數(shù)器
3.2.1 二進制計數(shù)器
module comp2(q, clk, rst);
output q;
input clk,rst;
reg q;
always@(posedge clk or rst_n)
if(!rst)
q <= 1'b0;
else
q <= ~q;
endmodule
3.2.2 任意模數(shù)的計數(shù)器
任意模值M的計數(shù)器,第一步需要確定計數(shù)器所需要觸發(fā)器個數(shù)。N個觸發(fā)器對應(yīng)了2N個狀態(tài)。應(yīng)有2N > M任意模值計數(shù)器選取滿足條件的最小N,N為計數(shù)器中觸發(fā)器的個數(shù)。有兩種方法實現(xiàn) : 反饋清零法和反饋置數(shù)法。
//反饋清零法設(shè)計的模11計數(shù)器
module comp11(count, clk, rst);
output[3:0] count;
input clk,rst;
reg[3:0] count;
always@(posedge clk)
if(rst)
count <= 4'b0000;
else
if(count == 4'b1010)
count <= 4'b0000;
else
count <= count + 1;
endmodule
3.3 移位寄存器
移位寄存器可以用來實現(xiàn)數(shù)據(jù)的串并轉(zhuǎn)換,也可以構(gòu)成移位行計數(shù)器,進行計數(shù)、分頻,還可以構(gòu)成序列碼發(fā)生器、序列碼檢測器等,它也是數(shù)字系統(tǒng)中應(yīng)用非常廣泛的時序邏輯部件之一。
例:環(huán)形移位寄存器
N位環(huán)型寄存器由N個移位寄存器組成,可以實現(xiàn)環(huán)型移位
將每個寄存器的輸出作為下一位寄存器的輸入,并將高位寄存器的輸出作為循環(huán)的輸入。
module shiftregist(D, clk, rst_n);
parameter shiftregist_width = 4;
output [shiftregist_width-1:0] D;
input clk,rst_n;
reg [shiftregist_width-1:0] D;
always@(posedge clk)
if(!rst_n)
D<=4'b0000;
else
D<={D[shiftregist_width-2:0], D[shiftregist_width-2:1]};
endmodule
3.4 序列信號發(fā)生器
序列信號是數(shù)字電路系統(tǒng)中常用的功能單元,按照序列循環(huán)長度M和觸發(fā)器數(shù)目n的關(guān)系一般可分為三種:
(1) 最大循環(huán)長度序列碼,M=2n;
(2) 最長線形序列碼(m序列碼),M=2n-1;
(3) 任意循環(huán)長度序列碼,M<2n。
序列信號發(fā)生器是能夠產(chǎn)生一組或多組序列信號的時序電路,它可以由純時序電路構(gòu)成,也可以由包含時序和組合邏輯的混合電路構(gòu)成。
例:設(shè)計一個產(chǎn)生10011序列的信號發(fā)生器
- 方法(1):由移位寄存器構(gòu)成
由于移位寄存器輸入和輸出信號之間沒有組合電路,不需要進過組合邏輯的反饋運算,因此這種序列產(chǎn)生電路的工作頻率很高。 缺點是移位寄存器長度取決于序列長度,因此占用電路的面積很大。
module maker(out, clk, load, D);
parameter M=6;
output out;
input clk,load;
input [M-1:0] D;
reg [M-1:0] Q;
initial Q=6'b10011;
always@(posedge clk)
if(load)
Q<=D;
else
Q<={Q[M-2:0], Q[M-1]};
assign out=Q[M];
endmodule
方法(2):由移位寄存器和組合邏輯電路構(gòu)成
反饋移位型序列碼發(fā)生器的結(jié)構(gòu)框圖如圖所示,它由移位寄存器和組合邏輯網(wǎng)絡(luò)組成,從移位寄存器的某一輸出端可以得到周期性的序列碼。
其設(shè)計按以下步驟進行:
(1)根據(jù)給定序列信號的循環(huán)周期M,確定移位寄存器位數(shù)n,2n-1<M≤2n。
(2)確定移位寄存器的M個獨立狀態(tài)。將給定的序列碼按照移位規(guī)律每n位一組,劃分為M個狀態(tài)。若M個狀態(tài)中出現(xiàn)重復(fù)現(xiàn)象,則應(yīng)增加移位寄存器位數(shù)。用n + 1位再重復(fù)上述過程,直到劃分為M個獨立狀態(tài)為止。
(3)根據(jù)M個不同的狀態(tài)列出移位寄存器的態(tài)序表和反饋函數(shù)表,求出反饋函數(shù)F的表達式。
(4)檢查自啟動性能。
與上面的序列信號發(fā)生器相比,各個寄存器的輸出需要經(jīng)過反饋網(wǎng)絡(luò),然后才連接到移位寄存器的輸入端。因此,電路的速度必然下降,但反饋網(wǎng)絡(luò)的好處在于它可以節(jié)省寄存器。
對于“ 1001 1 1 "序列的信號發(fā)生器。
首先,確定所需移位寄存器的個數(shù)n。因M = 6,故n 3。
然后,確定移位寄存器的六個獨立狀態(tài)。
按照規(guī)律每三位一組,劃分六個狀態(tài)為100,001,011,111,111,110。其中狀態(tài)111重復(fù)出現(xiàn),故取n=4,并重新劃分狀態(tài),得到:1001、0011、0111、1111、1110、1100。因此確定n =4。
第三,列態(tài)序表和反饋激勵函數(shù)表,求反饋函數(shù)F的表達式。
首先列出態(tài)序表,然后根據(jù)每一狀態(tài)所需要的移位輸入即反饋輸入信號,列出反饋激勵函數(shù)表,如下表所示。求得反饋激勵函數(shù):
//反饋移位型序列信號發(fā)生器
module maker(out, clk, load, D);
parameter M=4;
output out;
input clk,load;
input [M-1:0] D;
reg {M-1:0] Q;
wire w1;
always@(posedge clk)
if(load)
Q<=D;
else
Q<={Q[M-2:0],ww1};
assign w1 = (~Q[3])|((~Q[1])&(~Q[0]))|(Q[3]&(~Q[2]));
assign out =Q[M-1];
endmodule
方法(3):由計數(shù)器構(gòu)成
計數(shù)型序列信號發(fā)生器和反饋型序列信號發(fā)生器大體相同,它們都是由時序電路和組合電路兩部分構(gòu)成。不同在于,反饋型序列信號發(fā)生器的時序狀態(tài)由移位寄存器產(chǎn)生,輸出取寄存器的最高位;而在計數(shù)型序列信號發(fā)生器中,采用計數(shù)器代替移位寄存器產(chǎn)生時序狀態(tài),輸出由組合電路產(chǎn)生。
計數(shù)型的好處在于,計數(shù)器的狀態(tài)設(shè)置與輸出序列沒有直接關(guān)系,不需要像上面一樣,根據(jù)輸出確定狀態(tài)。只需要將反饋網(wǎng)絡(luò)設(shè)計好就可以了。因此計數(shù)結(jié)構(gòu)對于輸出序列的更改比較方便,而且只要連接到不同的反饋網(wǎng)絡(luò),它可以同時產(chǎn)生多組序列碼。
設(shè)計過程分為兩步:
第一,根據(jù)序列碼的長度M設(shè)計模M計數(shù)器,狀態(tài)可以自定;
第二,按計數(shù)器的狀態(tài)轉(zhuǎn)移關(guān)系和序列碼的要求設(shè)計組合輸出網(wǎng)絡(luò)。對于“ 100111 "序列的信號發(fā)生器。序列信號的M值為6,因為需選用模6的計數(shù)器。計數(shù)器的狀態(tài)選擇從000到101,可得下表。
由真值表可畫出卡諾圖,得到輸出函數(shù):
如下代碼:
module maker(OUT, clk, reset);
parameter M=3;
input clk,reset;
reg [M-1:0] counter;
always@(posedge clk)
if(!reset)
counter <= 3'b000;
else
counter <= counter + 1;
assign OUT = counter[2] | ((~counter[1])&(~counter[0])) | (counter[1]&counter[0]);
endmodule
例:設(shè)計偽隨機碼發(fā)生器
隨機碼是一種變化規(guī)律與隨機碼類似的二進制代碼,可以作為數(shù)字通信中的一個信號源,通過信道發(fā)送到接收機,用于檢測數(shù)字通信系統(tǒng)錯碼的概率,即誤碼率。
在傳統(tǒng)的數(shù)字電路設(shè)計中,偽隨機序列信號發(fā)生器是用移位存型計數(shù)器來實現(xiàn)的,反饋網(wǎng)絡(luò)輸入信號從移位寄存器的部分輸出端(QN-1 ~ Q0)中取出,它的輸出端F反饋到移位寄存器的串行輸入端。
通過不同的反饋網(wǎng)絡(luò),可以形成不同的移存型計數(shù)器。以m序列碼為例,反饋函數(shù)如下表所示,表中的N 是觸發(fā)器的級數(shù),F(xiàn)是反饋函數(shù)的列表。
例如N =4,則反饋函數(shù)如下:
以N =4為例,在15位最長線性序列移存型計數(shù)器中,有一個由"0000"構(gòu)成的死循環(huán),為了打破死循環(huán),可以修改式為:
根據(jù)N=4的最長線性序列移位寄存器計數(shù)器:
module signal(out, clk, load_n, D_load);
output out;
input load_n,clk;
input [3:0] D_load;
reg [3:0] Q;
wire F;
always@(posedge clk)
if(~load_n)
Q<=D_load;
else
Q<={Q[2:0],F};
assign F = (Q[1]^Q[0]) | (~Q[3]&~Q[2]&~Q[1]&~Q[0]);
assign out = Q[3];
endmodule
4.有限同步狀態(tài)機
有限狀態(tài)機是時序電路的通用模型,任何時序電路都可以表示為有限狀態(tài)機。有限狀態(tài)機從本質(zhì)上講是由寄存器與組合邏輯構(gòu)成的時序電路,各個狀態(tài)之間的轉(zhuǎn)移總是在時鐘的觸發(fā)下進行的,狀態(tài)信息存儲在寄存器中。因為狀態(tài)的個數(shù)是有限的所以稱為有限狀態(tài)機
。
同其它時序電路一樣,有限狀態(tài)機也是由兩部分組成:存儲電路和組合邏輯電路。存儲電路,用來生成狀態(tài)機的狀態(tài);組合邏輯電路,用來提供輸出以及狀態(tài)機跳轉(zhuǎn)的條件。
根據(jù)輸出信號的產(chǎn)生方式,有限狀態(tài)機可以分為米利型(Mealy)和摩爾型(Moore)兩類。Mealy型狀態(tài)機的輸出與當(dāng)前狀態(tài)和輸入有關(guān)系,Moore型狀態(tài)機的輸出僅依賴當(dāng)前狀態(tài)而與輸入無關(guān)。
狀態(tài)機編碼方式很多,由此產(chǎn)生的電路也不相同,常見的編碼方式有三種:二進制編碼、格雷編碼和一位獨熱編碼。
(1)二進制編碼:狀態(tài)寄存器是由觸發(fā)器組成的。N個觸發(fā)器可以構(gòu)成2n個狀態(tài)。二進制編碼的優(yōu)點是使用的觸發(fā)器個數(shù)較少,節(jié)省資源;缺點是狀態(tài)跳轉(zhuǎn)時可能有多個bit位同時變化,引起毛刺,造成邏輯錯誤。
(2)格雷編碼:格雷編碼和二進制編碼類似。格雷編碼狀態(tài)跳轉(zhuǎn)時只有一個 bit位發(fā)生變化,減少了產(chǎn)生毛刺和一些暫態(tài)的可能。
(3)One hot編碼:是對于n個狀態(tài)采用n個bit位來編碼,每個狀態(tài)編碼中只有一個bit位為1,如:0001,0010,0100,1000。One hot編碼增加了使用觸發(fā)器的個數(shù),但是這種編碼方便譯碼,可以有效地節(jié)省和化簡組合電路。
在Verilog中,有限狀態(tài)機的寫法較多,常用的有兩段式和三段式兩種。
(1)狀態(tài)機兩段式描述方式:
//第一個進程,同步時序always模塊,格式化描述次態(tài)寄存器遷移到現(xiàn)態(tài)寄存器
always@(posedge clk or negedge rst_n) //異步復(fù)位
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state; //注意,使用的是非阻塞賦值
//第二個進程,組合邏輯always模塊,描述狀態(tài)轉(zhuǎn)移條件判斷
always@(current_state) //電平觸發(fā)
begin
next state = x; //要初始化,使得系統(tǒng)復(fù)位后能進入正確的狀態(tài)
case(current_state)
S1:if(...)
next_state=S2; //阻塞賦值
out1<= 1'b1;//注意是非阻塞邏輯
...
endcase
end
(2)狀態(tài)機三段式描述方式:
//第一個進程,同步時序always模塊,格式化描述次態(tài)寄存器遷移到現(xiàn)態(tài)寄存器
always @ (posedge clk or negedge rst_n) //異步復(fù)位
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state;//注意,使用的是非阻塞賦值
//二個進程,組合邏輯always模塊,描述狀態(tài)轉(zhuǎn)移條件判斷
always @ (current_state) //電平觸發(fā)
begin
next_state=x; //要初始化,使得系統(tǒng)復(fù)位后能進入正確的狀態(tài)
case(current_state)
S1:if(...)
next_state=S2; //阻塞賦值
...
endcase
end
//第三個進程,同步時序always模塊,格式化描述次態(tài)寄存器輸出
always@(posedge clk or negedge rst_n)
...//初始化
case(next_state)
S1:
out1 <= 1'b1;//注意是非阻塞邏輯
S2:
out2 <= 1'b1;
default:... //default的作用是免除綜合工具綜合出鎖存器。
endcase
end
//三段式不一定要寫三個always塊,如果狀態(tài)機更為復(fù)雜,always塊也會相應(yīng)增加。
例:設(shè)計順序脈沖發(fā)生器
順序脈沖發(fā)生器又稱脈沖分配器,它將高電平的脈沖依次分配到不同輸出上。保證在每個時鐘內(nèi)只有一路輸出上是高電平脈沖,不同時鐘上脈沖電平依次出現(xiàn)在所有輸出。
以4位順序脈沖發(fā)生器為例,它有四路輸出W0W1W2W3,每路輸出上高電平脈沖依次出現(xiàn),輸出在1000,0100,0010,0001之間循環(huán)。4位順序脈沖發(fā)生器的狀態(tài)轉(zhuǎn)移圖。如圖,它由4 個狀態(tài)構(gòu)成,每個狀態(tài)中“1"的個數(shù)都是 1個,表示每個時鐘周期內(nèi)只有一路輸出端為高電平(脈沖),而且是輪流出現(xiàn),因此生成順序脈沖信號。
對四狀態(tài)機編碼時,只需要兩位二進制編碼即可:
module state4(out, clk);
output [3:0] out;
input clk;
reg [3:0] out;
reg [1:0] state, next_state;
always@(state)
case(state)
2'b00:
begin
out <= 4'b1000;
next_state <= 2'b01;
end
2'b01:
begin
out <= 4'b0100;
next_state <= 2'b10;
end
2'b10:
begin
out <= 4'b0010;
next_state <= 2'b11;
end
2'b00:
begin
out <= 4'b0001;
next_state <= 2'b010;
end
endcase
always@(posedge clk)
state <= next_state;
endmodule
例:設(shè)計一個賣報機,報紙價錢八角,紙幣有1角,2角,5角,一元。該賣報機不考慮投幣為大額面值等特殊情況。下圖是賣報機的狀態(tài)轉(zhuǎn)移圖,圖中S0 ~ S7 為狀態(tài)機的8個狀態(tài),角標(biāo)代表己投幣的總合,如SO代表沒有投幣,S1代表己投入1 角,依此類推。M代表輸入,M1表示投入1角硬幣,M2代表投入2角硬幣,M5代表投入5角硬幣,M10代表投入一元。
Verilog代碼:
//data_out=1表示給出報紙,data_out_return=1表示找回1角硬幣,data_out_return2=1表示找回2角硬幣
module auto_sellor(current_state,data_out, data_out_return1, data_out_retum2, clk, rst_n, data_in);
parameter state_width = 3, data_in_width = 3;
output [state_width-1:0] current_state;
output data_out, data_out_return1, data_out_return2;
input [data_in_width-1:0] data_in;
input clk, rst_n;
reg [state_width-1 :0] current_state, next_state;
reg data_out, data_out_return1, data_out_return2;
always@(current_state or rst_n)
if (!rstn)
next_statec=0;
else
case(current_state)
3'b000:
case(data_in)
3'b000:
begin
next_state <= 3'b000;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b001;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b010:
begin
next_state <= 3'b010;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b011:
begin
next_state <= 3'b101;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b100:
begin
next_state <= 3'b000;
data_out <=1'b1;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b1;
end
endcase
3'b001:
case(data_in)
3'b000:
begin
next_state <= 3'b001;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b010;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b010:
begin
next_state <= 3'b011;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b011:
begin
next_state <= 3'b110;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b010:
case(data_in)
3'b000:
begin
next_state <= 3'b010;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b011;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b010:
begin
next_state <= 3'b100;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b011:
begin
next_state <= 3'b111;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b011:
case(data_in)
3'b000:
begin
next_state <= 3'b011;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b100;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b010:
begin
next_state <= 3'b101;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b011:
begin
next_state <= 3'b000;
data_out <=1'b1;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b100:
case(data_in)
3'b000:
begin
next_state <= 3'b000;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b101;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b010:
begin
next_state <= 3'b110;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b011:
begin
next_state <= 3'b000;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b101:
case(data_in)
3'b000:
begin
next_state <= 3'b101;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b110;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b111:
begin
next_state <= 3'b011;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b011:
begin
next_state <= 3'b000;
data_out <=1'b1;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b1;
end
endcase
3'b110:
case(data_in)
3'b000:
begin
next_state <= 3'b110;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b111;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b010:
begin
next_state <= 3'b000;
data_out <=1'b1;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b111:
case(data_in)
3'b000:
begin
next_state <= 3'b111;
data_out <=1'b0;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
3'b001:
begin
next_state <= 3'b000;
data_out <=1'b1;
data_out_return1 <=1'b0;
data_out_return2 <= 1'b0;
end
endcase
always@(posedge clk ir rst_n)
if(!rst_n)
current_state <= 3'b000;
else
current_state <= next_state;
endmodule
例:"11010"序列檢測器
序列檢測器就是將一個指定的序列從數(shù)字碼流中檢測出來。當(dāng)輸入端出現(xiàn)序列11010時,輸出為1,否則輸出為0。在此不考慮重復(fù)序列,即出現(xiàn)指定序列后就重新開始序列檢測,不再考慮以前的數(shù)據(jù)。規(guī)定數(shù)據(jù)從右端輸入,即按照1-1-0-1-0的順序輸入。該序列檢測器的狀態(tài)轉(zhuǎn)移圖如下:文章來源:http://www.zghlxwxcb.cn/news/detail-404271.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-404271.html
module seqdet(dout,din,restn,clk);
parameter IDLE = 3'd0, A = 3'd1, B = 3'd3, C = 3'd4, E = 3'd5;
output dout;
input din,rstn,clk;
reg[2:0] state,next_state;
wire dout;
assign dout = (state==E)?1:0;
always@(posedge clk or negedge rstn)
if(!rstn)
state = IDLE;
else
case(state)
IDLE:
if(din)
next_state = A;
else
next_state = IDLE;
A:
if(din)
next_state = B;
else
next_state = IDLE;
B:
if(din)
next_state = B;
else
next_state = C;
C:
if(din)
next_state = D;
else
next_state = IDLE;
D:
if(din)
next_state = B;
else
next_state = IDLE;
E:
if(din)
next_state = IDLE;
else
next_state = A;
default:
next_state = IDLE;
endcase
always@(posedge clk)
state <= next_state;
endmodule
來源:蔡覺平老師的Verilog課程
到了這里,關(guān)于Verilog學(xué)習(xí)筆記(3):Verilog數(shù)字邏輯電路設(shè)計方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!