diff --git a/site/astro.config.mjs b/site/astro.config.mjs
index d4d40fa..a79140a 100644
--- a/site/astro.config.mjs
+++ b/site/astro.config.mjs
@@ -8,6 +8,22 @@ export default defineConfig({
devToolbar: {
enabled: false,
},
+ server: {
+ host: '0.0.0.0',
+ port: 4321,
+ },
+ vite: {
+ server: {
+ allowedHosts: [process.env.PUBLIC_DOMAIN, 'localhost'].filter(Boolean),
+ ...(process.env.VITE_HMR_HOST && {
+ hmr: {
+ host: process.env.VITE_HMR_HOST,
+ protocol: 'wss',
+ clientPort: 443,
+ },
+ }),
+ },
+ },
integrations: [
starlight({
title: 'SkyWalker-1 Docs',
@@ -44,6 +60,7 @@ export default defineConfig({
{
label: 'BCM4500',
items: [
+ { label: 'Register Map', slug: 'bcm4500/register-map' },
{ label: 'Demodulator', slug: 'bcm4500/demodulator' },
{ label: 'Tuning Protocol', slug: 'bcm4500/tuning-protocol' },
{ label: 'GPIF Streaming', slug: 'bcm4500/gpif-streaming' },
@@ -78,7 +95,8 @@ export default defineConfig({
{ label: 'Rev.2 Analysis', slug: 'firmware/rev2-analysis' },
{ label: 'Kernel FW01', slug: 'firmware/kernel-fw01' },
{ label: 'FW2.13 Variants', slug: 'firmware/fw213-variants' },
- { label: 'Custom v3.01\u2013v3.02', slug: 'firmware/custom-v301' },
+ { label: 'Custom v3.01', slug: 'firmware/custom-v301' },
+ { label: 'Custom v3.02', slug: 'firmware/custom-v302' },
{ label: 'Storage Formats', slug: 'firmware/storage-formats' },
],
},
diff --git a/site/src/content/docs/bcm4500/demodulator.mdx b/site/src/content/docs/bcm4500/demodulator.mdx
index e86a810..5a531fe 100644
--- a/site/src/content/docs/bcm4500/demodulator.mdx
+++ b/site/src/content/docs/bcm4500/demodulator.mdx
@@ -7,6 +7,8 @@ import { Tabs, TabItem, Badge, Aside, Steps } from '@astrojs/starlight/component
The Broadcom BCM4500 is a 128-pin MQFP satellite demodulator that handles RF demodulation, forward error correction, and MPEG-2 transport stream output. The FX2 communicates with it exclusively over the shared I2C bus using an indirect register protocol.
+See the [Register Map](/bcm4500/register-map/) for a consolidated lookup of all BCM4500 and FX2 register addresses referenced on this page.
+
## I2C Addressing
| Parameter | Value |
@@ -122,9 +124,49 @@ The trailing zero write (step 3) appears in all stock firmware versions. Its pur
## Demodulator Scan
-The tune function tries up to 3 different I2C address configurations per attempt, with 3 outer retries (up to 9 total I2C programming attempts). This supports hardware variants where the BCM4500 may appear at different bus addresses.
+### Tuning Retry (All Firmware Versions)
-The v2.13 firmware adds boot-time probing: the INT0 handler polls addresses 0x7F and 0x3F up to 40 times, setting a flag if neither responds. This flag prevents tuning attempts on boards with absent demodulators.
+The tune function wraps the BCM4500 I2C programming sequence in a two-level retry loop:
+
+- **Inner loop**: tries up to 3 different I2C address configurations per attempt. This supports hardware variants where the BCM4500 may appear at different bus addresses.
+- **Outer loop**: retries the entire inner scan up to 3 times.
+
+This yields up to **3 × 3 = 9 total I2C programming attempts** per tune command. The v2.13 firmware adds a 20-attempt retry with checksum verification on each individual I2C write within the programming step.
+
+### Boot-Time Probe (v2.13 Only)
+
+The v2.13 firmware repurposed the INT0 interrupt handler (vector at `CODE:0003`) from USB re-enumeration to demodulator availability detection. The handler runs once during boot, before the main loop:
+
+```c title="INT0 handler (v2.13) — demod probe"
+void INT0_vector(void) {
+ for (counter = 0x28; counter != 0; counter--) { // 40 iterations
+ byte result = I2C_read(0x7F); // Probe first alternate address
+ if (result != 0x01) {
+ result = I2C_read(0x3F); // Probe second alternate address
+ if (result != 0x01) break; // Got a response — demod present
+ }
+ }
+ no_demod_flag = (counter == 0); // True if all 40 attempts failed
+}
+```
+
+If neither address responds after 40 iterations, `no_demod_flag` is set. This flag causes the firmware to skip all tuning attempts, avoiding I2C bus hangs on boards where the demodulator is absent or unpopulated.
+
+
+
+### `no_demod_flag` Behavior
+
+When the boot probe fails (all 40 attempts exhausted):
+
+1. `no_demod_flag` is set to a non-zero value
+2. The firmware enters its normal main loop but skips BCM4500 initialization
+3. `TUNE_8PSK` (0x86) commands are accepted but silently fail (no I2C transactions issued)
+4. `GET_SIGNAL_LOCK` (0x90) returns 0x00 (unlocked)
+5. The device remains functional for USB communication but cannot tune
+
+This graceful degradation allows the host software to detect the condition via persistent lock failure rather than USB timeouts.
## FEC Architecture
diff --git a/site/src/content/docs/bcm4500/register-map.mdx b/site/src/content/docs/bcm4500/register-map.mdx
new file mode 100644
index 0000000..8143850
--- /dev/null
+++ b/site/src/content/docs/bcm4500/register-map.mdx
@@ -0,0 +1,199 @@
+---
+title: BCM4500 Register Map
+description: Definitive register lookup for BCM4500 direct registers, indirect registers, FX2 XRAM/IRAM locations, and I2C controller addresses.
+---
+
+import { Badge, Aside } from '@astrojs/starlight/components';
+
+
+
+This page consolidates every known register address used by the SkyWalker-1 hardware into a single lookup reference.
+
+## BCM4500 Direct Registers
+
+These registers are accessed via standard I2C read/write to the BCM4500 at 7-bit address **0x08** (write byte 0x10, read byte 0x11).
+
+| Address | Name | R/W | Function |
+|---------|------|-----|----------|
+| 0xA2 | Status | R | Readiness status. Returns 0x02 when powered on, no signal locked. Polled during boot probe and [signal strength readback](/bcm4500/signal-monitoring/). |
+| 0xA4 | Lock | R | Signal lock indicator. Bit 5 (mask 0x20) = signal locked. Read by `GET_SIGNAL_LOCK` (0x90). The kernel treats any non-zero value as locked. |
+| 0xA6 | Indirect Page | W | Page/address select for the [indirect register protocol](/bcm4500/demodulator/#indirect-register-protocol). Typically written with 0x00 (page 0). |
+| 0xA7 | Indirect Data | R/W | Data register for indirect reads and writes. Supports auto-increment for multi-byte writes within a single I2C transaction. |
+| 0xA8 | Indirect Command | R/W | Command register. Write 0x01 = indirect read, 0x03 = indirect write. Read to poll: bit 0 clear = command complete. |
+| 0xF9 | Demod Status | R | Extended demodulator status. Read by `GET_DEMOD_STATUS` (0x99) in v2.13 firmware. Also polled by the v2.13 INT0 handler. Not accessed by v2.06 or Rev.2. |
+
+### Indirect Register Triad
+
+Registers 0xA6, 0xA7, and 0xA8 form a triad that provides access to the BCM4500's internal register space. The sequence is always: select page (0xA6) → write/read data (0xA7) → execute command (0xA8) → poll 0xA8 for completion.
+
+See [Demodulator — Indirect Register Protocol](/bcm4500/demodulator/#indirect-register-protocol) for the full byte-level I2C sequences.
+
+## Indirect Registers (Page 0)
+
+These are the BCM4500 internal registers accessed through the 0xA6/0xA7/0xA8 indirect protocol. All known registers are on page 0x00.
+
+### Signal Quality
+
+| Register | Size | Function | Read By |
+|----------|------|----------|---------|
+| 0x00--0x01 | 2 bytes | SNR value (16-bit, little-endian). Bytes 0--1 of `GET_SIGNAL_STRENGTH` (0x87) response. | [Signal Monitoring](/bcm4500/signal-monitoring/) |
+| 0x02--0x05 | 4 bytes | AGC and diagnostic data. Bytes 2--5 of `GET_SIGNAL_STRENGTH` (0x87) response. | [Signal Monitoring](/bcm4500/signal-monitoring/) |
+
+### Initialization Blocks
+
+Three blocks written during BCM4500 firmware load. The first byte of each block is the starting register address.
+
+| Block | Start Reg | Length | Data (hex) | Purpose |
+|-------|-----------|--------|------------|---------|
+| 0 | 0x06 | 7 bytes | `06 0b 17 38 9f d9 80` | Primary demod configuration |
+| 1 | 0x07 | 8 bytes | `07 09 39 4f 00 65 b7 10` | Secondary demod configuration |
+| 2 | 0x0F | 3 bytes | `0f 0c 09` | Final demod configuration |
+
+
+
+### Tuning Configuration
+
+After modulation dispatch, the [tuning protocol](/bcm4500/tuning-protocol/) writes frequency, symbol rate, FEC, and modulation parameters into BCM4500 page 0 registers via the indirect write protocol. The exact target register range depends on the configuration data length (typically 12--18 bytes starting at register 0x00).
+
+## FX2 XRAM Locations
+
+External RAM (XRAM) addresses used by the FX2 microcontroller for tuning state and configuration. These are **not** BCM4500 registers — they are FX2 memory locations that hold data destined for or read from the demodulator.
+
+### Modulation Configuration
+
+| Address | Name | Function |
+|---------|------|----------|
+| 0xE0EB | FEC Code Rate | Looked up from the FEC table for the active modulation. DCII modes use fixed value 0xFC. DSS/BPSK modes OR the lookup with 0x80. |
+| 0xE0EC | Modulation Type | 0x09 for DVB-S, Turbo, DSS, and BPSK modes. DCII modes load from the DCII lookup table. |
+| 0xE0F5 | Demod Mode | 0x10 for most modes. DCII variants use 0x10 (combo), 0x11 (offset QPSK), 0x12 (I-stream), or 0x16 (Q-stream). |
+| 0xE0F6 | Turbo Flag | 0x00 = standard FEC. 0x01 = turbo FEC (QPSK/8PSK/16QAM turbo modes). |
+
+### Tuning Parameters
+
+| Address | Size | Content | Source |
+|---------|------|---------|--------|
+| 0xE0CB--0xE0CE | 4 bytes | Symbol rate (big-endian) | Byte-reversed from EP0BUF[0--3] during `TUNE_8PSK` |
+| 0xE0DB--0xE0DE | 4 bytes | IF frequency (big-endian) | Byte-reversed from EP0BUF[4--7] during `TUNE_8PSK` |
+
+### FEC Rate Lookup Tables
+
+Populated at boot from CODE-space initialization tables. Indexed by the FEC rate byte from the `TUNE_8PSK` command payload.
+
+| Base Address | Modulation | Max Index | Rates |
+|-------------|-----------|-----------|-------|
+| 0xE0B1 | Turbo 8PSK | 5 | Turbo-specific code rates |
+| 0xE0B7 | Turbo QPSK | 5 | Turbo-specific code rates |
+| 0xE0BC | Turbo 16QAM | 1 | Single code rate |
+| 0xE0BD | DCII (all variants) | 9 | Combined code + modulation values |
+| 0xE0F9 | DVB-S QPSK / DSS / BPSK | 7 | 1/2, 2/3, 3/4, 5/6, 7/8, auto, none |
+
+### FW2/FW3 External Configuration
+
+| Address | Size | Content |
+|---------|------|---------|
+| 0xE080--0xE08E | 15 bytes | External calibration data loaded by [FW2 and FW3](/firmware/fw213-variants/) into demod registers at 0xE6C0--0xE6CD. Not used by FW1 (hardcoded config). |
+
+### USB Endpoint Buffer
+
+| Address | Size | Content |
+|---------|------|---------|
+| 0xE740--0xE749 | 10 bytes | EP0BUF — USB control transfer buffer. Contains the raw `TUNE_8PSK` payload before parsing. |
+
+## FX2 IRAM by Firmware Version
+
+Internal RAM (IRAM) addresses vary between firmware versions due to different stack pointer placement. This table maps the key locations for each version.
+
+### Stack and Status
+
+| Location | v2.06 | Rev.2 v2.10 | v2.13 FW1/FW2 | v2.13 FW3 |
+|----------|-------|-------------|---------------|-----------|
+| Stack pointer (SP) | 0x72 | 0x4F | 0x50 | 0x52 |
+| Config status byte | 0x6D | 0x4E | 0x4F | 0x51 |
+| I2C buffer high | -- | 0x48 | 0x48 | 0x4A |
+| I2C buffer low | -- | 0x49 | 0x49 | 0x4B |
+
+The config status byte is returned by `GET_8PSK_CONFIG` (0x80). See [Config Status](/usb/config-status/) for bit definitions.
+
+### Tuning Parameter Storage
+
+| Location | Address | Function |
+|----------|---------|----------|
+| Modulation type | 0x4D | Copied from EP0BUF[8] during `TUNE_8PSK` parsing |
+| FEC rate index | 0x4F | Copied from EP0BUF[9] during `TUNE_8PSK` parsing |
+
+
+
+### Custom Firmware (v3.01+)
+
+The custom firmware built with SDCC + fx2lib uses C variables instead of fixed IRAM addresses. The compiler manages allocation, so addresses are not guaranteed stable across builds. Key variables:
+
+| Variable | Type | Purpose |
+|----------|------|---------|
+| `config_status` | `volatile BYTE` | Configuration status byte |
+| `boot_stage` | `volatile BYTE` | Boot progress (0x00 = not started, 0xFF = complete) |
+| `i2c_buf[16]` | `__xdata BYTE` | I2C scratch buffer for writes |
+| `i2c_rd[8]` | `__xdata BYTE` | I2C scratch buffer for reads |
+| `tm_result[10]` | `__xdata BYTE` | Tune monitor result buffer |
+
+## FX2 I2C Controller
+
+The Cypress FX2LP's built-in I2C master controller uses three hardware registers in the SFR-mapped XRAM space.
+
+| Register | Address | Function |
+|----------|---------|----------|
+| I2CS | 0xE678 | Control/Status. Bit fields: DONE (bit 0), ACK (bit 1), BERR (bit 2), ID (bits 4:3), LASTRD (bit 5), STOP (bit 6), START (bit 7). |
+| I2DAT | 0xE679 | Data register. Write to transmit a byte, read to receive. First write after START sends the slave address byte. |
+| I2CTL | 0xE67A | Control register. Bit 0 = 400 kHz mode (set by all firmware versions at init). Bit 1 = STOPIE (stop interrupt enable). |
+
+### I2C Bus Addresses
+
+| 7-bit Address | 8-bit Write | 8-bit Read | Device |
+|--------------|-------------|------------|--------|
+| 0x08 | 0x10 | 0x11 | BCM4500 demodulator (operating address) |
+| 0x10 | 0x20 | 0x21 | Tuner / LNB controller |
+| 0x51 | 0xA2 | 0xA3 | Configuration EEPROM (serial number, calibration, firmware storage) |
+| 0x3F | 0x7E | 0x7F | BCM4500 alternate probe address (v2.13 boot detection only) |
+| 0x7F | 0xFE | 0xFF | BCM4500 alternate probe address (v2.13 boot detection only) |
+
+See [I2C Bus Architecture](/i2c/bus-architecture/) for bus topology and the [STOP Corruption Bug](/i2c/stop-corruption-bug/) for the spurious STOP issue affecting the FX2 controller.
+
+## Cross-Reference Index
+
+Every documentation page that references specific registers or memory addresses:
+
+### BCM4500 Direct Registers
+
+| Register | Pages |
+|----------|-------|
+| 0xA2 (Status) | [Demodulator](/bcm4500/demodulator/), [Signal Monitoring](/bcm4500/signal-monitoring/), [Version Comparison](/firmware/version-comparison/) |
+| 0xA4 (Lock) | [Demodulator](/bcm4500/demodulator/), [Signal Monitoring](/bcm4500/signal-monitoring/), [Tuning Protocol](/bcm4500/tuning-protocol/) |
+| 0xA6/0xA7/0xA8 (Indirect) | [Demodulator](/bcm4500/demodulator/), [Tuning Protocol](/bcm4500/tuning-protocol/), [Signal Monitoring](/bcm4500/signal-monitoring/) |
+| 0xF9 (Demod Status) | [Demodulator](/bcm4500/demodulator/), [Signal Monitoring](/bcm4500/signal-monitoring/), [Version Comparison](/firmware/version-comparison/) |
+
+### FX2 XRAM
+
+| Address Range | Pages |
+|--------------|-------|
+| 0xE0B1--0xE0F9 (FEC tables) | [Tuning Protocol](/bcm4500/tuning-protocol/) |
+| 0xE0CB--0xE0DE (Tune params) | [Tuning Protocol](/bcm4500/tuning-protocol/) |
+| 0xE0EB--0xE0F6 (Mod config) | [Tuning Protocol](/bcm4500/tuning-protocol/) |
+| 0xE080--0xE08E (FW2/FW3 cal) | [FW2.13 Variants](/firmware/fw213-variants/) |
+
+### FX2 IRAM
+
+| Address | Pages |
+|---------|-------|
+| Config status (version-dependent) | [Config Status](/usb/config-status/), [Version Comparison](/firmware/version-comparison/), [FW2.13 Variants](/firmware/fw213-variants/) |
+| SP, I2C buffers | [FW2.13 Variants](/firmware/fw213-variants/), [Version Comparison](/firmware/version-comparison/) |
+
+### I2C Controller
+
+| Register | Pages |
+|----------|-------|
+| I2CS/I2DAT/I2CTL (0xE678--0xE67A) | [I2C Bus Architecture](/i2c/bus-architecture/), [STOP Corruption Bug](/i2c/stop-corruption-bug/), [Demodulator](/bcm4500/demodulator/) |
diff --git a/site/src/content/docs/bcm4500/signal-monitoring.mdx b/site/src/content/docs/bcm4500/signal-monitoring.mdx
index 8f97c1f..d079254 100644
--- a/site/src/content/docs/bcm4500/signal-monitoring.mdx
+++ b/site/src/content/docs/bcm4500/signal-monitoring.mdx
@@ -7,6 +7,8 @@ import { Badge, Aside } from '@astrojs/starlight/components';
Signal monitoring uses two vendor commands: GET_SIGNAL_LOCK (0x90) for lock status and GET_SIGNAL_STRENGTH (0x87) for SNR and diagnostic data. Both read BCM4500 direct registers via I2C.
+See the [Register Map](/bcm4500/register-map/) for a consolidated lookup of all register addresses referenced on this page.
+
## Signal Lock (GET_SIGNAL_LOCK, 0x90)
Returns 1 byte from BCM4500 direct register 0xA4.
diff --git a/site/src/content/docs/bcm4500/tuning-protocol.mdx b/site/src/content/docs/bcm4500/tuning-protocol.mdx
index d741643..d7a4288 100644
--- a/site/src/content/docs/bcm4500/tuning-protocol.mdx
+++ b/site/src/content/docs/bcm4500/tuning-protocol.mdx
@@ -7,6 +7,8 @@ import { Tabs, TabItem, Badge, Steps, Aside } from '@astrojs/starlight/component
The TUNE_8PSK vendor command (0x86) is the primary mechanism for programming the BCM4500 demodulator to receive a satellite signal. The command carries a 10-byte payload encoding frequency, symbol rate, modulation type, and FEC rate. The firmware parses this payload, dispatches to a modulation-specific handler, programs the BCM4500 via I2C, and the host then polls for signal lock.
+See the [Register Map](/bcm4500/register-map/) for a consolidated lookup of all XRAM addresses and BCM4500 registers referenced on this page.
+
## Command Format
```
diff --git a/site/src/content/docs/firmware/fw213-variants.mdx b/site/src/content/docs/firmware/fw213-variants.mdx
index a448574..2e9f89b 100644
--- a/site/src/content/docs/firmware/fw213-variants.mdx
+++ b/site/src/content/docs/firmware/fw213-variants.mdx
@@ -21,10 +21,40 @@ The v2.13 firmware was distributed as three sub-variants via the `SW1_update_2_1
| Demod interface | **I2C bus** | **Parallel bus (P0/P1)** | **Parallel bus (enhanced)** |
| Config source | Hardcoded | External (`0xE080`--`0xE08E`) | External (`0xE080`--`0xE08E`) |
-