Wildbits PC Resource Page - by Roger Taylor

Kits, memory maps and other resources for WildBits NitrOS-9 on the K2 and Jr2.

2,016 KBLongview RAM
20 Mhzup from 12 Mhz in RC22
320-256c / 640-16c240-line Bitmap modes
128Hardware sprites
What's new
RC24
20 Mhz turbo mode
all WizFi360 baud rates, chip reset and readable tile registers
RC22
Longview: 2,016 KB RAM
$C0-$C3 moves to $FC-$FF, and the map is otherwise wide open.
RC21
MIDI IN timing
K2; also a black border at reset
RC20
Reliable DMA
logic operations and copies fixed
RC19
12 Mhz turbo mode
new timing scheduler
RC18
K2 RP2040 supervisor
also stable reset, UART timing and sound registers
RC17
DMA logic operations
also faster line drawing and I/O writes
RC16
1,792 KB RAM
flash window usable as RAM
Core / NitrOS-9 ParityK2 Stock
Longview_rc24
core built 2026-10-09
stock kit built 2026-10-09 14:18
Jr2 Stock
Longview_rc24
core built 2026-10-09
stock kit built 2026-10-09 14:19
K2 Future
Longview_rc24
core built 2026-10-09
future kit built 2026-10-09 14:18
Jr2 Future
Longview_rc24
core built 2026-10-09
future kit built 2026-10-09 14:19
2,016 KB SRAM with FLASHDIS; VICKY / fonts + CLUT / text / color pages at $FC / $FD / $FE / $FF✓✓✓✓
Memory / bus: 2,016 KB RAM, shaped flash/cart writes and RTC write-strobe handling, DIP-switchable turbo mode✓✓✓✓
Video / Graphics: hardware lines, sprite engine fixes, 640 × 240 × 16-color bitmaps, and readable text color LUT registers; OS-9 friendly font and palette are built in (saving over 2K of bootfile space if needed)✓✓✓✓
Sound / Music: WM8776 codec chip; FPGA OPL3 FM synthesis on K2 and Jr2; MIDI control register with FIFO-empty flags and FIFO-reset bit (like WizFi); VS1053b mp3/sound chip wiring fixed; $FF9x sound registers✓✓✓✓
Mach-speed: DMA with logic operations, FPU, math coprocessor✓✓✓✓
Communications: DriveWire fractional baud-enable generator (BAUDCE) - WizFi RX/TX interrupts✓✓✓✓
UART baud timing and reset-sequencing improvements✓✓✓✓
RP2040 supervisor: RPDrv/rp mailbox driver and fpga command for status, image listing, SD upload and flash programming✓—✓—
Bells and whistles: Hardware mouse pointer with software-controlled visibility✓✓✓✓
Hardware key-repeat (typematic) engine——✓—
20 Mhz turbo mode: 10-tick RAM reads, 14-tick RAM writes, 25 Mhz internal cycles✓✓✓✓
WizFi360: all 17 baud rates; chip, FIFO and UART reset register ($FF21)——✓✓
W6100 ethernet port✓—✓—
Overlaid now on the Future disks: wb/drivewire_stability, wb/k2_core_typematic_support, wb/rp2040, wb/wizfi, wb/rtaylor — not in main; open pull requests in bold
K2 hardware-typematic keyboard: interrupt-driven keydrv with core key repeat wb/k2_core_typematic_support · overlaid, 3 patches ahead of main · tip 4943eaadc 2026-09-01——✓—
DriveWire stability rework: dwio/rbdw error correction, bounded transmit wait, abort handshake, stream resync wb/drivewire_stability · overlaid, 1 patch ahead of main · tip 49b77e1bd 2026-08-28——✓✓
RP2040 supervisor: RPDrv + rp in the K2 Level 1/FEU bootfile; fpga command with flash-slot wipe (fwipe/pwipe); a latched supervisor error no longer fails every request wb/rp2040 · PR #439 open · overlaid, 8 patches ahead of main · tip f94b00eb2 2026-10-02——✓—
Play improvements; Play and View move to Level 2 CMDS; wildspeed ed.5 with an internal-cycle (mul) class in the perceived blend; MIDrv/mi read and write (MIDI OUT); wmset testing mode removed wb/rtaylor · overlaid, 7 patches ahead of main · PR #441 closed · tip 62934ba10 2026-10-09——✓✓
WizFi360: all 17 baud rates, chip/FIFO/UART reset register at $FF21, data at $FF22; wizupdate firmware updater; internal SD ready timer wb/wizfi · overlaid, 1 patch ahead of main · tip 1b7fe960f 2026-10-07——✓✓

Memory Atlas

How the Wildbits (FNX6809, B0C cores) translates the 6809’s 64K into physical RAM, flash, and I/O under NitrOS-9 Level 2 — the MMU hardware, the FEU boot path, the trampolines, and the runtime windows the OS actually uses. Region colors are consistent across every diagram. Ladders are not to scale.

RAM Flash (SST39VF1681) Expansion RAM I/O Unreachable verified read from source inferred from behavior/comments

1The translation pipeline

Every CPU access goes through one of eight 8K slots. The slot’s LUT entry supplies the physical block; the entry’s top bits pick which bus answers.

CPU address

A15..A13 selects one of 8 slots; A12..A0 is the 8K offset. Fixed I/O at $FDxx–$FFxx bypasses translation.

→

MMU LUT entry

4 LUTs × 8 slots × 8 bits. Active LUT = $FFA0[1:0]. Slot registers at $FFA8–$FFAF read/write the LUT selected by $FFA0[5:4].

→

Physical bus

Entry prefix routes to RAM, the flash window, expansion RAM, or a sectored I/O page. Block number becomes the high address bits.

LUT entry encoding verified (TyVKy2K2x1_MMU_Register.v)
entry bitsregionblockssizephysical
00xxxxxxRAM$00–$3F512 KBSRAM (also the VKY video port)
01xxxxxxFlash window$40–$7F512 KB$08_0000–$0F_FFFF on the system bus; chip offset $00000–$7FFFF
100xxxxxExpansion RAM$80–$9F256 KB$10_0000–$13_FFFF
$A0–$FBRAM$A0–$FB736 KB$14_0000–$1F_7FFF (block × $2000)
111111xxSectored device pages$FC–$FF4×8 KBVICKY / fonts + CLUTs / text / attributes
$00–$FBRAM with FLASHDIS set$00–$FB2,016 KB$00_0000–$1F_7FFF; replaces flash/expansion at $40–$9F
K2 and Jr2 Longview: 252 RAM blocks (2,016 KB) with FLASHDIS set. Flash and expansion rows apply only while FLASHDIS is clear. Use the matching Longview disk and FEU. Physical map · Register and boot sequence.
Only 512 KB of flash is ever addressable: the flash chip gets 13 address bits from the CPU bus (the offset inside an 8 KB block) and six from the FPGA’s MMU-isolated lines (C816_MMU_A_o[5:0] = LUT entry bits 5:0), 19 bits in all. The absolute address’s bits 19–20 exist only inside the FPGA, where they select the flash chip; they are not driven out by this interface. Board-level straps are not specified by RTL. /f0 and /f1 cannot outgrow this window without additional board-supported banking.
7–6unused
5–4edit LUT (reg access)
3–2unused
1–0active LUT (translation)

$FFA0 control byte. The kernel keeps edit == active in system state; code that pokes $FFA8–AF (rbmem, mousedrv) silently assumes this. $FFA1 bit 0 enables the $FD00–$FDFF RAM zone; bit 1 enables $FFF0–$FFFF.

2Block decode at reset · FLASHDIS clear

$00
⋮
$3F
RAM · 512 KB
System + process memory, video framebuffers. VKY fetches from the same physical RAM.
$40
⋮
$77
Flash: /f1 region · 448 KB
User flash drive (rbmem, R/W with erase/program cycles). Descriptor: BLOCK $40, 448×4 sectors.
$78
⋮
$7F
Flash: FEU + /f0 · 64 KB
The FEU’s own area; /f0 is a read-only 40 KB RBF volume here (BLOCK $78). Block $7F is the reset-time boot block (see §5).
$80
⋮
$9F
Expansion RAM · 256 KB
$A0–$FB
System RAM · 736 KB
$14_0000–$1F_7FFF · block × $2000 throughout; includes the former $Cx and $F0–$FB gaps.
$FC–$FF
Sectored device pages · 32 KB
$FC VICKY registers; $FD fonts and graphics CLUTs; $FE text; $FF text attributes. Device memory, not SRAM. Sound uses fixed CPU registers $FF91–$FF99.

At reset: 156 RAM blocks (1,248 KB). Block numbers are what you write into a slot register; fixed CPU register addresses are separate.

Who maps what, at runtime
Codeslotmaps inNotes
vtio7 / 2$FC–$FFvideo and CLUT pages; sound uses fixed $FF9x registers; bootlist warns it must init early to claim $E000+ safely
mousedrv2$FCdraws the pointer sprite via $4C00
rbmem2$40–$7Fflash sector reads/writes through $4000; rbmem temporarily clears FLASHDIS for flash access and restores it afterward
wildspeed, probes—FE-pagefixed I/O needs no mapping
Slot-2 is the communal work window ($4000–$5FFF). Code that borrows it must save/restore the map and interrupt state. Anything mapped at $4000–$5FFF is hidden while the slot is borrowed; keep executing code, stacks and live buffers outside that window.

3System-state 64K (Level 2)

What the kernel’s own map looks like once NitrOS-9 is up.

$0000–$00FF
System direct page verified
The D.xxx globals: D.Tick, D.Sec, D.Proc, D.SysIRQ, D.AltIRQ, D.Poll, D.Clock…
$0100–$015F
Dispatch table inferred
Kernel copies DisTable to D.Clock: timeslice entry (FAlltskSleepProcQ), SWI vectors, D.XIRQ chain.
$0160–
LowSub — the trampolines verified
R.Flip0 and friends: tiny routines copied into block 0 that write DAT.Task ($FFA0) to switch maps. They live in low RAM because block 0 is present in every map — the instruction after the map switch must still exist.
~$0200
⋮
$DFFF
Boot modules + system memory
The OS9Boot module chain (ioman, SCF/RBF, drivers, descriptors, clock…) mapped low-to-high, and allocated system data (path descriptors and buffers). Exact boundaries depend on the bootfile and current allocations; this is not a fixed partition. Slot 2 ($4000–$5FFF) doubles as a work window.
$E000–
Video / CLUT claim inferred
vtio’s early-boot claim (“must be near the top of the bootlist so it can safely map the text and CLUT blocks into $E000–$FFFF”).
$EE00
Bt.Start — the kernel verified
krn executes from the boot area at $EE00; deliberately not marked allocated in the DAT image.
$FD00–$FDFF
Constant RAM page verified
Kernel shadows its always-mapped routines here (CoCo3 uses $FE00; Wildbits moved it to $FD00 because $FExx is I/O). Gated by $FFA1 bit 0.
$FE00–$FFFF
Fixed-System I/O Page
Fixed peripheral registers, MMU controls and slot registers, VICKY master registers, and CPU vectors; fixed decoding in every task — see §4. $FFA1 bit 1 selects internal vector RAM at $FFF0–$FFFF in place of boot flash.

User processes get their own LUT: block 0’s trampoline page is common, the process’s data/code blocks fill the middle, and the fixed I/O pages ride on top. The kernel switches maps by writing $FFA0[1:0] from the LowSub trampolines.

4Fixed-System I/O Page, $FE00–$FFFF

Fixed peripheral registers, the MMU, VICKY’s master registers and CPU vectors: one block stack on the left, register tables on the right, with bits listed under each register.

6809 vectors
fixed decode range
$FFF0–$FFFF
Floating-point unit
fixed decode range
$FFE0–$FFEF
VICKY master control
fixed decode range
$FFC0–$FFDF
VIA1 (W65C22)
fixed decode range
$FFB0–$FFBF
MMU (TinyVicky)
fixed decode range
$FFA0–$FFAF
PSG / OPL3 / SID
fixed decode range
$FF91–$FF99
DIP switches
fixed decode range
$FF90
NES / SNES pads
fixed decode range
$FF80–$FF8F
Logo LCD (SPI)
fixed decode range
$FF70–$FF74
I2C master (HDMI)
fixed decode range
$FF60–$FF6F
VS1053b audio codec
fixed decode range
$FF50–$FF5F
WizNet W6100 ethernet
fixed decode range
$FF40–$FF48
MIDI FIFO + SAM2695 Synth
fixed decode range
$FF30–$FF39
WizFi360 WiFi UART
fixed decode range
$FF20–$FF2A
Splash / SPI flash DMA
fixed decode range
$FF10–$FF18
SD card 1 (SPI)
fixed decode range
$FF00–$FF01
Math coprocessor
fixed decode range
$FEE0–$FEFB
DMA engine
fixed decode range
$FEC0–$FED7
VIA0 (W65C22)
fixed decode range
$FEB0–$FEBF
Mouse pointer
fixed decode range
$FEA0–$FEA8
K2 RP2040 mailbox
16 registers · rc18
$FE78–$FE7F
$FE88–$FE8F
SD card 0 (SPI)
fixed decode range
$FE90–$FE91
IEC serial bus
1 register; K2 rc18 upper half is mailbox
$FE80–$FE87 K2
$FE80–$FE8F Jr2
CODEC
fixed decode range
$FE70–$FE72
UART (DriveWire)
fixed decode range
$FE60–$FE67
PS/2 ports
fixed decode range
$FE50–$FE54
Real-time clock
fixed decode range
$FE40–$FE4F
Timers 0 / 1
fixed decode range
$FE30–$FE3F
Interrupt controller
fixed decode range
$FE20–$FE2F
K2 optical keyboard
fixed decode range
$FE10–$FE16
System control
fixed decode range
$FE00–$FE0F
fixed I/O block

$FE00–$FFFF has fixed decoding in every task map. Blocks are shown from high addresses at the top to low addresses at the bottom.

$FE00–$FE0F · System control

used by: krn scrub, wbreset, wbinfo, feu

RegisterBits, reset values and notes
$FE00SYS0 write:
b7 hardware reset (requires the $DE/$AD sentinels)
b6 network LED
b5 caps-lock LED enable
b4 buzzer
b3/b2 LED1/LED0
b1 SD LED
b0 power LED
$FE00 (read)SYS0 read: b7 SD write-protect, b6 card-detect, b5:0 stored SYS0 control bits. SYS0 resets to $01; SYS1 resets to $40.
$FE01SYS1:
b7:6 LED1 blink rate
b5:4 LED0 blink rate
b3 SID stereo
b2 PSG stereo
b1/b0 LED1/LED0 manual mode
$FE02/$FE03RST0/RST1 reset sentinels: write $DE, $AD to arm the SYS0 b7 hardware reset (what wbreset does)
$FE04/$FE05Random-number value low / high on read; seed low / high on write.
$FE06Random-number generator control: b0 enable, b1 seed-valid; b7 reads the generator’s done flag. Not keyboard-LED enable.
$FE07Read: machine ID, $16 K2 / $1A Jr2.
$FE07–$FE0FRead: $FE08/$FE09 board revision characters; $FE0A/$FE0B subversion, $FE0C/$FE0D version and $FE0E/$FE0F chip number, low byte first. K2 writes to this range set RGB keyboard-LED colors; read and write meanings differ.

$FE10–$FE16 · K2 optical keyboard

used by: keydrv_k2 (F$IRQ on INT_PENDING_3 b2)

RegisterBits, reset values and notes
$FE10key data (FIFO head)
$FE11status:
b7 = 1 mechanical / 0 optical
b0 = 1 FIFO empty
$FE12/$FE13FIFO count lo / hi
$FE14typematic initial delay in 60 Hz frames (reset 30 = 500 ms)
$FE15typematic repeat period in frames (reset 5 = 12 cps)
$FE16b0 = 1 enables hardware key repeat (reset 0 = off, so older disks see stock behavior)
—all three typematic registers read back; write-then-readback of $FE14 is keydrv’s core probe; a hardware reset clears $FE16, a software restart does not

$FE20–$FE2F · Interrupt controller

used by: krn, clock (SOF), keydrv, wizfi, mousedrv

RegisterBits, reset values and notes
$FE20–$FE23pending, groups 0–3 (write 1 to clear)
$FE24–$FE27polarity, groups 0–3
$FE28–$FE2Bedge select, groups 0–3
$FE2C–$FE2Fmask, groups 0–3 (1 = masked; reset = all masked)
group 0
b0 VICKY start-of-frame
b1 start-of-line
b2 PS/2 keyboard
b3 PS/2 mouse
b4 timer 0
b5 timer 1
b6 DMA
b7 cartridge
group 1
b0 UART
b4 RTC
b5 VIA0
b6 VIA1
b7 SD insert
group 2
b0 IEC data
b1 IEC clock
b2 IEC ATN
b3 IEC SREQ
group 3
b0 WiFi RX
b1 MIDI RX
b2 K2 keyboard FIFO
b3 WizNet FIFO route (output tied to 0 in RC24)
b4 reserved MIDI-VS input (not connected on K2/Jr2)
b5 WiFi TX empty (all edge)
—not reset by a software restart: krn cold start writes $FF to all four masks and pendings

$FE30–$FE3F · Timers 0 / 1

used by: wizfi Timer0 polling

RegisterBits, reset values and notes
$FE30 / $FE38write: counter control (clear, load, count up/down); read: status
$FE31–$FE33 / $FE39–$FE3B24-bit counter value
$FE34 / $FE3Ccompare control (reload on match)
$FE35–$FE37 / $FE3D–$FE3F24-bit compare value; a match raises INT group 0
b4 / b5

$FE40–$FE4F · Real-time clock

used by: clock2, wildspeed timebase

RegisterBits, reset values and notes
$FE40 / $FE41seconds / seconds alarm (BCD)
$FE42 / $FE43minutes / minutes alarm
$FE44 / $FE45hours / hours alarm
$FE46 / $FE47day / day alarm
$FE48day of week
$FE49 / $FE4Amonth / year
$FE4Brates
$FE4Cenables
$FE4Dflags
$FE4Econtrol:
b1 24-hour mode
b2 run on battery
b3 UTI update-transfer inhibit (latch before reading)
$FE4Fcentury

$FE50–$FE54 · PS/2 ports

used by: mousedrv, keydrv_ps2 (Jr2)

RegisterBits, reset values and notes
$FE50control:
b5 mouse FIFO clear
b4 keyboard FIFO clear
b3 mouse write
b1 keyboard write
$FE51byte to send
$FE52keyboard input
$FE53mouse input
$FE54status:
b7/b6 keyboard ack/nak
b5/b4 mouse ack/nak
b1 mouse FIFO empty
b0 keyboard FIFO empty

$FE60–$FE67 · UART (DriveWire)

used by: dwinit / dwread / dwwrite

RegisterBits, reset values and notes
$FE60RX / TX data (divisor low when DLAB set)
$FE61interrupt enable (divisor high when DLAB set)
$FE62interrupt ID (read) / FIFO control (write)
$FE63line control (b7 = DLAB)
$FE64modem control
$FE65line status
$FE66modem status
$FE67scratch
—baud = 22.1184 Mhz / (16 × (divisor + 1)) on BAUDCE-fixed cores: 230400 = divisor 5, 115200 = 11

$FE70–$FE72 · CODEC

used by: audio setup

RegisterBits, reset values and notes
$FE70 / $FE71command lo / hi
$FE72Read: b0 busy. Write any byte while idle to start transmission of the command stored at $FE70/$FE71.

$FE80–$FE87 · IEC serial bus (K2)

RegisterBits, reset values and notes
$FE80–$FE87data / clock / ATN / SREQ line control and sense. Jr2 retains the $FE80–$FE8F decode; K2 uses $FE88–$FE8F for the RP2040 mailbox.
—input edges arrive on INT group 2
b0–b3

$FE78–$FE7F / $FE88–$FE8F · K2 RP2040 mailbox

K2 rc18 and later; used by RPDrv/rp and the fpga command. Jr2 has no onboard RP2040 supervisor. Register names follow defs/wildbits.d on wb/rp2040.

RegisterBits, reset values and notes
$FE78RP.Control — Read/write; reset $01.
b0 enable mailbox polling and command transfer
b1 clear last error when written as 1
b7 clear TX and RX FIFOs when written as 1
FIFO clear does not abort a supervisor operation.
$FE79RP.Status — Read-only; reset $20.
b7 error present
b6 RX FIFO has data
b5 TX FIFO empty
b4 TX FIFO full
b3 command pending or in flight
b2 supervisor SD-present flag
b1 supervisor upload-active flag
b0 supervisor seen online
$FE7ARP.Command — Write a command byte to submit the TX payload; read back the most recently accepted command. Submit only while status b3 is clear. Reset $00.
$FE7BRP.Remote — Read-only raw status byte from the latest valid supervisor response. Reset $00.
$FE7C / $FE7DRP.TxCount_H / RP.TxCount_L — Read-only TX FIFO byte count, high byte first; range 0–256. Reset 0.
$FE7E / $FE7FRP.RxCount_H / RP.RxCount_L — Read-only RX FIFO byte count, high byte first; range 0–256. Reset 0.
$FE88RP.TxData — Write one payload byte into the TX FIFO. Writes while full are ignored; reads return $00.
$FE89RP.RxData — Read and remove one byte from the RX FIFO; empty reads return $00. Writes have no effect.
$FE8ARP.ADC0 — Read-only supervisor ADC channel 0 sample; reset $00.
$FE8BRP.ADC1 — Read-only supervisor ADC channel 1 sample; reset $00.
$FE8CRP.ADC2 — Read-only supervisor ADC channel 2 sample; reset $00.
$FE8DRP.ADC3 — Read-only supervisor ADC channel 3 sample; reset $00.
$FE8ERP.Error — Read-only last error; $00 = none. Local errors: $E1 command submitted while busy, $E2 TX payload too long, $E3 RX FIFO overflow. Valid supervisor responses also update this byte.
$FE8FRP.FwMajor — Read-only supervisor firmware major version from its response; reset $00.

The 6809 count registers are big endian; multibyte command payload fields use the supervisor protocol’s little-endian order. Each FIFO holds 256 bytes; a command payload is at most 240 bytes. The current RPDrv waits one 60 Hz tick after busy clears before copying the response, because RX FIFO filling can still be in progress.

$FE90–$FE91 · SD card 0 (SPI)

used by: llwbsd (/s0, /s1)

RegisterBits, reset values and notes
$FE90status / control:
b7 SPI busy
b1 slow SPI clock select (1 = slow initialization rate; 0 = fast)
b0 chip-select enable
$FE91data: write a byte to shift it out, read the byte shifted in

$FEA0–$FEA8 · Mouse pointer

used by: mousedrv

RegisterBits, reset values and notes
$FEA0
b0 show pointer
b1 mode (0 = OS computes X/Y, 1 = hardware decodes PS/2 packets)
$FEA2 / $FEA3X position: write high / low; read low / high. Do not use the same byte order for both.
$FEA4 / $FEA5Y position: write high / low; read low / high.
$FEA6–$FEA8Raw PS/2 packet bytes 0–2, supplied by software for the hardware packet decoder.

$FEB0–$FEBF · VIA0 (W65C22)

used by: joystick readers

RegisterBits, reset values and notes
$FEB0 / $FEB1port B / port A data
$FEB2 / $FEB3DDRB / DDRA
$FEB4–$FEB7timer 1 counter lo/hi, latch lo/hi
$FEB8 / $FEB9timer 2 counter lo / hi
$FEBAshift register
$FEBBauxiliary control (ACR)
$FEBCperipheral control (PCR)
$FEBDinterrupt flags (IFR)
$FEBEinterrupt enable (IER)
$FEBFport A, no handshake
—the joystick ports hang off this VIA

$FEC0–$FED7 · DMA engine

RegisterBits, reset values and notes
$FEC0control:
b0 enable
b1 2D mode
b2 fill
b3 interrupt enable
b5:4 byte-lane mask — either bit set and the transfer completes writing nothing
b6 double speed, and fill takes the 16-bit word
b7 start transfer
$FEC1status (read: b7 transfer in progress, b6:0 hardwired 0) / 8-bit fill byte (write)
$FEC2 / $FEC316-bit fill word, high / low — used instead of $FEC1 when control b6 is set
$FEC5–$FEC7source address hi / mid / lo
$FEC9–$FECBdestination address hi / mid / lo
$FECC / $FECDX size hi / lo
$FECE / $FECFY size hi / lo — 2D only
$FED0–$FED3source stride hi/lo, destination stride hi/lo — 2D only
$FED4DMA_OP_REG (rc17): b2:0 operation — DMA_OP_COPY 0, DMA_OP_OR 1, DMA_OP_AND 2, DMA_OP_XOR 3, DMA_OP_MASK 4 (per nibble: a source nibble of 0 keeps the destination’s)
b3 DMA_OP_NOT — the result inverted (NOR, NAND, XNOR with the others)
b7 DMA_OP_Implemented, read-only: 1 on a core that has the ops (probe it first)
reset 0 = a plain copy
$FED5–$FED7read and write as ordinary bytes but drive nothing
the 1D length is not contiguous: bits 23:16 come from $FECF, bits 15:8 from $FECC and bits 7:0 from $FECD. $FECE is ignored in 1D mode
DMA_RDY holds the CPU while a transfer runs; the bus grant / DMA active / drain handshake keeps a transfer and the CPU out of the same SRAM slot, and the $FED4 logic ops apply to 1D and 2D copies and to fills alike
Read-back. Those are the write addresses, and they are not the read addresses. Every multi-byte field is big endian, high byte at the low address. Writes land directly, but the read decode hands back a different register for sixteen of the thirty-two bytes: both address quads come back reversed, and all four size and stride pairs come back swapped. A driver that reads a register back to check what it wrote will not recognise its own values unless that permutation is built in. The tests/dma probe writes each address’s own low byte into itself and prints what comes back, which identifies whether the fitted core matches this decode or a later one.
The map above was corrected on 2026-09-09 against the core RTL. What was documented before that was wrong from $FEC4 down: both address quads were one byte low, and the whole size and stride block was four bytes high.
Driving it (read out of the core RTL):
  1. Start is a rising edge on bit 7, not a level, and bit 0 must already be high when the edge lands. Nothing in the hardware ever clears bit 7, so the CPU has to write it back to 0 before it can start another transfer — storing $81 twice in a row does one transfer, not two. Set everything up, store the control byte with bit 7 clear, then store it again with bit 7 set.
  2. Completion is a self-clearing level in status bit 7. There is no acknowledge and no write-1-to-clear. Poll until it goes low.
  3. Transfers run in scheduler-granted vertical-blank windows. One started just after the window closes moves no bytes for most of a frame, so a timeout has to be at least two frames, around 40 ms, not microseconds. On RC24 cores a transfer paused when the window closes resumes exactly where it stopped in the next one.
  4. 1D length is 24-bit. There is no 130 KB limit in the RC24 counter. Keep every transfer within allocated SRAM and avoid wrapping the physical address space.
  5. The engine goes straight to the SRAM and does not pass through the MMU. Addresses are flat 24-bit physical, and only bits 20:1 reach the memory pins, so the space aliases every 2 MB. A logical $xxxx address will land on the wrong page: work out block number × 8192 + offset first.
  6. Logic operations. DMA_OP_REG ($FED4) picks what a copy or a fill writes: bits 2:0 DMA_OP_COPY 0, DMA_OP_OR 1, DMA_OP_AND 2, DMA_OP_XOR 3, DMA_OP_MASK 4 (per nibble: a source nibble of 0 keeps the destination’s, so color 0 is paper); bit 3 DMA_OP_NOT inverts the result, giving NOR, NAND and XNOR with the others. Logic operations read the destination before writing the result; copies also fetch the source, whereas fills use the programmed fill value. Throughput depends on the operation and scheduler grants. It works in 1D and 2D and with fills. Bit 7 reads 1 (DMA_OP_Implemented) on a core that has the ops; probe it before relying on them, since an older core writes a plain copy whatever the register holds.
  7. Bus handshake. The engine asks for the bus and starts only when the scheduler has granted it and the previous halt acknowledgement has cleared; after the last byte it keeps the request up for eight more clocks so its output pipeline drains before the CPU resumes. Every resumed burst repeats that handshake. A transfer and the CPU therefore never write the same SRAM slot.
RC24 uses the scheduler bus-grant and pipeline-drain handshake described above. dmaxfer exercises 1D/2D copies, fills and logic operations. CPU polling is supported; sleep is optional. Hardware completion depends on continued scheduler grants.

$FEE0–$FEFB · Math coprocessor

used by: wild (sprites, CLUT math)

RegisterBits, reset values and notes
$FEE0 / $FEE1unsigned multiply operand A (16-bit)
$FEE2 / $FEE3multiply operand B
$FEE4 / $FEE5divisor
$FEE6 / $FEE7dividend
$FEE8–$FEEB32-bit add operand A
$FEEC–$FEEF32-bit add operand B
$FEF0–$FEF332-bit product (read)
$FEF4 / $FEF5quotient (read)
$FEF6 / $FEF7remainder (read)
$FEF8–$FEFB32-bit sum (read)
F256 math-block layout at base $FEE0; wild also parks scratch pointers in the add registers
Fixed I/O on both boards, so it needs no MMU work from any task. Everything is big endian, which suits the 6809: a 16-bit std or ldd lands the right way round. The XYMATH_* block once documented at $D300 does not exist in these cores — nothing decodes that address.
Write the operands, then read the result, and only write below $FEF0. The write decode keys on address bit 3 alone and ignores bit 4, so a write to $FEF0–$FEF7 lands in the multiply and divide operands, and a write to $FEF8–$FEFF lands in the adder’s inputs. Storing to a result address silently destroys an operand. Operands read back at their own addresses.
The multiply is combinational and needs no wait. It is unsigned, 16×16, and the full 32-bit product survives, because 32 bits is the exact width a 16×16 product needs — nothing is truncated. FFFF×FFFF returns FFFE0001; a signed multiplier would return 00000001. The divider is a different matter: it is pipelined with a latency of 12 clocks and both its valid inputs tied high, so it re-divides every clock. Allow at least 12 math-block clocks after writing the operands before reading; these are the approximately 25 Mhz I/O clocks, not 6809 instruction or E-clock cycles.

$FF00–$FF01 · SD card 1 (SPI)

used by: second SD slot (SDC1); /s0 uses $FE90

RegisterBits, reset values and notes
$FF00status / control:
b7 SPI busy
b1 slow SPI clock select (1 = slow initialization rate; 0 = fast)
b0 chip-select enable
$FF01data: write a byte to shift it out, read the byte shifted in

$FF10–$FF18 · Splash / SPI flash DMA

used by: splash loader, flash utilities

RegisterBits, reset values and notes
$FF10control: read
b7 busy
b6 FIFO empty
b5:0 control bits
$FF11command byte for the flash
$FF12/$FF13Read: receive FIFO count low / high (12-bit). Write: transfer length high / low (16-bit). Read and write orders differ.
$FF14–$FF16$FF14 is a stored control byte, not part of the source address. The 24-bit source address is at $FF15–$FF17, high / middle / low.
$FF17Low byte of the 24-bit flash source address (see $FF15–$FF17).
$FF18FIFO data port (read pops one byte)

$FF20–$FF2A · WizFi360 WiFi UART

used by: wizfi (WizCon4), wizi, ntptime, wizupdate, modem -R

RegisterBits, reset values and notes
$FF20control/status, reset $0A:
b4–b0 rate code 0–16: the WizFi360's actual rates, 600.006 to 2,000,000 baud (10 = 115,273.8 default, 13 = 930,232.6; nominal names remain 115200 and 921600)
b5 reserved (reads 0)
b6 RX FIFO empty (read)
b7 TX FIFO empty (read)
$FF21reset, reset $80 (each bit holds its reset while set):
b0 WizFi360 chip reset
b1 TX and RX FIFO reset
b2 TX and RX UART reset
b7 reads 1: the register exists
$FF22data: write pushes to the 2K TX FIFO, read pops the 2K RX FIFO
$FF23/$FF24RX FIFO read count (16-bit)
$FF25/$FF26RX FIFO write count
$FF27/$FF28TX FIFO read count
$FF29/$FF2ATX FIFO write count
—RX non-empty and TX drained edges arrive on INT group 3
b0 / b5

RC24 uses the same 24 Mhz serial clock and fractional bit-period settings for WizFi TX and RX. These rates follow the W600 divisor values; nominal names do not state the exact baud.

CodeNominal baud nameImplemented baud
0600600.006
112001,200.01
218001,800.02
324002,400.1
448004,800.2
596009,601.5
61440014,404.0
71920019,203.1
83840038,424.6
95760057,636.9
10115200115,273.8
11230400231,213.9
12460800465,116.3
13921600930,232.6
1410000001,000,000
1515000001,538,461.5
1620000002,000,000

$FF30–$FF39 · MIDI FIFO + SAM2695 Synth

used by: MIDI tools

RegisterBits, reset values and notes
$FF30control / status:
read: b3 TX FIFO empty · b2 RX FIFO empty · b7:4 and b1:0 read back the control byte
write: b1 = 1 holds both FIFOs in reset (FIFO reset only, as on the WizFi; the synth chip is untouched) · b0 unused (no rate select)
$FF31FIFO data port: write = next byte to the synth (TX FIFO), read = next received byte (RX FIFO)
$FF32/$FF33RX FIFO count hi / lo — bytes waiting to be read (hi = bits 10:8, 11-bit count)
$FF34/$FF35RX FIFO write-side count hi / lo (the UART’s view of the same FIFO; normally equal to $FF32/$FF33)
$FF36/$FF37TX FIFO read-side count hi / lo (bytes the UART still has to send, as it drains)
$FF38/$FF39TX FIFO write-side count hi / lo — bytes queued by the CPU (hi = bits 10:8)
—MIDI RX events: INT group 3
b1: a received-byte event pulse while the RX FIFO has data. b4 is not connected on either board.

$FF40–$FF48 · WizNet W6100 ethernet

used by: wiznet drivers (K2 only)

RegisterBits, reset values and notes
$FF40control:
b0 enable
b3:1 command
b4 reset FIFOs
b5 start transfer
b6 stored control bit; no FIFO interrupt output is implemented in RC24
b7 transfer in progress (read)
$FF41MR register value (read / write)
$FF42TX FIFO count low byte (read); not a full 11-bit count.
$FF43single-access port: write a byte to / read a byte from the W6100
$FF44/$FF45Write: W6100 address high / low. Read: stored address low / high. The read multiplexer reverses this pair.
$FF46/$FF47Read: RX FIFO count high / low (11-bit). Write: transfer size high / low (16-bit).
$FF48FIFO data port; $FF49–$FF4F mirror this port in the RTL. Reads remove a byte and writes enqueue a byte.
—Group 3 b3 is the reserved FIFO IRQ route, but WizNet_FIFO_IRQn_o is tied to 0 in RC24. Poll the bridge; the module IRQ pin has a separate group-2 route.

$FF50–$FF5F · VS1053b audio codec

used by: vs (in main); MP3 / audio streaming (K2 and Jr2)

RegisterBits, reset values and notes
$FF50control:
b0 START: a 0→1 edge starts one SCI transaction; it does not self-clear, so write 0 then 1
b1 READ: 1 = SCI read, 0 = SCI write
b2 FAST: 1 = SPI clock IO_Clk/4 (6.29 Mhz) for streaming once CLOCKF has raised the chip clock; 0 = IO_Clk/16 (1.57 Mhz), within the chip’s boot-time limits
b3 RESET: 1 holds the chip’s XRESET low with the bit engine idle and the SDI FIFO flushed; write 1, wait a tick, write 0
b6:4 unused, read back as written
b7 BUSY (read): transfer in progress, or waiting for DREQ
$FF51SCI register select:
b3:0 SCI register number: 0 MODE, 1 STATUS, 2 BASS, 3 CLOCKF, 4 DECODE_TIME, 5 AUDATA, 6 WRAM, 7 WRAMADDR, 8 HDAT0, 9 HDAT1, A AIADDR, B VOL, C–F AICTRL0–3
b7:4 unused
$FF52SCI data high:
b7:0 bits 15–8 of the value to write, or of the last read result (high byte first, so one std / ldd covers both)
$FF53SCI data low:
b7:0 bits 7–0 of the value to write, or of the last read result
$FF54SDI FIFO status (read):
b7 FIFO empty
b6 FIFO full
b5:3 read as 0
b2:0 FIFO count bits 10–8; the read also snapshots the whole count for $FF55
$FF55SDI FIFO count (read):
b7:0 FIFO count bits 7–0 from the $FF54 snapshot: ldd $FF54 then anda #7 gives the 11-bit count in one consistent read
$FF56b7:0 read as $00
$FF57SDI FIFO data port (write):
b7:0 next stream byte for the chip; 2048-byte FIFO, sent over XDCS as DREQ permits
$FF58–$FF5Fmirror $FF50–$FF57
—DREQ flow control in hardware: BUSY stays set until the chip is ready. Frames are exactly 32 clocks per SCI command and 8 per SDI byte, and DREQ is synchronized in the FPGA. The chip runs from 12.288 Mhz on both machines; its reset follows the board cold reset or CTRL bit 3. Equates in wildbits.d; the vs command (in main) tests and plays through it
—K2 drives the VS1053 boot strap from the FPGA; Jr2 does not. Decoder/synth startup therefore depends on board straps and software initialization. This table specifies the FPGA bridge, not a guarantee of the chip’s current playback mode. Consult the installed vs command and board documentation before changing straps.

$FF60–$FF6F · I2C master (HDMI)

used by: video init, i2c tools

RegisterBits, reset values and notes
$FF60Control: b0 request write, b1 request read; clear the request bits before issuing another command. Read b7 = receive FIFO empty.
$FF61I2C slave address (reset $72 for the HDMI transmitter).
$FF62Register address within the target device.
$FF63Write data / receive FIFO read port (read removes a byte).
$FF64Transfer count (reset $02).
$FF65–$FF67Stored extra command bytes.
$FF68–$FF6FMirrors $FF60–$FF67. K2 only; the automatic controller initializes HDMI before user commands.

$FF70–$FF74 · Logo LCD (SPI)

used by: case LCD tools

RegisterBits, reset values and notes
$FF70data byte
$FF71command byte
$FF72/$FF73pixel lo / hi (16-bit color)
$FF74control: reset value $30; read back
b7 busy
b6 tearing-effect input
b5:0 control (backlight, reset, DC)

$FF80–$FF8F · NES / SNES pads

used by: game pads

RegisterBits, reset values and notes
$FF80control:
b0 enable the serial pad scanner
b2 pad type (0 = SNES, 1 = NES)
b6 fetch complete (read)
b7 start fetch (self-clearing)
$FF81–$FF8FButton read ports: $FF84/$FF85, $FF86/$FF87, $FF88/$FF89 and $FF8A/$FF8B for pads 0–3. The first byte depends on NES/SNES mode; the second contains the remaining low nibble. Other offsets in this range return $A5, not button words.
—the plain joystick ports are connected through VIA0 ($FEB0–$FEBF)

$FF90 · DIP switches

used by: wildspeed, wbinfo, feu

RegisterBits, reset values and notes
$FF90read-only:
b7 gamma on
b6:4 user 2..0
b3:0 boot mode 3..0
b0 (SW_BOOT_MODE0) is the turbo gate on RC24: 1 selects the faster SRAM schedule, live-flippable; actual CPU rate depends on read/write/I/O cycles and video arbitration

$FF91–$FF99 · PSG, OPL3 and SID

Fixed sound registers on K2 and Jr2; no sectored sound page is needed.

RegisterAccess and meaning
$FF91 / $FF92 / $FF93Write PSG left / both / right.
$FF94 / $FF95Write OPL3 bank 0 address / data.
$FF96 / $FF97Write OPL3 bank 1 address / data.
$FF98SID selector, read/write, reset $00: bits 6:5 select left (00), right (01), both (10), or neither (11); bits 4:0 select the SID register. Bit 7 reads 0.
$FF99Write SID data to the selected chip(s) and register. A 6809 std $FF98 writes selector then data; protect that pair if another writer can interleave.
ReadsOnly $FF98 reads the selector back; the other sound ports return $FF. These are FPGA bridge ports, not nine independent chip registers.

$FFA0–$FFAF · MMU (TinyVicky)

used by: krn, F$Link/VModul (slots 0–1 window), vtio/rbmem/mousedrv (slot 2), bootos9

RegisterBits, reset values and notes
$FFA0memory control — MMU_MEM_CTRL / DAT.Task (defs/wildbits.d):
b5:4 which LUT edits write
b1:0 active LUT (reset 0)
$FFA1I/O control — MMU_IO_CTRL (defs/wildbits.d):
b0 internal RAM at $FD00–$FDFF
b1 internal RAM at $FFF0–$FFFF (vectors)
b2 FLASHDIS: 1 = LUT blocks $40–$9F are RAM (768 KB, chip bytes $08_0000–$13_FFFF); 0 = flash at $40–$7F and the expansion connector at $80–$9F
b7 FLASHDIS.OK, read-only: 1 when FLASHDIS is implemented (older cores read back 0)
All bits cleared by reset, so the machine always boots from flash. Read-modify-write only once a kernel runs: a bare store clears b2 and pulls 768 KB of live RAM away. See Documentation · FLASHDIS.
$FFA8–$FFAFslot 0–7 block registers of the LUT selected for editing (8K slots at $0000, $2000 … $E000); reset = identity 0–7 with slot 7 on flash block $7F in boot mode; writes are captured on the 25 Mhz side during the CPU’s data-valid window
—reads of $FFA0–$FFAF return the register copies (used by pmap, the crash dump, F$SetTsk)

$FFB0–$FFBF · VIA1 (W65C22)

used by: joystick / expansion

RegisterBits, reset values and notes
$FFB0–$FFBFsame layout as VIA0: port B, port A, DDRB, DDRA, T1 counter/latch, T2, SR, ACR, PCR, IFR, IER, port A no-handshake
—external device on the K2; its interrupt is INT group 1 b6

$FFC0–$FFDF · VICKY master control

used by: vtio (banner, cursor, palette), SOLdrv, scfg

RegisterBits, reset values and notes
$FFC0/$FFC1$FFC0 master control: b0 text, b1 text overlay, b2 graphics, b3 bitmap, b4 tiles, b5 sprites, b6 gamma, b7 video disable. $FFC1 is a different register: b2:0 video mode, b3 sync control, b4 font background in overlay, b5 font bank, b6 MemText enable, b7 MemText background.
$FFC2/$FFC3layer control 0 / 1 (which bitmap/tile layers draw where)
$FFC4border:
b0 enable
b6:4 X scroll offset
$FFC5–$FFC7border color B / G / R
$FFC8/$FFC9Border X / Y size: six-bit fields (0–63), reset $10 = 16.
$FFCAVKY_DRAWLINE_REG: b0 VKY_DRAWLINE_EN — queued line-draw pixels reach SRAM only while it is set
$FFCBGFX MODE (VKY_GFX_MODE):
b0 HIRES4 — every bitmap plane 640 × 240 at four bits per dot
b3:1 GROUP — the 16-entry CLUT slice the nibbles index
A plane alone: bit 4 of its bitmap control byte. Sprites, tiles and text stay 320-wide. Details: Documentation · 640 × 240 × 16-color mode. Reset 0 = the 320-wide modes.
$FFCD–$FFCFbackground color B / G / R (graphics mode, pixel value 0)
$FFD0cursor control: b0 text-cursor enable
$FFD1text buffer start offset
$FFD2/$FFD3cursor character / color
$FFD4–$FFD7Cursor X and Y: write X high/low, Y high/low; read X low/high, Y low/high.
$FFD8Write: line-interrupt control, b0 enable. Read: current horizontal pixel count high nibble (bits 11:8).
$FFDBRead: raster-line count low byte. No line-compare control field here.
$FFD9/$FFDAWrite: 12-bit line compare high nibble / low byte. Read: $FFD9 horizontal pixel count low byte; $FFDA raster-line count high nibble.
$FFDC–$FFDFread-only core version: VKY_VERSION_LO, VKY_VERSION_HI, VKY_SUBVER_LO, VKY_SUBVER_HI
—SOL line interrupt arrives on INT group 0 b1

$FFE0–$FFEF · Floating-point unit

used by: float-math demos

RegisterBits, reset values and notes
$FFE0control 0:
b0/b1 route input A/B through the fixed→float converter
b3 add/subtract select
b5:4 and b7:6 operand routing
$FFE1control 1: b1:0 result select
$FFE2/$FFE3$FFE2 valid controls: b0 convert input A, b1 direct input A valid, b2 convert input B, b3 direct input B valid. $FFE3 is stored but unused by this RTL.
$FFE8–$FFEBinput A (32-bit, big-endian; 20.12 fixed or IEEE float)
$FFEC–$FFEFinput B
$FFE4–$FFE7 (read)status: multiply, divide (b3 divide-by-zero), add/sub, float→int converter; each has a result-valid bit plus zero/underflow/overflow flags
$FFE8–$FFEB (read)FPMATH_OUT: the result selected by control 1
$FFEC–$FFEF (read)fixed-point converter result

IEEE-754 single precision, 32 bits, big endian, in fixed I/O on both boards, so like the integer block it needs no MMU work. Inside are Xilinx AXI cores: multiply, divide, add/subtract, and two converters between 20.12 fixed point and float. Everything is pipelined — poll the valid bit in the matching status register before reading a result. Latencies are 6 clocks for the multiply and both converters, 14 for the divide.

Operands are written to the same sixteen bytes the results are read from. Writes always land in the control file; reads return control, status or a result depending on the address. So an operand at $FFE8 or $FFEC can never be read back, only the result that replaced it. The input valid signals are levels taken from control 2, not pulses: write the operands, then set control 2, then wait for the pipe. Both of the adder’s input muxes default to input 0, so adding input 0 to input 1 needs control 0 bits 7:6 set to 01 — $40 adds, $48 subtracts.

Two status bits are dead. The multiply’s zero flag and the divider’s divide-by-zero flag are declared in the RTL and never driven — the only code that ever drove them is a commented-out instantiation left at the bottom of the file — so both synthesize to a constant 0. The multiply status bit 3 always reads 0 even when the product is zero, and the divide status bit 4 always reads 0. The divider’s real divide-by-zero flag is wired to what the map calls its zero bit, so on this RTL divide status bit 3 means divide-by-zero, not “result is zero”. tests/fpu divides 1.0 by 0.0 and reports which bit actually moved.

$FFF0–$FFFF · 6809 vectors

used by: krn (DisTable), feu

RegisterBits, reset values and notes
$FFF0reserved (6309 illegal-opcode trap)
$FFF2SWI3
$FFF4SWI2 — every OS-9 system call
$FFF6FIRQ
$FFF8IRQ
$FFFASWI
$FFFCNMI
$FFFERESET
—fetched from flash block $7F (the FEU) in boot mode; once $FFA1 b1 is set they come from the internal RAM overlay, which is how krn installs its own vectors (D.XSWI2 etc.)

Both pages retain their fixed addresses in every task map. The vector area at $FFF0–$FFFF switches between boot flash and internal vector RAM under $FFA1 control.

5Boot: from reset to shell

Reset — boot mode. The MMU comes up with slots 0–6 identity-mapped to RAM and slot 7 pointed at flash block $7F (verified in the LUT reset values), so the 6809’s vectors at $FFFE fetch from the top 8K of the flash window: the FEU.

FEU runs from flash. The Flash Environment Utility (living in blocks $78–$7F, with its file area visible to OS-9 later as /f0) initializes hardware, shows its menu, and executes its startup script: bootos9 /s0/OS9Boot.

bootos9 loads the bootfile. OS9Boot is read from the SD (or DriveWire) volume into RAM. The loader requires krn to be the final module, anchored exactly 4096 bytes before end-of-file — break that and you get “can’t locate the kernel in the bootfile.”

Kernel takes over. krn (at Bt.Start = $EE00) copies DisTable to D.Clock, plants the LowSub trampolines at $0160, shadows the constant page at $FD00, clears boot mode so slot 7 becomes RAM, and walks the module chain: ioman, file managers, drivers, clock.

sysgo → startup → shell. sysgo forks the shell (loading the merged SHELLMODS pack), startup runs (load utilpak1 / link shell / wbinfo; other commands depend on the installed startup file), and the console is yours.

Sources & confidence. RC24 shared MMU/scheduler, K2/Jr2 device wrappers, peripheral register modules, defs/wildbits.d, kernel and loader source. The register map describes implemented RTL; runtime allocation boundaries are illustrative. Source audit 2026-10-08; this is not a new hardware test.
WildBits K2 / Jr2 · FNX6809 core · hardware reference · companion to the Physical Memory Map

WildBits Interrupt Groups: Hardware vs. wildbits.d

Hardware truth from fpga-6809-cores-staging/source/IRQ_Controller_Jr.v (the lirq0 concatenation, line 153–156) vs. the OS definitions in nitros9/defs/wildbits.d (lines 206–251). Registers per group: PENDING $FE20+n, POLARITY $FE24+n, EDGE $FE28+n, MASK $FE2C+n. Report date 2026-09-01.

Group 0 · core system
$FE20 / $FE24 / $FE28 / $FE2C
bits 7:0
Group 1 · peripherals
$FE21 / $FE25 / $FE29 / $FE2D
bits 15:8
Group 2 · IEC bus + module IRQ pins
$FE22 / $FE26 / $FE2A / $FE2E
bits 23:16
Group 3 · FIFO events: WiFi / keyboard / MIDI / WizNet
$FE23 / $FE27 / $FE2B / $FE2F
bits 31:24
PENDING
write 1 to clear · latches unmasked too
$FE20–$FE23
POLARITY
0 falling / 1 rising
$FE24–$FE27
EDGE
1 edge / 0 level (reset $FF)
$FE28–$FE2B
MASK
1 masked (reset $FF)
$FE2C–$FE2F
group 0 · core group 1 · peripherals group 2 · IEC + pins group 3 · FIFOs

Low bits at the bottom. The four 8-bit groups make one 32-bit lirq word; each group owns one byte in each of the four register quads, at $FE20+n, $FE24+n, $FE28+n, $FE2C+n.

Interrupt routing · IRQ path
GROUP 0GROUP 1GROUP 2GROUP 3PENDING+ MASKCPUIRQ

RC24 interrupt routing

SD insertion is group 1 bit 7; VIA1 is bit 6. DMA is group 0 bit 6. Groups 2 and 3 have definitions in the current wildbits.d; board wiring determines which inputs are connected.

Group 0 — core system (bits 7:0 of lirq)

PENDING $FE20 · POLARITY $FE24 · EDGE $FE28 · MASK $FE2C

BitHardware signal (RTL)What it iswildbits.dStatus
0VICKY_INT_Sync[0]TinyVicky start of frame (60 Hz) — the OS clock tickINT_VKY_SOF %00000001MATCH
1VICKY_INT_Sync[1]TinyVicky start of line (per raster line)INT_VKY_SOL %00000010MATCH
2Keyboard_int_PulSe[3]PS/2 keyboard event pulseINT_PS2_KBD %00000100MATCH
3Mouse_int_PulSe[3]PS/2 mouse event pulseINT_PS2_MOUSE %00001000MATCH
4~Timer0_iTimer 0 reached targetINT_TIMER_0 %00010000MATCH
5~Timer1_iTimer 1 reached targetINT_TIMER_1 %00100000MATCH
6DMA_INT_iDMA engine interruptINT_DMA %01000000MATCH
7CRT_IRQn_SyncCartridge (“CRT”) IRQ line from the expansion portINT_CARTRIDGE %10000000MATCH

Group 1 — peripherals (bits 15:8)

PENDING $FE21 · POLARITY $FE25 · EDGE $FE29 · MASK $FE2D

BitHardware signal (RTL)What it iswildbits.dStatus
0!COM1_int_PulSe[3]UART (COM1 / 16550) readyINT_UART %00000001MATCH
1VICKY_INT_Sync[2]Unused VICKY input (tied off by the board wrapper)—Unused
2VICKY_INT_Sync[3]Unused VICKY input (tied off by the board wrapper)—Unused
3VICKY_INT_Sync[4]Unused VICKY input (tied off by the board wrapper)—Unused
4RTC_IRQ[2]Real-time clock chip eventINT_RTC %00010000MATCH
5VIA0_INT_i65C22 VIA #0 eventINT_VIA0 %00100000MATCH
6VIA1_INT_iVIA1 event on K2; no external VIA1 interrupt on Jr2INT_VIA1 %01000000MATCH
7SDC_IRQ[2]SD card insertedINT_SDC_INS %01000000WRONG VALUE

SD insertion and VIA1 are separate

The current definitions use INT_SDC_INS = %10000000 and INT_VIA1 = %01000000. The optical keyboard is group 3 bit 2 on the K2.

Group 2 — IEC bus + module IRQ pins (bits 23:16)

PENDING $FE22 · POLARITY $FE26 · EDGE $FE2A · MASK $FE2E

BitHardware signal (RTL)What it iswildbits.dStatus
0IEC_DATA_i_SyncIEC serial bus DATA inIEC_DATA_i %00000001MATCH
1IEC_CLK_i_SyncIEC serial bus CLK inIEC_CLK_i %00000010MATCH
2IEC_ATN_i_SyncIEC serial bus ATN inIEC_ATN_i %00000100MATCH
3IEC_SREQ_i_SyncIEC serial bus SREQ inIEC_SREQ_i %00001000MATCH
4NET_IRQn_SyncEthernet (WizNet module) IRQ pinINT_NET_PIN %00010000MATCH
5WIFI_IRQn_SyncWiFi module IRQ pin (the module’s own line, not the FIFOs)INT_WIFI_PIN %00100000MATCH
6HDMI_IRQn_SyncHDMI encoder IRQ pinINT_HDMI_PIN %01000000MATCH
7constant 1'b0unused—n/a

The IEC bits also drive NMI

The four IEC bits (group 2 bits 0–3, Interrupt[16..19]) have a second life: when the IEC_NMI_IRQn_i input is high they also drive the CPU’s NMI through the same pending/mask terms as IRQ (IRQ_Controller_Jr.v).

Group 3 — FIFO events: WiFi / keyboard / MIDI / WizNet (bits 31:24)

PENDING $FE23 · POLARITY $FE27 · EDGE $FE2B · MASK $FE2F

BitHardware signal (RTL)What it iswildbits.dStatus
0NEW_Rx_FIFO_WIFI_SyncWiFi RX FIFO went non-emptyINT_WIZFI_RX %00000001MATCH
1NEW_Rx_FIFO_MIDI_SyncMIDI received-byte event pulse (while RX data is available)INT_MIDI_RX %00000010MATCH
2NEW_Optical_Kbd_SyncK2 optical keyboard FIFO went non-empty (latches on every keystroke; Jr2 never wires this)INT_OPT_KBD %00000100MATCH
3NEW_WizNet_FIFO_SyncWizNet FIFO route; bridge output is tied to 0 in RC24, so it does not generate FIFO eventsINT_WIZNET %00001000MATCH
4NEW_Rx_FIFO_MIDI_VS_SyncReserved MIDI-VS input; tied inactive on both boardsINT_MIDI_VS_RX %00010000MATCH
5NEW_Tx_FIFO_WIFI_SyncWiFi TX FIFO drained to emptyINT_WIZFI_TX %00100000MATCH
6–7constant 2'b00unused—n/a

Shared group, separate masks and handlers

WiFi, MIDI and the K2 keyboard share PENDING_3/MASK_3. Each driver must clear and unmask only its own bits. The overlaid K2 typematic keyboard driver installs an F$IRQ handler for bit 2; it does not rely solely on 60 Hz polling.

Controller behavior (applies to all four groups)

  • Reset defaults: POLARITY = $00 (falling edge), EDGE = $FF (edge mode), MASK = $FF (all masked), PENDING = $00. These reset only on FPGA reset — a soft reboot preserves them, so mask bits a driver unmasked (e.g. wizfi’s group-3 bits) survive into the next OS boot.
  • PENDING latches unconditionally: pending <= pending | irq_event — the mask gates only the CPU IRQ output (Interrupt[n] = pending[n] & ~mask[n]), never the latch.
  • PENDING is write-1-to-clear; reads are side-effect-free. MASK is a plain read/write register.
  • OS cold start: the Level 2 kernel writes $FF to all four MASK and PENDING registers, masking and clearing every group before driver initialization.

Definitions and board wiring

The current definitions include DMA, SD insertion and group 2/3 sources. An equate does not imply a connected peripheral: the board wrappers tie off unused VICKY inputs and MIDI-VS RX. K2-only keyboard and Ethernet inputs do not become Jr2 hardware.

Where this comes from

RC24: IRQ_Controller_Jr.v, the K2/Jr2 IO_Page0 device wrappers, OpticalKeyboardScanner.v, F256K2_MIDI_Interface.v, defs/wildbits.d, Level 2 krn.asm and the K2 typematic-overlay driver. Register decoding and board connections were reviewed together.

WildBits K2 / Jr2 · Longview RC24 · source audit 2026-10-08.
WildBits K2 / Jr2 · FNX6809 core · hardware reference · companion to the 64K Memory Map

WildBits Physical Memory Map

The Longview map with FLASHDIS enabled: 252 allocatable RAM blocks (2,016 KB), four device pages, and one address rule for CPU, VICKY and DMA. Boot and runtime allocations reduce the memory shown as free.

SRAM address space · 8 KB per block
$00–$FB
System RAM · 2,016 KB
$00_0000–$1F_7FFF · one contiguous run of 252 blocks with FLASHDIS set; block × $2000 + offset for CPU, VICKY, DMA and the debug port.
$FC–$FF
Sectored device pages · 32 KB
$FC VICKY registers; $FD fonts and graphics CLUTs; $FE text; $FF text attributes. Device memory, not SRAM. Sound uses fixed CPU registers $FF91–$FF99.

One address rule

block × $2000 + offset

2,016 KB mapped from a 2,048 KB SRAM chip. The final four block entries select 32 KB of device address space instead of SRAM.

System RAM — who owns what at run time

BlocksOwnerContents
$00Kernel (permanent)The system block: D.* globals page, the 8K-block allocation map at $0200 (one byte per physical block, up to 2MB), system/user dispatch tables, kernel data — and the boot trampoline at $0600 (below). Marked used by the memory-sizing routine itself.
$01–$03Boot-size-dependentMay hold boot modules or be available for general allocation. (Block 1 doubles as bootos9’s temporary MMU copy window during a re-boot, then returns to the pool.)
$04–$07Boot modulesOS9Boot is loaded into the blocks just below block 8 — blocks (8−n)…7 for an n-block bootfile (for n=4 this is $04–$07; larger bootfiles occupy more lower blocks). The kernel (last module in the merge) lands in the top block and is marked used; the rest hold the boot module directory contents.
$08–$3FGeneral allocation (448 KB span)Process address spaces, RBF/SCF buffers, bitmap framebuffers (VICKY fetches these over its RAM port — the layers you see in view/shellbg live here), and rbmem’s 8K flash-write cache (one block via F$AllRAM at Init).
$40–$9FGeneral RAM · 768 KBFLASHDIS replaces the flash and expansion selects with SRAM at $08_0000–$13_FFFF.
$A0–$FBGeneral RAM · 736 KBSRAM at $14_0000–$1F_7FFF, including former device and undecoded gaps. No separate RAM windows.
$FC–$FFDevice pages · 32 KBVICKY, fonts/CLUTs, text and attributes; excluded from the RAM allocator.

Memory sizing starts with the boot map. The Longview krnp2 expands the block table to 256 entries, checks FLASHDIS.OK, and sets FLASHDIS when supported. The pool has 252 blocks (2,016 KB); only $FC–$FF are marked NotRAM. With FLASHDIS clear, $40–$9F are also excluded, leaving 156 blocks (1,248 KB). mfree reports what remains after allocations, not the full pool. Longview needs its matching kernel, disk and FEU.

The trampoline

When bootos9 (re)boots the system, running code is about to yank the MMU out from under itself. The escape: it copies a tiny relocatable stub to $0600 in block 0 (RELOC_ADDR), jumps to it, and the stub — running from an address that stays mapped — resets MMU slots 0–7 to identity (blocks 0–7), then jumps to the kernel entry point found in the freshly-loaded bootfile. The same staging is used by the FEU’s os9boot. The staging allocation depends on the bootfile size; $04–$07 describes a four-block bootfile, not every current build.

The boot chain, block by block

  1. Power-on → Booter (flash $7D–$7F, the top 24 KB of the addressable flash window — the three booter_*.bin pieces fnxmgr installs).
  2. Booter → FEU OS-9: loads the mini system from /f0 (flash $78–$7C, the five f0_*.bin pieces, 40K). FEU = “First Executable Unit” — a Level 1-style OS-9 system with boot modules in flash and working data in RAM.
  3. FEU startup → bootos9 /s0/OS9Boot: the FEU’s startup script chains to the real system — bootos9 reads the SD card’s OS9Boot into RAM blocks (8−n)…7 through the block-1 copy window.
  4. Trampoline: stub at $0600, MMU identity map, jump to kernel — full OS-9 running from SD-loaded RAM. The FEU’s flash blocks return to being just the /f0 drive.

Flash at reset · FLASHDIS clear

BlocksSizeRole
$40–$77448K/f1 — the user flash drive (formattable, writable; rbmem erase/program with DQ6 polling).
$78–$7C40K/f0 — the FEU system image; mounted read-only at run time. fnxmgr’s bulk.csv flashes these as chip sectors $38–$3C.
$7D–$7F24KBooter — first code after reset; chip sectors $3D–$3F.

Expansion window · FLASHDIS clear

One external-bus decode, with board-dependent attached hardware: on the K2 this is the 256 KB expansion region (physical $10_0000–$13_FFFF). On the Jr2 the same select reaches the cartridge port: /c0 is based at block $80 and /c1 at $90 (cartridge flash identification must use the actual cartridge chip; it is not necessarily the onboard flash type). This region shares the external bus — and its single write strobe — with the flash chip and the RTC, which is why the v8_rc6 core’s strobe policy covers all three.

Sectored device pages ($FC–$FF)

BlockContents
$FCVICKY registers and tables, by page offset: $0000–$0BFF gamma windows B / G / R (each has a 256-byte table mirrored through a 1 KB decode window, readable)
$0C00–$0FFF mouse pointer graphic
$1000–$10FF bitmap layer registers (three 8-byte sets at $1000 / $1008 / $1010; the line-draw accelerator at $1080–$1087, see the sprite chapter) · $1100–$11FF tile registers · $1200–$12FF memtext registers
$1300–$16FF sprite attribute records (128 × 8 bytes, see the sprite chapter)
$1700–$173F text foreground color LUT · $1740–$177F text background color LUT (16 entries × 4 bytes each, B G R A; loaded with the OS-9 palette at power-up; readable through shadow copies)
$FDFont memory at $0000–$0FFF (FONT_BLK); the four graphics CLUTs at $1000–$1FFF (256 entries × 4 bytes each, LUTn at $1000 + $400×n; readable; all zero at power-up until a program loads them)
$FEText screen memory; the device decode exposes offsets $0000–$12BF (4,800 bytes) in this 8 KB page.
$FFText color attribute memory; offsets $0000–$12BF (4,800 bytes). One byte per character cell: foreground index in the high nibble, background in the low.

These are VICKY-internal pages, not RAM — mapping one into a slot windows the device, and the MMU entry pattern 1111 11xx routes there instead of to memory.

Longview system RAM

2,016 KB of SRAM in one run (K2 and Jr2): with FLASHDIS set, LUT entries $00–$FB select SRAM at $00_0000–$1F_7FFF. The former $C0–$CF device gap and $F0–$FB undecoded blocks are now RAM. Devices occupy only $FC–$FF. Every RAM block follows block × $2000 + offset; the 16-bit SRAM chip’s word-address pins carry the byte address divided by two. The kernel excludes the four device pages from its 256-entry allocation map. Fixed CPU register and vector overlays remain unchanged.

Memory and external-bus writes

With the max-RAM kernel, FLASHDIS maps 2,016 KB of SRAM on Longview. Flash and cartridge accesses use the shaped write pulse when FLASHDIS is clear; when set, those MMU blocks select SRAM instead. RTC accesses retain the raw CPU write signal for their wait-stretched cycles. DMA remains a separate physical-address engine; the DMA sequencing and limitations above still apply.

Source: shared TyVKy2K2turbo_MMU_FNX6809.v write-strobe logic and TyVKy2K2x1_MMU_Register.v FLASHDIS decode, used by both projects.

FLASHDIS — the flash window as RAM: MMU_IO_CTRL ($FFA1) bit 2

768 KB more RAM (K2 and Jr2). The SRAM is 2 MB, but the flash chip and the expansion connector sat in front of its middle third: LUT entries $40–$7F selected the flash and $80–$9F the expansion, so chip bytes $08_0000–$13_FFFF were never reachable. One bit swaps them out.

FLASHDIS = 0 — Longview reset map

$00–$3F
System RAM · 512 KB
$00_0000–$07_FFFF
$40–$7F
Flash · 512 KB
FEU and flash drives; SRAM at $08_0000–$0F_FFFF is hidden
$80–$9F
Expansion · 256 KB
Expansion connector; SRAM at $10_0000–$13_FFFF is hidden
$A0–$FB
System RAM · 736 KB
$14_0000–$1F_7FFF · block × $2000 throughout; includes the former $Cx and $F0–$FB gaps.
$FC–$FF
Sectored device pages · 32 KB
$FC VICKY registers; $FD fonts and graphics CLUTs; $FE text; $FF text attributes. Device memory, not SRAM. Sound uses fixed CPU registers $FF91–$FF99.

156 RAM blocks · 1,248 KB in all

FLASHDIS = 1 — Longview RAM map

$00–$FB
System RAM · 2,016 KB
$00_0000–$1F_7FFF · one contiguous run of 252 blocks with FLASHDIS set; block × $2000 + offset for CPU, VICKY, DMA and the debug port.
$FC–$FF
Sectored device pages · 32 KB
$FC VICKY registers; $FD fonts and graphics CLUTs; $FE text; $FF text attributes. Device memory, not SRAM. Sound uses fixed CPU registers $FF91–$FF99.

252 RAM blocks · 2,016 KB in all · free memory depends on allocations

RegisterBitName (defs/wildbits.d)Meaning
$FFA1 MMU_IO_CTRL7FLASHDIS.OKRead-only. 1 on a core that implements FLASHDIS, 0 on one that does not — they hand back what was stored, and nothing stores a 1 there. The kernel tests this bit before touching bit 2.
2FLASHDIS1 = LUT blocks $40–$9F are RAM. 0 = flash at $40–$7F and the expansion connector at $80–$9F, as always. Cleared by reset, so the machine boots from flash every time; the FEU trampoline runs from flash and stores $00 / $02 here, and is unaffected.
1—Internal RAM at $FFF0–$FFFF (the vector page); unchanged.
0—Internal RAM at $FD00–$FDFF; unchanged.

The register is readable; names as in defs/wildbits.d (equates FLASHDIS = %00000100, FLASHDIS.OK = %10000000).

What the kernel does at boot (Longview krnp2, both machines, before anything is forked):

1 · read

lda >MMU_IO_CTRL — one read of $FFA1.

→

2 · FLASHDIS.OK set

ORs FLASHDIS in (read-modify-write, bits 0/1 kept). Only $FC–$FF are excluded: 252 RAM blocks, 2,016 KB.

→

2′ · FLASHDIS.OK clear

Leaves the register unchanged and also excludes $40–$9F. On the Longview reset map, 156 RAM blocks remain (1,248 KB). This flag does not identify or make a V8 device map compatible.

Rules. After boot nobody stores an absolute value to MMU_IO_CTRL — a bare store clears bit 2 and pulls 768 KB of live RAM out from under the kernel; read-modify-write only. While FLASHDIS is set the FEU blocks in flash are hidden. The rbmem driver briefly restores flash mapping during guarded flash operations, then restores the control byte; reset also clears FLASHDIS.
WildBits K2 / Jr2 · Longview cores · updated 2026-10-05. Companion: WildBits 64K Memory Map.
WildBits K2 / Jr2 · FNX6809 core · hardware reference

WildBits 64K Memory Map

Which CPU addresses pass through the MMU, and which are hard-wired — including the two constant-RAM pages that sit outside MMU translation entirely. Derived from the shipping RTL decode logic, not documentation.

Slot 0$0000–$1FFF
Slot 1$2000–$3FFF
Slot 2$4000–$5FFF
Slot 3$6000–$7FFF
Slot 4$8000–$9FFF
Slot 5$A000–$BFFF
Slot 6$C000–$DFFF
Slot 7
top carved out →
$E000–$FFFF
Constant RAM
switchable · $FFA1 bit 0
$FD00–$FDFF
Fixed I/O$FE00–$FEFF
Fixed I/O$FF00–$FF9F
MMU registers$FFA0–$FFAF
Fixed I/O$FFB0–$FFEF
Constant RAM · vectors
switchable · $FFA1 bit 1
$FFF0–$FFFF
MMU-translated (8K slots) Fixed I/O (always) Constant RAM (switchable) MMU register window

Low addresses at the bottom, datasheet-style. The right column expands the top 768 bytes of slot 7; $E000–$FCFF below the carve-outs is ordinary MMU-translated space.

How the split works

The CPU’s 64K space is divided into eight 8K slots, each translated through an MMU look-up entry. A single inhibit term overrides that translation for the top pages:

RegionClassBehavior
$0000–$FCFFMMUTranslated through the active LUT entry for its slot. The entry’s high bits pick the physical target (see encoding below).
$FD00–$FDFFConstant RAMWhen $FFA1 bit 0 = 1, a dedicated internal RAM page supersedes whatever the MMU maps there. Bit 0 = 0 (the reset state): ordinary MMU space.
$FE00–$FEFFFixed I/OAlways the fixed I/O page — never RAM, regardless of MMU contents.
$FF00–$FF9FFixed I/OAlways fixed I/O.
$FFA0–$FFAFMMU regsThe MMU’s own control and slot registers (decoded as $FFAx).
$FFB0–$FFEFFixed I/OAlways fixed I/O (includes the text controller at $FFC0).
$FFF0–$FFFFConstant RAMThe 6809 interrupt-vector page. When $FFA1 bit 1 = 1, a dedicated internal RAM page supersedes MMU RAM/flash. Bit 1 = 0 (reset state): vectors come from MMU space (RAM or flash).

The constant-RAM pages — what makes them special

Both switchable pages ($FD00–$FDFF and $FFF0–$FFFF) are physically separate internal RAM, not part of the MMU-managed block RAM. Three properties follow:

•  While enabled, they are visible at the same addresses in every task and every LUT — remapping slots never moves or hides them. That is what makes the vector page usable for interrupt dispatch across task switches.
•  RESET clears both enable bits, so the pages disappear from the map after a reset until software sets $FFA1 again — but their contents are retained until power-off. Values written before a reset are still there when the page is re-enabled.
•  They supersede reads and writes: with a page enabled, nothing behind it (MMU RAM or flash) can be touched at those addresses.

MMU machinery

RegisterAddressFunction
MMU_MEM_CTRL$FFA0Bits 1:0 select the active LUT (0–3); bits 5:4 select the LUT being edited through the slot registers.
MMU_IO_CTRL$FFA1Bit 0 enables constant RAM at $FD00–$FDFF; bit 1 enables constant RAM at $FFF0–$FFFF; bit 2 FLASHDIS turns LUT blocks $40–$9F from flash/expansion into 768 KB of RAM; bit 7 FLASHDIS.OK (read-only) reads 1 when FLASHDIS exists. Readable; read-modify-write it. Names as in defs/wildbits.d.
MMU_SLOT_0–7$FFA8–$FFAFOne LUT entry per 8K slot ($FFA8 → $0000–$1FFF … $FFAF → $E000–$FFFF).

Slot-entry encoding (physical target select)

Entry bitsTargetNotes
00xx xxxxSystem RAM8K block number in the low bits.
01xx xxxxFlash / SRAMBlocks $40–$7F: flash with FLASHDIS clear; SRAM with it set.
100x xxxxExpansion / SRAMBlocks $80–$9F: expansion with FLASHDIS clear; SRAM with it set.
$A0–$FBSystem RAM736 KB at $14_0000–$1F_7FFF, regardless of FLASHDIS.
$00–$FBSystem RAM with FLASHDIS set252 blocks (2,016 KB) at $00_0000–$1F_7FFF.
1111 11xxSectored I/O pageThe four relocatable device pages ($FC–$FF).

Selected fixed I/O groups

AddressDevice
$FE00–$FE03SYS0/SYS1 system control, RST0/RST1
$FE20–$FE2FInterrupt controller (pending / polarity / edge / mask)
$FE50–$FE54PS/2 keyboard and mouse
$FE60–$FE6716750 UART (DriveWire)
$FE70WM8776 codec control
$FE90SD card controller
$FEB0VIA0
$FEC0DMA controller
$FF20–$FF2AWizFi UART and reset controls
$FF30–$FF39MIDI FIFO + SAM2695 Synth
$FF91–$FF99PSG / OPL3 / SID sound ports
$FE78–$FE7F / $FE88–$FE8FK2 RP2040 mailbox
$FFC0Text controller (TXT.Base)

Where this comes from

Decode logic traced in the shipping cores (both machines share these files):
• TyVKy2K2turbo_MMU_FNX6809.v — page decodes ($FDxx / $FExx / refined $FF00–$FF9F + $FFB0–$FFEF / $FFFx) and the $FFAx MMU-register select.
• TyVKy2K2x1_MMU_Register.v — RAM_Access_Inhibit (the master “not subject to the MMU” term), slot-entry target encoding, and the two $FFA1 enable bits.
• defs/wildbits.d — register names, device addresses, and the constant-RAM retention note.
One caveat: all fixed decodes are qualified by !Dbg_Mode_i — when the hardware debugger owns the bus, these carve-outs are bypassed.

WildBits K2 / Jr2 · Longview RC24 · source audit 2026-10-08.
WildBits K2 / Jr2 · FNX6809 core · hardware reference · companion to the 64K Memory Map

WildBits Sprite Engine

Hardware reference for the 128-sprite engine in the 6809 cores: register map, attribute format, coordinate system, the minimum programming recipe for putting a sprite on screen — and the mapping required by Longview RC24.

Gamma tables B / G / R
3 × 256 bytes
$0000–$0BFF
Mouse pointer graphic$0C00–$0FFF
Bitmap + line-draw regs$1000–$10FF
Tile map regs$1100–$11FF
MEMTEXT regs
future
$1200–$12FF
Sprite attributes
128 × 8 bytes, 4 banks of 32 · record →
$1300–$16FF
Text color LUTs
foreground $1700, background $1740
$1700–$177F
Reserved$1780–$1FFF
CTRL
b0 enable · b2:1 LUT · b4:3 depth · b6:5 size
+0
ADDR hi / mid / lo
pixel data, 24-bit, big-endian
+1–+3
X hi / lo+4–+5
Y hi / lo+6–+7
sprite attributes / pixel address engine registers tables and positions other page contents

Low offsets at the bottom. Page $FC reaches the CPU through an MMU slot (slot 2 puts record n at $5300 + 8n); the pixel data the record points to lives in system RAM, not in the page.

Sprite image → display · schematic
CLUTSCREENSRAM pixels → palette → compositionIndex 0 lets the layer behind show through.
At a glanceDetail
128hardware sprites, scanned 127 → 0 each line pair (sprite 0 composites on top)
4 sizes32×32, 24×24, 16×16, 8×8 — per-sprite, 2 control bits
8 bppindexed color through one of 4 graphics CLUTs; index 0 = transparent
320×240coordinate space, origin offset +32: screen top-left is (32,32)

How the engine works

Sprites are line-buffered, not framebuffered. The display runs 640×480 with every 320×240 pixel doubled, so the engine only needs each sprite line once per pair of scanlines. On every odd scanline, during horizontal blanking, the master video scheduler enters its sprite phase (DoSpriteHere), hands VRAM channel 3 to the sprite state machine, and fires it.

The sprite state machine then walks all 128 attribute records, from sprite 127 down to sprite 0. For each record it checks two things in two clocks: the per-sprite enable bit, and a line hit — whether the upcoming pixel row falls inside the sprite’s vertical span. Disabled records take the probe/next path; enabled records also perform the line-hit check. Rendering throughput depends on the number and width of sprites hitting that row. On a hit, the engine multiplies the row-within-sprite by the sprite’s line width, adds the pixel base address, and streams that one line of pixels (8–32 bytes, fetched 16 bits at a time) from video RAM into the sprite line buffer at horizontal position X. Because sprite 0 is written last, it wins overlaps.

During the following even scanline, the compositor reads the line buffer back at pixel rate and merges it with text, bitmap, and tiles according to the master control register. A non-zero pixel index is looked up in the sprite’s selected CLUT; index 0 lets the layers behind show through.

The scan pipeline, per line pair

StageState(s)What happens
ArmSP_IDLE → SP_PRESTATESprite_Effect_On raised by the master scheduler on odd-line blanking; channel select preloaded to sprite 127.
ProbeSP_STATE0 → SP_STATE1One clock of BRAM latency, then the 64-bit attribute record is valid. Disabled → NEXTCHANNEL.
Line hitENABLEDHit when Y ≤ line/2+32 < Y+height. Miss → NEXTCHANNEL.
FetchSP_GET_DATA_VRAM0..1, SP_WRITE_ATTRIB0..2Line-buffer write pointer set to X+64; VRAM counter loaded with start/stop = base + row×width (+width); pixels stream on each VRAM_Data_Valid until the counter reaches stop.
Next / doneNEXTCHANNEL → … → SP_TRF_DONEDecrement sprite select; after sprite 0, signal done — the master scheduler moves on to bitmap/tile slots.

Register map

Master control — $FFC0 (fixed I/O, visible in every map)

BitMaskNameFunction
0$01Text_Mode_EnText layer on
1$02Text_OverlayText floats over graphics (text background transparent)
2$04Graph_Mode_EnGraphics pipeline on — required for sprites
3$08Bitmap_EnBitmap layer on
4$10TileMap_EnTile layer on
5$20Sprite_EnSprite layer on
6$40GAMMA_EnGamma correction
7$80Disable_VidDisable video; available CPU bandwidth still depends on other bus users

Text + overlay + graphics + sprites = $27. Add bitmap for $2F.

Sprite attribute block — VICKY page $FC, offsets $1300–$16FF

The 128 attribute records live in a dual-port BRAM inside I/O page $FC (the same page as the bitmap/gamma registers). Map the page into a CPU slot to reach it — e.g. write $FC to MMU_SLOT_2 ($FFAA) and the block appears at $4000–$5FFF. Each sprite owns 8 bytes:

SpritesPage offsetCPU addr (slot 2)Record n at
0 – 31$1300–$13FF$5300–$53FF$5300 + 8×n
32 – 63$1400–$14FF$5400–$54FF$5400 + 8×(n−32)
64 – 95$1500–$15FF$5500–$55FF$5500 + 8×(n−64)
96 – 127$1600–$16FF$5600–$56FF$5600 + 8×(n−96)

The RTL rotates the page index (RecodedAddy) so that page $13 lands on BRAM rows 0–31 — the table above is the net effect; sprite 0 really is the first 8 bytes of $1300.

The 8-byte attribute record

Multi-byte fields are big-endian (high byte first, 6809-friendly), so a single 16-bit STD at the high offset stores X or Y correctly in one instruction:

Worth knowing if you are reading other documentation: pre-rework cores and the official 65C02 material describe these fields as little-endian. The 6809 rework changed it, confirmed on the hardware, and the NitrOS-9 equates were corrected to match on 2026-08-31.

OffsetFieldContents
+0CTRLbit 0 enable · bits 2:1 LUT · bits 4:3 depth · bits 6:5 size
+1ADDR hipixel data address bits 23:16
+2ADDR midpixel data address bits 15:8
+3ADDR lopixel data address bits 7:0
+4X hiposition bits 15:8
+5X loposition bits 7:0
+6Y hiposition bits 15:8
+7Y loposition bits 7:0
CTRL bits 6:5SizeExample CTRL (enable, LUT0)
0032 × 32$01
0124 × 24$21
1016 × 16$41
118 × 8$61

The pixel-data address is a physical address in system RAM (block × $2000 + offset, for every SRAM block through $FB), pixels stored row-major, one byte per pixel, rows packed at the sprite’s width. Keep depth = 00 (8 bpp).

Graphics CLUTs — VICKY page $FD, offsets $1000–$1FFF

Sprites pick one of four CLUTs with CTRL bits 2:1. The CLUTs share page $FD with the font (font at $0000–$0FFF, CLUTs above it). Each CLUT is 256 entries × 4 bytes, ordered B, G, R, A. All four read back (the CPU port of a true dual-port RAM) and hold zeros at power-up: the shell’s colors come from the text color LUTs below, so nothing loads these until a bitmap viewer or a sprite program does.

CLUTPage offsetCPU addr (slot 2)Entry i at
LUT0$1000–$13FF$5000–$53FF$5000 + 4×i
LUT1$1400–$17FF$5400–$57FF$5400 + 4×i
LUT2$1800–$1BFF$5800–$5BFF$5800 + 4×i
LUT3$1C00–$1FFF$5C00–$5FFF$5C00 + 4×i

Text color LUTs — VICKY page $FC, offsets $1700 (foreground) and $1740 (background)

Text and the banner font take their colors from two 16-entry tables in page $FC, the sprite-record page: foreground at $1700–$173F, background at $1740–$177F, 4 bytes per entry ordered B, G, R, A, indexed by the two nibbles of the character’s attribute byte. The core loads both with the OS-9 palette when the bitstream comes up, so they survive a reset; a power cycle restores them. The CPU reads them back (each table has a shadow copy written on the same strobe), so a program can save the tables it is about to change and put them back on exit. lutrd on the kit disks dumps both, plus the graphics CLUTs and the gamma tables.

TablePage offsetEntriesAccess
text FG$1700–$173F16 × B G R Aread / write
text BG$1740–$177F16 × B G R Aread / write
gamma B / G / R$0000 / $0400 / $08003 × 256 bytesread / write
graphics LUT0–3page $FD $1000 + $400×n256 × B G R A eachread / write

Line-draw accelerator — VICKY page $FC, offsets $1080–$1087 (wildbits.d: TyVKY_LD_*)

A Bresenham line engine sits at the top of the bitmap register block (TyVKY_BM0_CTRL_REG is $F000 with page $FC in slot 7, so these are $F080–$F087). Write the two end points and a color, raise the go bit, and the engine walks the line at 100 Mhz, queueing line writes into an 8,192-entry × 34-bit FIFO (34 KB of queue data; 36 KB of allocated block RAM) that the memory manager drains into the chosen bitmap. It writes one byte per pixel at bitmap start + y×320 + x in the 320-wide 8-bit modes; in HIRES4 (GFX_HIRES4) X runs to 639 (TyVKY_LD_XMAX4) and the low nibble of the color is the dot. Pixels reach SRAM only while VKY_DRAWLINE_REG ($FFCA) bit 0 is set.

Offsetwildbits.dWriteRead
$1080TyVKY_LD_CTRLbit 0 TyVKY_LD_ENABLE (legacy; the write gate is $FFCA bit 0) · bit 1 TyVKY_LD_GO · bits 3:2 target bitmap (TyVKY_LD_BM0 $00, TyVKY_LD_BM1 $04, TyVKY_LD_BM2 $08; $0C falls back to base $001000) · bit 4 TyVKY_LD_RESETbit 7 TyVKY_LD_DONE (1 = the generator is done, not busy), bits 6:0 the control bits
$1081TyVKY_LD_COLOR8-bit CLUT index (HIRES4: bits 3:0)the color
$1082TyVKY_LD_X0_HX0 bits 9:8TyVKY_LD_COUNT_H: FIFO entries still queued, bits 13:8
$1083TyVKY_LD_X0_LX0 bits 7:0TyVKY_LD_COUNT_L: FIFO entries still queued, bits 7:0
$1084TyVKY_LD_X1_HX1 bits 9:8X1 bits 7:0 (the read order is swapped)
$1085TyVKY_LD_X1_LX1 bits 7:0X1 bits 9:8
$1086TyVKY_LD_Y0Y0 (8 bits)Y1 (swapped)
$1087TyVKY_LD_Y1Y1 (8 bits)Y0 (swapped)
  • Accepted range: X0 and X1 below 320 (640 in HIRES4), Y0 and Y1 below 240 (TyVKY_LD_XMAX8, TyVKY_LD_XMAX4, TyVKY_LD_YMAX) — a go with any end point outside is ignored (the engine stays idle, done never rises).
  • Handshake: asserting the go bit while idle starts the line and the engine parks in its done state until the go bit is written back to 0; drop it before the next line. Done (bit 7 on read) says the walk has finished; the FIFO count at $1082/$1083 says how many entries are still queued. Wait for the queue to drain before treating the bitmap as complete. In HIRES4, shallow lines can combine two adjacent pixels into one entry; unpaired pixels preserve the other nibble.
  • Read-back quirks: X0 cannot be read (its two bytes return the FIFO count), and the X1 and Y read order is the reverse of the write order — both are in TinyVicky_BM_Registers.v’s read multiplexer. Bit 7 on read is TyVKY_LD_DONE.
  • Target address: bits 3:2 pick which bitmap layer’s start address ($1001–$1003 / $1009–$100B / $1011–$1013) the pixel addresses are built on; the layer does not have to be displayed.
  • Cost: the line FIFO uses 8 × RAMB36 (288 Kbit physical), with 8,192 × 34 bits (272 Kbit) of queue data. The sprite engine has a separate 512 × 18-bit line buffer; it does not use this FIFO.

Sources: TinyVicky_BM_Registers.v (LINE_DRAWING_REG, the write decode on address bit 7, the read multiplexer), LineDraw.v (X0_Ok/Y0_Ok limits, the IDLE/RUN/DONE machine, Addy_Addyx_Offset), TinyVickyCoreModule.v (the LINEDRAWING_Reg64 wiring), TinyVKY2K2_IO_Page0_Devices.v (CS_VICKY_BITMAP: page $FC, offsets $1000–$10FF; absolute $1F_9000–$1F_90FF; the Jr2 decode is identical).

640 × 240 × 16-color bitmap mode — GFX MODE $FFCB

The bitmap engine’s native picture is 320 × 240 with one byte per dot, each dot shown twice across. HIRES4 keeps every byte where it is and reads it as two dots of four bits, the high nibble on the left, so a 320-byte row becomes 640 dots and the frame stays 76,800 bytes: same RAM, same fetch bandwidth, same raster, nothing for an old monitor to notice. Two ways to switch it on, OR’d together:

WhereBits
$FFCB (fixed I/O)bit 0 GFX_HIRES4: every bitmap plane · bits 3:1 GFX_GROUP: which 16-entry slice of the plane’s CLUT the nibbles index. Pokeable from any task, no page $FC mapping needed; reset value 0 = the 320-wide behaviour.
bitmap control byte ($F000 / $F008 / $F010 with page $FC in slot 7)bit 4 BM0_HIRES4: this plane alone · bits 7:5 BM0_GROUP: its CLUT slice. Bits 3:0 (enable, LUT number) unchanged.

Colors. A dot’s CLUT entry is group × 16 + nibble, in the CLUT the plane’s LUT bits select; the sixteen entries of the slice are the whole palette of that plane. Nibble 0 is transparent, as byte 0 is in the 320 mode, so it shows the layer behind or VICKY’s background color ($FFCD–$FFCF). Transparency is per 640 dot: the two halves of one byte can show through to different things.

What it does not change. Sprites, tiles and text are not part of it. They fetch and draw exactly as before, at 320 dots doubled, and are composited with the 640-wide bitmap dots in the usual layer order ($FFC2/$FFC3): a sprite or tile dot always covers a pair of bitmap dots, and its X position is still a 320-column unit, so it cannot sit on an odd 640 column. Each plane decides for itself, so a 640-wide picture and a 320-wide one can share the frame. The dot order inside a pair is fixed by the design (a blanking-aligned phase, not a sampled clock), so it is the same on every build.

On the Jr2 the mode costs a second CLUT copy and a second color line in block RAM (see the block-RAM budget below); both cores carry it.

Coordinates

Sprite positions live in a space offset 32 pixels beyond the visible screen on the top and left, so sprites can slide off any edge. The visible 320×240 area spans sprite coordinates (32,32) to (351,271):

(0,0) off-screen margin (32,32) screen top-left (351,271) bottom-right 8×8 @ (344,32) = ($0158,$0020) visible 320 × 240

Upper-right corner for an N-wide sprite: X = 32 + 320 − N, Y = 32. For 8×8: X = 344 ($0158), Y = 32 ($0020).

Minimum recipe — a green 8×8 sprite at screen center

Read this first

Five register groups, one protected mapping window. This example describes direct MLUT access: the kernel restores maps during task switches, so a temporary direct mapping must remain protected until it is restored. Use kernel mapping services where the installed kernel supports the required device mapping.

  1. Prepare pixel data (no masking needed) — fill a 64-byte buffer in RAM you own with $01 (pixel index 1) and compute its physical address: block# × $2000 + offset. The buffer must outlive the sprite — a process’s pages are recycled at exit, so stay resident or use memory you keep.
  2. Enter the masked window — save CC first, then orcc #IntMasks. Everything touching $FFA0, the slot registers, or the mapped window sits inside one masked stretch.
  3. MLUT setup — read $FFA0, save it, write it back with bits [5:4] (EDIT map) copied from bits [1:0] (ACTIVE map) — otherwise slot writes edit somebody else’s map. Save slot 5 ($FFAD, window at $A000) and write $FD into it.
  4. Palette (page $FD) — LUT0 entry 1 at window+$1004: write $00, $FF, $00, $00 (B, G, R, A) — pure green.
  5. Sprite record (page $FC) — write $FC to $FFAD; sprite 0’s record is at window+$1300, eight bytes, big-endian fields:
    OffsetValueMeaning
    +0$61enable + 8×8 (size 11) + LUT0 + depth 0
    +1..+3addr hi, mid, lophysical address of the pixel buffer
    +4, +5$00, $BCX = 188  (center: 32 + (320−8)/2)
    +6, +7$00, $94Y = 148  (center: 32 + (240−8)/2)
    If the other 127 records can’t be trusted (power-on garbage can carry stray enable bits), zero $1300–$16FF first.
  6. Leave the window — restore $FFAD, restore $FFA0, then restore the saved CC (including the original interrupt masks).
  7. Enable the layer — $FFC0 is fixed I/O: no mapping, no masking, any map, any time. Read it, OR in $26 (graphics $04 + overlay $02 + sprite $20, preserving the text bit), write it back. The green square appears at center.

To hide the sprite later: clear bit 5 of $FFC0 (no mapping needed), or clear the record’s enable bit (needs the mapped window again). The complete working implementation of this recipe is the sprtest command source: level1/wildbits/cmds/sprtest.asm.

Where this comes from

RTL and definitions read for this reference:
• Sprite_State_Machine.v — the per-line-pair scan, line-hit test and VRAM fetch.
• TinyVickyCoreModule.v — master video scheduler and compositor.
• TinyVKY2K2_IO_Page0_Devices.v — attribute BRAM, page rotation (RecodedAddy), CLUTs.
• defs/wildbits.d — register names and addresses.

WildBits K2 / Jr2 · FNX6809 core · hardware reference · the FPGA's own memory

How the cores spend their block RAM

Routed RAMB36/RAMB18 totals for both RC24 builds, followed by a source/IP inventory of the main memories. Per-purpose grouping follows those instances; logical capacity differs from physical allocation. The 2 MB external SRAM (the CPU's memory and the video RAM) is not FPGA memory and is outside this ledger.

Inside the FPGA
Graphics
CLUTs, sprite attributes and line buffers
Text
Character matrix, colors and font
I/O
FIFOs between the CPU and peripherals
External SRAM
2 MB chip; separate from block RAM
Block RAM use · RC24 report snapshot
K2 · 44 / 365 tilesJr2 · 40 / 50 tiles
Notes
640-pixel bitmaps
HIRES4 control and composition
Line-draw accelerator
the Bresenham engine at $1080
Notes
FLASHDIS
Current RAM mode and safe register writes
System RAM
252 blocks in the Longview RAM pool

Source: RC24 routed utilization reports (K2 and Jr2, October 9) and memory IP configurations (.xci). Physical primitive totals are report figures; logical capacities come from the IP configuration and RTL arrays. Kbit = 1,024 bits; a RAMB36 tile is 36 Kbit, a RAMB18 half-tile 18 Kbit.

K2 (xc7a200t)

At a glanceDetail
44 / 365block RAM tiles used (12.05%)
1,584 Kbit198 KB physical: 29 × 36K + 30 × 18K (27 RAMB36E1, 2 FIFO36E1, 28 RAMB18E1, 2 FIFO18E1)
272 Kbitline FIFO queue data; physical allocation includes primitive granularity
584 LUTsas distributed RAM (1.26% of the LUTs that can be memory), plus 196 as shift registers

By purpose

PurposeKbitShare · Of the 1,584 KbitWhat it is
Graphics engine (VICKY)39625.0%
CLUTs, three layer line buffers, sprite line, final RGB lines, tile-map capture, mouse pointer, sprite registers, gamma
Serial and bus I/O FIFOs27017.0%
MIDI, WiFi, WizNet, VS1053, PS/2, optical keyboard, LCD, I²C
Text display25215.9%
character matrix, color matrix, font, foreground and background palettes
MemText (VRAM text mode)18011.4%
its own font, two line memories, two greyscale LUTs
Line-draw accelerator FIFO28818.2%
one 8,192-entry × 34-bit line-write FIFO
Sound905.7%
PSG/SID command FIFOs, SID and OPL3 emulation tables
Debug serial port905.7%
the Gavin debug channel's command, reply and receive buffers
System page RAM181.1%
$FD00 page, palette read-back shadows, the $FFF0 vector copy
Total1,584100%44 tiles

Block by block

Logical = what the IP was configured to hold; physical = the primitives it occupies. A true-dual-port memory with a 32- or 64-bit second port is forced into whole 36 Kbit tiles however small its contents, which is where most of the gap lives.

InstanceHoldsConfiguredLogical KbitPhysicalKbit
Text display
TEXT_BLOCKthe text screen's character matrix (page $FE)8192 × 8, true dual port642 × RAMB3672
COLOR_BLOCKthe text screen's color matrix (page $FF)8192 × 8, true dual port642 × RAMB3672
FONTthe two text font sets, initialized in the FPGA image from Font_OS9_bannerfont.coe4096 × 8, true dual port321 × RAMB3636
FOREGROUND_LUT16-entry text foreground palette (B,G,R,A); the video side reads it 32 bits wide64 × 8 / 320.51 × RAMB3636
BACKGROUND_LUT16-entry text background palette64 × 8 / 320.51 × RAMB3636
Graphics engine
LUT_4Tables_Hthe four graphics CLUTs (4 × 256 entries × 4 bytes)4096 × 8 / 32321 × RAMB3636
LUT_4Tables_La second copy of the CLUTs so HIRES4 looks up both dots of a byte in one cycle4096 × 8 / 32321 × RAMB3636
Layer0/1/2_DPMemone scan line of pixels for each of the three bitmap/tile layers3 × (256 × 32 / 16)243 × RAMB36108
Sprite_DPMemthe composed sprite line512 × 1891 × RAMB1818
OUTPUT_RGB_Hthe final RGB pixel line handed to the output512 × 32, simple dual port161 × RAMB1818
OUTPUT_RGB_Lthe second dot of each HIRES4 pair, one color line of its own512 × 32, simple dual port161 × RAMB1818
TileMapCapturetwo tile-map lines captured as 16-bit entries512 × 16, simple dual port81 × RAMB1818
MousePointerMemthe hardware mouse pointer image1024 × 8, true dual port81 × RAMB1818
Sprite_Reg_Block_instthe 128 sprite attribute records (page $FC, $1300–$16FF); the engine reads a whole 64-bit record per cycle1024 × 8 / 6482 × RAMB3672
GAMMA_R / G / Bgamma tables, boot-loaded from init_hex_GAMMA.coe3 × (256 × 8)63 × RAMB1854
Line-draw accelerator
LD_AddyPixel_FIFOthe Bresenham unit's queue: mode/nibble flags, color and 24-bit addressFIFO 8,192 × 34, common clock2728 × RAMB36288
MemText — the text mode whose matrices live in video RAM (master control register 1, bit 6)
MEM_TEXT_FONTtwo 8×8 font sets and one 8×16 set, from FontSet2x8x8Set_1x8x16Set.coe8192 × 8, true dual port642 × RAMB3672
TEXT_MEMORY, COLOR_MEMORYone line of characters and one of colors fetched from VRAM2 × (128 × 16)42 × RAMB1836
FG_LUT, BG_LUTMemText palettes, greyscale at boot (LUT_GreyScale.coe)2 × (2048 × 8 / 32)322 × RAMB3672
System page RAM
FC00_Block_RAMthe $FD00–$FDFF page, read-back shadows of the text palettes at $FF00–$FF7F, and the $FFF0–$FFFF vector copy that lets any block sit in slot 71024 × 8, single port81 × RAMB1818
Serial and bus I/O FIFOs
MIDI_RxD_FIFO, MIDI_TxD_FIFOthe MIDI UART (SAM2695 and the DIN port)2 × (FIFO 2048 × 8)322 × RAMB1836
WIFI_RxD_FIFO, WIFI_TxD_FIFOthe WizFi serial channel2 × (FIFO 2048 × 8)322 × RAMB1836
Wiz5100S Rx_FIFO, Tx_FIFOK2 only: the WizNet Ethernet bus interface2 × (FIFO 2048 × 8)322 × RAMB1836
VS1053B_My_FIFOdata stream to the VS1053 codec ($FF50 bridge)FIFO 2048 × 8161 × RAMB1818
FIFOKeyboard, FIFOMousePS/2 receive queues2 × (FIFO 256 × 8)42 × RAMB1836
FIFO_OPTKBDK2 only: the optical keyboard scannerFIFO 1024 × 16161 × RAMB1818
LCD_FIFO_2KK2 only: SPI LCD command/data streamFIFO 2048 × 12, built-in241 × FIFO3636
I2C_FIFO_CMD, I2C_FIFO_READK2 only: the I²C master's command and read queuesFIFO 1024 × 36; FIFO 2048 × 8521 × RAMB36 + 1 × RAMB1854
Sound
PSG_CMD_Write_FIFO_instregister writes queued to the sound chipsFIFO 256 × 174.31 × RAMB1818
SID_FIFO_instthe SID/OPL3 bridge's access FIFOFIFO 1024 × 16, built-in161 × FIFO1818
sid_6581_Lefttables inferred inside the SID emulationRTL arrays—1 × RAMB1818
opl/channelschannel state of the OPL3 emulationRTL arrays—2 × RAMB1836
Debug serial port (GavinDebug)
Serial2CPU48-bit debug commands from the hostFIFO 512 × 48, built-in241 × FIFO3636
CPU2Serialreplies to the hostFIFO 512 × 8, built-in41 × FIFO1818
DEBUG_SERIAL_BUFthe debug data buffer (what k2dump reads out)2048 × 8, true dual port161 × RAMB1818
SerialRxD_FIFOraw receive queue of the debug UARTFIFO 512 × 841 × RAMB1818
Total block RAM—44 tiles1,584

Distributed (LUT) RAM

The RC24 placed report counts 584 LUTs as distributed RAM and 196 as shift registers. LUT RAM serves small peripheral queues, emulation storage and palette shadows; shift registers provide pipeline delays and synchronization storage.

Jr2 (xc7a35t)

At a glanceDetail
40 / 50block RAM tiles used (80.0%)
1,440 Kbit180 KB physical: 27 × 36K + 26 × 18K (26 RAMB36E1, 1 FIFO36E1, 24 RAMB18E1, 2 FIFO18E1)
272 Kbitline FIFO queue data; physical allocation includes primitive granularity
488 LUTsas distributed RAM (5.1% of the 9,600 LUTs that can be memory), plus 180 as shift registers

By purpose

PurposeKbitShare · Of the 1,440 KbitDifference from the K2
Graphics engine (VICKY)39627.5%
same blocks: the HIRES4 pair (second CLUT copy, second RGB line, +54 Kbit)
Text display25217.5%
same blocks
MemText (VRAM text mode)18012.5%
same blocks
Line-draw accelerator FIFO28820.0%
same block
Serial and bus I/O FIFOs1268.8%
no WizNet, optical keyboard, LCD or I²C queues (−144 Kbit)
Sound906.2%
same blocks
Debug serial port906.2%
same blocks
System page RAM181.2%
same block
Total1,440100%40 tiles

Block by block

InstanceHoldsConfiguredLogical KbitPhysicalKbit
Text display — as the K2
TEXT_BLOCK, COLOR_BLOCKcharacter and color matrices2 × (8192 × 8)1284 × RAMB36144
FONTthe two text font sets (FONT_CPU_Memory here, the same contents)4096 × 8321 × RAMB3636
FOREGROUND_LUT, BACKGROUND_LUTtext palettes2 × (64 × 8 / 32)12 × RAMB3672
Graphics engine
LUT_4Tables_Hthe four graphics CLUTs (4 × 256 entries × 4 bytes)4096 × 8 / 32321 × RAMB3636
LUT_4Tables_Lthe second copy of the CLUTs for HIRES4’s two dots per byte (as the K2)4096 × 8 / 32321 × RAMB3636
Layer0/1/2_DPMemthree layer line buffers3 × (256 × 32 / 16)243 × RAMB36108
Sprite_DPMemthe composed sprite line512 × 1891 × RAMB1818
OUTPUT_RGB_Hthe final RGB pixel line handed to the output512 × 32161 × RAMB1818
OUTPUT_RGB_Lthe second dot of each HIRES4 pair, one color line of its own512 × 32161 × RAMB1818
TileMapCapture, MousePointerMemtile-map line capture; mouse pointer image512 × 16; 1024 × 8162 × RAMB1836
Sprite_Reg_Block_instthe 128 sprite attribute records1024 × 8 / 6482 × RAMB3672
GAMMA_R / G / Bgamma tables3 × (256 × 8)63 × RAMB1854
Line-draw accelerator, MemText, system page — as the K2
LD_AddyPixel_FIFOthe line-draw pixel queueFIFO 8,192 × 342728 × RAMB36288
MEM_TEXT_FONT, TEXT_MEMORY, COLOR_MEMORY, FG_LUT, BG_LUTthe MemText font, line memories and palettes8192 × 8; 2 × (128 × 16); 2 × (2048 × 8 / 32)1004 × RAMB36 + 2 × RAMB18180
FC00_Block_RAMthe $FD00 page, palette shadows and vector copy1024 × 881 × RAMB1818
Serial and bus I/O FIFOs
MIDI_RxD_FIFO, MIDI_TxD_FIFOthe MIDI UART2 × (FIFO 2048 × 8)322 × RAMB1836
WIFI_RxD_FIFO, WIFI_TxD_FIFOthe WizFi serial channel2 × (FIFO 2048 × 8)322 × RAMB1836
VS1053B_My_FIFOdata stream to the VS1053 codecFIFO 2048 × 8161 × RAMB1818
FIFOKeyboard, FIFOMousePS/2 receive queues2 × (FIFO 256 × 8)42 × RAMB1836
Sound and debug port — as the K2
PSG_CMD_Write_FIFO_inst, SID_FIFO_inst, sid_6581_Left, opl/channelssound-chip command queues and emulation tablesFIFO 256 × 17; FIFO 1024 × 16; RTL arrays≈ 201 × FIFO18 + 4 × RAMB1890
Serial2CPU, CPU2Serial, DEBUG_SERIAL_BUF, SerialRxD_FIFOthe debug channel's queues and bufferFIFO 512 × 48; FIFO 512 × 8; 2048 × 8; FIFO 512 × 8481 × FIFO36 + 1 × FIFO18 + 2 × RAMB1890
Total block RAM—40 tiles1,440

The Jr2 RC24 placed report counts 488 LUTs as distributed RAM (5.1% of the 9,600 memory-capable LUTs) and 181 as shift registers.

What this means

  • The Jr2 is the constrained board. RC24 uses 40 of 50 block RAM tiles, leaving 10 tiles (360 Kbit). The line FIFO alone occupies eight tiles.
  • The K2 has 321 tiles free (11,556 Kbit). Block RAM is nowhere near a limit there; the K2 core's timing closure (the 200 Mhz scheduler, the SRAM strobe constraints) is the constraint, not memory.
  • Physical allocation exceeds logical contents because of primitive granularity. The four palette-style LUTs (text foreground/background, MemText foreground/background) occupy 144 Kbit for 33 Kbit of contents because their video-side ports are 32 bits wide; the sprite register block takes 72 Kbit for 8 because its engine port is 64 bits wide; the three gamma tables take 54 Kbit for 6. These are allocation costs, not unused externally addressable RAM; changing them requires redesigning the video ports.
  • No ILA or VIO debug cores are in either routed build. The MC6809_ILA, Chipscope144_3x12 and vio_0 IPs exist in both projects but occupy no block RAM in these bitstreams.
  • The text screen lives in the FPGA, the graphics do not. The 8 KB character matrix, 8 KB color matrix and 4 KB font are block RAM (mapped through device pages $FD–$FF), while bitmaps, tiles and sprite images stream from the external 2 MB SRAM through the line buffers listed above.