VHDL設(shè)計(jì)進(jìn)階:邏輯綜合的原則以及可綜合的代碼設(shè)計(jì)風(fēng)格
4.5.1 always塊語(yǔ)言指導(dǎo)原則
本文引用地址:http://butianyuan.cn/article/201610/308583.htm使用always塊進(jìn)行可綜合的代碼設(shè)計(jì)時(shí)需要注意以下幾個(gè)問題。
(1)每個(gè)always塊只能有一個(gè)事件控制“@(event-expression)”,而且要緊跟在always關(guān)鍵字后面。
(2)always塊可以表示時(shí)序邏輯或者組合邏輯,也可以用always塊既表示電平敏感的透明鎖存器又同時(shí)表示組合邏輯。但是不推薦使用這種描述方法,因?yàn)檫@容易產(chǎn)生錯(cuò)誤和多余的電平敏感的透明鎖存器。
(3) 帶有posedge 或 negedge 關(guān)鍵字的事件表達(dá)式表示沿觸發(fā)的時(shí)序邏輯;沒有posedge 或negedge關(guān)鍵字的表示組合邏輯或電平敏感的鎖存器,或者兩種都表示。在表示時(shí)序和組合邏輯的事件控制表達(dá)式中如有多個(gè)沿和多個(gè)電平,其間必須用關(guān)鍵字“or” 連接 。
(4)每個(gè)表示時(shí)序邏輯的always塊只能由一個(gè)時(shí)鐘跳變沿觸發(fā),置位或復(fù)位最好也由該時(shí)鐘跳變沿觸發(fā)。
(5)每個(gè)在always塊中賦值的信號(hào)都必需定義成reg型或整型。整型變量缺省為32bit,使用Verilog操作符可對(duì)其進(jìn)行二進(jìn)制求補(bǔ)的算術(shù)運(yùn)算。綜合器還支持整型量的范圍說明,這樣就允許產(chǎn)生不是32位的整型量,句法結(jié)構(gòu)如下:
integer[
(6)always塊中應(yīng)該避免組合反饋回路。每次執(zhí)行always塊時(shí),在生成組合邏輯的always塊中賦值的所有信號(hào)必需都有明確的值;否則需要設(shè)計(jì)者在設(shè)計(jì)中加入電平敏感的鎖存器來保持賦值前的最后一個(gè)值。
只有這樣,綜合器才能正常生成電路。如果不這樣做,綜合器會(huì)發(fā)出警告,提示設(shè)計(jì)中插入了鎖存器。如果在設(shè)計(jì)中存在綜合器認(rèn)為不是電平敏感鎖存器的組合回路時(shí),綜合器會(huì)發(fā)出錯(cuò)誤信息(例如設(shè)計(jì)中有異步狀態(tài)機(jī)時(shí))。
用always塊設(shè)計(jì)純組合邏輯電路時(shí),在生成組合邏輯的always塊中,參與賦值的所有信號(hào)都必須有明確的值,即在賦值表達(dá)式右端參與賦值的信號(hào)都必需在always @(敏感電平列表)中列出。
如果在賦值表達(dá)式右端引用了敏感電平列表中沒有列出的信號(hào),那么在綜合時(shí),將會(huì)為該信號(hào)產(chǎn)生一個(gè)隱含的透明鎖存器。這是因?yàn)樵撔盘?hào)的變化不會(huì)立刻引起所賦值的變化,而必須等到敏感電平列表中某一個(gè)信號(hào)變化時(shí),它的作用才顯現(xiàn)出來。
也就是相當(dāng)于存在著一個(gè)透明鎖存器把該信號(hào)的變化暫存起來,待敏感電平列表中某一個(gè)信號(hào)變化時(shí)再起作用,純組合邏輯電路不可能做到這一點(diǎn)。這樣,綜合后所得電路已經(jīng)不是純組合邏輯電路了。這時(shí)綜合器會(huì)發(fā)出警告提示設(shè)計(jì)中插入了鎖存器,如下所示:
input a,b,c;
reg e,d;
always @(a or b or c) begin
e = d a b; //因?yàn)閐沒有在敏感電平列表中,所以d變化時(shí),e不能立刻變化,
//要等到a或b或c變化時(shí)才體現(xiàn)出來。這就是說實(shí)際上相當(dāng)于存在
//一個(gè)電平敏感的透明鎖存器在起作用, 把d信號(hào)的變化鎖存其中
d = e | c;
end
(7)對(duì)一個(gè)寄存器型(reg)或整型(integer)變量的賦值只允許在一個(gè)always塊內(nèi)進(jìn)行,如果在另一always塊也對(duì)其賦值,這是非法的。
(8)把某一信號(hào)值賦為'bx,綜合器就把它解釋成無(wú)關(guān)狀態(tài),因而綜合器為其生成的硬件電路最簡(jiǎn)潔。
4.5.2 可綜合風(fēng)格的Verilog HDL模塊實(shí)例
1.組合邏輯電路設(shè)計(jì)實(shí)例
例4.6:8位帶進(jìn)位端的加法器的設(shè)計(jì)實(shí)例(利用簡(jiǎn)單的算法描述)。
module adder_8(cout,sum,a,b,cin); //模塊聲明
output cout;
output [7:0] sum;
input cin;
input[7:0] a,b; //端口聲明
assign {cout,sum} = a + b + cin; //加法器算法
endmodule
例4.7:指令譯碼電路的設(shè)計(jì)實(shí)例(利用電平敏感的always塊來設(shè)計(jì)組合邏輯)。
'define plus 3'd0 //操作碼的宏定義
'define minus 3'd1
'define band 3'd2
'define bor 3'd3'
'define unegate 3'd4
module alu(out,opcode,a,b); //模塊聲明
output [7:0] out;
input [2:0] opcode;
input [7:0] a,b; //端口聲明
reg [7:0] out; //寄存器聲明
always @(opcode or a or b) begin //用電平敏感的always塊描述組合邏輯
case(opcode)
'plus: out = a + b; //算術(shù)運(yùn)算
'minus: out = a - b;
'band: out = a b; //位運(yùn)算
'bor: out = a | b;
'unegate: out = ~a; //單目運(yùn)算
default: out = 8'hx;
endcase
end
endmodule
例4.8:比較后重組信號(hào)的組合邏輯(利用task和電平敏感的always塊設(shè)計(jì))。
module sort4(ra,rb,rc,rd,a,b,c,d); //模塊聲明
output [t:0] ra, rb, rc, rd;
input [t:0] a, b, c, d; //端口聲明
reg [t:0] ra, rb, rc, rd;
reg [t:0] va, vb, vc, vd; //寄存器聲明
parameter t=3; //參數(shù)聲明
always @(a or b or c or d) begin //用電平敏感的always塊描述組合邏輯
{va,vb,vc,vd}={a,b,c,d};
sort2(va,vc); //信號(hào)重組
sort2(vb,vd);
sort2(va,vb);
sort2(vc,vd);
sort2(vb,vc);
{ra,rb,rc,rd}={va,vb,vc,vd};
end
task sort2; //x與y互換任務(wù)
inout [t:0] x,y;
reg [t:0] tmp;
if(x > y) begin
tmp = x; //使用臨時(shí)變量tmp保存x的值
x = y;
y = tmp;
end
endtask
endmodule
例4.9:比較器的設(shè)計(jì)實(shí)例(利用賦值語(yǔ)句設(shè)計(jì)組合邏輯)。
module compare(equal,a,b); //模塊聲明
output equal;
input [size-1:0] a,b; //端口聲明
parameter size=1; //參數(shù)聲明
assign equal =(a==b)? 1 : 0; //比較器
endmodule
例4.10:3-8譯碼器設(shè)計(jì)實(shí)例(利用賦值語(yǔ)句設(shè)計(jì)組合邏輯)。
module decoder(out,in); //模塊聲明
output [7:0] out;
input [2:0] in; //端口聲明
assign out = 1'b1in; //把最低位的1左移 in(根據(jù)從in口輸入的值)位
//將移位結(jié)果賦予out
endmodule
例4.11:3-8編碼器的設(shè)計(jì)實(shí)例。
編碼器設(shè)計(jì)方案一。
module encoder1(none_on,out,in); //模塊聲明
output none_on;
output [2:0] out;
input [7:0] in; //端口聲明
reg [2:0] out;
reg none_on; //寄存器聲明
always @(in) begin: local //in有變化時(shí),觸發(fā)
integer i; //變量聲明
out = 0;
none_on = 1; //初始化
for( i=0; i8; i=i+1 ) begin //for循環(huán)語(yǔ)句
if( in[i] ) begin //將in中值為1的位編碼
out = i;
none_on = 0;
end
end
end
endmodule
編碼器設(shè)計(jì)方案二。
module encoder2 ( none_on,out2,out1,out0,h,g,f,e,d,c,b,a); //模塊聲明
input h,g,f,e,d,c,b,a;
output none_on,out2,out1,out0; //端口聲明
wire [3:0] outvec; //向量聲明
assign outvec = //使用assign語(yǔ)句實(shí)現(xiàn)輸出向量賦值
h ? 4'b0111 : g ? 4'b0110 : f ? 4'b0101:
e ? 4'b0100 : d ? 4'b0011 : c ? 4'b0010 :
b ? 4'b0001 : a ? 4'b0000 : 4'b1000;
assign none_on = outvec[3]; //使用assign語(yǔ)句進(jìn)行編碼
assign out2 = outvec[2];
assign out1 = outvec[1];
assign out0 = outvec[0];
endmodule
編碼器設(shè)計(jì)方案三。
module encoder3 ( none_on,out2,out1,out0,h,g,f,e,d,c,b,a); //模塊聲明
input h,g,f,e,d,c,b,a;
output none_on,out2,out1,out0; //端口聲明
wire [3:0] outvec; //向量聲明
assign {none_on,out2,out1,out0} = outvec; //與上例的編碼方式一致
always @( a or b or c or d or e or f or g or h) begin
if(h) outvec=4'b0111; //使用if_else語(yǔ)句實(shí)現(xiàn)向量賦值
else if(g) outvec=4'b0110; //共9個(gè)分支,其中向量的低3位有8種編碼方式
else if(f) outvec=4'b0101;
else if(e) outvec=4'b0100;
else if(d) outvec=4'b0011;
else if(c) outvec=4'b0010;
else if(b) outvec=4'b0001;
else if(a) outvec=4'b0000;
else outvec=4'b1000;
end
endmodule
例4.12:多路器的設(shè)計(jì)實(shí)例。
使用assign賦值語(yǔ)句、case語(yǔ)句或if-else語(yǔ)句可以生成多路器電路。如果條件語(yǔ)句(case或if-else)中分支條件是互斥的話,綜合器能自動(dòng)地生成并行的多路器。
多路器設(shè)計(jì)方案一。
modul emux1(out,a,b,sel); //模塊聲明
output out;
input a,b,sel; //端口聲明
//使用assign語(yǔ)句檢查輸入信號(hào)sel的值
assign out = sel ? a : b; //當(dāng)sel為1時(shí),out為a;否則為b
endmodule
多路器設(shè)計(jì)方案二。
module mux2( out,a,b,sel); //模塊聲明
output out;
input a,b,sel; //端口聲明
reg out;
always @(a or b or sel) begin //用電平觸發(fā)的always塊來設(shè)計(jì)多路器的組合邏輯
case( sel ) //使用case語(yǔ)句檢查輸入信號(hào)sel的值
1'b1: out = a; //如果為1,輸出out為a
1'b0: out = b; //如果為0,輸出out為b
default: out = 'bx; //默認(rèn)狀態(tài)
endcase
end
endmodule
多路器設(shè)計(jì)方案三。
module mux3( out,a,b sel); //模塊聲明
output out;
input a, b, sel; //端口聲明
reg out;
always @( a or b or sel ) begin
if( sel ) //使用if_else語(yǔ)句檢查輸入信號(hào)sel的值
out = a; //如果為1,輸出out為a
else
out = b; //如果為0,輸出out為b
end
endmodule
例4.13:奇偶校驗(yàn)位生成器設(shè)計(jì)實(shí)例。
module parity( even_numbits,odd_numbits,input_bus); //模塊聲明
output even_numbits, odd_numbits;
input [7:0] input_bus; //端口聲明
assign odd_numbits = ^input_bus; //當(dāng)input_bus中1的個(gè)數(shù)為奇數(shù)時(shí),輸出為1
assign even_numbits = ~odd_numbits; //此時(shí)輸出even_numbits為0
endmodule
例4.14:三態(tài)輸出驅(qū)動(dòng)器設(shè)計(jì)實(shí)例(用連續(xù)賦值語(yǔ)句建立三態(tài)門模型)。
三態(tài)輸出驅(qū)動(dòng)器設(shè)計(jì)方案一。
module trist1( out,in,enable); //模塊聲明
output out;
input in, enable; //端口聲明
assign out = enable? in: 'bz; //使用assign語(yǔ)句判斷enable的值
endmodule
三態(tài)輸出驅(qū)動(dòng)器設(shè)計(jì)方案二。
module trist2( out,in,enable ); //模塊聲明
output out;
input in,enable; //端口聲明
bufif1 mybuf1(out, in, enable); //bufif1是一個(gè) Verilog門級(jí)原語(yǔ)(primitive)
//通過實(shí)例化該原語(yǔ),實(shí)現(xiàn)三態(tài)門的調(diào)用
endmodule
例4.15:三態(tài)雙向驅(qū)動(dòng)器設(shè)計(jì)實(shí)例。
module bidir(tri_inout,out,in,en,b); //模塊聲明
inout tri_inout;
output out;
input in,en,b; //端口聲明
assign tri_inout = en? in : 'bz; //三態(tài)門的輸入為in
assign out = tri_inout ^ b; //三態(tài)門的輸出為b
endmodule
2.時(shí)序邏輯電路設(shè)計(jì)實(shí)例
例4.16:觸發(fā)器設(shè)計(jì)實(shí)例。
module dff( q,data,clk); //模塊聲明
output q;
input data,clk; //端口聲明
reg q;
always @( posedge clk ) begin //邊緣檢測(cè)
q = data; //通過always語(yǔ)句,實(shí)現(xiàn)觸發(fā)器
end
endmodule
例4.17:電平敏感型鎖存器設(shè)計(jì)實(shí)例一(assign語(yǔ)句)。
module latch1( q,data,clk); //模塊聲明
output q;
input data,clk; //端口聲明
assign q = clk ? data : q; //通過assign語(yǔ)句,實(shí)現(xiàn)的是一個(gè)鎖存器
endmodule
例4.18:帶置位和復(fù)位端的電平敏感型鎖存器設(shè)計(jì)實(shí)例二(assign語(yǔ)句)。
module latch2( q,data,clk,set,reset); //模塊聲明
output q;
input data,clk,set,reset; //端口聲明
assign q= reset ? 0 : ( set? 1:(clk? data : q ) );
//通過assign語(yǔ)句,實(shí)現(xiàn)的是一個(gè)鎖存器
//其中,set為置位端,reset為復(fù)位端
//在clk為高電平時(shí),鎖存data,否則保持q值
endmodule
例4.19:電平敏感型鎖存器設(shè)計(jì)實(shí)例三(always塊)。
module latch3( q, data, clk); //模塊聲明
output q;
input data,clk; //端口聲明
reg q;
always @(clk or data) begin //電平檢測(cè)
if(clk) //clk為高電平時(shí),q鎖存data值
q = data;
end
endmodule
注意 有的綜合器會(huì)產(chǎn)生一個(gè)警告信息,提示將產(chǎn)生了一個(gè)電平敏感型鎖存器。因?yàn)榇死性O(shè)計(jì)的就是一個(gè)電平敏感型鎖存器,所以這個(gè)警告信息是沒有問題的。
例4.20:移位寄存器設(shè)計(jì)實(shí)例。
module shifter( din,clk,clr,dout); //模塊聲明
input din,clk,clr;
output [7:0] dout; //端口聲明
reg [7:0] dout;
always @(posedge clk) begin
if(clr) //清零
dout = 8'b0;
else begin
dout = dout1; //左移一位
dout[0] = din; //把輸入信號(hào)放入寄存器的最低位
end
end
endmodule
例4.21:8位計(jì)數(shù)器設(shè)計(jì)實(shí)例一。
module counter1( out, cout, data, load, cin, clk); //模塊聲明
output [7:0] out;
output cout;
input [7:0] data;
input load, cin, clk; //端口聲明
reg [7:0] out;
always @(posedge clk) begin //邊緣檢測(cè)
if( load ) //加載信號(hào)檢測(cè)
out = data;
else
out = out + cin;
end
assign cout= out cin; //只有當(dāng)out[7:0]的所有各位都為1
//并且進(jìn)位cin也為1時(shí)才能產(chǎn)生進(jìn)位cout
endmodule
例4.22:8位計(jì)數(shù)器設(shè)計(jì)實(shí)例二。
module counter2( out, cout, data, load, cin, clk); //模塊聲明
output [7:0] out;
output cout;
input [7:0] data;
input load, cin, clk; //端口聲明
reg [7:0] out;
reg cout;
reg [7:0] preout; //寄存器聲明
always @(posedge clk) begin //邊緣檢測(cè)
out = preout; //觸發(fā)器
end
//計(jì)算計(jì)數(shù)器和進(jìn)位的下一個(gè)狀態(tài),為提高性能,load不應(yīng)影響進(jìn)位
always @( out or data or load or cin ) begin
{cout, preout} = out + cin; //進(jìn)位操作
if(load) preout = data; //判斷加載信號(hào)
end
endmodule
評(píng)論