DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <time.h> 00021 #include <math.h> 00022 00023 #include "dosbox.h" 00024 #include "timer.h" 00025 #include "cpu.h" 00026 #include "pic.h" 00027 #include "inout.h" 00028 #include "mem.h" 00029 #include "bios_disk.h" 00030 #include "setup.h" 00031 #include "cross.h" //fmod on certain platforms 00032 #include "control.h" 00033 bool date_host_forced=false; 00034 #if defined (WIN32) && !defined (__MINGW32__) 00035 #include "sys/timeb.h" 00036 #else 00037 #include "sys/time.h" 00038 #endif 00039 00040 // sigh... Windows doesn't know gettimeofday 00041 #if defined (WIN32) && !defined (__MINGW32__) 00042 typedef Bitu suseconds_t; 00043 00044 struct timeval { 00045 time_t tv_sec; 00046 suseconds_t tv_usec; 00047 }; 00048 00049 static void gettimeofday (timeval* ptime, void* pdummy) { 00050 struct _timeb thetime; 00051 _ftime(&thetime); 00052 00053 ptime->tv_sec = thetime.time; 00054 ptime->tv_usec = (Bitu)thetime.millitm; 00055 } 00056 00057 #endif 00058 00059 static struct { 00060 Bit8u regs[0x40]; 00061 bool nmi; 00062 bool bcd; 00063 bool ampm; // am/pm mode (false = 24h mode) 00064 bool lock; // lock bit set (no updates) 00065 Bit8u reg; 00066 struct { 00067 bool enabled; 00068 Bit8u div; 00069 float delay; 00070 bool acknowledged; 00071 } timer; 00072 struct { 00073 double timer; 00074 double ended; 00075 double alarm; 00076 } last; 00077 bool update_ended; 00078 time_t time_diff; // difference between real UTC and DOSbox UTC 00079 struct timeval locktime; // UTC time of setting lock bit 00080 struct timeval safetime; // UTC time of last safe time 00081 } cmos; 00082 00083 static void cmos_timerevent(Bitu val) { 00084 (void)val;//UNUSED 00085 if (cmos.timer.acknowledged) { 00086 cmos.timer.acknowledged=false; 00087 PIC_ActivateIRQ(8); 00088 } 00089 if (cmos.timer.enabled) { 00090 PIC_AddEvent(cmos_timerevent,cmos.timer.delay); 00091 cmos.regs[0xc] = 0xC0;//Contraption Zack (music) 00092 } 00093 } 00094 00095 static void cmos_checktimer(void) { 00096 PIC_RemoveEvents(cmos_timerevent); 00097 if (cmos.timer.div<=2) cmos.timer.div+=7; 00098 cmos.timer.delay=(1000.0f/(32768.0f / (1 << (cmos.timer.div - 1)))); 00099 if (!cmos.timer.div || !cmos.timer.enabled) return; 00100 LOG(LOG_PIT,LOG_NORMAL)("RTC Timer at %.2f hz",1000.0/cmos.timer.delay); 00101 // PIC_AddEvent(cmos_timerevent,cmos.timer.delay); 00102 /* A rtc is always running */ 00103 double remd=fmod(PIC_FullIndex(),(double)cmos.timer.delay); 00104 PIC_AddEvent(cmos_timerevent,(float)((double)cmos.timer.delay-remd)); //Should be more like a real pc. Check 00105 // status reg A reading with this (and with other delays actually) 00106 } 00107 00108 void cmos_selreg(Bitu port,Bitu val,Bitu iolen) { 00109 (void)port;//UNUSED 00110 (void)iolen;//UNUSED 00111 if (machine != MCH_PCJR) { 00112 /* bit 7 also controls NMI masking, if set, NMI is disabled */ 00113 CPU_NMI_gate = (val&0x80) ? false : true; 00114 } 00115 00116 cmos.reg=val & 0x3f; 00117 cmos.nmi=(val & 0x80)>0; 00118 } 00119 00120 static void cmos_writereg(Bitu port,Bitu val,Bitu iolen) { 00121 (void)port;//UNUSED 00122 (void)iolen;//UNUSED 00123 if (date_host_forced && (cmos.reg <= 0x09 || cmos.reg == 0x32)) { // date/time related registers 00124 if (cmos.bcd) // values supplied are BCD, convert to binary values 00125 { 00126 if ((val & 0xf0) > 0x90 || (val & 0x0f) > 0x09) return; // invalid BCD value 00127 // other checks for valid values are done in case-switch 00128 00129 // convert pm hours differently (bcd 81-92 corresponds to hex 81-8c) 00130 if (cmos.reg == 0x04 && val >= 0x80) 00131 { 00132 val = (val < 90) ? 0x80 : 0x8a + (val & 0x0f); 00133 } 00134 else 00135 { 00136 val = ((val >> 4) * 10) + (val & 0x0f); 00137 } 00138 } 00139 00140 struct tm *loctime; // local dosbox time (based on dosbox UTC) 00141 00142 if (cmos.lock) // if locked, use locktime instead of current time 00143 { 00144 loctime = localtime((time_t*)&cmos.locktime.tv_sec); 00145 } 00146 else // not locked, use current time 00147 { 00148 struct timeval curtime; 00149 gettimeofday(&curtime, NULL); 00150 curtime.tv_sec += cmos.time_diff; 00151 loctime = localtime((time_t*)&curtime.tv_sec); 00152 } 00153 00154 switch (cmos.reg) 00155 { 00156 case 0x00: /* Seconds */ 00157 if (val > 59) return; // invalid seconds value 00158 loctime->tm_sec = (int)val; 00159 break; 00160 00161 case 0x02: /* Minutes */ 00162 if (val > 59) return; // invalid minutes value 00163 loctime->tm_min = (int)val; 00164 break; 00165 00166 case 0x04: /* Hours */ 00167 if (cmos.ampm) // 12h am/pm mode 00168 { 00169 if ((val > 12 && val < 0x81) || val > 0x8c) return; // invalid hour value 00170 if (val > 12) val -= (0x80-12); // convert pm to 24h 00171 } 00172 else // 24h mode 00173 { 00174 if (val > 23) return; // invalid hour value 00175 } 00176 00177 loctime->tm_hour = (int)val; 00178 break; 00179 00180 case 0x06: /* Day of week */ 00181 // seems silly to set this, as it is calculated? ignore for now 00182 break; 00183 00184 case 0x07: /* Date of month */ 00185 if (val > 31) return; // invalid date value (mktime() should catch the rest) 00186 loctime->tm_mday = (int)val; 00187 break; 00188 00189 case 0x08: /* Month */ 00190 if (val > 12) return; // invalid month value 00191 loctime->tm_mon = (int)val; 00192 break; 00193 00194 case 0x09: /* Year */ 00195 loctime->tm_year = (int)val; 00196 break; 00197 00198 case 0x32: /* Century */ 00199 if (val < 19) return; // invalid century value? 00200 loctime->tm_year += (int)((val * 100) - 1900); 00201 break; 00202 00203 case 0x01: /* Seconds Alarm */ 00204 case 0x03: /* Minutes Alarm */ 00205 case 0x05: /* Hours Alarm */ 00206 LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Trying to set alarm"); 00207 cmos.regs[cmos.reg] = (Bit8u)val; 00208 return; // done 00209 } 00210 00211 time_t newtime = mktime(loctime); // convert new local time back to dosbox UTC 00212 00213 if (newtime != (time_t)-1) 00214 { 00215 if (!cmos.lock) // no lock, takes immediate effect 00216 { 00217 cmos.time_diff = newtime - time(NULL); // calculate new diff 00218 } 00219 else 00220 { 00221 cmos.locktime.tv_sec = newtime; // store for later use 00222 // no need to set usec, we don't use it 00223 } 00224 } 00225 00226 return; 00227 } 00228 00229 switch (cmos.reg) { 00230 case 0x00: /* Seconds */ 00231 case 0x02: /* Minutes */ 00232 case 0x04: /* Hours */ 00233 case 0x06: /* Day of week */ 00234 case 0x07: /* Date of month */ 00235 case 0x08: /* Month */ 00236 case 0x09: /* Year */ 00237 case 0x32: /* Century */ 00238 /* Ignore writes to change alarm */ 00239 if(!date_host_forced) break; 00240 case 0x01: /* Seconds Alarm */ 00241 case 0x03: /* Minutes Alarm */ 00242 case 0x05: /* Hours Alarm */ 00243 if(!date_host_forced) { 00244 LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Trying to set alarm"); 00245 cmos.regs[cmos.reg]=(Bit8u)val; 00246 break; 00247 } 00248 case 0x0a: /* Status reg A */ 00249 cmos.regs[cmos.reg]=val & 0x7f; 00250 if ((val & 0x70)!=0x20) LOG(LOG_BIOS,LOG_ERROR)("CMOS Illegal 22 stage divider value"); 00251 cmos.timer.div=(val & 0xf); 00252 cmos_checktimer(); 00253 break; 00254 case 0x0b: /* Status reg B */ 00255 if(date_host_forced) { 00256 bool waslocked = cmos.lock; 00257 00258 cmos.ampm = !(val & 0x02); 00259 cmos.bcd = !(val & 0x04); 00260 if ((val & 0x10) != 0) LOG(LOG_BIOS,LOG_ERROR)("CMOS:Updated ended interrupt not supported yet"); 00261 cmos.timer.enabled = (val & 0x40) > 0; 00262 cmos.lock = (val & 0x80) != 0; 00263 00264 if (cmos.lock) // if locked, set locktime for later use 00265 { 00266 if (!waslocked) // if already locked, no further action 00267 { 00268 // locked for the first time, calculate dosbox UTC 00269 gettimeofday(&cmos.locktime, NULL); 00270 cmos.locktime.tv_sec += cmos.time_diff; 00271 } 00272 } 00273 else if (waslocked) // time was locked, now unlock 00274 { 00275 // calculate new diff between real UTC and dosbox UTC 00276 cmos.time_diff = cmos.locktime.tv_sec - time(NULL); 00277 } 00278 00279 cmos.regs[cmos.reg] = (Bit8u)val; 00280 cmos_checktimer(); 00281 } else { 00282 cmos.bcd=!(val & 0x4); 00283 cmos.regs[cmos.reg]=val & 0x7f; 00284 cmos.timer.enabled=(val & 0x40)>0; 00285 if (val&0x10) LOG(LOG_BIOS,LOG_ERROR)("CMOS:Updated ended interrupt not supported yet"); 00286 cmos_checktimer(); 00287 } 00288 break; 00289 case 0x0c: 00290 if(date_host_forced) break; 00291 case 0x0d:/* Status reg D */ 00292 if(!date_host_forced) { 00293 cmos.regs[cmos.reg]=val & 0x80; /*Bit 7=1:RTC Pown on*/ 00294 } 00295 break; 00296 case 0x0f: /* Shutdown status byte */ 00297 cmos.regs[cmos.reg]=val & 0x7f; 00298 break; 00299 default: 00300 cmos.regs[cmos.reg]=val & 0x7f; 00301 LOG(LOG_BIOS,LOG_ERROR)("CMOS:WRite to unhandled register %x",cmos.reg); 00302 } 00303 } 00304 00305 unsigned char CMOS_GetShutdownByte() { 00306 return cmos.regs[0x0F]; 00307 } 00308 00309 #define MAKE_RETURN(_VAL) ((unsigned char)(cmos.bcd ? (((((unsigned int)_VAL) / 10U) << 4U) | (((unsigned int)_VAL) % 10U)) : ((unsigned int)_VAL))) 00310 00311 static Bitu cmos_readreg(Bitu port,Bitu iolen) { 00312 (void)port;//UNUSED 00313 (void)iolen;//UNUSED 00314 if (cmos.reg>0x3f) { 00315 LOG(LOG_BIOS,LOG_ERROR)("CMOS:Read from illegal register %x",cmos.reg); 00316 return 0xff; 00317 } 00318 00319 // JAL_20060817 - rewrote most of the date/time part 00320 if (date_host_forced && (cmos.reg <= 0x09 || cmos.reg == 0x32)) { // date/time related registers 00321 struct tm* loctime; 00322 00323 if (cmos.lock) // if locked, use locktime instead of current time 00324 { 00325 loctime = localtime((time_t*)&cmos.locktime.tv_sec); 00326 } 00327 else // not locked, get current time 00328 { 00329 struct timeval curtime; 00330 gettimeofday(&curtime, NULL); 00331 00332 // allow a little more leeway (1 sec) than the .244 sec officially given 00333 if (curtime.tv_sec - cmos.safetime.tv_sec == 1 && 00334 curtime.tv_usec < cmos.safetime.tv_usec) 00335 { 00336 curtime = cmos.safetime; // within safe range, use safetime instead of current time 00337 } 00338 00339 curtime.tv_sec += cmos.time_diff; 00340 loctime = localtime((time_t*)&curtime.tv_sec); 00341 } 00342 00343 switch (cmos.reg) 00344 { 00345 case 0x00: // seconds 00346 return MAKE_RETURN(loctime->tm_sec); 00347 case 0x02: // minutes 00348 return MAKE_RETURN(loctime->tm_min); 00349 case 0x04: // hours 00350 if (cmos.ampm && loctime->tm_hour > 12) // time pm, convert 00351 { 00352 loctime->tm_hour -= 12; 00353 loctime->tm_hour += (cmos.bcd) ? 80 : 0x80; 00354 } 00355 return MAKE_RETURN(loctime->tm_hour); 00356 case 0x06: /* Day of week */ 00357 return MAKE_RETURN(loctime->tm_wday + 1); 00358 case 0x07: /* Date of month */ 00359 return MAKE_RETURN(loctime->tm_mday); 00360 case 0x08: /* Month */ 00361 return MAKE_RETURN(loctime->tm_mon + 1); 00362 case 0x09: /* Year */ 00363 return MAKE_RETURN(loctime->tm_year % 100); 00364 case 0x32: /* Century */ 00365 return MAKE_RETURN(loctime->tm_year / 100 + 19); 00366 00367 case 0x01: /* Seconds Alarm */ 00368 case 0x03: /* Minutes Alarm */ 00369 case 0x05: /* Hours Alarm */ 00370 return MAKE_RETURN(cmos.regs[cmos.reg]); 00371 } 00372 } 00373 00374 Bitu drive_a, drive_b; 00375 Bit8u hdparm; 00376 time_t curtime; 00377 struct tm *loctime; 00378 /* Get the current time. */ 00379 curtime = time (NULL); 00380 00381 /* Convert it to local time representation. */ 00382 loctime = localtime (&curtime); 00383 00384 switch (cmos.reg) { 00385 case 0x00: /* Seconds */ 00386 if(!date_host_forced) return MAKE_RETURN(loctime->tm_sec); 00387 case 0x02: /* Minutes */ 00388 if(!date_host_forced) return MAKE_RETURN(loctime->tm_min); 00389 case 0x04: /* Hours */ 00390 if(!date_host_forced) return MAKE_RETURN(loctime->tm_hour); 00391 case 0x06: /* Day of week */ 00392 if(!date_host_forced) return MAKE_RETURN(loctime->tm_wday + 1); 00393 case 0x07: /* Date of month */ 00394 if(!date_host_forced) return MAKE_RETURN(loctime->tm_mday); 00395 case 0x08: /* Month */ 00396 if(!date_host_forced) return MAKE_RETURN(loctime->tm_mon + 1); 00397 case 0x09: /* Year */ 00398 if(!date_host_forced) return MAKE_RETURN(loctime->tm_year % 100); 00399 case 0x32: /* Century */ 00400 if(!date_host_forced) return MAKE_RETURN(loctime->tm_year / 100 + 19); 00401 case 0x01: /* Seconds Alarm */ 00402 case 0x03: /* Minutes Alarm */ 00403 case 0x05: /* Hours Alarm */ 00404 if(!date_host_forced) return cmos.regs[cmos.reg]; 00405 case 0x0a: /* Status register A */ 00406 if(date_host_forced) { 00407 // take bit 7 of reg b into account (if set, never updates) 00408 gettimeofday (&cmos.safetime, NULL); // get current UTC time 00409 if (cmos.lock || // if lock then never updated, so reading safe 00410 cmos.safetime.tv_usec < (1000-244)) { // if 0, at least 244 usec should be available 00411 return cmos.regs[0x0a]; // reading safe 00412 } else { 00413 return cmos.regs[0x0a] | 0x80; // reading not safe! 00414 } 00415 } else { 00416 if (PIC_TickIndex()<0.002) { 00417 return (cmos.regs[0x0a]&0x7f) | 0x80; 00418 } else { 00419 return (cmos.regs[0x0a]&0x7f); 00420 } 00421 } 00422 case 0x0c: /* Status register C */ 00423 cmos.timer.acknowledged=true; 00424 if (cmos.timer.enabled) { 00425 /* In periodic interrupt mode only care for those flags */ 00426 Bit8u val=cmos.regs[0xc]; 00427 cmos.regs[0xc]=0; 00428 return val; 00429 } else { 00430 /* Give correct values at certain times */ 00431 Bit8u val=0; 00432 double index=PIC_FullIndex(); 00433 if (index>=(cmos.last.timer+cmos.timer.delay)) { 00434 cmos.last.timer=index; 00435 val|=0x40; 00436 } 00437 if (index>=(cmos.last.ended+1000)) { 00438 cmos.last.ended=index; 00439 val|=0x10; 00440 } 00441 if(date_host_forced) cmos.regs[0xc] = 0; // JAL_20060817 - reset here too! 00442 return val; 00443 } 00444 case 0x10: /* Floppy size */ 00445 drive_a = 0; 00446 drive_b = 0; 00447 if(imageDiskList[0] != NULL) drive_a = imageDiskList[0]->GetBiosType(); 00448 if(imageDiskList[1] != NULL) drive_b = imageDiskList[1]->GetBiosType(); 00449 return ((drive_a << 4) | (drive_b)); 00450 /* First harddrive info */ 00451 case 0x12: 00452 /* NTS: DOSBox 0.74 mainline has these backwards: the upper nibble is the first hard disk, 00453 the lower nibble is the second hard disk. It makes a big difference to stupid OS's like 00454 Windows 95. */ 00455 hdparm = 0; 00456 if(imageDiskList[3] != NULL) hdparm |= 0xf; 00457 if(imageDiskList[2] != NULL) hdparm |= 0xf0; 00458 // hdparm = 0; 00459 return hdparm; 00460 case 0x19: 00461 if(imageDiskList[2] != NULL) return 47; /* User defined type */ 00462 return 0; 00463 case 0x1b: 00464 if(imageDiskList[2] != NULL) return (imageDiskList[2]->cylinders & 0xff); 00465 return 0; 00466 case 0x1c: 00467 if(imageDiskList[2] != NULL) return ((imageDiskList[2]->cylinders & 0xff00)>>8); 00468 return 0; 00469 case 0x1d: 00470 if(imageDiskList[2] != NULL) return (imageDiskList[2]->heads); 00471 return 0; 00472 case 0x1e: 00473 if(imageDiskList[2] != NULL) return 0xff; 00474 return 0; 00475 case 0x1f: 00476 if(imageDiskList[2] != NULL) return 0xff; 00477 return 0; 00478 case 0x20: 00479 if(imageDiskList[2] != NULL) return (0xc0 | (((imageDiskList[2]->heads) > 8) << 3)); 00480 return 0; 00481 case 0x21: 00482 if(imageDiskList[2] != NULL) return (imageDiskList[2]->cylinders & 0xff); 00483 return 0; 00484 case 0x22: 00485 if(imageDiskList[2] != NULL) return ((imageDiskList[2]->cylinders & 0xff00)>>8); 00486 return 0; 00487 case 0x23: 00488 if(imageDiskList[2] != NULL) return (imageDiskList[2]->sectors); 00489 return 0; 00490 /* Second harddrive info */ 00491 case 0x1a: 00492 if(imageDiskList[3] != NULL) return 47; /* User defined type */ 00493 return 0; 00494 case 0x24: 00495 if(imageDiskList[3] != NULL) return (imageDiskList[3]->cylinders & 0xff); 00496 return 0; 00497 case 0x25: 00498 if(imageDiskList[3] != NULL) return ((imageDiskList[3]->cylinders & 0xff00)>>8); 00499 return 0; 00500 case 0x26: 00501 if(imageDiskList[3] != NULL) return (imageDiskList[3]->heads); 00502 return 0; 00503 case 0x27: 00504 if(imageDiskList[3] != NULL) return 0xff; 00505 return 0; 00506 case 0x28: 00507 if(imageDiskList[3] != NULL) return 0xff; 00508 return 0; 00509 case 0x29: 00510 if(imageDiskList[3] != NULL) return (0xc0 | (((imageDiskList[3]->heads) > 8) << 3)); 00511 return 0; 00512 case 0x2a: 00513 if(imageDiskList[3] != NULL) return (imageDiskList[3]->cylinders & 0xff); 00514 return 0; 00515 case 0x2b: 00516 if(imageDiskList[3] != NULL) return ((imageDiskList[3]->cylinders & 0xff00)>>8); 00517 return 0; 00518 case 0x2c: 00519 if(imageDiskList[3] != NULL) return (imageDiskList[3]->sectors); 00520 return 0; 00521 case 0x39: 00522 return 0; 00523 case 0x3a: 00524 return 0; 00525 00526 00527 case 0x0b: /* Status register B */ 00528 case 0x0d: /* Status register D */ 00529 case 0x0f: /* Shutdown status byte */ 00530 case 0x14: /* Equipment */ 00531 case 0x15: /* Base Memory KB Low Byte */ 00532 case 0x16: /* Base Memory KB High Byte */ 00533 case 0x17: /* Extended memory in KB Low Byte */ 00534 case 0x18: /* Extended memory in KB High Byte */ 00535 case 0x30: /* Extended memory in KB Low Byte */ 00536 case 0x31: /* Extended memory in KB High Byte */ 00537 // LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %X : %04X",cmos.reg,cmos.regs[cmos.reg]); 00538 return cmos.regs[cmos.reg]; 00539 case 0x2F: 00540 extern bool PS1AudioCard; 00541 if( PS1AudioCard ) 00542 return 0xFF; 00543 default: 00544 LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %X",cmos.reg); 00545 return cmos.regs[cmos.reg]; 00546 } 00547 } 00548 00549 void CMOS_SetRegister(Bitu regNr, Bit8u val) { 00550 cmos.regs[regNr] = val; 00551 } 00552 00553 00554 static IO_ReadHandleObject ReadHandler[2]; 00555 static IO_WriteHandleObject WriteHandler[2]; 00556 00557 void CMOS_Destroy(Section* sec) { 00558 (void)sec;//UNUSED 00559 } 00560 00561 void CMOS_Reset(Section* sec) { 00562 (void)sec;//UNUSED 00563 LOG(LOG_MISC,LOG_DEBUG)("CMOS_Reset(): reinitializing CMOS/RTC controller"); 00564 00565 WriteHandler[0].Uninstall(); 00566 WriteHandler[1].Uninstall(); 00567 ReadHandler[0].Uninstall(); 00568 ReadHandler[1].Uninstall(); 00569 00570 if (IS_PC98_ARCH) 00571 return; 00572 00573 WriteHandler[0].Install(0x70,cmos_selreg,IO_MB); 00574 WriteHandler[1].Install(0x71,cmos_writereg,IO_MB); 00575 ReadHandler[0].Install(0x71,cmos_readreg,IO_MB); 00576 cmos.timer.enabled=false; 00577 cmos.timer.acknowledged=true; 00578 cmos.reg=0xa; 00579 cmos_writereg(0x71,0x26,1); 00580 cmos.reg=0xb; 00581 cmos_writereg(0x71,0x2,1); //Struct tm *loctime is of 24 hour format, 00582 if(date_host_forced) { 00583 cmos.regs[0x0d]=(Bit8u)0x80; 00584 } else { 00585 cmos.reg=0xd; 00586 cmos_writereg(0x71,0x80,1); /* RTC power on */ 00587 } 00588 // Equipment is updated from bios.cpp and bios_disk.cpp 00589 /* Fill in base memory size, it is 640K always */ 00590 cmos.regs[0x15]=(Bit8u)0x80; 00591 cmos.regs[0x16]=(Bit8u)0x02; 00592 /* Fill in extended memory size */ 00593 Bitu exsize=MEM_TotalPages()*4; 00594 if (exsize >= 1024) exsize -= 1024; 00595 else exsize = 0; 00596 if (exsize > 65535) exsize = 65535; /* cap at 64MB. this value is returned as-is by INT 15H AH=0x88 in a 16-bit register */ 00597 cmos.regs[0x17]=(Bit8u)exsize; 00598 cmos.regs[0x18]=(Bit8u)(exsize >> 8); 00599 cmos.regs[0x30]=(Bit8u)exsize; 00600 cmos.regs[0x31]=(Bit8u)(exsize >> 8); 00601 if (date_host_forced) { 00602 cmos.time_diff = 0; 00603 cmos.locktime.tv_sec = 0; 00604 } 00605 } 00606 00607 void CMOS_Init() { 00608 LOG(LOG_MISC,LOG_DEBUG)("Initializing CMOS/RTC"); 00609 00610 if (control->opt_date_host_forced) { 00611 LOG_MSG("Synchronize date with host: Forced"); 00612 date_host_forced=true; 00613 } 00614 00615 AddExitFunction(AddExitFunctionFuncPair(CMOS_Destroy),true); 00616 AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(CMOS_Reset)); 00617 } 00618 00619 // save state support 00620 void *cmos_timerevent_PIC_Event = (void*)((uintptr_t)cmos_timerevent); 00621 00622 namespace 00623 { 00624 class SerializeCmos : public SerializeGlobalPOD 00625 { 00626 public: 00627 SerializeCmos() : SerializeGlobalPOD("CMOS") 00628 { 00629 registerPOD(cmos.regs); 00630 registerPOD(cmos.nmi); 00631 registerPOD(cmos.reg); 00632 registerPOD(cmos.timer.enabled); 00633 registerPOD(cmos.timer.div); 00634 registerPOD(cmos.timer.delay); 00635 registerPOD(cmos.timer.acknowledged); 00636 registerPOD(cmos.last.timer); 00637 registerPOD(cmos.last.ended); 00638 registerPOD(cmos.last.alarm); 00639 registerPOD(cmos.update_ended); 00640 } 00641 } dummy; 00642 }