From 7a7857f47b33f1b63fb585d2dc6c60d87c3e928f Mon Sep 17 00:00:00 2001 From: aliaspider Date: Mon, 9 Nov 2015 19:55:28 +0100 Subject: C++ --> C99 --- src/srtc.c | 528 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 src/srtc.c (limited to 'src/srtc.c') diff --git a/src/srtc.c b/src/srtc.c new file mode 100644 index 0000000..be390f0 --- /dev/null +++ b/src/srtc.c @@ -0,0 +1,528 @@ +/* + * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + * + * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and + * Jerremy Koot (jkoot@snes9x.com) + * + * Super FX C emulator code + * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and + * Gary Henderson. + * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. + * + * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. + * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. + * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com). + * + * DOS port code contains the works of other authors. See headers in + * individual files. + * + * Snes9x homepage: http://www.snes9x.com + * + * Permission to use, copy, modify and distribute Snes9x in both binary and + * source form, for non-commercial purposes, is hereby granted without fee, + * providing that this license information and copyright notice appear with + * all copies and any derived work. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event shall the authors be held liable for any damages + * arising from the use of this software. + * + * Snes9x is freeware for PERSONAL USE only. Commercial users should + * seek permission of the copyright holders first. Commercial use includes + * charging money for Snes9x or software derived from Snes9x. + * + * The copyright holders request that bug fixes and improvements to the code + * should be forwarded to them so everyone can benefit from the modifications + * in future versions. + * + * Super NES and Super Nintendo Entertainment System are trademarks of + * Nintendo Co., Limited and its subsidiary companies. + */ +#include +#include "snes9x.h" +#include "srtc.h" +#include "memmap.h" + +/*** The format of the rtc_data structure is: + +Index Description Range (nibble) +----- -------------- --------------------------------------- + + 0 Seconds low 0-9 + 1 Seconds high 0-5 + + 2 Minutes low 0-9 + 3 Minutes high 0-5 + + 4 Hour low 0-9 + 5 Hour high 0-2 + + 6 Day low 0-9 + 7 Day high 0-3 + + 8 Month 1-C (0xC is December, 12th month) + + 9 Year ones 0-9 + A Year tens 0-9 + B Year High 9-B (9=19xx, A=20xx, B=21xx) + + C Day of week 0-6 (0=Sunday, 1=Monday,...,6=Saturday) + +***/ + +SRTC_DATA rtc; + + +static int month_keys[12] = { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 }; + + +/********************************************************************************************* + * + * Note, if you are doing a save state for this game: + * + * On save: + * + * Call S9xUpdateSrtcTime and save the rtc data structure. + * + * On load: + * + * restore the rtc data structure + * rtc.system_timestamp = time (NULL); + * + * + *********************************************************************************************/ + + +void S9xResetSRTC () +{ + rtc.index = -1; + rtc.mode = MODE_READ; +} + +void S9xHardResetSRTC () +{ + ZeroMemory (&rtc, sizeof (rtc)); + rtc.index = -1; + rtc.mode = MODE_READ; + rtc.count_enable = FALSE; + rtc.needs_init = TRUE; + + // Get system timestamp + rtc.system_timestamp = time (NULL); +} + +/**********************************************************************************************/ +/* S9xSRTCComputeDayOfWeek() */ +/* Return 0-6 for Sunday-Saturday */ +/**********************************************************************************************/ +unsigned int S9xSRTCComputeDayOfWeek () +{ + unsigned year = rtc.data[10]*10 + rtc.data[9]; + unsigned month = rtc.data[8]; + unsigned day = rtc.data[7]*10 + rtc.data[6]; + unsigned day_of_week; + + year += (rtc.data[11] - 9) * 100; + + // Range check the month for valid array indicies + if ( month > 12 ) + month = 1; + + day_of_week = year + (year / 4) + month_keys[month-1] + day - 1; + + if(( year % 4 == 0 ) && ( month <= 2 ) ) + day_of_week--; + + day_of_week %= 7; + + return day_of_week; +} + + +/**********************************************************************************************/ +/* S9xSRTCDaysInMonth() */ +/* Return the number of days in a specific month for a certain year */ +/**********************************************************************************************/ +int S9xSRTCDaysInMmonth( int month, int year ) +{ + int mdays; + + switch ( month ) + { + case 2: + if ( ( year % 4 == 0 ) ) // DKJM2 only uses 199x - 22xx + mdays = 29; + else + mdays = 28; + break; + + case 4: + case 6: + case 9: + case 11: + mdays = 30; + break; + + default: // months 1,3,5,7,8,10,12 + mdays = 31; + break; + } + + return mdays; +} + + +#define DAYTICKS (60*60*24) +#define HOURTICKS (60*60) +#define MINUTETICKS 60 + + +/**********************************************************************************************/ +/* S9xUpdateSrtcTime() */ +/* Advance the S-RTC time if counting is enabled */ +/**********************************************************************************************/ +void S9xUpdateSrtcTime () +{ + time_t cur_systime; + long time_diff; + + // Keep track of game time by computing the number of seconds that pass on the system + // clock and adding the same number of seconds to the S-RTC clock structure. + // I originally tried using mktime and localtime library functions to keep track + // of time but some of the GNU time functions fail when the year goes to 2099 + // (and maybe less) and this would have caused a bug with DKJM2 so I'm doing + // it this way to get around that problem. + + // Note: Dai Kaijyu Monogatari II only allows dates in the range 1996-21xx. + + if (rtc.count_enable && !rtc.needs_init) + { + cur_systime = time (NULL); + + // This method assumes one time_t clock tick is one second + // which should work on PCs and GNU systems. + // If your tick interval is different adjust the + // DAYTICK, HOURTICK, and MINUTETICK defines + + time_diff = (long) (cur_systime - rtc.system_timestamp); + rtc.system_timestamp = cur_systime; + + if ( time_diff > 0 ) + { + int seconds; + int minutes; + int hours; + int days; + int month; + int year; + int temp_days; + + int year_hundreds; + int year_tens; + int year_ones; + + + if ( time_diff > DAYTICKS ) + { + days = time_diff / DAYTICKS; + time_diff = time_diff - days * DAYTICKS; + } + else + { + days = 0; + } + + if ( time_diff > HOURTICKS ) + { + hours = time_diff / HOURTICKS; + time_diff = time_diff - hours * HOURTICKS; + } + else + { + hours = 0; + } + + if ( time_diff > MINUTETICKS ) + { + minutes = time_diff / MINUTETICKS; + time_diff = time_diff - minutes * MINUTETICKS; + } + else + { + minutes = 0; + } + + if ( time_diff > 0 ) + { + seconds = time_diff; + } + else + { + seconds = 0; + } + + + seconds += (rtc.data[1]*10 + rtc.data[0]); + if ( seconds >= 60 ) + { + seconds -= 60; + minutes += 1; + } + + minutes += (rtc.data[3]*10 + rtc.data[2]); + if ( minutes >= 60 ) + { + minutes -= 60; + hours += 1; + } + + hours += (rtc.data[5]*10 + rtc.data[4]); + if ( hours >= 24 ) + { + hours -= 24; + days += 1; + } + + if ( days > 0 ) + { + year = rtc.data[10]*10 + rtc.data[9]; + year += ( 1000 + rtc.data[11] * 100 ); + + month = rtc.data[8]; + days += (rtc.data[7]*10 + rtc.data[6]); + while ( days > (temp_days = S9xSRTCDaysInMmonth( month, year )) ) + { + days -= temp_days; + month += 1; + if ( month > 12 ) + { + year += 1; + month = 1; + } + } + + year_tens = year % 100; + year_ones = year_tens % 10; + year_tens /= 10; + year_hundreds = (year - 1000) / 100; + + rtc.data[6] = days % 10; + rtc.data[7] = days / 10; + rtc.data[8] = month; + rtc.data[9] = year_ones; + rtc.data[10] = year_tens; + rtc.data[11] = year_hundreds; + rtc.data[12] = S9xSRTCComputeDayOfWeek (); + } + + rtc.data[0] = seconds % 10; + rtc.data[1] = seconds / 10; + rtc.data[2] = minutes % 10; + rtc.data[3] = minutes / 10; + rtc.data[4] = hours % 10; + rtc.data[5] = hours / 10; + + return; + } + } +} + + +/**********************************************************************************************/ +/* S9xSetSRTC() */ +/* This function sends data to the S-RTC used in Dai Kaijyu Monogatari II */ +/**********************************************************************************************/ +void S9xSetSRTC (uint8 data, uint16 Address) +{ + + data &= 0x0F; // Data is only 4-bits, mask out unused bits. + + if( data >= 0xD ) + { + // It's an RTC command + + switch ( data ) + { + case 0xD: + rtc.mode = MODE_READ; + rtc.index = -1; + break; + + case 0xE: + rtc.mode = MODE_COMMAND; + break; + + default: + // Ignore the write if it's an 0xF ??? + // Probably should switch back to read mode -- but this + // sequence never occurs in DKJM2 + break; + } + + return; + } + + if ( rtc.mode == MODE_LOAD_RTC ) + { + if ( (rtc.index >= 0) || (rtc.index < MAX_RTC_INDEX) ) + { + rtc.data[rtc.index++] = data; + + if ( rtc.index == MAX_RTC_INDEX ) + { + // We have all the data for the RTC load + + rtc.system_timestamp = time (NULL); // Get local system time + + // Get the day of the week + rtc.data[rtc.index++] = S9xSRTCComputeDayOfWeek (); + + // Start RTC counting again + rtc.count_enable = TRUE; + rtc.needs_init = FALSE; + } + + return; + } + else + { + // Attempting to write too much data + // error(); // ignore?? + } + } + else if ( rtc.mode == MODE_COMMAND ) + { + switch( data ) + { + case COMMAND_CLEAR_RTC: + // Disable RTC counter + rtc.count_enable = FALSE; + + ZeroMemory (rtc.data, MAX_RTC_INDEX+1); + rtc.index = -1; + rtc.mode = MODE_COMMAND_DONE; + break; + + case COMMAND_LOAD_RTC: + // Disable RTC counter + rtc.count_enable = FALSE; + + rtc.index = 0; // Setup for writing + rtc.mode = MODE_LOAD_RTC; + break; + + default: + rtc.mode = MODE_COMMAND_DONE; + // unrecognized command - need to implement. + } + + return; + } + else + { + if ( rtc.mode == MODE_READ ) + { + // Attempting to write while in read mode. Ignore. + } + + if ( rtc.mode == MODE_COMMAND_DONE ) + { + // Maybe this isn't an error. Maybe we should kick off + // a new E command. But is this valid? + } + } +} + +/**********************************************************************************************/ +/* S9xGetSRTC() */ +/* This function retrieves data from the S-RTC */ +/**********************************************************************************************/ +uint8 S9xGetSRTC (uint16 Address) +{ + if ( rtc.mode == MODE_READ ) + { + if ( rtc.index < 0 ) + { + S9xUpdateSrtcTime (); // Only update it if the game reads it + rtc.index++; + return ( 0x0f ); // Send start marker. + } + else if (rtc.index > MAX_RTC_INDEX) + { + rtc.index = -1; // Setup for next set of reads + return ( 0x0f ); // Data done marker. + } + else + { + // Feed out the data + return rtc.data[rtc.index++]; + } + } + else + { + return 0x0; + } +} + +void S9xSRTCPreSaveState () +{ + if (Settings.SRTC) + { + S9xUpdateSrtcTime (); + + int s = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + if (s > 0x20000) + s = 0x20000; + + SRAM [s + 0] = rtc.needs_init; + SRAM [s + 1] = rtc.count_enable; + memmove (&SRAM [s + 2], rtc.data, MAX_RTC_INDEX + 1); + SRAM [s + 3 + MAX_RTC_INDEX] = rtc.index; + SRAM [s + 4 + MAX_RTC_INDEX] = rtc.mode; + +#ifdef LSB_FIRST + memmove (&SRAM [s + 5 + MAX_RTC_INDEX], &rtc.system_timestamp, 8); +#else + SRAM [s + 5 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 0); + SRAM [s + 6 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 8); + SRAM [s + 7 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 16); + SRAM [s + 8 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 24); + SRAM [s + 9 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 32); + SRAM [s + 10 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 40); + SRAM [s + 11 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 48); + SRAM [s + 12 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 56); +#endif + } +} + +void S9xSRTCPostLoadState () +{ + if (Settings.SRTC) + { + int s = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + if (s > 0x20000) + s = 0x20000; + + rtc.needs_init = SRAM [s + 0]; + rtc.count_enable = SRAM [s + 1]; + memmove (rtc.data, &SRAM [s + 2], MAX_RTC_INDEX + 1); + rtc.index = SRAM [s + 3 + MAX_RTC_INDEX]; + rtc.mode = SRAM [s + 4 + MAX_RTC_INDEX]; + +#ifdef LSB_FIRST + memmove (&rtc.system_timestamp, &SRAM [s + 5 + MAX_RTC_INDEX], 8); +#else + rtc.system_timestamp |= (SRAM [s + 5 + MAX_RTC_INDEX] << 0); + rtc.system_timestamp |= (SRAM [s + 6 + MAX_RTC_INDEX] << 8); + rtc.system_timestamp |= (SRAM [s + 7 + MAX_RTC_INDEX] << 16); + rtc.system_timestamp |= (SRAM [s + 8 + MAX_RTC_INDEX] << 24); + rtc.system_timestamp |= (SRAM [s + 9 + MAX_RTC_INDEX] << 32); + rtc.system_timestamp |= (SRAM [s + 10 + MAX_RTC_INDEX] << 40); + rtc.system_timestamp |= (SRAM [s + 11 + MAX_RTC_INDEX] << 48); + rtc.system_timestamp |= (SRAM [s + 12 + MAX_RTC_INDEX] << 56); +#endif + S9xUpdateSrtcTime (); + } +} -- cgit v1.2.3