绪论
在一些应用中,两个电路模块交界处,一个电路模块的输出数据位宽大于另一个模块的输入数据位宽,此时需要进行数据转换。例如,在SATA控制器中,内部数据位宽为32比特,但是与外部物理收发器PHY的接口通常为16比特或8比特。同样的,从PHY接收到的数据也是16比特或8比特,数据交给控制器后,在其内部使用之前转换为32比特。下面将介绍进行数据宽度转换的电路,电路中没有使用FIFO,是通过时钟分频与倍频实现数据位宽转换和传输的。
由宽到窄数据转换
图6.30是位宽由宽变窄时的示意图。6.31是数据转换波形示意图。
电路模块B的工作时钟为clk2x,在电路模块A中将其二分频得到clklX。clk1x与clk2x之间有一个同定的相位 差。根据图6.30和图6.31,具体的数据传输过程如下:
- clklx下方的数据datain[31:0]经过clk2x采样产生datain_sync[31:0],由于clk1x在相位上滞后于clk2x且二者为同步时钟,因此数据从时钟域clklx传递到时钟域clk2x时不会存在问题;
- 在clk2x时钟域内,当clklx为0时,使用clk2x选择datain_sync的低16比特,当clklx为1时,选择datain_sync的高16比特;
- 完成数据变换,最终输出dataout_clk2x[15:0]。
代码及仿真结果如下。
module wide_to_narrow
(clk2x,
clklx,
datain,
dataout_clk2x);
input clk2x;
input clklx;
input [31: 0] datain;
output [15: 0] dataout_clk2x;
//***************************************
reg [31:0] datain_sync;
reg [15:0] dataout_clk2x;
wire [15:0] dataout_clk2x_nxt;
// Flop the data first with clk2x. Reset is not required as it is a datapath and
// default (reset) value of the flops are don’t care.
//***************************************
always @(posedge clk2x)
begin
datain_sync <- datain;
end
// Select the lower and upper halves from datain_sync
//***************************************
assign dataout_clk2x_nxt = !clk 1 x ? datain_sync[15:0] :datain_sync[31:16];
// Flop the selected 16 bit data with clk2x and drive out
//***************************************
always @(posedge clk2x)
begin
dataout_clk2x <= dataout_clk2x_nxt;
end
endmodule
由窄到宽数据转换
图6.32和图6.33是实现由窄到宽数据转换操作的电路和工作波形。
代码及仿真结果如下。
module narrow_to_wide
(clk2x,
clklx,
data16,
data32_clk1x);
input clk2x;
input clklx;
input [15: 0] data16;
output [31: 0] data32_clk1x;
//***************************************
reg [15:0] data16_tmp;
reg [31:0] data32_clk1x data32_clk1x_nxt;
/* store temporary data into a register
along with the 16 bits of tmp data stored in pervious cycle to form 32 bits of data.
These 32 bits of data is flopped with clklx, and this happens for every two-clock
periods of clk2x.
When data is passed from 2x (fast) to the lx (slow) domain, make sure that there is
enough delay in the data path to avoid set-up/hold violation in the immediate risi
edge of lx clock. The data should have more delay in the path to pass beyond
immediate rising edge of 1x clock*/
//***************************************
always @(posedge clk2x)
begin
datal6_tmp <= #2 datal 6;
end
// Form the 32-bit data
assign data32_clklx_nxt = {datal 6[15:0], data16_tmp[l5:0]};
// Flop the selected 16 bit data with clk2x and drive out
always @(posedge elklx)
begin
data32_clklx <= data32_clklx_nxt;
end
endmodulemodule narrow_to_wide
(clk2x,
clklx,
data16,
data32_clk1x);
input clk2x;
input clklx;
input [15: 0] data16;
output [31: 0] data32_clk1x;
//***************************************
reg [15:0] data16_tmp;
reg [31:0] data32_clk1x data32_clk1x_nxt;
/* store temporary data into a register
along with the 16 bits of tmp data stored in pervious cycle to form 32 bits of data.
These 32 bits of data is flopped with clklx, and this happens for every two-clock
periods of clk2x.
When data is passed from 2x (fast) to the lx (slow) domain, make sure that there is
enough delay in the data path to avoid set-up/hold violation in the immediate risi
edge of lx clock. The data should have more delay in the path to pass beyond
immediate rising edge of 1x clock*/
//***************************************
always @(posedge clk2x)
begin
datal6_tmp <= #2 datal 6;
end
// Form the 32-bit data
assign data32_clklx_nxt = {datal 6[15:0], data16_tmp[l5:0]};
// Flop the selected 16 bit data with clk2x and drive out
always @(posedge elklx)
begin
data32_clklx <= data32_clklx_nxt;
end
endmodule
原文:FPGA 的逻辑
作者:碎碎思
相关文章推荐