Parser

Struct Parser 

Source
pub struct Parser<'a, R: Reader> { /* private fields */ }
Expand description

Parser for Software Defined Retro ROM (SDRR) firmware images.

This parser extracts configuration and ROM data from SDRR firmware files, which are used in devices that emulate vintage ROM chips (2316/2332/2364). The parser is designed to work efficiently in both PC and embedded environments.

§Architecture

The parser uses a two-phase approach:

  1. Metadata parsing - Headers, pin configurations, and ROM set information are parsed immediately into memory (typically just a few KB)
  2. ROM data access - ROM images (up to 64KB each) remain in the source and are accessed lazily through reader callbacks

This design allows embedded devices with limited RAM to parse and work with SDRR firmware without loading entire ROM images into memory.

§Usage

// Create a reader for your data source
let reader = MyReader::new("firmware.bin")?;

// Create parser and parse metadata
let mut parser = Parser::new(reader);
let info = parser.parse()?;

// Access ROM data lazily
let byte = parser.read_rom_byte(&info, 0, 0x1000, true, None, None)?;

§Firmware Structure

SDRR firmware contains:

  • A header with “SDRR” magic bytes at offset 0x200 from base
  • Version information and build metadata
  • Pin mapping configuration for the STM32F4 microcontroller
  • One or more ROM sets, each containing up to 3 ROM images
  • ROM data that has been pre-processed for efficient serving

§Address Translation

ROM addresses and data bytes are “mangled” in the firmware for efficient real-time serving. The parser handles the translation between logical addresses/data and their physical representation in the firmware.

Implementations§

Source§

impl<'a, R: Reader> Parser<'a, R>

Source

pub fn new(reader: &'a mut R) -> Self

Create a new parser with the default STM32F4 base address (0x08000000).

§Arguments
  • reader - Implementation of Reader trait that provides access to firmware bytes
§Example
let reader = MyReader::new();
let mut parser = Parser::new(reader);
Source

pub fn with_base_flash_address( reader: &'a mut R, base_flash_address: u32, base_ram_address: u32, ) -> Self

Create a new parser with a custom base address.

Use this when parsing firmware for devices with non-standard memory maps or when analyzing relocated firmware images.

§Arguments
  • reader - Implementation of Reader trait that provides access to firmware bytes
  • base_flash_address - Base address where flash memory begins (e.g., 0x08000000 for STM32F4)
  • base_ram_address - Base address where RAM begins (e.g., 0x20000000 for STM32F4)
Source

pub async fn detect(&mut self) -> bool

Function to do a brief check whether this is an SDRR device.

Returns:

  • true if the SDRR header was found and is valid
  • false if the header was not found (or an error occured)
Source

pub async fn parse(&mut self) -> Sdrr

Parses both flash and RAM

Source

pub async fn parse_flash(&mut self) -> Result<SdrrInfo, String>

Parse SDRR metadata from the firmware.

This method reads and parses all structural information from the firmware, including headers, version info, pin configurations, and ROM set descriptors. ROM image data is NOT loaded - only pointers to where it exists in the firmware.

§What gets parsed
  • SDRR header with version and build information
  • Pin mapping configuration for STM32F4 GPIO
  • ROM set headers with serving algorithms
  • ROM information (type, CS line configuration)
  • String data (build date, hardware revision, ROM filenames)
§Error handling

The parser attempts to continue parsing even when encountering errors in non-critical sections. Failed sections are recorded in SdrrInfo::parse_errors while their fields are set to None.

§Returns

Returns Ok(SdrrInfo) if the header was found and core fields parsed successfully. Returns Err if:

  • SDRR magic bytes not found at expected location
  • Version is newer than this parser supports
  • Critical header fields are corrupted
§Example
let mut parser = Parser::new(reader);
match parser.parse_flash() {
    Ok(info) => {
        println!("Parsed SDRR v{}.{}.{}",
                 info.major_version,
                 info.minor_version,
                 info.patch_version);
        if !info.parse_errors.is_empty() {
            println!("Encountered {} non-fatal errors", info.parse_errors.len());
        }
    }
    Err(e) => eprintln!("Failed to parse: {}", e),
}
Source

pub async fn parse_ram(&mut self) -> Result<SdrrRuntimeInfo, String>

Auto Trait Implementations§

§

impl<'a, R> Freeze for Parser<'a, R>

§

impl<'a, R> RefUnwindSafe for Parser<'a, R>
where R: RefUnwindSafe,

§

impl<'a, R> Send for Parser<'a, R>
where R: Send,

§

impl<'a, R> Sync for Parser<'a, R>
where R: Sync,

§

impl<'a, R> Unpin for Parser<'a, R>

§

impl<'a, R> !UnwindSafe for Parser<'a, R>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.