diff --git a/run_tb.sh b/run_tb.sh index 6a45154..5815199 100755 --- a/run_tb.sh +++ b/run_tb.sh @@ -120,6 +120,84 @@ execute_tcl() { # each = "snapshot:K:CASE". Launches all specs in parallel, waits, # then prints an ordered summary and returns nonzero if any job failed. PAR_BASE="${TMPDIR:-/tmp}/run_tb_par_$$" + +print_timing_summary() { + local logs=("$@") + local found=0 log + + for log in "${logs[@]}"; do + if [ -f "$log" ] && grep -q '^TIME ' "$log"; then + found=1 + fi + done + [ "$found" -eq 0 ] && return 0 + + echo "" + echo "Timing summary (clk=20MHz, period=50ns)" + printf " %-7s %-3s %-5s %10s %12s %12s %s\n" "OP" "K" "CASE" "cycles" "time_us" "time_ms" "log" + for log in "${logs[@]}"; do + [ -f "$log" ] || continue + awk -v logfile="$log" ' + /^TIME / { + k = ""; c = ""; op = ""; cycles = ""; runtime = ""; + for (i = 1; i <= NF; i++) { + split($i, a, "="); + if (a[1] == "K") k = a[2]; + else if (a[1] == "CASE") c = a[2]; + else if (a[1] == "OP") op = a[2]; + else if (a[1] == "cycles") cycles = a[2]; + else if (a[1] == "runtime") runtime = a[2]; + } + if (runtime != "") { + printf " %-7s %-3s %-5s %10d %12.3f %12.3f %s\n", + op, k, c, cycles, runtime / 1000.0, runtime / 1000000.0, logfile; + } + } + ' "$log" + done + + local found_state=0 + for log in "${logs[@]}"; do + if [ -f "$log" ] && grep -q '^ STATE ' "$log"; then + found_state=1 + fi + done + [ "$found_state" -eq 0 ] && return 0 + + echo "" + echo "State timing breakdown (clk=20MHz, period=50ns)" + printf " %-7s %-3s %-5s %-12s %10s %12s\n" "OP" "K" "CASE" "STATE" "cycles" "time_us" + for log in "${logs[@]}"; do + [ -f "$log" ] || continue + awk ' + /^TIME_BREAKDOWN / { + k = ""; c = ""; op = ""; + for (i = 1; i <= NF; i++) { + split($i, a, "="); + if (a[1] == "K") k = a[2]; + else if (a[1] == "CASE") c = a[2]; + else if (a[1] == "OP") op = a[2]; + } + next; + } + /^ STATE / { + state = $2; + cycles = ""; + time_ns = ""; + for (i = 1; i <= NF; i++) { + split($i, a, "="); + if (a[1] == "cycles") cycles = a[2]; + else if (a[1] == "time_ns") time_ns = a[2]; + } + if (time_ns != "") { + printf " %-7s %-3s %-5s %-12s %10d %12.3f\n", + op, k, c, state, cycles, time_ns / 1000.0; + } + } + ' "$log" + done +} + run_xsim_jobs() { local mtag="$1" pgrep="$2" pmatch="$3"; shift 3 local specs=("$@") @@ -146,12 +224,13 @@ run_xsim_jobs() { wait # ordered summary + per-job log copy to /tmp/run_tb__k*_c*.log - local fail=0 pf nf log + local fail=0 pf nf log timing_logs=() for s in "${specs[@]}"; do IFS=: read -r snap k c <<< "$s" wd="$PAR_BASE/${mtag}_k${k}_c${c}" log="/tmp/run_tb_${mtag}_k${k}_c${c}.log" cp -f "$wd/run.out" "$log" 2>/dev/null + timing_logs+=("$log") pf=$(grep -oE "$pgrep" "$log" | tail -1) nf=$(grep -c 'cannot be opened' "$log") echo " K=$k CASE=$c -> ${pf:-NORESULT} (file-not-found=$nf, log: $log)" @@ -162,6 +241,7 @@ run_xsim_jobs() { { [ "$pf" = "$pmatch" ] && [ "$nf" -eq 0 ]; } || fail=1 fi done + print_timing_summary "${timing_logs[@]}" rm -rf "$PAR_BASE" return $fail } diff --git a/sync_rtl/poly_mul/poly_mul_sync.v b/sync_rtl/poly_mul/poly_mul_sync.v index 1fe3301..6de85bc 100644 --- a/sync_rtl/poly_mul/poly_mul_sync.v +++ b/sync_rtl/poly_mul/poly_mul_sync.v @@ -55,7 +55,11 @@ module poly_mul_sync ( reg [7:0] load_cnt; // 0..256 for loading 256 pairs reg [6:0] comp_k; // 0..127, current base-case index - // Registered basecase_mul results + // Registered basecase_mul inputs/results + reg [11:0] bc_a0_reg, bc_a1_reg; + reg [11:0] bc_b0_reg, bc_b1_reg; + reg [11:0] bc_zeta_reg; + reg bc_valid_reg; reg [11:0] c0_reg, c1_reg; // Combinational read signals for COMP_CALC @@ -73,19 +77,19 @@ module poly_mul_sync ( .zeta (zeta) ); - // Pipelined basecase multiply. One request is issued at a time; the - // output interface is unchanged for top-level consumers. + // Pipelined basecase multiply. One request is issued at a time; inputs are + // registered locally so comp_k does not directly drive the DSP input muxes. wire [11:0] bc_c0, bc_c1; wire bc_vo; basecase_mul_pipe u_bc ( .clk (clk), .rst_n(rst_n), - .valid_i(state == S_COMP_ISSUE), - .a0 (mem_a0), - .a1 (mem_a1), - .b0 (mem_b0), - .b1 (mem_b1), - .zeta(zeta), + .valid_i(bc_valid_reg), + .a0 (bc_a0_reg), + .a1 (bc_a1_reg), + .b0 (bc_b0_reg), + .b1 (bc_b1_reg), + .zeta(bc_zeta_reg), .c0 (bc_c0), .c1 (bc_c1), .valid_o(bc_vo) @@ -122,6 +126,12 @@ module poly_mul_sync ( state <= S_IDLE; load_cnt <= 8'd0; comp_k <= 7'd0; + bc_a0_reg <= 12'd0; + bc_a1_reg <= 12'd0; + bc_b0_reg <= 12'd0; + bc_b1_reg <= 12'd0; + bc_zeta_reg <= 12'd0; + bc_valid_reg <= 1'b0; c0_reg <= 12'd0; c1_reg <= 12'd0; for (i = 0; i < 256; i = i + 1) begin @@ -130,6 +140,7 @@ module poly_mul_sync ( end end else begin state <= next_state; + bc_valid_reg <= 1'b0; // ---- LOAD phase ---- // First coefficient captured on IDLE → LOAD transition @@ -147,6 +158,18 @@ module poly_mul_sync ( end // ---- COMPUTE phase ---- + // COMP_ISSUE: cut the comp_k -> memory mux -> basecase DSP path. + // bc_valid_reg pulses on the following cycle, while these regs hold + // stable inputs through the basecase pipeline launch. + if (state == S_COMP_ISSUE) begin + bc_a0_reg <= mem_a0; + bc_a1_reg <= mem_a1; + bc_b0_reg <= mem_b0; + bc_b1_reg <= mem_b1; + bc_zeta_reg <= zeta; + bc_valid_reg <= 1'b1; + end + // COMP_WAIT: capture pipelined basecase_mul results when ready. if (state == S_COMP_WAIT && bc_vo) begin c0_reg <= bc_c0; diff --git a/sync_rtl/top/TB/tb_mlkem_dec_katK_xsim.v b/sync_rtl/top/TB/tb_mlkem_dec_katK_xsim.v index 397e7b7..b9ff83b 100644 --- a/sync_rtl/top/TB/tb_mlkem_dec_katK_xsim.v +++ b/sync_rtl/top/TB/tb_mlkem_dec_katK_xsim.v @@ -13,7 +13,7 @@ module tb_mlkem_dec_katK_xsim; localparam EKB = 384*KP + 32; // ek_pke bytes within dk localparam DKPB = 384*KP; // dk_pke bytes localparam CTB = (KP==4) ? 1568 : (32*(10*KP+4)); // ct bytes: 768/1088/1568 - localparam integer CLK_PERIOD_NS = 100; // 10 MHz + localparam integer CLK_PERIOD_NS = 50; // 20 MHz localparam integer CLK_HALF_NS = CLK_PERIOD_NS / 2; reg clk=0, rst_n=0, start_i=0; @@ -112,7 +112,7 @@ module tb_mlkem_dec_katK_xsim; integer runtime_ns; begin runtime_ns = cycles * CLK_PERIOD_NS; - $display("TIME K=%0d CASE=%0d OP=%0s cycles=%0d clk=10MHz period=%0dns runtime=%0d ns (%0d.%03d us, %0d.%03d ms)", + $display("TIME K=%0d CASE=%0d OP=%0s cycles=%0d clk=20MHz period=%0dns runtime=%0d ns (%0d.%03d us, %0d.%03d ms)", KP, casenum, op_name, cycles, CLK_PERIOD_NS, runtime_ns, runtime_ns/1000, runtime_ns%1000, runtime_ns/1000000, (runtime_ns%1000000)/1000); diff --git a/sync_rtl/top/TB/tb_mlkem_enc_katK_xsim.v b/sync_rtl/top/TB/tb_mlkem_enc_katK_xsim.v index 9dba17a..967fbc6 100644 --- a/sync_rtl/top/TB/tb_mlkem_enc_katK_xsim.v +++ b/sync_rtl/top/TB/tb_mlkem_enc_katK_xsim.v @@ -12,7 +12,7 @@ module tb_mlkem_enc_katK_xsim; localparam CTB = (KP==4) ? 1568 : (32*(10*KP+4)); // ct bytes: K2 768,K3 1088,K4 1568 localparam DU = (KP==4) ? 11 : 10; // compression du localparam C1B = 32*DU*KP; // c1 byte count: K2 640,K3 960,K4 1408 - localparam integer CLK_PERIOD_NS = 100; // 10 MHz + localparam integer CLK_PERIOD_NS = 50; // 20 MHz localparam integer CLK_HALF_NS = CLK_PERIOD_NS / 2; reg clk=0, rst_n=0, start_i=0; @@ -105,7 +105,7 @@ module tb_mlkem_enc_katK_xsim; integer runtime_ns; begin runtime_ns = cycles * CLK_PERIOD_NS; - $display("TIME K=%0d CASE=%0d OP=%0s cycles=%0d clk=10MHz period=%0dns runtime=%0d ns (%0d.%03d us, %0d.%03d ms)", + $display("TIME K=%0d CASE=%0d OP=%0s cycles=%0d clk=20MHz period=%0dns runtime=%0d ns (%0d.%03d us, %0d.%03d ms)", KP, casenum, op_name, cycles, CLK_PERIOD_NS, runtime_ns, runtime_ns/1000, runtime_ns%1000, runtime_ns/1000000, (runtime_ns%1000000)/1000); diff --git a/sync_rtl/top/TB/tb_mlkem_hello_world_xsim.v b/sync_rtl/top/TB/tb_mlkem_hello_world_xsim.v index 3bf83ff..9a3ff78 100644 --- a/sync_rtl/top/TB/tb_mlkem_hello_world_xsim.v +++ b/sync_rtl/top/TB/tb_mlkem_hello_world_xsim.v @@ -57,7 +57,7 @@ module tb_mlkem_hello_world_xsim; .dbg_mprime_o(dbg_mprime_o), .dbg_kbar_o(dbg_kbar_o), .dbg_decz_o(dbg_decz_o), .dbg_dech_o(dbg_dech_o) ); - always #5 clk = ~clk; + always #25 clk = ~clk; // 20 MHz // storage shuttled between operations (the "wire" between Alice and Bob) reg [7:0] ek_b [0:EKB-1]; diff --git a/sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v b/sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v index 70e2b28..fe8091a 100644 --- a/sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v +++ b/sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v @@ -7,7 +7,7 @@ module tb_mlkem_kg_katK_xsim; parameter KP = 2; localparam EKB = 384*KP + 32; localparam DKB = 768*KP + 96; - localparam integer CLK_PERIOD_NS = 100; // 10 MHz + localparam integer CLK_PERIOD_NS = 50; // 20 MHz localparam integer CLK_HALF_NS = CLK_PERIOD_NS / 2; reg clk=0, rst_n=0, start_i=0; @@ -99,7 +99,7 @@ module tb_mlkem_kg_katK_xsim; integer runtime_ns; begin runtime_ns = cycles * CLK_PERIOD_NS; - $display("TIME K=%0d CASE=%0d OP=%0s cycles=%0d clk=10MHz period=%0dns runtime=%0d ns (%0d.%03d us, %0d.%03d ms)", + $display("TIME K=%0d CASE=%0d OP=%0s cycles=%0d clk=20MHz period=%0dns runtime=%0d ns (%0d.%03d us, %0d.%03d ms)", KP, casenum, op_name, cycles, CLK_PERIOD_NS, runtime_ns, runtime_ns/1000, runtime_ns%1000, runtime_ns/1000000, (runtime_ns%1000000)/1000); diff --git a/sync_rtl/top/TB/tb_mlkem_two_inst_xsim.v b/sync_rtl/top/TB/tb_mlkem_two_inst_xsim.v index 476371c..03a9fa6 100644 --- a/sync_rtl/top/TB/tb_mlkem_two_inst_xsim.v +++ b/sync_rtl/top/TB/tb_mlkem_two_inst_xsim.v @@ -23,7 +23,7 @@ module tb_mlkem_two_inst_xsim; localparam MLEN = 11; // "hello world" reg clk=0; - always #5 clk = ~clk; + always #25 clk = ~clk; // 20 MHz // ---------------- Instance A: KeyGen + Encaps ---------------- reg a_rst_n=0, a_start=0;