diff --git a/.gitignore b/.gitignore index 9fb7057..636c795 100644 --- a/.gitignore +++ b/.gitignore @@ -219,6 +219,7 @@ outputs/ .claude/settings.local.json openspec/changes/ .logs/ +docs/superpowers # Devenv .devenv* diff --git a/hw/rtl/cam_noisy.sv b/hw/rtl/cam_noisy.sv index ce2cb36..d85cde4 100644 --- a/hw/rtl/cam_noisy.sv +++ b/hw/rtl/cam_noisy.sv @@ -51,7 +51,7 @@ module cam_noisy #( S_COMMIT } state_t; - state_t state_q, state_d; + state_t curr_state, next_state; // ── Latch registers ── logic [(`ROW_BITS)-1:0] addr_q; @@ -60,6 +60,7 @@ module cam_noisy #( // ── Noise generation ── logic [63:0] prng_state; logic [(`HASH_BITS)-1:0] flip_mask; + localparam int MASK_GROUPS = `HASH_BITS / NOISE_GEN_BITS; logic [($clog2(`HASH_BITS/NOISE_GEN_BITS+1))-1:0] mask_group_idx; // 0..HASH_BITS/NOISE_GEN_BITS-1 // ── Precomputed threshold ── @@ -81,49 +82,56 @@ module cam_noisy #( assign noisy_hash = write_hash_q ^ flip_mask; // ── wr_ready: only in IDLE ── - assign wr_ready = (state_q == S_IDLE); + assign wr_ready = (curr_state == S_IDLE); - // ── FSM combinational logic ── + // ── FSM block 1: state register ── + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + curr_state <= S_IDLE; + end else begin + curr_state <= next_state; + end + end + + // ── FSM block 2: next-state logic ── always_comb begin - state_d = state_q; - case (state_q) + next_state = curr_state; + case (curr_state) S_IDLE: begin if (wr_valid && wr_ready) begin if (NOISE_EN && (NOISE_RATE_NUM > 0)) - state_d = S_GEN_MASK; + next_state = S_GEN_MASK; else - state_d = S_COMMIT; + next_state = S_COMMIT; end end S_GEN_MASK: begin - if (mask_group_idx == (`HASH_BITS / NOISE_GEN_BITS - 1)) - state_d = S_COMMIT; + if (int'(mask_group_idx) == (MASK_GROUPS - 1)) + next_state = S_COMMIT; end S_COMMIT: begin - state_d = S_IDLE; + next_state = S_IDLE; end - default: state_d = S_IDLE; + default: next_state = S_IDLE; endcase end - // ── Sequential logic ── + // ── FSM block 3: state actions / datapath registers ── always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin - state_q <= S_IDLE; - addr_q <= '0; - write_hash_q <= '0; - flip_mask <= '0; - prng_state <= NOISE_SEED; + addr_q <= '0; + write_hash_q <= '0; + flip_mask <= '0; + prng_state <= NOISE_SEED; mask_group_idx <= '0; end else begin - state_q <= state_d; - case (state_q) + case (curr_state) S_IDLE: begin - flip_mask <= '0; + flip_mask <= '0; mask_group_idx <= '0; if (wr_valid && wr_ready) begin addr_q <= wr_addr; @@ -141,7 +149,7 @@ module cam_noisy #( for (int b = 0; b < NOISE_GEN_BITS; b++) begin logic [NOISE_SAMPLE_BITS-1:0] sample; sample = prng_next[b * NOISE_SAMPLE_BITS +: NOISE_SAMPLE_BITS]; - if (sample < THRESHOLD) begin + if (int'(sample) < THRESHOLD) begin flip_mask[mask_group_idx * NOISE_GEN_BITS + b] <= 1'b1; end end @@ -164,7 +172,7 @@ module cam_noisy #( logic [(`ROW_BITS)-1:0] core_wr_row; logic [(`HASH_BITS)-1:0] core_wr_hash; - assign core_wr_en = (state_q == S_COMMIT); + assign core_wr_en = (curr_state == S_COMMIT); assign core_wr_row = addr_q; assign core_wr_hash = noisy_hash; diff --git a/hw/rtl/random/random128.sv b/hw/rtl/random/random128.sv new file mode 100644 index 0000000..12e02c9 --- /dev/null +++ b/hw/rtl/random/random128.sv @@ -0,0 +1,57 @@ +`timescale 1ns / 1ps + +module random128 ( + input logic clk, + input logic rst_n, + input logic enable, + input logic [127:0] seed, + output logic [127:0] out +); + + // xorshift128: + // state = {x, y, z, w} + // + // t = x ^ (x << 11) + // x = y + // y = z + // z = w + // w = w ^ (w >> 19) ^ t ^ (t >> 8) + // + // 注意:seed 不能为全 0,否则会永久输出 0。 + function automatic logic [127:0] xorshift128(input logic [127:0] state); + logic [31:0] x; + logic [31:0] y; + logic [31:0] z; + logic [31:0] w; + logic [31:0] t; + logic [31:0] next_x; + logic [31:0] next_y; + logic [31:0] next_z; + logic [31:0] next_w; + + begin + x = state[127:96]; + y = state[95:64]; + z = state[63:32]; + w = state[31:0]; + + t = x ^ (x << 11); + + next_x = y; + next_y = z; + next_z = w; + next_w = w ^ (w >> 19) ^ t ^ (t >> 8); + + return {next_x, next_y, next_z, next_w}; + end + endfunction + + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + out <= seed; + end else if (enable) begin + out <= xorshift128(out); + end + end + +endmodule diff --git a/hw/rtl/random/random32.sv b/hw/rtl/random/random32.sv new file mode 100644 index 0000000..5ee04b5 --- /dev/null +++ b/hw/rtl/random/random32.sv @@ -0,0 +1,28 @@ +`timescale 1ns / 1ps + +module random32 ( + input logic clk, + input logic rst_n, + input logic enable, + input logic [31:0] seed, + output logic [31:0] out +); + + function automatic logic [31:0] xorshift32(input logic [31:0] x); + logic [31:0] s; + s = x; + s ^= s << 13; + s ^= s >> 17; + s ^= s << 5; + return s; + endfunction + + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + out <= seed; + end else if (enable) begin + out <= xorshift32(out); + end + end + +endmodule diff --git a/hw/rtl/random/random64.sv b/hw/rtl/random/random64.sv new file mode 100644 index 0000000..122cd32 --- /dev/null +++ b/hw/rtl/random/random64.sv @@ -0,0 +1,28 @@ +`timescale 1ns / 1ps + +module random64 ( + input logic clk, + input logic rst_n, + input logic enable, + input logic [63:0] seed, + output logic [63:0] out +); + + function automatic logic [63:0] xorshift64(input logic [63:0] x); + logic [63:0] s; + s = x; + s ^= s << 13; + s ^= s >> 7; + s ^= s << 17; + return s; + endfunction + + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + out <= seed; + end else if (enable) begin + out <= xorshift64(out); + end + end + +endmodule