Skip to content

Commit 0865bdf

Browse files
moritzScheremo
authored andcommitted
[NFC] Improve L0 cache write port sampling time
This PR changes the latch-based snitch L0 cache implementation which is used when CFG.EARLY_LATCH is enabled. Up to now, the latch-memory often required (practically) infeasible timing constraints. This PR rewrites the latch cache to arrive at virtually the same timing constraints on the setup window as the flip-flop cache while using less area and causing significantly less leakage in all reasonable configurations. The first issue with the current implementation is that it transparent-low latches to replace the posedge-triggered flip-flops used in the FF version of the L0 cache. Since the latches' gate pin is driven by a clock gate, this introduces a non-obvious critical timing condition: Since the latches' gate pin must be stable before the negative clock cycle, the clock gate's output must be calculated and latched within half of a clock cycle since its inputs (validate_strb[i]) depend on posedge-triggered flip flops and module inputs (out_rsp_id_i), which in turn depends on checking for a prefetch hit. This can lead to the path becoming critical for the entire cache. The second issue with the current implementation is that the prefetch/refill path to the L0 storage elements (latches and flipflops) is oftentimes tight if not critical, especially in low-power implementation scenarios where the refilling memory (the L1 cache) has slow (e.g. more than half a clock period) CK -> Q timing. In contrast, the storage elements' read timing is usually much less critical as they are directly fed to a processor core. This forces the implementation to size all L0 storage elements accordingly, often leading to significant leakage and increased drive strength "creep" towards the cores. Both of these issues are addressed in this pull request; instead of using transparent-low latches, the new implementation uses a posedge-triggered write port flip-flop to latch the refill/prefetch line, and selectively updates the new L0 cache which is implemented using transparent-high latches instead. This style of implementation achieves fundamentally the same cycle latency, and only adds the latches' setup and propagation delay to the cache's read path length. In practice, this is close to negligible. The first issue of having the clock gate in a (sub-)critical path is fixed by the fact that the latches are transparent-high now; this directly implies we can use the whole clock cycle to set up the enable pin. The second issue of high drive strength on the main storage elements is mitigated as well. Since the refill/prefetch line is now stored in a write port flip-flop, the latches (being the main storage element) are no longer in a timing-relevant path. Since typical implementations use 8 (or more) L0 cache lines, these leakage savings are quite noticeable. In our experiments this change alone has reduced the leakage of an entire cluster by over 15% without performance degradation compared to the flip-flop variant. Hold constraints are also no more critical than in the previous implementation as the storage latches hold condition is practically always met (the write port flip flop's output value on changes on a posedge) and next receiving storage element's hold condition edge is typically on the posedge of the next cycle.
1 parent ce0ed94 commit 0865bdf

1 file changed

Lines changed: 12 additions & 7 deletions

File tree

src/snitch_icache_l0.sv

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,16 @@ module snitch_icache_l0
139139
assign hit_prefetch_any = |hit_prefetch;
140140
assign miss = ~hit_any & in_valid_i & ~pending_refill_q & ~prefetching_missed_line;
141141

142-
logic clk_inv;
143-
tc_clk_inverter i_clk_inv (
144-
.clk_i(clk_i),
145-
.clk_o(clk_inv)
146-
);
142+
logic [CFG.LINE_WIDTH-1:0] line_in_q;
143+
if (CFG.EARLY_LATCH) begin
144+
always_ff @(posedge clk_i or negedge rst_ni) begin
145+
if (~rst_ni) begin
146+
line_in_q <= '0;
147+
end else begin
148+
line_in_q <= out_rsp_data_i;
149+
end
150+
end
151+
end
147152

148153
for (genvar i = 0; i < CFG.L0_LINE_COUNT; i++) begin : gen_array
149154
// Tag Array
@@ -167,7 +172,7 @@ module snitch_icache_l0
167172
if (CFG.EARLY_LATCH) begin : gen_latch
168173
logic clk_vld;
169174
tc_clk_gating i_clk_gate (
170-
.clk_i (clk_inv),
175+
.clk_i (clk_i),
171176
.en_i (validate_strb[i]),
172177
.test_en_i(1'b0),
173178
.clk_o (clk_vld)
@@ -177,7 +182,7 @@ module snitch_icache_l0
177182
/* verilator lint_off COMBDLY */
178183
always_latch begin
179184
if (clk_vld) begin
180-
data[i] <= out_rsp_data_i;
185+
data[i] <= line_in_q;
181186
end
182187
end
183188
/* verilator lint_on COMBDLY */

0 commit comments

Comments
 (0)