|
这是特权同学在《深入浅出玩转FPGA》里面的“基于FPGA的跨时钟域信号处理”一章里面的一个例子,以此来强调同步设计思想。该程序因为脉冲信号和由CPU控制总线产生的选通信号是来至两个异步时钟域的信号,它们作为内部时钟信号时,如果同一时刻出现一个时钟在写寄存器counter,另一个时钟在读寄存器counter,那么很明显存在发生冲突的可能。
module fp(
clk,
rst,
pulse, //脉冲信号,高电平有效
cs_n, //低电平有效
rd_n, //读使能信号,低电平有效
addr_bus, //地址总线
data_bus //数据总线
);
input clk;
input rst;
input plush;
input cs_n;
input rd_n;
input [3:0] addr_bus;
output [15:0] data_bus;
reg [15:0] counter;
reg [15:0] data_bus;
always @(posedge plush or negedge rst)
if(!rst)
counter <= 16'b0;
else if(plush)
counter <= counter + 1'b1;
wire dsp_cs = cs_en || rd_en;
always @(dsp_cs or addr_bus)
if(dsp_cs)
data_bus <= 16'hzzzz;
else begin
case (addr_bus)
4'h0: data_bus <= counter;
...
endcase
end
endmodule
该例同步设计方法:先使用脉冲同步法把脉冲信号与系统时钟信号clk同步,然后使用脉冲同步法得到一个系统时钟宽度的使能信号作为数据锁存信号,同时也将CPU的控制信号与系统时钟信号同步。本人根据这个思想写了如下程序。我的疑问是同一个时刻clk出现写counter和读counter,怎么不会发生数据冲突。
module fp(
clk,
rst,
pulse, //脉冲信号,高电平有效
cs_n, //低电平有效
rd_n, //读使能信号,低电平有效
addr_bus, //地址总线
data_bus //数据总线
);
input clk;
input rst;
input plush;
input cs_n;
input rd_n;
input [3:0] addr_bus;
output [15:0] data_bus;
reg [15:0] counter;
reg [15:0] data_bus;
reg preg1,preg2;
always @(posedge clk or negedge rst)
if(!rst) begin
preg1 <= 1'b1;
preg2 <= 1'b1;
end
else begin
preg1 <= plush;
preg2 <= preg1;
end
wire pos_en;
assign pos_en = preg1 & (~preg2); //检测脉冲信号,一个时钟周期有效的高电平
always @(posedge clk or negedge rst)
if(!rst)
counter <= 16'b0;
else if(pos_en)
counter <= counter + 1'b1;
wire pos_en = cs_en || rd_en; //片选信号和读信号同时为低时,对地址总线进行译码,把采样脉冲值送给数据总线
reg dreg1,dreg2;
always @(posedge clk or negedge rst)
if(!rst) begin
dreg1 <= 1'b1;
dreg2 <= 1'b1;
end
else begin
dreg1 <= ce_en;
dreg2 <= preg1;
end
wire dsp_cs;
assign dsp_cs = dreg2 & (~dreg1); //使能信号
s
always @(posedge clk or negedge rst)
if(!rst)
data_bus <= 16'hzzzz;
else if(dsp_cs) begin
case (addr_bus)
4'h0: data_bus <= counter;
...
endcase
end
endmodule
2012-11-28
|
|