Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
972
simulators/bochs/iodev/pit82c54.cc
Normal file
972
simulators/bochs/iodev/pit82c54.cc
Normal file
@ -0,0 +1,972 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 The Bochs Project
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
/*
|
||||
* 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?
|
||||
*/
|
||||
|
||||
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
||||
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
||||
// is used to know when we are exporting symbols and when we are importing.
|
||||
#define BX_PLUGGABLE
|
||||
|
||||
#include "iodev.h"
|
||||
#include "pit82c54.h"
|
||||
#define LOG_THIS this->
|
||||
|
||||
|
||||
void pit_82C54::print_counter(counter_type &thisctr)
|
||||
{
|
||||
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"));
|
||||
}
|
||||
|
||||
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, bx_bool data)
|
||||
{
|
||||
if (thisctr.OUTpin != data) {
|
||||
thisctr.OUTpin = data;
|
||||
if (thisctr.out_handler != NULL) {
|
||||
thisctr.out_handler(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)
|
||||
{
|
||||
put("PIT81");
|
||||
|
||||
for(int 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;
|
||||
counter[i].out_handler=NULL;
|
||||
}
|
||||
seen_problems=0;
|
||||
}
|
||||
|
||||
pit_82C54::pit_82C54(void)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void pit_82C54::reset(unsigned type) {}
|
||||
|
||||
void pit_82C54::register_state(bx_param_c *parent)
|
||||
{
|
||||
char name[4];
|
||||
|
||||
for (unsigned i=0; i<3; i++) {
|
||||
sprintf(name, "%d", i);
|
||||
bx_list_c *tim = new bx_list_c(parent, name, 22);
|
||||
new bx_shadow_bool_c(tim, "GATE", &counter[i].GATE);
|
||||
new bx_shadow_bool_c(tim, "OUTpin", &counter[i].OUTpin);
|
||||
new bx_shadow_num_c(tim, "count", &counter[i].count);
|
||||
new bx_shadow_num_c(tim, "outlatch", &counter[i].outlatch);
|
||||
new bx_shadow_num_c(tim, "inlatch", &counter[i].inlatch);
|
||||
new bx_shadow_num_c(tim, "status_latch", &counter[i].status_latch);
|
||||
new bx_shadow_num_c(tim, "rw_mode", &counter[i].rw_mode);
|
||||
new bx_shadow_num_c(tim, "mode", &counter[i].mode);
|
||||
new bx_shadow_bool_c(tim, "bcd_mode", &counter[i].bcd_mode);
|
||||
new bx_shadow_bool_c(tim, "null_count", &counter[i].null_count);
|
||||
new bx_shadow_bool_c(tim, "count_LSB_latched", &counter[i].count_LSB_latched);
|
||||
new bx_shadow_bool_c(tim, "count_MSB_latched", &counter[i].count_MSB_latched);
|
||||
new bx_shadow_bool_c(tim, "status_latched", &counter[i].status_latched);
|
||||
new bx_shadow_num_c(tim, "count_binary", &counter[i].count_binary);
|
||||
new bx_shadow_bool_c(tim, "triggerGATE", &counter[i].triggerGATE);
|
||||
new bx_shadow_num_c(tim, "write_state", (Bit8u*)&counter[i].write_state);
|
||||
new bx_shadow_num_c(tim, "read_state", (Bit8u*)&counter[i].read_state);
|
||||
new bx_shadow_bool_c(tim, "count_written", &counter[i].count_written);
|
||||
new bx_shadow_bool_c(tim, "first_pass", &counter[i].first_pass);
|
||||
new bx_shadow_bool_c(tim, "state_bit_1", &counter[i].state_bit_1);
|
||||
new bx_shadow_bool_c(tim, "state_bit_2", &counter[i].state_bit_2);
|
||||
new bx_shadow_num_c(tim, "next_change_time", &counter[i].next_change_time);
|
||||
}
|
||||
}
|
||||
|
||||
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 = data;
|
||||
thisctr.write_state = MSByte_multiple;
|
||||
break;
|
||||
case LSByte:
|
||||
thisctr.inlatch = data;
|
||||
thisctr.count_written = 1;
|
||||
break;
|
||||
case MSByte_multiple:
|
||||
thisctr.write_state = LSByte_multiple;
|
||||
thisctr.inlatch |= (data << 8);
|
||||
thisctr.count_written = 1;
|
||||
break;
|
||||
case MSByte:
|
||||
thisctr.inlatch = (data << 8);
|
||||
thisctr.count_written = 1;
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("write counter in invalid write state."));
|
||||
break;
|
||||
}
|
||||
if (thisctr.count_written && thisctr.write_state != MSByte_multiple) {
|
||||
thisctr.null_count = 1;
|
||||
set_count(thisctr, thisctr.inlatch);
|
||||
}
|
||||
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, bx_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool pit_82C54::read_OUT(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number incorrect in 82C54 read_OUT"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return counter[cnum].OUTpin;
|
||||
}
|
||||
|
||||
bx_bool pit_82C54::read_GATE(Bit8u cnum)
|
||||
{
|
||||
if (cnum>MAX_COUNTER) {
|
||||
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return counter[cnum].next_change_time;
|
||||
}
|
||||
|
||||
Bit32u pit_82C54::get_next_event_time(void)
|
||||
{
|
||||
Bit32u time0=get_clock_event_time(0);
|
||||
Bit32u time1=get_clock_event_time(1);
|
||||
Bit32u time2=get_clock_event_time(2);
|
||||
|
||||
Bit32u 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;
|
||||
}
|
||||
|
||||
void pit_82C54::set_OUT_handler(Bit8u counternum, out_handler_t outh)
|
||||
{
|
||||
counter[counternum].out_handler = outh;
|
||||
}
|
||||
Reference in New Issue
Block a user