Verilog学习脚印2-时序逻辑
附:verilog语法笔记(持续更新ing)
目录
触发器基础
因为笔者对触发器知识有所遗忘,因此在这里做一个回顾
以下这篇文章对RS触发器(Reset Set flip-flop)、D触发器(data flip-flop或delay flip-flop)描述已经较为详细。
链接
bash命令
bash调用dve和vcs的命令:
dve & // 启用VDE
vcs *.v -R -timescale=1ns/10ps +v2k +define+RTL_SAIF // 编译
实例1:计数器
电路原理(来自B站-北交李金城老师的PPT,侵删)
代码实现与验证
完整代码:
`timescale 1ns/10ps
// ----- definition of counter -----
module counter(
clk,
res,
y
);
input clk;
input res;
output[7:0] y;
reg[7:0] y;
wire[7:0] sum; // result of +1
assign sum=y+1; // logic
always@(posedge clk or negedge res)
if(~res) begin
y<=0;
end
else begin
y<=sum;
end
endmodule
// ----- testbench of counter -----
module counter_tb;
reg clk,res;
wire[7:0] y;
counter counter(
.clk(clk),
.res(res),
.y(y)
);
initial begin
$dumpfile("counter_tb.vcd"); // save wave file
$dumpvars(0,counter);
end
initial begin
clk<=0;res<=0; // nitice! initial of res and clk is must!
#20 res<=1;
#6000 $stop;
end
always #5 clk<=~clk;
endmodule
波形输出:
实例2:4级伪随机码发生器
电路原理(来自B站-北交李金城老师的PPT,侵删)
代码实现与验证
代码如下:
// Level 4 pseudo-random code generator
`timescale 1ns/1ps
// ----- definition -----
module p_random_code_generator(
clk,
res,
y
);
input clk;
input res;
output y;
reg[3:0] d;
assign y=d[0];
always@(posedge clk or negedge res)
if(~res) begin
d<=4'b1111;
end
else begin
d[2:0]<=d[3:1]; // notice! '>>' is not recommanded!
d[3]<=d[3]+d[0]; // nitoce! module 2 addition!
end
endmodule
// ----- testbench -----
module p_random_code_generator_tb;
reg clk,res;
wire y;
p_random_code_generator p_random_code_generator(
.clk(clk),
.res(res),
.y(y)
);
initial begin
$dumpfile("p_random_code_generator_tb.vcd"); // save wave file
$dumpvars(0,p_random_code_generator);
end
initial begin
clk<=0;res<=0; // nitice! initial of res and clk is must!
#20 res<=1;
#600 $stop;
end
always #5 clk<=~clk;
endmodule
验证结果如下:
实例3:秒计数器
电路原理(来自B站-北交李金城老师的PPT,侵删)
功能说明:对于24MHz系统时钟,实现能够循环0-9的秒计数器
实现思路:首先得到秒脉冲,再对秒脉冲进行计数
代码实现与验证
代码:
// s_counter from 0 to 9
`timescale 1ns/1ps
module s_counter(
clk,
res,
s_sum
);
input clk;
input res;
output s_sum;
reg[24:0] con_t; // crossover count. notice! why 24!
reg s_pulse; // seconds pulse peak
reg[3:0] s_sum; // second counter
parameter frequency_clk=24; // 24MHz: system clock frequency
always@(posedge clk or negedge res)
if(~res)begin // notice! reset of all registers is must!
con_t<=0;s_pulse<=0;s_sum<=0;
end
else begin
if(con_t==frequency_clk*1000000-1)begin
con_t<=0;
end
else begin
con_t<=con_t+1;
end
if(con_t==0)begin
s_pulse<=1;
end
else begin
s_pulse<=0;
end
if(s_pulse==1)begin
if(s_sum==9)begin
s_sum<=0;
end
else begin
s_sum<=s_sum+1;
end
end
end
endmodule
// ----- testbench -----
module s_counter_tb;
reg clk,res;
wire[3:0] s_sum;
s_counter s_counter(
.clk(clk),
.res(res),
.s_sum(s_sum)
);
initial begin
$dumpfile("s_counter_tb.vcd"); // save wave file
$dumpvars(0,s_counter);
end
initial begin
clk<=0;res<=0;
#17 res<=1;
#10000 $stop;
end
always #5 clk=~clk;
endmodule
验证结果如下:
实例4:相邻16点相加输出
功能说明:从data_in中每读取16个数据,就输出它们的和。
代码如下:
// add 16 numbers from data_in flow
`timescale 1ns/1ps
// ----- definition -----
module add_16(
clk,
res,
data_in,
syn_in,
data_out,
syn_out
);
input clk;
input res;
input[7:0] data_in; // sample signal
input syn_in; // sample clock signal
output[11:0] data_out; // output the add result
output syn_out; // output the sync pulse of the add result
reg syn_in_n1; // reverse time delay of 'syn_in'
wire syn_pulse;
reg[3:0] con_syn; // counter of sync clock
wire[7:0] comp_8; // complement code
wire[11:0] d_12; // notice! raise the wide to prevent overflow!!!
reg[11:0] sigma; // result of add
reg[11:0] data_out; // output
reg syn_out;
assign comp_8=data_in[7]?{data_in[7],~data_in[6:0]+1}:data_in;
assign d_12={comp_8[7],comp_8[7],comp_8[7],comp_8[7],comp_8}; // why?
assign syn_pulse=syn_in&syn_in_n1;
always@(posedge clk or negedge res)
if(~res)begin // notice! all registr must be reset!
syn_in_n1<=0;sigma<=0;data_out<=0;syn_out<=0;con_syn<=0;
end
else begin
syn_in_n1<=~syn_in;
if(syn_pulse)begin
con_syn<=con_syn+1;
end
if(syn_pulse)begin
if(con_syn==15)begin
sigma<=d_12;
data_out<=sigma;
syn_out<=1;
end
else begin
sigma<=sigma+d_12;
end
end
else begin
syn_out<=0;
end
end
endmodule
// ----- testbench -----
module add_16_tb;
reg clk,res;
reg[7:0] data_in;
reg syn_in;
wire[11:0] data_out;
wire syn_out;
add_16 add_16(
.clk(clk),
.res(res),
.data_in(data_in),
.syn_in(syn_in),
.data_out(data_out),
.syn_out(syn_out)
);
initial begin
$dumpfile("add_16_tb.vcd"); // save wave file
$dumpvars(0,add_16);
end
initial begin
clk<=0;res<=0;data_in<=1;syn_in<=0; // if data_in=-1, then data_in=8'b1000_0001
#17 res<=1; // why 17? Avoid coinciding clock edges and reset edges
#6000 $stop;
end
always #5 clk<=~clk;
always #100 syn_in<=~syn_in;
endmodule
验证如下: