Bochs/bochs/iodev/pit82c54.cc
Stanislav Shwartsman 5873b26a82 Speed up compilation process.
bochs.h already not include iodev.h which reduces compilation dependences for almost all cpu and fpu files, now cpu files will not be recompiled if iodev includes was changed
2004-06-19 15:20:15 +00:00

898 lines
23 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id: pit82c54.cc,v 1.25 2004-06-19 15:20:13 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
/*
* Emulator of an Intel 8254/82C54 Programmable Interval Timer.
* Greg Alexander <yakovlev@usa.com>
*
*
* Things I am unclear on (greg):
* 1.)What happens if both the status and count registers are latched,
* but the first of the two count registers has already been read?
* I.E.:
* latch count 0 (16-bit)
* Read count 0 (read LSByte)
* READ_BACK status of count 0
* Read count 0 - do you get MSByte or status?
* This will be flagged as an error.
* 2.)What happens when we latch the output in the middle of a 2-part
* unlatched read?
* 3.)I assumed that programming a counter removes a latched status.
* 4.)I implemented the 8254 description of mode 0, not the 82C54 one.
* 5.)clock() calls represent a rising clock edge followed by a falling
* clock edge.
* 6.)What happens when we trigger mode 1 in the middle of a 2-part
* write?
*/
#include "iodev.h"
#include "pit82c54.h"
#define LOG_THIS this->
void pit_82C54::print_counter(counter_type & thisctr) {
#if 1
BX_INFO(("Printing Counter"));
BX_INFO(("count: %d",thisctr.count));
BX_INFO(("count_binary: %x",thisctr.count_binary));
BX_INFO(("counter gate: %x",thisctr.GATE));
BX_INFO(("counter OUT: %x",thisctr.OUTpin));
BX_INFO(("next_change_time: %d",thisctr.next_change_time));
BX_INFO(("End Counter Printout"));
#endif
}
void pit_82C54::print_cnum(Bit8u cnum) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Bad counter index to print_cnum"));
} else {
print_counter(counter[cnum]);
}
}
void pit_82C54::latch_counter(counter_type & thisctr) {
if(thisctr.count_LSB_latched || thisctr.count_MSB_latched) {
//Do nothing because previous latch has not been read.;
} else {
switch(thisctr.read_state) {
case MSByte:
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_MSB_latched=1;
break;
case LSByte:
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_LSB_latched=1;
break;
case LSByte_multiple:
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_LSB_latched=1;
thisctr.count_MSB_latched=1;
break;
case MSByte_multiple:
if(!(seen_problems & UNL_2P_READ)) {
// seen_problems|=UNL_2P_READ;
BX_ERROR(("Unknown behavior when latching during 2-part read."));
BX_ERROR((" This message will not be repeated."));
}
//I guess latching and resetting to LSB first makes sense;
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_LSB_latched=1;
thisctr.count_MSB_latched=1;
break;
default:
BX_ERROR(("Unknown read mode found during latch command."));
break;
}
}
}
void pit_82C54::set_OUT (counter_type & thisctr, bool data) {
//This will probably have a callback, so I put it here.
thisctr.OUTpin=data;
}
void BX_CPP_AttrRegparmN(2)
pit_82C54::set_count (counter_type & thisctr, Bit32u data) {
thisctr.count=data & 0xFFFF;
set_binary_to_count(thisctr);
}
void BX_CPP_AttrRegparmN(1)
pit_82C54::set_count_to_binary(counter_type & thisctr) {
if(thisctr.bcd_mode) {
thisctr.count=
(((thisctr.count_binary/1)%10)<<0) |
(((thisctr.count_binary/10)%10)<<4) |
(((thisctr.count_binary/100)%10)<<8) |
(((thisctr.count_binary/1000)%10)<<12)
;
} else {
thisctr.count=thisctr.count_binary;
}
}
void BX_CPP_AttrRegparmN(1)
pit_82C54::set_binary_to_count(counter_type & thisctr) {
if(thisctr.bcd_mode) {
thisctr.count_binary=
(1*((thisctr.count>>0)&0xF)) +
(10*((thisctr.count>>4)&0xF)) +
(100*((thisctr.count>>8)&0xF)) +
(1000*((thisctr.count>>12)&0xF))
;
} else {
thisctr.count_binary=thisctr.count;
}
}
void BX_CPP_AttrRegparmN(1)
pit_82C54::decrement (counter_type & thisctr) {
if(!thisctr.count) {
if(thisctr.bcd_mode) {
thisctr.count=0x9999;
thisctr.count_binary=9999;
} else {
thisctr.count=0xFFFF;
thisctr.count_binary=0xFFFF;
}
} else {
thisctr.count_binary--;
set_count_to_binary(thisctr);
}
}
void pit_82C54::init (void) {
Bit8u i;
put("PIT81");
settype(PIT81LOG);
for(i=0;i<3;i++) {
BX_DEBUG(("Setting read_state to LSB"));
counter[i].read_state=LSByte;
counter[i].write_state=LSByte;
counter[i].GATE=1;
counter[i].OUTpin=1;
counter[i].triggerGATE=0;
counter[i].mode=4;
counter[i].first_pass=0;
counter[i].bcd_mode=0;
counter[i].count=0;
counter[i].count_binary=0;
counter[i].state_bit_1=0;
counter[i].state_bit_2=0;
counter[i].null_count=0;
counter[i].rw_mode=1;
counter[i].count_written=1;
counter[i].count_LSB_latched=0;
counter[i].count_MSB_latched=0;
counter[i].status_latched=0;
counter[i].next_change_time=0;
}
seen_problems=0;
}
pit_82C54::pit_82C54 (void) {
init();
}
void pit_82C54::reset (unsigned type) {
}
void BX_CPP_AttrRegparmN(2)
pit_82C54::decrement_multiple(counter_type & thisctr, Bit32u cycles) {
while(cycles>0) {
if(cycles<=thisctr.count_binary) {
thisctr.count_binary-=cycles;
cycles-=cycles;
set_count_to_binary(thisctr);
} else {
cycles-=(thisctr.count_binary+1);
thisctr.count_binary-=thisctr.count_binary;
set_count_to_binary(thisctr);
decrement(thisctr);
}
}
}
void pit_82C54::clock_multiple(Bit8u cnum, Bit32u cycles) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Counter number too high in clock"));
} else {
counter_type & thisctr = counter[cnum];
while(cycles>0) {
if(thisctr.next_change_time==0) {
if(thisctr.count_written) {
switch(thisctr.mode) {
case 0:
if(thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
decrement_multiple(thisctr, cycles);
}
break;
case 1:
decrement_multiple(thisctr, cycles);
break;
case 2:
if( (!thisctr.first_pass) && thisctr.GATE ) {
decrement_multiple(thisctr, cycles);
}
break;
case 3:
if( (!thisctr.first_pass) && thisctr.GATE ) {
decrement_multiple(thisctr, 2*cycles);
}
break;
case 4:
if(thisctr.GATE) {
decrement_multiple(thisctr, cycles);
}
break;
case 5:
decrement_multiple(thisctr, cycles);
break;
default:
break;
}
}
cycles-=cycles;
} else {
switch(thisctr.mode) {
case 0:
case 1:
case 2:
case 4:
case 5:
if( thisctr.next_change_time > cycles ) {
decrement_multiple(thisctr,cycles);
thisctr.next_change_time-=cycles;
cycles-=cycles;
} else {
decrement_multiple(thisctr,(thisctr.next_change_time-1));
cycles-=thisctr.next_change_time;
clock(cnum);
}
break;
case 3:
if( thisctr.next_change_time > cycles ) {
decrement_multiple(thisctr,cycles*2);
thisctr.next_change_time-=cycles;
cycles-=cycles;
} else {
decrement_multiple(thisctr,(thisctr.next_change_time-1)*2);
cycles-=thisctr.next_change_time;
clock(cnum);
}
break;
default:
cycles-=cycles;
break;
}
}
}
#if 0
print_counter(thisctr);
#endif
}
}
void BX_CPP_AttrRegparmN(1)
pit_82C54::clock(Bit8u cnum) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Counter number too high in clock"));
} else {
counter_type & thisctr = counter[cnum];
switch(thisctr.mode) {
case 0:
if(thisctr.count_written) {
if(thisctr.null_count) {
set_count(thisctr, thisctr.inlatch);
if(thisctr.GATE) {
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
thisctr.null_count=0;
} else {
if(thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
decrement(thisctr);
if(!thisctr.OUTpin) {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
if(!thisctr.count) {
set_OUT(thisctr,1);
}
} else {
thisctr.next_change_time=0;
}
} else {
thisctr.next_change_time=0; //if the clock isn't moving.
}
}
} else {
thisctr.next_change_time=0; //default to 0.
}
thisctr.triggerGATE=0;
break;
case 1:
if(thisctr.count_written) {
if(thisctr.triggerGATE) {
set_count(thisctr, thisctr.inlatch);
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
thisctr.null_count=0;
set_OUT(thisctr,0);
if(thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
} else {
decrement(thisctr);
if(!thisctr.OUTpin) {
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
if(thisctr.count==0) {
set_OUT(thisctr,1);
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0; //default to 0.
}
thisctr.triggerGATE=0;
break;
case 2:
if(thisctr.count_written) {
if(thisctr.triggerGATE || thisctr.first_pass) {
set_count(thisctr, thisctr.inlatch);
thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
thisctr.null_count=0;
if(thisctr.inlatch==1) {
BX_ERROR(("ERROR: count of 1 is invalid in pit mode 2."));
}
if(!thisctr.OUTpin) {
set_OUT(thisctr,1);
}
if(thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.first_pass=0;
} else {
if(thisctr.GATE) {
decrement(thisctr);
thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
if(thisctr.count==1) {
thisctr.next_change_time=1;
set_OUT(thisctr,0);
thisctr.first_pass=1;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
case 3:
if(thisctr.count_written) {
if( (thisctr.triggerGATE || thisctr.first_pass
|| thisctr.state_bit_2) && thisctr.GATE ) {
set_count(thisctr, thisctr.inlatch & 0xFFFE);
thisctr.state_bit_1=thisctr.inlatch & 0x1;
if( (!thisctr.OUTpin) || (!(thisctr.state_bit_1))) {
if(((thisctr.count_binary/2)-1)==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
}
} else {
if((thisctr.count_binary/2)==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
}
}
thisctr.null_count=0;
if(thisctr.inlatch==1) {
BX_ERROR(("Count of 1 is invalid in pit mode 3."));
}
if(!thisctr.OUTpin) {
set_OUT(thisctr,1);
} else if(thisctr.OUTpin && !thisctr.first_pass) {
set_OUT(thisctr,0);
}
if(thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.state_bit_2=0;
thisctr.first_pass=0;
} else {
if(thisctr.GATE) {
decrement(thisctr);
decrement(thisctr);
if( (!thisctr.OUTpin) || (!(thisctr.state_bit_1))) {
thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
} else {
thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
}
if(thisctr.count==0) {
thisctr.state_bit_2=1;
thisctr.next_change_time=1;
}
if( (thisctr.count==2) &&
( (!thisctr.OUTpin) || (!(thisctr.state_bit_1)))
) {
thisctr.state_bit_2=1;
thisctr.next_change_time=1;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
case 4:
if(thisctr.count_written) {
if(!thisctr.OUTpin) {
set_OUT(thisctr,1);
}
if(thisctr.null_count) {
set_count(thisctr, thisctr.inlatch);
if(thisctr.GATE) {
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
thisctr.null_count=0;
if(thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.first_pass=1;
} else {
if(thisctr.GATE) {
decrement(thisctr);
if(thisctr.first_pass) {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
if(!thisctr.count) {
set_OUT(thisctr,0);
thisctr.next_change_time=1;
thisctr.first_pass=0;
}
} else {
thisctr.next_change_time=0;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
case 5:
if(thisctr.count_written) {
if(!thisctr.OUTpin) {
set_OUT(thisctr,1);
}
if(thisctr.triggerGATE) {
set_count(thisctr, thisctr.inlatch);
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
thisctr.null_count=0;
if(thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.first_pass=1;
} else {
decrement(thisctr);
if(thisctr.first_pass) {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
if(!thisctr.count) {
set_OUT(thisctr,0);
thisctr.next_change_time=1;
thisctr.first_pass=0;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
default:
BX_ERROR(("Mode not implemented."));
thisctr.next_change_time=0;
thisctr.triggerGATE=0;
break;
}
}
}
void pit_82C54::clock_all(Bit32u cycles) {
BX_DEBUG(("clock_all: cycles=%d",cycles));
clock_multiple(0,cycles);
clock_multiple(1,cycles);
clock_multiple(2,cycles);
}
Bit8u pit_82C54::read(Bit8u address) {
if(address>MAX_ADDRESS) {
BX_ERROR(("Counter address incorrect in data read."));
} else if(address==CONTROL_ADDRESS) {
BX_DEBUG(("PIT Read: Control Word Register."));
//Read from control word register;
/* This might be okay. If so, 0 seems the most logical
* return value from looking at the docs.
*/
BX_ERROR(("Read from control word register not defined."));
return 0;
} else {
//Read from a counter;
BX_DEBUG(("PIT Read: Counter %d.",address));
counter_type & thisctr=counter[address];
if(thisctr.status_latched) {
//Latched Status Read;
if(thisctr.count_MSB_latched &&
(thisctr.read_state==MSByte_multiple) ) {
BX_ERROR(("Undefined output when status latched and count half read."));
} else {
thisctr.status_latched=0;
return thisctr.status_latch;
}
} else {
//Latched Count Read;
if(thisctr.count_LSB_latched) {
//Read Least Significant Byte;
if(thisctr.read_state==LSByte_multiple) {
BX_DEBUG(("Setting read_state to MSB_mult"));
thisctr.read_state=MSByte_multiple;
}
thisctr.count_LSB_latched=0;
return (thisctr.outlatch & 0xFF);
} else if(thisctr.count_MSB_latched) {
//Read Most Significant Byte;
if(thisctr.read_state==MSByte_multiple) {
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
}
thisctr.count_MSB_latched=0;
return ((thisctr.outlatch>>8) & 0xFF);
} else {
//Unlatched Count Read;
if(!(thisctr.read_state & 0x1)) {
//Read Least Significant Byte;
if(thisctr.read_state==LSByte_multiple) {
thisctr.read_state=MSByte_multiple;
BX_DEBUG(("Setting read_state to MSB_mult"));
}
return (thisctr.count & 0xFF);
} else {
//Read Most Significant Byte;
if(thisctr.read_state==MSByte_multiple) {
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
}
return ((thisctr.count>>8) & 0xFF);
}
}
}
}
//Should only get here on errors;
return 0;
}
void pit_82C54::write(Bit8u address, Bit8u data) {
if(address>MAX_ADDRESS) {
BX_ERROR(("Counter address incorrect in data write."));
} else if(address==CONTROL_ADDRESS) {
Bit8u SC, RW, M, BCD;
controlword=data;
BX_DEBUG(("Control Word Write."));
SC = (controlword>>6) & 0x3;
RW = (controlword>>4) & 0x3;
M = (controlword>>1) & 0x7;
BCD = controlword & 0x1;
if(SC == 3) {
//READ_BACK command;
int i;
BX_DEBUG(("READ_BACK command."));
for(i=0;i<=MAX_COUNTER;i++) {
if((M>>i) & 0x1) {
//If we are using this counter;
counter_type & thisctr=counter[i];
if(!((controlword>>5) & 1)) {
//Latch Count;
latch_counter(thisctr);
}
if(!((controlword>>4) & 1)) {
//Latch Status;
if(thisctr.status_latched) {
//Do nothing because latched status has not been read.;
} else {
thisctr.status_latch=
((thisctr.OUTpin & 0x1) << 7) |
((thisctr.null_count & 0x1) << 6) |
((thisctr.rw_mode & 0x3) << 4) |
((thisctr.mode & 0x7) << 1) |
(thisctr.bcd_mode&0x1)
;
thisctr.status_latched=1;
}
}
}
}
} else {
counter_type & thisctr = counter[SC];
if(!RW) {
//Counter Latch command;
BX_DEBUG(("Counter Latch command. SC=%d",SC));
latch_counter(thisctr);
} else {
//Counter Program Command;
BX_DEBUG(("Counter Program command. SC=%d, RW=%d, M=%d, BCD=%d",SC,RW,M,BCD));
thisctr.null_count=1;
thisctr.count_LSB_latched=0;
thisctr.count_MSB_latched=0;
thisctr.status_latched=0;
thisctr.inlatch=0;
thisctr.count_written=0;
thisctr.first_pass=1;
thisctr.rw_mode=RW;
thisctr.bcd_mode=(BCD > 0);
thisctr.mode=M;
switch(RW) {
case 0x1:
BX_DEBUG(("Setting read_state to LSB"));
thisctr.read_state=LSByte;
thisctr.write_state=LSByte;
break;
case 0x2:
BX_DEBUG(("Setting read_state to MSB"));
thisctr.read_state=MSByte;
thisctr.write_state=MSByte;
break;
case 0x3:
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
thisctr.write_state=LSByte_multiple;
break;
default:
BX_ERROR(("RW field invalid in control word write."));
break;
}
//All modes except mode 0 have initial output of 1.;
if(M) {
set_OUT(thisctr, 1);
} else {
set_OUT(thisctr, 0);
}
thisctr.next_change_time=0;
}
}
} else {
//Write to counter initial value.
counter_type & thisctr = counter[address];
BX_DEBUG(("Write Initial Count: counter=%d, count=%d",address,data));
switch(thisctr.write_state) {
case LSByte_multiple:
thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
thisctr.write_state=MSByte_multiple;
break;
case LSByte:
thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
thisctr.null_count=1;
thisctr.count_written=1;
break;
case MSByte_multiple:
thisctr.write_state=LSByte_multiple;
case MSByte: //shared between MSB_multiple and MSByte
thisctr.inlatch=(thisctr.inlatch & 0xFF) | (data<<8);
thisctr.null_count=1;
thisctr.count_written=1;
break;
default:
BX_ERROR(("write counter in invalid write state."));
break;
}
switch(thisctr.mode) {
case 0:
if(thisctr.write_state==MSByte_multiple) {
set_OUT(thisctr,0);
}
thisctr.next_change_time=1;
break;
case 1:
if(thisctr.triggerGATE) { //for initial writes, if already saw trigger.
thisctr.next_change_time=1;
} //Otherwise, no change.
break;
case 6:
case 2:
thisctr.next_change_time=1; //FIXME: this could be loosened.
break;
case 7:
case 3:
thisctr.next_change_time=1; //FIXME: this could be loosened.
break;
case 4:
thisctr.next_change_time=1;
break;
case 5:
if(thisctr.triggerGATE) { //for initial writes, if already saw trigger.
thisctr.next_change_time=1;
} //Otherwise, no change.
break;
}
}
}
void pit_82C54::set_GATE(Bit8u cnum, bool data) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 set_GATE"));
} else {
counter_type & thisctr = counter[cnum];
if(!( (thisctr.GATE&&data) || (!(thisctr.GATE||data)) )) {
BX_INFO(("Changing GATE %d to: %d",cnum,data));
thisctr.GATE=data;
if(thisctr.GATE) {
thisctr.triggerGATE=1;
}
switch(thisctr.mode) {
case 0:
if(data && thisctr.count_written) {
if(thisctr.null_count) {
thisctr.next_change_time=1;
} else {
if( (!thisctr.OUTpin) &&
(thisctr.write_state!=MSByte_multiple)
) {
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
if(thisctr.null_count) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=0;
}
}
break;
case 1:
if(data && thisctr.count_written) { //only triggers cause a change.
thisctr.next_change_time=1;
}
break;
case 2:
if(!data) {
set_OUT(thisctr,1);
thisctr.next_change_time=0;
} else {
if(thisctr.count_written) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=0;
}
}
break;
case 3:
if(!data) {
set_OUT(thisctr,1);
thisctr.first_pass=1;
thisctr.next_change_time=0;
} else {
if(thisctr.count_written) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=0;
}
}
break;
case 4:
if(!thisctr.OUTpin || thisctr.null_count) {
thisctr.next_change_time=1;
} else {
if(data && thisctr.count_written) {
if(thisctr.first_pass) {
if(thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
} else {
thisctr.next_change_time=0;
}
}
break;
case 5:
if(data && thisctr.count_written) { //only triggers cause a change.
thisctr.next_change_time=1;
}
break;
default:
break;
}
}
}
}
bool pit_82C54::read_OUT(Bit8u cnum) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 read_OUT"));
return 0;
} else {
return counter[cnum].OUTpin;
}
}
bool pit_82C54::read_GATE(Bit8u cnum) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
return 0;
} else {
return counter[cnum].GATE;
}
}
Bit32u pit_82C54::get_clock_event_time(Bit8u cnum) {
if(cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
return 0;
} else {
return counter[cnum].next_change_time;
}
}
Bit32u pit_82C54::get_next_event_time(void) {
Bit32u out;
Bit32u time0=get_clock_event_time(0);
Bit32u time1=get_clock_event_time(1);
Bit32u time2=get_clock_event_time(2);
out=time0;
if(time1 && (time1<out))
out=time1;
if(time2 && (time2<out))
out=time2;
return out;
}
Bit16u pit_82C54::get_inlatch(int counternum) {
return counter[counternum].inlatch;
}