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 <math.h> 00021 #include "dosbox.h" 00022 #include "inout.h" 00023 #include "pic.h" 00024 #include "cpu.h" 00025 #include "mem.h" 00026 #include "mixer.h" 00027 #include "timer.h" 00028 #include "setup.h" 00029 #include "control.h" 00030 00031 // This is only set in PC-98 mode and only if emulating PC-9801. 00032 // There is at least one game (PC-98 port of Thexder) that depends on PC-9801 PIT 1 00033 // behavior where the counter cycles at all times whether or not the PC speaker is 00034 // "on". This does not force the PC speaker output on (does not force an audible beep), 00035 // it only forces the clock gate on and PIT 1 to cycle. 00036 bool speaker_clock_lock_on = false; 00037 00038 static INLINE void BIN2BCD(Bit16u& val) { 00039 Bit16u temp=val%10 + (((val/10)%10)<<4)+ (((val/100)%10)<<8) + (((val/1000)%10)<<12); 00040 val=temp; 00041 } 00042 00043 static INLINE void BCD2BIN(Bit16u& val) { 00044 Bit16u temp= (val&0x0f) +((val>>4)&0x0f) *10 +((val>>8)&0x0f) *100 +((val>>12)&0x0f) *1000; 00045 val=temp; 00046 } 00047 00048 struct PIT_Block { 00049 struct read_counter_result { 00050 Bit16u counter = 0xFFFFu; 00051 Bit16u cycle = 0; // cycle (Mode 3: 0 or 1) 00052 }; 00053 00054 Bitu cntr = 0; /* counter value written to 40h-42h as the interval. may take effect immediately (after port 43h) or after count expires */ 00055 Bitu cntr_cur = 0; /* current counter value in effect */ 00056 double delay = 0; /* interval (in ms) between one full count cycle */ 00057 double start = 0; /* time base (in ms) that cycle started at */ 00058 double now = 0; /* current time (in ms) */ 00059 00060 Bit16u read_latch = 0; /* counter value, latched for read back */ 00061 Bit16u write_latch = 0; /* counter value, written by host */ 00062 00063 Bit8u mode = 0; /* 8254 mode (mode 0 through 5 inclusive) */ 00064 Bit8u read_state = 0; /* 0=read MSB, switch to LSB, 1=LSB only, 2=MSB only, 3=read LSB, switch to MSB, latch next value */ 00065 Bit8u write_state = 0; /* 0=write MSB, switch to LSB, 1=LSB only, 2=MSB only, 3=write MSB, switch to LSB, accept value */ 00066 Bit8u cycle_base = 0; 00067 00068 bool bcd = false; /* BCD mode */ 00069 bool go_read_latch = false; /* reading should latch another value */ 00070 bool new_mode = false; /* a new mode has been written to port 43h for this timer */ 00071 bool counterstatus_set = false; /* set by status_latch(), when using 8254 command to latch multiple counters */ 00072 bool counting = false; /* is counting (?) */ 00073 bool update_count = false; /* update count on completion */ 00074 00075 bool gate = true; /* gate signal (IN) */ 00076 bool output = true; /* output signal (OUT) */ 00077 00078 read_counter_result last_counter; /* what to return when gate == false (not counting) */ 00079 00080 void set_output(bool on) { 00081 output = on; 00082 // TODO: Event callback 00083 } 00084 00085 void set_next_counter(Bitu new_cntr) { 00086 update_count = true; 00087 cntr = new_cntr; 00088 } 00089 void set_active_counter(Bitu new_cntr) { 00090 assert(new_cntr != 0); 00091 00092 cntr_cur = new_cntr; 00093 delay = ((double)(1000ul * cntr_cur)) / PIT_TICK_RATE; 00094 } 00095 void latch_next_counter(void) { 00096 set_active_counter(cntr); 00097 } 00098 void reset_count_at(pic_tickindex_t t) { 00099 start = now = t; 00100 cycle_base = 0; 00101 } 00102 void restart_counter_at(pic_tickindex_t t,Bit16u counter) { 00103 double c_delay; 00104 00105 if (counter == 0) 00106 c_delay = ((double)(1000ull * 0x10000)) / PIT_TICK_RATE; 00107 else 00108 c_delay = ((double)(1000ull * counter)) / PIT_TICK_RATE; 00109 00110 start = (t - c_delay); 00111 } 00112 void track_time(pic_tickindex_t t) { 00113 now = t; 00114 00115 /* Mode 0 will always reset the count whether "new mode" or not. 00116 * Mode 1 will count down and stop. TODO: Writing a new counter without "new mode" starts another countdown? */ 00117 /* if any periodic mode (Mode 2, 3, 4, 5), then process fully. */ 00118 if (mode == 3) { 00119 const double half = delay / 2; 00120 00121 if (now >= (start+half)) { 00122 cycle_base = (cycle_base + 1u) & 1u; 00123 start += half; 00124 00125 if (update_count) { 00126 latch_next_counter(); 00127 update_count = false; 00128 } 00129 00130 if (now >= (start+half)) { 00131 unsigned int cnt = (unsigned int)floor((now - start) / half); 00132 cycle_base = (cycle_base + cnt) & 1u; 00133 start += cnt * half; 00134 } 00135 } 00136 } 00137 else if (mode >= 2) { 00138 if (now >= (start+delay)) { 00139 start += delay; 00140 00141 if (update_count) { 00142 latch_next_counter(); 00143 update_count = false; 00144 } 00145 00146 if (now >= (start+delay)) 00147 start += floor((now - start) / delay) * delay; 00148 } 00149 } 00150 00151 if (now < start) 00152 now = start; 00153 } 00154 double reltime(void) const { 00155 return now - start; 00156 } 00157 00158 void set_gate(bool on) { 00159 if (gate != on) { 00160 if (!on)/*on=false gate=true*/ 00161 last_counter = read_counter(); 00162 00163 // restart aka "trigger" the counters 00164 switch (mode) { 00165 case 0: /* Interrupt on Terminal Count */ 00166 case 4: /* Software Triggered Strobe */ 00167 restart_counter_at(now,last_counter.counter); 00168 break; 00169 case 1: /* Hardware Triggered one-shot */ 00170 /* output goes LOW when triggered, returns HIGH when counter expires */ 00171 if (on) { 00172 reset_count_at(now); 00173 latch_next_counter(); 00174 set_output(false); 00175 } 00176 /* TODO */ 00177 break; 00178 case 2: /* Rate Generator */ 00179 /* output goes HIGH immediately */ 00180 if (on) { 00181 reset_count_at(now); 00182 latch_next_counter(); 00183 } 00184 else { 00185 set_output(true); 00186 } 00187 /* TODO */ 00188 break; 00189 case 3: /* Square Wave Mode */ 00190 if (on) { 00191 reset_count_at(now); 00192 latch_next_counter(); 00193 } 00194 else { 00195 set_output(true); 00196 } 00197 /* TODO */ 00198 break; 00199 case 5: /* Hardware Triggered Strobe */ 00200 if (on) { 00201 reset_count_at(now); 00202 latch_next_counter(); 00203 set_output(true); 00204 } 00205 break; 00206 } 00207 00208 gate = on; 00209 } 00210 } 00211 00212 void update_output_from_counter(const read_counter_result &res) { 00213 set_output(get_output_from_counter(res)); 00214 } 00215 00216 bool get_output_from_counter(const read_counter_result &res) { 00217 switch (mode) { 00218 case 0: 00219 if (new_mode) return false; 00220 if (res.cycle != 0u/*index > delay*/) return true; 00221 else return false; 00222 break; 00223 case 2: 00224 if (new_mode) return true; 00225 return res.counter != 0; 00226 case 3: 00227 if (new_mode) return true; 00228 return res.cycle == 0; 00229 case 4: 00230 return true; 00231 default: 00232 break; 00233 } 00234 00235 return true; 00236 } 00237 00238 read_counter_result read_counter(void) const {//This assumes you call track_time() 00239 if (!gate) 00240 return last_counter; 00241 00242 const double index = reltime(); 00243 read_counter_result ret; 00244 00245 switch (mode) { 00246 case 4: /* Software Triggered Strobe */ 00247 case 0: /* Interrupt on Terminal Count */ 00248 { 00249 double tmp; 00250 00251 /* Counter keeps on counting after passing terminal count */ 00252 if (bcd) { 00253 tmp = fmod(index,((double)(1000ul * 10000ul)) / PIT_TICK_RATE); 00254 ret.counter = (Bit16u)(((unsigned long)(cntr_cur - ((tmp * PIT_TICK_RATE) / 1000.0))) % 10000ul); 00255 } else { 00256 tmp = fmod(index,((double)(1000ul * 0x10000ul)) / PIT_TICK_RATE); 00257 ret.counter = (Bit16u)(((unsigned long)(cntr_cur - ((tmp * PIT_TICK_RATE) / 1000.0))) % 0x10000ul); 00258 } 00259 00260 if (mode == 0) { 00261 if (index > delay) 00262 ret.cycle = 1; 00263 } 00264 } 00265 break; 00266 case 5: /* Hardware Triggered Strobe */ 00267 case 1: /* Hardware Retriggerable one-shot */ 00268 if (index > delay) // has timed out 00269 ret.counter = 0xFFFF; 00270 else 00271 ret.counter = (Bit16u)(cntr_cur - (index * (PIT_TICK_RATE / 1000.0))); 00272 break; 00273 case 2: /* Rate Generator */ 00274 ret.counter = (Bit16u)(cntr_cur - ((fmod(index,delay) / delay) * cntr_cur)); 00275 break; 00276 case 3: /* Square Wave Rate Generator */ 00277 { 00278 double tmp = fmod(index,(double)delay) * 2; 00279 00280 if (tmp < 0) { 00281 fprintf(stderr,"tmp %.9f index %.9f delay %.9f now %.3f start %.3f\n",tmp,index,delay,now,start); 00282 abort(); 00283 } 00284 00285 ret.cycle = cycle_base; 00286 if (tmp >= delay) { 00287 tmp -= delay; 00288 ret.cycle = (ret.cycle + 1u) & 1u; 00289 } 00290 00291 ret.counter = ((Bit16u)(cntr_cur - ((tmp * cntr_cur) / delay))) & 0xFFFEu; /* always even value */ 00292 } 00293 break; 00294 default: 00295 break; 00296 } 00297 00298 return ret; 00299 } 00300 }; 00301 00302 static PIT_Block pit[3]; 00303 00304 static Bit8u latched_timerstatus; 00305 // the timer status can not be overwritten until it is read or the timer was 00306 // reprogrammed. 00307 static bool latched_timerstatus_locked; 00308 00309 unsigned long PIT_TICK_RATE = PIT_TICK_RATE_IBM; 00310 00311 static void PIT0_Event(Bitu /*val*/) { 00312 PIC_ActivateIRQ(0); 00313 if (pit[0].mode != 0) { 00314 pit[0].track_time(PIC_FullIndex()); 00315 00316 /* event timing error checking */ 00317 double err = PIC_GetCurrentEventTime() - pit[0].start; 00318 00319 if (err >= (pit[0].delay/2)) 00320 err -= pit[0].delay; 00321 00322 #if 0//change if debug information wanted 00323 if (fabs(err) >= (0.5 / CPU_CycleMax)) 00324 LOG_MSG("PIT0_Event timing error %.6fms",err); 00325 #endif 00326 00327 PIC_AddEvent(PIT0_Event,pit[0].delay - (err * 0.05)); 00328 } 00329 } 00330 00331 static bool counter_output(Bitu counter) { 00332 PIT_Block *p = &pit[counter]; 00333 p->track_time(PIC_FullIndex()); 00334 00335 PIT_Block::read_counter_result res = p->read_counter(); 00336 p->update_output_from_counter(res); 00337 00338 return p->output; 00339 } 00340 static void status_latch(Bitu counter) { 00341 // the timer status can not be overwritten until it is read or the timer was 00342 // reprogrammed. 00343 if(!latched_timerstatus_locked) { 00344 PIT_Block * p=&pit[counter]; 00345 latched_timerstatus=0; 00346 // Timer Status Word 00347 // 0: BCD 00348 // 1-3: Timer mode 00349 // 4-5: read/load mode 00350 // 6: "NULL" - this is 0 if "the counter value is in the counter" ;) 00351 // should rarely be 1 (i.e. on exotic modes) 00352 // 7: OUT - the logic level on the Timer output pin 00353 if(p->bcd)latched_timerstatus|=0x1; 00354 latched_timerstatus|=((p->mode&7)<<1); 00355 if((p->read_state==0)||(p->read_state==3)) latched_timerstatus|=0x30; 00356 else if(p->read_state==1) latched_timerstatus|=0x10; 00357 else if(p->read_state==2) latched_timerstatus|=0x20; 00358 if(counter_output(counter)) latched_timerstatus|=0x80; 00359 if(p->new_mode) latched_timerstatus|=0x40; 00360 // The first thing that is being read from this counter now is the 00361 // counter status. 00362 p->counterstatus_set=true; 00363 latched_timerstatus_locked=true; 00364 } 00365 } 00366 00367 static void counter_latch(Bitu counter,bool do_latch=true) { 00368 PIT_Block *p = &pit[counter]; 00369 00370 p->track_time(PIC_FullIndex()); 00371 00372 PIT_Block::read_counter_result res = p->read_counter(); 00373 p->update_output_from_counter(res); 00374 00375 if (do_latch) { 00376 p->go_read_latch = false; 00377 p->read_latch = res.counter; 00378 } 00379 00380 if (counter == 0/*IRQ 0*/) { 00381 if (!p->output) 00382 PIC_DeActivateIRQ(0); 00383 } 00384 } 00385 00386 void TIMER_IRQ0Poll(void) { 00387 counter_latch(0,false/*do not latch*/); 00388 } 00389 00390 pic_tickindex_t speaker_pit_delta(void) { 00391 unsigned int speaker_pit = IS_PC98_ARCH ? 1 : 2; 00392 return fmod(pit[speaker_pit].now - pit[speaker_pit].start, pit[speaker_pit].delay); 00393 } 00394 00395 void speaker_pit_update(void) { 00396 unsigned int speaker_pit = IS_PC98_ARCH ? 1 : 2; 00397 pit[speaker_pit].track_time(PIC_FullIndex()); 00398 } 00399 00400 void PCSPEAKER_UpdateType(void); 00401 00402 bool TIMER2_ClockGateEnabled(void) { 00403 /* PC speaker emulation should treat "new mode" as if the clock gate is disabled. 00404 * On real hardware, mode 3 does not cycle if you write a control word but then 00405 * do not write a counter value. */ 00406 return !pit[IS_PC98_ARCH ? 1 : 2].new_mode; 00407 } 00408 00409 static void write_latch(Bitu port,Bitu val,Bitu /*iolen*/) { 00410 //LOG(LOG_PIT,LOG_ERROR)("port %X write:%X state:%X",port,val,pit[port-0x40].write_state); 00411 00412 // HACK: Port translation for this code PC-98 mode. 00413 // 0x71,0x73,0x75,0x77 => 0x40-0x43 00414 if (IS_PC98_ARCH) { 00415 if (port >= 0x3FD9) 00416 port = ((port - 0x3FD9) >> 1) + 0x40; 00417 else if (port >=0x71 && port <= 0x75) 00418 port = ((port - 0x71) >> 1) + 0x40; 00419 else { 00420 E_Exit("PIT: PC-98 port in write_latch is out of range."); 00421 return; 00422 } 00423 } 00424 00425 Bitu counter=port-0x40; 00426 PIT_Block * p=&pit[counter]; 00427 if(p->bcd == true) BIN2BCD(p->write_latch); 00428 00429 switch (p->write_state) { 00430 case 0: 00431 p->write_latch = p->write_latch | ((val & 0xff) << 8); 00432 p->write_state = 3; 00433 break; 00434 case 3: 00435 p->write_latch = val & 0xff; 00436 p->write_state = 0; 00437 break; 00438 case 1: 00439 p->write_latch = val & 0xff; 00440 break; 00441 case 2: 00442 p->write_latch = (val & 0xff) << 8; 00443 break; 00444 } 00445 if (p->bcd==true) BCD2BIN(p->write_latch); 00446 if (p->write_state != 0) { 00447 Bitu old_cntr = p->cntr; 00448 00449 p->track_time(PIC_FullIndex()); 00450 00451 if (p->write_latch == 0) { 00452 if (p->bcd == false) 00453 p->set_next_counter(0x10000); 00454 else 00455 p->set_next_counter(9999/*check this*/); 00456 } 00457 else if (p->write_latch == 1 && p->mode == 3/*square wave, count by 2*/) { /* counter==1 and mode==3 makes a low frequency buzz (Paratrooper) */ 00458 if (p->bcd == false) 00459 p->set_next_counter(0x10001); 00460 else 00461 p->set_next_counter(10000/*check this*/); 00462 } 00463 else { 00464 p->set_next_counter(p->write_latch); 00465 } 00466 00467 if (!p->new_mode) { 00468 if ((p->mode == 2/*common IBM PC mode*/ || p->mode == 3/*common PC-98 mode*/) && (counter == 0)) { 00469 // In mode 2 writing another value has no direct effect on the count 00470 // until the old one has run out. This might apply to other modes too. 00471 // This is not fixed for PIT2 yet!! 00472 p->update_count=true; 00473 return; 00474 } 00475 else if ((p->mode == 3) && (counter == (IS_PC98_ARCH ? 1 : 2))) { 00476 void PCSPEAKER_SetCounter_NoNewMode(Bitu cntr); 00477 00478 // PC speaker 00479 PCSPEAKER_SetCounter_NoNewMode(p->cntr); 00480 p->update_count=true; 00481 return; 00482 } 00483 00484 if (p->mode == 0) { 00485 /* Mode 0 is the only mode NOT to wait for the current counter to finish if you write another counter value 00486 * according to the Intel 8254 datasheet. 00487 * 00488 * For timer 0 (system timer) this is used by DoWhackaDo as a sort of one-shot timer interrupt. 00489 * For timer 2 (PC speaker) this is used to do PWM "realsound" digitized speech in some games. */ 00490 } 00491 else { 00492 // this debug message will help development trace down cases where writing without a new mode 00493 // would incorrectly restart the counter instead of letting the current count complete before 00494 // writing a new one. 00495 LOG(LOG_PIT,LOG_NORMAL)("WARNING: Writing counter %u in mode %u without writing port 43h not yet supported, will be handled as if new mode and reset of the cycle",(int)counter,(int)p->mode); 00496 } 00497 } 00498 00499 p->reset_count_at(PIC_FullIndex()); 00500 p->latch_next_counter(); 00501 00502 p->new_mode=false; 00503 switch (counter) { 00504 case 0x00: /* Timer hooked to IRQ 0 */ 00505 PIC_RemoveEvents(PIT0_Event); 00506 PIC_AddEvent(PIT0_Event,p->delay); 00507 00508 #if 0//change to #if 1 if you want to debug Mode 0 one-shot events 00509 if (p->mode == 0) 00510 LOG(LOG_PIT,LOG_NORMAL)("PIT 0 Timer one-shot event %.3fms",p->delay); 00511 #endif 00512 00513 //please do not spam the log and console if a game is writing the SAME counter value constantly, 00514 //and do not spam the console if Mode 0 is used because events are not consistent. 00515 if (p->cntr != old_cntr && p->mode != 0) 00516 LOG(LOG_PIT,LOG_NORMAL)("PIT 0 Timer at %.4f Hz mode %d",1000.0/p->delay,p->mode); 00517 00518 break; 00519 case 0x01: /* Timer hooked to PC-Speaker (NEC-PC98) */ 00520 if (IS_PC98_ARCH) 00521 PCSPEAKER_SetCounter(p->cntr,p->mode); 00522 break; 00523 case 0x02: /* Timer hooked to PC-Speaker (IBM PC) */ 00524 if (!IS_PC98_ARCH) 00525 PCSPEAKER_SetCounter(p->cntr,p->mode); 00526 break; 00527 default: 00528 LOG(LOG_PIT,LOG_ERROR)("PIT:Illegal timer selected for writing"); 00529 } 00530 } 00531 else { /* write state == 0 */ 00532 /* If a new count is written to the Counter, it will be 00533 * loaded on the next CLK pulse and counting will con- 00534 * tinue from the new count. If a two-byte count is writ- 00535 * ten, the following happens: 00536 * 1) Writing the first byte disables counting. OUT is set 00537 * low immediately (no clock pulse required) 00538 * 2) Writing the second byte allows the new count to 00539 * be loaded on the next CLK pulse. */ 00540 if (p->mode == 0) { 00541 if (counter == 0) { 00542 PIC_RemoveEvents(PIT0_Event); 00543 PIC_DeActivateIRQ(0); 00544 } 00545 p->update_count = false; 00546 } 00547 } 00548 } 00549 00550 static Bitu read_latch(Bitu port,Bitu /*iolen*/) { 00551 //LOG(LOG_PIT,LOG_ERROR)("port read %X",port); 00552 00553 // HACK: Port translation for this code PC-98 mode. 00554 // 0x71,0x73,0x75,0x77 => 0x40-0x43 00555 if (IS_PC98_ARCH) { 00556 if (port >= 0x3FD9) 00557 port = ((port - 0x3FD9) >> 1) + 0x40; 00558 else if (port >=0x71 && port <= 0x75) 00559 port = ((port - 0x71) >> 1) + 0x40; 00560 else { 00561 E_Exit("PIT: PC-98 port in read_latch is out of range."); 00562 return 0; 00563 } 00564 } 00565 00566 Bit32u counter=(Bit32u)(port-0x40); 00567 Bit8u ret=0; 00568 if(GCC_UNLIKELY(pit[counter].counterstatus_set)){ 00569 pit[counter].counterstatus_set = false; 00570 latched_timerstatus_locked = false; 00571 ret = latched_timerstatus; 00572 } else { 00573 if (pit[counter].go_read_latch == true) 00574 counter_latch(counter); 00575 00576 if( pit[counter].bcd == true) BIN2BCD(pit[counter].read_latch); 00577 00578 switch (pit[counter].read_state) { 00579 case 0: /* read MSB & return to state 3 */ 00580 ret=(pit[counter].read_latch >> 8) & 0xff; 00581 pit[counter].read_state = 3; 00582 pit[counter].go_read_latch = true; 00583 break; 00584 case 3: /* read LSB followed by MSB */ 00585 ret = pit[counter].read_latch & 0xff; 00586 pit[counter].read_state = 0; 00587 break; 00588 case 1: /* read LSB */ 00589 ret = pit[counter].read_latch & 0xff; 00590 pit[counter].go_read_latch = true; 00591 break; 00592 case 2: /* read MSB */ 00593 ret = (pit[counter].read_latch >> 8) & 0xff; 00594 pit[counter].go_read_latch = true; 00595 break; 00596 default: 00597 E_Exit("Timer.cpp: error in readlatch"); 00598 break; 00599 } 00600 if( pit[counter].bcd == true) BCD2BIN(pit[counter].read_latch); 00601 } 00602 return ret; 00603 } 00604 00605 static void write_p43(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { 00606 //LOG(LOG_PIT,LOG_ERROR)("port 43 %X",val); 00607 Bitu latch=(val >> 6) & 0x03; 00608 switch (latch) { 00609 case 0: 00610 case 1: 00611 case 2: 00612 if ((val & 0x30) == 0) { 00613 /* Counter latch command */ 00614 counter_latch(latch); 00615 } else { 00616 // save output status to be used with timer 0 irq 00617 bool old_output = counter_output(0); 00618 // save the current count value to be re-used in undocumented newmode 00619 counter_latch(latch); 00620 pit[latch].bcd = (val&1)>0; 00621 if (val & 1) { 00622 if(pit[latch].cntr>=9999) pit[latch].cntr=9999; 00623 } 00624 00625 // Timer is being reprogrammed, unlock the status 00626 if(pit[latch].counterstatus_set) { 00627 pit[latch].counterstatus_set=false; 00628 latched_timerstatus_locked=false; 00629 } 00630 // pit[latch].reset_count_at(PIC_FullIndex()); // for undocumented newmode 00631 pit[latch].go_read_latch = true; 00632 pit[latch].update_count = false; 00633 pit[latch].counting = false; 00634 pit[latch].read_state = (val >> 4) & 0x03; 00635 pit[latch].write_state = (val >> 4) & 0x03; 00636 Bit8u mode = (val >> 1) & 0x07; 00637 if (mode > 5) 00638 mode -= 4; //6,7 become 2 and 3 00639 00640 pit[latch].mode = mode; 00641 00642 /* If the line goes from low to up => generate irq. 00643 * ( BUT needs to stay up until acknowlegded by the cpu!!! therefore: ) 00644 * If the line goes to low => disable irq. 00645 * Mode 0 starts with a low line. (so always disable irq) 00646 * Mode 2,3 start with a high line. 00647 * counter_output tells if the current counter is high or low 00648 * So actually a mode 3 timer enables and disables irq al the time. (not handled) */ 00649 00650 /* Jon C: Oh yeah? Nobody abuses counter == 0 on IBM PC that way, but there is a PC-98 00651 * game that relies on that behavior: Steel Gun Nyan! */ 00652 00653 if (latch == 0) { 00654 PIC_RemoveEvents(PIT0_Event); 00655 if((mode != 0)&& !old_output) { 00656 PIC_ActivateIRQ(0); 00657 } else { 00658 PIC_DeActivateIRQ(0); 00659 } 00660 } 00661 pit[latch].new_mode = true; 00662 if (latch == (IS_PC98_ARCH ? 1 : 2)) { 00663 // notify pc speaker code that the control word was written. 00664 // until a counter value is written, the PC speaker should 00665 // treat the timer as if the clock gate were disabled. 00666 PCSPEAKER_UpdateType(); 00667 PCSPEAKER_SetPITControl(mode); 00668 } 00669 } 00670 break; 00671 case 3: 00672 if ((val & 0x20)==0) { /* Latch multiple pit counters */ 00673 if (val & 0x02) counter_latch(0); 00674 if (val & 0x04) counter_latch(1); 00675 if (val & 0x08) counter_latch(2); 00676 } 00677 // status and values can be latched simultaneously 00678 if ((val & 0x10)==0) { /* Latch status words */ 00679 // but only 1 status can be latched simultaneously 00680 if (val & 0x02) status_latch(0); 00681 else if (val & 0x04) status_latch(1); 00682 else if (val & 0x08) status_latch(2); 00683 } 00684 break; 00685 } 00686 } 00687 00688 // FIXME: I am assuming that the "buzzer inhibit" on PC-98 controls the "trigger" pin 00689 // that either enables the PIT to count or stops it and resets the counter. 00690 // Verify this on real hardware (DOSLIB TPCRAPI6.EXE) 00691 // 00692 // Note that on IBM PC/XT hardware, ports 60h-63h are the same PPI used in the 00693 // PC-98 systems, though wired differently. It is configured (According to IBM). 00694 // - Port A (input) Keyboard scan code / SW1 dip switches (depends on port 61h bit 7) 00695 // - Port B (output) Timer 2 gate speaker / Speaker data aka output gate / ... / bit 7 set to clear keyboard and read SW1 00696 // - Port C (input) I/O Read/Write Memory SW2 / Cassette Data In / Timer Channel 2 Out / ... 00697 // - Command byte 0x99 (IBM Technical Ref listing) 00698 // 00699 // This is the picture I have of the hardware: 00700 // 00701 // IBM PC/XT: 00702 // 00703 // Port 61h 00704 // - bit 0 PIT 2 counter gate (write) 00705 // - bit 1 PIT 2 counter output gate (write) 00706 // Port 62h 00707 // - bit 5 PIT 2 counter output (read). The connection point lies BEFORE the AND gate. 00708 // You will see the output toggle even if the speaker was muted by clearing the output gate bit. 00709 // 00710 // IBM PC/AT: 00711 // 00712 // Port 61h 00713 // - bit 0 PIT 2 counter gate (write) 00714 // - bit 1 PIT 2 counter output gate (write) 00715 // - bit 5 PIT 2 counter output (read). The connection point lies BEFORE the AND gate. 00716 // You will see the output toggle even if the speaker was muted by clearing the output gate bit. 00717 // 00718 // PC-98: 00719 // 00720 // Port 35h (Intel 8255 PPI Port C) 00721 // - bit 3 PIT 1 counter gate (there is no output gate). Setting the bit inhibits the counter (and therefore PC speaker) 00722 // - On PC-9821, this bit controls the clock gate of PIT 1 and therefore whether the PC speaker makes sound 00723 // - On PC-9801, the clock gate of PIT 1 is always on, and this bit controls whether the PC speaker makes sound 00724 // 00725 // IBM PC/XT/AT: 00726 // 00727 // counter output readback <- --------+ 00728 // | 00729 // +------+ | +----------+ 00730 // counter gate -> | 8254 | -> PIT 2 output -> | AND GATE | -> PC speaker 00731 // +------+ +----------+ 00732 // | 00733 // counter output gate -> --------------------------+ 00734 // 00735 // PC-9821: 00736 // 00737 // +------+ 00738 // counter gate -> | 8254 | -> PC speaker 00739 // +------+ 00740 // 00741 // PC-9801: 00742 // 00743 // +------+ +----------+ 00744 // logic high -> | 8254 | -> | AND GATE | -> PC speaker 00745 // (always on) +------+ +----------+ 00746 // | 00747 // inverse of bit 3 of port 37h ----+ 00748 // (bit 3 is inhibit) 00749 void TIMER_SetGate2(bool in) { 00750 unsigned int speaker_pit = IS_PC98_ARCH ? 1 : 2; 00751 pit[speaker_pit].track_time(PIC_FullIndex()); 00752 pit[speaker_pit].set_gate(in || speaker_clock_lock_on); 00753 } 00754 00755 bool TIMER_GetOutput2() { 00756 unsigned int speaker_pit = IS_PC98_ARCH ? 1 : 2;//NTS: For completion sake, even though there is no readback bit on PC-98 00757 00758 return counter_output(speaker_pit); 00759 } 00760 00761 #include "programs.h" 00762 00763 static IO_ReadHandleObject ReadHandler[4]; 00764 static IO_WriteHandleObject WriteHandler[4]; 00765 00766 /* PC-98 alias */ 00767 static IO_ReadHandleObject ReadHandler2[4]; 00768 static IO_WriteHandleObject WriteHandler2[4]; 00769 00770 void TIMER_BIOS_INIT_Configure() { 00771 PIC_RemoveEvents(PIT0_Event); 00772 PIC_DeActivateIRQ(0); 00773 00774 /* Setup Timer 0 */ 00775 pit[0].output = true; 00776 pit[0].gate = true; 00777 pit[0].cntr = 0x10000; 00778 pit[0].write_state = 3; 00779 pit[0].read_state = 3; 00780 pit[0].read_latch = 0; 00781 pit[0].write_latch = 0; 00782 pit[0].mode = 3; 00783 pit[0].bcd = false; 00784 pit[0].go_read_latch = true; 00785 pit[0].counterstatus_set = false; 00786 pit[0].update_count = false; 00787 pit[0].reset_count_at(PIC_FullIndex()); 00788 pit[0].track_time(PIC_FullIndex()); 00789 00790 pit[1].output = true; 00791 pit[1].gate = true; 00792 pit[1].bcd = false; 00793 pit[1].read_state = 1; 00794 pit[1].go_read_latch = true; 00795 pit[1].cntr = 18; 00796 pit[1].mode = 2; 00797 pit[1].write_state = 3; 00798 pit[1].counterstatus_set = false; 00799 pit[1].reset_count_at(PIC_FullIndex()); 00800 pit[1].track_time(PIC_FullIndex()); 00801 00802 pit[2].output = true; 00803 pit[2].gate = false; 00804 pit[2].bcd = false; 00805 pit[2].read_state = 1; 00806 pit[2].go_read_latch = true; 00807 pit[2].cntr = 18; 00808 pit[2].mode = 2; 00809 pit[2].write_state = 3; 00810 pit[2].counterstatus_set = false; 00811 pit[2].reset_count_at(PIC_FullIndex()); 00812 pit[2].track_time(PIC_FullIndex()); 00813 00814 /* TODO: I have observed that on real PC-98 hardware: 00815 * 00816 * Output 1 (speaker) does not cycle if inhibited by port 35h 00817 * 00818 * Output 2 (RS232C) does not cycle until programmed to cycle 00819 * to operate the 8251 for data transfer. It is configured by 00820 * the BIOS to countdown and stop, thus the UART is not cycling 00821 * until put into active use. */ 00822 00823 int pcspeaker_pit = IS_PC98_ARCH ? 1 : 2; /* IBM: PC speaker on output 2 PC-98: PC speaker on output 1 */ 00824 00825 { 00826 Section_prop *pcsec = static_cast<Section_prop *>(control->GetSection("speaker")); 00827 int freq = pcsec->Get_int("initial frequency"); /* original code: 1320 */ 00828 unsigned int div; 00829 00830 /* IBM PC defaults to 903Hz. 00831 * NEC PC-98 defaults to 2KHz */ 00832 if (freq < 0) 00833 freq = IS_PC98_ARCH ? 2000 : 903; 00834 00835 if (freq < 1) { 00836 div = 65535; 00837 } 00838 else { 00839 div = (unsigned int)PIT_TICK_RATE / (unsigned int)freq; 00840 if (div > 65535) div = 65535; 00841 } 00842 00843 pit[pcspeaker_pit].cntr = div; 00844 pit[pcspeaker_pit].read_latch = div; 00845 pit[pcspeaker_pit].write_state = 3; /* Chuck Yeager */ 00846 pit[pcspeaker_pit].read_state = 3; 00847 pit[pcspeaker_pit].mode = 3; 00848 pit[pcspeaker_pit].bcd = false; 00849 pit[pcspeaker_pit].go_read_latch = true; 00850 pit[pcspeaker_pit].counterstatus_set = false; 00851 pit[pcspeaker_pit].counting = false; 00852 pit[pcspeaker_pit].reset_count_at(PIC_FullIndex()); 00853 } 00854 00855 pit[0].latch_next_counter(); 00856 pit[1].latch_next_counter(); 00857 pit[2].latch_next_counter(); 00858 00859 PCSPEAKER_SetCounter(pit[pcspeaker_pit].cntr,pit[pcspeaker_pit].mode); 00860 PIC_AddEvent(PIT0_Event,pit[0].delay); 00861 00862 if (IS_PC98_ARCH) { 00863 /* BIOS data area at 0x501 tells the DOS application which clock rate to use */ 00864 phys_writeb(0x501, 00865 (phys_readb(0x501) & 0x7F) | 00866 ((PIT_TICK_RATE == PIT_TICK_RATE_PC98_8MHZ) ? 0x80 : 0x00) /* bit 7: 1=8MHz 0=5MHz/10MHz */ 00867 ); 00868 00869 /* Turn off PC speaker. 00870 * Note for PC9801 behavior this will help start the PIT cycling anyway. */ 00871 TIMER_SetGate2(false); 00872 00873 /* The timer is always on, there's no clock gate that I know of. 00874 * There's a bit 6 port 434h that might gate it on some hardware, but that doesn't seem to be the case on anything I have. 00875 * 00876 * NTS: If you run 8254.EXE from DOSLIB on PC-98 hardware and notice PIT 2 isn't cycling, try writing values to 75h 00877 * and see if it begins counting again. A PC-9821Lt2 laptop seems to have a bios that writes a mode byte for 00878 * it to 77h but then never writes to 75h, which leaves the timer idle. */ 00879 pit[2].track_time(PIC_FullIndex()); 00880 pit[2].set_gate(true); 00881 } 00882 } 00883 00884 void TIMER_OnPowerOn(Section*) { 00885 Section_prop * pc98_section=static_cast<Section_prop *>(control->GetSection("pc98")); 00886 assert(pc98_section != NULL); 00887 00888 // log 00889 LOG(LOG_MISC,LOG_DEBUG)("TIMER_OnPowerOn(): Reinitializing PIT timer emulation"); 00890 00891 PIC_RemoveEvents(PIT0_Event); 00892 00893 /* I/O port map (8254) 00894 * 00895 * IBM PC/XT/AT NEC-PC98 A1-A0 00896 * ----------------------------------- 00897 * 0x40 0x71 0 00898 * 0x41 0x73 1 00899 * 0x42 0x75 2 00900 * 0x43 0x77 3 00901 */ 00902 /* Timer output connection 00903 * 00904 * IBM PC/XT/AT NEC-PC98 Timer 00905 * ------------------------------------ 00906 * Timer int. Timer int. 0 00907 * DRAM refresh Speaker 1 00908 * Speaker RS-232C clk 2 00909 * 00910 * If I read documentation correctly, PC-98 wires timer output 2 00911 * to the clock pin of the 8251 UART for COM1 as a way to set the 00912 * baud rate. */ 00913 00914 WriteHandler[0].Uninstall(); 00915 WriteHandler[1].Uninstall(); 00916 WriteHandler[2].Uninstall(); 00917 WriteHandler[3].Uninstall(); 00918 ReadHandler[0].Uninstall(); 00919 ReadHandler[1].Uninstall(); 00920 ReadHandler[2].Uninstall(); 00921 ReadHandler[3].Uninstall(); 00922 00923 WriteHandler2[0].Uninstall(); 00924 WriteHandler2[1].Uninstall(); 00925 WriteHandler2[2].Uninstall(); 00926 WriteHandler2[3].Uninstall(); 00927 ReadHandler2[0].Uninstall(); 00928 ReadHandler2[1].Uninstall(); 00929 ReadHandler2[2].Uninstall(); 00930 ReadHandler2[3].Uninstall(); 00931 00932 if (IS_PC98_ARCH) { 00933 /* This code is written to eventually copy-paste out in general */ 00934 WriteHandler[0].Install(0x71,write_latch,IO_MB); 00935 WriteHandler[1].Install(0x73,write_latch,IO_MB); 00936 WriteHandler[2].Install(0x75,write_latch,IO_MB); 00937 WriteHandler[3].Install(0x77,write_p43,IO_MB); 00938 ReadHandler[0].Install(0x71,read_latch,IO_MB); 00939 ReadHandler[1].Install(0x73,read_latch,IO_MB); 00940 ReadHandler[2].Install(0x75,read_latch,IO_MB); 00941 00942 /* Apparently all but the first PC-9801 systems have an alias of these 00943 * ports at 0x3FD9-0x3FDF odd. This alias is required for games that 00944 * rely on this alias. */ 00945 WriteHandler2[0].Install(0x3FD9,write_latch,IO_MB); 00946 WriteHandler2[1].Install(0x3FDB,write_latch,IO_MB); 00947 WriteHandler2[2].Install(0x3FDD,write_latch,IO_MB); 00948 WriteHandler2[3].Install(0x3FDF,write_p43,IO_MB); 00949 ReadHandler2[0].Install(0x3FD9,read_latch,IO_MB); 00950 ReadHandler2[1].Install(0x3FDB,read_latch,IO_MB); 00951 ReadHandler2[2].Install(0x3FDD,read_latch,IO_MB); 00952 } 00953 else { 00954 WriteHandler[0].Install(0x40,write_latch,IO_MB); 00955 // WriteHandler[1].Install(0x41,write_latch,IO_MB); 00956 WriteHandler[2].Install(0x42,write_latch,IO_MB); 00957 WriteHandler[3].Install(0x43,write_p43,IO_MB); 00958 ReadHandler[0].Install(0x40,read_latch,IO_MB); 00959 ReadHandler[1].Install(0x41,read_latch,IO_MB); 00960 ReadHandler[2].Install(0x42,read_latch,IO_MB); 00961 } 00962 00963 latched_timerstatus_locked=false; 00964 00965 if (IS_PC98_ARCH) { 00966 int pc98rate; 00967 00968 { 00969 const char *s = pc98_section->Get_string("pc-98 timer always cycles"); 00970 00971 if (!strcmp(s,"true") || !strcmp(s,"1")) 00972 speaker_clock_lock_on = true; // PC-9801 behavior 00973 else if (!strcmp(s,"false") || !strcmp(s,"0")) 00974 speaker_clock_lock_on = false; // PC-9821 behavior 00975 else // anything else is handled as "auto" 00976 speaker_clock_lock_on = false; // PC-9821 behavior 00977 } 00978 00979 /* PC-98 has two different rates: 5/10MHz base or 8MHz base. Let the user choose via dosbox.conf */ 00980 pc98rate = pc98_section->Get_int("pc-98 timer master frequency"); 00981 if (pc98rate > 6) pc98rate /= 2; 00982 if (pc98rate == 0) pc98rate = 5; /* Pick the most likely to work with DOS games (FIXME: This is a GUESS!! Is this correct?) */ 00983 else if (pc98rate < 5) pc98rate = 4; 00984 else pc98rate = 5; 00985 00986 if (pc98rate >= 5) 00987 PIT_TICK_RATE = PIT_TICK_RATE_PC98_10MHZ; 00988 else 00989 PIT_TICK_RATE = PIT_TICK_RATE_PC98_8MHZ; 00990 00991 LOG_MSG("PC-98 PIT master clock rate %luHz",PIT_TICK_RATE); 00992 00993 latched_timerstatus_locked=false; 00994 } 00995 } 00996 00997 void TIMER_OnEnterPC98_Phase2_UpdateBDA(void) { 00998 if (!cpu.pmode) { 00999 /* BIOS data area at 0x501 tells the DOS application which clock rate to use */ 01000 phys_writeb(0x501, 01001 (phys_readb(0x501) & 0x7F) | 01002 ((PIT_TICK_RATE == PIT_TICK_RATE_PC98_8MHZ) ? 0x80 : 0x00) /* bit 7: 1=8MHz 0=5MHz/10MHz */ 01003 ); 01004 } 01005 else { 01006 LOG_MSG("PC-98 warning: PIT timer change cannot be reflected to BIOS data area in protected/vm86 mode"); 01007 } 01008 } 01009 01010 void TIMER_Destroy(Section*) { 01011 PIC_RemoveEvents(PIT0_Event); 01012 } 01013 01014 void TIMER_Init() { 01015 Bitu i; 01016 01017 LOG(LOG_MISC,LOG_DEBUG)("TIMER_Init()"); 01018 01019 PIT_TICK_RATE = PIT_TICK_RATE_IBM; 01020 01021 for (i=0;i < 3;i++) { 01022 pit[i].cntr = 0x10000; 01023 pit[i].write_state = 0; 01024 pit[i].read_state = 0; 01025 pit[i].read_latch = 0; 01026 pit[i].write_latch = 0; 01027 pit[i].mode = 0; 01028 pit[i].bcd = false; 01029 pit[i].go_read_latch = false; 01030 pit[i].counterstatus_set = false; 01031 pit[i].update_count = false; 01032 pit[i].latch_next_counter(); 01033 } 01034 01035 AddExitFunction(AddExitFunctionFuncPair(TIMER_Destroy)); 01036 AddVMEventFunction(VM_EVENT_POWERON, AddVMEventFunctionFuncPair(TIMER_OnPowerOn)); 01037 } 01038 01039 //save state support 01040 void *PIT0_Event_PIC_Event = (void*)((uintptr_t)PIT0_Event); 01041 01042 namespace 01043 { 01044 class SerializeTimer : public SerializeGlobalPOD 01045 { 01046 public: 01047 SerializeTimer() : SerializeGlobalPOD("IntTimer10") 01048 { 01049 registerPOD(pit); 01050 //registerPOD(gate2); 01051 registerPOD(latched_timerstatus); 01052 registerPOD(latched_timerstatus_locked); 01053 } 01054 } dummy; 01055 }