--- name: rtl-opt description: Applies local RTL timing optimizations in the user's SystemVerilog style (CSE, hierarchical shared conditions, decode, bit-slice, balanced trees, late mux, equivalent arith rewrite). Use only when the user explicitly asks to optimize RTL, timing, critical path, slack, PPA, or names rtl-opt / /rtl-opt. Do not apply when generating or casually editing DUT. Do not apply to testbench. --- # rtl-opt **預設不套用。** 只有明確說優化、丟 timing report、或叫 `/rtl-opt` 才讀本檔。一般寫 DUT 只走 **`design-format`** + **`rtl-constraint`**。 不管 `00_TESTBED` / `PATTERN` / `TESTBED`。不改規格、不加 latency、不重寫架構。改完仍須通過 `rtl-constraint`。排版走 `design-format`(`always_comb`、`logic`、`if(`、不對齊)。 有 report 時只動對到 critical path 的 cone;沒有 report 時只改使用者指定的那段。 --- ## 控制 / decode ### 1. 重複條件抽成 named logic 同一個 `(state == IDLE)`、`(cmd == START)` 出現多次 → 算一次再重用。 ```systemverilog logic state_is_idle, cmd_is_start, cmd_is_stop; logic go_start, go_stop; always_comb begin state_is_idle = (state == IDLE); cmd_is_start = (cmd == START); cmd_is_stop = (cmd == STOP); go_start = state_is_idle && cmd_is_start; go_stop = state_is_idle && cmd_is_stop; if(go_start) next_state = START; else if(go_stop) next_state = STOP; else next_state = state; end ``` ### 2. 階層共用條件,最後才做 branch check 多個 branch 共用 sub-condition 時,先建原子比較,再合成 prefix,最後才接各自的 check。 ```systemverilog logic state_is_data, sck_is_high, data_and_sck; logic count_is_max, count_is_gt; always_comb begin state_is_data = (state == DATA); sck_is_high = (sck == HIGH); data_and_sck = state_is_data && sck_is_high; count_is_max = (count == MAX); count_is_gt = (count > THRESH); fire_done = data_and_sck && count_is_max; fire_shift = data_and_sck && count_is_gt; end ``` CPU 式 `MCycle` / `TState` 同一套:先 `mc_is_1`、`ts_is_2`,再 AND。 ### 3. Decode 成 `state_is_*` / `op_is_*` FSM / opcode fan-out 時,先解成 boolean,再組控制。 ```systemverilog logic op_is_add, op_is_sub, op_is_and; always_comb begin op_is_add = (opcode == 4'b0001); op_is_sub = (opcode == 4'b0010); op_is_and = (opcode == 4'b0011); do_add = op_is_add && valid; do_sub = op_is_sub && valid; do_and = op_is_and && valid; end ``` ### 4. One-hot 用 bit 編碼保證 one-hot 時,`(State == 6'b100000)` 改 `State[5]`。**不確定編碼就不要改。** ### 5. FSM 重疊 state 先 group 多個輸出吃到重疊的 state 集合 → 先 group,再組輸出。 ```systemverilog logic state_is_read, state_is_write, state_is_start; logic state_group_rw; always_comb begin state_is_read = (state == READ); state_is_write = (state == WRITE); state_is_start = (state == START); state_group_rw = state_is_read || state_is_write; active = state_group_rw || state_is_start; end ``` ### 6. 深 if/else 改互斥 sel,單層 mux 長控制梯、priority 已知時:先做成互斥 `sel`,再單層選擇。`else if` 的 priority 要寫進 `!cond`,不能直接並行掉。 ```systemverilog logic sel1, sel2, sel3; always_comb begin sel1 = cond1; sel2 = !cond1 && cond2; sel3 = !cond1 && !cond2 && cond3; out = (sel1)? v1 : (sel2)? v2 : (sel3)? v3 : v0; end ``` --- ## 運算 CSE / 等價改寫 ### 7. 相同加減乘只算一次 ```systemverilog logic [`DATA_WIDTH-1:0] xy_sum; always_comb begin xy_sum = x + y; out_a = xy_sum + z; out_b = xy_sum + w; end ``` 子 module 都吃 `a * b` 時,在 parent 算一次再 port map(共用運算放運算 module,不要塞 chip top)。 長運算也拆 named stage,讓合成器看得到邊界: ```systemverilog logic [`DATA_WIDTH-1:0] stage1, stage2; always_comb begin stage1 = a * b; stage2 = stage1 + c; out = stage2 >> sh; end ``` ### 8. 常數比較 / 固定 shift 改 slice 語意等價時才改。不要把任意 `>=` 都改成看某一 bit。 ```systemverilog limit_reached = data_count[5]; trunc = full_result[23:8]; ``` ### 9. 常數乘改 shift-add compile-time 常數、且位寬等價時才改。 ```systemverilog prod = (x << 8) + x; ``` ### 10. 位寬延伸 / 截斷寫出來 混寬度加減先零擴或截斷到 named `logic`,不要靠隱式 cast。 ```systemverilog logic [15:0] a_ext, b_ext, sum_ext; always_comb begin a_ext = {8'b0, a[7:0]}; b_ext = {8'b0, b[7:0]}; sum_ext = a_ext + b_ext; end ``` --- ## 結構(不改 latency) ### 11. 長鏈改成平衡 tree OR / XOR / 連加 / 寬 mux 拉成一串時,兩兩合併。中間結果用 named `logic`。 連加 / 加減 tree 只有 **overflow、carry、saturation、截斷** 與原本等價時才做。OR / XOR / mux tree 不受這條限制。 ```systemverilog logic or01, or23, or45, or67, or0123, or4567; always_comb begin or01 = a | b; or23 = c | d; or45 = e | f; or67 = g | h; or0123 = or01 | or23; or4567 = or45 | or67; any_set = or0123 | or4567; end ``` ```systemverilog logic [`DATA_WIDTH-1:0] sum_ab, sum_cd; always_comb begin sum_ab = a + b; sum_cd = c + d; sum = sum_ab + sum_cd; end ``` ```systemverilog logic l10, l11, l12, l13, l20, l21; always_comb begin l10 = sel[0]? d1 : d0; l11 = sel[0]? d3 : d2; l12 = sel[0]? d5 : d4; l13 = sel[0]? d7 : d6; l20 = sel[1]? l11 : l10; l21 = sel[1]? l13 : l12; out = sel[2]? l21 : l20; end ``` ### 12. 算術先算,控制最後 mux `full ? ptr : ptr+1` 這種:兩邊都算,最後才選。面積可能變大,只在這條 path 卡住時做。 ```systemverilog logic [`DATA_WIDTH-1:0] ptr_hold, ptr_inc; always_comb begin ptr_hold = ptr; ptr_inc = ptr + 1'b1; ptr_n = (full)? ptr_hold : ptr_inc; end ``` ### 13. `sel ? (A+B) : (C+D)` 先 mux 再加 等價時改成一顆 adder。 ```systemverilog logic [`DATA_WIDTH-1:0] x, y; always_comb begin x = (sel)? A : C; y = (sel)? B : D; out = x + y; end ``` ### 14. mux 後比較 → 先比較再 mux ```systemverilog logic a_gt, b_gt; always_comb begin a_gt = (a > threshold); b_gt = (b > threshold); result = (sel)? a_gt : b_gt; end ``` --- ## 套用順序 1. 指定 cone 上先做 1–6(條件 / decode) 2. 再做 7–10(CSE / 等價改寫) 3. 長鏈、卡住的 mux/加減再做 11–14 4. 改完檢查單一驅動、無 latch、無 combo loop