summaryrefslogblamecommitdiffstatshomepage
path: root/src/emu/debug/dvmemory.cpp
blob: 293d1082fc02a439ad9e32a96e43d664c2ee3955 (plain) (tree)
1
2
3
4
5
6
7
8

                                





                                                                      


                                                                            
                     
 
                     
                     
 
                    
                  
                





                                                                            
                                                                                    








                                                                                                                                            



                                                                                                                                                                                                                    











                                                                            
                                                                                          
                                                   

                                                                                    
                                



                                                  


 
                                                                                           
                                  

                                   
                                      
                                         
                                                                                                 
                                                  
                                                               




                                                                                                                    

                                   



                                                      
                                                     














                                                                                                                      


                                      
                                     
                                 


                                        
                                     


                                    
 






                                                                       










                                                   
                                              






                                                   
                         

                                                    
                                                                                                   
                                                                                        





                                                                                                                                               

                                          
                                                         
         

                                                                                                                  

         
                                                                     

                                                                          

                                                                                         
         
                                      
                           

                                                                                                         



                                                                                                                      

         
                                                                                                                                     
 
                                          
                                                                                                                                                                  

                                                 
                                           



                                                   
                                                







                                                                 
                                                         






                                                                                                               


                                                  
                                                                                                                            
                                              
                                                                                                
                    
                                                          




                                                   
                                                 


                                                   
                                           


                        
                      






                                                   
                                                  


                                                   
                                            


                         
                      






                                                   












                                                                                                       
                                                                           

                                 
                                                   
         
                                                                          

                                                                 
                                               




                                                                                                        
                                                      













                                                                                                     
                                                                                                                            


                                               
                                                                         




                                                                                                          

                                                                 


                                                                                                               
                                                                
 
                                                         
                                                      
                                                                                                 



                                                                                                       
                                                                                       


                                                                                                                                              



                                                                                                               


                                               
                                                           
                                                          
                                                                            
                                                      
 
                                                                
                                                                                                                                      
                                            
                                                                                                                                        
 
                                                     


                                                                      
                                                                                                                 

                                                              
                                                                                                              

                                                              

                                                                                                          

                                                              


                                                                   
                                         
 
                                                                                                       
                                                              
                                                                                                          


                                                                                      
                                                                          

                                                                                      




                                                                                                               
                                 

                         
                                                                         


                                                                        
                                                                                 
                                                                              


                                                                           






                                                   
                                               





                                                   
                                                  
 



                                                                      













                                                                             
                                                                                                                  







                                                                           
                                                                                                                  








































                                                                                                   
                                               

                                      

                                                                                                                                      
                                 
                                                                               


                                      

                                                                      
                                                                
                                                                































                                                                                                       










                                                                              
                                                                     













                                                   
                                               







                                                                                                       
                                                  


                                                                                           
                    
                                      
         
                                                                                                          
                                                                         
                                                                                                            


            
                                                          
                                                                  



                                                            
                                                                                        
            
                                                                                        

                                                                                         

              
                                                                                
         
                                                                             




                                                               
                                                                  
         
      


                                                                               



                                                           


                                         

                                                                   




                                                                                    


















                                                                               
                                                                                                    






                                                   
                                               









                                                   


                                                                                                               
                                                                                                                                                     
                                 


                                                                                  
 
                                                                           








                                                                                       
                                                  


                                                   
                                                                                            


                                                   
                                                                           
                                                                                        

                                                                                    
                                 






















                                                                             
                                                             









                                                                   
 




                                                   
                                                 




                                                      
                                                                           













                                                                             




                                                                                  
 



                                                                                    
                                                                                   
         

                                     

                                                     










                                                   
                                                             



                                                                                                       
                           
         
                                                            
 



                                                  
                                                                                                                            
                 
                               



                                     



                                                                                                                                      









                                                            
                                 













                                                                   
                                             




                                                   


                                                   
                                                                      
 
              



                                                                                                       
                                                      
                                              
                                      


                                            

                                                          






                                                   
























                                                                                                                                                     


                                                   
                                                             



                                                                                                       
                           
         
                                                            
 

                             



                                                                                                                              
























                                                                         
                                             


                          
                                                                        
         
                                                                            
                                                 





                                                   
                                              


                                                   
                                                                     








                                                   

                                              

                                                   
                                                         
 

                          

                                                           
                                     
                                              




                                                   

                                                    

                                                   
                                                   
 


                          
                                           


                                    

                       
                                                
                                                                                                       
                                                    




                                                                                                                                
                                                                                                                            

















                                                                                                                                                      











                                                       

                                                                       
                                                                                                                            


                                                                   
                                              
                               


                                           
                                                   
                                                 












                                                           
                                               












                                                           

                                                  









                                                           
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*********************************************************************

    dvmemory.c

    Memory debugger view.

***************************************************************************/

#include "emu.h"
#include "dvmemory.h"

#include "debugcpu.h"
#include "debugger.h"

#include <algorithm>
#include <ctype.h>
#include <tuple>


//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

const debug_view_memory::memory_view_pos debug_view_memory::s_memory_pos_table[12] =
{
	/* 0 bytes per chunk:                         */ {  0, { 0 } },
	/* 1 byte  per chunk: 00 11 22 33 44 55 66 77 */ {  3, { 0x04, 0x00, 0x80 } },
	/* 2 bytes per chunk:  0011  2233  4455  6677 */ {  6, { 0x8c, 0x0c, 0x08, 0x04, 0x00, 0x80 } },
	/* 3 bytes per chunk:                         */ {  0, { 0 } },
	/* 4 bytes per chunk:   00112233    44556677  */ { 12, { 0x9c, 0x9c, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80 } },
	/* 5 bytes per chunk:                         */ {  0, { 0 } },
	/* 6 bytes per chunk:                         */ {  0, { 0 } },
	/* 7 bytes per chunk:                         */ {  0, { 0 } },
	/* 8 bytes per chunk:     0011223344556677    */ { 24, { 0xbc, 0xbc, 0xbc, 0xbc, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80 } },
	/* 32 bit floating point:                     */ { 16, { 0 } },
	/* 64 bit floating point:                     */ { 32, { 0 } },
	/* 80 bit floating point:                     */ { 32, { 0 } },
};



//**************************************************************************
//  DEBUG VIEW MEMORY SOURCE
//**************************************************************************

//-------------------------------------------------
//  debug_view_memory_source - constructors
//-------------------------------------------------

debug_view_memory_source::debug_view_memory_source(const char *name, address_space &space)
	: debug_view_source(name, &space.device()),
		m_space(&space),
		m_memintf(dynamic_cast<device_memory_interface *>(&space.device())),
		m_base(nullptr),
		m_length(0),
		m_offsetxor(0),
		m_endianness(space.endianness()),
		m_prefsize(space.data_width() / 8)
{
}

debug_view_memory_source::debug_view_memory_source(const char *name, memory_region &region)
	: debug_view_source(name),
		m_space(nullptr),
		m_memintf(nullptr),
		m_base(region.base()),
		m_length(region.bytes()),
		m_offsetxor(ENDIAN_VALUE_NE_NNE(region.endianness(), 0, region.bytewidth() - 1)),
		m_endianness(region.endianness()),
		m_prefsize(std::min<u8>(region.bytewidth(), 8))
{
}

debug_view_memory_source::debug_view_memory_source(const char *name, void *base, int element_size, int num_elements)
	: debug_view_source(name),
		m_space(nullptr),
		m_memintf(nullptr),
		m_base(base),
		m_length(element_size * num_elements),
		m_offsetxor(0),
		m_endianness(ENDIANNESS_NATIVE),
		m_prefsize(std::min(element_size, 8))
{
}



//**************************************************************************
//  DEBUG VIEW MEMORY
//**************************************************************************

//-------------------------------------------------
//  debug_view_memory - constructor
//-------------------------------------------------

debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
	: debug_view(machine, DVT_MEMORY, osdupdate, osdprivate),
		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),
		m_no_translation(false),
		m_edit_enabled(true),
		m_maxaddr(0),
		m_bytes_per_row(16),
		m_byte_offset(0)
{
	// hack: define some sane init values
	// that don't hurt the initial computation of top_left
	// in set_cursor_pos()
	m_section[0].m_pos = 0;
	m_section[0].m_width = 1 + 8 + 1;
	m_section[1].m_pos = m_section[0].m_pos + m_section[0].m_width;

	// fail if no available sources
	enumerate_sources();
	if (m_source_list.count() == 0)
		throw std::bad_alloc();

	// configure the view
	m_supports_cursor = true;
}


//-------------------------------------------------
//  enumerate_sources - enumerate all possible
//  sources for a memory view
//-------------------------------------------------

void debug_view_memory::enumerate_sources()
{
	// start with an empty list
	m_source_list.reset();
	std::string name;

	// first add all the devices' address spaces
	for (device_memory_interface &memintf : memory_interface_iterator(machine().root_device()))
		for (int spacenum = 0; spacenum < memintf.max_space_count(); ++spacenum)
			if (memintf.has_space(spacenum))
			{
				address_space &space = memintf.space(spacenum);
				name = string_format("%s '%s' %s space memory", memintf.device().name(), memintf.device().tag(), space.name());
				m_source_list.append(*global_alloc(debug_view_memory_source(name.c_str(), space)));
			}

	// then add all the memory regions
	for (auto &region : machine().memory().regions())
	{
		name = string_format("Region '%s'", region.second->name());
		m_source_list.append(*global_alloc(debug_view_memory_source(name.c_str(), *region.second.get())));
	}

	// finally add all global array symbols in alphabetical order
	std::vector<std::tuple<std::string, void *, u32, u32> > itemnames;
	itemnames.reserve(machine().save().registration_count());

	for (int itemnum = 0; itemnum < machine().save().registration_count(); itemnum++)
	{
		u32 valsize, valcount;
		void *base;
		std::string name_string(machine().save().indexed_item(itemnum, base, valsize, valcount));

		// add pretty much anything that's not a timer (we may wish to cull other items later)
		// also, don't trim the front of the name, it's important to know which VIA6522 we're looking at, e.g.
		if (strncmp(name_string.c_str(), "timer/", 6))
			itemnames.emplace_back(std::move(name_string), base, valsize, valcount);
	}

	std::sort(itemnames.begin(), itemnames.end(), [] (auto const &x, auto const &y) { return std::get<0>(x) < std::get<0>(y); });

	for (auto const &item : itemnames)
		m_source_list.append(*global_alloc(debug_view_memory_source(std::get<0>(item).c_str(), std::get<1>(item), std::get<2>(item), std::get<3>(item))));

	// reset the source to a known good entry
	set_source(*m_source_list.first());
}


//-------------------------------------------------
//  view_notify - handle notification of updates
//  to cursor changes
//-------------------------------------------------

void debug_view_memory::view_notify(debug_view_notification type)
{
	if (type == VIEW_NOTIFY_CURSOR_CHANGED)
	{
		// normalize the cursor
		set_cursor_pos(get_cursor_pos(m_cursor));
	}
	else if (type == VIEW_NOTIFY_SOURCE_CHANGED)
	{
		// update for the new source
		const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
		m_chunks_per_row = m_bytes_per_chunk * m_chunks_per_row / source.m_prefsize;
		m_bytes_per_chunk = source.m_prefsize;
		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
			m_expression.set_context(nullptr);
	}
}


//-------------------------------------------------
//  u32_to_float - return a floating point number
//  whose 32 bit representation is value
//-------------------------------------------------

static inline float u32_to_float(u32 value)
{
	union {
		float f;
		u32 i;
	} v;

	v.i = value;
	return v.f;
}

//-------------------------------------------------
//  u64_to_double - return a floating point number
//  whose 64 bit representation is value
//-------------------------------------------------

static inline float u64_to_double(u64 value)
{
	union {
		double f;
		u64 i;
	} v;

	v.i = value;
	return v.f;
}

//-------------------------------------------------
//  view_update - update the contents of the
//  memory view
//-------------------------------------------------

void debug_view_memory::view_update()
{
	const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);

	// if we need to recompute, do it now
	if (needs_recompute())
		recompute();

	// get positional data
	const memory_view_pos &posdata = s_memory_pos_table[m_data_format];

	// loop over visible rows
	for (u32 row = 0; row < m_visible.y; row++)
	{
		debug_view_char *destmin = &m_viewdata[row * m_visible.x];
		debug_view_char *destmax = destmin + m_visible.x;
		debug_view_char *destrow = destmin - m_topleft.x;
		u32 effrow = m_topleft.y + row;

		// reset the line of data; section 1 is normal, others are ancillary, cursor is selected
		debug_view_char *dest = destmin;
		for (int ch = 0; ch < m_visible.x; ch++, dest++)
		{
			u32 effcol = m_topleft.x + ch;
			dest->byte = ' ';
			dest->attrib = DCA_ANCILLARY;
			if (m_section[1].contains(effcol))
			{
				dest->attrib = DCA_NORMAL;
				if (m_cursor_visible && effrow == m_cursor.y && effcol == m_cursor.x)
					dest->attrib |= DCA_SELECTED;
			}
		}

		// if this visible row is valid, add it to the buffer
		if (effrow < m_total.y)
		{
			offs_t addrbyte = m_byte_offset + effrow * m_bytes_per_row;
			offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(addrbyte) : addrbyte;
			char addrtext[20];

			// generate the address
			sprintf(addrtext, m_addrformat.c_str(), address);
			dest = destrow + m_section[0].m_pos + 1;
			for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++)
				if (dest >= destmin && dest < destmax)
					dest->byte = addrtext[ch];

			// 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;
				int spacing = posdata.m_spacing;

				if (m_data_format <= 8) {
					u64 chunkdata;
					bool ismapped = read_chunk(address, chunknum, 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)
						{
							u8 shift = posdata.m_shift[ch];
							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;
					char valuetext[64];
					u64 chunkdata = 0;
					extFloat80_t chunkdata80 = { 0, 0 };
					bool ismapped;

					if (m_data_format != 11)
						ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata);
					else
						ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80);

					if (ismapped)
						switch (m_data_format)
						{
						case 9:
							sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata)));
							break;
						case 10:
							sprintf(valuetext, "%.24g", u64_to_double(chunkdata));
							break;
						case 11:
							float64_t f64 = extF80M_to_f64(&chunkdata80);
							sprintf(valuetext, "%.24g", u64_to_double(f64.v));
							break;
						}
					else {
						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++)
						if (dest >= destmin && dest < destmax)
							dest->byte = valuetext[ch];
					// then fill with spaces
					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, but follow the chunks
			if (m_section[2].m_width > 0)
			{
				dest = destrow + m_section[2].m_pos + 1;
				for (size_t i = 0; i != chunkascii.size(); i++) {
					if (dest >= destmin && dest < destmax)
						dest->byte = chunkascii[i];
					dest++;
				}
			}
		}
	}
}


//-------------------------------------------------
//  view_char - handle a character typed within
//  the current view
//-------------------------------------------------

void debug_view_memory::view_char(int chval)
{
	// get the position
	cursor_pos pos = get_cursor_pos(m_cursor);

	// editing is not supported when showing floating point values
	if (m_edit_enabled == false)
		return;

	// handle the incoming key
	switch (chval)
	{
		case DCH_UP:
			if (pos.m_address >= m_byte_offset + m_bytes_per_row)
				pos.m_address -= m_bytes_per_row;
			break;

		case DCH_DOWN:
			if (pos.m_address <= m_maxaddr - m_bytes_per_row)
				pos.m_address += m_bytes_per_row;
			break;

		case DCH_PUP:
			for (u32 delta = (m_visible.y - 2) * m_bytes_per_row; delta > 0; delta -= m_bytes_per_row)
				if (pos.m_address >= m_byte_offset + delta)
				{
					pos.m_address -= delta;
					break;
				}
			break;

		case DCH_PDOWN:
			for (u32 delta = (m_visible.y - 2) * m_bytes_per_row; delta > 0; delta -= m_bytes_per_row)
				if (pos.m_address <= m_maxaddr - delta)
				{
					pos.m_address += delta;
					break;
				}
			break;

		case DCH_HOME:
			pos.m_address -= pos.m_address % m_bytes_per_row;
			pos.m_shift = (m_bytes_per_chunk * 8) - 4;
			break;

		case DCH_CTRLHOME:
			pos.m_address = m_byte_offset;
			pos.m_shift = (m_bytes_per_chunk * 8) - 4;
			break;

		case DCH_END:
			pos.m_address += (m_bytes_per_row - (pos.m_address % m_bytes_per_row) - 1);
			pos.m_shift = 0;
			break;

		case DCH_CTRLEND:
			pos.m_address = m_maxaddr;
			pos.m_shift = 0;
			break;

		case DCH_CTRLLEFT:
			if (pos.m_address >= m_byte_offset + m_bytes_per_chunk)
				pos.m_address -= m_bytes_per_chunk;
			break;

		case DCH_CTRLRIGHT:
			if (pos.m_address <= m_maxaddr - m_bytes_per_chunk)
				pos.m_address += m_bytes_per_chunk;
			break;

		default:
		{
			static const char hexvals[] = "0123456789abcdef";
			char *hexchar = (char *)strchr(hexvals, tolower(chval));
			if (hexchar == nullptr)
				break;

			const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
			offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(pos.m_address) : pos.m_address;
			u64 data;
			bool ismapped = read(m_bytes_per_chunk, address, data);
			if (!ismapped)
				break;

			data &= ~(u64(0x0f) << pos.m_shift);
			data |= u64(hexchar - hexvals) << pos.m_shift;
			write(m_bytes_per_chunk, address, data);
			// fall through to the right-arrow press
		}

		case DCH_RIGHT:
			if (pos.m_shift == 0 && pos.m_address != m_maxaddr)
			{
				pos.m_shift = m_bytes_per_chunk * 8 - 4;
				pos.m_address += m_bytes_per_chunk;
			}
			else
				pos.m_shift -= 4;
			break;

		case DCH_LEFT:
			if (pos.m_shift == m_bytes_per_chunk * 8 - 4 && pos.m_address != m_byte_offset)
			{
				pos.m_shift = 0;
				pos.m_address -= m_bytes_per_chunk;
			}
			else
				pos.m_shift += 4;
			break;
	}

	// set a new position
	begin_update();
	set_cursor_pos(pos);
	m_update_pending = true;
	end_update();
}


//-------------------------------------------------
//  view_click - handle a mouse click within the
//  current view
//-------------------------------------------------

void debug_view_memory::view_click(const int button, const debug_view_xy& pos)
{
	const debug_view_xy origcursor = m_cursor;
	m_cursor = pos;

	/* cursor popup|toggle */
	bool cursorVisible = true;
	if (m_cursor.y == origcursor.y && m_cursor.x == origcursor.x)
	{
		cursorVisible = !m_cursor_visible;
	}

	/* send a cursor changed notification */
	begin_update();
	m_cursor_visible = cursorVisible;
	view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
	m_update_pending = true;
	end_update();
}


//-------------------------------------------------
//  recompute - recompute the internal data and
//  structure of the memory view
//-------------------------------------------------

void debug_view_memory::recompute()
{
	const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);

	// get the current cursor position
	cursor_pos pos = get_cursor_pos(m_cursor);

	// determine the maximum address and address format string from the raw information
	int addrchars;
	u64 maxbyte;
	if (source.m_space != nullptr)
	{
		m_maxaddr = m_no_translation ? source.m_space->addrmask() : source.m_space->logaddrmask();
		maxbyte = source.m_space->address_to_byte_end(m_maxaddr);
		addrchars = m_no_translation ? source.m_space->addrchars() : source.m_space->logaddrchars();
	}
	else
	{
		maxbyte = m_maxaddr = source.m_length - 1;
		addrchars = string_format("%X", m_maxaddr).size();
	}

	// generate an 8-byte aligned format for the address
	if (!m_reverse_view)
		m_addrformat = string_format("%*s%%0%dX", 8 - addrchars, "", addrchars);
	else
		m_addrformat = string_format("%%0%dX%*s", addrchars, 8 - addrchars, "");

	// if we are viewing a space with a minimum chunk size, clamp the bytes per chunk
	// BAD
#if 0
	if (source.m_space != nullptr && source.m_space->byte_to_address(1) > 1)
	{
		u32 min_bytes_per_chunk = source.m_space->byte_to_address(1);
		while (m_bytes_per_chunk < min_bytes_per_chunk)
		{
			m_bytes_per_chunk *= 2;
			m_chunks_per_row /= 2;
		}
		m_chunks_per_row = std::max(1U, m_chunks_per_row);
	}
#endif

	// recompute the byte offset based on the most recent expression result
	m_bytes_per_row = m_bytes_per_chunk * m_chunks_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;
	if (m_data_format <= 8)
		m_section[1].m_width = 1 + 3 * m_bytes_per_row + 1;
	else {
		const memory_view_pos &posdata = s_memory_pos_table[m_data_format];

		m_section[1].m_width = 1 + posdata.m_spacing * m_chunks_per_row + 1;
	}
	m_section[2].m_width = m_ascii_view ? (1 + m_bytes_per_row + 1) : 0;

	// compute the section positions
	if (!m_reverse_view)
	{
		m_section[0].m_pos = 0;
		m_section[1].m_pos = m_section[0].m_pos + m_section[0].m_width;
		m_section[2].m_pos = m_section[1].m_pos + m_section[1].m_width;
		m_total.x = m_section[2].m_pos + m_section[2].m_width;
	}
	else
	{
		m_section[2].m_pos = 0;
		m_section[1].m_pos = m_section[2].m_pos + m_section[2].m_width;
		m_section[0].m_pos = m_section[1].m_pos + m_section[1].m_width;
		m_total.x = m_section[0].m_pos + m_section[0].m_width;
	}

	// derive total sizes from that
	m_total.y = (maxbyte - u64(m_byte_offset) + u64(m_bytes_per_row) /*- 1*/) / m_bytes_per_row;

	// reset the current cursor position
	set_cursor_pos(pos);
}


//-------------------------------------------------
//  needs_recompute - determine if anything has
//  changed that requires a recomputation
//-------------------------------------------------

bool debug_view_memory::needs_recompute()
{
	bool recompute = m_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 & (m_no_translation ? source.m_space->addrmask() : source.m_space->logaddrmask()));
		recompute = true;

		m_byte_offset = val % m_bytes_per_row;
		m_topleft.y = std::min(s32(val / m_bytes_per_row), m_total.y - 1);

		set_cursor_pos(cursor_pos(val, m_bytes_per_chunk * 8 - 4));
	}

	// expression is clean at this point, and future recomputation is not necessary
	m_recompute = false;
	return recompute;
}


//-------------------------------------------------
//  get_cursor_pos - return the cursor position as
//  an address and a shift value
//-------------------------------------------------

debug_view_memory::cursor_pos debug_view_memory::get_cursor_pos(const debug_view_xy& cursor)
{
	// start with the base address for this row
	cursor_pos pos;
	const memory_view_pos &posdata = s_memory_pos_table[m_data_format];
	pos.m_address = m_byte_offset + cursor.y * m_bytes_per_chunk * m_chunks_per_row;

	// determine the X position within the middle section, clamping as necessary
	if (m_data_format <= 8) {
		int xposition = cursor.x - m_section[1].m_pos - 1;
		if (xposition < 0)
			xposition = 0;
		else if (xposition >= posdata.m_spacing * m_chunks_per_row)
			xposition = posdata.m_spacing * m_chunks_per_row - 1;

		// compute chunk number and offset within that chunk
		int chunknum = xposition / posdata.m_spacing;
		int chunkoffs = xposition % posdata.m_spacing;

		// reverse the chunknum if we're reversed
		if (m_reverse_view)
			chunknum = m_chunks_per_row - 1 - chunknum;

		// compute the address and shift
		pos.m_address += chunknum * m_bytes_per_chunk;
		pos.m_shift = posdata.m_shift[chunkoffs] & 0x7f;
	}
	else {
		int xposition = cursor.x - m_section[1].m_pos - 1;
		// check for lower limit
		if (xposition < 0)
			xposition = 0;
		int chunknum = xposition / posdata.m_spacing;
		// check for upper limit
		if (chunknum >= m_chunks_per_row)
			chunknum = m_chunks_per_row - 1;
		// reverse the chunknum if we're reversed
		if (m_reverse_view)
			chunknum = m_chunks_per_row - 1 - chunknum;
		// compute the address
		pos.m_address += chunknum * m_bytes_per_chunk;
		pos.m_shift = 0;
	}

	return pos;
}


//-------------------------------------------------
//  set_cursor_pos - set the cursor position as a
//  function of an address and a shift value
//-------------------------------------------------

void debug_view_memory::set_cursor_pos(cursor_pos pos)
{
	const memory_view_pos &posdata = s_memory_pos_table[m_data_format];

	// offset the address by the byte offset
	if (pos.m_address < m_byte_offset)
		pos.m_address = m_byte_offset;
	pos.m_address -= m_byte_offset;

	// compute the Y coordinate and chunk index
	m_cursor.y = pos.m_address / m_bytes_per_row;
	int chunknum = (pos.m_address % m_bytes_per_row) / m_bytes_per_chunk;

	// reverse the chunknum if we're reversed
	if (m_reverse_view)
		chunknum = m_chunks_per_row - 1 - chunknum;

	if (m_data_format <= 8) {
		// scan within the chunk to find the shift
		for (m_cursor.x = 0; m_cursor.x < posdata.m_spacing; m_cursor.x++)
			if (posdata.m_shift[m_cursor.x] == pos.m_shift)
				break;

		// add in the chunk offset and shift to the right of divider1
		m_cursor.x += m_section[1].m_pos + 1 + posdata.m_spacing * chunknum;
	}
	else {
		m_cursor.x = m_section[1].m_pos + 1 + posdata.m_spacing * chunknum;
	}

	// clamp to the window bounds
	m_cursor.x = std::min(m_cursor.x, m_total.x);
	m_cursor.y = std::min(m_cursor.y, m_total.y);

	// scroll if out of range
	adjust_visible_x_for_cursor();
	adjust_visible_y_for_cursor();
}


//-------------------------------------------------
//  read - generic memory view data reader
//-------------------------------------------------

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)
	{
		auto dis = machine().disable_side_effects();

		bool ismapped = offs <= m_maxaddr;
		if (ismapped && !m_no_translation)
		{
			offs_t dummyaddr = offs;
			ismapped = source.m_memintf->translate(source.m_space->spacenum(), TRANSLATE_READ_DEBUG, dummyaddr);
		}
		data = ~u64(0);
		if (ismapped)
		{
			switch (size)
			{
				case 1: data = machine().debugger().cpu().read_byte(*source.m_space, offs, !m_no_translation); break;
				case 2: data = machine().debugger().cpu().read_word(*source.m_space, offs, !m_no_translation); break;
				case 4: data = machine().debugger().cpu().read_dword(*source.m_space, offs, !m_no_translation); break;
				case 8: data = machine().debugger().cpu().read_qword(*source.m_space, offs, !m_no_translation); break;
			}
		}
		return ismapped;
	}

	// if larger than a byte, reduce by half and recurse
	if (size > 1)
	{
		size /= 2;

		u64 data0, data1;
		bool ismapped = read(size, offs + 0 * size, data0);
		ismapped |= read(size, offs + 1 * size, data1);

		if (source.m_endianness == ENDIANNESS_LITTLE)
			data = data0 | (data1 << (size * 8));
		else
			data = data1 | (data0 << (size * 8));
		return ismapped;
	}

	// all 0xff if out of bounds
	offs ^= source.m_offsetxor;
	if (offs >= source.m_length)
		return false;
	data = *((u8 *)source.m_base + offs);
	return true;
}


//-------------------------------------------------
//  read - read a 80 bit value
//-------------------------------------------------

bool debug_view_memory::read(u8 size, offs_t offs, extFloat80_t &data)
{
	u64 t;
	bool mappedhi, mappedlo;
	const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);

	if (source.m_endianness == ENDIANNESS_LITTLE) {
		mappedlo = read(8, offs, data.signif);
		mappedhi = read(2, offs+8, t);
		data.signExp = u16(t);
	}
	else {
		mappedhi = read(2, offs, t);
		data.signExp = u16(t);
		mappedlo = read(8, offs + 2, data.signif);
	}

	return mappedhi && mappedlo;
}


//-------------------------------------------------
//  read_chunk - memory view data reader helper
//-------------------------------------------------

bool debug_view_memory::read_chunk(offs_t address, int chunknum, u64 &chunkdata)
{
	const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
	if (source.m_space) {
		address += source.m_space->byte_to_address(chunknum * m_bytes_per_chunk);
		if (!source.m_space->byte_to_address(m_bytes_per_chunk)) {
			// if chunks are too small to be addressable, read a minimal chunk and split it up
			u8 minbytes = 1 << -source.m_space->addr_shift();
			bool ismapped = read(minbytes, address, chunkdata);
			u8 suboffset = (chunknum * m_bytes_per_chunk) & (minbytes - 1);
			chunkdata >>= 8 * (source.m_space->endianness() == ENDIANNESS_LITTLE ? suboffset : minbytes - m_bytes_per_chunk - suboffset);
			chunkdata &= ~u64(0) >> (64 - 8 * m_bytes_per_chunk);
			return ismapped;
		}
	}
	else
		address += chunknum * m_bytes_per_chunk;
	return read(m_bytes_per_chunk, address, chunkdata);
}


//-------------------------------------------------
//  write - generic memory view data writer
//-------------------------------------------------

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)
	{
		auto dis = machine().disable_side_effects();

		switch (size)
		{
			case 1: machine().debugger().cpu().write_byte(*source.m_space, offs, data, !m_no_translation); break;
			case 2: machine().debugger().cpu().write_word(*source.m_space, offs, data, !m_no_translation); break;
			case 4: machine().debugger().cpu().write_dword(*source.m_space, offs, data, !m_no_translation); break;
			case 8: machine().debugger().cpu().write_qword(*source.m_space, offs, data, !m_no_translation); break;
		}
		return;
	}

	// if larger than a byte, reduce by half and recurse
	if (size > 1)
	{
		size /= 2;
		if (source.m_endianness == ENDIANNESS_LITTLE)
		{
			write(size, offs + 0 * size, data);
			write(size, offs + 1 * size, data >> (8 * size));
		}
		else
		{
			write(size, offs + 1 * size, data);
			write(size, offs + 0 * size, data >> (8 * size));
		}
		return;
	}

	// ignore if out of bounds
	offs ^= source.m_offsetxor;
	if (offs >= source.m_length)
		return;
	*((u8 *)source.m_base + offs) = data;

// hack for FD1094 editing
#ifdef FD1094_HACK
	if (source.m_base == machine().root_device().memregion("user2"))
	{
		extern void fd1094_regenerate_key(running_machine &machine);
		fd1094_regenerate_key(machine());
	}
#endif
}


//-------------------------------------------------
//  set_expression - set the expression string
//  describing the home address
//-------------------------------------------------

void debug_view_memory::set_expression(const std::string &expression)
{
	begin_update();
	m_expression.set_string(expression);
	m_recompute = m_update_pending = true;
	end_update();
}


//-------------------------------------------------
//  set_chunks_per_row - specify the number of
//  chunks displayed across a row
//-------------------------------------------------

void debug_view_memory::set_chunks_per_row(u32 rowchunks)
{
	if (rowchunks < 1)
		return;

	cursor_pos pos = begin_update_and_get_cursor_pos();
	m_chunks_per_row = rowchunks;
	m_recompute = m_update_pending = true;
	end_update_and_set_cursor_pos(pos);
}


//-------------------------------------------------
//  set_data_format - specify what kind of values
//  are shown, 1-8 8-64 bits, 9 32bit floating point
//-------------------------------------------------

void debug_view_memory::set_data_format(int format)
{
	cursor_pos pos;

	// should never be
	if ((format <= 0) || (format > 11))
		return;
	// no need to change
	if (format == m_data_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)) {

		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;

		pos.m_shift += 8 * ((pos.m_address % m_bytes_per_chunk) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1)));
		pos.m_address -= pos.m_address % m_bytes_per_chunk;
	} else {
		if (format <= 8) {
			m_supports_cursor = true;
			m_edit_enabled = true;

			m_bytes_per_chunk = format;
		}
		else {
			m_supports_cursor = false;
			m_edit_enabled = false;
			m_cursor_visible = false;

			switch (format)
			{
			case 9:
				m_bytes_per_chunk = 4;
				break;
			case 10:
				m_bytes_per_chunk = 8;
				break;
			case 11:
				m_bytes_per_chunk = 10;
				break;
			}
		}
		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;
	}
	m_recompute = m_update_pending = true;
	m_data_format = format;
	end_update_and_set_cursor_pos(pos);
}

//-------------------------------------------------
//  set_reverse - specify true if the memory view
//  is displayed reverse
//-------------------------------------------------

void debug_view_memory::set_reverse(bool reverse)
{
	cursor_pos pos = begin_update_and_get_cursor_pos();
	m_reverse_view = reverse;
	m_recompute = m_update_pending = true;
	end_update_and_set_cursor_pos(pos);
}


//-------------------------------------------------
//  set_ascii - specify true if the memory view
//  should display an ASCII representation
//-------------------------------------------------

void debug_view_memory::set_ascii(bool ascii)
{
	cursor_pos pos = begin_update_and_get_cursor_pos();
	m_ascii_view = ascii;
	m_recompute = m_update_pending = true;
	end_update_and_set_cursor_pos(pos);
}


//-------------------------------------------------
//  set_physical - specify true if the memory view
//  should display physical addresses versus
//  logical addresses
//-------------------------------------------------

void debug_view_memory::set_physical(bool physical)
{
	cursor_pos pos = begin_update_and_get_cursor_pos();
	m_no_translation = physical;
	m_recompute = m_update_pending = true;
	end_update_and_set_cursor_pos(pos);
}