1 // license:LGPL-2.1+
2 // copyright-holders:Angelo Salese, R. Belmont
3 /************************************************************************************
4 
5 Sega Saturn SMPC - System Manager and Peripheral Control MCU simulation
6 
7 The SMPC is actually a 4-bit Hitachi HD404920FS MCU, labeled with a Sega custom
8 315-5744 (that needs decapping)
9 
10 MCU simulation by Angelo Salese & R. Belmont
11 
12 TODO:
13 - timings;
14 - fix intback issue with inputs (according to the docs, it should fall in between
15   VBLANK-IN and OUT, for obvious reasons);
16 - clean-ups;
17 - RTC subdevice (unknown type, handled here for convenience);
18 - Does ST-V even has a battery backed NVRAM?
19 
20 Notes:
21 SMPC NVRAM contents:
22 [0] unknown (always 0)
23 [1] unknown (always 0)
24 [2] ---- -x-- Button Labels (0=enable)
25     ---- --x- Audio Out (1=Mono 0=Stereo)
26     ---- ---x BIOS audio SFXs enable (0=enable)
27 [3] language select (0=English, 5=Japanese)
28 
29 *************************************************************************************/
30 /* SMPC Addresses
31 
32 00
33 01 -w  Input Register 0 (IREG)
34 02
35 03 -w  Input Register 1
36 04
37 05 -w  Input Register 2
38 06
39 07 -w  Input Register 3
40 08
41 09 -w  Input Register 4
42 0a
43 0b -w  Input Register 5
44 0c
45 0d -w  Input Register 6
46 0e
47 0f
48 10
49 11
50 12
51 13
52 14
53 15
54 16
55 17
56 18
57 19
58 1a
59 1b
60 1c
61 1d
62 1e
63 1f -w  Command Register (COMREG)
64 20
65 21 r-  Output Register 0 (OREG)
66 22
67 23 r-  Output Register 1
68 24
69 25 r-  Output Register 2
70 26
71 27 r-  Output Register 3
72 28
73 29 r-  Output Register 4
74 2a
75 2b r-  Output Register 5
76 2c
77 2d r-  Output Register 6
78 2e
79 2f r-  Output Register 7
80 30
81 31 r-  Output Register 8
82 32
83 33 r-  Output Register 9
84 34
85 35 r-  Output Register 10
86 36
87 37 r-  Output Register 11
88 38
89 39 r-  Output Register 12
90 3a
91 3b r-  Output Register 13
92 3c
93 3d r-  Output Register 14
94 3e
95 3f r-  Output Register 15
96 40
97 41 r-  Output Register 16
98 42
99 43 r-  Output Register 17
100 44
101 45 r-  Output Register 18
102 46
103 47 r-  Output Register 19
104 48
105 49 r-  Output Register 20
106 4a
107 4b r-  Output Register 21
108 4c
109 4d r-  Output Register 22
110 4e
111 4f r-  Output Register 23
112 50
113 51 r-  Output Register 24
114 52
115 53 r-  Output Register 25
116 54
117 55 r-  Output Register 26
118 56
119 57 r-  Output Register 27
120 58
121 59 r-  Output Register 28
122 5a
123 5b r-  Output Register 29
124 5c
125 5d r-  Output Register 30
126 5e
127 5f r-  Output Register 31
128 60
129 61 r-  SR
130 62
131 63 rw  SF
132 64
133 65
134 66
135 67
136 68
137 69
138 6a
139 6b
140 6c
141 6d
142 6e
143 6f
144 70
145 71
146 72
147 73
148 74
149 75 rw PDR1
150 76
151 77 rw PDR2
152 78
153 79 -w DDR1
154 7a
155 7b -w DDR2
156 7c
157 7d -w IOSEL2/1
158 7e
159 7f -w EXLE2/1
160 */
161 
162 #include "emu.h"
163 #include "machine/smpc.h"
164 
165 #include "screen.h"
166 #include "coreutil.h"
167 
168 
169 #define LOG_SMPC 0
170 #define LOG_PAD_CMD 0
171 
172 //**************************************************************************
173 //  GLOBAL VARIABLES
174 //**************************************************************************
175 
176 // device type definition
177 DEFINE_DEVICE_TYPE(SMPC_HLE, smpc_hle_device, "smpc_hle", "Sega Saturn SMPC HLE (HD404920FS)")
178 
179 // TODO: use DEVICE_ADDRESS_MAP once this fatalerror is fixed:
180 // "uplift_submaps unhandled case: range straddling slots."
smpc_regs(address_map & map)181 void smpc_hle_device::smpc_regs(address_map &map)
182 {
183 //  map.unmap_value_high();
184 	map(0x00, 0x0d).w(FUNC(smpc_hle_device::ireg_w));
185 	map(0x1f, 0x1f).w(FUNC(smpc_hle_device::command_register_w));
186 	map(0x20, 0x5f).r(FUNC(smpc_hle_device::oreg_r));
187 	map(0x61, 0x61).r(FUNC(smpc_hle_device::status_register_r));
188 	map(0x63, 0x63).rw(FUNC(smpc_hle_device::status_flag_r), FUNC(smpc_hle_device::status_flag_w));
189 	map(0x75, 0x75).rw(FUNC(smpc_hle_device::pdr1_r), FUNC(smpc_hle_device::pdr1_w));
190 	map(0x77, 0x77).rw(FUNC(smpc_hle_device::pdr2_r), FUNC(smpc_hle_device::pdr2_w));
191 	map(0x79, 0x79).w(FUNC(smpc_hle_device::ddr1_w));
192 	map(0x7b, 0x7b).w(FUNC(smpc_hle_device::ddr2_w));
193 	map(0x7d, 0x7d).w(FUNC(smpc_hle_device::iosel_w));
194 	map(0x7f, 0x7f).w(FUNC(smpc_hle_device::exle_w));
195 }
196 
197 //**************************************************************************
198 //  LIVE DEVICE
199 //**************************************************************************
200 
201 //-------------------------------------------------
202 //  smpc_hle_device - constructor
203 //-------------------------------------------------
204 
smpc_hle_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)205 smpc_hle_device::smpc_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
206 	: device_t(mconfig, SMPC_HLE, tag, owner, clock)
207 	, device_memory_interface(mconfig, *this)
208 	, m_space_config("regs", ENDIANNESS_LITTLE, 8, 7, 0, address_map_constructor(FUNC(smpc_hle_device::smpc_regs), this))
209 	, m_mini_nvram(*this, "smem")
210 	, m_mshres(*this)
211 	, m_mshnmi(*this)
212 	, m_sshres(*this)
213 	, m_sndres(*this)
214 	, m_sysres(*this)
215 	, m_syshalt(*this)
216 	, m_dotsel(*this)
217 	, m_pdr1_read(*this)
218 	, m_pdr2_read(*this)
219 	, m_pdr1_write(*this)
220 	, m_pdr2_write(*this)
221 	, m_irq_line(*this)
222 	, m_ctrl1(*this, finder_base::DUMMY_TAG)
223 	, m_ctrl2(*this, finder_base::DUMMY_TAG)
224 	, m_screen(*this, finder_base::DUMMY_TAG)
225 {
226 	m_has_ctrl_ports = false;
227 }
228 
229 //-------------------------------------------------
230 //  device_add_mconfig - device-specific machine
231 //  configuration addiitons
232 //-------------------------------------------------
233 
device_add_mconfig(machine_config & config)234 void smpc_hle_device::device_add_mconfig(machine_config &config)
235 {
236 	NVRAM(config, "smem", nvram_device::DEFAULT_ALL_0);
237 
238 	// TODO: custom RTC subdevice
239 }
240 
241 //-------------------------------------------------
242 //  device_start - device-specific startup
243 //-------------------------------------------------
244 
device_start()245 void smpc_hle_device::device_start()
246 {
247 	system_time systime;
248 	machine().base_datetime(systime);
249 
250 //  check if SMEM has valid data via byte 4 in the array, if not then simulate a battery backup fail
251 //  (-> call the RTC / Language select menu for Saturn)
252 	m_mini_nvram->set_base(&m_smem, 5);
253 
254 	m_mshres.resolve_safe();
255 	m_mshnmi.resolve_safe();
256 	m_sshres.resolve_safe();
257 	m_sndres.resolve_safe();
258 	m_sysres.resolve_safe();
259 	m_syshalt.resolve_safe();
260 	m_dotsel.resolve_safe();
261 	m_irq_line.resolve_safe();
262 
263 	m_pdr1_read.resolve_safe(0xff);
264 	m_pdr2_read.resolve_safe(0xff);
265 	m_pdr1_write.resolve_safe();
266 	m_pdr2_write.resolve_safe();
267 
268 	save_item(NAME(m_sf));
269 	save_item(NAME(m_sr));
270 	save_item(NAME(m_ddr1));
271 	save_item(NAME(m_ddr2));
272 	save_item(NAME(m_pdr1_readback));
273 	save_item(NAME(m_pdr2_readback));
274 	save_item(NAME(m_iosel1));
275 	save_item(NAME(m_iosel2));
276 	save_item(NAME(m_exle1));
277 	save_item(NAME(m_exle2));
278 	save_item(NAME(m_ireg));
279 	save_item(NAME(m_oreg));
280 	save_item(NAME(m_comreg));
281 	save_item(NAME(m_command_in_progress));
282 	save_item(NAME(m_intback_buf));
283 	save_item(NAME(m_intback_stage));
284 	save_item(NAME(m_pmode));
285 	save_item(NAME(m_rtc_data));
286 	save_item(NAME(m_smem));
287 
288 	m_cmd_timer = timer_alloc(COMMAND_ID);
289 	m_rtc_timer = timer_alloc(RTC_ID);
290 	m_intback_timer = timer_alloc(INTBACK_ID);
291 	m_sndres_timer = timer_alloc(SNDRES_ID);
292 
293 	m_rtc_data[0] = DectoBCD(systime.local_time.year / 100);
294 	m_rtc_data[1] = DectoBCD(systime.local_time.year % 100);
295 	m_rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1);
296 	m_rtc_data[3] = DectoBCD(systime.local_time.mday);
297 	m_rtc_data[4] = DectoBCD(systime.local_time.hour);
298 	m_rtc_data[5] = DectoBCD(systime.local_time.minute);
299 	m_rtc_data[6] = DectoBCD(systime.local_time.second);
300 }
301 
302 
303 //-------------------------------------------------
304 //  device_reset - device-specific reset
305 //-------------------------------------------------
306 
device_reset()307 void smpc_hle_device::device_reset()
308 {
309 	m_sr = 0x40; // this bit is always on according to docs (?)
310 	m_sf = false;
311 	m_cd_sf = false;
312 	m_ddr1 = 0;
313 	m_ddr2 = 0;
314 	m_pdr1_readback = 0;
315 	m_pdr2_readback = 0;
316 
317 	memset(m_ireg,0,7);
318 	memset(m_oreg,0,32);
319 
320 	m_cmd_timer->reset();
321 	m_intback_timer->reset();
322 	m_sndres_timer->reset();
323 	m_comreg = 0xff;
324 	m_command_in_progress = false;
325 	m_NMI_reset = false;
326 	m_cur_dotsel = false;
327 
328 	m_rtc_timer->adjust(attotime::zero, 0, attotime::from_seconds(1));
329 }
330 
memory_space_config() const331 device_memory_interface::space_config_vector smpc_hle_device::memory_space_config() const
332 {
333 	return space_config_vector {
334 		std::make_pair(0, &m_space_config)
335 	};
336 }
337 
338 
339 //**************************************************************************
340 //  READ/WRITE HANDLERS
341 //**************************************************************************
342 
ireg_w(offs_t offset,uint8_t data)343 void smpc_hle_device::ireg_w(offs_t offset, uint8_t data)
344 {
345 	if (!(offset & 1)) // avoid writing to even bytes
346 		return;
347 
348 	m_ireg[offset >> 1] = data;
349 
350 	if(offset == 1) // check if we are under intback
351 	{
352 		if(m_intback_stage)
353 		{
354 			if(data & 0x40)
355 			{
356 				if(LOG_PAD_CMD) printf("SMPC: BREAK request\n");
357 				sr_ack();
358 				m_intback_stage = 0;
359 			}
360 			else if(data & 0x80)
361 			{
362 				if(LOG_PAD_CMD) printf("SMPC: CONTINUE request\n");
363 
364 				m_intback_timer->adjust(attotime::from_usec(700));  // TODO: is timing correct?
365 
366 				// TODO: following looks wrong here
367 				m_oreg[31] = 0x10;
368 				sf_set();
369 			}
370 		}
371 	}
372 }
373 
oreg_r(offs_t offset)374 uint8_t smpc_hle_device::oreg_r(offs_t offset)
375 {
376 	if (!(offset & 1)) // avoid reading to even bytes (TODO: is it 0s or 1s?)
377 		return 0x00;
378 
379 	return m_oreg[offset >> 1];
380 }
381 
status_register_r()382 uint8_t smpc_hle_device::status_register_r()
383 {
384 	return m_sr;
385 }
386 
status_flag_r()387 uint8_t smpc_hle_device::status_flag_r()
388 {
389 	// bit 3: CD enable related?
390 	return (m_sf<<0) | (m_cd_sf<<3);
391 }
392 
status_flag_w(uint8_t data)393 void smpc_hle_device::status_flag_w(uint8_t data)
394 {
395 	m_sf = BIT(data,0);
396 	m_cd_sf = false;
397 }
398 
pdr1_r()399 uint8_t smpc_hle_device::pdr1_r()
400 {
401 	uint8_t res = (m_pdr1_read() & ~m_ddr1) | m_pdr1_readback;
402 
403 	return res;
404 }
405 
pdr2_r()406 uint8_t smpc_hle_device::pdr2_r()
407 {
408 	uint8_t res = (m_pdr2_read() & ~m_ddr2) | m_pdr2_readback;
409 
410 	return res;
411 }
412 
pdr1_w(uint8_t data)413 void smpc_hle_device::pdr1_w(uint8_t data)
414 {
415 //  pins defined as output returns in input
416 	m_pdr1_readback = (data & m_ddr1);
417 	m_pdr1_readback &= 0x7f;
418 	m_pdr1_write(m_pdr1_readback);
419 //  bit 7 can be read back apparently
420 	m_pdr1_readback |= data & 0x80;
421 }
422 
pdr2_w(uint8_t data)423 void smpc_hle_device::pdr2_w(uint8_t data)
424 {
425 //  pins defined as output returns in input
426 	m_pdr2_readback = (data & m_ddr2);
427 	m_pdr2_readback &= 0x7f;
428 	m_pdr2_write(m_pdr2_readback);
429 //  bit 7 can be read back apparently
430 	m_pdr2_readback |= data & 0x80;
431 }
432 
ddr1_w(uint8_t data)433 void smpc_hle_device::ddr1_w(uint8_t data)
434 {
435 	m_ddr1 = data & 0x7f;
436 }
437 
ddr2_w(uint8_t data)438 void smpc_hle_device::ddr2_w(uint8_t data)
439 {
440 	m_ddr2 = data & 0x7f;
441 }
442 
iosel_w(uint8_t data)443 void smpc_hle_device::iosel_w(uint8_t data)
444 {
445 	m_iosel1 = BIT(data,0);
446 	m_iosel2 = BIT(data,1);
447 }
448 
exle_w(uint8_t data)449 void smpc_hle_device::exle_w(uint8_t data)
450 {
451 	m_exle1 = BIT(data,0);
452 	m_exle2 = BIT(data,1);
453 }
454 
sr_ack()455 inline void smpc_hle_device::sr_ack()
456 {
457 	m_sr &= 0x0f;
458 }
459 
sr_set(uint8_t data)460 inline void smpc_hle_device::sr_set(uint8_t data)
461 {
462 	m_sr = data;
463 }
464 
sf_ack(bool cd_enable)465 inline void smpc_hle_device::sf_ack(bool cd_enable)
466 {
467 	m_sf = false;
468 	m_cd_sf = cd_enable;
469 }
470 
sf_set()471 inline void smpc_hle_device::sf_set()
472 {
473 	m_sf = true;
474 }
475 
476 // Saturn Direct Mode polling check for delegate
get_iosel(bool which)477 bool smpc_hle_device::get_iosel(bool which)
478 {
479 	return which == true ? m_iosel2 : m_iosel1;
480 }
481 
get_ddr(bool which)482 uint8_t smpc_hle_device::get_ddr(bool which)
483 {
484 	return which == true ? m_ddr2 : m_ddr1;
485 }
486 
487 
master_sh2_nmi()488 inline void smpc_hle_device::master_sh2_nmi()
489 {
490 	m_mshnmi(1);
491 	m_mshnmi(0);
492 }
493 
irq_request()494 inline void smpc_hle_device::irq_request()
495 {
496 	m_irq_line(1);
497 	m_irq_line(0);
498 }
499 
500 // TODO: trampolines that needs to go away
501 
read(offs_t offset)502 uint8_t smpc_hle_device::read(offs_t offset)
503 {
504 	return this->space().read_byte(offset);
505 }
506 
write(offs_t offset,uint8_t data)507 void smpc_hle_device::write(offs_t offset, uint8_t data)
508 {
509 	this->space().write_byte(offset,data);
510 }
511 
512 //**************************************************************************
513 //  Command simulation
514 //**************************************************************************
515 
command_register_w(uint8_t data)516 void smpc_hle_device::command_register_w(uint8_t data)
517 {
518 //  don't send a command if previous one is still in progress
519 //  ST-V tries to send a sysres command if OREG31 doesn't return the ack command
520 	if(m_command_in_progress == true)
521 		return;
522 
523 	m_comreg = data & 0x1f;
524 
525 	if(data & 0xe0)
526 		logerror("%s COMREG = %02x!?\n",this->tag(),data);
527 
528 	m_command_in_progress = true;
529 	if(m_comreg == 0x0e || m_comreg == 0x0f)
530 	{
531 		/* on ST-V timing of this is pretty fussy, you get 2 credits at start-up otherwise
532 		 * My current theory is that the PLL device can halt the whole system until the frequency change occurs.
533 		 *  (cfr. diagram on page 3 of SMPC manual)
534 		 * I really don't think that the system can do an usable mid-frame clock switching anyway.
535 		 */
536 		m_syshalt(1);
537 
538 		m_cmd_timer->adjust(m_screen->time_until_pos(m_screen->visible_area().max_y,0));
539 	}
540 	else if(m_comreg == 0x10)
541 	{
542 		// copy ireg to our intback buffer
543 		for(int i=0;i<3;i++)
544 			m_intback_buf[i] = m_ireg[i];
545 
546 		// calculate the timing for intback command
547 		int timing;
548 
549 		timing = 8;
550 
551 		if( m_ireg[0] != 0) // non-peripheral data
552 			timing += 8;
553 
554 		// TODO: At vblank-out actually ...
555 		if( m_ireg[1] & 8) // peripheral data
556 			timing += 700;
557 
558 		// TODO: check against ireg2, must be 0xf0
559 
560 		m_cmd_timer->adjust(attotime::from_usec(timing));
561 	}
562 	else
563 		m_cmd_timer->adjust(attotime::from_usec(m_cmd_table_timing[m_comreg]));
564 }
565 
566 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)567 void smpc_hle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
568 {
569 	switch(id)
570 	{
571 		case COMMAND_ID:
572 		{
573 			switch(m_comreg)
574 			{
575 				case 0x00: // MSHON
576 					// enable Master SH2
577 					m_mshres(m_comreg & 1);
578 					break;
579 
580 				case 0x02: // SSHON
581 				case 0x03: // SSHOFF
582 					// enable or disable Slave SH2
583 					m_sshres(m_comreg & 1);
584 					break;
585 
586 				case 0x06: // SNDON
587 				case 0x07: // SNDOFF
588 					// enable or disable 68k
589 					m_sndres(m_comreg & 1);
590 					break;
591 
592 				case 0x08: // CDON
593 				case 0x09: // CDOFF
594 					// ...
595 					m_command_in_progress = false;
596 					m_oreg[31] = m_comreg;
597 					sf_ack(true); //clear hand-shake flag (TODO: diagnostic wants this to have bit 3 high)
598 					return;
599 
600 //              case 0x0a: // NETLINKON
601 //              case 0x0b: // NETLINKOFF
602 
603 				case 0x0d: // SYSRES
604 					// send a 1 -> 0 to device reset lines
605 					m_sysres(1);
606 					m_sysres(0);
607 
608 					// send a 1 -> 0 transition to reset line (was PULSE_LINE)
609 					m_mshres(1);
610 					m_mshres(0);
611 					break;
612 
613 				case 0x0e: // CKCHG352
614 				case 0x0f: // CKCHG320
615 					m_dotsel(m_comreg & 1);
616 
617 					// send a NMI to Master SH2 if enabled
618 					if(m_NMI_reset == false)
619 						master_sh2_nmi();
620 
621 					// assert Slave SH2 line
622 					m_sshres(1);
623 					// clear PLL system halt
624 					m_syshalt(0);
625 
626 					// setup the new dot select
627 					m_cur_dotsel = (m_comreg & 1) ^ 1;
628 					break;
629 
630 				case 0x10: // INTBACK
631 					resolve_intback();
632 					return;
633 
634 				case 0x16: // SETTIME
635 				{
636 					for(int i=0;i<7;i++)
637 						m_rtc_data[i] = m_ireg[i];
638 					break;
639 				}
640 
641 				case 0x17: // SETSMEM
642 				{
643 					for(int i=0;i<4;i++)
644 						m_smem[i] = m_ireg[i];
645 
646 					// clear the SETIME variable, simulate a cr2032 battery alive in the system
647 					m_smem[4] = 0xff;
648 					break;
649 				}
650 
651 				case 0x18: // NMIREQ
652 					// NMI is unconditionally requested
653 					master_sh2_nmi();
654 					break;
655 
656 				case 0x19: // RESENAB
657 				case 0x1a: // RESDISA
658 					m_NMI_reset = m_comreg & 1;
659 					break;
660 
661 				default:
662 					logerror("%s unemulated %02x command\n",this->tag(),m_comreg);
663 					return;
664 			}
665 
666 			m_command_in_progress = false;
667 			m_oreg[31] = m_comreg;
668 			sf_ack(false);
669 			break;
670 		}
671 
672 		case INTBACK_ID: intback_continue_request(); break;
673 		case RTC_ID: handle_rtc_increment(); break;
674 
675 		// from m68k reset opcode trigger
676 		case SNDRES_ID:
677 			m_sndres(1);
678 			m_sndres(0);
679 			break;
680 
681 		default:
682 			printf("%d\n",id);
683 			break;
684 	}
685 }
686 
resolve_intback()687 void smpc_hle_device::resolve_intback()
688 {
689 	int i;
690 
691 	m_command_in_progress = false;
692 
693 	if(m_intback_buf[0] != 0)
694 	{
695 		m_oreg[0] = ((m_smem[4] & 0x80) | ((m_NMI_reset & 1) << 6));
696 
697 		for(i=0;i<7;i++)
698 			m_oreg[1+i] = m_rtc_data[i];
699 
700 		m_oreg[8] = 0; // CTG0 / CTG1?
701 
702 		m_oreg[9] = m_region_code; // TODO: system region on Saturn
703 
704 		/*
705 		 0-11 -1-- unknown
706 		 -x-- ---- VDP2 dot select
707 		 ---- x--- MSHNMI
708 		 ---- --x- SYSRES
709 		 ---- ---x SOUNDRES
710 		 */
711 		m_oreg[10] = 0 << 7 |
712 					 m_cur_dotsel << 6 |
713 					 1 << 5 |
714 					 1 << 4 |
715 					 0 << 3 |
716 					 1 << 2 |
717 					 0 << 1 |
718 					 0 << 0;
719 
720 		m_oreg[11] = 0 << 6; // CDRES
721 
722 		for(i=0;i<4;i++)
723 			m_oreg[12+i] = m_smem[i];
724 
725 		for(i=0;i<15;i++)
726 			m_oreg[16+i] = 0xff; // undefined
727 
728 		m_intback_stage = (m_intback_buf[1] & 8) >> 3; // first peripheral
729 		sr_set(0x40 | (m_intback_stage << 5));
730 		m_pmode = m_intback_buf[0]>>4;
731 
732 		irq_request();
733 
734 		// put issued command in OREG31
735 		m_oreg[31] = 0x10; // TODO: doc says 0?
736 		/* clear hand-shake flag */
737 		sf_ack(false);
738 	}
739 	else if(m_intback_buf[1] & 8)
740 	{
741 		m_intback_stage = (m_intback_buf[1] & 8) >> 3; // first peripheral
742 		sr_set(0x40);
743 		m_oreg[31] = 0x10;
744 		intback_continue_request();
745 	}
746 	else
747 	{
748 		/* Shienryu calls this, it would be plainly illegal on Saturn, I'll just return the command and clear the hs flag for now. */
749 		m_oreg[31] = 0x10;
750 		sf_ack(false);
751 	}
752 }
753 
intback_continue_request()754 void smpc_hle_device::intback_continue_request()
755 {
756 	if( m_has_ctrl_ports == true )
757 		read_saturn_ports();
758 
759 	if (m_intback_stage == 2)
760 	{
761 		sr_set(0x80 | m_pmode);     // pad 2, no more data, echo back pad mode set by intback
762 		m_intback_stage = 0;
763 	}
764 	else
765 	{
766 		sr_set(0xc0 | m_pmode);    // pad 1, more data, echo back pad mode set by intback
767 		m_intback_stage ++;
768 	}
769 	irq_request();
770 
771 	m_oreg[31] = 0x10; // callback for last command issued
772 	sf_ack(false);
773 }
774 
DectoBCD(int num)775 int smpc_hle_device::DectoBCD(int num)
776 {
777 	int i, cnt = 0, tmp, res = 0;
778 
779 	while (num > 0) {
780 		tmp = num;
781 		while (tmp >= 10) tmp %= 10;
782 		for (i=0; i<cnt; i++)
783 			tmp *= 16;
784 		res += tmp;
785 		cnt++;
786 		num /= 10;
787 	}
788 
789 	return res;
790 }
791 
792 //**************************************************************************
793 //  RTC handling
794 //**************************************************************************
795 
handle_rtc_increment()796 void smpc_hle_device::handle_rtc_increment()
797 {
798 	const uint8_t dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 };
799 	int year_num, year_count;
800 
801 	/*
802 	    m_smpc.rtc_data[0] = DectoBCD(systime.local_time.year /100);
803 	    m_smpc.rtc_data[1] = DectoBCD(systime.local_time.year %100);
804 	    m_smpc.rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1);
805 	    m_smpc.rtc_data[3] = DectoBCD(systime.local_time.mday);
806 	    m_smpc.rtc_data[4] = DectoBCD(systime.local_time.hour);
807 	    m_smpc.rtc_data[5] = DectoBCD(systime.local_time.minute);
808 	    m_smpc.rtc_data[6] = DectoBCD(systime.local_time.second);
809 	*/
810 
811 	m_rtc_data[6]++;
812 
813 	/* seconds from 9 -> 10*/
814 	if((m_rtc_data[6] & 0x0f) >= 0x0a)         { m_rtc_data[6]+=0x10; m_rtc_data[6]&=0xf0; }
815 	/* seconds from 59 -> 0 */
816 	if((m_rtc_data[6] & 0xf0) >= 0x60)         { m_rtc_data[5]++;     m_rtc_data[6] = 0; }
817 	/* minutes from 9 -> 10 */
818 	if((m_rtc_data[5] & 0x0f) >= 0x0a)         { m_rtc_data[5]+=0x10; m_rtc_data[5]&=0xf0; }
819 	/* minutes from 59 -> 0 */
820 	if((m_rtc_data[5] & 0xf0) >= 0x60)         { m_rtc_data[4]++;     m_rtc_data[5] = 0; }
821 	/* hours from 9 -> 10 */
822 	if((m_rtc_data[4] & 0x0f) >= 0x0a)         { m_rtc_data[4]+=0x10; m_rtc_data[4]&=0xf0; }
823 	/* hours from 23 -> 0 */
824 	if((m_rtc_data[4] & 0xff) >= 0x24)             { m_rtc_data[3]++; m_rtc_data[2]+=0x10; m_rtc_data[4] = 0; }
825 	/* week day name sunday -> monday */
826 	if((m_rtc_data[2] & 0xf0) >= 0x70)             { m_rtc_data[2]&=0x0f; }
827 	/* day number 9 -> 10 */
828 	if((m_rtc_data[3] & 0x0f) >= 0x0a)             { m_rtc_data[3]+=0x10; m_rtc_data[3]&=0xf0; }
829 
830 	// year BCD to dec conversion (for the leap year stuff)
831 	{
832 		year_num = (m_rtc_data[1] & 0xf);
833 
834 		for(year_count = 0; year_count < (m_rtc_data[1] & 0xf0); year_count += 0x10)
835 			year_num += 0xa;
836 
837 		year_num += (m_rtc_data[0] & 0xf)*0x64;
838 
839 		for(year_count = 0; year_count < (m_rtc_data[0] & 0xf0); year_count += 0x10)
840 			year_num += 0x3e8;
841 	}
842 
843 	/* month +1 check */
844 	/* the RTC have a range of 1980 - 2100, so we don't actually need to support the leap year special conditions */
845 	if(((year_num % 4) == 0) && (m_rtc_data[2] & 0xf) == 2)
846 	{
847 		if((m_rtc_data[3] & 0xff) >= dpm[(m_rtc_data[2] & 0xf)-1]+1+1)
848 			{ m_rtc_data[2]++; m_rtc_data[3] = 0x01; }
849 	}
850 	else if((m_rtc_data[3] & 0xff) >= dpm[(m_rtc_data[2] & 0xf)-1]+1){ m_rtc_data[2]++; m_rtc_data[3] = 0x01; }
851 	/* year +1 check */
852 	if((m_rtc_data[2] & 0x0f) > 12)                { m_rtc_data[1]++;  m_rtc_data[2] = (m_rtc_data[2] & 0xf0) | 0x01; }
853 	/* year from 9 -> 10 */
854 	if((m_rtc_data[1] & 0x0f) >= 0x0a)             { m_rtc_data[1]+=0x10; m_rtc_data[1]&=0xf0; }
855 	/* year from 99 -> 100 */
856 	if((m_rtc_data[1] & 0xf0) >= 0xa0)             { m_rtc_data[0]++; m_rtc_data[1] = 0; }
857 
858 	// probably not SO precise, here just for reference ...
859 	/* year from 999 -> 1000 */
860 	//if((m_rtc_data[0] & 0x0f) >= 0x0a)               { m_rtc_data[0]+=0x10; m_rtc_data[0]&=0xf0; }
861 	/* year from 9999 -> 0 */
862 	//if((m_rtc_data[0] & 0xf0) >= 0xa0)               { m_rtc_data[0] = 0; } //roll over
863 }
864 
865 
866 
867 
868 /********************************************
869  *
870  * Saturn handlers
871  *
872  *******************************************/
873 
874 /*
875     [0] port status:
876         0x04 Sega-tap
877         0x16 Multi-tap
878         0x2x clock serial peripheral
879         0xf0 peripheral isn't connected
880         0xf1 peripheral is connected
881     [1] Peripheral ID (note: lowest four bits determines the size of the input packet)
882         0x02 digital pad
883         0x25 (tested by Game Basic?)
884         0x34 keyboard
885 
886  Lower 4 bits of the port status tell the number of controllers to check for the port
887  Lower 4 bits of the peripheral ID tell the number of registers used by each controller
888  For multitap / segatap, we have implemented the following logic:
889  SMPC reads in sequence
890  - status for port 1
891  - ID first controller, followed by the number of reads needed by the plugged controller
892  - ID second controller, followed by the number of reads needed by the plugged controller
893  - and so on... until the 4th (for SegaTap) or 6th (for Multitap) controller is read
894  TODO: how does the multitap check if a controller is connected? does it ask for the
895  controller status of each subport? how does this work exactly?
896  currently, there is a small problem in some specific controller config which seems to
897  lose track of one controller. E.g. if I put multitap in port2 with inserted joy1, joy2 and joy4
898  it does not see joy4 controller, but if I put joy1, joy2, joy4 and joy5 it sees
899  all four of them. The same happens if I skip controllers with id = 0xff...
900  how did a real unit behave in this case?
901 */
902 
read_saturn_ports()903 void smpc_hle_device::read_saturn_ports()
904 {
905 	uint8_t status1 = m_ctrl1 ? m_ctrl1->read_status() : 0xf0;
906 	uint8_t status2 = m_ctrl2 ? m_ctrl2->read_status() : 0xf0;
907 
908 	uint8_t reg_offset = 0;
909 	uint8_t ctrl1_offset = 0;     // this is used when there is segatap or multitap connected
910 	uint8_t ctrl2_offset = 0;     // this is used when there is segatap or multitap connected
911 
912 	m_oreg[reg_offset++] = status1;
913 
914 	// read ctrl1
915 	for (int i = 0; i < (status1 & 0xf); i++)
916 	{
917 		uint8_t id = m_ctrl1->read_id(i);
918 
919 		m_oreg[reg_offset++] = id;
920 		for (int j = 0; j < (id & 0xf); j++)
921 			m_oreg[reg_offset++] = m_ctrl1->read_ctrl(j + ctrl1_offset);
922 
923 		ctrl1_offset += (id & 0xf);
924 	}
925 
926 	m_oreg[reg_offset++] = status2;
927 
928 	// read ctrl2
929 	for (int i = 0; i < (status2 & 0xf); i++)
930 	{
931 		uint8_t id = m_ctrl2->read_id(i);
932 
933 		m_oreg[reg_offset++] = id;
934 
935 		for (int j = 0; j < (id & 0xf); j++)
936 			m_oreg[reg_offset++] = m_ctrl2->read_ctrl(j + ctrl2_offset);
937 
938 		ctrl2_offset += (id & 0xf);
939 	}
940 }
941 
INPUT_CHANGED_MEMBER(smpc_hle_device::trigger_nmi_r)942 INPUT_CHANGED_MEMBER(smpc_hle_device::trigger_nmi_r )
943 {
944 	// punt if NMI trigger is disabled
945 	if(!m_NMI_reset)
946 		return;
947 
948 	// TODO: generated during the 3VINT period according to manual
949 	if(newval)
950 		master_sh2_nmi();
951 }
952 
953 /* Official documentation says that the "RESET/TAS opcodes aren't supported", but Out Run definitely contradicts with it.
954    Since that m68k can't reset itself via the RESET opcode I suppose that the SMPC actually do it by reading an i/o
955    connected to this opcode. */
m68k_reset_trigger()956 void smpc_hle_device::m68k_reset_trigger()
957 {
958 	m_sndres_timer->adjust(attotime::from_usec(100));
959 }
960