ice40时钟延迟,输出时序分析
ice40 clock delay, output timing analysis
我有一个驱动 ASIC 时钟和数据输入的 ice40。
ice40 驱动 ASIC 的时钟与驱动 ice40 的内部逻辑的时钟相同。问题是上升时钟触发 ice40 的内部逻辑并在上升时钟到达 ASIC 之前 几纳秒 改变 ice40 的数据输出,因此 ASIC 在其上升时观察到错误数据时钟。
我已经通过使用反相器链来延迟 ice40 的内部时钟而不延迟驱动 ASIC 的时钟来解决这个问题。这样,上升时钟在 ice40 的数据输出改变之前到达 ASIC。但这提出了几个问题:
我的策略——使用反相器链来延迟 ice40 内部时钟——是一个好的策略吗?
为了诊断问题,我使用 Lattice 的 iCEcube2 来分析内部时钟和输出引脚之间的 min/max 延迟:
请注意 asic_dataX
延迟比 clk_out
延迟短,表明存在问题。
有没有办法从 yosys/nextpnr 获取此信息?
感谢您的任何见解!
我建议使用既定技术,而不是修补延迟。例如,SPI 简单在一个边沿上记录数据并在另一个边沿上更改它们:.
实现的逻辑相当简单。这里有一个 SPI 从设备的示例实现:
module SPI_slave #(parameter WIDTH = 6'd16, parameter phase = 1'b0,
parameter polarity = 1'b0, parameter bits = 5) (
input wire rst,
input wire CS,
input wire SCLK,
input wire MOSI,
output reg MISO,
output wire data_avbl,
input wire [WIDTH-1:0] data_tx,
output reg [WIDTH-1:0] data_rx
);
reg [bits:0] bitcount;
reg [WIDTH-1:0] buf_send;
assign clk = phase ^ polarity ^ SCLK;
assign int_rst = rst | CS;
assign tx_clk = clk | CS;
assign data_avbl = bitcount == 0;
always @(negedge tx_clk or posedge rst) begin
MISO <= rst ? 1'b0 : buf_send[WIDTH-1];
end
always @(posedge clk or posedge int_rst) begin
if (int_rst) begin
bitcount <= WIDTH;
data_rx <= 0;
buf_send <= 0;
end else begin
bitcount <= (data_avbl ? WIDTH : bitcount) - 1'b1;
data_rx <= { data_rx[WIDTH-2:0], MOSI };
buf_send <= bitcount == 1 ? data_tx[WIDTH-1:0] : { buf_send[WIDTH-2:0], 1'b0};
end
end
endmodule
正如你所看到的,数据在上升沿被捕获并在下降沿被改变。如果想避免边沿敏感度的混合,可以使用双倍时钟。
我有一个驱动 ASIC 时钟和数据输入的 ice40。
ice40 驱动 ASIC 的时钟与驱动 ice40 的内部逻辑的时钟相同。问题是上升时钟触发 ice40 的内部逻辑并在上升时钟到达 ASIC 之前 几纳秒 改变 ice40 的数据输出,因此 ASIC 在其上升时观察到错误数据时钟。
我已经通过使用反相器链来延迟 ice40 的内部时钟而不延迟驱动 ASIC 的时钟来解决这个问题。这样,上升时钟在 ice40 的数据输出改变之前到达 ASIC。但这提出了几个问题:
我的策略——使用反相器链来延迟 ice40 内部时钟——是一个好的策略吗?
为了诊断问题,我使用 Lattice 的 iCEcube2 来分析内部时钟和输出引脚之间的 min/max 延迟:
请注意 asic_dataX
延迟比 clk_out
延迟短,表明存在问题。
有没有办法从 yosys/nextpnr 获取此信息?
感谢您的任何见解!
我建议使用既定技术,而不是修补延迟。例如,SPI 简单在一个边沿上记录数据并在另一个边沿上更改它们:
实现的逻辑相当简单。这里有一个 SPI 从设备的示例实现:
module SPI_slave #(parameter WIDTH = 6'd16, parameter phase = 1'b0,
parameter polarity = 1'b0, parameter bits = 5) (
input wire rst,
input wire CS,
input wire SCLK,
input wire MOSI,
output reg MISO,
output wire data_avbl,
input wire [WIDTH-1:0] data_tx,
output reg [WIDTH-1:0] data_rx
);
reg [bits:0] bitcount;
reg [WIDTH-1:0] buf_send;
assign clk = phase ^ polarity ^ SCLK;
assign int_rst = rst | CS;
assign tx_clk = clk | CS;
assign data_avbl = bitcount == 0;
always @(negedge tx_clk or posedge rst) begin
MISO <= rst ? 1'b0 : buf_send[WIDTH-1];
end
always @(posedge clk or posedge int_rst) begin
if (int_rst) begin
bitcount <= WIDTH;
data_rx <= 0;
buf_send <= 0;
end else begin
bitcount <= (data_avbl ? WIDTH : bitcount) - 1'b1;
data_rx <= { data_rx[WIDTH-2:0], MOSI };
buf_send <= bitcount == 1 ? data_tx[WIDTH-1:0] : { buf_send[WIDTH-2:0], 1'b0};
end
end
endmodule
正如你所看到的,数据在上升沿被捕获并在下降沿被改变。如果想避免边沿敏感度的混合,可以使用双倍时钟。