题目如下:用Verilog 设计一个接口转换电路,接口timing如下图所示,假设clka频率为clkb频率的两倍(不同源,注意图中clock关系仅为示意),且两次有效访问(wra_n)的间隔时间足够长。
方法一
按照传统的串行输入/并行输出寄存器来解决,不考虑满时钟域到快时钟域的同步打拍问题。
源代码:
module chuan_bing(
input clka,clkb,//clka串行输入时钟,clkb并行输出时钟
input da,//串行输入数据
input rst_n,//异步复位低电平有效
input wra_n,//输入使能低电平有效
output [7:0]db,//并行输出
output reg[2:0] cnt,//计数器:记录da输入的次数,从0计数,满7,wrb有效,输出并行数据
output reg wrb//输出
);
reg [7:0]db_reg;
// reg wra_1,wra_2;
assign db = (wrb)?(db_reg):8'hxx;//如果wrb有效,则db输出寄存器的值,否则输出0;
//a时钟域
//串行数据输入及存储
always @(posedge clka, negedge rst_n) begin
if(!rst_n) begin//如果复位,输出为0,计数器清零
cnt <= 'b0;
db_reg <= 8'hxx;
end
else if(!wra_n) begin//只在wra_n为0时 才计数
cnt <= cnt + 'b1;
db_reg <= {db_reg[6:0],da};
end
end
//并行数据输出
//快时钟域到慢时钟域需要打拍
always @(posedge clkb, negedge rst_n) begin
if(!rst_n)
wrb <= 'b0;
else if(wra_n && cnt=='b0) begin//wrb只在cnt计满值并溢出,且wra_n无效时输出
wrb <= 'b1;
cnt <= 'bxxx;
end
else if(wrb)//只让wrb有效一个周期,即输出只输出一个周期
wrb <= 'b0;
end
/* always @(posedge clkb) begin
wra_1 <= wra_n;
wra_2 <= wra_1;
end*/
endmodule
测试代码:
`timescale 1ns/1ns
module tb_chuan_bing;
reg clka,clkb,da,rst_n,wra_n;
wire [7:0] db;
wire [2:0] cnt;
wire wrb;
chuan_bing U1(
.clka(clka),
.clkb(clkb),
.da(da),
.rst_n(rst_n),
.wra_n(wra_n),
.db(db),
.cnt(cnt),
.wrb(wrb)
);
initial begin
clka = 0;
clkb = 0;
rst_n = 0;
#5 rst_n = 1;
end
always begin
#10 clkb = ~clkb;
end
always begin
#5 clka = ~clka;
end
initial
begin
wra_n = 1;
#5 wra_n = 0;
da = 1;#10;
da = 1;#10;
da = 0;#10;
da = 0;#10;
da = 0;#10;
da = 0;#10;
da = 1;#10;
da = 1;#10;
da = 'bx;
wra_n = 1;
#100;
$stop;
end
endmodule
仿真结果:
仅从波形图上来看,实现了基本功能,但是没有考虑异步时钟域问题。
方法二
源代码
module chuan_bing(
input clka,clkb,//clka串行输入时钟,clkb并行输出时钟
input da,//串行输入数据
input wra_n,//输入使能低电平有效
output reg wra_n_reg1, wra_n_reg2,
output [7:0]db,//并行输出
output wrb//输出
);
reg [7:0]db_reg = 0;
// reg wra_1,wra_2;
//a时钟域
//串行数据输入及存储
always @(posedge clka) begin
if(!wra_n) begin//只在wra_n为0时 才计数
db_reg <= {db_reg[6:0],da};
end
end
//并行数据输出
//快时钟域到慢时钟域需要打拍
//reg wra_n_reg1, wra_n_reg2;
always @(posedge clkb) begin
wra_n_reg1 <= wra_n ;
wra_n_reg2 <= wra_n_reg1 ;
end
wire wra_n_check ;
assign wra_n_check = wra_n_reg1 &&(!wra_n_reg2); //异或亦可以
assign wrb = wra_n_check ;
assign db = (wra_n_check == 1'b1) ? db_reg : 0;
endmodule
仿真代码:
`timescale 1ns/1ns
module tb_chuan_bing;
reg clka ;
reg wra_n;
reg da ;
reg clkb ;
wire [7:0] db ;
wire wrb ;
wire wra_n_reg1, wra_n_reg2;
initial begin
clka = 0 ;
#3 ;
clkb = 0 ;
end
initial begin
wra_n = 1 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 0 ;
da = $random%2 ;
@(posedge clka) wra_n = 1;
end
always #5 clka = ~clka ;
always #10 clkb = ~clkb ;
chuan_bing my_chuan_bing (
.clka(clka) ,
.wra_n(wra_n),
.da(da) ,
.clkb(clkb) ,
.db(db) ,
.wrb(wrb),
.wra_n_reg1(wra_n_reg1),
.wra_n_reg2(wra_n_reg2)
);
endmodule
仿真结果: