Files
hmmmm/flatbuffers/config/mem_config.fbs
root 589bc8d620 feat: migrate config management from TOML to FlatBuffers
Config is now loaded at runtime via WebSocket (ConfigCtrlMessage)
instead of from hardcoded TOML files. The emulator starts with no
devices and waits for clients to send configuration.

- Define FlatBuffers schemas: EmulationConfig, ComposeDeviceConfig,
  BaseDeviceConfig with recursive DeviceConfig union
- Rename MemSegment.start → addr (flatcc builder/reader name collision)
- Add ConfigCtrlMessage handler: validates STILL state, walks the
  device tree depth-first, assigns numeric IDs, responds with
  DeviceIdMappingNotif or ConfigLoadError
- Add fb_build_config_device_id_mapping() and fb_build_config_error()
  FlatBuffer builders
- Remove hardcoded device loading from main.c; iterate dynamically
  loaded devices in the exec loop
- Fix double-free: freeConf() already frees the struct itself, remove
  redundant free() calls in config.c and base_device.c
- Fix heap-buffer-overflow in device parseSpecsFromConfig: malloc
  for segment name was missing +1 for the null terminator

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 14:02:41 +00:00

74 lines
2.8 KiB
Plaintext

namespace hmmmm.config;
// Named offset within a segment — symbolic variable for protocol/tool use
// (e.g. PIN=0, PORT=1, DDR=2 in a GPIO device).
table NamedOffset {
name: string;
offset: uint32;
}
// A contiguous memory segment within a base device.
table MemSegment {
name: string;
addr: uint32; // base address in device flat address space
len: uint32;
word_len: uint8 = 1; // word size in bytes
executable: bool = false;
variables: [NamedOffset]; // optional symbolic offsets within segment
}
// ── Projections ──────────────────────────────────────────────────────────────
// Maps a segment from one device into the flat address space of another.
// After projection, accesses to [base_seg + shift .. shift+len) in base_at
// are transparently forwarded to target_at:target_seg.
table Projection {
base_at: string; // device where the projection appears
base_seg: string; // segment in that device that is the projection window
target_at: string; // device owning the real data
target_seg: string;
shift: uint32 = 0; // offset from base_seg start
}
// ── Intercepts ───────────────────────────────────────────────────────────────
enum InterceptOp: byte {
op_read = 0,
op_write = 1,
op_both = 2,
}
enum InterceptMode: byte {
shadow_copy = 1, // duplicate write to point_at:point_addr as well
shadow_replace = 2, // redirect access to point_at:point_addr instead
callback = 3, // invoke a handler registered by point_at device
}
table Intercept {
name: string;
op: InterceptOp = op_both;
mode: InterceptMode = callback;
base_at: string; // device where the triggering access occurs
base_seg: string;
base_addr: uint32;
point_at: string; // device that handles/receives the intercept
point_seg: string;
point_addr: uint32;
}
// ── Memory initialisation ─────────────────────────────────────────────────────
enum OverflowBehaviour: byte {
overflow_error = 0, // abort if file is larger than segment
overflow_ignore = 1, // stop reading at segment end, no error
overflow_wrap = 2, // wrap around and continue writing from segment start
}
// Load initial segment contents from a file (e.g. firmware binary, /dev/urandom).
table MemSetup {
device: string;
segment: string;
filepath: string;
overflow: OverflowBehaviour = overflow_error;
}