Verilog实现常见电路(一)
计划将常见电路的verilog实现进行总结,如有不对的地方,欢迎大家批评指正,先放目录
一、边沿检测
二、串并转换
三、分频器
一、边沿检测
首先对数据打两拍,然后通过两拍数据之间的逻辑关系来判断出是上升沿还是下降沿
module edge_detect(
input clk,
input rst_n,
input data,
output pos_edge,
output neg_edge
);
reg data_d0,data_d1;
always@(posedge clk or negedge rst_n)
if(~rst_n)begin
data_d0 <= 'h0;
data_d1 <= 'h0;
end
else begin
data_d0 <= data;
data_d1 <= data_d0;
end
assign pos_edge = data_d0 && ~data_d1;
assign neg_edge = ~data_d0 && data_d1;
endmodule
仿真代码
module tb_edge_detect();
parameter PERIOD = 10;
bit clk;
reg rst_n;
reg data;
wire pos_edge;
wire neg_edge;
always #(PERIOD/2) clk = ~clk;
initial begin
rst_n=1'b1;
#20;
rst_n=1'b1;
@(posedge clk);
data=1'b1;
#40;
data=1'b0;
#40;
data=1'b1;
#40;
end
edge_detect u_edge_detect(
.clk (clk ),
.rst_n (rst_n ),
.data (data ),
.pos_edge (pos_edge ),
.neg_edge (neg_edge )
);
endmodule
仿真波形
二、串并转换
1、串转并
输入1bit位宽的数据将其合并为8bit位宽数据输出,输入输出都通过valid来表明此数据有效、
可以通过两种方式实现,计数器和移位寄存器。
module serial2parallel(
input wire clk,
input wire rst_n,
input wire data_in,
input wire valid_i,
output reg [7:0] data_o,
output wire valid_o
);
reg [2:0] cnt;
always@(posedge clk or negedge rst_n)
if(~rst_n)begin
cnt<='h0;
data_o<='h0;
end
else if(valid_i)begin
if(cnt==3'b111)
cnt<='h0;
else begin
//方法一:计数器
data_o[cnt]<=data_in; //低位优先
// data_o[7-cnt]<=data_in; //高位优先
//方法二:移位寄存器
//data_o<={data_o[6:0],data_in}; //低位优先
//data_o<={data_in,data_o[7:1]}; //高位优先
cnt<=cnt+1'b1;
end
end
assign valid_o = (cnt==3'b111)? 1'b1:1'b0;
endmodule
仿真代码
`timescale 1ns/1ps
module tb_serial2parallel();
parameter PERIOD=10;
bit clk;
reg rst_n;
reg data_in;
reg valid_i;
wire [7:0] data_o;
wire valid_o;
always #(PERIOD/2) clk = ~clk;
initial begin
rst_n = 0;
#PERIOD;
rst_n =1;
#PERIOD;
end
always@(posedge clk or negedge rst_n)
if(~rst_n)begin
valid_i <= 0;
data_in <= 1'b0;
end
else begin
valid_i = 1;
data_in <= ($random)%2;
end
serial2parallel u_serial2parallel(
.clk (clk ),
.rst_n (rst_n ),
.data_in (data_in ),
.valid_i (valid_i ),
.data_o (data_o ),
.valid_o (valid_o )
);
endmodule
仿真波形
2、并转串
输入8bit位宽的数据将其转换为1bit位宽的数据输出,输入输出都通过valid来表明此数据有效
module parallel2serial(
input wire clk,
input wire rst_n,
input wire [7:0] data_in,
input wire valid_i,
output reg data_o,
output reg valid_o
);
reg [2:0] cnt;
reg [7:0] data;
reg bit_flag;
always@(posedge clk or negedge rst_n)
if(~rst_n)
data_o<='h0;
else if(valid_i)
data<=data_in;
else if(bit_flag)
data_o<=data[cnt];
always@(posedge clk or negedge rst_n)
if(~rst_n)
bit_flag<=1'b0;
else if(valid_i)
bit_flag<=1'b1;
else if(cnt==3'b111)
bit_flag<=1'b0;
always@(posedge clk or negedge rst_n)
if(~rst_n)
valid_o<=1'b0;
else if(bit_flag)
valid_o<=1'b1;
else
valid_o<=1'b0;
always@(posedge clk or negedge rst_n)
if(~rst_n)
cnt<='h0;
else if(bit_flag)
if(cnt==3'b111)
cnt<='h0;
else
cnt<=cnt+1'b1;
endmodule
仿真代码
`timescale 1ns/1ps
module tb_parallel2serial();
parameter PERIOD=10;
bit clk;
reg rst_n;
reg [7:0] data_in;
reg valid_i;
wire data_o;
wire valid_o;
always #(PERIOD/2) clk = ~clk;
initial begin
rst_n = 0;
#PERIOD;
rst_n =1;
#PERIOD;
valid_i = 0;
generate_data();
#200;
generate_data();
end
task generate_data;
begin
@(posedge clk);
valid_i = 1;
data_in = ($random)%20;
@(posedge clk);
valid_i= 0;
end
endtask
parallel2serial u_parallel2serial(
.clk (clk ),
.rst_n (rst_n ),
.data_in (data_in ),
.valid_i (valid_i ),
.data_o (data_o ),
.valid_o (valid_o )
);
endmodule
仿真波形
三、分频器
见之前总结过的文章