1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /***********************************************************************************************************
4 
5     Bandai Wonderswan / Wonderswan Color cart emulation
6     (through slot devices)
7 
8  ***********************************************************************************************************/
9 
10 
11 #include "emu.h"
12 #include "slot.h"
13 
14 //**************************************************************************
15 //  GLOBAL VARIABLES
16 //**************************************************************************
17 
18 DEFINE_DEVICE_TYPE(WS_CART_SLOT, ws_cart_slot_device, "ws_cart_slot", "Wonderswan Cartridge Slot")
19 
20 //**************************************************************************
21 //    Wonderswan Cartridges Interface
22 //**************************************************************************
23 
24 //-------------------------------------------------
25 //  device_ws_cart_interface - constructor
26 //-------------------------------------------------
27 
device_ws_cart_interface(const machine_config & mconfig,device_t & device)28 device_ws_cart_interface::device_ws_cart_interface(const machine_config &mconfig, device_t &device) :
29 	device_interface(device, "wswancart"),
30 	m_rom(nullptr),
31 	m_rom_size(0),
32 	m_bank_mask(0),
33 	m_has_rtc(false),
34 	m_is_rotated(false)
35 {
36 }
37 
38 
39 //-------------------------------------------------
40 //  ~device_ws_cart_interface - destructor
41 //-------------------------------------------------
42 
~device_ws_cart_interface()43 device_ws_cart_interface::~device_ws_cart_interface()
44 {
45 }
46 
47 //-------------------------------------------------
48 //  rom_alloc - alloc the space for the cart
49 //-------------------------------------------------
50 
rom_alloc(uint32_t size,const char * tag)51 void device_ws_cart_interface::rom_alloc(uint32_t size, const char *tag)
52 {
53 	if (m_rom == nullptr)
54 	{
55 		m_rom = device().machine().memory().region_alloc(std::string(tag).append(WSSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base();
56 		m_rom_size = size;
57 		m_bank_mask = ((m_rom_size >> 16) - 1);
58 	}
59 }
60 
61 
62 //-------------------------------------------------
63 //  nvram_alloc - alloc the space for the ram
64 //-------------------------------------------------
65 
nvram_alloc(uint32_t size)66 void device_ws_cart_interface::nvram_alloc(uint32_t size)
67 {
68 	m_nvram.resize(size);
69 }
70 
71 
72 //**************************************************************************
73 //  LIVE DEVICE
74 //**************************************************************************
75 
76 //-------------------------------------------------
77 //  ws_cart_slot_device - constructor
78 //-------------------------------------------------
ws_cart_slot_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)79 ws_cart_slot_device::ws_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
80 	device_t(mconfig, WS_CART_SLOT, tag, owner, clock),
81 	device_image_interface(mconfig, *this),
82 	device_single_card_slot_interface<device_ws_cart_interface>(mconfig, *this),
83 	m_type(WS_STD),
84 	m_cart(nullptr)
85 {
86 }
87 
88 
89 //-------------------------------------------------
90 //  ws_cart_slot_device - destructor
91 //-------------------------------------------------
92 
~ws_cart_slot_device()93 ws_cart_slot_device::~ws_cart_slot_device()
94 {
95 }
96 
97 //-------------------------------------------------
98 //  device_start - device-specific startup
99 //-------------------------------------------------
100 
device_start()101 void ws_cart_slot_device::device_start()
102 {
103 	m_cart = get_card_device();
104 }
105 
106 
107 //-------------------------------------------------
108 //  WSWAN PCB
109 //-------------------------------------------------
110 
111 struct ws_slot
112 {
113 	int                     pcb_id;
114 	const char              *slot_option;
115 };
116 
117 // Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
118 static const ws_slot slot_list[] =
119 {
120 	{ WS_STD,      "ws_rom" },
121 	{ WS_SRAM,     "ws_sram" },
122 	{ WS_EEPROM,   "ws_eeprom" }
123 };
124 
ws_get_pcb_id(const char * slot)125 static int ws_get_pcb_id(const char *slot)
126 {
127 	for (auto & elem : slot_list)
128 	{
129 		if (!core_stricmp(elem.slot_option, slot))
130 			return elem.pcb_id;
131 	}
132 
133 	return 0;
134 }
135 
ws_get_slot(int type)136 static const char *ws_get_slot(int type)
137 {
138 	for (auto & elem : slot_list)
139 	{
140 		if (elem.pcb_id == type)
141 			return elem.slot_option;
142 	}
143 
144 	return "std";
145 }
146 
147 
148 /*-------------------------------------------------
149  call load
150  -------------------------------------------------*/
151 
call_load()152 image_init_result ws_cart_slot_device::call_load()
153 {
154 	if (m_cart)
155 	{
156 		uint8_t *ROM;
157 		uint32_t size = !loaded_through_softlist() ? length() : get_software_region_length("rom");
158 		uint32_t nvram_size = 0;
159 
160 		m_cart->rom_alloc(size, tag());
161 		ROM = m_cart->get_rom_base();
162 
163 		if (!loaded_through_softlist())
164 			fread(ROM, size);
165 		else
166 			memcpy(ROM, get_software_region("rom"), size);
167 
168 		if (!loaded_through_softlist())
169 		{
170 			int chunks = size / 0x10000;
171 			// get cart type and nvram length
172 			m_type = get_cart_type(ROM, size, nvram_size);
173 
174 			if (ROM[(chunks - 1) * 0x10000 + 0xfffd])
175 				m_cart->set_has_rtc(true);
176 			if (ROM[(chunks - 1) * 0x10000 + 0xfffc] & 0x01)
177 				m_cart->set_is_rotated(true);
178 		}
179 		else
180 		{
181 			const char *pcb_name = get_feature("slot");
182 			if (pcb_name)
183 				m_type = ws_get_pcb_id(pcb_name);
184 
185 			if (m_type == WS_SRAM)
186 				nvram_size = get_software_region_length("sram");
187 			if (m_type == WS_EEPROM)
188 				nvram_size = get_software_region_length("eeprom");
189 
190 			if (get_feature("rtc"))
191 			{
192 				if (!core_stricmp(get_feature("rtc"), "yes"))
193 					m_cart->set_has_rtc(true);
194 			}
195 			if (get_feature("rotated"))
196 			{
197 				if (!core_stricmp(get_feature("rotated"), "yes"))
198 					m_cart->set_is_rotated(true);
199 			}
200 		}
201 
202 		//printf("Type: %s\n", ws_get_slot(m_type));
203 
204 		if (nvram_size)
205 		{
206 			// allocate NVRAM
207 			m_cart->nvram_alloc(nvram_size);
208 			// and load possible battery save
209 			battery_load(m_cart->get_nvram_base(), m_cart->get_nvram_size(), 0x00);
210 		}
211 
212 		internal_header_logging(ROM, ((size >> 16) - 1) << 16, size);
213 	}
214 
215 	return image_init_result::PASS;
216 }
217 
218 /*-------------------------------------------------
219  call_unload
220  -------------------------------------------------*/
221 
call_unload()222 void ws_cart_slot_device::call_unload()
223 {
224 	if (m_cart && m_cart->get_nvram_base() && m_cart->get_nvram_size())
225 		battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size());
226 }
227 
228 
229 /*-------------------------------------------------
230  get cart type from cart file
231  -------------------------------------------------*/
232 
get_cart_type(const uint8_t * ROM,uint32_t len,uint32_t & nvram_len) const233 int ws_cart_slot_device::get_cart_type(const uint8_t *ROM, uint32_t len, uint32_t &nvram_len) const
234 {
235 	int chunks = len / 0x10000;
236 	int type = WS_STD;
237 
238 	switch (ROM[(chunks - 1) * 0x10000 + 0xfffb])
239 	{
240 		case 0x00:
241 			break;
242 		case 0x01:  // SRAM 64Kbit
243 			type = WS_SRAM;
244 			nvram_len = 0x2000;
245 			break;
246 		case 0x02:  // SRAM 256Kbit
247 			type = WS_SRAM;
248 			nvram_len = 0x8000;
249 			break;
250 		case 0x05:  // SRAM 512Kbit
251 			type = WS_SRAM;
252 			nvram_len = 0x10000;
253 			break;
254 		case 0x03:  // SRAM 1Mbit
255 			type = WS_SRAM;
256 			nvram_len = 0x20000;
257 			break;
258 		case 0x04:  // SRAM 2Mbit
259 			type = WS_SRAM;
260 			nvram_len = 0x40000;
261 			break;
262 		case 0x10:  // EEPROM 1Kbit
263 			type = WS_EEPROM;
264 			nvram_len = 0x80;
265 			break;
266 		case 0x50:  // EEPROM 8Kbit
267 			type = WS_EEPROM;
268 			nvram_len = 0x400;
269 			break;
270 		case 0x20:  // EEPROM 16Kbit
271 			type = WS_EEPROM;
272 			nvram_len = 0x800;
273 			break;
274 		default:
275 			printf("Unknown RAM size [0x%X]\n", ROM[(chunks - 1) * 0x10000 + 0xfffb]);
276 			logerror("Unknown RAM size [0x%X]\n", ROM[(chunks - 1) * 0x10000 + 0xfffb]);
277 			break;
278 	}
279 
280 	return type;
281 }
282 
283 /*-------------------------------------------------
284  get default card software
285  -------------------------------------------------*/
286 
get_default_card_software(get_default_card_software_hook & hook) const287 std::string ws_cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
288 {
289 	if (hook.image_file())
290 	{
291 		const char *slot_string;
292 		uint32_t size = hook.image_file()->size();
293 		std::vector<uint8_t> rom(size);
294 		int type;
295 		uint32_t nvram;
296 
297 		hook.image_file()->read(&rom[0], size);
298 
299 		// nvram size is not really used here, but we set it up nevertheless
300 		type = get_cart_type(&rom[0], size, nvram);
301 		slot_string = ws_get_slot(type);
302 
303 		//printf("type: %s\n", slot_string);
304 
305 		return std::string(slot_string);
306 	}
307 
308 	return software_get_default_slot("ws_rom");
309 }
310 
311 /*-------------------------------------------------
312  read_rom20
313  -------------------------------------------------*/
314 
read_rom20(offs_t offset)315 uint8_t ws_cart_slot_device::read_rom20(offs_t offset)
316 {
317 	if (m_cart)
318 		return m_cart->read_rom20(offset);
319 	else
320 		return 0xff;
321 }
322 
323 /*-------------------------------------------------
324  read_rom30
325  -------------------------------------------------*/
326 
read_rom30(offs_t offset)327 uint8_t ws_cart_slot_device::read_rom30(offs_t offset)
328 {
329 	if (m_cart)
330 		return m_cart->read_rom30(offset);
331 	else
332 		return 0xff;
333 }
334 
335 /*-------------------------------------------------
336  read_rom40
337  -------------------------------------------------*/
338 
read_rom40(offs_t offset)339 uint8_t ws_cart_slot_device::read_rom40(offs_t offset)
340 {
341 	if (m_cart)
342 		return m_cart->read_rom40(offset);
343 	else
344 		return 0xff;
345 }
346 
347 /*-------------------------------------------------
348  read_ram
349  -------------------------------------------------*/
350 
read_ram(offs_t offset)351 uint8_t ws_cart_slot_device::read_ram(offs_t offset)
352 {
353 	if (m_cart)
354 		return m_cart->read_ram(offset);
355 	else
356 		return 0xff;
357 }
358 
359 /*-------------------------------------------------
360  write_ram
361  -------------------------------------------------*/
362 
write_ram(offs_t offset,uint8_t data)363 void ws_cart_slot_device::write_ram(offs_t offset, uint8_t data)
364 {
365 	if (m_cart)
366 		m_cart->write_ram(offset, data);
367 }
368 
369 /*-------------------------------------------------
370  read_io
371  -------------------------------------------------*/
372 
read_io(offs_t offset)373 uint8_t ws_cart_slot_device::read_io(offs_t offset)
374 {
375 	if (m_cart)
376 		return m_cart->read_io(offset);
377 	else
378 		return 0xff;
379 }
380 
381 /*-------------------------------------------------
382  write_io
383  -------------------------------------------------*/
384 
write_io(offs_t offset,uint8_t data)385 void ws_cart_slot_device::write_io(offs_t offset, uint8_t data)
386 {
387 	if (m_cart)
388 		m_cart->write_io(offset, data);
389 }
390 
391 
392 
393 /*-------------------------------------------------
394  Internal header logging
395  -------------------------------------------------*/
396 
397 static const char *const sram_str[] = { "none", "64Kbit SRAM", "256Kbit SRAM", "512Kbit SRAM", "1Mbit SRAM", "2Mbit SRAM" };
398 static const char *const eeprom_str[] = { "none", "1Kbit EEPROM", "16Kbit EEPROM", "Unknown", "Unknown", "8Kbit EEPROM" };
399 static const char *const romsize_str[] = { "Unknown", "Unknown", "4Mbit", "8Mbit", "16Mbit", "Unknown", "32Mbit", "Unknown", "64Mbit", "128Mbit" };
400 
internal_header_logging(uint8_t * ROM,uint32_t offs,uint32_t len)401 void ws_cart_slot_device::internal_header_logging(uint8_t *ROM, uint32_t offs, uint32_t len)
402 {
403 	int sum = 0, banks = len / 0x10000;
404 	uint8_t romsize, ramtype, ramsize;
405 	romsize = ROM[offs + 0xfffa];
406 	ramtype = (ROM[offs + 0xfffb] & 0xf0) ? 1 : 0;  // 1 = EEPROM, 0 = SRAM
407 	ramsize = ramtype ? ((ROM[offs + 0xfffb] & 0xf0) >> 4) : (ROM[offs + 0xfffb] & 0x0f);
408 
409 
410 	logerror( "ROM DETAILS\n" );
411 	logerror( "===========\n\n" );
412 	logerror("\tDeveloper ID: %X\n", ROM[offs + 0xfff6]);
413 	logerror("\tMinimum system: %s\n", ROM[offs + 0xfff7] ? "WonderSwan Color" : "WonderSwan");
414 	logerror("\tCart ID: %X\n", ROM[offs + 0xfff8]);
415 	logerror("\tROM size: %s\n", romsize_str[romsize]);
416 	if (ramtype)
417 		logerror("\tEEPROM size: %s\n", (ramsize < 6) ? eeprom_str[ramsize] : "Unknown");
418 	else
419 		logerror("\tSRAM size: %s\n", (ramsize < 6) ? sram_str[ramsize] : "Unknown");
420 	logerror("\tFeatures: %X\n", ROM[offs + 0xfffc]);
421 	logerror("\tRTC: %s\n", ROM[offs + 0xfffd] ? "yes" : "no");
422 	for (int i = 0; i < banks; i++)
423 	{
424 		for (int count = 0; count < 0x10000; count++)
425 		{
426 			sum += ROM[(i * 0x10000) + count];
427 		}
428 	}
429 	sum -= ROM[offs + 0xffff];
430 	sum -= ROM[offs + 0xfffe];
431 	sum &= 0xffff;
432 	logerror("\tChecksum: %.2X%.2X (calculated: %04X)\n", ROM[offs + 0xffff], ROM[offs + 0xfffe], sum);
433 }
434