Verilog入门设计(一)——基本组合电路设计
一、门电路
1、基本门电路
module gate1(a,b,c,d,f);
input a,b,c,d;
output f;
nand(s1,a,b);
and(s2,b,c,d);
or(f,s1,s2);
endmodule
(2)数据流描述
module gate2(f,a,b,c,d);
input a,b,c,d;
output f;
assign f=(~(a&b))|(b&c&d);
endmodule
(3)行为描述
module gate3(f,a,b,c,d);
input a,b,c,d;
output f;reg f;
always@(a or b or c or d)
begin
f=(~(a&b))|(b&c&d);
end
endmodule
2、三态门
三态:即高电平、低电平和高阻态。三态门是普通门的基础上加上控制端构成的,在需要信息传输的地方,三态门是必须的。下面以几种方式描述三态门。
(1)行为描述的三态门
module tri_gate1(out,en,in);
input en,in;
output out; reg out;
always@(en,in)
begin
if(en) out<=in;
else out<=1'bz;
end
endmodule
当en控制端为高电平时,out=in(即高、低电平态);当en为低电平时,out为高阻态。
(2)调用门元件bufif1描述的三态门
module tri_gate2(out,en,in);
input en,in;
output out; tri out; //out声明为tri表示out综合后的电路连接具有三态功能
bufif1(out,in,en); //三态门端口顺序:输出、输入、控制端
endmodule
(3)数据流描述三态门
module tri_gate3(out,en,in);
input en,in;
output out;
assign out=en?in:'bz;
endmodule
3、三态双向驱动器
双向表示既可作输入、又可作输出。下面例举两个example说明三态驱动器的Verilog设计。
(1)数据流描述(使用assign 持续赋值语句)
//三态双向驱动器
module bidir(tri_out,out,in,en,b);
input in,en,b;
output out;
inout tri_out;
assign tri_out=en?in:'bz;
assign out=b^tri_out;
endmodule
- 当en=1,tri_out=in,即此时tri_out为输出端口;tri_out的状态可为高电平和低电平状态。
- 当en=0,tri_out为高阻态,out=b^tri_out。因为out的两个输入信号有一个为高阻态,所以out输出为不确定状态。
(2)行为+数据流描述(使用always过程语句和assign持续赋值语句)
module bidir2(bidir,en,clk);
input en,clk;
inout[7:0] bidir;reg[7:0] temp;
assign bidir=en?temp:8'bz; //bidir作为输入
always@(posedge clk)
begin if(en) temp=bidir; //bidir作为输出
else temp=temp+1; //改变输入、输出值
end
endmodule
二、编码器、译码器
1、3-8译码器
3-8译码器具有3输入、8输出。译码器一般用于驱动数码管,根据数码管是共阴还是共阳的,可选择译码器是输出高电平还是低电平有效。下面的例子为输出高电平有效,若需要低电平有效只需将case语句中,8位二进制的取反(0变成1,1变成0)。
module tan_74138(cin,cout);
input[2:0] cin;
output[7:0] cout; reg[7:0] cout;
always@(cin)
begin
case(cin)
3'd0:cout=8'b00000001;
3'd1:cout=8'b00000010;
3'd2:cout=8'b00000100;
3'd3:cout=8'b00001000;
3'd4:cout=8'b00010000;
3'd5:cout=8'b00100000;
3'd6:cout=8'b01000000;
3'd7:cout=8'b10000000;
default:cout[7:0]=7'bx;
endcase
end
endmodule
2、8-3优先编码器
module encoder8_3(none_on,outcode,a,b,c,d,e,f,g,h);
input a,b,c,d,e,f,g,h;
output none_on;output[2:0] outcode;reg[3:0] outtemp;
assign {none_on,outcode}=outtemp; //none_on=1,无输入,否则有输入
always@(a or b or c or d or e or f or g or h)
begin
if(h) outtemp=4'b0111;
else if(g) outtemp=4'b0110;
else if(f) outtemp=4'b0101;
else if(e) outtemp=4'b0100;
else if(d) outtemp=4'b0011;
else if(c) outtemp=4'b0010;
else if(b) outtemp=4'b0001;
else if(a) outtemp=4'b0000;
else outtemp=4'b1000;
end
endmodule
作为条件语句,if-else语句具有优先顺序,利用这个特点,实现优先编码器的设计。在该例子中,输入为a~h,输出为outcode。输入高电平有效,根据if-else语句顺序,h的优先级最高,a的优先级最低。
3、七段数码管译码器
module decode7(decodeout,dec_in);
input[3:0] dec_in;
output[6:0] decodeout;reg[6:0] decodeout;
always@(dec_in)
begin
case(dec_in) //case语句进行译码
4'd0:decodeout=7'b1111110; //decodeout[6]~[0]分别对应数码管的a~g
4'd1:decodeout=7'b0110000;
4'd2:decodeout=7'b1101101;
4'd3:decodeout=7'b1111001;
4'd4:decodeout=7'b0110011;
4'd5:decodeout=7'b1011011;
4'd6:decodeout=7'b1011111;
4'd7:decodeout=7'b1110000;
4'd8:decodeout=7'b1111111;
4'd9:decodeout=7'b1111011;
default:decodeout=7'bx;
endcase
end
endmodule
4、奇偶校验位产生器
module parity(even_bit,odd_bit,input_bus);
input[7:0] input_bus;
output even_bit,odd_bit;
assign odd_bit=^input_bus; //产生奇检验位
assign even_bit=~odd_bit; //产生偶检验位
endmodule
计检验位产生原理:
odd_bit等于input_bus各位异或的结果。
例如:input_bus=00000001,则:
odd_bit=((((((0^0)^0)^0)^0)^0)^0)^1=1
如果input_bus的各位1的个数为奇数,则odd_bit=1,否则odd_bit=0,因为1的数量不是奇数就是偶数。所以偶校验位:even_bit=~odd_bit;
三、数据选择器
以4选1数据选择器为例,有4个输入端口,一个2位选择控制端,一个输出端。
(1)用if~else语句描述的4选1数据选择器
module mux4_1
(
input in1,in2,in3,in4,
input[1:0] sel,
output reg out
);
always@(in1,in2,in3,in4,sel)
begin
if(sel==2'b00)
out=in1;
else if(sel==2'b01)
out=in2;
else if(sel==2'b10)
out=in3;
else
out=in4;
end
endmodule
(2)用case语句描述的4选1数据选择器
module mux4_1
(
input in1,in2,in3,in4,
input[1:0] sel,
output reg out
);
always@(in1,in2,in3,in4,sel)
begin case(sel)
2'b00: out=in1;
2'b01: out=in2;
2'b10: out=in3;
default: out=in4;
endcase
end
endmodule
四、其他组合电路
下面的例子是用组合电路实现的ROM,该存储器用16个存储单元存储了16个结果,分别是0~15共16个数的平方,根据地址输出相应的结果。
module rom
(
input[3:0] addr,
output[7:0] data
);
function[7:0] romout;
input[3:0] addr;
case(addr)
0:romout=0;
1:romout=1;
2:romout=4;
3:romout=9;
4:romout=16;
5:romout=25;
6:romout=36;
7:romout=49;
8:romout=64;
9:romout=81;
10:romout=100;
11:romout=121;
12:romout=144;
13:romout=169;
14:romout=196;
15:romout=215;
16:romout=256;
default:romout=8'hxx;
endcase
endfunction
assign data=romout(addr);
endmodule