Appendix J.5 - SRM-D Full Cycle Execution

<< Click to Display Table of Contents >>

Navigation:  ASA-EMulatR Reference Guide > Introduction > Appendix > Appendix J - SRM Firmware Topic Hive >

Appendix J.5 - SRM-D Full Cycle Execution

This section covers the complete boot cycle from firmware image selection through the start of the main emulation run-loop pump. The scope is limited to the loading and pump-start sequence -- ongoing SRM console execution and PAL dispatch are covered in Appendix J.4.

 


 

J.5.1 Boot Cycle Overview

 

PHASE 13 -- ROM Selection:

 m_srmRomLoader.loadFromFile(srmRomFile)

 -> findDecompressor() scans first 4KB for 12-byte signature

 -> Signature at offset 0x0 (ES40/ES45/DS10/DS20/GS320)

 -> OR at offset 0x240 (cl67srmrom.exe, clsrmrom.exe)

 -> m_payloadData, m_payloadSize, m_headerSkip set

 -> isLoaded() == true

 

PHASE 14 -- Firmware Load (bifurcated):

 

 [FAST PATH -- snapshot exists and validates]

 loadSnapshot(path, writeToPhysical, setPC, setPalBase,

 setIntRegs, setFpRegs, setIPRs)

 -> Validate magic, version, romHash, buildId, checksum

 -> Write regionCount memory regions to guest physical RAM

 -> Restore R0-R31, F0-F31, all IPRs

 -> setPC(finalPC) finalPC = 0x5C0

 -> setPalBase(finalPalBase) palBase = 0x900000

 -> result.fromSnapshot = true

 -> Elapsed: < 500 ms (dominated by memory write throughput)

 

 [SLOW PATH -- first run or stale snapshot]

 decompress(cfg, writeToPhysical, singleStep,

 setPC, setPalBase, getPalBase, progress)

 -> writeToPhysical(0x0, payload, size) mirror write

 -> writeToPhysical(0x900000, payload, size) decompressor home

 -> setPC(0x900001)

 -> setPalBase(0x900000)

 -> Single-step loop: 5,767,331 iterations

 Phase 1: Init (158 steps, ~31 ms)

 Phase 2: Copy loop (524,288 iterations, ~16 min debug)

 Phase 3: Decompressor (variable steps, ~3 min debug)

 -> PC drops below 0x200000 -> goto done:

 -> result.finalPC = 0x5C0, result.success = true

 -> saveSnapshot(path, result, regions,

 readFromPhysical, getIntRegs, getFpRegs, getIPRs)

 

PHASE 15 -- CPU State Validation:

 ASSERT result.success == true

 ASSERT result.cleanPC() == 0x5C0

 ASSERT result.finalPalBase == 0x900000

 Log "[Phase 15] SRM firmware resident -- boot PC=0x5C0"

 

PHASE 16 -- Pipeline Initialization:

 AlphaPipeline::reset()

 AlphaPipeline::setPC(result.bootPC())

 AlphaPipeline::setPalBase(result.finalPalBase)

 Decode cache warm (PA cache pre-populated from decompressor run)

 

PHASE 17 -- Run-Loop Pump Start:

 m_runLoopTimer->start(0) Qt zero-interval timer

 -> QCoreApplication::exec() enters event loop

 -> Timer fires: AlphaPipeline::tick() each event loop iteration

 -> Pipeline executes SRM firmware from PC=0x5C0

 -> Console firmware initialization begins

 

J.5.2 Run-Loop Pump

 

The run-loop pump is a zero-interval QTimer driving AlphaPipeline::tick() from the Qt event loop. A zero-interval timer fires as fast as the event loop allows, yielding to the OS scheduler between ticks so Qt events (UI updates, input, signals) are processed while executing pipeline cycles at the maximum rate the host allows.

 

Why a timer rather than a dedicated thread? The single-threaded event-driven model avoids mutex contention on pipeline state from the main thread, simplifies debugger integration (breakpoints and single-step are just timer suspension), and allows the emulator UI to remain responsive. A dedicated execution thread would require locking on every UI interaction with pipeline state. The event loop model trades raw throughput for maintainability and debuggability during the current development phase.

 

Execution rate. Debug build with full CpuTrace I/O: approximately 5,772 instructions per second. Release build without trace: several hundred thousand instructions per second. The snapshot eliminates the 16-minute initialization penalty entirely in both configurations -- the slow path runs exactly once per ROM revision per emulator build.

 

J.5.3 PC at Run-Loop Start

 

The pipeline is primed with bootPC() = 0x5C0 before the run-loop pump starts. This is the entry point of the decompressed SRM firmware at PA 0x0. The PAL mode bit is clear (0x5C0 & 1 == 0) -- the firmware enters in normal mode. The first instruction executed is at guest physical address 0x5C0.

 

PAL_BASE is set to 0x900000 -- the decompressor image home. Until the decompressed SRM firmware performs its own PAL_BASE relocation (part of the SRM console initialization sequence), PAL calls dispatch into the code at 0x900000.

 

J.5.4 Snapshot Load Timing (Fast Path)

 

On the snapshot fast path, the entire Phase 14 load sequence -- writing 6.7 MB of memory regions, restoring 32 integer registers, 32 FP registers, and all IPRs, and validating the footer checksum -- completes in under 500 milliseconds on typical SSD storage. The dominant cost is sequential physical memory write throughput, not the checksum validation or register restore.

 

Path

Phase 14 Time (debug)

Phase 14 Time (release)

Slow (decompress)

~16 minutes 39 seconds

~10 seconds (estimated)

Fast (snapshot)

< 500 ms

< 200 ms

 

The snapshot is a one-time investment. After the first successful decompression run, every subsequent boot -- including debug builds with full trace I/O -- pays only the fast path cost.

 

See Also: J.2 - SRM-D Configuration and Initialization; J.3 - SRM-D Snapshot Mechanics; J.4 - SRM Firmware Initialization and PAL Exception Dispatch; Appendix G - Instruction Grain Mechanics .h; memoryLib/SrmRomLoader.cpp;coreLib/cpuTrace.h (hh:mm:ss.mmm elapsed time);Chapter 13 -- AlphaPipeline Implementation (run-loop pump and pipeline tick);grainFactoryLib/GrainResolver.h (decode cache warm after decompressor run).