summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/bus/megadrive/md_slot.cpp
blob: f338fc25d87b425c7ef1747eac24a0287a3a1c84 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                          
                                                                                                            
 




                                     



                                                                                               


                                                                                                     

























                                                                                                               
 

                                                                                                             
                
                    




                                                                            


                                                                                                              









                                                                                                   
                                                                                                                                                      
                               
                             















                                                     
                                                                      
 
                             
         
                                                                                                                                                                      

                                  






                                                   
                                                       
 
                                              

 
                                                   
                                                 


                                                   
                                                           

              
                                                          

                                            
 










                                                                                 
 
                  





                                                       


                                                   
                  

                                                   
                                                                 
 
                                    









                                                   







                                                                            


                                                                                                                                                       
                                                                                    

                                          


 
                                                                                                                           
                                                                          


 
                                                                                                                               
                                                                            


 
                                                                                                                                   
                                                                              


 













                                                     
                                   

 















                                                                                                    
                               


                                  
                                       
                                


                                 
 

                                      
                                          




                                       
 




                                         
 
                             
                                  
                                 

                                                             
                                  









                                     
                                     
                                  






                                   
                               


                                     
                                         
                                    







                                              
                                     
         
                                                    
                                           
         
 




                                        
                                     
         

                                                
         
 












                                                    
                                                       



                                  
                                      
 


                                                                                                 
                                               


                                             
 
                                                    
 
                                                   
                 



                                                                             

                                                                                
 




                                                                                                       
 
                                                                                                                          


                           
         
 
                                       


 
                                                       
 

                                                            

                               


                                                                                                                     
                                         
                                     
                                                                                              



                                                                                                                          
 
                                                         


                                                  

                                                                  
                                                                    

                                              
                                       







                                                  
                                                               
 
                                                                                                             


                         
                                                                                   
                         
 


                                
                                                                                                                 
                         
 
                             
                                                                                    
                         
 
                                    
                                                                                        
                         
 
                               
                                                                                                               
                         
 
                        
                                                                                   
                         
 
                          
                                                                                        
                         
 
                              
                                                                                    
                         
 
                             
                                                                                     
                         
 
                       
                                                                                     
                         
 
                                
                                                                                        
                         
 
                                      
                                                                                                                  
                         
 
                          
                                                                                     
                         
 







                                       
                                                          
 
                           
                           

                                                
 
                                                                                                      
                                  








                                                                                                                     
 

                                                                                                     
 
                                                            
                                                      
 
                   
         
                                           
 
                                                                            


                                                        

                                                                                                         

                         
         
                       
         
                                          
 
                                                         
                 
                                                                      


                                                          

            
                                           
 



                                   
                                                                                                                 


                                                                                                        
 
                                                                                      
                                                     
 


                                                                  
 
 
                                                                                        

                               





                                              
      
 
                                       


                                                   
            



                                                    
                                                                           





                                                                                 
                                                 














                                                                                                    
         



                                            
                                                         











                                                                                                                                                                               
 
                                                                          
                                                                                                                                        
                                                                                     
 

                                                           
 

                                                         
 
                                                                                             
                                                                        
                                                           
                                                               






                                                                             

                                                                                                                        
                                                                                             
                                                                        

                                                           
 

                                                              
                                

                                                                                                             
                                                                                             
                                                                        





                                                                                                             
                                                                                             


                                                               
 
                                                                                


                                                                                                             
                                                                                             


                                                               
                            

                                                                             
                                                                                             


                                                               
                             
                                                         
                                                                             
                                                                    

                                                   


                                                                             
                                                                                             

                                                   





                                                                              


                                                   




         
                                                                             

























                                                                                                                          
 
                    
         


                                                                                  
 


                                                                            
                                               
 
                                                                                               
                                                
 
                                                                                                 

                                                   
 
                             
 
                                                                                           

                                                   
 


                                                                                     
 

                                                                                
 

                                                                                 
 
                                                                                
                                              
 

                                                                               
 
                                                                                              
                                                
 
                                                                                                        
                                                   
 
                                                                                                  
                                                    
 
                                                                                                                                
                                                  
 
                                                                                                                                                          

                                                    
 


                                                                            
 

                                                                           
 

                                                                                       
 

                                                                             
 

                                                                               
 

                                                                                
 

                                                                                  
 

                                                                                  
 

                                                                             
 

                                                                                 
 

                                                                                   
 
                                                                                         
                                               
 
                                                                                                                
                                                   
 

                                                                                                                                                                           
                                                   
 
                                                                               

                                                


                                                                                       
                              
 



                                                                                       
 



                                                                                           
 


                                                                           
 

                                                                                  
 
                                                                                          
                                                  
 
                                                                                                      
                                                  
 
                              
 



                                                                                                                 
 

                                                                                  
 

                                                                                   
 
                                                                                                         
                                                 
 
                                                                                              
                                              
 
                                                                                                 
                                              
 


                                                                                        
                              
 
                              
                                                                                        



                                            
                                                                                            









                                                
                                                                                      
                                                           
                 

                                                                                                              
                                                                                                              








                                                                                                                
                                                                                             



                                                       
 





                                                    
                                                                                                           
 
                              
         
                                        
                                                                     
                                              
                         
 
                                                      
 
                                                             

                                               
                                                                 
                                                
 
                                                

            
                                                        







                                                    
                                                      

                   
                                            



                              
                                                          

                   
                                                



                              
                                                          

                   
                                                








                                                    
                                                                                     

                   
                                                      

 
                                                                      

                   
                                                

 
                                                                      

                   
                                                
 

                                                   
                      

                                                    
                                                                                                


                                                                              

                                                                                      
                                                 
                                      

                           

                                   
                                           
                                                                                                                             












                                                                      
                                                   
                                              
                               
                                    
                                                     
                                    
                                                         
                                    
                                                         
                                    
                                                  




                                                    
                                              
                                 
                                                                 
                                 
                                                                 



                                                                                             

                                                                                              

                                                     
                                  




                                                                                                      
                                                 
                                    
                                                

                                    
                                                   
                                      
                                                     
                                      
                                                   
                                      
                                                      







                                                                     
 

                                      














                                                                                                         
                                                                       

                                          
                                                             










                                                                               
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli,Cowering
/***********************************************************************************************************


    MegaDrive cart emulation
    (through slot devices)

    The driver exposes address ranges
    0x000000-0x7fffff to read/write (typically cart data, possibly banked, and some protection)
    0x130000-0x1300ff to read_a13/write_a13 (typically SRAM toggling or protection)
    0x150000-0x1500ff to read_a15/write_a15 (for SVP registers, not converted yet to slots)

    currently available slot devices:
    md_rom: standard carts + carts with NVRAM (SRAM/FRAM) + pirate carts with protection & bankswitch
    md_eeprom: carts + I2C EEPROM (EEPROM device hooked up only, support to be completed)
    md_jcart: Codemasters J-Cart & J-Cart+SEPROM (again, EEPROM device hooked up only, support to be completed)
    md_sk: Sonic & Knuckles pass-thorugh cart (enables a second slot to mount any other cart)
    md_stm95: cart + STM95 EEPROM (e.g. Pier Solar)


    Cart Mirroring (based Eke's research)

    MD Cartridge area is mapped to $000000-$3fffff: when accessing ROM, 68k address lines A1 to A21 can be
    used by the internal cartridge hardware to decode full 4MB address range.
    Depending on ROM total size and additional decoding hardware, some address lines might be ignored,
    resulting in ROM mirroring.

    Cartridges typically use either 8-bits (x2) or 16-bits (x1, x2) Mask ROM chips, each chip size is a
    factor of 2 bytes.
    When one chip ROM1 of size 2^N is present, it is generally mirrored each 2^N bytes so that read access
    to cart area sees the sequence ROM1,ROM1,ROM1,... (up to 4MB)
    When two chips ROM1 & ROM2 are present and the whole size is 2^N, then the block ROM1+ROM2 is mirrored
    in the cart area, and reads see the sequence ROM1+ROM2,ROM1+ROM2,... (up to 4MB)
    When two chips ROM1 & ROM2 are present and the whole size is not 2^N (e.g. because ROM1 and ROM2 have
    different sizes), then the area between the end of ROM2 and next power 2^N is generally ignored, and
    reads see the sequence ROM1,ROM2,XXXX,ROM1,ROM2,XXXX... (up to 4MB)

    At loading time we first compute first power 2^N larger than cart size (see get_padded_size function),
    we allocate such a size for ROM and we fill of 0xff the area between end of dump and 2^N.
    Then we handle mirroring by creating a rom_bank_map[] (see rom_map_setup function) which points each
    access in 0x000000-0x400000 to the correct 64K ROM bank.

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

#include "emu.h"
#include "md_slot.h"

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

DEFINE_DEVICE_TYPE(MD_CART_SLOT,     md_cart_slot_device,     "md_cart_slot",     "Mega Drive Cartridge Slot")
DEFINE_DEVICE_TYPE(PICO_CART_SLOT,   pico_cart_slot_device,   "pico_cart_slot",   "Pico Cartridge Slot")
DEFINE_DEVICE_TYPE(COPERA_CART_SLOT, copera_cart_slot_device, "copera_cart_slot", "Copera Cartridge Slot")

//**************************************************************************
//    MD cartridges Interface
//**************************************************************************

//-------------------------------------------------
//  device_md_cart_interface - constructor
//-------------------------------------------------

device_md_cart_interface::device_md_cart_interface(const machine_config &mconfig, device_t &device)
	: device_interface(device, "mdcart"), m_nvram_start(0), m_nvram_end(0), m_nvram_active(0), m_nvram_readonly(0), m_nvram_handlers_installed(0),
		m_rom(nullptr),
		m_rom_size(0)
{
}


//-------------------------------------------------
//  ~device_md_cart_interface - destructor
//-------------------------------------------------

device_md_cart_interface::~device_md_cart_interface()
{
}

//-------------------------------------------------
//  rom_alloc - alloc the space for the cart
//-------------------------------------------------

void device_md_cart_interface::rom_alloc(size_t size, const char *tag)
{
	if (m_rom == nullptr)
	{
		m_rom = (uint16_t *)device().machine().memory().region_alloc(std::string(tag).append(MDSLOT_ROM_REGION_TAG).c_str(), size, 2, ENDIANNESS_BIG)->base();
		m_rom_size = size;
	}
}


//-------------------------------------------------
//  nvram_alloc - alloc the space for the nvram
//-------------------------------------------------

void device_md_cart_interface::nvram_alloc(size_t size)
{
	m_nvram.resize(size/sizeof(uint16_t));
}

//-------------------------------------------------
//  rom_map_setup - setup map of rom banks in 64K
//  blocks, so to simplify ROM mirroring
//-------------------------------------------------

void device_md_cart_interface::rom_map_setup(uint32_t size)
{
	int i;
	// setup the rom_bank_map array to faster ROM read
	for (i = 0; i < size / 0x10000; i++)
		rom_bank_map[i] = i;

	// fill up remaining blocks with mirrors
	while (i % 64)
	{
		int j = 0, repeat_banks;
		while ((i % (64 >> j)) && j < 7)
			j++;
		repeat_banks = i % (64 >> (j - 1));
		for (int k = 0; k < repeat_banks; k++)
			rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks];
		i += repeat_banks;
	}

// check bank map!
//  for (i = 0; i < 64; i++)
//  {
//      printf("bank %3d = %3d\t", i, rom_bank_map[i]);
//      if ((i%8) == 7)
//          printf("\n");
//  }
}

//-------------------------------------------------
// get_padded_size
//-------------------------------------------------

uint32_t device_md_cart_interface::get_padded_size(uint32_t size)
{
	uint32_t pad_size = 0x10000;
	while (size > pad_size)
		pad_size <<= 1;

	if (pad_size < 0x800000 && size < pad_size)
		return pad_size;
	else
		return size;
}



//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  base_md_cart_slot_device - constructor
//-------------------------------------------------
base_md_cart_slot_device::base_md_cart_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, type, tag, owner, clock),
	device_image_interface(mconfig, *this),
	device_single_card_slot_interface<device_md_cart_interface>(mconfig, *this),
	m_type(SEGA_STD), m_cart(nullptr),
	m_must_be_loaded(1)
{
}

md_cart_slot_device::md_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	base_md_cart_slot_device(mconfig, MD_CART_SLOT, tag, owner, clock)
{
}

pico_cart_slot_device::pico_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	base_md_cart_slot_device(mconfig, PICO_CART_SLOT, tag, owner, clock)
{
}

copera_cart_slot_device::copera_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	base_md_cart_slot_device(mconfig, COPERA_CART_SLOT, tag, owner, clock)
{
}

//-------------------------------------------------
//  base_md_cart_slot_device - destructor
//-------------------------------------------------

base_md_cart_slot_device::~base_md_cart_slot_device()
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void base_md_cart_slot_device::device_start()
{
	m_cart = get_card_device();
}


//-------------------------------------------------
//  MD PCB
//-------------------------------------------------


struct md_slot
{
	int                     pcb_id;
	const char              *slot_option;
};

// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
static const md_slot slot_list[] =
{
	{ SEGA_SK, "rom_sk" },
	{ SEGA_SVP, "rom_svp"},

	{ SEGA_SRAM, "rom_sram" },
	{ SEGA_FRAM, "rom_fram" },
	{ HARDBALL95, "rom_hardbl95" },
	{ XINQIG, "rom_xinqig"},
	{ BEGGARP, "rom_sf001"},
	{ WUKONG, "rom_sf002"},
	{ STARODYS, "rom_sf004"},

	{ SEGA_EEPROM, "rom_eeprom" },
	{ NBA_JAM, "rom_nbajam" },
	{ NBA_JAM_ALT, "rom_nbajam_alt" },
	{ NBA_JAM_TE, "rom_nbajamte" },
	{ NFL_QB_96, "rom_nflqb" },
	{ C_SLAM, "rom_cslam" },
	{ EA_NHLPA, "rom_nhlpa" },
	{ BRIAN_LARA, "rom_blara" },

	{ CM_JCART, "rom_jcart" },
	{ CODE_MASTERS, "rom_codemast" },
	{ CM_MM96, "rom_mm96" },

	{ PSOLAR, "rom_stm95"},

	{ SSF2, "rom_ssf2" },
	{ CM_2IN1, "rom_cm2in1" },
	{ RADICA, "rom_radica" },
//  { GAME_KANDUME, "rom_gkand" },  // what's needed by this?

	{ TILESMJ2, "rom_16mj2" },
	{ BUGSLIFE, "rom_bugs" },
	{ CHINFIGHT3, "rom_chinf3" },
	{ ELFWOR, "rom_elfwor" },
	{ KAIJU, "rom_pokestad" },
	{ KOF98, "rom_kof98" },
	{ KOF99, "rom_kof99" },
	{ LIONK2, "rom_lion2" },
	{ LIONK3, "rom_lion3" },
	{ MC_PIRATE, "rom_mcpir" },
	{ MJLOVER, "rom_mjlov" },
	{ CJMJCLUB, "rom_cjmjclub" },
	{ POKEMONA, "rom_pokea" },
	{ REALTEC, "rom_realtec" },
	{ REDCL_EN, "rom_redcl" },
	{ REDCLIFF, "rom_redcl" },
	{ ROCKMANX3, "rom_rx3" },
	{ SBUBBOB, "rom_sbubl" },
	{ SMB, "rom_smb" },
	{ SMB2, "rom_smb2" },
	{ SMW64, "rom_smw64" },
	{ SMOUSE, "rom_smouse" },
	{ SOULBLAD, "rom_soulblad" },
	{ SQUIRRELK, "rom_squir" },
	{ SRAM_ARG96, "rom_sram_arg96" },
	{ TEKKENSP, "rom_tekkesp" },
	{ TOPFIGHTER, "rom_topf" },

	{ SEGA_SRAM_FULLPATH, "rom_sram" },
	{ SEGA_SRAM_FALLBACK, "rom_sramsafe" }
};

static int md_get_pcb_id(const char *slot)
{
	for (auto & elem : slot_list)
	{
		if (!strcmp(elem.slot_option, slot))
			return elem.pcb_id;
	}

	return SEGA_STD;
}

static const char *md_get_slot(int type)
{
	for (auto & elem : slot_list)
	{
		if (elem.pcb_id == type)
			return elem.slot_option;
	}

	return "rom";
}


/*-------------------------------------------------
 SRAM handling
 -------------------------------------------------*/

/*-------------------------------------------------
 call load
 -------------------------------------------------*/


image_init_result base_md_cart_slot_device::call_load()
{
	if (m_cart)
	{
		m_type = SEGA_STD;
		image_init_result res;

		// STEP 1: load the file image and keep a copy for later banking
		// STEP 2: identify the cart type
		// The two steps are carried out differently if we are loading from a list or not
		if (!loaded_through_softlist())
			res = load_nonlist();
		else
			res = load_list();

		//printf("cart type: %d\n", m_type);

		if (res == image_init_result::PASS)
		{
			//speed-up rom access from SVP add-on, if present
			if (m_type == SEGA_SVP)
				m_cart->set_bank_to_rom("cart_svp", 0x800/2);

			// STEP 3: install memory handlers for this type of cart
			setup_custom_mappers();

			// STEP 4: take care of SRAM.
			setup_nvram();

			if (m_cart->get_nvram_size())
				battery_load(m_cart->get_nvram_base(), m_cart->get_nvram_size(), 0xff);

			file_logging((uint8_t *)m_cart->get_rom_base(), m_cart->get_rom_size(), m_cart->get_nvram_size());
		}

		return res;
	}

	return image_init_result::PASS;
}


image_init_result base_md_cart_slot_device::load_list()
{
	uint16_t *ROM;
	uint32_t length = get_software_region_length("rom");
	const char  *slot_name;

	// if cart size is not (2^n * 64K), the system will see anyway that size so we need to alloc a bit more space
	length = m_cart->get_padded_size(length);

	m_cart->rom_alloc(length, tag());
	ROM = m_cart->get_rom_base();
	memcpy((uint8_t *)ROM, get_software_region("rom"), get_software_region_length("rom"));

	// if we allocated a ROM larger that the file (e.g. due to uneven cart size), set remaining space to 0xff
	if (length > get_software_region_length("rom"))
		memset(ROM + get_software_region_length("rom")/2, 0xffff, (length - get_software_region_length("rom"))/2);

	if ((slot_name = get_feature("slot")) == nullptr)
		m_type = SEGA_STD;
	else
		m_type = md_get_pcb_id(slot_name);

	// handle mirroring of ROM, unless it's SSF2 or Pier Solar
	if (m_type != SSF2 && m_type != PSOLAR && m_type != CM_2IN1)
		m_cart->rom_map_setup(length);

	return image_init_result::PASS;
}


/*************************************
 *  Helper function: Detect SMD file
 *************************************/

/* code taken directly from GoodGEN by Cowering */
static int genesis_is_SMD(unsigned char *buf, unsigned int len)
{
	if (len > 0x2081 && buf[0x2080] == 'S' && buf[0x80] == 'E' && buf[0x2081] == 'G' && buf[0x81] == 'A')
		return 1;

	/* aq quiz */
	if (len > (0xf0 + 8) && !strncmp("UZ(-01  ", (const char *) &buf[0xf0], 8))
		return 1;

	/* Phelios USA redump */
	/* target earth */
	/* klax (namcot) */
	if (len > 0x2081 && buf[0x2080] == ' ' && buf[0x0080] == 'S' && buf[0x2081] == 'E' && buf[0x0081] == 'G')
		return 1;

	/* jpn baseball 94 */
	if (len > (0xf0 + 9) && !strncmp("OL R-AEAL", (const char *) &buf[0xf0], 9))
		return 1;

	/* devilish Mahjong Tower */
	if (len > (0xf3 + 11) && !strncmp("optrEtranet", (const char *) &buf[0xf3], 11))
		return 1;

	/* golden axe 2 beta */
	if (len > 0x0103 && buf[0x0100] == 0x3c && buf[0x0101] == 0 && buf[0x0102] == 0 && buf[0x0103] == 0x3c)
		return 1;

	/* omega race */
	if (len > (0x90 + 8) && !strncmp("OEARC   ", (const char *) &buf[0x90], 8))
		return 1;

	/* budokan beta */
	if ((len >= 0x6708 + 8) && !strncmp(" NTEBDKN", (const char *) &buf[0x6708], 8))
		return 1;

	/* cdx pro 1.8 bios */
	if (len > (0x2c0 + 7) && !strncmp("so fCXP", (const char *) &buf[0x2c0], 7))
		return 1;

	/* ishido (hacked) */
	if (len > (0x90 + 8) && !strncmp("sio-Wyo ", (const char *) &buf[0x0090], 8))
		return 1;

	/* onslaught */
	if (len > (0x88 + 8) && !strncmp("SS  CAL ", (const char *) &buf[0x0088], 8))
		return 1;

	/* tram terror pirate */
	if ((len >= 0x3648 + 8) && !strncmp("SG NEPIE", (const char *) &buf[0x3648], 8))
		return 1;

	/* breath of fire 3 chinese */
	if (len > 0xa && buf[0x0007] == 0x1c && buf[0x0008] == 0x0a && buf[0x0009] == 0xb8 && buf[0x000a] == 0x0a)
		return 1;

	/*tetris pirate */
	if ((len >= 0x1cbe + 5) && !strncmp("@TTI>", (const char *) &buf[0x1cbe], 5))
		return 1;

	return 0;
}

/*************************************
 *  Loading a cart image *not* from
 *  softlist
 *************************************/

image_init_result base_md_cart_slot_device::load_nonlist()
{
	unsigned char *ROM;
	bool is_smd, is_md;
	uint32_t tmplen = length(), offset, len;
	std::vector<uint8_t> tmpROM(tmplen);

	// STEP 1: store a (possibly headered) copy of the file and determine its type (SMD? MD? BIN?)
	fread(&tmpROM[0], tmplen);
	is_smd = genesis_is_SMD(&tmpROM[0x200], tmplen - 0x200);
	is_md = (tmpROM[0x80] == 'E') && (tmpROM[0x81] == 'A') && (tmpROM[0x82] == 'M' || tmpROM[0x82] == 'G');

	// take header into account, if any
	offset = is_smd ? 0x200 : 0;

	// STEP 2: allocate space for the real copy of the game
	// if cart size is not (2^n * 64K), the system will see anyway that size so we need to alloc a bit more space
	len = m_cart->get_padded_size(tmplen - offset);

	// this contains an hack for SSF2: its current bankswitch code needs larger rom space to work
	m_cart->rom_alloc((len == 0x500000) ? 0x900000 : len, tag());

	// STEP 3: copy the game data in the appropriate way
	ROM = (unsigned char *)m_cart->get_rom_base();

	if (is_smd)
	{
		osd_printf_debug("SMD!\n");

		for (int ptr = 0; ptr < (tmplen - 0x200) / 0x2000; ptr += 2)
		{
			for (int x = 0; x < 0x2000; x++)
			{
				ROM[ptr * 0x2000 + x * 2 + 0] = tmpROM[0x200 + ((ptr + 1) * 0x2000) + x];
				ROM[ptr * 0x2000 + x * 2 + 1] = tmpROM[0x200 + ((ptr + 0) * 0x2000) + x];
			}
		}
	}
	else if (is_md)
	{
		osd_printf_debug("MD!\n");

		for (int ptr = 0; ptr < tmplen; ptr += 2)
		{
			ROM[ptr] = tmpROM[(tmplen >> 1) + (ptr >> 1)];
			ROM[ptr + 1] = tmpROM[(ptr >> 1)];
		}
	}
	else
	{
		osd_printf_debug("BIN!\n");

		fseek(0, SEEK_SET);
		fread(ROM, len);
	}

	// if we allocated a ROM larger that the file (e.g. due to uneven cart size), set remaining space to 0xff
	if (len > (tmplen - offset))
		memset(m_cart->get_rom_base() + (tmplen - offset)/2, 0xffff, (len - tmplen + offset)/2);


	// STEP 4: determine the cart type (to deal with sram/eeprom & pirate mappers)
	m_type = get_cart_type(ROM, tmplen - offset);

	// handle mirroring of ROM, unless it's SSF2 or Pier Solar
	if (m_type != SSF2 && m_type != PSOLAR)
		m_cart->rom_map_setup(len);


// CPU needs to access ROM as a ROM_REGION16_BE, so we need to compensate on LE machines
#ifdef LSB_FIRST
	unsigned char fliptemp;
	for (int ptr = 0; ptr < len; ptr += 2)
	{
		fliptemp = ROM[ptr];
		ROM[ptr] = ROM[ptr+1];
		ROM[ptr+1] = fliptemp;
	}
#endif

	return image_init_result::PASS;
}

/*-------------------------------------------------
 call_unload
 -------------------------------------------------*/

void base_md_cart_slot_device::call_unload()
{
	if (m_cart && m_cart->get_nvram_base() && m_cart->get_nvram_size())
		battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size());
}


void base_md_cart_slot_device::setup_custom_mappers()
{
	uint16_t *ROM16 = m_cart->get_rom_base();

	switch (m_type)
	{
		case SSF2:
			// copy the image in 0x400000-0x900000 and keep the beginning for bankswitch
			for (int x = 0x500000/2; x > 0; x--)
				ROM16[x + 0x400000/2 - 1] = ROM16[x - 1];
			for (int x = 0; x < 0x400000/2; x++)
				ROM16[x] = ROM16[x + 0x400000/2];
			break;
		case REDCL_EN:
			// decrypt
			for (int x = 0; x < 0x200000/2; x++)
				ROM16[x] = ROM16[x + 2] ^ 0x4040;
			break;
	}
}

void base_md_cart_slot_device::setup_nvram()
{
	uint8_t *ROM = (uint8_t *)m_cart->get_rom_base();
	m_cart->m_nvram_readonly = 0;
	m_cart->m_nvram_active = 0;
	m_cart->m_nvram_handlers_installed = 0;

	/* install SRAM & i2c handlers for the specific type of cart */
	switch (m_type)
	{
		// These types only come from fullpath loading
		case SEGA_SRAM_FULLPATH:
			m_cart->m_nvram_start = (ROM[0x1b5] << 24 | ROM[0x1b4] << 16 | ROM[0x1b7] << 8 | ROM[0x1b6]);
			m_cart->m_nvram_end = (ROM[0x1b9] << 24 | ROM[0x1b8] << 16 | ROM[0x1bb] << 8 | ROM[0x1ba]);
			logerror("SRAM detected from header: starting location %X - SRAM Length %X\n", m_cart->m_nvram_start, m_cart->m_nvram_end - m_cart->m_nvram_start + 1);

			// We assume at most 64k of SRAM. is this correct?
			if ((m_cart->m_nvram_start > m_cart->m_nvram_end) || ((m_cart->m_nvram_end - m_cart->m_nvram_start) >= 0x10000))
				m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff;

			if (m_cart->m_nvram_start & 1)
				m_cart->m_nvram_start -= 1;

			if (!(m_cart->m_nvram_end & 1))
				m_cart->m_nvram_end += 1;

			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			if (m_cart->m_rom_size <= m_cart->m_nvram_start)
				m_cart->m_nvram_active = 1;
			m_cart->m_nvram_handlers_installed = 1;
			// don't trust too much header?
			m_cart->m_nvram_start &= 0x3fffff;
			m_cart->m_nvram_end &= 0x3fffff;
			break;
		case SEGA_SRAM_FALLBACK:
			m_cart->m_nvram_start = 0x200000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff;
			logerror("No SRAM detected from header, using fallback SRAM in case this is a broken header\n");

			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			if (m_cart->m_rom_size <= m_cart->m_nvram_start)
				m_cart->m_nvram_active = 1;
			break;

		// These types only come from softlist loading
		case SEGA_SRAM:
		case SRAM_ARG96:
			m_cart->m_nvram_start = 0x200000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("sram") - 1;
			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			if (m_cart->m_rom_size <= m_cart->m_nvram_start)
				m_cart->m_nvram_active = 1;
			m_cart->m_nvram_handlers_installed = 1;
			break;
		case SEGA_FRAM:
			m_cart->m_nvram_start = 0x200000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("fram") - 1;
			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			m_cart->m_nvram_active = 1;
			m_cart->m_nvram_handlers_installed = 1;
			break;

		// These types might come from both (pending proper id routines)
		case HARDBALL95:
			m_cart->m_nvram_start = 0x300000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("sram") - 1;
			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			m_cart->m_nvram_active = 1;
			m_cart->m_nvram_handlers_installed = 1;
			break;
		case XINQIG:
			m_cart->m_nvram_start = 0x400000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff;
			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			m_cart->m_nvram_active = 1;
			m_cart->m_nvram_handlers_installed = 1;
			break;
		case BEGGARP:
			m_cart->m_nvram_start = 0x400000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff;
			m_cart->nvram_alloc(0x8000); // 32K mirrored
			m_cart->m_nvram_active = 1;
			break;
		case WUKONG:
			m_cart->m_nvram_start = 0x3c0000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + 0x3fff;
			m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1);
			m_cart->m_nvram_active = 1;
			break;
		case STARODYS:
			m_cart->m_nvram_start = 0x200000;
			m_cart->m_nvram_end = m_cart->m_nvram_start + 0xfffff;
			m_cart->nvram_alloc(0x8000/2); // 32K mirrored
			m_cart->m_nvram_active = 1;
			break;
		case NBA_JAM_ALT:
			m_cart->nvram_alloc(0x100);
			break;
	}
}



int base_md_cart_slot_device::get_cart_type(const uint8_t *ROM, uint32_t len)
{
	int type = SEGA_STD;

	/* Detect carts which need additional handlers */
	static const unsigned char smouse_sig[] = { 0x4d, 0xf9, 0x00, 0x40, 0x00, 0x02 },
	mjlover_sig[]   = { 0x13, 0xf9, 0x00, 0x40, 0x00, 0x00 }, // move.b  ($400000).l,($FFFF0C).l (partial)
	squir_sig[]     = { 0x26, 0x79, 0x00, 0xff, 0x00, 0xfa },
	bugsl_sig[]     = { 0x20, 0x12, 0x13, 0xc0, 0x00, 0xff },
	sbub_sig[]      = { 0x0c, 0x39, 0x00, 0x55, 0x00, 0x40 }, // cmpi.b  #$55,($400000).l
	lk3_sig[]       = { 0x0c, 0x01, 0x00, 0x30, 0x66, 0xe4 },
	sdk_sig[]       = { 0x48, 0xe7, 0xff, 0xfe, 0x52, 0x79 },
	redcliff_sig[]  = { 0x10, 0x39, 0x00, 0x40, 0x00, 0x04 }, // move.b  ($400004).l,d0
	redcl_en_sig[]  = { 0x50, 0x79, 0x40, 0x00, 0x40, 0x44 }, // move.b  ($400004).l,d0
	smb_sig[]       = { 0x20, 0x4d, 0x41, 0x52, 0x49, 0x4f },
	smb2_sig[]      = { 0x4e, 0xb9, 0x00, 0x0f, 0x25, 0x84 },
	kaiju_sig[]     = { 0x19, 0x7c, 0x00, 0x01, 0x00, 0x00 },
	chifi3_sig[]    = { 0xb6, 0x16, 0x66, 0x00, 0x00, 0x4a },
	lionk2_sig[]    = { 0x26, 0x79, 0x00, 0xff, 0x00, 0xf4 },
	rx3_sig[]       = { 0x66, 0x00, 0x00, 0x0e, 0x30, 0x3c },
	kof98_sig[]     = { 0x9b, 0xfc, 0x00, 0x00, 0x4a, 0x00 },
	s15in1_sig[]    = { 0x22, 0x3c, 0x00, 0xa1, 0x30, 0x00 },
	kof99_sig[]     = { 0x20, 0x3c, 0x30, 0x00, 0x00, 0xa1 }, // move.l  #$300000A1,d0
	radica_sig[]    = { 0x4e, 0xd0, 0x30, 0x39, 0x00, 0xa1 }, // jmp (a0) move.w ($a130xx),d0
	soulb_sig[]     = { 0x33, 0xfc, 0x00, 0x0c, 0x00, 0xff }, // move.w  #$C,($FF020A).l (what happens if check fails)
	s19in1_sig[]    = { 0x13, 0xc0, 0x00, 0xa1, 0x30, 0x38 },
	rockman_sig[]   = { 0xea, 0x80 };

	switch (len)
	{
		case 0x80000:
			if (!memcmp(&ROM[0x08c8], smouse_sig, sizeof(smouse_sig)))
				type = SMOUSE;

			if (!memcmp((char *)&ROM[0x7e30e], "SEGA", 4) ||
				!memcmp((char *)&ROM[0x7e100], "SEGA", 4) ||
				!memcmp((char *)&ROM[0x7e1e6], "SEGA", 4))
				type = REALTEC;

			if (!memcmp((char *)&ROM[0x0180], "GM T-50396", 10)) // NHLPA Hockey 93
				type = EA_NHLPA;

			if (!memcmp((char *)&ROM[0x0180], "GM MK-1215", 10)) // Evander Holyfield
				type = SEGA_EEPROM;
			break;

		case 0xc0000:

			if (!memcmp((char *)&ROM[0x0180], "GM G-4060 ", 8)) // Wonder Boy V
				type = SEGA_EEPROM;
			break;

		case 0x100000:
			if (!memcmp(&ROM[0x01b24], mjlover_sig, sizeof(mjlover_sig)))
				type = MJLOVER;

			if (!memcmp(&ROM[0x03b4], squir_sig, sizeof(squir_sig)))
				type = SQUIRRELK;

			if (!memcmp(&ROM[0xee0d0], bugsl_sig, sizeof(bugsl_sig)))
				type = BUGSLIFE;

			if (!memcmp((char *)&ROM[0x0172], "GAME : ELF WOR", 14))
				type = ELFWOR;

			if (!memcmp(&ROM[0x123e4], sbub_sig, sizeof(sbub_sig)))
				type = SBUBBOB;

			if (!memcmp((char *)&ROM[0x0180], "GM T-50176", 10)) // Rings of Power
				type = EA_NHLPA;

			if (!memcmp((char *)&ROM[0x0180], "MK 00001211-00", 14)) // Sports Talk Baseball
				type = SEGA_EEPROM;

			if (!memcmp((char *)&ROM[0x0180], "GM T-120096-", 12)) // Micro Machines 2
				type = CODE_MASTERS;

			if (!memcmp((char *)&ROM[0x0180], "GM T-120146-", 12)) // Brian Lara Cricket 96 / Shane Wayne Cricket 96
				type = BRIAN_LARA;

			if (!memcmp((char *)&ROM[0x0190], "OJKRPTBVFCA     ", 0x10)) // Micro Machines '96 / Military TODO: better way to recognize these?
				type = CODE_MASTERS;
			break;

		case 0x200000:
			if (!memcmp(&ROM[0x18c6], lk3_sig, sizeof(lk3_sig)))
				type = LIONK3;

			if (!memcmp(&ROM[0x220], sdk_sig, sizeof(sdk_sig)))
				type = LIONK3;

			if (!memcmp(&ROM[0xce560], redcliff_sig, sizeof(redcliff_sig)))
				type = REDCLIFF;

			if (!memcmp(&ROM[0xc8cb0], smb_sig, sizeof(smb_sig)))
				type = SMB;

			if (!memcmp(&ROM[0xf24d6], smb2_sig, sizeof(smb2_sig)))
				type = SMB2;

			if (!memcmp(&ROM[0x674e], kaiju_sig, sizeof(kaiju_sig)))
				type = KAIJU;

			if (!memcmp(&ROM[0x1780], chifi3_sig, sizeof(chifi3_sig)))
				type = CHINFIGHT3;

			if (!memcmp(&ROM[0x03c2], lionk2_sig, sizeof(lionk2_sig)))
				type = LIONK2;

			if (!memcmp(&ROM[0xc8b90], rx3_sig, sizeof(rx3_sig)))
				type = ROCKMANX3;

			if (!memcmp(&ROM[0x56ae2], kof98_sig, sizeof(kof98_sig)))
				type = KOF98;

			if (!memcmp(&ROM[0x17bb2], s15in1_sig, sizeof(s15in1_sig)))
				type = MC_PIRATE;

			if (!memcmp((char *)&ROM[0x0180], "GM T-081326 ", 12)) // NBA Jam
				type = NBA_JAM;

			if (!memcmp((char *)&ROM[0x0180], "GM MK-1228", 10)) // Greatest Heavyweight of the Ring
				type = SEGA_EEPROM;

			if ((!memcmp((char *)&ROM[0x0180], "GM T-12046", 10)) || // Mega Man
				(!memcmp((char *)&ROM[0x0180], "GM T-12053", 10) && !memcmp(&ROM[0x18e], rockman_sig, sizeof(rockman_sig)))) // / Rock Man (EEPROM version)
				type = SEGA_EEPROM;

			if (!memcmp((char *)&ROM[0x0150], "Virtua Racing", 13))
				type = SEGA_SVP;

			if (!memcmp((char *)&ROM[0x0180], "SF-004", 6)) // Star Odyssey
				type = STARODYS;

			break;

		case 0x200005:
			if (!memcmp(&ROM[0xce564], redcl_en_sig, sizeof(redcliff_sig)))
				type = REDCL_EN;
			break;

		case 0x220000:
			if (!memcmp((char *)&ROM[0x0180], "SF-002", 6)) // Legend of Wukong
				type = WUKONG;
			break;

		case 0x300000:
			if (!memcmp(&ROM[0x220], sdk_sig, sizeof(sdk_sig)))
				type = LIONK3;

			if (!memcmp(&ROM[0x1fd0d2], kof99_sig, sizeof(kof99_sig)))
				type = KOF99;

			if (!memcmp((char *)&ROM[0x0180], "GM T-81406", 10)) // NBA Jam TE
				type = NBA_JAM_TE;

			if (!memcmp((char *)&ROM[0x0180], "GM T-081276 ", 12)) // NFL Quarterback Club
				type = NBA_JAM_TE;

			break;

		case 0x400000:
			if (!memcmp(&ROM[0x3c031c], radica_sig, sizeof(radica_sig)) ||
				!memcmp(&ROM[0x3f031c], radica_sig, sizeof(radica_sig))) // ssf+gng + radica vol1
				type = RADICA;

			if (!memcmp(&ROM[0x028460], soulb_sig, sizeof(soulb_sig)))
				type = SOULBLAD;

			if (!memcmp(&ROM[0x1e700], s19in1_sig, sizeof(s19in1_sig)))
				type = MC_PIRATE;

			if (!memcmp((char *)&ROM[0x0180], "GM T-081586-", 12)) // NFL Quarterback Club 96
				type = NFL_QB_96;

			if (!memcmp((char *)&ROM[0x0180], "GM T-081576 ", 12)) // College Slam
				type = C_SLAM;

			if (!memcmp((char *)&ROM[0x0180], "GM T-81476", 10)) // Big Hurt Baseball
				type = C_SLAM;

			if (!memcmp((char *)&ROM[0x0180], "SF-001", 6)) // Beggar Prince
				type = BEGGARP;

			break;

		case 0x500000:
			if (!memcmp((char *)&ROM[0x0120], "SUPER STREET FIGHTER2 ", 22))
				type = SSF2;
			break;

		case 0x800000:
			if (!memcmp((char *)&ROM[0x0180], "GM T-574023-", 12)) // Pier Solar
				type = PSOLAR;
			break;

		default:
			break;
	}

	//check for SRAM among the general carts
	if (type == SEGA_STD)
	{
		// If the cart is not of a special type, we check the header for SRAM.
		if (ROM[0x1b1] == 'A' && ROM[0x1b0] == 'R')
		{
			uint32_t start = (ROM[0x1b4] << 24 | ROM[0x1b5] << 16 | ROM[0x1b6] << 8 | ROM[0x1b7]);
			uint32_t end = (ROM[0x1b8] << 24 | ROM[0x1b9] << 16 | ROM[0x1ba] << 8 | ROM[0x1bb]);
			// For some games using serial EEPROM, difference between SRAM end to start is 0 or 1.
			// Carts with EEPROM should have been already detected above, but better safe than sorry
			if (end - start < 2)
				type = SEGA_EEPROM;
			else
				type = SEGA_SRAM_FULLPATH;
		}
		else
		{
			// Unfortunately, there are ROMs without correct info in the header,
			// Hence, when loading from fullpath we do the SRAM mapping anyway...
			// but treat it in a custom way
			type = SEGA_SRAM_FALLBACK;
		}
	}

	return type;
}
/*-------------------------------------------------
 get default card software
 -------------------------------------------------*/

std::string base_md_cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
{
	if (hook.image_file())
	{
		const char *slot_string;
		uint32_t len = hook.image_file()->size(), offset = 0;
		std::vector<uint8_t> rom(len);
		int type;

		hook.image_file()->read(&rom[0], len);

		if (genesis_is_SMD(&rom[0x200], len - 0x200))
				offset = 0x200;

		type = get_cart_type(&rom[offset], len - offset);
		slot_string = md_get_slot(type);

		return std::string(slot_string);
	}
	else
		return software_get_default_slot("rom");
}



/*-------------------------------------------------
 read
 -------------------------------------------------*/

uint16_t base_md_cart_slot_device::read(offs_t offset)
{
	if (m_cart)
		return m_cart->read(offset);
	else
		return 0xffff;
}

uint16_t base_md_cart_slot_device::read_a13(offs_t offset)
{
	if (m_cart)
		return m_cart->read_a13(offset);
	else
		return 0xffff;
}

uint16_t base_md_cart_slot_device::read_a15(offs_t offset)
{
	if (m_cart)
		return m_cart->read_a15(offset);
	else
		return 0xffff;
}


/*-------------------------------------------------
 write
 -------------------------------------------------*/

void base_md_cart_slot_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
{
	if (m_cart)
		m_cart->write(offset, data, mem_mask);
}

void base_md_cart_slot_device::write_a13(offs_t offset, uint16_t data)
{
	if (m_cart)
		m_cart->write_a13(offset, data);
}

void base_md_cart_slot_device::write_a15(offs_t offset, uint16_t data)
{
	if (m_cart)
		m_cart->write_a15(offset, data);
}

/*-------------------------------------------------
 Image loading logging
 -------------------------------------------------*/

void base_md_cart_slot_device::file_logging(uint8_t *ROM8, uint32_t rom_len, uint32_t nvram_len)
{
	char console[16], copyright[16], domestic_name[48], overseas_name[48];
	char serial[14], io[16], modem[12], memo[40], country[16];
	uint32_t rom_start, rom_end, ram_start, ram_end, sram_start = 0, sram_end = 0;
	uint16_t checksum, csum = 0;
	bool valid_sram = false, is_pico = false;
	std::string ctrl(""), reg("");

	// LOG FILE DETAILS
	logerror("FILE DETAILS\n");
	logerror("============\n");
	logerror("Name: %s\n", basename());
	logerror("File Size: 0x%08x\n", !loaded_through_softlist() ? (int)length() : (int)get_software_region_length("rom"));
	logerror("Detected type: %s\n", md_get_slot(m_type));
	logerror("ROM (Allocated) Size: 0x%X\n", rom_len);
	logerror("NVRAM: %s\n", nvram_len ? "Yes" : "No");
	if (nvram_len)
		logerror("NVRAM (Allocated) Size: 0x%X\n", nvram_len);
	logerror("\n" );


	// LOG HEADER DETAILS
	if (rom_len < 0x200)
		return;

	for (int i = 0; i < 16; i++)
		console[i] = ROM8[0x100 + (i ^ 1)];
	if (!strncmp("SEGA PICO", console, 9))
		is_pico = true;
	for (int i = 0; i < 16; i++)
		copyright[i] = ROM8[0x110 + (i ^ 1)];
	for (int i = 0; i < 48; i++)
		domestic_name[i] = ROM8[0x120 + (i ^ 1)];
	for (int i = 0; i < 48; i++)
		overseas_name[i] = ROM8[0x150 + (i ^ 1)];
	for (int i = 0; i < 14; i++)
		serial[i] = ROM8[0x180 + (i ^ 1)];

	checksum = ROM8[0x18e] | (ROM8[0x18f] << 8);

	for (int i = 0; i < 16; i++)
	{
		io[i] = ROM8[0x190 + (i ^ 1)];
		if (io[i] == 'J')
			ctrl.append(" - Joypad 3 buttons [J]\n");
		if (io[i] == '6')
			ctrl.append(" - Joypad 6 buttons [6]\n");
	}

	rom_start = (ROM8[0x1a1] << 24 | ROM8[0x1a0] << 16 | ROM8[0x1a3] << 8 | ROM8[0x1a2]);
	rom_end = (ROM8[0x1a5] << 24 | ROM8[0x1a4] << 16 | ROM8[0x1a7] << 8 | ROM8[0x1a6]);
	ram_start =  (ROM8[0x1a9] << 24 | ROM8[0x1a8] << 16 | ROM8[0x1ab] << 8 | ROM8[0x1aa]);
	ram_end = (ROM8[0x1ad] << 24 | ROM8[0x1ac] << 16 | ROM8[0x1af] << 8 | ROM8[0x1ae]);
	if (ROM8[0x1b1] == 'R' && ROM8[0x1b0] == 'A')
	{
		valid_sram = true;
		sram_start = (ROM8[0x1b5] << 24 | ROM8[0x1b4] << 16 | ROM8[0x1b7] << 8 | ROM8[0x1b6]);
		sram_end = (ROM8[0x1b9] << 24 | ROM8[0x1b8] << 16 | ROM8[0x1bb] << 8 | ROM8[0x1ba]);
	}

	for (int i = 0; i < 12; i++)
		modem[i] = ROM8[0x1bc + (i ^ 1)];
	for (int i = 0; i < 40; i++)
		memo[i] = ROM8[0x1c8 + (i ^ 1)];
	for (int i = 0; i < 16; i++)
	{
		country[i] = ROM8[0x1f0 + (i ^ 1)];
		if (country[i] == 'J')
			reg.append(" - Japan [J]\n");
		if (country[i] == 'U')
			reg.append(" - USA [U]\n");
		if (country[i] == 'E')
			reg.append(" - Europe [E]\n");
	}

	// compute cart checksum to compare with expected one
	for (int i = 0x200; i < (rom_end + 1) && i < rom_len; i += 2)
	{
		csum += (ROM8[i] | (ROM8[i + 1] << 8));
		csum &= 0xffff;
	}

	logerror("INTERNAL HEADER\n");
	logerror("===============\n");
	logerror("Console: %.16s\n", console);
	logerror("Copyright String: %.16s\n", copyright);
	logerror(" - Manufacturer: %.4s\n", copyright + 3); // TODO: convert code to manufacturer name!
	logerror(" - Date: %.8s\n", copyright + 8);
	logerror("Name (domestic): %.48s\n", domestic_name);
	logerror("Name (overseas): %.48s\n", overseas_name);
	logerror("Serial String: %.14s\n", serial);
	if (!is_pico)
	{
		logerror(" - Type: %.2s (%s)\n", serial, !strncmp("GM", serial, 2) ? "Game" : "Unknown");
		logerror(" - Serial Code: %.8s\n", serial + 3);
		logerror(" - Revision: %.2s\n", serial + 12);
	}
	logerror("Checksum: %X\n", checksum);
	logerror(" - Calculated Checksum: %X\n", csum);
	logerror("Supported I/O Devices: %.16s\n%s", io, ctrl.c_str());
	logerror("Modem: %.12s\n", modem);
	logerror("Memo: %.40s\n", memo);
	logerror("Country: %.16s\n%s", country, reg.c_str());
	logerror("ROM Start:  0x%.8X\n", rom_start);
	logerror("ROM End:    0x%.8X\n", rom_end);
	logerror("RAM Start:  0x%.8X\n", ram_start);
	logerror("RAM End:    0x%.8X\n", ram_end);
	logerror("SRAM detected from header: %s\n", valid_sram ? "Yes" : "No");
	if (valid_sram)
	{
		logerror("SRAM Start: 0x%.8X\n", sram_start);
		logerror("SRAM End:   0x%.8X\n", sram_end);
	}
}