Skip to main content

mp.memory — 60 functions

Address-aware helpers (*_at) take absolute MCU addresses; the buffer offset is computed automatically: buffer_offset = addr - region.start_address.

-- Flash region starts at 0x4000. Read 4 bytes at MCU address 0xF650:
local bytes = mp.memory.read_at("Flash", 0xF650, 4)
-- internally reads buffer offset: 0xF650 - 0x4000 = 0xB650

Region navigation

FunctionReturnsDescription
get_regions()tableArray of region names
current_region()stringName of active region
region_count()intNumber of regions
select_region(idx)voidSwitch region by 0-based index
select_region_by_name(n)boolSwitch region by name
get_region_info([r])table{index, name, size, start_address, end_address, cell_size}r is name (string), 0-based index, or omitted (active)
region_size(r)intRegion size in bytes — r is name or 0-based index

Writability

Tabs open in read-only by default, just like the GUI. Writes silently return false until you enable writability.

FunctionReturnsDescription
set_writable(r, b)ok, errr is name (string) or 0-based index (int); b is bool. Bare set_writable(b) (single bool) toggles all tabs. A bare integer set_writable(0) returns (false, "...")
set_writable_all(b)ok, errApply to all regions
is_writable([r])boolr is name, 0-based index, or omitted (active region)

Reads — offset-based

FunctionReturnsDescription
read_byte(r, off)intSingle byte (-1 if out of range)
read_range(r, start, len)tableByte array
read_bytes(r, off, n)tableByte array (alias-class with read_range)
read_hex(r, off, n)stringHex string e.g. "deadbeef"
read_string(r, off, maxLen)stringRaw string (may include non-printable)
read_string_until_null(r, off, maxLen?)stringRead up to first NUL byte (max 256 by default)
get_region_data(r)tableEntire region as byte array
get_all_data()tableAll regions concatenated as byte array

Reads — address-based

FunctionReturnsDescription
read_at(r, addr, n)tableByte array starting at MCU address
read_byte_at(r, addr)intSingle byte at MCU address
read_string_at(r, addr, maxLen)stringRaw string at MCU address
read_string_until_null_at(r, addr, maxLen?)stringRead up to first NUL at absolute address (max 256)

Writes — offset-based

FunctionReturnsDescription
write_byte(r, off, v)boolSingle byte
write_range(r, off, bytes)boolByte array
write_hex(r, off, hexStr)boolBytes from hex string
write_string(r, off, text)boolRaw string
fill(r, off, len, v)boolFill with constant byte
fill_pattern(r, off, len, pattern)boolFill with repeating byte pattern

Writes — address-based

FunctionReturnsDescription
write_at(r, addr, bytes)boolByte array at MCU address
write_byte_at(r, addr, v)boolSingle byte at MCU address
write_string_at(r, addr, text)boolRaw string at MCU address
FunctionReturnsDescription
find(r, hex, startOff?)intFirst match offset, or -1
find_prev(r, hex, startOff?)intLast match before start, or -1
find_all(r, hex) / find_all(r, byte_table)tableArray of offsets within the region. For ASCII needles use the byte-table form or find_string
find_string(r, text, startOff?)intFirst ASCII match offset, or -1
search_all(hex) / search_all(region, hex)table{region, offset, address, offset_hex, address_hex} per hit. No-region form scans every region
search_string_all(text) / search_string_all(region, text)tableSame plus context_hex (matched bytes + 16 trailing)
search_patterns(patterns)tableBatch: {label, hits[], count}

Selection & cursor

FunctionReturnsDescription
set_selection(r, off, len)voidHighlight bytes
get_selection(r)table{start, end, length, hex} or empty
go_to(r, off)ok, errMove cursor to offset
cursor_offset(r)intCurrent cursor offset

Undo / redo

FunctionReturnsDescription
undo(r)voidUndo last edit
redo(r)voidRedo
can_undo(r)bool
can_redo(r)bool

Bookmarks

FunctionReturnsDescription
add_bookmark(r, off, comment) / add_bookmark(off, comment)ok, errAdd a bookmark
get_bookmarks(r) / get_bookmarks() / list_bookmarks(...)tableArray of {offset, comment}
clear_bookmarks(r)voidRemove all

Address conversion

FunctionReturnsDescription
addr_to_offset(r, addr)intMCU address → buffer offset (-1 if below base)
offset_to_addr(r, off)intBuffer offset → MCU address

Buffer & export

FunctionReturnsDescription
clear()voidClear all buffers (via backend)
load_file() / show_load_dialog()voidOpen Import file dialog
load_file(path)ok, errParse file, populate matching regions by address
save_file() / show_save_dialog()voidOpen Export file dialog
save_file(path)ok, errWrite all regions to <path> (format from extension)
export_region(r, path[, off, len])stringError or empty. Optional off, len carve a buffer-byte slice; output's first record uses start_address + off
export_all(path)stringExport all regions to single file
compare(r1, r2)table{diffs[], diff_count, size1, size2, equal}

Region-name and cell_size pitfalls

Three things that catch every new script author:

1. Region names are not "Flash" everywhere

Each backend uses its own names — P_Flash, D_Flash, RAM_P (DSC), Code Flash, EEPROM, User Boot, etc. Don't hardcode. Enumerate first:

for i, name in ipairs(mp.memory.get_regions()) do
mp.log.info(i .. ": " .. name)
end

A wrong name makes read_byte / go_to / cursor_offset silently return 0 / false / -1. The backend logs a [QT-WARN] listing the names it actually has — check the log when something "always returns 0".

2. Buffer initial content depends on the backend

Most backends pre-fill each region with 0xFF at full size on set_target, so region_size may already return the real flash size and read_byte returns 0xFF — that's NOT the chip's content, it's a dummy erased-flash fill. Always call mp.backend.read() (or mp.file.load(path)) before assuming mp.memory.read_* reflects what's on the chip.

3. Word-addressed targets — DSC, dsPIC and friends

Freescale / NXP DSC (MC56F8xxx) is word-addressed: one device address points to a 16-bit cell, but the buffer holds raw bytes, so region.size is 2× the addressable word count and cell_size = 2.

Check cell_size and convert when crossing the address ↔ buffer-offset boundary:

local info = mp.memory.get_region_info() -- e.g. P_Flash on MC56F8006
-- info.start_address = 0x800, size = 12288 (bytes), cell_size = 2
-- → 6144 device words from word-address 0x800 to 0x37FF

-- byte_offset (Lua API) = (device_address - start_address) * cell_size
local addr = 0x900
local byte_offset = (addr - info.start_address) * info.cell_size -- 0x200
local lo = mp.memory.read_byte(info.name, byte_offset)
local hi = mp.memory.read_byte(info.name, byte_offset + 1)
local word = lo | (hi << 8)

The _at helpers (read_at, read_byte_at, write_at, write_byte_at, addr_to_offset, offset_to_addr) do NOT multiply by cell_size — they treat address - start_address as a byte offset into the buffer. On cell_size == 1 that's identity; on DSC you must pre-multiply by cell_size yourself, or work in byte offsets directly with read_range / read_byte.

mp.memory.go_to(region, off) and cursor_offset(region) operate on buffer bytes, not device words — multiply your address by cell_size if it came from a datasheet or HEX file.