Skip to main content

COMPUTE_CLOCK_VERILOG

Constant COMPUTE_CLOCK_VERILOG 

Source
pub const COMPUTE_CLOCK_VERILOG: &str = r#"module logos_compute_clock #(parameter DIVIDE = 2, parameter LEAD = 0)
  (input clk, input rst_n, output reg cclk, output cclk_rst_n, output fedge, output fmid);
  localparam W = (DIVIDE > 2) ? $clog2(DIVIDE / 2) : 1;
  localparam [W-1:0] LAST = DIVIDE / 2 - 1;
  reg [W-1:0] count;
  always @(posedge clk or negedge rst_n)
    if (!rst_n) begin count <= {W{1'b0}}; cclk <= 1'b0; end
    else if (count == LAST) begin count <= {W{1'b0}}; cclk <= ~cclk; end
    else count <= count + 1'b1;
  // The marks registered, each the next cycle's, so an enable of the whole engine leaves a register.
  wire [W-1:0] count_next = (count == LAST) ? {W{1'b0}} : count + 1'b1;
  wire cclk_next = (count == LAST) ? ~cclk : cclk;
  (* maxfan = 2000 *) reg mark_edge, mark_mid;
  always @(posedge clk or negedge rst_n)
    if (!rst_n) begin mark_edge <= LAST == {W{1'b0}}; mark_mid <= 1'b0; end
    else begin mark_edge <= count_next == LAST && !cclk_next; mark_mid <= count_next == LAST && cclk_next; end
  reg [1:0] release_q;
  always @(posedge clk or negedge rst_n)
    if (!rst_n) release_q <= 2'b00; else if (mark_edge) release_q <= {release_q[0], 1'b1};
  // LEAD > 0: the marks and the reset's release LEAD user clocks on, through registers of no reset the retimer may move
  // along the wire and the last of which Quartus copies beside its loads, so no mark crosses the die in one clock; the
  // reset still asserted the moment the user clock's is. Every consumer sees the divider LEAD clocks late, alike.
  generate
    if (LEAD == 0) begin : now
      assign fedge = mark_edge;
      assign fmid = mark_mid;
      assign cclk_rst_n = release_q[1];
    end else begin : late
      (* maxfan = 64 *) reg [LEAD-1:0] edge_d, mid_d;
      reg [LEAD-1:0] release_d;
      always @(posedge clk) begin
        edge_d <= (edge_d << 1) | {{(LEAD-1){1'b0}}, mark_edge};
        mid_d <= (mid_d << 1) | {{(LEAD-1){1'b0}}, mark_mid};
        release_d <= (release_d << 1) | {{(LEAD-1){1'b0}}, release_q[1]};
      end
      assign fedge = edge_d[LEAD-1];
      assign fmid = mid_d[LEAD-1];
      assign cclk_rst_n = release_q[1] && release_d[LEAD-1];
    end
  endgenerate
endmodule
"#;
Expand description

The user clock divided by DIVIDE (even), as marks in the user clock: a register toggled every DIVIDE / 2 user clock edges (the divided clock, a level that clocks nothing); fedge and fmid high in the user cycles that end with its rising and falling edges, where the shell’s compute side and an engine’s core step and an engine’s step boundary takes the engine’s values; and a reset asserted with the user clock’s and released in the user clock at the second divided rising edge after it.