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