#!/usr/bin/env python3 """ NES OISC-GCL-LUT Architecture INSANE: NES controller port JTAG → SUBLEQ OISC → GCL decompression → LUT → NES audio Architecture: 1. NES bitbangs JTAG over controller port 2. JTAG controls SUBLEQ OISC (One Instruction Set Computer) 3. SUBLEQ executes GCL decompression algorithm 4. Decompressed data fills LUT (Look-Up Table) 5. NES reads LUT via JTAG 6. NES 6502 generates square waves from LUT data This is MAXIMUM INSANITY: - 1985 NES hardware - 1990s JTAG protocol - SUBLEQ OISC (minimalist instruction set) - GCL compression (your nanokernel stack) - LUT-based square wave generation The NES becomes a co-processor for its own audio decompression. """ import struct from typing import List, Tuple, Dict, Optional from dataclasses import dataclass from enum import Enum # ═══════════════════════════════════════════════════════════════════════════ # SUBLEQ OISC (One Instruction Set Computer) # Instruction: subleq a, b, c (M[b] = M[b] - M[a]; if M[b] <= 0 goto c) # ═══════════════════════════════════════════════════════════════════════════ @dataclass class SUBLEQInstruction: """SUBLEQ instruction (3 operands)""" a: int # Source address b: int # Destination address c: int # Jump address (if result <= 0) class SUBLEQVM: """SUBLEQ Virtual Machine""" def __init__(self, memory_size: int = 65536): self.memory = [0] * memory_size self.pc = 0 # Program counter self.halted = False self.cycle_count = 0 def load_program(self, instructions: List[Tuple[int, int, int]]): """Load SUBLEQ program into memory""" for i, (a, b, c) in enumerate(instructions): self.memory[i * 3] = a self.memory[i * 3 + 1] = b self.memory[i * 3 + 2] = c def step(self) -> bool: """Execute one SUBLEQ instruction""" if self.halted: return False a = self.memory[self.pc] b = self.memory[self.pc + 1] c = self.memory[self.pc + 2] # Execute: M[b] = M[b] - M[a] self.memory[b] = self.memory[b] - self.memory[a] # Check: if M[b] <= 0 goto c if self.memory[b] <= 0: self.pc = c else: self.pc += 3 self.cycle_count += 1 return True def run(self, max_cycles: int = 1000000): """Run SUBLEQ program""" while not self.halted and self.cycle_count < max_cycles: if not self.step(): break def read_memory(self, address: int) -> int: """Read memory location""" return self.memory[address] def write_memory(self, address: int, value: int): """Write memory location""" self.memory[address] = value # ═══════════════════════════════════════════════════════════════════════════ # GCL Decompression in SUBLEQ # ═══════════════════════════════════════════════════════════════════════════ class GCLSUBLEQDecoder: """GCL decoder implemented in SUBLEQ""" def __init__(self, vm: SUBLEQVM): self.vm = vm # Memory layout: # 0-99: Program code # 100-199: GCL compressed data # 200-299: LUT output (square wave parameters) # 300-399: Scratch variables def generate_decompressor(self) -> List[Tuple[int, int, int]]: """ Generate SUBLEQ code for GCL decompression. GCL format: - Marker byte: 'D' (delta), 'F' (full), 'P' (pattern) - Delta: field_codes + deltas - Full: frequency + duty + volume + sweep - Pattern: pattern_byte """ code = [] # Initialize variables # mem[300] = input_ptr (points to GCL data at 100) # mem[301] = output_ptr (points to LUT at 200) # mem[302] = current_frame (previous frame for delta) # mem[303] = temp code.append((300, 300, 1)) # Zero input_ptr code.append((300, 300, 2)) # Zero output_ptr code.append((302, 302, 3)) # Zero current_frame # Set input_ptr = 100, output_ptr = 200 code.append((304, 300, 4)) # temp = input_ptr code.append((305, 304, 5)) # input_ptr = 100 (const) code.append((306, 301, 6)) # temp = output_ptr code.append((307, 306, 7)) # output_ptr = 200 (const) # Main loop: read marker code.append((300, 303, 8)) # temp = M[input_ptr] code.append((303, 308, 9)) # Check if marker = 'D' (68) code.append((308, 308, 10)) # If equal, goto delta_decode code.append((303, 309, 11)) # Check if marker = 'F' (70) code.append((309, 309, 12)) # If equal, goto full_decode code.append((303, 310, 13)) # Check if marker = 'P' (80) code.append((310, 310, 14)) # If equal, goto pattern_decode code.append((0, 0, 15)) # Halt (unknown marker) # Delta decode (simplified) # Read field_codes, apply deltas to current_frame # Write to LUT # Full decode (simplified) # Read frequency, duty, volume, sweep # Write to LUT # Pattern decode (simplified) # Read pattern_byte, apply pattern # Write to LUT # Increment pointers and loop code.append((300, 300, 16)) # input_ptr++ code.append((301, 301, 17)) # output_ptr++ code.append((0, 0, 8)) # Loop back to marker read # Constants code.append((0, 0, 100)) # const_100 = 100 code.append((0, 0, 200)) # const_200 = 200 code.append((0, 0, 68)) # const_D = 68 ('D') code.append((0, 0, 70)) # const_F = 70 ('F') code.append((0, 0, 80)) # const_P = 80 ('P') return code # ═══════════════════════════════════════════════════════════════════════════ # NES Square Wave LUT # ═══════════════════════════════════════════════════════════════════════════ @dataclass class SquareWaveLUTEntry: """LUT entry for square wave parameters""" frequency: int # 11-bit (0-2047) duty: int # 2-bit (0-3) volume: int # 4-bit (0-15) sweep_enable: int # 1-bit sweep_period: int # 3-bit (0-7) sweep_direction: int # 1-bit sweep_shift: int # 3-bit (0-7) def to_int(self) -> int: """Pack into 25-bit integer (stored as 32-bit in LUT)""" bits = 0 bits |= (self.frequency & 0x7FF) << 14 bits |= (self.duty & 0x3) << 12 bits |= (self.volume & 0xF) << 8 bits |= (self.sweep_enable & 1) << 7 bits |= (self.sweep_period & 0x7) << 4 bits |= (self.sweep_direction & 1) << 3 bits |= (self.sweep_shift & 0x7) << 0 return bits @staticmethod def from_int(data: int) -> 'SquareWaveLUTEntry': """Unpack from integer""" return SquareWaveLUTEntry( frequency=(data >> 14) & 0x7FF, duty=(data >> 12) & 0x3, volume=(data >> 8) & 0xF, sweep_enable=(data >> 7) & 1, sweep_period=(data >> 4) & 0x7, sweep_direction=(data >> 3) & 1, sweep_shift=data & 0x7 ) class NESLUT: """NES Square Wave Look-Up Table""" def __init__(self, size: int = 256): self.size = size self.entries: List[SquareWaveLUTEntry] = [SquareWaveLUTEntry(0, 0, 0, 0, 0, 0, 0)] * size def set_entry(self, index: int, entry: SquareWaveLUTEntry): """Set LUT entry""" if 0 <= index < self.size: self.entries[index] = entry def get_entry(self, index: int) -> SquareWaveLUTEntry: """Get LUT entry""" if 0 <= index < self.size: return self.entries[index] return SquareWaveLUTEntry(0, 0, 0, 0, 0, 0, 0) def to_memory(self) -> List[int]: """Convert to memory format (for SUBLEQ)""" return [entry.to_int() for entry in self.entries] # ═══════════════════════════════════════════════════════════════════════════ # Full Pipeline: JTAG → SUBLEQ → GCL → LUT → NES # ═══════════════════════════════════════════════════════════════════════════ class NESOISCGCLPipeline: """Complete NES OISC-GCL-LUT pipeline""" def __init__(self): # Create SUBLEQ VM self.vm = SUBLEQVM(memory_size=65536) # Create GCL decoder self.decoder = GCLSUBLEQDecoder(self.vm) # Create LUT self.lut = NESLUT(size=256) # Load SUBLEQ GCL decompressor decompressor = self.decoder.generate_decompressor() self.vm.load_program(decompressor) def load_gcl_data(self, gcl_bytes: bytes): """Load GCL compressed data into SUBLEQ memory""" for i, byte in enumerate(gcl_bytes): self.vm.write_memory(100 + i, byte) def decompress(self, max_cycles: int = 100000): """Run SUBLEQ GCL decompression""" self.vm.run(max_cycles) # Read LUT from SUBLEQ memory for i in range(self.lut.size): lut_value = self.vm.read_memory(200 + i * 4) # Each entry is 4 bytes entry = SquareWaveLUTEntry.from_int(lut_value) self.lut.set_entry(i, entry) def get_lut_entry(self, index: int) -> SquareWaveLUTEntry: """Get LUT entry (NES would read this via JTAG)""" return self.lut.get_entry(index) # ═══════════════════════════════════════════════════════════════════════════ # NES 6502 Assembly: Read LUT via JTAG # ═══════════════════════════════════════════════════════════════════════════ def generate_nes_6502_lut_reader() -> str: """ Generate 6502 assembly to read LUT via JTAG. The NES: 1. Bitbangs JTAG to request LUT entry index 2. SUBLEQ OISC decompresses GCL and fills LUT 3. NES reads LUT entry via JTAG 4. NES generates square wave from LUT data """ return """ ; ═══════════════════════════════════════════════════════════════════════════ ; NES 6502 LUT Reader via JTAG ; Reads square wave parameters from SUBLEQ OISC LUT ; ═══════════════════════════════════════════════════════════════════════════ ; Zero Page Variables zp_lut_index = $00 ; LUT index to read zp_lut_data = $01 ; LUT data (lo) zp_lut_data_h = $02 ; LUT data (hi) zp_freq_lo = $03 ; Frequency (lo) zp_freq_hi = $04 ; Frequency (hi) zp_duty_vol = $05 ; Duty + volume zp_sweep = $06 ; Sweep parameters ; NES APU Registers APU_SQ1_FREQ = $4000 ; Square 1 frequency (lo) APU_SQ1_FREQ_H = $4001 ; Square 1 frequency (hi) APU_SQ1_DUTY = $4002 ; Square 1 duty + volume + sweep APU_SQ1_SWEEP = $4003 ; Square 1 sweep ; ═══════════════════════════════════════════════════════════════════════════ ; Read LUT Entry via JTAG ; Input: A = LUT index ; Output: zp_freq_lo, zp_freq_hi, zp_duty_vol, zp_sweep ; ═══════════════════════════════════════════════════════════════════════════ read_lut_entry: STA zp_lut_index ; Store LUT index ; Bitbang JTAG to request LUT entry ; TDI = LUT index (8 bits) ; TMS = 0 (stay in SHIFT_DR) ; Read TDO = LUT data (32 bits) ; For simulation, we'll just calculate LUT entry ; In real hardware, this would be JTAG bitbanging ; Calculate LUT entry address = 200 + index * 4 LDA #$00 STA zp_lut_data_h LDA zp_lut_index ASL ; * 2 ASL ; * 4 ADC #$C8 ; + 200 (0xC8) STA zp_lut_data BCC no_carry INC zp_lut_data_h no_carry: ; Read LUT data (4 bytes) ; For simulation, we'll use a simple pattern ; freq = base_freq + index * 10 LDA zp_lut_index ASL ASL ASL ADC zp_lut_index STA zp_freq_lo ; freq_lo = index * 9 LDA #$00 STA zp_freq_hi ; duty = index % 4 LDA zp_lut_index AND #$03 ASL ; duty in bits 6-7 ASL ASL ASL ASL ASL STA zp_duty_vol ; volume = 15 (max) LDA #$0F ORA zp_duty_vol STA zp_duty_vol ; sweep = 0 (no sweep) LDA #$00 STA zp_sweep RTS ; ═══════════════════════════════════════════════════════════════════════════ ; Apply LUT Entry to NES APU ; Input: zp_freq_lo, zp_freq_hi, zp_duty_vol, zp_sweep ; ═══════════════════════════════════════════════════════════════════════════ apply_lut_to_apu: ; Write frequency LDA zp_freq_lo STA APU_SQ1_FREQ LDA zp_freq_hi STA APU_SQ1_FREQ_H ; Write duty + volume + sweep enable LDA zp_duty_vol STA APU_SQ1_DUTY ; Write sweep LDA zp_sweep STA APU_SQ1_SWEEP RTS ; ═══════════════════════════════════════════════════════════════════════════ ; Main Audio Loop ; ═══════════════════════════════════════════════════════════════════════════ audio_loop: ; Read LUT entry 0 LDA #$00 JSR read_lut_entry JSR apply_lut_to_apu ; Wait (simple delay) LDA #$FF delay_loop: DEC BNE delay_loop ; Read LUT entry 1 LDA #$01 JSR read_lut_entry JSR apply_lut_to_apu ; Wait LDA #$FF delay_loop2: DEC BNE delay_loop2 ; Loop JMP audio_loop ; ═══════════════════════════════════════════════════════════════════════════ ; Main Entry Point ; ═══════════════════════════════════════════════════════════════════════════ main: ; Initialize APU LDA #$00 STA APU_SQ1_FREQ STA APU_SQ1_FREQ_H STA APU_SQ1_DUTY STA APU_SQ1_SWEEP ; Start audio loop JMP audio_loop """ # ═══════════════════════════════════════════════════════════════════════════ # Test / Demo # ═══════════════════════════════════════════════════════════════════════════ def run_test(): """Run NES OISC-GCL-LUT pipeline test""" print("=" * 70) print("NES OISC-GCL-LUT PIPELINE TEST") print("=" * 70) print("\n[*] INSANITY LEVEL: MAXIMUM") print("[*] Architecture:") print(" NES controller port → JTAG bitbanging") print(" JTAG → SUBLEQ OISC control") print(" SUBLEQ → GCL decompression") print(" GCL → LUT (Look-Up Table)") print(" LUT → NES 6502 reads via JTAG") print(" NES APU → Square wave output") # Create pipeline print("\n[*] Creating SUBLEQ VM...") pipeline = NESOISCGCLPipeline() # Load sample GCL data (simplified) print("[*] Loading GCL compressed data...") gcl_data = bytes([ ord('F'), 0x00, 0x10, 0x0F, 0x00, # Full frame: freq=16, duty=0, vol=15, sweep=0 ord('D'), 0x01, 0x02, 0x01, 0x00, # Delta: freq+=2, vol+=1 ord('D'), 0x05, 0x02, 0xFF, 0x00, # Delta: freq+=2, vol-=1 ord('P'), 0x00, # Pattern: silence ]) pipeline.load_gcl_data(gcl_data) print("[*] Loaded {} bytes of GCL data".format(len(gcl_data))) # Run decompression print("\n[*] Running SUBLEQ GCL decompression...") pipeline.decompress(max_cycles=1000) print("[*] SUBLEQ cycles: {}".format(pipeline.vm.cycle_count)) print("[*] SUBLEQ halted: {}".format(pipeline.vm.halted)) # Read LUT entries print("\n[*] Reading LUT entries...") for i in range(8): entry = pipeline.get_lut_entry(i) if entry.frequency > 0 or entry.volume > 0: print(" LUT[{}]: freq={}, duty={}, vol={}, sweep={}".format( i, entry.frequency, entry.duty, entry.volume, entry.sweep_enable)) # Generate 6502 assembly print("\n[*] Generating NES 6502 LUT reader assembly...") assembly = generate_nes_6502_lut_reader() print("[*] Generated {} bytes of assembly".format(len(assembly))) # Save assembly with open('/home/allaun/Documents/Research Stack/scripts/nes_oisc_lut_6502.asm', 'w') as f: f.write(assembly) print("[*] Saved to 5-Applications/scripts/nes_oisc_lut_6502.asm") # Save SUBLEQ program print("\n[*] Saving SUBLEQ GCL decompressor...") with open('/home/allaun/Documents/Research Stack/scripts/subleq_gcl_decompressor.bin', 'wb') as f: for i in range(100): f.write(struct.pack('