一键导入
rtl-opt
Critical path patterns with corresponding optimization strategies. Use this when users request optimize the RTL code based on the timing analysis results.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Critical path patterns with corresponding optimization strategies. Use this when users request optimize the RTL code based on the timing analysis results.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | rtl-opt |
| description | Critical path patterns with corresponding optimization strategies. Use this when users request optimize the RTL code based on the timing analysis results. |
| license | Complete terms in LICENSE.txt |
op_is_add, op_is_sub, state_is_idle) computed once and reusedcount_is_max, state_is_active), compute once, reuse across always blocksfull, enable)ptr+1, ptr+2), then select with late muxsel?(A+B):(C+D) structure(sel?A:C)+(sel?B:D) - move mux before addercount == MAX_COUNT)| Path Characteristic | Recommended Strategy | Confidence |
|---|---|---|
| FSM state decode to output | One-hot pre-decode (#1), FSM output registration (#4) | High |
| Counter with comparison | Condition pre-computation (#2), wire extraction | High |
| High-fanout control signal | Register duplication (#3), input registration (#5) | High |
| Arithmetic gated by control | Late mux-select (#6), mux-before-adder (#7) | Medium |
| Large case/lookup table | Hierarchical decomposition (#8) | Medium |
| GF/crypto arithmetic | Logic tree balancing (#9), CSE (#10) | Medium |
| Binary-encoded FSM | One-hot encoding (#11) - with caution | Medium |
| Deeply nested ternary | Wire decomposition (#14) - modest benefit | Low |
| Priority-encoded chain | AVOID parallel flattening | Anti-pattern |
| Memory array paths | SKIP - out of scope | N/A |
| Design Type | Best Strategies | SEC Pass Rate |
|---|---|---|
| FSM-heavy (ticket_machine, vending_machine) | One-hot (#1, #11), mux-before-adder (#7) | 60% |
| Communication (UART, SPI, router) | Input registration (#5), FSM output reg (#4), condition pre-compute (#2) | 70% |
| Pipeline (router, FIFO) | Register duplication (#3), input registration (#5) | 80% |
| Datapath (DSP, LSTM, datapath) | Tree balancing (#9), CSE (#10), wire decomposition (#14) | 65% |
| Encoder/Decoder (pcie) | Hierarchical decomposition (#8) | 85% |
| Controller (cpu_fsm, controller) | One-hot pre-decode (#1), condition pre-compute (#2) | 90% |
| Strategy | Attempts | Successes | Rate | Avg WNS Improvement |
|---|---|---|---|---|
| One-hot pre-decode | 12 | 11 | 92% | +8% |
| Condition pre-computation | 18 | 16 | 89% | +5% |
| Register duplication | 8 | 7 | 88% | +7% |
| FSM output registration | 10 | 9 | 90% | +8% |
| Input signal registration | 14 | 12 | 86% | +10% |
| Late mux-select | 6 | 4 | 67% | +12% |
| Mux-before-adder | 4 | 3 | 75% | +40% |
| Hierarchical decomposition | 5 | 4 | 80% | +35% |
| Logic tree balancing | 8 | 5 | 63% | +6% |
| CSE | 10 | 7 | 70% | +4% |
| One-hot FSM encoding | 8 | 5 | 63% | +35% |
| Parallel logic flattening | 6 | 2 | 33% | +35% (when successful) |
| Count direction change | 4 | 0 | 0% | N/A |
| Wire decomposition | 12 | 10 | 83% | +3% |
Conservative wins over aggressive: High SEC pass rate more important than large improvements. A 5% improvement that passes SEC beats a 30% improvement that fails.
Sequential optimizations are safer: Adding registers (strategies #3, #4, #5) rarely break SEC. Combinational restructuring is higher risk.
Pre-computation beats restructuring: Extracting conditions to wires (#1, #2) is safer than restructuring logic (#7, #11, #12).
Design complexity matters: Simple designs (FIFO, SPI) tolerate more aggressive optimization. Complex designs (LSTM, cpu_pipe) need conservative approaches.
Module-focused optimization works: Targeting specific modules (pcie decoder, datapath sBox) more successful than whole-design changes.
Diversity strategy helps discovery: Different path selection (endpoint clustering, high fanout, module-focused) finds different optimization opportunities.
Baseline sensitivity varies: Some designs (simple_spi) are already highly optimized; aggressive changes cause synthesis failures rather than SEC failures.
This file merges and normalizes the uploaded skill libraries into one comprehensive reference. It organizes the skills into High-confidence, Medium-confidence, Low-confidence, and Do not use. Each skill is written in the format:
<pattern, strategy, example>
For every example, both before and after Verilog snippets are included.
<repeated comparisons / repeated control checks, pre-compute shared condition wires and reuse them, example>(state == X), (cmd == Y), (count == Z) or repeated shared condition fragments across branches.always / assign logic. Very safe and consistently effective for FSM decode, counters, and control fanout.// BEFORE
always @(*) begin
if (state == IDLE && cmd == START)
next_state = START;
else if (state == IDLE && cmd == STOP)
next_state = STOP;
else
next_state = state;
end
// AFTER
wire state_is_idle = (state == IDLE);
wire cmd_is_start = (cmd == START);
wire cmd_is_stop = (cmd == STOP);
wire go_start = state_is_idle & cmd_is_start;
wire go_stop = state_is_idle & cmd_is_stop;
always @(*) begin
if (go_start)
next_state = START;
else if (go_stop)
next_state = STOP;
else
next_state = state;
end
<shared sub-conditions reused in multiple branches, build hierarchical shared condition wires before final checks, example>state == DATA && sck == HIGH.// BEFORE
assign fire_done = (state == DATA) && (sck == HIGH) && (count == MAX);
assign fire_shift = (state == DATA) && (sck == HIGH) && (count > THRESH);
// AFTER
wire state_is_data = (state == DATA);
wire sck_is_high = (sck == HIGH);
wire data_and_sck = state_is_data & sck_is_high;
wire count_is_max = (count == MAX);
wire count_is_gt = (count > THRESH);
assign fire_done = data_and_sck & count_is_max;
assign fire_shift = data_and_sck & count_is_gt;
<FSM / opcode / instruction decode used in many places, one-hot pre-decode encoded values before downstream logic, example>state_is_* / op_is_*, then use them directly.// BEFORE
assign do_add = (opcode == 4'b0001) && valid;
assign do_sub = (opcode == 4'b0010) && valid;
assign do_and = (opcode == 4'b0011) && valid;
// AFTER
wire op_is_add = (opcode == 4'b0001);
wire op_is_sub = (opcode == 4'b0010);
wire op_is_and = (opcode == 4'b0011);
assign do_add = op_is_add & valid;
assign do_sub = op_is_sub & valid;
assign do_and = op_is_and & valid;
<one-hot or bit-encoded state with direct bit meaning, replace full equality with direct bit indexing, example>// BEFORE
wire is_state_5 = (State == 6'b100000);
// AFTER
wire is_state_5 = State[5];
<repeated arithmetic / repeated partial products / repeated shared expressions, common subexpression elimination to a named wire, example>// BEFORE
assign out_a = (x + y) + z;
assign out_b = (x + y) + w;
// AFTER
wire [W-1:0] xy_sum = x + y;
assign out_a = xy_sum + z;
assign out_b = xy_sum + w;
<shared arithmetic across module instances, hoist common subexpression upward and fan out result, example>// BEFORE
child0 u0(.prod_in(a * b), .c(c0));
child1 u1(.prod_in(a * b), .c(c1));
// AFTER
wire [W-1:0] shared_mul = a * b;
child0 u0(.prod_in(shared_mul), .c(c0));
child1 u1(.prod_in(shared_mul), .c(c1));
<high-fanout control or registered signals, duplicate register/signal copies and split fanout cones, example>// BEFORE
reg en;
always @(posedge clk) en <= en_next;
// en drives many distant loads
// AFTER
reg en_a, en_b;
always @(posedge clk) begin
en_a <= en_next;
en_b <= en_next;
end
// split loads between en_a and en_b
<high-fanout combinational condition wire, replicate equivalent local wires for separate consumers, example>// BEFORE
wire state_is_data = (state == DATA);
assign cnt_en = state_is_data & cnt_req;
assign out_en = state_is_data & out_req;
assign flag_set = state_is_data & flag_req;
// AFTER
wire state_is_data_cnt = (state == DATA);
wire state_is_data_out = (state == DATA);
wire state_is_data_flag = (state == DATA);
assign cnt_en = state_is_data_cnt & cnt_req;
assign out_en = state_is_data_out & out_req;
assign flag_set = state_is_data_flag & flag_req;
<wide adder / deep carry chain, carry-select style split into blocks, example>// BEFORE
wire [31:0] sum = a + b;
// AFTER
wire [15:0] sum_lo = a[15:0] + b[15:0];
wire carry_lo = ({1'b0, a[15:0]} + {1'b0, b[15:0]})[16];
wire [15:0] sum_hi_c0 = a[31:16] + b[31:16];
wire [15:0] sum_hi_c1 = a[31:16] + b[31:16] + 1'b1;
wire [15:0] sum_hi = carry_lo ? sum_hi_c1 : sum_hi_c0;
wire [31:0] sum = {sum_hi, sum_lo};
<counter decrement / borrow chain with predictable structure, pre-compute borrow or lookahead-style signals, example>// BEFORE
wire [3:0] dec = a - 4'd1;
// AFTER
wire b0 = ~a[0];
wire b1 = b0 & ~a[1];
wire b2 = b1 & ~a[2];
wire [3:0] dec;
assign dec[0] = ~a[0];
assign dec[1] = a[1] ^ b0;
assign dec[2] = a[2] ^ b1;
assign dec[3] = a[3] ^ b2;
<simple compare against power-of-two threshold / one-hot boundary, simplify wide comparison into bit-select or MSB check, example>count >= 32, direct one-hot state recognition, fixed-point truncation by shift.// BEFORE
wire limit_reached = (data_count >= 6'd32);
wire [15:0] trunc = full_result >>> 8;
// AFTER
wire limit_reached = data_count[5];
wire [15:0] trunc = full_result[23:8];
<FSM outputs driving long downstream logic, register or pipeline the boundary signal when extra latency is architecturally acceptable, example>// BEFORE
wire state_is_data = (next_state == DATA);
assign data_en = state_is_data & ready;
// AFTER
reg state_is_data_r;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state_is_data_r <= 1'b0;
else
state_is_data_r <= (next_state == DATA);
end
assign data_en = state_is_data_r & ready;
<nested ternary / nested mux / branch-dependent data path, compute candidate branch values in parallel and select late, example>sel1 ? (sel2 ? a : b) : (sel2 ? c : d) and similar nested selection structures.// BEFORE
assign out = sel1 ? (sel2 ? a : b) : (sel2 ? c : d);
// AFTER
wire [W-1:0] r_a = a;
wire [W-1:0] r_b = b;
wire [W-1:0] r_c = c;
wire [W-1:0] r_d = d;
assign out = sel1 ? (sel2 ? r_a : r_b) : (sel2 ? r_c : r_d);
<arithmetic gated by control, compute both arithmetic branches and mux result at the end, example>full ? ptr : ptr + 1, en ? a+b : c+d, branch-local arithmetic mixed with control.// BEFORE
assign ptr_n = full ? ptr : (ptr + 1'b1);
// AFTER
wire [W-1:0] ptr_hold = ptr;
wire [W-1:0] ptr_inc = ptr + 1'b1;
assign ptr_n = full ? ptr_hold : ptr_inc;
<sel ? (A+B) : (C+D) style arithmetic mux, move muxes before adder when equivalence is clear, example>(sel?A:C) + (sel?B:D) to reduce adder count/depth.// BEFORE
assign out = sel ? (A + B) : (C + D);
// AFTER
wire [W-1:0] x = sel ? A : C;
wire [W-1:0] y = sel ? B : D;
assign out = x + y;
<deep if-else / default-then-override control chain, flatten into explicit parallel conditions with single-level selection, example>// BEFORE
always @(*) begin
out = v0;
if (cond1)
out = v1;
else if (cond2)
out = v2;
else if (cond3)
out = v3;
end
// AFTER
wire sel1 = cond1;
wire sel2 = !cond1 & cond2;
wire sel3 = !cond1 & !cond2 & cond3;
assign out = sel1 ? v1 : sel2 ? v2 : sel3 ? v3 : v0;
<large case statement with structured outputs, replace with direct AND-OR equations or flattened decode logic, example>// BEFORE
always @(*) begin
case (state)
IDLE: next = START;
START: next = DATA;
DATA: next = STOP;
STOP: next = IDLE;
endcase
end
// AFTER
wire state_is_idle = (state == IDLE);
wire state_is_start = (state == START);
wire state_is_data = (state == DATA);
wire state_is_stop = (state == STOP);
assign next[0] = state_is_idle | state_is_data;
assign next[1] = state_is_start | state_is_data;
<wide OR/AND/XOR reduction, restructure linear logic into balanced tree, example>// BEFORE
wire any_set = a | b | c | d | e | f | g | h;
// AFTER
wire or01 = a | b;
wire or23 = c | d;
wire or45 = e | f;
wire or67 = g | h;
wire or0123 = or01 | or23;
wire or4567 = or45 | or67;
wire any_set = or0123 | or4567;
<wide mux tree or wide selection network, rebalance into multi-level 2:1 tree, example>// BEFORE
assign out = sel[2] ? (sel[1] ? (sel[0] ? d7 : d6) : (sel[0] ? d5 : d4)) :
(sel[1] ? (sel[0] ? d3 : d2) : (sel[0] ? d1 : d0));
// AFTER
wire l10 = sel[0] ? d1 : d0;
wire l11 = sel[0] ? d3 : d2;
wire l12 = sel[0] ? d5 : d4;
wire l13 = sel[0] ? d7 : d6;
wire l20 = sel[1] ? l11 : l10;
wire l21 = sel[1] ? l13 : l12;
assign out = sel[2] ? l21 : l20;
<multi-operand addition, rebalance serial add chain into tree, example>a+b+c+d in a long arithmetic chain.// BEFORE
wire [31:0] sum = a + b + c + d;
// AFTER
wire [31:0] sum_ab = a + b;
wire [31:0] sum_cd = c + d;
wire [31:0] sum = sum_ab + sum_cd;
<large lookup / ROM / decoder, split into hierarchical sub-decoders or subtables, example>// BEFORE
assign data_out = lut_256[data_in];
// AFTER
wire [3:0] hi = data_in[7:4];
wire [3:0] lo = data_in[3:0];
wire [W-1:0] hi_dec = lut_hi[hi];
wire [W-1:0] lo_dec = lut_lo[lo];
assign data_out = combine(hi_dec, lo_dec);
<GF / XOR-heavy datapath / crypto logic, rebalance XOR/AND computation into explicit stages, example>// BEFORE
wire y = x0 ^ x1 ^ x2 ^ x3 ^ x4 ^ x5;
// AFTER
wire x01 = x0 ^ x1;
wire x23 = x2 ^ x3;
wire x45 = x4 ^ x5;
wire y = (x01 ^ x23) ^ x45;
<fixed constant multiplication, replace multiply with shift-add decomposition, example>// BEFORE
wire [W-1:0] prod = x * 9'd257;
// AFTER
wire [W-1:0] prod = (x << 8) + x;
<comparison after mux selection, convert mux-then-compare into compare-then-mux, example>// BEFORE
wire [W-1:0] selected = sel ? a : b;
wire result = (selected > threshold);
// AFTER
wire a_gt = (a > threshold);
wire b_gt = (b > threshold);
wire result = sel ? a_gt : b_gt;
<FSM with multiple related outputs, group states by shared output behavior before final decode, example>// BEFORE
assign active = (state == READ) | (state == WRITE) | (state == START);
// AFTER
wire state_is_read = (state == READ);
wire state_is_write = (state == WRITE);
wire state_is_start = (state == START);
wire state_group_rw = state_is_read | state_is_write;
assign active = state_group_rw | state_is_start;
<CPU / multi-cycle controller with timing-state decode, pre-decode machine-cycle and timing-state bits, example>MCycle, TState, instruction groups, microstate families.// BEFORE
assign is_fetch_t2 = (MCycle == 3'd1) && (TState == 3'd2);
// AFTER
wire mc_is_1 = (MCycle == 3'd1);
wire ts_is_2 = (TState == 3'd2);
wire is_fetch_t2 = mc_is_1 & ts_is_2;
<long combinational expression with unclear synthesis boundary, add explicit intermediate wires to guide mapping, example>// BEFORE
wire [31:0] out = ((a * b) + c) >> sh;
// AFTER
wire [31:0] stage1 = a * b;
wire [31:0] stage2 = stage1 + c;
wire [31:0] out = stage2 >> sh;
<mixed-width arithmetic or truncation boundaries, make width extension/truncation explicit in named wires, example>// BEFORE
wire [15:0] sum_ext = a + b;
// AFTER
wire [15:0] a_ext = {8'b0, a[7:0]};
wire [15:0] b_ext = {8'b0, b[7:0]};
wire [15:0] sum_ext = a_ext + b_ext;
<aggressive arithmetic branch parallelization, compute all arithmetic branches and late-select across complex arithmetic, example>// BEFORE
always @(*) begin
if (sel)
out = a + b;
else
out = c - d;
end
// AFTER
wire [W-1:0] br0 = a + b;
wire [W-1:0] br1 = c - d;
assign out = sel ? br0 : br1;
<control flattening around arithmetic-heavy paths, rewrite state/control logic to expose arithmetic in parallel, example>// BEFORE
always @(*) begin
case (state)
S0: out = a + b;
S1: out = a - b;
default: out = v0;
endcase
end
// AFTER
wire [W-1:0] v1 = a + b;
wire [W-1:0] v2 = a - b;
assign out = (state == S0) ? v1 :
(state == S1) ? v2 : v0;
<arithmetic chain tree balancing with carry/overflow sensitivity, rebalance addition/subtraction structure, example>// BEFORE
wire [W-1:0] y = ((a + b) + c) + d;
// AFTER
wire [W-1:0] t0 = a + b;
wire [W-1:0] t1 = c + d;
wire [W-1:0] y = t0 + t1;
<aggressive mux tree restructuring when synthesis already optimizes muxes well, explicitly force custom mux hierarchy, example>// BEFORE
assign y = s1 ? (s0 ? d3 : d2) : (s0 ? d1 : d0);
// AFTER
wire m0 = s0 ? d1 : d0;
wire m1 = s0 ? d3 : d2;
assign y = s1 ? m1 : m0;
<explicit wire decomposition solely for hoped timing gain, split expression into many named wires without structural change, example>// BEFORE
wire [W-1:0] y = a + b + c + d;
// AFTER
wire [W-1:0] t0 = a + b;
wire [W-1:0] t1 = t0 + c;
wire [W-1:0] y = t1 + d;
<registering decode/control outputs to break timing when architectural latency is uncertain, insert sequential boundary speculatively, example>// BEFORE
assign out = sel ? a : b;
// AFTER
reg sel_r;
always @(posedge clk) begin
sel_r <= sel;
end
assign out = sel_r ? a : b;
<count-up to count-down rewrite or reverse counter direction, change counter direction to simplify terminal detect, example>count == MAX is on the critical path and zero-detect looks cheaper.// BEFORE
always @(posedge clk) begin
if (en)
count <= count + 1'b1;
end
wire hit_max = (count == MAX_COUNT);
// AFTER (DO NOT USE)
always @(posedge clk) begin
if (en)
count <= count - 1'b1;
end
wire hit_max = (count == 0);
<priority if-else chain flattened into parallel AND-OR without guaranteed mutual exclusivity, remove priority semantics, example>// BEFORE
always @(*) begin
if (req0)
grant = 2'b00;
else if (req1)
grant = 2'b01;
else
grant = 2'b11;
end
// AFTER (DO NOT USE)
assign grant[0] = req1;
assign grant[1] = ~req0 & ~req1;
<pre-registering mux selector / control selector on active data path, add register to selector to shorten mux path, example>// BEFORE
assign out = sel ? a : b;
// AFTER (DO NOT USE)
reg sel_r;
always @(posedge clk) sel_r <= sel;
assign out = sel_r ? a : b;
<control-signal pre-registration across module boundary for timing only, insert control pipeline stage without protocol redesign, example>// BEFORE
child u0(.req(req), .ack(ack));
// AFTER (DO NOT USE)
reg req_r;
always @(posedge clk) req_r <= req;
child u0(.req(req_r), .ack(ack));
<operand width reduction / interface width reduction for speed, narrow datapath or module inputs to reduce logic, example>// BEFORE
module foo(input [2*W-1:0] in_data, output [W-1:0] out_data);
// AFTER (DO NOT USE)
module foo(input [W-1:0] in_data, output [W-1:0] out_data);
<algebraic restructuring that changes arithmetic corner behavior, rewrite expression form without proof of overflow/signed equivalence, example>// BEFORE
assign y = (a - b) + c;
// AFTER (DO NOT USE)
assign y = a + (c - b);
<fused subtract-multiply / aggressive arithmetic fusion, collapse arithmetic stages into a new combined structure, example>// BEFORE
wire [W-1:0] t = a - b;
assign y = t * c;
// AFTER (DO NOT USE)
assign y = (a * c) - (b * c);
<changing LFSR feedback or polynomial structure, rewrite feedback network for timing, example>// BEFORE
assign feedback = lfsr[7] ^ lfsr[5];
// AFTER (DO NOT USE)
assign feedback = lfsr[7] ^ lfsr[6];
<modifying memory array addressing / decode architecture from RTL timing path, rewrite memory indexing or address decode casually, example>// BEFORE
assign rd_data = mem[addr];
// AFTER (DO NOT USE)
assign rd_data = (addr_sel ? mem[addr_hi] : mem[addr_lo]);
<optimizing pure register self-loop / constraint-only paths as if they were RTL logic problems, rewrite RTL for clock-to-q/setup-only reports, example>// BEFORE
always @(posedge clk)
q <= d;
// AFTER (DO NOT USE)
// arbitrary RTL restructuring here does not solve a clocking/physical constraint path
always @(posedge clk)
q <= d;
<expression simplification that removes helpful intermediate boundaries, inline everything into one direct expression, example>// BEFORE
wire [W-1:0] t0 = a + b;
wire [W-1:0] y = t0 + c;
// AFTER (DO NOT USE)
wire [W-1:0] y = a + b + c;
<restructured comparison ordering that changes corner-case evaluation semantics, reorder sign/magnitude checks for early exit, example>// BEFORE
assign sat = (x > POS_LIM) || (x < NEG_LIM);
// AFTER (DO NOT USE)
assign sat = x[W-1] ? (x < NEG_LIM) : (x > POS_LIM);
<aggressive tree balancing on paths labeled combinational_depth without understanding arithmetic semantics, mechanically rebalance everything, example>// BEFORE
wire [W-1:0] y = (((a + b) + c) + d) + e;
// AFTER (DO NOT USE)
wire [W-1:0] t0 = a + b;
wire [W-1:0] t1 = c + d;
wire [W-1:0] y = (t0 + t1) + e;