EDA实验汇总
EDA实验汇总
实验1_简单组合电路的设计
2选1
module mux21a(a, b, s, y);
input a, b, s;
output y;
assign y = s ? a : b;
endmodule
思考题
1-1、用 Verilog 设计一个 3 选 1 多路选择器,并在软件上进行仿真,得出仿真波形。
// 3选1
// 多了一个 2 位的标志位,可以取4种情况
module mux31a(a, b, c, flag, y);
input a, b, c;
input [1:0]flag;
output reg y;
always @ (a, b, c, flag)
begin
case(flag)
2'b00 : y <= a;
2'b01 : y <= b;
2'b10 : y <= c;
default : y <= a;
endcase
end
endmodule
// 4选1
module mux41a(a, b, c, d, s1, s0, y);
input a, b, c, d;
input s1, s0;
output reg y;
always @ (a, b, c, d, s1, s0)
begin
case({s1, s0})
2'b00 : y <=a ;
2'b01 : y <= b;
2'b10 : y <= c;
2'b11 : y <= d;
default : y <= a;
endcase
end
endmodule
1-2、说明波形文件 mux21a.vwf 和仿真结果波形文件 mux21a-sim.vwf 的差别。
1.mux21a.vwf可以对输入数据进行修改,不会显示输出波形。修改输入波形数据后,输出波形不变。
2.mux21a-sim.vmf是在对输入赋值后运行生成的仿真波形文件,显示出了输出波形,这个文件是一个只读文件,不能对输入数据进行修改。
实验2_两种锁存器的设计
不能以latch命名
电平锁存器
锁存器也称寄存器、触发器,电平锁存器是使用时钟作为控制信号。
- 在时钟的高电平期间,不锁存输入信号的值,输出等于输入
- 在低电平期间,锁存下降沿到来时输入的值,然后输出保持不变
- 锁存的时间是半个周期。
module latch_level(clk, d, q);
input clk, d;
output reg q;
always @ (d, clk)
if (clk)
q <= d;
endmodule
时钟沿锁存器
时钟沿锁存器是使用时钟作为控制信号
-
在时钟沿到来时(上升沿或者下降沿),将此时的输入值传到输出,然后保持不变,直到下一个时钟沿到来时才更新。
-
在下一个时钟沿到来期间,输入的值无论如何变化,输出都保持不变
-
即锁存的时间是一个时钟周期。
module latch_edge(clk, d, q)
input clk, d;
output reg q;
// 上升沿
always @ (posedge clk)
q <= d;
endmodule
思考题
2-1、设计一个锁存器,具有电平锁存和时钟沿锁存 2 种功能。设输入信号是 CLK 和 D,输出是
Q1 和 Q2,其中 Q1 是电平锁存器的输出,Q2 是时钟沿锁存器的输出。写出设计代码,并在软件上仿
真得到仿真波形。
module latch_level_edge(CLK, D, Q1, Q2);
input CLK, D;
output reg Q1, Q2;
always @ (D, CLK)
Q1 <= D;
always @ (posedge CLK)
Q2 <= D;
endmodule
2-2*、试说明为什么 D 触发器具有抗干扰作用。
D触发器允许在CLK触发沿来到前一瞬间加入输入信号,输入端受到干扰的时间大大缩短,受干扰的可能性就降低了。D触发器也称为维持-阻塞边沿D触发器。
实验3_计数器的设计
1位十进制计数器
module cnt_10(reset, en, clk, cq, cout);
input reset, en, clk;
output reg [3:0]cq, cout;
always @ (posedge reset, posedge clk)
begin
if (reset)
cq <= 0;
// en 是使能信号
else if (en)
begin
// cq 是计数值
// 范围是0 - 9 十进制
if (cq == 9)
cq <= 0;
else
cq <= cq + 1;
end
end
always @ (reset, cq)
begin
if (reset)
cout <= 0;
// 当计数到9时候输出进位脉冲
else if (cq == 9)
cout <= 1;
else
cout <= 0;
end
endmodule
思考题
试设计一个 2 位十进制加法计数器(提示:如果调用本实验所设计的 1 位十进制计数器,则
需要改为时钟下降沿计数)。
下面是错误的
// 2位十进制加法计数器
module cnt_10_2bit(reset, en, clk, cq, cout);
input reset, en, clk;
// 0 - 99 范围
output reg [10:0]cq, cout;
always @ (posedge reset, posedge clk)
begin
if (reset)
cq <= 0;
// en 是使能信号
else if (en)
begin
// cq 是计数值
// 0 - 99
if (cq == 99)
cq <= 0;
else
cq <= cq + 1;
end
end
always @ (reset, cq)
begin
if (reset)
cout <= 0;
// 当计数到99时候输出进位脉冲
else if (cq == 99)
cout <= 1;
else
cout <= 0;
end
endmodule
正确如下
module cnt_10_2bit(reset, clk, cnt0, cnt1, cout0, cout1);
input reset,clk;
output reg [3:0]cnt0;
output reg [3:0]cnt1;
output reg cout1, cout0;
always @ (posedge reset or posedge clk)
begin
if(reset)
cnt0 <= 0;
else
begin
// 跟 1 位的一样
if(cnt0 == 9)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
always @ (posedge reset or posedge clk)
begin
if(reset)
cout0 <= 0;
// 到9 就输出了
// 到 8 这里就要输出了 9 - 1 = 8
else if(cnt0 == 8)
cout0 <= 1;
else
cout0 <= 0;
end
always @ (posedge reset or posedge clk)
begin
if(reset)
cnt1 <= 0;
else if(cout0 == 1)
begin
if(cnt1 == 9)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
always @ (posedge reset or posedge clk)
begin
if(reset)
cout1 <= 0;
// 总是少 1
// 98 = 99 - 1 时候
else if((cnt1 == 9) && (cnt0 == 8))
cout1 <= 1;
else
cout1 <= 0;
end
endmodule
实验4_分频器的设计
数控分频器的设计与仿真
通过输入不同的初值,改变输出时钟信号的频率
module divider_control(clk, d, fout);
input clk;
input [7:0]d;
output reg fout;
reg cout;
reg [7:0]cnt8;
always @ (posedge clk)
begin
if (cnt8 == 8'b11111111)
cnt8 <= d;
else
cnt8 <= cnt8 + 1;
end
always @ (posedge clk)
begin
if (cnt8 == 8'b11111110)
cout <= 1'b1;
else
cout <= 1'b0;
end
always @ (posedge cout)
fout <= ~fout;
endmodule
一般分频器的设计
// 5分频 2/5 占空比
// 仿真波形如下图,可以看出分频时钟的周期是输入时钟周期的 5 倍
module div5_duty40(reset, clk, div5);
input reset, clk;
output reg div5;
reg [2:0] cnt;
always @ (posedge reset, posedge clk)
begin
if (reset)
cnt <= 0;
else
begin
// 分频数
// 5 - 1 = 4
if (cnt == 4)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
always @ (posedge reset, posedge clk)
begin
if (reset)
div5 <= 0;
// 2 / 5 的占空比
else if (cnt < 2)
div5 <= 1;
else
div5 <= 0;
end
endmodule
50M时钟分频器的设计
50MHz 的晶振比较常用,实验箱的核心板 DE1-SOC 板提供了 4 个 50MHz 的时钟(如附录二表 3-5
所示),通过分频可以产生各种需要的时钟,例如,1hz,10hz,100hz,500hz,1khz,50khz 等。
产生 50Khz 时钟的设计代码如下,其中分频比和?处的数据自己补充。
// 50Mhz的晶振
// 产生50kHz 时钟
// 1s 产生50M / 50k = 1000个
module div_50M(reset, clk, clk_50khz);
input reset, clk;
output reg clk_50khz;
reg [31:0]cnt;
always @ (posedge reset, posedge clk)
begin
if (reset)
cnt <= 0;
else
begin
if (cnt == 1000 - 1)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
always @ (posedge reset, posedge clk)
begin
if (reset)
clk_50khz <= 0;
// 0 - 499 500 - 999
else if (cnt < 1000 / 2)
clk_50khz <= 1;
else
clk_50khz <= 0;
end
endmodule
在实验箱验证数控分频器
module div_ctr(reset, clk_50m, d, fout);
input reset, clk_50m;
input [7:0] d;
output fout;
// 50khz timer
reg clk_50khz;
reg [9:0] cnt;
always @ (negedge reset, posedge clk_50m)
begin
if (!reset)
cnt <= 0;
else
begin
if (cnt == 1000 - 1)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
always @ (negedge reset, posedge clk_50m)
begin
if (!reset)
clk_50khz <= 0;
else if (cnt < 1000 / 2)
clk_50khz <= 1;
else
clk_50khz <= 0;
end
// 数控分频器
reg fout;
reg cout;
reg [7:0] cnt8;
always @ (posedge clk_50khz)
begin
if (cnt8 == 8'b11111111)
cnt8 <= d;
else
cnt8 <= cnt8 + 1;
end
always @ (posedge clk_50khz)
begin
if (cnt8 == 8'b11111110)
cout <= 1;
else
cout <= 0;
end
always @ (posedge cout)
fout <= ~fout;
endmodule
思考题
4-1、 设计一个同步复位的 6 分频器,占空比是 50%,信号名规定如下:复位信号 reset,高电平
复位,输入时钟信号 clk,输出的 6 分频时钟为 div6,内部计数器为 counter。写出代码并仿真。
module div6_50duty(reset, clk, div6);
input reset, clk;
output reg div6;
reg [2:0] counter;
always @ (posedge reset, posedge clk)
begin
if (reset)
counter <= 0;
else
begin
// 6分频
// 6 - 1 = 5
if (counter == 5)
counter <= 0;
else
counter <= counter + 1;
end
end
always @ (posedge reset, posedge clk)
begin
if (reset)
div6 <= 0;
// 50 % 占空比
else if (counter < 3)
div6 <= 1;
else
div6 <= 0;
end
endmodule
4-2、设计一个 1.5 分频的分频器。
module div_1dot5(clk, reset, div1d5, clkN, clkP, count);
input clk, reset;
output div1d5, clkN, clkP;
output reg [2:0] count;
wire [2:0]shiftcount;
reg clkP, clkN;
assign shiftcount = 3'b001;
always @ (posedge clk ,negedge reset)
begin
if(!reset)
count <= shiftcount;
else
count <= {count[1:0],count[2]};
end
always @ (negedge clk or negedge reset)
begin
if(!reset)
clkN <= 0;
else if(count == 3'b010)
clkN <= 1;
else
clkN <= 0;
end
always @ (posedge clk or negedge reset)
begin
if(!reset)
clkP <= 0;
else if(count == 3'b100)
clkP <= 1;
else
clkP <= 0;
end
assign div1d5 = clkP | clkN;
endmodule
2.5分频
参考
module D2div5(
input clk,
input reset,
output D2div5,
output [4:0] count,
output clkN,
output clkP
);
reg [4:0] count;
wire [4:0]shiftcount;
reg clkP,clkN;
assign shiftcount = 5'b00001;
always @ (posedge clk ,negedge reset)
if(!reset)
count <= shiftcount;
else
count <= {count[3:0],count[4]};
always @ (negedge clk or negedge reset)
if(!reset)
clkN <= 1'b0;
else if(count == 5'b01000 || count == 5'b10000)
clkN <= 1'b1;
else clkN <= 1'b0;
always @ (posedge clk or negedge reset)
if(!reset)
clkP <= 1'b0;
else if(count == 5'b00001 || count == 5'b00010)
clkP <= 1'b1;
else clkP <= 1'b0;
assign D2div5 = clkP | clkN;
endmodule
3分频50%占空比
module div3_duty50(
input clk,
input rst,
output clk_div
);
reg [2:0] cnt;
reg clk_p;
reg clk_n;
always@(posedge clk or negedge rst)
begin
if(!rst)
cnt<=0;
else if(cnt==2)
cnt<=0;
else
cnt<=cnt+1;
end
//下降沿采样上述时钟
always@(posedge clk or negedge rst)
begin
if(!rst)
clk_p<=0;
else if(cnt==1)
clk_p<=~clk_p;
else if(cnt==2)
clk_p<=~clk_p;
else
clk_p<=clk_p;
end
//下降沿采样上述时钟
always@(negedge clk or negedge rst)
begin
if(!rst)
clk_n<=0;
else
clk_n<=clk_p;
end
//产生分频时钟
assign clk_div = clk_n | clk_p;
endmodule
4-3、利用实验箱的资源验证实验一中的选择器,可以将 a 设为 1hz,b 设为 10hz,a 和 b 可以使
用分频器产生。S 连接到拨码开关 SW0,y 连接到 LEDR0 上。
4-4、利用实验箱的资源验证实验三中的计数器,验证方案自己确定,原则上要求易于操作,易于
观察。
实验5 用原理图输入设计8位全加器
半加器
// SO = a ^ b
// CO = a & b
module h_adder(a, b, CO, SO);
input a, b;
output CO, SO;
assign SO = a ^ b;
assign CO = a & b;
endmodule
全加器
module f_adder_1bit(ain, bin, cin, sum, cout);
input ain, bin, cin;
output sum, cout;
assign sum = ain ^ bin ^ cin;
assign cout = (ain & bin) | (bin & cin) | (ain & cin);
endmodule
8 位全加器
思考题
用verilog代码设计1位全加器
module f_adder_1bit(ain, bin, cin, sum, cout);
input ain, bin, cin;
output sum, cout;
// 1 ^ 1 ^ 1 = 1
// 1 ^ 0 ^ 0 = 1
// 1 ^ 1 ^ 0 = 0
// 0 ^ 0 ^ 0 = 1
assign sum = ain ^ bin ^ cin;
// 有两个 1 才行
assign cout = (ain & bin) | (bin & cin) | (ain & cin);
endmodule
module add_1bit(
input a, b, in,
output c, out
);
// out 是进位
assign {out, c} = a + b + in;
endmodule
实验7 数码管应用电路的设计
HEX0 数码管
module decoder(seg_in,seg_en,seg_out);
input [3:0] seg_in;
input seg_en;
output reg[7:0] seg_out;
always@(seg_in or seg_en)
begin
case(seg_in)
4'b0000:
if(seg_en)
seg_out[7:0]=8'b1100_0000;
else
seg_out = 8'b11111111;
4'b0001:
if(seg_en)
seg_out[7:0]=8'b1111_1001;
else
seg_out = 8'b11111111;
4'b0010:
if(seg_en)
seg_out[7:0]=8'b1010_0100;
else
seg_out = 8'b11111111;
4'b0011:
if(seg_en)
seg_out[7:0]=8'b1011_0000;
else
seg_out = 8'b11111111;
4'b0100:
if(seg_en)
seg_out[7:0]=8'b1001_1001;
else
seg_out = 8'b11111111;
4'b0101:
if(seg_en)
seg_out[7:0]=8'b1001_0010;
else
seg_out = 8'b11111111;
4'b0110:
if(seg_en)
seg_out[7:0]=8'b1000_0010;
else
seg_out = 8'b11111111;
4'b0111:
if(seg_en)
seg_out[7:0]=8'b1111_1000;
else
seg_out = 8'b11111111;
4'b1000:
if(seg_en)
seg_out[7:0]=8'b1000_0000;
else
seg_out = 8'b11111111;
4'b1001:
if(seg_en)
seg_out[7:0]=8'b1001_1000;
else
seg_out = 8'b11111111;
4'b1010:
if(seg_en)
seg_out[7:0]=8'b1000_1000;
else
seg_out = 8'b11111111;
4'b1011:
if(seg_en)
seg_out[7:0]=8'b1000_0011;
else
seg_out = 8'b11111111;
4'b1100:
if(seg_en)
seg_out[7:0]=8'b1100_0110;
else
seg_out = 8'b11111111;
4'b1101:
if(seg_en)
seg_out[7:0]=8'b1010_0001;
else
seg_out = 8'b11111111;
4'b1110:
if(seg_en)
seg_out[7:0]=8'b1000_0110;
else
seg_out = 8'b11111111;
4'b1111:
if(seg_en)
seg_out[7:0]=8'b1000_1110;
else
seg_out = 8'b11111111;
default:
seg_out = 8'b11111111;
endcase
end
endmodule
50M时钟分频器
module divider_50m(reset,
clk,
clk_1hz,clk_10hz,clk_50hz,clk_50khz);
input reset,clk;
output reg clk_1hz, clk_10hz, clk_50hz, clk_50khz;
// 计数器
reg [9:0]counter1;
reg [9:0]counter2;
reg [2:0]counter3;
reg [3:0]counter4;
//*********** clk_50khz ***********
// 50M / 50k = 1000
always@(negedge reset or posedge clk)
begin
if(!reset)
counter1 <= 0;
else
begin
if(counter1 == 999)
counter1 <= 0;
else
counter1 <= counter1+1;
end
end
always@(negedge reset or posedge clk)
begin
if(!reset)
clk_50khz <= 0;
else if(counter1 < 500)
clk_50khz <= 1;
else
clk_50khz <= 0;
end
//********* clk_50hz*******************
// 50M / 50k = 1000
always@(negedge reset or posedge clk_50khz)
begin
if(!reset)
counter2 <= 0;
else
begin
if(counter2 == 999)
counter2 <= 0;
else
counter2 <= counter2 + 1;
end
end
always@(negedge reset or posedge clk_50khz)
begin
if(!reset)
clk_50hz <= 0;
else if(counter2 < 500)
clk_50hz <= 1;
else
clk_50hz <= 0;
end
//********* clk_10hz*******************
always@(negedge reset or posedge clk_50hz)
begin
if(!reset)
counter3 <= 0;
else
begin
if(counter3 == 4)
counter3 <= 0;
else
counter3 <= counter3 + 1;
end
end
always@(negedge reset or posedge clk_50hz)
begin
if(!reset)
clk_10hz <= 0;
else if(counter3 < 2)
clk_10hz <= 1;
else
clk_10hz <= 0;
end
//********* clk_1hz*******************
always@(negedge reset or posedge clk_10hz)
begin
if(!reset)
counter4 <= 0;
else
begin
if(counter4 == 9)
counter4 <= 0;
else
counter4 <= counter4 + 1;
end
end
always@(negedge reset or posedge clk_10hz)
begin
if(!reset)
clk_1hz <= 0;
else if(counter4 < 5)
clk_1hz <= 1;
else
clk_1hz <= 0;
end
endmodule
2位十进制计数器
module cnt10_2bcd(reset,clk,
bcd0,bcd1,cout0,cout1);
input reset,clk;
output [3:0]bcd0;
output [3:0]bcd1;
output cout1,cout0;
reg [3:0]bcd0;
reg [3:0]bcd1;
reg cout0;
reg cout1;
//******** bcd0 ***********
always@(negedge reset or posedge clk)
begin
if(!reset)
bcd0 <= 0;
else
begin
if(bcd0==9)
bcd0 <= 0;
else
bcd0<= bcd0+1;
end
end
always@(negedge reset or posedge clk)
begin
if(!reset)
cout0 <= 0;
else if(bcd0==8)
cout0<= 1;
else
cout0<= 0;
end
//******* bcd1 **********
always@(negedge reset or posedge clk)
begin
if(!reset)
bcd1 <= 0;
else if(cout0 == 1)
begin
if(bcd1==9)
bcd1 <= 0;
else
bcd1<= bcd1+1;
end
end
always@(negedge reset or posedge clk)
begin
if(!reset)
cout1 <= 0;
else if((bcd1==9)&&(bcd0==8))
cout1<= 1;
else
cout1<= 0;
end
endmodule
顶层模块的设计
module counter_top(reset,clk,sel, key_in,
seg_out0,seg_out1,cout);
input reset,clk,sel, key_in;
output[7:0] seg_out0, seg_out1;
output cout;
wire[3:0] bcd0,bcd1;
wire clk_counter,clk_1hz,clk_50hz;
reg clk_key,sel_key;
wire seg_en = 1'b1;
always@( posedge clk_50hz)
begin clk_key <= key_in;sel_key <= sel;end
assign clk_counter = sel_key? clk_1hz:clk_key;
//***** 模块调用 **************
divider_50m div0 (.reset(reset),
.clk(clk),
.clk_1hz(clk_1hz),
.clk_10hz( ),
.clk_50hz(clk_50hz),
.clk_50khz( )) ;
cnt10_2bcd count0 (.reset (reset ) ,
.clk (clk_counter ) ,
.bcd0 (bcd0 ) ,
.bcd1 (bcd1 ) ,
.cout0 (cout ) ,
.cout1 ( ) );
decoder decoder0 (.seg_in(bcd0),
.seg_en(seg_en),
.seg_out(seg_out0));
decoder decoder1 (.seg_in(bcd1),
.seg_en(seg_en),
.seg_out(seg_out1));
endmodule
思考题
利用本实验提供的设计模块代码,做适当修改,使用 4 个数码管显示自己学号的低 4 位
// 4 位
module counter_top(reset,
seg_out0,seg_out1, seg_out2, seg_out3);
input reset;
output[7:0] seg_out0, seg_out1, seg_out2, seg_out3;
// 从右边开始数起
wire[3:0] bcd0 = 2,bcd1 = 8, bcd2 = 0, bcd3 = 1;
wire seg_en = 1'b1;
decoder decoder0 (.seg_in(bcd0),
.seg_en(seg_en),
.seg_out(seg_out0));
decoder decoder1 (.seg_in(bcd1),
.seg_en(seg_en),
.seg_out(seg_out1));
decoder decoder2 (.seg_in(bcd2),
.seg_en(seg_en),
.seg_out(seg_out2));
decoder decoder3 (.seg_in(bcd3),
.seg_en(seg_en),
.seg_out(seg_out3));
endmodule
// 6 位数码管
module counter_top(reset,
seg_out0,seg_out1, seg_out2, seg_out3, seg_out4, seg_out5);
input reset;
output[7:0] seg_out0, seg_out1, seg_out2, seg_out3, seg_out4, seg_out5;
// 从右边开始数起
wire[3:0] bcd0 = 2,bcd1 = 8, bcd2 = 0, bcd3 = 1, bcd4 = 1, bcd5 = 1;
// 使能信号
wire seg_en = 1'b1;
decoder decoder0 (.seg_in(bcd0),
.seg_en(seg_en),
.seg_out(seg_out0));
decoder decoder1 (.seg_in(bcd1),
.seg_en(seg_en),
.seg_out(seg_out1));
decoder decoder2 (.seg_in(bcd2),
.seg_en(seg_en),
.seg_out(seg_out2));
decoder decoder3 (.seg_in(bcd3),
.seg_en(seg_en),
.seg_out(seg_out3));
decoder decoder4 (.seg_in(bcd4),
.seg_en(seg_en),
.seg_out(seg_out4));
decoder decoder5 (.seg_in(bcd5),
.seg_en(seg_en),
.seg_out(seg_out5));
endmodule
实验8 用状态机实现系列检测器
使用状态机可以实现系列检测器,状态机设为 s0~s8 共 9 个状态, 当状态机进入 S8 状态时表示前
面的检测都正确,检测到所预制的系列。状态机输出 1,其他状态输出都为 0。
module fsm_detector(rst, clk, din, sout);
input rst, clk;
input din;
output sout;
parameter s0 = 0, s1 = 1, s2 = 2, s3 = 3, s4 = 4;
parameter s5 = 5, s6 = 6, s7 = 7, s8 = 8;
reg [4:0] state;
always @ (posedge rst, posedge clk)
begin
if(rst)
state <= 0;
else
case(state)
s0 :
if (din == 1'b1)
state <= s1;
else
state <= 0;
s1 :
if (din == 1'b1)
state <= s2;
else
state <= 0;
s2 :
if (din == 1'b1)
state <= s3;
else
state <= 0;
s3 :
if (din == 1'b1)
state <= s4;
else
state <= 0;
s4 :
if (din == 1'b1)
state <= s5;
else
state <= 0;
s6 :
if (din == 1'b1)
state <= s7;
else
state <= 0;
s7 :
if (din == 1'b1)
state <= s8;
else
state <= 0;
s8 :
state <= 0;
default :
state <= 0;
endcase
end
assign sout = (state == s8);
endmodule