1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 /***********************************************************************************************************
4
5 BS-X Satellaview cartridge emulation (for SNES/SFC)
6
7 ***********************************************************************************************************/
8
9
10 // TODO: Emulate FLASH memory... (possibly using flash device?)
11
12
13 #include "emu.h"
14 #include "bsx.h"
15
16
17 //-------------------------------------------------
18 // sns_rom_bsx_device - constructor
19 //-------------------------------------------------
20
21 DEFINE_DEVICE_TYPE(SNS_ROM_BSX, sns_rom_bsx_device, "sns_rom_bsx", "SNES BS-X Cart")
22 DEFINE_DEVICE_TYPE(SNS_LOROM_BSX, sns_rom_bsxlo_device, "sns_rom_bsxlo", "SNES Cart (LoROM) + BS-X slot")
23 DEFINE_DEVICE_TYPE(SNS_HIROM_BSX, sns_rom_bsxhi_device, "sns_rom_bsxhi", "SNES Cart (HiROM) + BS-X slot")
24 DEFINE_DEVICE_TYPE(SNS_BSMEMPAK, sns_rom_bsmempak_device, "sns_bsmempak", "SNES BS-X Memory packs")
25
26
sns_rom_bsx_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)27 sns_rom_bsx_device::sns_rom_bsx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
28 : sns_rom_device(mconfig, type, tag, owner, clock)
29 , m_base_unit(nullptr)
30 , access_00_1f(0)
31 , access_80_9f(0)
32 , access_40_4f(0)
33 , access_50_5f(0)
34 , access_60_6f(0)
35 , rom_access(0)
36 , m_slot(*this, "bs_slot")
37 {
38 }
39
sns_rom_bsx_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)40 sns_rom_bsx_device::sns_rom_bsx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
41 : sns_rom_bsx_device(mconfig, SNS_ROM_BSX, tag, owner, clock)
42 {
43 }
44
sns_rom_bsxlo_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)45 sns_rom_bsxlo_device::sns_rom_bsxlo_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
46 : sns_rom_device(mconfig, SNS_LOROM_BSX, tag, owner, clock)
47 , m_slot(*this, "bs_slot")
48 {
49 }
50
sns_rom_bsxhi_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)51 sns_rom_bsxhi_device::sns_rom_bsxhi_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
52 : sns_rom21_device(mconfig, SNS_HIROM_BSX, tag, owner, clock)
53 , m_slot(*this, "bs_slot")
54 {
55 }
56
sns_rom_bsmempak_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)57 sns_rom_bsmempak_device::sns_rom_bsmempak_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
58 : sns_rom_device(mconfig, SNS_BSMEMPAK, tag, owner, clock)
59 , m_command(0), m_write_old(0), m_write_new(0), m_flash_enable(0), m_read_enable(0), m_write_enable(0)
60 {
61 }
62
63
device_start()64 void sns_rom_bsx_device::device_start()
65 {
66 m_base_unit = std::make_unique<bsx_base>(machine());
67 m_base_unit->init();
68
69 memset(m_cart_regs, 0x00, sizeof(m_cart_regs));
70 m_cart_regs[7] = 0x80;
71 m_cart_regs[8] = 0x80;
72 access_update();
73
74 save_item(NAME(m_cart_regs));
75 save_item(NAME(access_00_1f));
76 save_item(NAME(access_80_9f));
77 save_item(NAME(access_40_4f));
78 save_item(NAME(access_50_5f));
79 save_item(NAME(access_60_6f));
80 save_item(NAME(rom_access));
81 save_item(NAME(m_pram));
82 }
83
device_reset()84 void sns_rom_bsx_device::device_reset()
85 {
86 memset(m_pram, 0xff, sizeof(m_pram));
87 }
88
device_start()89 void sns_rom_bsxlo_device::device_start()
90 {
91 }
92
device_start()93 void sns_rom_bsxhi_device::device_start()
94 {
95 }
96
device_start()97 void sns_rom_bsmempak_device::device_start()
98 {
99 save_item(NAME(m_command));
100 save_item(NAME(m_write_old));
101 save_item(NAME(m_write_new));
102 save_item(NAME(m_flash_enable));
103 save_item(NAME(m_read_enable));
104 save_item(NAME(m_write_enable));
105 }
106
device_reset()107 void sns_rom_bsmempak_device::device_reset()
108 {
109 m_command = 0;
110 m_write_old = 0;
111 m_write_new = 0;
112
113 m_flash_enable = 0;
114 m_read_enable = 0;
115 m_write_enable = 0;
116 }
117
118
119
120 // BS-X Base Unit emulation, to be device-fied ?
121
bsx_base(running_machine & machine)122 sns_rom_bsx_device::bsx_base::bsx_base(running_machine &machine)
123 : r2192_minute(0), m_machine(machine)
124 {
125 m_machine.save().save_item(regs, "SNES_BSX/regs");
126 m_machine.save().save_item(r2192_counter, "SNES_BSX/r2192_counter");
127 m_machine.save().save_item(r2192_hour, "SNES_BSX/r2192_hour");
128 m_machine.save().save_item(r2192_second, "SNES_BSX/r2192_second");
129 }
130
init()131 void sns_rom_bsx_device::bsx_base::init()
132 {
133 std::fill(std::begin(regs), std::end(regs), 0);
134 r2192_counter = 0;
135 r2192_hour = 0;
136 r2192_minute = 0;
137 r2192_second = 0;
138 }
139
140
read(uint32_t offset)141 uint8_t sns_rom_bsx_device::bsx_base::read(uint32_t offset)
142 {
143 offset &= 0xffff;
144 if (offset < 0x2188 || offset >= 0x21a0)
145 {
146 osd_printf_debug("BS-X Base Unit reg read outside correct range!\n");
147 return 0x00;
148 }
149
150 switch (offset)
151 {
152 // no 218b? no 218d? no 2191? no 2195? no 219a-219f?
153 case 0x2192:
154 {
155 uint8_t counter = r2192_counter++;
156 if (r2192_counter >= 18)
157 r2192_counter = 0;
158
159 if (counter == 0)
160 {
161 system_time curtime, *systime = &curtime;
162 m_machine.current_datetime(curtime);
163 r2192_hour = systime->local_time.hour;
164 r2192_minute = systime->local_time.minute;
165 r2192_second = systime->local_time.second;
166 }
167
168 switch (counter)
169 {
170 case 0: return 0x00; //???
171 case 1: return 0x00; //???
172 case 2: return 0x00; //???
173 case 3: return 0x00; //???
174 case 4: return 0x00; //???
175 case 5: return 0x01;
176 case 6: return 0x01;
177 case 7: return 0x00;
178 case 8: return 0x00;
179 case 9: return 0x00;
180 case 10: return r2192_second;
181 case 11: return r2192_minute;
182 case 12: return r2192_hour;
183 case 13: return 0x00; //???
184 case 14: return 0x00; //???
185 case 15: return 0x00; //???
186 case 16: return 0x00; //???
187 case 17: return 0x00; //???
188 }
189 }
190 break;
191
192 case 0x2193:
193 return regs[offset - 0x2188] & ~0x0c;
194
195 default:
196 return regs[offset - 0x2188];
197 }
198
199 return 0x00;
200 }
201
202
write(uint32_t offset,uint8_t data)203 void sns_rom_bsx_device::bsx_base::write(uint32_t offset, uint8_t data)
204 {
205 offset &= 0xffff;
206 if (offset < 0x2188 || offset >= 0x21a0)
207 {
208 osd_printf_debug("BS-X Base Unit reg write outside correct range!\n");
209 return;
210 }
211
212 switch(offset)
213 {
214 // no 218d? no 2190? no 2195? no 2196? no 2198? no 219a-219f?
215 case 0x218f:
216 regs[6] >>= 1; // 0x218e
217 regs[6] = regs[7] - regs[6]; // 0x218f - 0x218e
218 regs[7] >>= 1; // 0x218f
219 break;
220
221 case 0x2191:
222 regs[offset - 0x2188] = data;
223 r2192_counter = 0;
224 break;
225
226 case 0x2192:
227 regs[8] = data; // sets 0x2190
228 break;
229
230 default:
231 regs[offset - 0x2188] = data;
232 break;
233 }
234 }
235
236
bsx_cart(device_slot_interface & device)237 static void bsx_cart(device_slot_interface &device)
238 {
239 device.option_add_internal("bsmempak", SNS_BSMEMPAK);
240 }
241
242
243 //-------------------------------------------------
244 // device_add_mconfig - add device configuration
245 //-------------------------------------------------
246
device_add_mconfig(machine_config & config)247 void sns_rom_bsx_device::device_add_mconfig(machine_config &config)
248 {
249 SNS_BSX_CART_SLOT(config, m_slot, bsx_cart, nullptr);
250 }
251
device_add_mconfig(machine_config & config)252 void sns_rom_bsxlo_device::device_add_mconfig(machine_config &config)
253 {
254 SNS_BSX_CART_SLOT(config, m_slot, bsx_cart, nullptr);
255 }
256
device_add_mconfig(machine_config & config)257 void sns_rom_bsxhi_device::device_add_mconfig(machine_config &config)
258 {
259 SNS_BSX_CART_SLOT(config, m_slot, bsx_cart, nullptr);
260 }
261
262
263 /*-------------------------------------------------
264 mapper specific handlers
265 -------------------------------------------------*/
266
267 // BS-X base + cart
268
access_update()269 void sns_rom_bsx_device::access_update()
270 {
271 access_00_1f = BIT(m_cart_regs[0x07], 7);
272 access_40_4f = !BIT(m_cart_regs[0x05], 7);
273 access_50_5f = !BIT(m_cart_regs[0x06], 7);
274 access_60_6f = BIT(m_cart_regs[0x03], 7);
275 access_80_9f = BIT(m_cart_regs[0x08], 7);
276 if (BIT(m_cart_regs[0x01], 7))
277 rom_access = 0;
278 else
279 {
280 // rom_access = BIT(m_cart_regs[0x02], 7) + 1;
281 rom_access = 1; // for whatever reason bsxsore changes access mode here and then fails to read the ROM properly!
282 printf("rom_access %s\n", !BIT(m_cart_regs[0x02], 7) ? "Lo" : "Hi");
283 }
284 }
285
read_l(offs_t offset)286 uint8_t sns_rom_bsx_device::read_l(offs_t offset)
287 {
288 if (offset < 0x200000 && access_00_1f)
289 {
290 // 0x00-0x1f:0x8000-0xffff -> CART
291 if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
292 return m_slot->m_cart->read_l(offset);
293 }
294 if (offset >= 0x200000 && offset < 0x400000)
295 {
296 // 0x20-0x3f:0x6000-0x7fff -> PRAM
297 if ((offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)
298 return m_pram[offset & 0xffff];
299 }
300 if (offset >= 0x400000 && offset < 0x500000 && access_40_4f)
301 {
302 // 0x40-0x4f:0x0000-0xffff -> PRAM
303 return m_pram[offset & 0x7ffff];
304 }
305 if (offset >= 0x500000 && offset < 0x600000 && access_50_5f)
306 {
307 // 0x50-0x5f:0x0000-0xffff -> PRAM
308 return m_pram[offset & 0x7ffff];
309 }
310 if (offset >= 0x600000 && offset < 0x700000 && access_60_6f)
311 {
312 // 0x60-0x6f:0x0000-0xffff -> PRAM
313 return m_pram[offset & 0x7ffff];
314 }
315 if (offset >= 0x700000 && offset < 0x780000)
316 {
317 // 0x70-0x77:0x0000-0xffff -> PRAM
318 return m_pram[offset & 0x7ffff];
319 }
320
321 // if not in any of the cases above...
322 //$00-3f|80-bf:8000-ffff
323 //$40-7f|c0-ff:0000-ffff
324 if (!rom_access)
325 return m_pram[offset & 0x7ffff];
326 else
327 {
328 int bank = (rom_access == 1) ? (offset / 0x10000) : (offset / 0x8000);
329 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
330 }
331
332 // never executed
333 //return 0x00;
334 }
335
336
read_h(offs_t offset)337 uint8_t sns_rom_bsx_device::read_h(offs_t offset)
338 {
339 if (offset < 0x200000 && access_80_9f)
340 {
341 // 0x80-0x9f:0x8000-0xffff -> CART
342 if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
343 return m_slot->m_cart->read_l(offset);
344 }
345
346 // if not in any of the cases above...
347 //$00-3f|80-bf:8000-ffff
348 //$40-7f|c0-ff:0000-ffff
349 if (!rom_access)
350 return m_pram[offset & 0x7ffff];
351 else
352 {
353 int bank = (rom_access == 1) ? (offset / 0x10000) : (offset / 0x8000);
354 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
355 }
356
357 // never executed
358 //return 0x00;
359 }
360
write_l(offs_t offset,uint8_t data)361 void sns_rom_bsx_device::write_l(offs_t offset, uint8_t data)
362 {
363 if (offset < 0x200000 && access_00_1f)
364 {
365 // write to cart...
366 return;
367 }
368 if (offset >= 0x200000 && offset < 0x400000)
369 {
370 // 0x20-0x3f:0x6000-0x7fff -> PRAM
371 if ((offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)
372 m_pram[offset & 0xffff] = data;
373 }
374 if (offset >= 0x400000 && offset < 0x500000 && access_40_4f)
375 {
376 // 0x40-0x4f:0x0000-0xffff -> PRAM
377 m_pram[offset & 0x7ffff] = data;
378 }
379 if (offset >= 0x500000 && offset < 0x600000 && access_50_5f)
380 {
381 // 0x50-0x5f:0x0000-0xffff -> PRAM
382 m_pram[offset & 0x7ffff] = data;
383 }
384 if (offset >= 0x600000 && offset < 0x700000 && access_60_6f)
385 {
386 // 0x60-0x6f:0x0000-0xffff -> PRAM
387 m_pram[offset & 0x7ffff] = data;
388 }
389 if (offset >= 0x700000 && offset < 0x780000)
390 {
391 // 0x70-0x77:0x0000-0xffff -> PRAM
392 m_pram[offset & 0x7ffff] = data;
393 }
394
395 // if not in any of the cases above...
396 //$00-3f|80-bf:8000-ffff
397 //$40-7f|c0-ff:0000-ffff
398 if (!rom_access)
399 m_pram[offset & 0x7ffff] = data;
400 }
401
402
write_h(offs_t offset,uint8_t data)403 void sns_rom_bsx_device::write_h(offs_t offset, uint8_t data)
404 {
405 if (offset < 0x200000 && access_80_9f)
406 {
407 // write to cart...
408 return;
409 }
410
411 // if not in any of the cases above...
412 //$00-3f|80-bf:8000-ffff
413 //$40-7f|c0-ff:0000-ffff
414 if (!rom_access)
415 m_pram[offset & 0x7ffff] = data;
416 }
417
418
chip_read(offs_t offset)419 uint8_t sns_rom_bsx_device::chip_read(offs_t offset)
420 {
421 if ((offset & 0xffff) >= 0x2188 && (offset & 0xffff) < 0x21a0)
422 return m_base_unit->read(offset & 0xffff);
423
424 if ((offset & 0xf0ffff) == 0x005000) //$[00-0f]:5000 reg access
425 {
426 uint8_t n = (offset >> 16) & 0x0f;
427 return m_cart_regs[n];
428 }
429
430 if ((offset & 0xf8f000) == 0x105000) //$[10-17]:[5000-5fff] SRAM access
431 {
432 return m_nvram[((offset >> 16) & 7) * 0x1000 + (offset & 0xfff)];
433 }
434
435 return 0x00;
436 }
437
chip_write(offs_t offset,uint8_t data)438 void sns_rom_bsx_device::chip_write(offs_t offset, uint8_t data)
439 {
440 if ((offset & 0xffff) >= 0x2188 && (offset & 0xffff) < 0x21a0)
441 m_base_unit->write(offset & 0xffff, data);
442
443 if ((offset & 0xf0ffff) == 0x005000) //$[00-0f]:5000 reg access
444 {
445 uint8_t n = (offset >> 16) & 0x0f;
446 m_cart_regs[n] = data;
447 if (n == 0x0e && data & 0x80)
448 access_update();
449 }
450
451 if ((offset & 0xf8f000) == 0x105000) //$[10-17]:[5000-5fff] SRAM access
452 {
453 m_nvram[((offset >> 16) & 7) * 0x1000 + (offset & 0xfff)] = data;
454 }
455 }
456
457
458 // LoROM cart w/BS-X slot
459
read_l(offs_t offset)460 uint8_t sns_rom_bsxlo_device::read_l(offs_t offset)
461 {
462 if (offset < 0x400000)
463 {
464 int bank = offset / 0x10000;
465 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
466 }
467 // nothing [40-6f]
468 // RAM [70-7f]
469 return 0x00;
470 }
471
read_h(offs_t offset)472 uint8_t sns_rom_bsxlo_device::read_h(offs_t offset)
473 {
474 if (offset < 0x400000)
475 {
476 int bank = offset / 0x10000;
477 if (offset < 0x200000)
478 bank += 64;
479 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
480 }
481 else if (offset < 0x700000)
482 {
483 if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
484 return m_slot->m_cart->read_h(offset);
485 }
486 // RAM [70-7f]
487 return 0x00;
488 }
489
490
491 // HiROM cart w/BS-X slot
492
read_l(offs_t offset)493 uint8_t sns_rom_bsxhi_device::read_l(offs_t offset)
494 {
495 return read_h(offset);
496 }
497
read_h(offs_t offset)498 uint8_t sns_rom_bsxhi_device::read_h(offs_t offset)
499 {
500 if (offset < 0x200000 && (offset & 0xffff) >= 0x8000)
501 {
502 int bank = offset / 0x8000;
503 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
504 }
505 if (offset >= 0x200000 && offset < 0x400000)
506 {
507 if (m_slot->m_cart && m_slot->m_cart->get_rom_size() && (offset & 0xffff) >= 0x8000)
508 return m_slot->m_cart->read_h(offset);
509 }
510 if (offset >= 0x400000 && offset < 0x600000)
511 {
512 // TODO: Ongaku Tsukuru Kanadeeru does not like accesses in 0x0000-0x8000 here... investigate...
513 int bank = offset / 0x8000;
514 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
515 }
516 if (offset >= 0x600000)
517 {
518 if (m_slot->m_cart && m_slot->m_cart->get_rom_size())
519 return m_slot->m_cart->read_h(offset);
520 }
521 return 0xff;
522 }
523
524 /*-------------------------------------------------
525 BS-X Memory Packs
526 -------------------------------------------------*/
527
528 // Here we're cheating a bit, for the moment, to avoid the need of BSX mempacks as a completely different device
529 // which would require separate loading routines
530 // Hence, we use low read handler for ROM access in the 0x8000-0xffff range (i.e. mempack mapped as LoROM) and
531 // hi read handler for ROM access in the 0x0000-0xffff range (i.e. mempack mapped as HiROM)...
532
read_l(offs_t offset)533 uint8_t sns_rom_bsmempak_device::read_l(offs_t offset)
534 {
535 int bank = offset / 0x10000;
536 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
537 }
538
read_h(offs_t offset)539 uint8_t sns_rom_bsmempak_device::read_h(offs_t offset)
540 {
541 int bank = offset / 0x8000;
542 return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)];
543 }
544
write_l(offs_t offset,uint8_t data)545 void sns_rom_bsmempak_device::write_l(offs_t offset, uint8_t data)
546 {
547 }
548