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