0

I have an ice40 that drives the clock and data inputs of an ASIC.

The ice40 drives the ASIC's clock with the same clock that drives the ice40's internal logic. The problem is that the rising clock triggers the ice40's internal logic and changes the ice40's data outputs a few nanoseconds before the rising clock reaches the ASIC, and therefore the ASIC observes the wrong data at its rising clock.

I've solved this issue by using an inverter chain to delay the ice40's internal clock without delaying the clock driving the ASIC. That way, the rising clock reaches the ASIC before the ice40's data outputs change. But that raises a few questions:

  1. Is my strategy -- using an inverter chain to delay the ice40 internal clock -- a good strategy?

  2. To diagnose the problem, I used Lattice's iCEcube2 to analyze the min/max delays between the internal clock and output pins:

enter image description here

Notice that the asic_dataX delays are shorter than the clk_out delay, indicating the problem.

Is there a way to get this information from yosys/nextpnr?

Thank you for any insight!

Dave
  • 23
  • 1
  • 4
  • What is the reasoning against changing data on the falling edge if the clk is sensistive to the rising edge? SPI does that for example. You can search for spi verilog module to find some examples. – Christian B. Jul 15 '20 at 13:34
  • Thanks for the suggestion Christian, that might work. Originally I disregarded solutions involving inverting the clock (since the ASIC's output hold time is too short to permit reading data on the negedge). But maybe I can keep everything posedge sensitive, except the ice40's output flops would be negedge sensitive. I still need to figure out the timing implications for the logic that drives the negedge flops though: either the logic needs to be fast enough to beat the negedge (+t_setup), or slow enough so that the input at the negedge flops isn't disturbed at the negedge (+t_hold). – Dave Jul 17 '20 at 22:10

1 Answers1

1

Instead of tinkering with the delays I would recommend to use established techniques. For example SPI simple clocks the data on the one edge and changes them on the other: Source https://www.ti.com/lit/an/slaa734a/slaa734a.pdf.

The logic to implement that is rather simple. Here an example implementation for an SPI slave:

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

As one can see the data are captured at the positive edge and changed on the negative edge. If one wants to avoid the mixing of edge sensistivies a doubled clock can be used instead.

Christian B.
  • 816
  • 6
  • 11