The crate is wai-quantum-landscape-fpga, beside the fabric's simulated FPGA member, which has its own workflow. The README gives the board and part as data, what the design does and refuses, what it takes to build, the build and load steps, the checks and the power protocol. No bitstream is distributed: the vendor tool's licence limits a bitstream holding its components to that vendor's devices, which Apache-2.0 does not carry, so the README gives the build and the sha256 of the bitstream measured. measurements/2026-11-05 holds the first version's raw power logs and the predictions committed before them, unchanged. The workflow runs the unit tests and every check against the model of the logic on each change. Co-Authored-By: Claude Opus 5.5 <[email protected]>
457 lines
20 KiB
Verilog
457 lines
20 KiB
Verilog
// SPDX-License-Identifier: Apache-2.0
|
|
// Energy-landscape engine: the two kernels of wai.quantum.landscape/1 (extensions/quantum-landscape.md
|
|
// section 4) for up to 64 cells, in programmable logic. A classical design: three-state cells, a
|
|
// counter-based random stream, no quantum effect.
|
|
//
|
|
// One field cone per cell computes h_i = b_i + sum_j W_ij s_j from the current state, every clock.
|
|
// The couplings W (ternary), the fields b and the cost c are registers the host writes.
|
|
//
|
|
// MODE 0 T0 every cell at once to threshold(h, c): the settle kernel, section 4.1. One sweep
|
|
// per clock; it stops at a fixed point, a two-cycle or the bound.
|
|
// MODE 1 GIBBS one cell at a time, in order, each drawn given the cells before it have just
|
|
// moved: the sample kernel, section 4.2. Four clocks per cell.
|
|
// MODE 2 JACOBI every cell drawn from the same old state and moved together at the end of the
|
|
// sweep. NOT the sample kernel: it does not sample the joint distribution. It is
|
|
// here only as the negative control the spec's coupled test asks to fail.
|
|
//
|
|
// The draw of cell i in sweep k of a chain with seed C is the top 53 bits of out(C, k*n + i + 1),
|
|
// out(s, j) = mix(s + j * 0x9E3779B97F4A7C15), the SplitMix64 output. Cells go in order and the
|
|
// index rises by one per cell, so the engine keeps a counter x, adds the constant once per cell and
|
|
// runs mix() in a nine-stage pipeline that advances once per cell; the host writes x's start
|
|
// (C + the constant) and the pipeline is primed for nine clocks when a job starts.
|
|
//
|
|
// The draw is compared with two cut points the host computes for the cell's field at the sweep's
|
|
// temperature (a = floor(P(-1) 2^53), b = floor((P(-1)+P(0)) 2^53), 54 bits each): -1 if u < a,
|
|
// 0 if u < b, else +1. The table holds 8,192 pairs: 2^(13-WBITS) temperature levels of 2^WBITS
|
|
// fields from WIN_LO. A field outside the window takes threshold(h, c); the host puts the window
|
|
// where every field whose draw is not certain falls inside it, or refuses the job.
|
|
//
|
|
// Register map: src/regs.rs. Cycle counts are part of the contract with src/model.rs.
|
|
`timescale 1ns/1ps
|
|
`default_nettype none
|
|
|
|
module landscape_field (
|
|
input wire [127:0] s, // {neg,pos} per cell
|
|
input wire [127:0] w, // {neg,pos} per coupling, row i
|
|
input wire signed [19:0] b,
|
|
output wire signed [21:0] h
|
|
);
|
|
wire [63:0] p, n;
|
|
genvar j;
|
|
generate
|
|
for (j = 0; j < 64; j = j + 1) begin : T
|
|
assign p[j] = (w[2*j] & s[2*j]) | (w[2*j+1] & s[2*j+1]);
|
|
assign n[j] = (w[2*j] & s[2*j+1]) | (w[2*j+1] & s[2*j]);
|
|
end
|
|
endgenerate
|
|
function automatic signed [2:0] c3(input [2:0] pp, input [2:0] nn);
|
|
c3 = $signed({2'b0, pp[0]}) + $signed({2'b0, pp[1]}) + $signed({2'b0, pp[2]})
|
|
- $signed({2'b0, nn[0]}) - $signed({2'b0, nn[1]}) - $signed({2'b0, nn[2]});
|
|
endfunction
|
|
wire signed [2:0] v0 [0:21];
|
|
wire signed [3:0] v1 [0:10];
|
|
wire signed [4:0] v2 [0:5];
|
|
wire signed [5:0] v3 [0:2];
|
|
wire signed [6:0] v4 [0:1];
|
|
wire signed [7:0] v5;
|
|
genvar k;
|
|
generate
|
|
for (k = 0; k < 21; k = k + 1) begin : C
|
|
assign v0[k] = c3(p[3*k+2:3*k], n[3*k+2:3*k]);
|
|
end
|
|
assign v0[21] = c3({2'b0, p[63]}, {2'b0, n[63]});
|
|
for (k = 0; k < 11; k = k + 1) begin : L1
|
|
assign v1[k] = v0[2*k] + v0[2*k+1];
|
|
end
|
|
for (k = 0; k < 5; k = k + 1) begin : L2
|
|
assign v2[k] = v1[2*k] + v1[2*k+1];
|
|
end
|
|
assign v2[5] = v1[10];
|
|
for (k = 0; k < 3; k = k + 1) begin : L3
|
|
assign v3[k] = v2[2*k] + v2[2*k+1];
|
|
end
|
|
endgenerate
|
|
assign v4[0] = v3[0] + v3[1];
|
|
assign v4[1] = v3[2];
|
|
assign v5 = v4[0] + v4[1];
|
|
assign h = v5 + b;
|
|
endmodule
|
|
|
|
// The low 64 bits of x * K for a 64-bit constant K, in three stages, each stage's registers enabled
|
|
// by `en`: sixteen-bit limbs, the ten partial products that reach the low word, their sums by
|
|
// weight, then the total.
|
|
module landscape_mul64 #(parameter [63:0] K = 64'd0) (
|
|
input wire clk,
|
|
input wire en,
|
|
input wire [63:0] x,
|
|
output reg [63:0] y = 64'd0
|
|
);
|
|
wire [15:0] x0 = x[15:0], x1 = x[31:16], x2 = x[47:32], x3 = x[63:48];
|
|
localparam [15:0] K0 = K[15:0], K1 = K[31:16], K2 = K[47:32], K3 = K[63:48];
|
|
reg [31:0] p00 = 0, p01 = 0, p10 = 0, p02 = 0, p11 = 0, p20 = 0, p03 = 0, p12 = 0, p21 = 0, p30 = 0;
|
|
reg [33:0] w0 = 0, w1 = 0, w2 = 0, w3 = 0;
|
|
always @(posedge clk) if (en) begin
|
|
p00 <= x0 * K0;
|
|
p01 <= x0 * K1; p10 <= x1 * K0;
|
|
p02 <= x0 * K2; p11 <= x1 * K1; p20 <= x2 * K0;
|
|
p03 <= x0 * K3; p12 <= x1 * K2; p21 <= x2 * K1; p30 <= x3 * K0;
|
|
w0 <= {2'b0, p00};
|
|
w1 <= {2'b0, p01} + {2'b0, p10};
|
|
w2 <= {2'b0, p02} + {2'b0, p11} + {2'b0, p20};
|
|
w3 <= {2'b0, p03} + {2'b0, p12} + {2'b0, p21} + {2'b0, p30};
|
|
y <= {30'd0, w0} + {14'd0, w1, 16'd0} + {w2[31:0], 32'd0} + {w3[15:0], 48'd0};
|
|
end
|
|
endmodule
|
|
|
|
// SplitMix64's mix() on a counter: u = top 53 bits of mix(x), nine stages, advancing on `en`.
|
|
module landscape_draws (
|
|
input wire clk,
|
|
input wire load, // x <- x0, the pipeline's contents become stale (prime it)
|
|
input wire [63:0] x0,
|
|
input wire en,
|
|
output wire [52:0] u
|
|
);
|
|
localparam [63:0] GOLDEN = 64'h9E3779B97F4A7C15;
|
|
reg [63:0] x = 64'd0, g1 = 64'd0, g3 = 64'd0, g5 = 64'd0;
|
|
wire [63:0] m1, m2;
|
|
always @(posedge clk) begin
|
|
if (load) x <= x0;
|
|
else if (en) x <= x + GOLDEN;
|
|
if (en) begin
|
|
g1 <= x ^ (x >> 30);
|
|
g3 <= m1 ^ (m1 >> 27);
|
|
g5 <= m2 ^ (m2 >> 31);
|
|
end
|
|
end
|
|
landscape_mul64 #(.K(64'hBF58476D1CE4E5B9)) M1 (.clk(clk), .en(en), .x(g1), .y(m1));
|
|
landscape_mul64 #(.K(64'h94D049BB133111EB)) M2 (.clk(clk), .en(en), .x(g3), .y(m2));
|
|
assign u = g5[63:11];
|
|
endmodule
|
|
|
|
module landscape_core (
|
|
input wire clk,
|
|
input wire reg_stb, // one clock
|
|
input wire reg_we,
|
|
input wire [15:0] reg_addr,
|
|
input wire [31:0] reg_wdata,
|
|
output reg [31:0] reg_rdata,
|
|
output wire busy_o,
|
|
output wire done_o
|
|
);
|
|
localparam MODE_T0 = 2'd0, MODE_GIBBS = 2'd1, MODE_JACOBI = 2'd2;
|
|
localparam [3:0] S_IDLE = 0, S_LOAD = 1, S_T0 = 2, S_REQ = 3, S_TBL = 4, S_COMMIT = 5,
|
|
S_JAC = 6, S_FINAL = 7, S_END = 8, S_IDX = 9, S_PRIME = 10;
|
|
localparam [1:0] TERM_NONE = 0, TERM_FP = 1, TERM_2C = 2, TERM_BOUND = 3;
|
|
localparam integer PRIME = 9; // the draw pipeline's depth
|
|
|
|
// ---- host-written configuration ------------------------------------------------------
|
|
reg [1:0] mode = MODE_T0;
|
|
reg rep = 1'b0;
|
|
reg final_t0 = 1'b0;
|
|
reg [5:0] n_m1 = 6'd0;
|
|
reg [19:0] theta = 20'd0;
|
|
reg [31:0] bound = 32'd0;
|
|
reg [15:0] spl = 16'd1; // sweeps per temperature level
|
|
reg [5:0] levels_m1 = 6'd0;
|
|
reg [127:0] boundary = 128'd0;
|
|
reg [63:0] x0 = 64'd0; // the draw counter's start: chain seed + 0x9E3779B97F4A7C15
|
|
reg signed [21:0] win_lo = 22'sd0; // the table window's first field
|
|
reg [3:0] wbits = 4'd7; // the window holds 2^wbits fields
|
|
|
|
wire w_we = reg_stb & reg_we & (reg_addr[15:8] == 8'h10);
|
|
wire b_we = reg_stb & reg_we & (reg_addr[15:6] == 10'b0000_0010_00);
|
|
reg w_clear = 1'b0;
|
|
|
|
// ---- state ---------------------------------------------------------------------------
|
|
reg [127:0] state = 128'd0;
|
|
reg [127:0] prev = 128'd0;
|
|
reg [127:0] prev2 = 128'd0;
|
|
reg have1 = 1'b0, have2 = 1'b0;
|
|
reg [3:0] fsm = S_IDLE;
|
|
reg done = 1'b0;
|
|
reg [1:0] term = TERM_NONE;
|
|
reg [5:0] sel = 6'd0;
|
|
reg [63:0] sel_hot = 64'd1;
|
|
reg [5:0] level = 6'd0;
|
|
reg [15:0] spl_cnt = 16'd0;
|
|
reg [31:0] steps = 32'd0;
|
|
reg [3:0] prime_cnt = 4'd0;
|
|
|
|
assign busy_o = (fsm != S_IDLE);
|
|
assign done_o = done;
|
|
|
|
// ---- the cones -----------------------------------------------------------------------
|
|
wire signed [21:0] h [0:63];
|
|
wire [63:0] gt, lt;
|
|
wire signed [21:0] th_s = {2'b00, theta};
|
|
wire signed [21:0] nth_s = -th_s;
|
|
genvar i;
|
|
generate
|
|
for (i = 0; i < 64; i = i + 1) begin : CELL
|
|
reg [127:0] row = 128'd0;
|
|
reg signed [19:0] b = 20'sd0;
|
|
always @(posedge clk) begin
|
|
if (w_clear) row <= 128'd0;
|
|
else if (w_we && reg_addr[7:2] == i) begin
|
|
case (reg_addr[1:0])
|
|
2'd0: row[31:0] <= reg_wdata;
|
|
2'd1: row[63:32] <= reg_wdata;
|
|
2'd2: row[95:64] <= reg_wdata;
|
|
2'd3: row[127:96] <= reg_wdata;
|
|
endcase
|
|
end
|
|
if (w_clear) b <= 20'sd0;
|
|
else if (b_we && reg_addr[5:0] == i) b <= reg_wdata[19:0];
|
|
end
|
|
landscape_field f (.s(state), .w(row), .b(b), .h(h[i]));
|
|
assign gt[i] = (h[i] > th_s);
|
|
assign lt[i] = (h[i] < nth_s);
|
|
end
|
|
endgenerate
|
|
|
|
wire signed [21:0] h_sel = h[sel];
|
|
reg signed [21:0] h_reg = 22'sd0;
|
|
reg det_gt = 1'b0, det_lt = 1'b0, in_win = 1'b0;
|
|
reg [12:0] tidx = 13'd0;
|
|
|
|
// ---- the cut-point table: 8,192 x {b[53:0], a[53:0]} -----------------------------------
|
|
(* ram_style = "ultra" *) reg [107:0] tbl [0:8191];
|
|
reg [12:0] tbl_addr = 13'd0;
|
|
reg [53:0] wa = 54'd0; // a, written first
|
|
reg [31:0] tbl_b_lo = 32'd0; // b's low word; b's high word commits the pair
|
|
reg [107:0] tbl_q = 108'd0;
|
|
wire tbl_host_we = reg_stb & reg_we & (reg_addr == 16'h001A);
|
|
wire tbl_run_rd = (fsm == S_TBL);
|
|
reg tbl_host_rd = 1'b0;
|
|
wire [12:0] tbl_a = tbl_run_rd ? tidx : tbl_addr;
|
|
always @(posedge clk)
|
|
if (tbl_run_rd | tbl_host_rd | tbl_host_we) begin
|
|
if (tbl_host_we) tbl[tbl_a] <= {reg_wdata[21:0], tbl_b_lo, wa};
|
|
else tbl_q <= tbl[tbl_a];
|
|
end
|
|
wire [53:0] cut_a = tbl_q[53:0];
|
|
wire [53:0] cut_b = tbl_q[107:54];
|
|
|
|
// ---- the draws -------------------------------------------------------------------------
|
|
wire sampling = (mode == MODE_GIBBS) | (mode == MODE_JACOBI);
|
|
wire draw_load = (fsm == S_LOAD) & sampling;
|
|
wire draw_adv = (fsm == S_PRIME) | (fsm == S_COMMIT);
|
|
wire [52:0] u;
|
|
landscape_draws D (.clk(clk), .load(draw_load), .x0(x0), .en(draw_adv), .u(u));
|
|
|
|
wire [54:0] uz = {2'b00, u};
|
|
wire u_lt_a = (uz < {1'b0, cut_a});
|
|
wire u_lt_b = (uz < {1'b0, cut_b});
|
|
wire [1:0] s_cut = u_lt_a ? 2'b10 : (u_lt_b ? 2'b00 : 2'b01);
|
|
wire [1:0] s_smp = in_win ? s_cut : {det_lt, det_gt};
|
|
|
|
// ---- termination, on registers only ----------------------------------------------------
|
|
wire eq1 = (state == prev);
|
|
wire eq2 = (state == prev2);
|
|
wire step_limit = (steps == bound);
|
|
wire last_cell = (sel == n_m1);
|
|
wire last_sweep = (steps + 32'd1 == bound);
|
|
|
|
wire t0_terminal = (have1 & eq1) | (have2 & eq2) | step_limit;
|
|
wire t0_commit = ((fsm == S_T0) & ~t0_terminal) | (fsm == S_FINAL);
|
|
wire g_commit = (fsm == S_COMMIT) & (mode == MODE_GIBBS);
|
|
wire j_commit = (fsm == S_COMMIT) & (mode == MODE_JACOBI);
|
|
wire jac_all = (fsm == S_JAC);
|
|
wire load_state = (fsm == S_LOAD) | (reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[3] & (fsm == S_IDLE));
|
|
|
|
generate
|
|
for (i = 0; i < 64; i = i + 1) begin : UPD
|
|
always @(posedge clk) begin
|
|
if (load_state) state[2*i +: 2] <= boundary[2*i +: 2];
|
|
else if (t0_commit) state[2*i +: 2] <= {lt[i], gt[i]};
|
|
else if (jac_all) state[2*i +: 2] <= prev[2*i +: 2];
|
|
else if (g_commit & sel_hot[i]) state[2*i +: 2] <= s_smp;
|
|
|
|
if (load_state) prev[2*i +: 2] <= boundary[2*i +: 2];
|
|
else if (t0_commit) prev[2*i +: 2] <= state[2*i +: 2];
|
|
else if (j_commit & sel_hot[i]) prev[2*i +: 2] <= s_smp;
|
|
|
|
if (t0_commit) prev2[2*i +: 2] <= prev[2*i +: 2];
|
|
end
|
|
end
|
|
endgenerate
|
|
|
|
// ---- counters ------------------------------------------------------------------------
|
|
reg [47:0] uptime = 48'd0;
|
|
reg [47:0] cycles = 48'd0;
|
|
reg [47:0] updates = 48'd0;
|
|
reg [47:0] jobs = 48'd0;
|
|
reg [20:0] rd_hi = 21'd0;
|
|
|
|
wire start = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[0];
|
|
wire cont = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[1];
|
|
wire stop = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[2];
|
|
wire clrw = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[4];
|
|
wire clrc = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[5];
|
|
|
|
// the window offset and the level's base, for the table index
|
|
wire signed [22:0] d_full = {h_reg[21], h_reg} - {win_lo[21], win_lo};
|
|
wire [13:0] wsize = 14'd1 << wbits;
|
|
wire [12:0] lbase = {7'd0, level} << wbits;
|
|
|
|
always @(posedge clk) begin
|
|
uptime <= uptime + 48'd1;
|
|
w_clear <= clrw;
|
|
tbl_host_rd <= reg_stb & reg_we & (reg_addr == 16'h0016);
|
|
|
|
if (clrc) begin
|
|
cycles <= 48'd0; updates <= 48'd0; jobs <= 48'd0;
|
|
end else begin
|
|
if (fsm != S_IDLE) cycles <= cycles + 48'd1;
|
|
if (fsm == S_COMMIT) updates <= updates + 48'd1;
|
|
if (fsm == S_END) jobs <= jobs + 48'd1;
|
|
end
|
|
|
|
if (fsm == S_REQ || fsm == S_IDLE) h_reg <= h_sel;
|
|
if (fsm == S_IDX) begin
|
|
in_win <= (d_full >= 23'sd0) && (d_full < $signed({9'd0, wsize}));
|
|
tidx <= lbase + d_full[12:0];
|
|
det_gt <= (h_reg > th_s);
|
|
det_lt <= (h_reg < nth_s);
|
|
end
|
|
|
|
case (fsm)
|
|
S_IDLE: begin
|
|
if (start) begin
|
|
fsm <= S_LOAD; done <= 1'b0; term <= TERM_NONE;
|
|
end else if (cont) begin
|
|
done <= 1'b0; term <= TERM_NONE; steps <= 32'd0;
|
|
level <= 6'd0; spl_cnt <= 16'd0; sel <= 6'd0; sel_hot <= 64'd1;
|
|
have1 <= 1'b0; have2 <= 1'b0;
|
|
fsm <= (mode == MODE_T0) ? S_T0 : S_REQ;
|
|
end
|
|
end
|
|
S_LOAD: begin
|
|
steps <= 32'd0; level <= 6'd0; spl_cnt <= 16'd0; sel <= 6'd0; sel_hot <= 64'd1;
|
|
have1 <= 1'b0; have2 <= 1'b0; prime_cnt <= 4'd0;
|
|
fsm <= (mode == MODE_T0) ? S_T0 : S_PRIME;
|
|
end
|
|
S_PRIME: begin
|
|
prime_cnt <= prime_cnt + 4'd1;
|
|
if (prime_cnt == PRIME - 1)
|
|
fsm <= (bound == 32'd0) ? (final_t0 ? S_FINAL : S_END) : S_REQ;
|
|
end
|
|
S_T0: begin
|
|
if (t0_terminal) begin
|
|
term <= (have1 & eq1) ? TERM_FP : ((have2 & eq2) ? TERM_2C : TERM_BOUND);
|
|
fsm <= S_END;
|
|
end else begin
|
|
steps <= steps + 32'd1;
|
|
have1 <= 1'b1;
|
|
have2 <= have1;
|
|
end
|
|
end
|
|
S_REQ: fsm <= S_IDX;
|
|
S_IDX: fsm <= S_TBL;
|
|
S_TBL: fsm <= S_COMMIT;
|
|
S_COMMIT: begin
|
|
if (last_cell) begin
|
|
sel <= 6'd0; sel_hot <= 64'd1;
|
|
if (mode == MODE_JACOBI) fsm <= S_JAC;
|
|
else begin
|
|
steps <= steps + 32'd1;
|
|
if (last_sweep) fsm <= final_t0 ? S_FINAL : S_END;
|
|
else begin
|
|
fsm <= S_REQ;
|
|
if (spl_cnt + 16'd1 == spl) begin
|
|
spl_cnt <= 16'd0;
|
|
if (level != levels_m1) level <= level + 6'd1;
|
|
end else spl_cnt <= spl_cnt + 16'd1;
|
|
end
|
|
end
|
|
end else begin
|
|
sel <= sel + 6'd1;
|
|
sel_hot <= {sel_hot[62:0], 1'b0};
|
|
fsm <= S_REQ;
|
|
end
|
|
end
|
|
S_JAC: begin
|
|
steps <= steps + 32'd1;
|
|
if (last_sweep) fsm <= final_t0 ? S_FINAL : S_END;
|
|
else begin
|
|
fsm <= S_REQ;
|
|
if (spl_cnt + 16'd1 == spl) begin
|
|
spl_cnt <= 16'd0;
|
|
if (level != levels_m1) level <= level + 6'd1;
|
|
end else spl_cnt <= spl_cnt + 16'd1;
|
|
end
|
|
end
|
|
S_FINAL: fsm <= S_END;
|
|
S_END: begin
|
|
if (rep) fsm <= S_LOAD;
|
|
else begin fsm <= S_IDLE; done <= 1'b1; end
|
|
end
|
|
default: fsm <= S_IDLE;
|
|
endcase
|
|
|
|
if (stop) begin fsm <= S_IDLE; done <= 1'b0; end
|
|
|
|
// ---- register writes -------------------------------------------------------------
|
|
if (reg_stb && reg_we) begin
|
|
case (reg_addr)
|
|
16'h0004: begin mode <= reg_wdata[1:0]; rep <= reg_wdata[8]; final_t0 <= reg_wdata[9]; end
|
|
16'h0005: n_m1 <= reg_wdata[5:0];
|
|
16'h0006: theta <= reg_wdata[19:0];
|
|
16'h0007: bound <= reg_wdata;
|
|
16'h0008: spl <= reg_wdata[15:0];
|
|
16'h0009: levels_m1 <= reg_wdata[5:0];
|
|
16'h0010: x0[31:0] <= reg_wdata;
|
|
16'h0011: x0[63:32] <= reg_wdata;
|
|
16'h0012: win_lo <= reg_wdata[21:0];
|
|
16'h0013: wbits <= reg_wdata[3:0];
|
|
16'h0014: if (fsm == S_IDLE) sel <= reg_wdata[5:0];
|
|
16'h0016: tbl_addr <= reg_wdata[12:0];
|
|
16'h0017: wa[31:0] <= reg_wdata;
|
|
16'h0018: wa[53:32] <= reg_wdata[21:0];
|
|
16'h0019: tbl_b_lo <= reg_wdata;
|
|
16'h001A: tbl_addr <= tbl_addr + 13'd1;
|
|
16'h0100: boundary[31:0] <= reg_wdata;
|
|
16'h0101: boundary[63:32] <= reg_wdata;
|
|
16'h0102: boundary[95:64] <= reg_wdata;
|
|
16'h0103: boundary[127:96] <= reg_wdata;
|
|
default: ;
|
|
endcase
|
|
end
|
|
|
|
// ---- register reads --------------------------------------------------------------
|
|
if (reg_stb && !reg_we) begin
|
|
case (reg_addr)
|
|
16'h0000: reg_rdata <= 32'h4C414E44; // "LAND"
|
|
16'h0001: reg_rdata <= 32'h0040_4002; // 64 cells, 64 levels, rtl version 2
|
|
16'h0002: reg_rdata <= {28'd0, term, done, busy_o};
|
|
16'h0004: reg_rdata <= {22'd0, final_t0, rep, 6'd0, mode};
|
|
16'h0005: reg_rdata <= {26'd0, n_m1};
|
|
16'h0006: reg_rdata <= {12'd0, theta};
|
|
16'h0007: reg_rdata <= bound;
|
|
16'h0012: reg_rdata <= {{10{win_lo[21]}}, win_lo};
|
|
16'h0013: reg_rdata <= {28'd0, wbits};
|
|
16'h0015: reg_rdata <= {{10{h_reg[21]}}, h_reg};
|
|
16'h0016: reg_rdata <= {19'd0, tbl_addr};
|
|
16'h0017: reg_rdata <= tbl_q[31:0];
|
|
16'h0018: reg_rdata <= {10'd0, tbl_q[53:32]};
|
|
16'h0019: reg_rdata <= tbl_q[85:54];
|
|
16'h001A: reg_rdata <= {10'd0, tbl_q[107:86]};
|
|
16'h001B: begin reg_rdata <= u[31:0]; rd_hi <= u[52:32]; end
|
|
16'h001C: reg_rdata <= {11'd0, rd_hi};
|
|
16'h0020: begin reg_rdata <= uptime[31:0]; rd_hi <= {5'd0, uptime[47:32]}; end
|
|
16'h0022: begin reg_rdata <= cycles[31:0]; rd_hi <= {5'd0, cycles[47:32]}; end
|
|
16'h0024: begin reg_rdata <= updates[31:0]; rd_hi <= {5'd0, updates[47:32]}; end
|
|
16'h0026: begin reg_rdata <= jobs[31:0]; rd_hi <= {5'd0, jobs[47:32]}; end
|
|
16'h0021, 16'h0023, 16'h0025, 16'h0027: reg_rdata <= {11'd0, rd_hi};
|
|
16'h0028: reg_rdata <= steps;
|
|
16'h0110: reg_rdata <= state[31:0];
|
|
16'h0111: reg_rdata <= state[63:32];
|
|
16'h0112: reg_rdata <= state[95:64];
|
|
16'h0113: reg_rdata <= state[127:96];
|
|
default: reg_rdata <= 32'hDEAD_BEEF;
|
|
endcase
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
`default_nettype wire
|