2 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5 * Jerremy Koot (jkoot@snes9x.com)
7 * Super FX C emulator code
8 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
10 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
12 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13 * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14 * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
16 * DOS port code contains the works of other authors. See headers in
19 * Snes9x homepage: http://www.snes9x.com
21 * Permission to use, copy, modify and distribute Snes9x in both binary and
22 * source form, for non-commercial purposes, is hereby granted without fee,
23 * providing that this license information and copyright notice appear with
24 * all copies and any derived work.
26 * This software is provided 'as-is', without any express or implied
27 * warranty. In no event shall the authors be held liable for any damages
28 * arising from the use of this software.
30 * Snes9x is freeware for PERSONAL USE only. Commercial users should
31 * seek permission of the copyright holders first. Commercial use includes
32 * charging money for Snes9x or software derived from Snes9x.
34 * The copyright holders request that bug fixes and improvements to the code
35 * should be forwarded to them so everyone can benefit from the modifications
38 * Super NES and Super Nintendo Entertainment System are trademarks of
39 * Nintendo Co., Limited and its subsidiary companies.
47 /*** The format of the rtc_data structure is:
49 Index Description Range (nibble)
50 ----- -------------- ---------------------------------------
64 8 Month 1-C (0xC is December, 12th month)
68 B Year High 9-B (9=19xx, A=20xx, B=21xx)
70 C Day of week 0-6 (0=Sunday, 1=Monday,...,6=Saturday)
77 static int month_keys[12] = { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 };
80 /*********************************************************************************************
82 * Note, if you are doing a save state for this game:
86 * Call S9xUpdateSrtcTime and save the rtc data structure.
90 * restore the rtc data structure
91 * rtc.system_timestamp = time (NULL);
94 *********************************************************************************************/
100 rtc.mode = MODE_READ;
103 void S9xHardResetSRTC ()
105 ZeroMemory (&rtc, sizeof (rtc));
107 rtc.mode = MODE_READ;
108 rtc.count_enable = FALSE;
109 rtc.needs_init = TRUE;
111 // Get system timestamp
112 rtc.system_timestamp = time (NULL);
115 /**********************************************************************************************/
116 /* S9xSRTCComputeDayOfWeek() */
117 /* Return 0-6 for Sunday-Saturday */
118 /**********************************************************************************************/
119 unsigned int S9xSRTCComputeDayOfWeek ()
121 unsigned year = rtc.data[10]*10 + rtc.data[9];
122 unsigned month = rtc.data[8];
123 unsigned day = rtc.data[7]*10 + rtc.data[6];
124 unsigned day_of_week;
126 year += (rtc.data[11] - 9) * 100;
128 // Range check the month for valid array indicies
132 day_of_week = year + (year / 4) + month_keys[month-1] + day - 1;
134 if(( year % 4 == 0 ) && ( month <= 2 ) )
143 /**********************************************************************************************/
144 /* S9xSRTCDaysInMonth() */
145 /* Return the number of days in a specific month for a certain year */
146 /**********************************************************************************************/
147 int S9xSRTCDaysInMmonth( int month, int year )
154 if ( ( year % 4 == 0 ) ) // DKJM2 only uses 199x - 22xx
167 default: // months 1,3,5,7,8,10,12
176 #define DAYTICKS (60*60*24)
177 #define HOURTICKS (60*60)
178 #define MINUTETICKS 60
181 /**********************************************************************************************/
182 /* S9xUpdateSrtcTime() */
183 /* Advance the S-RTC time if counting is enabled */
184 /**********************************************************************************************/
185 void S9xUpdateSrtcTime ()
190 // Keep track of game time by computing the number of seconds that pass on the system
191 // clock and adding the same number of seconds to the S-RTC clock structure.
192 // I originally tried using mktime and localtime library functions to keep track
193 // of time but some of the GNU time functions fail when the year goes to 2099
194 // (and maybe less) and this would have caused a bug with DKJM2 so I'm doing
195 // it this way to get around that problem.
197 // Note: Dai Kaijyu Monogatari II only allows dates in the range 1996-21xx.
199 if (rtc.count_enable && !rtc.needs_init)
201 cur_systime = time (NULL);
203 // This method assumes one time_t clock tick is one second
204 // which should work on PCs and GNU systems.
205 // If your tick interval is different adjust the
206 // DAYTICK, HOURTICK, and MINUTETICK defines
208 time_diff = (long) (cur_systime - rtc.system_timestamp);
209 rtc.system_timestamp = cur_systime;
226 if ( time_diff > DAYTICKS )
228 days = time_diff / DAYTICKS;
229 time_diff = time_diff - days * DAYTICKS;
236 if ( time_diff > HOURTICKS )
238 hours = time_diff / HOURTICKS;
239 time_diff = time_diff - hours * HOURTICKS;
246 if ( time_diff > MINUTETICKS )
248 minutes = time_diff / MINUTETICKS;
249 time_diff = time_diff - minutes * MINUTETICKS;
266 seconds += (rtc.data[1]*10 + rtc.data[0]);
273 minutes += (rtc.data[3]*10 + rtc.data[2]);
280 hours += (rtc.data[5]*10 + rtc.data[4]);
289 year = rtc.data[10]*10 + rtc.data[9];
290 year += ( 1000 + rtc.data[11] * 100 );
293 days += (rtc.data[7]*10 + rtc.data[6]);
294 while ( days > (temp_days = S9xSRTCDaysInMmonth( month, year )) )
305 year_tens = year % 100;
306 year_ones = year_tens % 10;
308 year_hundreds = (year - 1000) / 100;
310 rtc.data[6] = days % 10;
311 rtc.data[7] = days / 10;
313 rtc.data[9] = year_ones;
314 rtc.data[10] = year_tens;
315 rtc.data[11] = year_hundreds;
316 rtc.data[12] = S9xSRTCComputeDayOfWeek ();
319 rtc.data[0] = seconds % 10;
320 rtc.data[1] = seconds / 10;
321 rtc.data[2] = minutes % 10;
322 rtc.data[3] = minutes / 10;
323 rtc.data[4] = hours % 10;
324 rtc.data[5] = hours / 10;
332 /**********************************************************************************************/
334 /* This function sends data to the S-RTC used in Dai Kaijyu Monogatari II */
335 /**********************************************************************************************/
336 void S9xSetSRTC (uint8 data, uint16 Address)
339 data &= 0x0F; // Data is only 4-bits, mask out unused bits.
343 // It's an RTC command
348 rtc.mode = MODE_READ;
353 rtc.mode = MODE_COMMAND;
357 // Ignore the write if it's an 0xF ???
358 // Probably should switch back to read mode -- but this
359 // sequence never occurs in DKJM2
366 if ( rtc.mode == MODE_LOAD_RTC )
368 if ( (rtc.index >= 0) || (rtc.index < MAX_RTC_INDEX) )
370 rtc.data[rtc.index++] = data;
372 if ( rtc.index == MAX_RTC_INDEX )
374 // We have all the data for the RTC load
376 rtc.system_timestamp = time (NULL); // Get local system time
378 // Get the day of the week
379 rtc.data[rtc.index++] = S9xSRTCComputeDayOfWeek ();
381 // Start RTC counting again
382 rtc.count_enable = TRUE;
383 rtc.needs_init = FALSE;
390 // Attempting to write too much data
391 // error(); // ignore??
394 else if ( rtc.mode == MODE_COMMAND )
398 case COMMAND_CLEAR_RTC:
399 // Disable RTC counter
400 rtc.count_enable = FALSE;
402 ZeroMemory (rtc.data, MAX_RTC_INDEX+1);
404 rtc.mode = MODE_COMMAND_DONE;
407 case COMMAND_LOAD_RTC:
408 // Disable RTC counter
409 rtc.count_enable = FALSE;
411 rtc.index = 0; // Setup for writing
412 rtc.mode = MODE_LOAD_RTC;
416 rtc.mode = MODE_COMMAND_DONE;
417 // unrecognized command - need to implement.
424 if ( rtc.mode == MODE_READ )
426 // Attempting to write while in read mode. Ignore.
429 if ( rtc.mode == MODE_COMMAND_DONE )
431 // Maybe this isn't an error. Maybe we should kick off
432 // a new E command. But is this valid?
437 /**********************************************************************************************/
439 /* This function retrieves data from the S-RTC */
440 /**********************************************************************************************/
441 uint8 S9xGetSRTC (uint16 Address)
443 if ( rtc.mode == MODE_READ )
447 S9xUpdateSrtcTime (); // Only update it if the game reads it
449 return ( 0x0f ); // Send start marker.
451 else if (rtc.index > MAX_RTC_INDEX)
453 rtc.index = -1; // Setup for next set of reads
454 return ( 0x0f ); // Data done marker.
459 return rtc.data[rtc.index++];
468 void S9xSRTCPreSaveState ()
472 S9xUpdateSrtcTime ();
474 int s = Memory.SRAMSize ?
475 (1 << (Memory.SRAMSize + 3)) * 128 : 0;
479 SRAM [s + 0] = rtc.needs_init;
480 SRAM [s + 1] = rtc.count_enable;
481 memmove (&SRAM [s + 2], rtc.data, MAX_RTC_INDEX + 1);
482 SRAM [s + 3 + MAX_RTC_INDEX] = rtc.index;
483 SRAM [s + 4 + MAX_RTC_INDEX] = rtc.mode;
486 memmove (&SRAM [s + 5 + MAX_RTC_INDEX], &rtc.system_timestamp, 8);
488 SRAM [s + 5 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 0);
489 SRAM [s + 6 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 8);
490 SRAM [s + 7 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 16);
491 SRAM [s + 8 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 24);
492 SRAM [s + 9 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 32);
493 SRAM [s + 10 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 40);
494 SRAM [s + 11 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 48);
495 SRAM [s + 12 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 56);
500 void S9xSRTCPostLoadState ()
504 int s = Memory.SRAMSize ?
505 (1 << (Memory.SRAMSize + 3)) * 128 : 0;
509 rtc.needs_init = SRAM [s + 0];
510 rtc.count_enable = SRAM [s + 1];
511 memmove (rtc.data, &SRAM [s + 2], MAX_RTC_INDEX + 1);
512 rtc.index = SRAM [s + 3 + MAX_RTC_INDEX];
513 rtc.mode = SRAM [s + 4 + MAX_RTC_INDEX];
516 memmove (&rtc.system_timestamp, &SRAM [s + 5 + MAX_RTC_INDEX], 8);
518 rtc.system_timestamp |= (SRAM [s + 5 + MAX_RTC_INDEX] << 0);
519 rtc.system_timestamp |= (SRAM [s + 6 + MAX_RTC_INDEX] << 8);
520 rtc.system_timestamp |= (SRAM [s + 7 + MAX_RTC_INDEX] << 16);
521 rtc.system_timestamp |= (SRAM [s + 8 + MAX_RTC_INDEX] << 24);
522 rtc.system_timestamp |= (SRAM [s + 9 + MAX_RTC_INDEX] << 32);
523 rtc.system_timestamp |= (SRAM [s + 10 + MAX_RTC_INDEX] << 40);
524 rtc.system_timestamp |= (SRAM [s + 11 + MAX_RTC_INDEX] << 48);
525 rtc.system_timestamp |= (SRAM [s + 12 + MAX_RTC_INDEX] << 56);
527 S9xUpdateSrtcTime ();