Research-Stack/4-Infrastructure/hardware/Blitter6502OISC_small.v
Brandon Schneider aba1fba7ad fix(adversarial-review): resolve 35 critical coding bugs across 8 subsystems
Security & correctness fixes from full adversarial review:

Lean (7 fixes):
- FixedPoint.lean: guard false theorem with n > 0 precondition
- QFactor.lean: remove double-scaling error in energy decrease
- AVMIsa/Step.lean: implement addSatQ16/subSatQ16 primitives
- BraidEigensolid.lean: fix crossStep second output argument swap
- SSMS.lean: complete ACI preservation proof (with rounding caveat)
- HouseholderQR.lean: add n > 0 precondition to spectral theorem

Verilog (7 fixes):
- q16_lut_core.v: fix multiply shift (16 → 32 bits)
- q16_lut_top.v: fix valid bit (0 → 1)
- cff_accelerator.v: fix SHA-256 padding (len < 448 check)
- research_stack_top.v: fix trigger aliasing (unique counters)
- Blitter6502OISC_small.v: fix address width (15 → 16 bits)
- spatial_hash_bram.v: add OOB write guard
- tmr_oepi_safety_fsm.v: fix double-increment race

WGSL (6 fixes):
- shaders.wgsl: atomicAdd for concurrent writes
- frustration_qubo.wgsl: double-buffer + CAS loop
- braid_fft.wgsl: workgroupBarrier synchronization
- burgers_scar_filter.wgsl: atomic E_bins array

Rust (9 fixes):
- thermodynamic.rs: Arc::from_raw → Arc::clone (double-free)
- thermodynamic.rs: Box::into_raw → Box (leak)
- tools/src/lib.rs: shell injection → shlex.quote
- ene-node/src/lib.rs: LRU caps, constant-time HMAC, peer caps

Python (6 fixes):
- similarity/__init__.py: pickle.load → RestrictedUnpickler
- AI-Feynman: torch.load → weights_only=True (14 calls)
- fetch_arxiv.py, fetch_s2.py: eval → ast.literal_eval
- topology.py: os.system → shutil.copy2
- SSH pipe: os.system → base64 pipe

Build: lake build 3572 jobs, 0 errors
2026-05-31 23:38:03 -05:00

343 lines
12 KiB
Verilog

//------------------------------------------------------------------------------
// 6502 OISC Blitter — 0D Scalar Proof Engine
// Target: Sipeed Tang Nano 9K (GW1NR-LV9QN88PC6/I5)
//
// One-Instruction-Set Computer with 6502 memory map.
// Single instruction: SUBLEQ (Subtract and Branch if Less-or-Equal).
//
// SUBLEQ src dst next:
// MEM[dst] <= MEM[dst] - MEM[src]
// if MEM[dst] <= 0 then PC <= next else PC <= PC + 6
//
// The "blitter" is built from SUBLEQ loops — block memory operations
// that iterate over memory, one cell at a time (0D scalar).
//
// Memory map:
// $0000-$00FF : Zero page (registers, blitter params)
// $0100-$01FF : Stack
// $0200-$02FF : S3C sqrt LUT (256 entries)
// $0300-$03FF : Blitter program segment
// $0400-$7FFF : General memory
// $8000-$FFFF : I/O mapped (LEDs, UART, I2S)
//------------------------------------------------------------------------------
module Blitter6502OISC (
input wire clk,
input wire rst_n,
input wire start,
output reg busy,
output reg [5:0] led,
output reg uart_tx,
// Memory interface (for external loading)
input wire mem_we,
input wire [11:0] mem_addr,
input wire [7:0] mem_wdata,
output wire [7:0] mem_rdata
);
//==========================================================================
// Parameters
//==========================================================================
localparam MEM_SIZE = 4096;
localparam MAX_CYCLES = 24'd1000000; // ~37ms at 27MHz
//==========================================================================
// Memory (64K x 8-bit)
// Implemented as block RAM (BSRAM) on GW1NR
//==========================================================================
reg [7:0] mem [0:MEM_SIZE-1];
reg [15:0] mem_raddr;
// Dual-port memory interface
// Port A: CPU access (synchronous read, synchronous write)
// Port B: External loader access
always @(posedge clk) begin
if (mem_we)
mem[mem_addr] <= mem_wdata;
mem_raddr <= mem_addr;
end
assign mem_rdata = mem[mem_raddr];
//==========================================================================
// CPU State
//==========================================================================
// FIX: Widen pc to 16-bit to match 16-bit address assembly throughout
reg [15:0] pc;
reg [7:0] a_reg; // Accumulator (mirrors $0000)
reg [7:0] x_reg; // X register (mirrors $0001)
reg [7:0] y_reg; // Y register (mirrors $0002)
reg [23:0] cycle_cnt;
reg halted;
// Instruction decode registers
// FIX: Widen address registers to 16-bit to match pc width
reg [15:0] src_addr;
reg [15:0] dst_addr;
reg [15:0] next_addr;
reg [7:0] src_val;
reg [7:0] dst_val;
reg [7:0] result;
// State machine
localparam ST_IDLE = 4'd0;
localparam ST_FETCH_S0 = 4'd1;
localparam ST_FETCH_S1 = 4'd2;
localparam ST_FETCH_D0 = 4'd3;
localparam ST_FETCH_D1 = 4'd4;
localparam ST_FETCH_N0 = 4'd5;
localparam ST_FETCH_N1 = 4'd6;
localparam ST_READ_SRC = 4'd7;
localparam ST_READ_DST = 4'd8;
localparam ST_EXECUTE = 4'd9;
localparam ST_WRITE = 4'd10;
localparam ST_BRANCH = 4'd11;
localparam ST_HALT = 4'd12;
reg [3:0] state;
//==========================================================================
// S3C sqrt LUT (preloaded at $0200-$02FF)
// 256 entries: sqrtLUT8[n] = floor(sqrt(n))
//==========================================================================
initial begin
// First 32 entries (rest loaded via external interface or defaults)
mem[16'h0200] = 8'd0; mem[16'h0201] = 8'd1; mem[16'h0202] = 8'd1; mem[16'h0203] = 8'd1;
mem[16'h0204] = 8'd2; mem[16'h0205] = 8'd2; mem[16'h0206] = 8'd2; mem[16'h0207] = 8'd2;
mem[16'h0208] = 8'd2; mem[16'h0209] = 8'd3; mem[16'h020A] = 8'd3; mem[16'h020B] = 8'd3;
mem[16'h020C] = 8'd3; mem[16'h020D] = 8'd3; mem[16'h020E] = 8'd3; mem[16'h020F] = 8'd3;
mem[16'h0210] = 8'd4; mem[16'h0211] = 8'd4; mem[16'h0212] = 8'd4; mem[16'h0213] = 8'd4;
mem[16'h0214] = 8'd4; mem[16'h0215] = 8'd4; mem[16'h0216] = 8'd4; mem[16'h0217] = 8'd4;
mem[16'h0218] = 8'd4; mem[16'h0219] = 8'd5; mem[16'h021A] = 8'd5; mem[16'h021B] = 8'd5;
mem[16'h021C] = 8'd5; mem[16'h021D] = 8'd5; mem[16'h021E] = 8'd5; mem[16'h021F] = 8'd5;
end
//==========================================================================
// State Machine
//==========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
pc <= 16'h0300; // Program starts at $0300
a_reg <= 8'd0;
x_reg <= 8'd0;
y_reg <= 8'd0;
cycle_cnt <= 24'd0;
halted <= 1'b0;
busy <= 1'b0;
led <= 6'b000000;
state <= ST_IDLE;
end else begin
case (state)
ST_IDLE: begin
if (start) begin
busy <= 1'b1;
pc <= 16'h0300;
cycle_cnt <= 24'd0;
halted <= 1'b0;
state <= ST_FETCH_S0;
end
end
// Fetch src address (2 bytes, little-endian)
ST_FETCH_S0: begin
src_addr[7:0] <= mem[pc];
state <= ST_FETCH_S1;
end
ST_FETCH_S1: begin
src_addr[15:8] <= mem[pc + 16'd1];
state <= ST_FETCH_D0;
end
// Fetch dst address
ST_FETCH_D0: begin
dst_addr[7:0] <= mem[pc + 16'd2];
state <= ST_FETCH_D1;
end
ST_FETCH_D1: begin
dst_addr[15:8] <= mem[pc + 16'd3];
state <= ST_FETCH_N0;
end
// Fetch next address
ST_FETCH_N0: begin
next_addr[7:0] <= mem[pc + 16'd4];
state <= ST_FETCH_N1;
end
ST_FETCH_N1: begin
next_addr[15:8] <= mem[pc + 16'd5];
state <= ST_READ_SRC;
end
// Read src and dst values
ST_READ_SRC: begin
src_val <= mem[src_addr];
state <= ST_READ_DST;
end
ST_READ_DST: begin
dst_val <= mem[dst_addr];
state <= ST_EXECUTE;
end
// Execute: dst = dst - src (unsigned wrap, check signed <= 0)
ST_EXECUTE: begin
result <= dst_val - src_val;
cycle_cnt <= cycle_cnt + 24'd1;
state <= ST_WRITE;
end
// Write result back
ST_WRITE: begin
mem[dst_addr] <= result;
state <= ST_BRANCH;
end
// Branch if result <= 0 (signed interpretation)
// In 8-bit signed: negative if MSB is 1, zero if all bits 0
ST_BRANCH: begin
if (result[7] == 1'b1 || result == 8'd0) begin
// Result <= 0: branch to next_addr
pc <= next_addr;
end else begin
// Result > 0: fall through
pc <= pc + 16'd6;
end
// Check halt conditions
if (cycle_cnt >= MAX_CYCLES) begin
halted <= 1'b1;
busy <= 1'b0;
led <= 6'b111111; // Error: cycle exhausted
state <= ST_HALT;
end else if (next_addr == 16'hFFFF) begin
// Halt opcode: next_addr = $FFFF
halted <= 1'b1;
busy <= 1'b0;
led <= {a_reg[1:0], x_reg[1:0], y_reg[1:0]}; // Success pattern
state <= ST_HALT;
end else begin
state <= ST_FETCH_S0;
end
end
ST_HALT: begin
// Remain halted until reset
halted <= 1'b1;
busy <= 1'b0;
end
default: state <= ST_IDLE;
endcase
end
end
// UART telemetry: when halted, send a_reg as status byte (once only)
reg [3:0] uart_bit_cnt;
reg [15:0] uart_div;
reg [9:0] uart_shift;
reg uart_active;
reg uart_sent; // prevents retransmission
localparam UART_DIV = 16'd233; // 115384 baud at 27MHz (matches Lean uartBaudDivisor)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
uart_tx <= 1'b1;
uart_bit_cnt <= 4'd0;
uart_div <= 16'd0;
uart_shift <= 10'b0;
uart_active <= 1'b0;
uart_sent <= 1'b0;
end else begin
if (halted && !uart_active && !uart_sent) begin
// Send recognizable pattern: 0xAA + a_reg
uart_shift <= {1'b1, 8'hAA, 1'b0}; // stop, 0xAA, start
uart_active <= 1'b1;
uart_bit_cnt <= 4'd0;
uart_div <= 16'd0;
uart_sent <= 1'b1;
end
if (uart_active) begin
if (uart_div >= UART_DIV) begin
uart_div <= 16'd0;
uart_tx <= uart_shift[0];
uart_shift <= {1'b1, uart_shift[9:1]};
uart_bit_cnt <= uart_bit_cnt + 4'd1;
if (uart_bit_cnt >= 4'd9) begin
uart_active <= 1'b0;
uart_tx <= 1'b1;
end
end else begin
uart_div <= uart_div + 16'd1;
end
end
end
end
endmodule
//------------------------------------------------------------------------------
// Blitter Top-Level Wrapper with Clock/Reset
//------------------------------------------------------------------------------
module Blitter6502OISCTop (
input wire clk, // 27 MHz oscillator
input wire rst_n, // Active-low reset
input wire user_btn, // Button to start blitter
output wire [5:0] led,
output wire uart_tx
);
wire btn_pressed = ~user_btn;
reg btn_sync1, btn_sync2, btn_rise;
reg [19:0] debounce_cnt;
// Button debounce (same as SparkleTangNano9KTop)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
btn_sync1 <= 1'b0;
btn_sync2 <= 1'b0;
btn_rise <= 1'b0;
debounce_cnt <= 20'd0;
end else begin
btn_sync1 <= btn_pressed;
btn_sync2 <= btn_sync1;
if (btn_sync2) begin
if (debounce_cnt < 20'd500000)
debounce_cnt <= debounce_cnt + 20'd1;
end else begin
debounce_cnt <= 20'd0;
end
btn_rise <= (debounce_cnt >= 20'd500000) && !btn_sync2;
end
end
// Auto-start: trigger CPU 100ms after reset
reg [31:0] auto_start_cnt;
reg auto_start;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
auto_start_cnt <= 0;
auto_start <= 0;
end else if (!auto_start) begin
if (auto_start_cnt >= 2700000) begin // 100ms at 27MHz
auto_start <= 1;
end else begin
auto_start_cnt <= auto_start_cnt + 1;
end
end
end
// Blitter instance
Blitter6502OISC blitter (
.clk(clk),
.rst_n(rst_n),
.start(auto_start),
.busy(),
.led(led),
.uart_tx(uart_tx),
.mem_we(1'b0),
.mem_addr(12'd0),
.mem_wdata(8'd0),
.mem_rdata()
);
endmodule