Mercurial > vba-clojure
view src/gba/RTC.cpp @ 536:c2ee7222a3c4
investigating a problem with bad sound when writing RAM with bootstrapping program
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 25 Jun 2012 14:23:16 -0500 |
parents | f9f4f1b99eed |
children |
line wrap: on
line source
1 #include <cstring>3 #include "../Port.h"4 #include "../NLS.h"5 #include "../common/System.h" // systemMessage6 #include "../common/Util.h"7 #include "../common/movie.h"8 #include "GBAGlobals.h"10 enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };12 typedef struct13 {14 u8 byte0;15 u8 byte1;16 u8 byte2;17 u8 command;18 int dataLen;19 int bits;20 RTCSTATE state;21 u8 data[12];22 // reserved variables for future23 u8 reserved[12];24 bool reserved2;25 u32 reserved3;26 } RTCCLOCKDATA;28 static RTCCLOCKDATA rtcClockData;29 static bool rtcEnabled = false;31 void rtcEnable(bool enable)32 {33 rtcEnabled = enable;34 }36 bool rtcIsEnabled()37 {38 return rtcEnabled;39 }41 u16 rtcRead(u32 address)42 {43 if (rtcEnabled)44 {45 if (address == 0x80000c8)46 return rtcClockData.byte2;47 else if (address == 0x80000c6)48 return rtcClockData.byte1;49 else if (address == 0x80000c4)50 {51 return rtcClockData.byte0;52 }53 }55 return READ16LE((&rom[address & 0x1FFFFFE]));56 }58 static u8 toBCD(u8 value)59 {60 value = value % 100;61 int l = value % 10;62 int h = value / 10;63 return h * 16 + l;64 }66 bool rtcWrite(u32 address, u16 value)67 {68 if (!rtcEnabled)69 return false;71 if (address == 0x80000c8)72 {73 rtcClockData.byte2 = (u8)value; // enable ?74 }75 else if (address == 0x80000c6)76 {77 rtcClockData.byte1 = (u8)value; // read/write78 }79 else if (address == 0x80000c4)80 {81 if (rtcClockData.byte2 & 1)82 {83 if (rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5)84 {85 rtcClockData.state = COMMAND;86 rtcClockData.bits = 0;87 rtcClockData.command = 0;88 }89 else if (!(rtcClockData.byte0 & 1) && (value & 1)) // bit transfer90 {91 rtcClockData.byte0 = (u8)value;92 switch (rtcClockData.state)93 {94 case COMMAND:95 rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits);96 rtcClockData.bits++;97 if (rtcClockData.bits == 8)98 {99 rtcClockData.bits = 0;100 switch (rtcClockData.command)101 {102 case 0x60:103 // not sure what this command does but it doesn't take parameters104 // maybe it is a reset or stop105 rtcClockData.state = IDLE;106 rtcClockData.bits = 0;107 break;108 case 0x62:109 // this sets the control state but not sure what those values are110 rtcClockData.state = READDATA;111 rtcClockData.dataLen = 1;112 break;113 case 0x63:114 rtcClockData.dataLen = 1;115 rtcClockData.data[0] = 0x40;116 rtcClockData.state = DATA;117 break;118 case 0x65:119 {120 struct tm *newtime;121 time_t long_time;123 if (VBAMovieActive() || VBAMovieLoading())124 {125 long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;126 newtime = gmtime(&long_time);127 }128 else129 {130 time(&long_time); /* Get time as long integer. */131 newtime = localtime(&long_time); /* Convert to local time. */132 }134 rtcClockData.dataLen = 7;135 rtcClockData.data[0] = toBCD(newtime->tm_year);136 rtcClockData.data[1] = toBCD(newtime->tm_mon+1);137 rtcClockData.data[2] = toBCD(newtime->tm_mday);138 rtcClockData.data[3] = 0;139 rtcClockData.data[4] = toBCD(newtime->tm_hour);140 rtcClockData.data[5] = toBCD(newtime->tm_min);141 rtcClockData.data[6] = toBCD(newtime->tm_sec);142 rtcClockData.state = DATA;143 break;144 }145 case 0x67:146 {147 struct tm *newtime;148 time_t long_time;150 if (VBAMovieActive() || VBAMovieLoading())151 {152 long_time = VBAMovieGetId() + VBAMovieGetFrameCounter()/60;153 newtime = gmtime(&long_time);154 }155 else156 {157 time(&long_time); /* Get time as long integer. */158 newtime = localtime(&long_time); /* Convert to local time. */159 }161 rtcClockData.dataLen = 3;162 rtcClockData.data[0] = toBCD(newtime->tm_hour);163 rtcClockData.data[1] = toBCD(newtime->tm_min);164 rtcClockData.data[2] = toBCD(newtime->tm_sec);165 rtcClockData.state = DATA;166 break;167 }168 default:169 systemMessage(0, N_("Unknown RTC command %02x"), rtcClockData.command);170 rtcClockData.state = IDLE;171 break;172 }173 }174 break;175 case DATA:176 if (rtcClockData.byte1 & 2)177 {}178 else179 {180 rtcClockData.byte0 = (rtcClockData.byte0 & ~2) |181 ((rtcClockData.data[rtcClockData.bits >> 3] >>182 (rtcClockData.bits & 7)) & 1)*2;183 rtcClockData.bits++;184 if (rtcClockData.bits == 8*rtcClockData.dataLen)185 {186 rtcClockData.bits = 0;187 rtcClockData.state = IDLE;188 }189 }190 break;191 case READDATA:192 if (!(rtcClockData.byte1 & 2))193 {}194 else195 {196 rtcClockData.data[rtcClockData.bits >> 3] =197 (rtcClockData.data[rtcClockData.bits >> 3] >> 1) |198 ((value << 6) & 128);199 rtcClockData.bits++;200 if (rtcClockData.bits == 8*rtcClockData.dataLen)201 {202 rtcClockData.bits = 0;203 rtcClockData.state = IDLE;204 }205 }206 break;207 default:208 break;209 }210 }211 else212 rtcClockData.byte0 = (u8)value;213 }214 }215 return true;216 }218 void rtcReset()219 {220 memset(&rtcClockData, 0, sizeof(rtcClockData));222 rtcClockData.byte0 = 0;223 rtcClockData.byte1 = 0;224 rtcClockData.byte2 = 0;225 rtcClockData.command = 0;226 rtcClockData.dataLen = 0;227 rtcClockData.bits = 0;228 rtcClockData.state = IDLE;229 }231 void rtcSaveGame(gzFile gzFile)232 {233 utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));234 }236 void rtcReadGame(gzFile gzFile)237 {238 utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));239 }