Rev.2 Firmware Analysis
The Rev.2 v2.10.4 firmware targets the Rev.2 hardware variant (PID 0x0202) and contains 107 functions — the most of any firmware version. Despite this, it produces the smallest binary (8,843 bytes) due to aggressive function decomposition into small helper routines.
Architectural Position
Section titled “Architectural Position”Rev.2 sits architecturally between v2.06 and v2.13:
| Aspect | v2.06 | Rev.2 v2.10 | v2.13 |
|---|---|---|---|
| INT0 behavior | USB re-enumeration | USB re-enumeration | Demod polling |
| Descriptor base | 0x1200 | 0x0E00 | 0x0E00 |
| Stack pointer | 0x72 | 0x4F | 0x50 |
| Vendor command range | 0x80—0x9D (30) | 0x80—0x9A (27) | 0x80—0x9D (30) |
| Demod probe at boot | No | No | Yes |
| Retry loops | No | No | Yes |
| Function count | 61 | 107 | 82-88 |
| Binary size | 9,472 bytes | 8,843 bytes | 9,322 bytes |
Why 107 Functions?
Section titled “Why 107 Functions?”The high function count is driven by three factors:
-
Granular decomposition: Rev.2 breaks large operations into many small helper functions (10-30 bytes each), where v2.06 inlines the same logic and v2.13 recombines it differently.
-
Massive configuration dispatcher:
FUN_CODE_0800is 874 bytes and contains an embedded copy of the main loop, causing Ghidra to count additional entry points as separate functions. -
Extra I2C/demodulator helper chains: GPIO control primitives, hardware-polling wait loops, and I2C bus management exist as individual callable units rather than being inlined.
Function Inventory Overview
Section titled “Function Inventory Overview”The 107 functions are organized into logical groups:
Vector Table and ISR Region (0x0000—0x0055)
Section titled “Vector Table and ISR Region (0x0000—0x0055)”| Address | Name | Size | Role |
|---|---|---|---|
0x0000 | RESET_vector | 3 | Jump to main at 0x155F |
0x0003 | INT0_ISR | 12 | INT0 handler — USB re-enumeration |
0x000F | INT0_ISR_bit_clear | 36 | CPUCS pulse, IRQ clear, delay |
0x0033 | INT2_USB_GPIF_vector | 3 | Clears CCON.4 (PCA timer) |
0x0036 | i2c_exchange_byte | 5 | I2C byte exchange primitive |
0x003B | I2C_ISR | 8 | I2C interrupt handler |
0x0043 | INT4_FX2_vector | 8 | Sets _0_1 flag, clears EXIF.4 |
0x004B | INT5_FX2_vector | 3 | Empty (RETI) |
0x0053 | INT6_FX2_vector | 3 | Sets _0_1 flag, clears EXIF.4 |
Vendor Command Dispatch (0x0056—0x0319)
Section titled “Vendor Command Dispatch (0x0056—0x0319)”| Address | Name | Size | Role |
|---|---|---|---|
0x0056 | vendor_cmd_dispatch | 342 | Range check 0x80—0x9A, jump table at 0x0076 |
0x01AC | GET_8PSK_CONFIG handler | 361 | Reads config byte, calls LNB probe |
0x0315 | vendor_cmd_stall | 2 | Stall handler (empty RET) |
0x0319 | Standard USB request handler | 869 | Switch for bRequest 0x00—0x0B |
Configuration and Tuning (0x0800—0x09A8)
Section titled “Configuration and Tuning (0x0800—0x09A8)”| Address | Name | Size | Role |
|---|---|---|---|
0x0800 | Config/tuning dispatcher | 874 | 128-entry switch on demod type, embedded main loop |
0x09A9 | Main init + main loop | 699 | Hardware init, infinite poll loop |
BCM4500 and GPIF (0x0C64—0x0F00)
Section titled “BCM4500 and GPIF (0x0C64—0x0F00)”| Address | Name | Size | Role |
|---|---|---|---|
0x0C64 | BCM4500 firmware loader | 280 | I2C block transfer with address tracking |
0x0D7C | GPIF/slave FIFO config | 128 | Enable/disable streaming mode |
0x0F00 | I2C multi-byte read | 256 | Parameter setup for bus transfer |
DiSEqC Implementation (0x07D1, 0x1D5E—0x1E3D)
Section titled “DiSEqC Implementation (0x07D1, 0x1D5E—0x1E3D)”| Address | Name | Size | Role |
|---|---|---|---|
0x07D1 | DiSEqC byte transmit | 45 | 8 data bits + odd parity via P0.4 |
0x1D5E | DiSEqC message sender | 59 | Iterates bytes, calls bit-bang per byte |
0x1E3D | DiSEqC byte wrapper | 54 | Sets P0.2, adds inter-byte delay |
0x213C | DiSEqC bit symbol | 22 | Carrier on/off via P0.3, data via P0.4 |
0x20E2 | 22 kHz tone burst | 23 | P0.3 ON, 25 ticks, P0.3 OFF |
0x225F | Timer2 tick wait | 6 | TF2 poll and clear (500 us tick) |
LNB and GPIO Control (0x1F5C—0x2038)
Section titled “LNB and GPIO Control (0x1F5C—0x2038)”| Address | Name | Size | Role |
|---|---|---|---|
0x1F5C | LNB voltage I2C select | 41 | Probes I2C device 0x60 or address from 0xE0B6 |
0x1FCF | GPIO pin controller | 46 | Sets P0.6, P0.0, P3.4 based on parameter bits |
0x2038 | GPIO clock strobe | 51 | Calls pin controller 3 times (setup, clock, cleanup) |
0x21B1 | LNB voltage select | 17 | Sets/clears P0.4, updates config bit 5 |
0x21C2 | 22 kHz tone enable | 17 | Sets/clears P0.3, updates config bit 4 |
0x21D3 | DiSEqC port direction | 17 | Sets/clears P3.6, updates config bit 3 |
I2C Bus Management (0x19F4—0x1B90)
Section titled “I2C Bus Management (0x19F4—0x1B90)”Rev.2 decomposes I2C operations into particularly fine-grained functions:
| Address | Name | Size | Role |
|---|---|---|---|
0x19F4 | I2C bus controller | 92 | Manages SDA/SCL via XRAM 0xE678 |
0x1A50 | I2C address select + start | 83 | START condition generation |
0x1AA3 | I2C stop + cleanup | 82 | STOP condition and bus release |
0x1AF5 | I2C address write helper | 9 | Writes device address byte |
0x1B01 | I2C byte-level transfer | 67 | Single byte send/receive |
0x1B44 | I2C ACK/NAK handling | 76 | Acknowledge detection |
0x1B90 | I2C bus reset/recovery | 74 | Error recovery sequence |
0x1F06 | I2C completion wait | 43 | Polls XRAM 0xE678 bit 0 with 16-bit timeout |
0x1F85 | I2C completion wait (2-flag) | 37 | Polls bits 0 and 2 |
0x2000 | I2C busy wait | 30 | Polls XRAM 0xE678 bit 6 with timeout |
Rev.2-Specific Features
Section titled “Rev.2-Specific Features”GPIO Pin Controller (FUN_CODE_1fcf)
Section titled “GPIO Pin Controller (FUN_CODE_1fcf)”A unique function that provides parameterized GPIO control through a bit-field interface:
void gpio_pin_controller(BYTE param) { if (param & 0x02) P0 |= 0x01; // P0.0 else P0 &= ~0x01;
if (param & 0x04) P0 |= 0x40; // P0.6 else P0 &= ~0x40;
if (param & 0x08) P3 |= 0x10; // P3.4 else P3 &= ~0x10;}This function is called via FUN_CODE_2038 (GPIO clock strobe) which invokes it three times per cycle — setup, clock edge, and cleanup — suggesting it controls a clocked peripheral interface.
Descriptor Version Checker (FUN_CODE_1f31)
Section titled “Descriptor Version Checker (FUN_CODE_1f31)”Walks a USB descriptor chain checking whether descriptor_byte + 1 == 0x03, enabling hardware-revision-aware code paths. This mechanism appears in a simplified form in v2.13 as the _1_3 flag check.
Prototype Commands 0x99/0x9A
Section titled “Prototype Commands 0x99/0x9A”Commands 0x99 and 0x9A exist in Rev.2 as partial prototype implementations, before becoming fully functional in v2.13:
| Command | Rev.2 Behavior | v2.13 Behavior |
|---|---|---|
0x99 | Prototype — limited status read | Full GET_DEMOD_STATUS (reads BCM4500 reg 0xF9) |
0x9A | Prototype — basic init call | Full INIT_DEMOD (3-attempt re-init with flag check) |
Cross-Version Function Mapping
Section titled “Cross-Version Function Mapping”Key Rev.2 functions and their counterparts in other versions:
| Rev.2 Function | Role | v2.06 | v2.13 |
|---|---|---|---|
0x155F main | RESET entry, IRAM clear | 0x188D | 0x170D |
0x09A9 main init | Init + main loop | 0x09A7 | 0x0800 |
0x10D9 USB setup | Descriptor/peripheral init | 0x13C3 | 0x11AB |
0x0056 vendor dispatch | Vendor command dispatcher | 0x0056 | 0x0056 |
0x0C64 BCM4500 loader | Firmware block transfer | 0x0DDD | 0x0CA4 |
0x0D7C GPIF/FIFO | Streaming management | 0x1919 | 0x1800 |
0x1BDA delay | Clock-compensated delay | 0x1DFB | 0x14B9 |
GPIO Differences from SkyWalker-1
Section titled “GPIO Differences from SkyWalker-1”The Rev.2 board has a different GPIO assignment from the standard SkyWalker-1:
| Pin | Rev.2 v2.10 | v2.06 / v2.13 |
|---|---|---|
| P0.0 | LNB control (cmd 0x97) | DiSEqC data (v2.13) / unused (v2.06) |
| P0.4 | LNB voltage + DiSEqC data | LNB voltage only |
| P0.5 | GPIO status input (cmd 0x98) | BCM4500 RESET |
| P0.6 | GPIO control (cmd 0x97) | Unused |
| P0.7 | Streaming indicator | DiSEqC data (v2.06) / streaming (v2.13) |
The most significant difference is that Rev.2 multiplexes DiSEqC data onto the LNB voltage pin (P0.4), and the BCM4500 RESET function on P0.5 is replaced by a GPIO status input.
Main Loop Structure
Section titled “Main Loop Structure”The Rev.2 main loop follows the same pattern as other versions but with the event handling delegated to FUN_CODE_201e:
void main_loop(void) { // Process init table from CODE:0B48 // Call USB/peripheral setup // Enable interrupts
while (1) { if (sudav_flag) { handle_setupdata(); sudav_flag = 0; } FUN_CODE_201e(); // Delegated I2C config read/write if (gpif_flag) { handle_gpif_event(); gpif_flag = 0; } else { PCON |= 0x01; // CPU idle } }}