summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug')
-rw-r--r--src/emu/debug/debugcmd.cpp29
-rw-r--r--src/emu/debug/debugcmd.h1
-rw-r--r--src/emu/debug/debugcpu.cpp98
-rw-r--r--src/emu/debug/debughlp.cpp16
-rw-r--r--src/emu/debug/dvdisasm.cpp8
-rw-r--r--src/emu/debug/dvmemory.cpp57
-rw-r--r--src/emu/debug/dvmemory.h1
7 files changed, 121 insertions, 89 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index 38bff17b8c4..1b48be30e1f 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -206,6 +206,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("stateload", CMDFLAG_NONE, 0, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1, _2));
m_console.register_command("sl", CMDFLAG_NONE, 0, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1, _2));
+ m_console.register_command("rewind", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_commands::execute_rewind, this, _1, _2));
+ m_console.register_command("rw", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_commands::execute_rewind, this, _1, _2));
+
m_console.register_command("save", CMDFLAG_NONE, AS_PROGRAM, 3, 4, std::bind(&debugger_commands::execute_save, this, _1, _2));
m_console.register_command("saved", CMDFLAG_NONE, AS_DATA, 3, 4, std::bind(&debugger_commands::execute_save, this, _1, _2));
m_console.register_command("savei", CMDFLAG_NONE, AS_IO, 3, 4, std::bind(&debugger_commands::execute_save, this, _1, _2));
@@ -1627,7 +1630,7 @@ void debugger_commands::execute_stateload(int ref, const std::vector<std::string
const std::string &filename(params[0]);
m_machine.immediate_load(filename.c_str());
- // Clear all PC & memory tracks
+ // clear all PC & memory tracks
for (device_t &device : device_iterator(m_machine.root_device()))
{
device.debug()->track_pc_data_clear();
@@ -1638,6 +1641,30 @@ void debugger_commands::execute_stateload(int ref, const std::vector<std::string
/*-------------------------------------------------
+ execute_rewind - execute the rewind command
+-------------------------------------------------*/
+
+void debugger_commands::execute_rewind(int ref, const std::vector<std::string> &params)
+{
+ if (!m_machine.save().rewind()->enabled())
+ {
+ m_console.printf("Rewind not enabled\n");
+ return;
+ }
+
+ m_machine.rewind_step();
+
+ // clear all PC & memory tracks
+ for (device_t &device : device_iterator(m_machine.root_device()))
+ {
+ device.debug()->track_pc_data_clear();
+ device.debug()->track_mem_data_clear();
+ }
+ m_console.printf("Rewind step attempted. Please refer to window message popup for results.\n");
+}
+
+
+/*-------------------------------------------------
execute_save - execute the save command
-------------------------------------------------*/
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index 98b6d8ae03d..41405ec0a71 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -131,6 +131,7 @@ private:
void execute_hotspot(int ref, const std::vector<std::string> &params);
void execute_statesave(int ref, const std::vector<std::string> &params);
void execute_stateload(int ref, const std::vector<std::string> &params);
+ void execute_rewind(int ref, const std::vector<std::string> &params);
void execute_save(int ref, const std::vector<std::string> &params);
void execute_load(int ref, const std::vector<std::string> &params);
void execute_dump(int ref, const std::vector<std::string> &params);
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index eab6f7771e7..17c26191186 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -389,34 +389,20 @@ u8 debugger_cpu::read_byte(address_space &space, offs_t address, bool apply_tran
u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_translation)
{
+ device_memory_interface &memory = space.device().memory();
+
/* mask against the logical byte mask */
address &= space.logaddrmask();
u16 result;
- if (!WORD_ALIGNED(address))
- { /* if this is misaligned read, or if there are no word readers, just read two bytes */
- u8 byte0 = read_byte(space, address + 0, apply_translation);
- u8 byte1 = read_byte(space, address + 1, apply_translation);
-
- /* based on the endianness, the result is assembled differently */
- if (space.endianness() == ENDIANNESS_LITTLE)
- result = byte0 | (byte1 << 8);
- else
- result = byte1 | (byte0 << 8);
+ /* translate if necessary; if not mapped, return 0xffff */
+ if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
+ {
+ result = 0xffff;
}
else
- { /* otherwise, this proceeds like the byte case */
- device_memory_interface &memory = space.device().memory();
-
- /* translate if necessary; if not mapped, return 0xffff */
- if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
- {
- result = 0xffff;
- }
- else
- { /* otherwise, call the byte reading function for the translated address */
- result = space.read_word(address);
- }
+ { /* otherwise, call the byte reading function for the translated address */
+ result = space.read_word_unaligned(address);
}
return result;
@@ -430,33 +416,20 @@ u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_tra
u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_translation)
{
+ device_memory_interface &memory = space.device().memory();
+
/* mask against the logical byte mask */
address &= space.logaddrmask();
u32 result;
- if (!DWORD_ALIGNED(address))
- { /* if this is a misaligned read, or if there are no dword readers, just read two words */
- u16 word0 = read_word(space, address + 0, apply_translation);
- u16 word1 = read_word(space, address + 2, apply_translation);
- /* based on the endianness, the result is assembled differently */
- if (space.endianness() == ENDIANNESS_LITTLE)
- result = word0 | (word1 << 16);
- else
- result = word1 | (word0 << 16);
+ if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
+ { /* translate if necessary; if not mapped, return 0xffffffff */
+ result = 0xffffffff;
}
else
- { /* otherwise, this proceeds like the byte case */
- device_memory_interface &memory = space.device().memory();
-
- if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
- { /* translate if necessary; if not mapped, return 0xffffffff */
- result = 0xffffffff;
- }
- else
- { /* otherwise, call the byte reading function for the translated address */
- result = space.read_dword(address);
- }
+ { /* otherwise, call the byte reading function for the translated address */
+ result = space.read_dword_unaligned(address);
}
return result;
@@ -470,34 +443,21 @@ u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_tr
u64 debugger_cpu::read_qword(address_space &space, offs_t address, bool apply_translation)
{
+ device_memory_interface &memory = space.device().memory();
+
/* mask against the logical byte mask */
address &= space.logaddrmask();
u64 result;
- if (!QWORD_ALIGNED(address))
- { /* if this is a misaligned read, or if there are no qword readers, just read two dwords */
- u32 dword0 = read_dword(space, address + 0, apply_translation);
- u32 dword1 = read_dword(space, address + 4, apply_translation);
- /* based on the endianness, the result is assembled differently */
- if (space.endianness() == ENDIANNESS_LITTLE)
- result = dword0 | (u64(dword1) << 32);
- else
- result = dword1 | (u64(dword0) << 32);
+ /* translate if necessary; if not mapped, return 0xffffffffffffffff */
+ if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
+ {
+ result = ~u64(0);
}
else
- { /* otherwise, this proceeds like the byte case */
- device_memory_interface &memory = space.device().memory();
-
- /* translate if necessary; if not mapped, return 0xffffffffffffffff */
- if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
- {
- result = ~u64(0);
- }
- else
- { /* otherwise, call the byte reading function for the translated address */
- result = space.read_qword(address);
- }
+ { /* otherwise, call the byte reading function for the translated address */
+ result = space.read_qword_unaligned(address);
}
return result;
@@ -1902,6 +1862,7 @@ void device_debug::single_step(int numsteps)
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_capture();
m_stepsleft = numsteps;
m_stepaddr = ~0;
m_flags |= DEBUG_FLAG_STEPPING;
@@ -1918,6 +1879,7 @@ void device_debug::single_step_over(int numsteps)
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_capture();
m_stepsleft = numsteps;
m_stepaddr = ~0;
m_flags |= DEBUG_FLAG_STEPPING_OVER;
@@ -1934,6 +1896,7 @@ void device_debug::single_step_out()
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_capture();
m_stepsleft = 100;
m_stepaddr = ~0;
m_flags |= DEBUG_FLAG_STEPPING_OUT;
@@ -1950,6 +1913,7 @@ void device_debug::go(offs_t targetpc)
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
m_stopaddr = targetpc;
m_flags |= DEBUG_FLAG_STOP_PC;
m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING);
@@ -1964,6 +1928,7 @@ void device_debug::go_vblank()
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
m_flags |= DEBUG_FLAG_STOP_VBLANK;
m_device.machine().debugger().cpu().go_vblank();
}
@@ -1978,6 +1943,7 @@ void device_debug::go_interrupt(int irqline)
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
m_stopirq = irqline;
m_flags |= DEBUG_FLAG_STOP_INTERRUPT;
m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING);
@@ -1997,6 +1963,7 @@ void device_debug::go_exception(int exception)
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
m_stopexception = exception;
m_flags |= DEBUG_FLAG_STOP_EXCEPTION;
m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING);
@@ -2012,6 +1979,7 @@ void device_debug::go_milliseconds(u64 milliseconds)
{
assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
m_stoptime = m_device.machine().time() + attotime::from_msec(milliseconds);
m_flags |= DEBUG_FLAG_STOP_TIME;
m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING);
@@ -2822,14 +2790,14 @@ void debugger_cpu::watchpoint_check(address_space& space, int type, offs_t addre
if (type & WATCHPOINT_WRITE)
{
- buffer = string_format("Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->index(), sizes[size], space.byte_to_address(address), pc);
+ buffer = string_format("Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->index(), sizes[size], address, pc);
if (value_to_write >> 32)
buffer.append(string_format(" (data=%X%08X)", u32(value_to_write >> 32), u32(value_to_write)));
else
buffer.append(string_format(" (data=%X)", u32(value_to_write)));
}
else
- buffer = string_format("Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index(), sizes[size], space.byte_to_address(address), pc);
+ buffer = string_format("Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index(), sizes[size], address, pc);
m_machine.debugger().console().printf("%s\n", buffer.c_str());
space.device().debug()->compute_debug_flags();
}
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index 2848f970003..f25d52b3ae7 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -94,6 +94,7 @@ static const help_item static_help_list[] =
" pcatmemd <address>[,<cpu>] -- query which PC wrote to a given data memory address for the current CPU\n"
" pcatmemi <address>[,<cpu>] -- query which PC wrote to a given I/O memory address for the current CPU\n"
" (Note: you can also query this info by right clicking in a memory window\n"
+ " rewind[rw] -- go back in time by loading the most recent rewind state"
" statesave[ss] <filename> -- save a state file for the current driver\n"
" stateload[sl] <filename> -- load a state file for the current driver\n"
" snap [<filename>] -- save a screen snapshot.\n"
@@ -455,6 +456,19 @@ static const help_item static_help_list[] =
" Print which PC wrote this CPU's memory location 0x400000.\n"
},
{
+ "rewind[rw]",
+ "\n"
+ " rewind[rw]"
+ "\n"
+ "The rewind command loads the most recent RAM-based state. Rewind states, when enabled, are "
+ "saved when \"step\", \"over\", or \"out\" command gets executed, storing the machine state as "
+ "of the moment before actually stepping. Consecutively loading rewind states can work like "
+ "reverse execution. Depending on which steps forward were taken previously, the bahavior can "
+ "be similar to GDB's \"reverse-stepi\" or \"reverse-next\". All output for this command is "
+ "currently echoed into the running machine window. Previous memory and PC tracking statistics "
+ "are cleared, actual reverse execution does not occur.\n"
+ },
+ {
"statesave[ss]",
"\n"
" statesave[ss] <filename>\n"
@@ -472,7 +486,7 @@ static const help_item static_help_list[] =
{
"stateload[sl]",
"\n"
- " stateload[ss] <filename>\n"
+ " stateload[sl] <filename>\n"
"\n"
"The stateload command retrieves a save state from disk. "
"The given state file gets read from the standard state directory (sta), and gets .sta to it - "
diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp
index 2292e766132..8084251c7b1 100644
--- a/src/emu/debug/dvdisasm.cpp
+++ b/src/emu/debug/dvdisasm.cpp
@@ -321,7 +321,7 @@ void debug_view_disasm::generate_dasm(debug_disasm_buffer &buffer, offs_t pc)
if(pos != -1) {
if(!pc_changed)
return;
- if(pos >= m_topleft.y && pos < m_topleft.y + m_visible.y)
+ if(pos >= m_topleft.y && pos < m_topleft.y + m_visible.y - 2)
return;
if(pos < m_total.y - m_visible.y) {
m_topleft.x = 0;
@@ -566,6 +566,8 @@ void debug_view_disasm::set_selected_address(offs_t address)
void debug_view_disasm::set_source(const debug_view_source &source)
{
- debug_view::set_source(source);
- m_dasm.clear();
+ if(&source != m_source) {
+ debug_view::set_source(source);
+ m_dasm.clear();
+ }
}
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index e32d576fa65..13297dbe7b9 100644
--- a/src/emu/debug/dvmemory.cpp
+++ b/src/emu/debug/dvmemory.cpp
@@ -98,6 +98,7 @@ debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_up
m_expression(machine),
m_chunks_per_row(16),
m_bytes_per_chunk(1),
+ m_steps_per_chunk(1),
m_data_format(1),
m_reverse_view(false),
m_ascii_view(true),
@@ -197,6 +198,7 @@ void debug_view_memory::view_notify(debug_view_notification type)
if (m_bytes_per_chunk > 8)
m_bytes_per_chunk = 8;
m_data_format = m_bytes_per_chunk;
+ m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk;
if (source.m_space != nullptr)
m_expression.set_context(&source.m_space->device().debug()->symtable());
else
@@ -290,7 +292,8 @@ void debug_view_memory::view_update()
if (dest >= destmin && dest < destmax)
dest->byte = addrtext[ch];
- // generate the data
+ // generate the data and the ascii string
+ std::string chunkascii;
for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++)
{
int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum;
@@ -298,7 +301,7 @@ void debug_view_memory::view_update()
if (m_data_format <= 8) {
u64 chunkdata;
- bool ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata);
+ bool ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata);
dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing;
for (int ch = 0; ch < posdata.m_spacing; ch++, dest++)
if (dest >= destmin && dest < destmax)
@@ -307,6 +310,10 @@ void debug_view_memory::view_update()
if (shift < 64)
dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*';
}
+ for (int i=0; i < m_bytes_per_chunk; i++) {
+ u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1));
+ chunkascii += char((ismapped && isprint(chval)) ? chval : '.');
+ }
}
else {
int ch;
@@ -316,9 +323,9 @@ void debug_view_memory::view_update()
bool ismapped;
if (m_data_format != 11)
- ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata);
+ ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata);
else
- ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata80);
+ ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80);
if (ismapped)
switch (m_data_format)
@@ -338,6 +345,7 @@ void debug_view_memory::view_update()
valuetext[0] = '*';
valuetext[1] = 0;
}
+
dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing;
// first copy the text
for (ch = 0; (ch < spacing) && (valuetext[ch] != 0); ch++, dest++)
@@ -347,20 +355,23 @@ void debug_view_memory::view_update()
for (; ch < spacing; ch++, dest++)
if (dest >= destmin && dest < destmax)
dest->byte = ' ';
+
+ for (int i=0; i < m_bytes_per_chunk; i++) {
+ u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1));
+ chunkascii += char((ismapped && isprint(chval)) ? chval : '.');
+ }
}
}
- // generate the ASCII data
+ // generate the ASCII data, but follow the chunks
if (m_section[2].m_width > 0)
{
dest = destrow + m_section[2].m_pos + 1;
- for (int ch = 0; ch < m_bytes_per_row; ch++, dest++)
+ for (size_t i = 0; i != chunkascii.size(); i++) {
if (dest >= destmin && dest < destmax)
- {
- u64 chval;
- bool ismapped = read(1, addrbyte + ch, chval);
- dest->byte = (ismapped && isprint(chval)) ? chval : '.';
- }
+ dest->byte = chunkascii[i];
+ dest++;
+ }
}
}
}
@@ -563,7 +574,10 @@ void debug_view_memory::recompute()
// recompute the byte offset based on the most recent expression result
m_bytes_per_row = m_bytes_per_chunk * m_chunks_per_row;
- m_byte_offset = m_expression.value() % m_bytes_per_row;
+ offs_t val = m_expression.value();
+ if (source.m_space)
+ val = source.m_space->address_to_byte(val);
+ m_byte_offset = val % m_bytes_per_row;
// compute the section widths
m_section[0].m_width = 1 + 8 + 1;
@@ -612,17 +626,20 @@ bool debug_view_memory::needs_recompute()
// handle expression changes
if (m_expression.dirty())
{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+ offs_t val = m_expression.value();
+ if (source.m_space)
+ val = source.m_space->address_to_byte(val);
recompute = true;
- m_topleft.y = (m_expression.value() - m_byte_offset) / m_bytes_per_row;
+ m_topleft.y = (val - m_byte_offset) / m_bytes_per_row;
m_topleft.y = std::max(m_topleft.y, 0);
m_topleft.y = std::min(m_topleft.y, m_total.y - 1);
- const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
offs_t resultbyte;
if (source.m_space != nullptr)
- resultbyte = m_expression.value() & source.m_space->logaddrmask();
+ resultbyte = val & source.m_space->logaddrmask();
else
- resultbyte = m_expression.value();
+ resultbyte = val;
set_cursor_pos(cursor_pos(resultbyte, m_bytes_per_chunk * 8 - 4));
}
@@ -740,7 +757,7 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data)
const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
// if no raw data, just use the standard debug routines
- if (source.m_space != nullptr)
+ if (source.m_space)
{
auto dis = machine().disable_side_effect();
@@ -823,7 +840,7 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data)
const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
// if no raw data, just use the standard debug routines
- if (source.m_space != nullptr)
+ if (source.m_space)
{
auto dis = machine().disable_side_effect();
@@ -919,13 +936,14 @@ void debug_view_memory::set_data_format(int format)
return;
pos = begin_update_and_get_cursor_pos();
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
if ((format <= 8) && (m_data_format <= 8)) {
- const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
pos.m_address += (pos.m_shift / 8) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1));
pos.m_shift %= 8;
m_bytes_per_chunk = format;
+ m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk;
m_chunks_per_row = m_bytes_per_row / format;
if (m_chunks_per_row < 1)
m_chunks_per_row = 1;
@@ -958,6 +976,7 @@ void debug_view_memory::set_data_format(int format)
}
}
m_chunks_per_row = m_bytes_per_row / m_bytes_per_chunk;
+ m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk;
pos.m_shift = 0;
pos.m_address -= pos.m_address % m_bytes_per_chunk;
}
diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h
index 1927e030d2b..c354b644053 100644
--- a/src/emu/debug/dvmemory.h
+++ b/src/emu/debug/dvmemory.h
@@ -107,6 +107,7 @@ private:
debug_view_expression m_expression; // expression describing the start address
u32 m_chunks_per_row; // number of chunks displayed per line
u8 m_bytes_per_chunk; // bytes per chunk
+ u8 m_steps_per_chunk; // bytes per chunk
int m_data_format; // 1-8 current values 9 32bit floating point
bool m_reverse_view; // reverse-endian view?
bool m_ascii_view; // display ASCII characters?