前言
剛學前端設計的時候,聽到的就是組合邏輯、時序邏輯,很重要!但是究竟有什麼用?到底怎麼展現,沒有多少老師可以明确指出來,當自己看的東西多了,就可以了解了,甚至可以得出自己的範式。
到目前為止,要想掌握組合邏輯,就請先掌握本文列出的編碼器、譯碼器、資料選擇器、加法器等簡單的組合邏輯電路。
1.編碼器和譯碼器
剛開始聽verilog的時候,估計都聽過3-8譯碼器,但是聽過編碼器嗎?
編碼器和譯碼器可以将不同輸入資料變換為不同的輸出資料。
編碼器的資料輸入比編碼後的輸出位數大,編碼器常用來減少資料通道數目;而譯碼器與之相反。
1.1 編碼器
編碼器把輸入信号編寫成一個對應的二進制信号,即把2^N個輸入信号轉化為N位編碼輸出。還可以分為:普通編碼器和優先編碼器。
普通編碼器:隻能一個一個的輸入,如果同時輸入兩個信号,編碼器不能識别;
優先編碼器:如果輸入兩個信号,對高位優先識别。(聯想if-else的優先級)
1.1.1 8-3普通編碼器
8-3普通編碼器功能真值表
設計代碼code8_3.v
module code8_3(
I,
O
);
input [7:0] I;
output [2:0] O;
reg [2:0] O;
[email protected](I)
begin
case(I)
8'b0000_0001:O = 3'b111;
8'b0000_0010:O = 3'b110;
8'b0000_0100:O = 3'b101;
8'b0000_1000:O = 3'b100;
8'b0001_0000:O = 3'b011;
8'b0010_0000:O = 3'b010;
8'b0100_0000:O = 3'b001;
8'b1000_0000:O = 3'b000;
default: O=3'bxxx;
endcase
end
endmodule
仿真檔案code8_3_tb.v
`timescale 1ns/1ns
`define clk_period 20
module code8_3_tb;
reg [7:0] I;
wire [2:0] O;
reg clk;
code8_3 code8_3_inst(
.I(I),
.O(O)
);
initial clk = 1'b1;
always #`clk_period clk = ~clk;
initial begin
I = 8'b0000_0001;
#`clk_period;
I = 8'b0000_0010;
#`clk_period;
I = 8'b0000_0100;
#`clk_period;
I = 8'b0000_1000;
#`clk_period;
I = 8'b0001_0000;
#`clk_period;
I = 8'b0010_0000;
#`clk_period ;
I = 8'b0100_0000;
#`clk_period;
I = 8'b1000_0000;
#`clk_period;
I = 8'b0000_0000;
#`clk_period;
$stop;
end
endmodule
功能仿真
1.1.1 8-3優先編碼器
詳細介紹見:優先級編碼器74LS148的電路結構、工作原理及使用方法
8-3優先編碼器功能真值表
上面這個真值表有問題,在網上找到了下面這一個。
8-3優先編碼器的邏輯符号
設計代碼code_8_3.v
module code_8_3(
EI_n,
I,
Y,
GS_n,
EO_n
);
input EI_n;
input [7:0] I;
output [2:0] Y;
output GS_n;
output EO_n;
reg [2:0] Y;
reg GS_n;
reg EO_n;
[email protected](EI_n or I)
begin
if(!EI_n)begin
if (~I[7]) begin Y = 3'd0;EO_n = 1;GS_n = 0;end
else if (~I[6]) begin Y = 3'd1;EO_n = 1;GS_n = 0;end
else if (~I[5]) begin Y = 3'd2;EO_n = 1;GS_n = 0;end
else if (~I[4]) begin Y = 3'd3;EO_n = 1;GS_n = 0;end
else if (~I[3]) begin Y = 3'd4;EO_n = 1;GS_n = 0;end
else if (~I[2]) begin Y = 3'd5;EO_n = 1;GS_n = 0;end
else if (~I[1]) begin Y = 3'd6;EO_n = 1;GS_n = 0;end
else if (~I[0]) begin Y = 3'd7;EO_n = 1;GS_n = 0;end
else begin Y = 3'd7;EO_n = 0;GS_n = 1;end
end
else begin Y = 3'd7;EO_n = 1;GS_n = 1;end
end
endmodule
仿真檔案code_8_3_tb.v
`timescale 1ns/1ns
`define clk_period 20
module code_8_3_tb;
reg EI_n;
reg [7:0] I;
wire [2:0] Y;
wire GS_n;
wire EO_n;
reg clk;
code_8_3 code_8_3_inst(
.EI_n(EI_n),
.I(I),
.Y(Y),
.GS_n(GS_n),
.EO_n(EO_n)
);
initial clk = 1'b1;
always #`clk_period clk = ~clk;
initial begin
EI_n = 1'b1;
I = 8'b1101_1111;
#`clk_period;
EI_n = 1'b0;
I = 8'b1111_1110;
#`clk_period;
I = 8'b0111_1101;
#`clk_period;
I = 8'b1010_1010;
#`clk_period;
I = 8'b1100_1111;
#`clk_period;
I = 8'b1111_1111;
#`clk_period ;
I = 8'b1110_0100;
#`clk_period;
I = 8'b1111_1111;
#`clk_period;
I = 8'b1110_0100;
#`clk_period;
I = 8'b1110_0110;
#`clk_period;
I = 8'b1111_1010;
#`clk_period;
I = 8'b1111_1100;
#`clk_period;
$stop;
end
endmodule
功能仿真
1.2 譯碼器
從電路功能上看,譯碼器和編碼器沒有實質的差别。
編碼器把輸入信号編寫成一個對應的二進制信号,即把2^N個輸入信号轉化為N位編碼輸出。
而譯碼器是把輸入的N位二進制信号轉換成2^N個代表代碼原意的狀态信号并輸出。
1.2.1 3-8譯碼器74LS138邏輯符号
3-8譯碼器74LS138的功能真值表
設計代碼decoder3_8
module decoder3_8(
Y,
S,
A
);
output [7:0] Y;
input [2:0] S;
input [2:0] A;
reg [7:0] Y;
[email protected](*)
begin
if(S[0] & (S[1]==0) & (S[2]==0))begin
case(A)
3'b000:Y = 8'b1111_1110;
3'b001:Y = 8'b1111_1101;
3'b010:Y = 8'b1111_1011;
3'b011:Y = 8'b1111_0111;
3'b100:Y = 8'b1110_1111;
3'b101:Y = 8'b1101_1111;
3'b110:Y = 8'b1011_1111;
3'b111:Y = 8'b0111_1111;
default Y=8'bX;
endcase
end
else Y = 8'b1111_1111;
end
endmodule
仿真檔案decoder3_8_tb.v
`timescale 1ns/1ns
module decoder3_8_tb;
wire [7:0] Y;
reg [2:0] S;
reg [2:0] A;
decoder3_8 decoder3_8_tb(
.Y(Y),
.S(S),
.A(A)
);
initial begin
A = 3'b000;
S = 3'b000;
#20;
A = 3'b001;
S = 3'b010;
#20;
A = 3'b000;
S = 3'b001;
#20;
A = 3'b001;
#20;
A = 3'b010;
#20;
A = 3'b011;
#20;
A = 3'b100;
#20 ;
A = 3'b101;
#20;
A = 3'b110;
#20;
A = 3'b111;
#20;
A = 3'b000;
#20;
$stop;
end
endmodule
功能仿真
在做前面幾個仿真檔案時,出現了時鐘,到這裡突然意識到,組合邏輯仿真時不必引入時鐘,隻需要利用延遲就可以得出仿真結果。
1.2.2 顯示譯碼器
請點選檢視譯碼器和資料選擇器
2.資料選擇器
4選1資料選擇器的邏輯符号
4選1資料選擇器的功能真值表
輸入S1 | 輸入S0 | 輸出Y |
---|---|---|
D0 | ||
1 | D1 | |
1 | D2 | |
1 | 1 | D3 |
4選1選擇器原理圖
4選1資料選擇器的三種模組化方式
(1)門級模組化MUX4_1a.v
module MUX4_1a(
D0,D1,D2,D3,
S0,S1,
Y
);
input D0,D1,D2,D3;
input S0,S1;
output Y;
wire notS0,notS1,Y0,Y1,Y2,Y3,Y4;
not not0(notS0,S0);
not not1(notS1,S1);
and and0(Y0,notS0,notS1,D0);
and and1(Y1,notS0,S1,D1);
and and2(Y2,S0,notS1,D2);
and and3(Y3,S0,S1,D3);
or or1(Y,Y0,Y1,Y2,Y3);
endmodule
綜合出來的電路
(2)資料流級模組化
assign語句描述出來的MUX4_1c.v
module MUX4_1b(
D0,D1,D2,D3,
S0,S1,
Y
);
input D0,D1,D2,D3;
input S0,S1;
output Y;
assign Y = ((D0 & ~S0 & ~S1)|(D1 & ~S0 & S1)|(D2 & S0 & ~S1)|(D3 & S0 & S1));
endmodule
綜合出來的電路
——條件表達式描述MUX4_1c.v
module MUX4_1c(
D0,D1,D2,D3,
S0,S1,
Y
);
input D0,D1,D2,D3;
input S0,S1;
output Y;
assign Y = S1?(S0?D3:D2):(S0?D1:D0);
endmodule
綜合出來的電路
(3)行為級模組化
——采用了if-else結構的MUX4_1d.v
module MUX4_1d(
D0,D1,D2,D3,
S0,S1,
Y
);
input D0,D1,D2,D3;
input S0,S1;
output Y;
reg Y;
//采用了if-else結構
[email protected](D0 or D1 or D2 or D3 or S0 or S1)
begin
if ({S1,S0}==2'b00) Y=D0;
else if ({S1,S0}==2'b01) Y=D1;
else if ({S1,S0}==2'b10) Y=D2;
else if ({S1,S0}==2'b11) Y=D3;
else Y=1'bx;
end
endmodule
if-else結構綜合出來的電路
——采用了case語句的MUX4_1e.v
module MUX4_1e(
D0,D1,D2,D3,
S0,S1,
Y
);
input D0,D1,D2,D3;
input S0,S1;
output Y;
reg Y;
//采用了case結構
[email protected](D0 or D1 or D2 or D3 or S0 or S1)
begin
case({S1,S0})
2'b00:Y=D0;
2'b01:Y=D1;
2'b10:Y=D2;
2'b11:Y=D3;
default: Y=1'bx;
endcase
end
endmodule
case語句綜合出來的電路
随着資料選擇器的輸入增多,if-else和case綜合出來的電路差異就很大。這種情況下就推薦使用case語句。
3.加法器
加法運算是最基本的運算,簡單的乘法、除法、減法和複雜的FFT(快速傅裡葉變換)都可以分解為加法運算。
點選閱讀筆記連載 | Day7 【半加器、全加器、16位加法器、16位減法器設計】 【原理及verilog實作、仿真】篇
3.1半加器
半加器,就是y=a+b,不考慮進位,如下真值表,a、b表示2個相加的數,y表示和,Co表示結果有沒有進位。
從真值表可以得出,y和Co的布爾表達式
Y = (~a&b) | (a&~b)
Co = a&b
設計代碼half_adder.v
module half_adder(
input a, //第一個加數a
input b, //第二個加數b
output sum, //和
output cout //位
);
assign sum=a ^ b; //sum=a⊕b
assign cout=a & b; //cout=ab
endmodule
綜合出來的電路圖
3.2全加器
強烈推薦閱讀:Verilog全加器
全加器,就是y=a+b+c_up,要考慮進位,如下真值表,a、b表示2個相加的數,c_up表示低位向本位的進位标志,Co表示計算結果有沒有向高位進位
從真值表可以得出,y和Co的布爾表達式
y = (~a&~b&c_up) | (~a&b&~c_up) | (a&~b&~c_up) | (a&b&c_up)
Co = (~a&b&c_up) | (a&~b&c_up) | (a&b&~c_up) | (a&b&c_up)
3.3減法器
減法器,就是y=a-b-c_down,要考慮借位,如下真值表,a、b表示2個相減的數,c_down低位向本位的借位标志,Co表示計算結果有沒有向高位借位
從真值表可以得出,y和Co的布爾表達式
y = (~a&~b&c_down) | (~a&b&~c_down) | (a&~b&~c_down) | (a&b&c_down)
C0 = (~a&~b&c_down) | (~a&b&~c_down) | (~a&b&c_down) | (a&b&c_down)
3.4級聯加法器
3.5超前進位加法器
4.乘法器
4.1 移位相加乘法器
4.2 并行乘法器
5.其他組合邏輯
5.1 基本門電路
二輸入與非門真值表
輸入a | 輸入b | 輸出F |
---|---|---|
1 | ||
1 | 1 | |
1 | 1 | |
1 | 1 |
二輸入與非門邏輯符号
資料流級描述二輸入與非門
module nand_2(
a,
b,
F
);
input a;
input b;
output F;
assign F = ~(a&b);
endmodule
行為級描述二輸入與非門
module nand_2(
a,
b,
F
);
input a;
input b;
output F;
reg F;
[email protected](a or b)
begin
if( a==1'b1 && b==1'b1)
F = 0;
else
F = 1;
end
endmodule
5.2 三态門電路
三态門大多數挂在總線上,以實作不同數字部件之間的資料傳輸。
三态門是在普通電路的基礎上附加控制電路,進而使得門電路的輸出端除了輸出高電平、低電平外,還可以出現第三種狀态,即高阻狀态(或稱禁止态)。
三态門的邏輯符号
din為資料輸入端,dout為資料輸出端,en為控制輸入端。
三态門的真值表
資料輸入 | 控制輸入端 | 資料輸出 |
---|---|---|
din | en | dout |
x | z | |
1 | ||
1 | 1 | 1 |
行為級描述三态門
module tri_gate(
din,
en,
dout
);
input din;
input en;
output dout;
reg dout;
[email protected](din or en)
begin
if(en)
dout = din;
else
dout = 1'bz;
end
endmodule
行為級描述綜合出來的電路如下:
資料流級描述三态門
module tri_gate(
din,
en,
dout
);
input din;
input en;
output dout;
assign dout=en?din:1'bz;
endmodule
資料流級描述綜合出來的電路如下:
(和上面的一樣)