Bochs/bochs/iodev/pit.cc

855 lines
29 KiB
C++
Raw Normal View History

/////////////////////////////////////////////////////////////////////////
// $Id: pit.cc,v 1.24 2006-09-17 19:19:15 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
//
// MandrakeSoft S.A.
// 43, rue d'Aboukir
// 75002 Paris - France
// http://www.linux-mandrake.com/
// http://www.mandrakesoft.com/
//
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "iodev.h"
#if (BX_USE_NEW_PIT==0)
#include "speaker.h"
#define LOG_THIS bx_pit.
// NOTES ON THE 8253/8254 PIT MODES
// MODE 0: Interrupt on Terminal Count
// ===================================
// Writing new count action:
// loaded upon next CLK pulse. counting doesn't start until GATE=1
// GATE 0..1 transition:
// ???
// GATE 1..0 transition:
// counter expiration action:
// wraps to FFFF
// * OUT rises until new count val or new control word for mode 0 written
// MODE 1: Programmable Monoflop
// =============================
// Writing new count action:
// not effective for current process
// GATE 0..1 transition:
// loads counter
// counter expiration action:
// wraps to FFFF
// NOTES:
// OUT rises until new count val or new control word for mode 0 written
// MODE 2: Rate Generator
// ======================
// Writing new count action:
// ???
// GATE 0..1 transition:
// loads initial count val and starts counting
// counter expiration action:
// reloads after count expires
// NOTES:
// * after control word & initial count val N loaded, PIT starts
// counting upon next CLK pulse.
// * when counter reaches 1, OUT drops to a low level, for one
// CLK cycle. (short peak pulse generated)
// * afterwards, the initial count val is automatically reloaded
// and the PIT restarts the same counting operation again.
// * distance of two OUT pulses is N CLK cycles long.
// * GATE=1 enables, GATE=0 disables counter.
// * if GATE drops to low level during counting operation and rises
// to high level later, PIT loads initial count value at the
// rise and starts counting.
// * PIT starts counting after last data byte written if GATE=1
// * if the output is low when the gate goes low, the output is
// immediately set high.
// MODE 3: Square Wave Generator
// =============================
// Writing new count action:
// ???
// GATE 0..1 transition:
// ???
// counter expiration action:
// reloads after count expires
// NOTES:
// * initially OUT at a high level
// * drop of GATE to a low level while OUT low, raises OUT to a high level
// * a rise from a low to a high level at GATE (trigger pulse),
// loads the counter with the initial count value and starts
// counting operation
// * a new count value supplied during the course of an active
// counting operation doesn't affect the current process.
// At the end of the current half cycle, the PIT loads the new value
// * if the GATE line goes low, count is temporarily halted until GATE
// returns high
// * if the OUT line is high when GATE goes low, OUT is forced low.
// ??? different for odd/even counts
// MODE 4: Software Triggered Pulse
// ================================
// Writing new count action:
// ???
// GATE 0..1 transition:
// ???
// counter expiration action:
// wraps to FFFF
// NOTES:
// MODE 5: Hardware Triggered Pulse
// ================================
// Writing new count action:
// ???
// GATE 0..1 transition:
// ???
// counter expiration action:
// wraps to FFFF
// NOTES:
#define BX_PIT_LATCH_MODE_LSB 10
#define BX_PIT_LATCH_MODE_MSB 11
#define BX_PIT_LATCH_MODE_16BIT 12
bx_pit_c bx_pit;
#if BX_USE_PIT_SMF
#define this (&bx_pit)
#endif
#ifdef OUT
# undef OUT
#endif
bx_pit_c::bx_pit_c(void)
{
2001-06-27 23:16:01 +04:00
put("PIT");
settype(PITLOG);
memset(&s, 0, sizeof(s));
/* 8254 PIT (Programmable Interval Timer) */
}
bx_pit_c::~bx_pit_c(void)
{
}
int bx_pit_c::init(void)
{
2002-10-26 07:57:19 +04:00
DEV_register_irq(0, "8254 PIT");
DEV_register_ioread_handler(this, read_handler, 0x0040, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0041, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0042, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0043, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0061, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0040, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0041, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0042, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0043, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0061, "8254 PIT", 1);
BX_PIT_THIS s.speaker_data_on = 0;
BX_PIT_THIS s.refresh_clock_div2 = 0;
BX_PIT_THIS s.timer[0].mode = 3; /* periodic rate generator */
BX_PIT_THIS s.timer[0].latch_mode = BX_PIT_LATCH_MODE_16BIT;
BX_PIT_THIS s.timer[0].input_latch_value = 0;
BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
BX_PIT_THIS s.timer[0].output_latch_value = 0;
BX_PIT_THIS s.timer[0].output_latch_toggle = 0;
BX_PIT_THIS s.timer[0].output_latch_full = 0;
BX_PIT_THIS s.timer[0].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
BX_PIT_THIS s.timer[0].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
BX_PIT_THIS s.timer[0].bcd_mode = 0; /* binary counting mode */
BX_PIT_THIS s.timer[0].GATE = 1; /* GATE tied to + logic */
BX_PIT_THIS s.timer[0].OUT = 1;
BX_PIT_THIS s.timer[0].active = 0;
BX_PIT_THIS s.timer[1].mode = 3; /* periodic rate generator */
BX_PIT_THIS s.timer[1].latch_mode = BX_PIT_LATCH_MODE_16BIT;
BX_PIT_THIS s.timer[1].input_latch_value = 0;
BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
BX_PIT_THIS s.timer[1].output_latch_value = 0;
BX_PIT_THIS s.timer[1].output_latch_toggle = 0;
BX_PIT_THIS s.timer[1].output_latch_full = 0;
BX_PIT_THIS s.timer[1].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
BX_PIT_THIS s.timer[1].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
BX_PIT_THIS s.timer[1].bcd_mode = 0; /* binary counting mode */
BX_PIT_THIS s.timer[1].GATE = 1; /* GATE tied to + logic */
BX_PIT_THIS s.timer[1].OUT = 1;
BX_PIT_THIS s.timer[1].active = 0;
BX_PIT_THIS s.timer[2].mode = 3; /* periodic rate generator */
BX_PIT_THIS s.timer[2].latch_mode = BX_PIT_LATCH_MODE_16BIT;
BX_PIT_THIS s.timer[2].input_latch_value = 0;
BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
BX_PIT_THIS s.timer[2].output_latch_value = 0;
BX_PIT_THIS s.timer[2].output_latch_toggle = 0;
BX_PIT_THIS s.timer[2].output_latch_full = 0;
BX_PIT_THIS s.timer[2].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
BX_PIT_THIS s.timer[2].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
BX_PIT_THIS s.timer[2].bcd_mode = 0; /* binary counting mode */
BX_PIT_THIS s.timer[2].GATE = 0; /* timer2 gate controlled by port 61h bit 0 */
BX_PIT_THIS s.timer[2].OUT = 1;
BX_PIT_THIS s.timer[2].active = 0;
return(1);
}
int bx_pit_c::exit(void)
{
}
2006-05-27 19:54:49 +04:00
void bx_pit_c::reset(unsigned type)
{
}
2006-05-27 19:54:49 +04:00
#if BX_SUPPORT_SAVE_RESTORE
void bx_pit_c::register_state(void)
{
unsigned i;
char name[4];
bx_list_c *tim;
bx_list_c *list = new bx_list_c(SIM->get_sr_root(), "pit", "8254 PIT State");
for (i=0; i<3; i++) {
sprintf(name, "timer%d", i);
tim = new bx_list_c(list, name, 13);
2006-05-27 19:54:49 +04:00
new bx_shadow_num_c(tim, "mode", &BX_PIT_THIS s.timer[i].mode, 16);
new bx_shadow_num_c(tim, "latch_mode", &BX_PIT_THIS s.timer[i].latch_mode, 16);
new bx_shadow_num_c(tim, "input_latch_value", &BX_PIT_THIS s.timer[i].input_latch_value, 16);
new bx_shadow_bool_c(tim, "input_latch_toggle", &BX_PIT_THIS s.timer[i].input_latch_toggle);
new bx_shadow_num_c(tim, "output_latch_value", &BX_PIT_THIS s.timer[i].output_latch_value, 16);
new bx_shadow_bool_c(tim, "output_latch_toggle", &BX_PIT_THIS s.timer[i].output_latch_toggle);
new bx_shadow_bool_c(tim, "output_latch_full", &BX_PIT_THIS s.timer[i].output_latch_full);
new bx_shadow_num_c(tim, "counter_max", &BX_PIT_THIS s.timer[i].counter_max, 16);
new bx_shadow_num_c(tim, "counter", &BX_PIT_THIS s.timer[i].counter, 16);
new bx_shadow_bool_c(tim, "bcd_mode", &BX_PIT_THIS s.timer[i].bcd_mode);
new bx_shadow_bool_c(tim, "active", &BX_PIT_THIS s.timer[i].active);
new bx_shadow_bool_c(tim, "GATE", &BX_PIT_THIS s.timer[i].GATE);
new bx_shadow_bool_c(tim, "OUT", &BX_PIT_THIS s.timer[i].OUT);
}
new bx_shadow_num_c(list, "speaker_data_on", &BX_PIT_THIS s.speaker_data_on, 16);
new bx_shadow_bool_c(list, "refresh_clock_div2", &BX_PIT_THIS s.refresh_clock_div2);
}
#endif
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u
bx_pit_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PIT_SMF
bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
return( class_ptr->read(address, io_len) );
}
Bit32u
bx_pit_c::read( Bit32u address, unsigned int io_len )
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIT_SMF
if (bx_dbg.pit)
BX_INFO(("pit: io read from port %04x", (unsigned) address));
switch (address) {
case 0x40: /* timer 0 - system ticks */
return( read_counter(0) );
break;
case 0x42: /* timer 2 read */
return( read_counter(2) );
break;
case 0x61:
/* AT, port 61h */
BX_PIT_THIS s.refresh_clock_div2 = !BX_PIT_THIS s.refresh_clock_div2;
return( (BX_PIT_THIS s.timer[2].OUT<<5) |
(BX_PIT_THIS s.refresh_clock_div2<<4) |
(BX_PIT_THIS s.speaker_data_on<<1) |
(BX_PIT_THIS s.timer[2].GATE) );
break;
default:
BX_PANIC(("pit: unsupported io read from port %04x", address));
}
return(0); /* keep compiler happy */
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void
bx_pit_c::write_handler(void *this_ptr, Bit32u address, Bit32u dvalue, unsigned io_len)
{
#if !BX_USE_PIT_SMF
bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
class_ptr->write(address, dvalue, io_len);
}
void
bx_pit_c::write( Bit32u address, Bit32u dvalue, unsigned int io_len )
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIT_SMF
Bit8u command, mode, bcd_mode;
Bit8u value;
value = (Bit8u)dvalue;
if (bx_dbg.pit)
BX_INFO(("pit: write to port %04x = %02x",
(unsigned) address, (unsigned) value));
switch (address) {
case 0x40: /* timer 0: write count register */
write_count_reg( value, 0 );
break;
case 0x41: /* timer 1: write count register */
write_count_reg( value, 1 );
break;
case 0x42: /* timer 2: write count register */
write_count_reg( value, 2 );
break;
case 0x43: /* timer 0-2 mode control */
/* |7 6 5 4|3 2 1|0|
* |-------|-----|-|
* |command|mode |bcd/binary|
*/
command = value >> 4;
mode = (value >> 1) & 0x07;
bcd_mode = value & 0x01;
BX_DEBUG(("timer 0-2 mode control: cmd=0x%02x mode=0x%02x bcd_mode=%u",
command, mode, bcd_mode));
if ( (mode > 5) || (command > 0x0e) )
BX_PANIC(("pit: outp(43h)=%02xh out of range", (unsigned) value));
if (bcd_mode)
BX_PANIC(("pit: outp(43h)=%02xh: bcd mode unhandled",
(unsigned) bcd_mode));
switch (command) {
case 0x0: /* timer 0: counter latch */
latch( 0 );
break;
case 0x1: /* timer 0: LSB mode */
case 0x2: /* timer 0: MSB mode */
BX_PANIC(("pit: outp(43h): command %02xh unhandled",
(unsigned) command));
break;
case 0x3: /* timer 0: 16-bit mode */
BX_PIT_THIS s.timer[0].mode = mode;
BX_PIT_THIS s.timer[0].latch_mode = BX_PIT_LATCH_MODE_16BIT;
BX_PIT_THIS s.timer[0].input_latch_value = 0;
BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
BX_PIT_THIS s.timer[0].bcd_mode = bcd_mode;
if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
BX_PANIC(("pit: outp(43h): comm 3, mode %02x, bcd %02x unhandled",
(unsigned) mode, bcd_mode));
break;
case 0x4: /* timer 1: counter latch */
latch( 1 );
break;
case 0x5: /* timer 1: LSB mode */
case 0x6: /* timer 1: MSB mode */
BX_INFO(("pit: outp(43h): command %02xh unhandled (ignored)",
(unsigned) command));
break;
case 0x7: /* timer 1: 16-bit mode */
BX_PIT_THIS s.timer[1].mode = mode;
BX_PIT_THIS s.timer[1].latch_mode = BX_PIT_LATCH_MODE_16BIT;
BX_PIT_THIS s.timer[1].input_latch_value = 0;
BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
BX_PIT_THIS s.timer[1].bcd_mode = bcd_mode;
if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
BX_PANIC(("pit: outp(43h): comm 7, mode %02x, bcd %02x unhandled",
(unsigned) mode, bcd_mode));
break;
case 0x8: /* timer 2: counter latch */
latch( 2 );
break;
case 0x9: /* timer 2: LSB mode */
case 0xa: /* timer 2: MSB mode */
BX_PANIC(("pit: outp(43h): command %02xh unhandled",
(unsigned) command));
break;
case 0xb: /* timer 2: 16-bit mode */
BX_PIT_THIS s.timer[2].mode = mode;
BX_PIT_THIS s.timer[2].latch_mode = BX_PIT_LATCH_MODE_16BIT;
BX_PIT_THIS s.timer[2].input_latch_value = 0;
BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
BX_PIT_THIS s.timer[2].bcd_mode = bcd_mode;
if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
BX_PANIC(("pit: outp(43h): comm Bh, mode %02x, bcd %02x unhandled",
(unsigned) mode, bcd_mode));
break;
#if 0
case 0xd: /* general counter latch */
if (value & 0x08) /* select counter 2 */
latch( 2 );
if (value & 0x04) /* select counter 1 */
latch( 1 );
if (value & 0x02) /* select counter 0 */
latch( 0 );
break;
case 0xe: /* latch status of timers */
BX_PANIC(("pit: outp(43h): command %02xh unhandled",
(unsigned) command);
break;
#endif
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
BX_INFO(("pit: ignoring 8254 command %u", (unsigned) command));
break;
default: /* 0xc & 0xf */
BX_PANIC(("pit: outp(43h) command %1xh unhandled",
(unsigned) command));
break;
}
break;
case 0x61:
BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
2004-01-16 19:30:46 +03:00
if ( BX_PIT_THIS s.speaker_data_on )
DEV_speaker_beep_on(440.0);
2004-01-16 19:30:46 +03:00
else
DEV_speaker_beep_off();
/* ??? only on AT+ */
set_GATE(2, value & 0x01);
break;
default:
BX_PANIC(("pit: unsupported io write to port %04x = %02x",
(unsigned) address, (unsigned) value));
}
}
void
bx_pit_c::write_count_reg( Bit8u value, unsigned timerid )
{
- Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a "bx_bool" which is always defined as Bit32u on all platforms. In Carbon specific code, Boolean is still used because the Carbon header files define it to unsigned char. - this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95. The bug was that some code in Bochs depends on Boolean to be a 32 bit value. (This should be fixed, but I don't know all the places where it needs to be fixed yet.) Because Carbon defined Boolean as an unsigned char, Bochs just followed along and used the unsigned char definition to avoid compile problems. This exposed the dependency on 32 bit Boolean on MacOS X only and led to major simulation problems, that could only be reproduced and debugged on that platform. - On the mailing list we debated whether to make all Booleans into "bool" or our own type. I chose bx_bool for several reasons. 1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all platforms, which makes it much less likely to have more platform-specific simulation differences in the future. (I spent hours on a borrowed MacOSX machine chasing bug 618388 before discovering that different sized Booleans were the problem, and I don't want to repeat that.) 2. We still have at least one dependency on 32 bit Booleans which must be fixed some time, but I don't want to risk introducing new bugs into the simulation just before the 2.0 release. Modified Files: bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile docs-html/cosimulation.html fpu/wmFPUemu_glue.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h gui/x.cc instrument/example0/instrument.cc instrument/example0/instrument.h instrument/example1/instrument.cc instrument/example1/instrument.h instrument/stubs/instrument.cc instrument/stubs/instrument.h iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc iodev/eth_packetmaker.cc iodev/eth_packetmaker.h iodev/floppy.cc iodev/floppy.h iodev/guest2host.h iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 15:44:41 +04:00
bx_bool xfer_complete;
switch ( BX_PIT_THIS s.timer[timerid].latch_mode ) {
case BX_PIT_LATCH_MODE_16BIT: /* write1=LSB, write2=MSB */
if (BX_PIT_THIS s.timer[timerid].input_latch_toggle==0) {
BX_PIT_THIS s.timer[timerid].input_latch_value = value;
BX_PIT_THIS s.timer[timerid].input_latch_toggle = 1;
xfer_complete = 0;
if (bx_dbg.pit)
BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x", (unsigned) value));
}
else {
BX_PIT_THIS s.timer[timerid].input_latch_value |= (value << 8);
BX_PIT_THIS s.timer[timerid].input_latch_toggle = 0;
xfer_complete = 1;
if (bx_dbg.pit)
BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x", (unsigned) value));
}
break;
case BX_PIT_LATCH_MODE_MSB: /* write1=MSB, LSB=0 */
BX_PIT_THIS s.timer[timerid].input_latch_value = (value << 8);
xfer_complete = 1;
if (bx_dbg.pit)
BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x", (unsigned) value));
break;
case BX_PIT_LATCH_MODE_LSB: /* write1=LSB, MSB=0 */
BX_PIT_THIS s.timer[timerid].input_latch_value = value;
xfer_complete = 1;
if (bx_dbg.pit)
BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x", (unsigned) value));
break;
default:
BX_PANIC(("write_count_reg: latch_mode unknown"));
xfer_complete = 0;
}
if (xfer_complete) {
BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].input_latch_value;
// reprogramming counter clears latch
BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
// counter bounds
// mode minimum maximum
// 0 1 0
// 1 1 0
// 2 2 0
// 3 2 0
// 4 1 0
// 5 1 0
switch (BX_PIT_THIS s.timer[timerid].mode) {
case 0:
BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
BX_PIT_THIS s.timer[timerid].active = 1;
if (BX_PIT_THIS s.timer[timerid].GATE) {
BX_PIT_THIS s.timer[timerid].OUT = 0; // OUT pin starts low
start( timerid );
}
break;
case 1:
BX_PANIC(("pit:write_count_reg(%u): mode1 unsupported",
timerid));
break;
case 2:
if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1",
timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
// software triggered
BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
BX_PIT_THIS s.timer[timerid].active = 1;
BX_PIT_THIS s.timer[timerid].OUT = 1; // initially set high
start( timerid );
}
break;
case 3:
if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1",
timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].counter_max & 0xfffe;
if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
// software triggered
BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
BX_PIT_THIS s.timer[timerid].active = 1;
BX_PIT_THIS s.timer[timerid].OUT = 1; // initially set high
start( timerid );
}
break;
case 4:
BX_PANIC(("pit:write_count_reg(%u): mode4 unsupported",
timerid));
break;
case 5:
BX_PANIC(("pit:write_count_reg(%u): mode5 unsupported",
timerid));
break;
}
}
}
Bit8u
bx_pit_c::read_counter( unsigned timerid )
{
Bit16u counter_value;
Bit8u retval;
if (BX_PIT_THIS s.timer[timerid].output_latch_full) { /* latched read */
counter_value = BX_PIT_THIS s.timer[timerid].output_latch_value;
}
else { /* direct unlatched read */
counter_value = BX_PIT_THIS s.timer[timerid].counter;
BX_INFO(("CV=%04x", (unsigned) BX_PIT_THIS s.timer[timerid].counter));
}
switch (BX_PIT_THIS s.timer[timerid].latch_mode) {
case BX_PIT_LATCH_MODE_LSB:
retval = (Bit8u ) counter_value;
BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
break;
case BX_PIT_LATCH_MODE_MSB:
retval = (Bit8u ) ( counter_value >> 8 );
BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
break;
case BX_PIT_LATCH_MODE_16BIT:
if (BX_PIT_THIS s.timer[timerid].output_latch_toggle==0) { /* LSB 1st */
retval = (Bit8u ) counter_value;
}
else { /* MSB 2nd */
retval = (Bit8u ) ( counter_value >> 8 );
}
BX_PIT_THIS s.timer[timerid].output_latch_toggle = !BX_PIT_THIS s.timer[timerid].output_latch_toggle;
if (BX_PIT_THIS s.timer[timerid].output_latch_toggle == 0)
BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
break;
default:
BX_PANIC(("pit: io read from port 40h: unknown latch mode"));
retval = 0; /* keep compiler happy */
}
return( retval );
}
void
bx_pit_c::latch( unsigned timerid )
{
/* subsequent counter latch commands are ignored until value read out */
if (BX_PIT_THIS s.timer[timerid].output_latch_full) {
BX_INFO(("pit: pit(%u) latch: output latch full, ignoring",
timerid));
return;
}
BX_PIT_THIS s.timer[timerid].output_latch_value = BX_PIT_THIS s.timer[timerid].counter;
if (bx_dbg.pit)
2002-10-26 07:57:19 +04:00
BX_INFO(("pit: latch_value = %u", (unsigned) BX_PIT_THIS s.timer[timerid].output_latch_value));
BX_PIT_THIS s.timer[timerid].output_latch_toggle = 0;
BX_PIT_THIS s.timer[timerid].output_latch_full = 1;
}
void
bx_pit_c::set_GATE(unsigned pit_id, unsigned value)
{
// GATE's for Timer 0 & Timer 1 are tied high.
if (pit_id != 2)
BX_PANIC(("pit:set_GATE: pit_id != 2"));
value = (value > 0);
/* if no transition of GATE input line, then nothing to do */
if (value == BX_PIT_THIS s.timer[2].GATE)
return;
if (value) { /* PIT2: GATE transition from 0 to 1 */
BX_PIT_THIS s.timer[2].GATE = 1;
switch ( BX_PIT_THIS s.timer[2].mode ) {
case 0:
BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
if (BX_PIT_THIS s.timer[2].active) {
BX_PIT_THIS s.timer[2].OUT = 0;
}
start( 2 );
break;
case 2:
// begin counting, reload counter
BX_PIT_THIS s.timer[2].active = 1;
BX_PIT_THIS s.timer[2].OUT = 1;
BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
start( 2 );
break;
case 3:
// begin counting, reload counter
BX_PIT_THIS s.timer[2].active = 1;
BX_PIT_THIS s.timer[2].OUT = 1;
BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
start( 2 );
break;
case 1:
case 4:
case 5:
default:
BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u",
(unsigned) BX_PIT_THIS s.timer[2].mode));
}
}
else { // PIT2: GATE transition from 1 to 0, deactivate
BX_PIT_THIS s.timer[2].GATE = 0;
switch ( BX_PIT_THIS s.timer[2].mode ) {
case 0:
break;
case 2:
// 1) stops count, 2) OUT goes immediately high
BX_PIT_THIS s.timer[2].active = 0;
BX_PIT_THIS s.timer[2].OUT = 1;
break;
case 3:
// 1) stops count, 2) OUT goes immediately high
BX_PIT_THIS s.timer[2].active = 0;
BX_PIT_THIS s.timer[2].OUT = 1;
break;
case 1:
case 4:
case 5:
default:
BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u",
(unsigned) BX_PIT_THIS s.timer[2].mode));
}
}
}
void
bx_pit_c::start(unsigned timerid)
{
double period_hz;
if (BX_PIT_THIS s.timer[timerid].counter_max == 0x0000) {
period_hz = 1193182.0 / 65536.0;
} else {
period_hz = 1193182 / BX_PIT_THIS s.timer[timerid].counter_max;
}
BX_INFO(("timer%u period set to %.1f Hz", timerid, period_hz));
switch (BX_PIT_THIS s.timer[timerid].mode) {
case 0: /* single timeout */
break;
case 1: /* retriggerable one-shot */
BX_PANIC(("start: mode %u unhandled",
(unsigned) BX_PIT_THIS s.timer[timerid].mode));
break;
case 2: /* rate generator */
break;
case 3: /* square wave mode */
break;
case 4: /* software triggered strobe */
BX_PANIC(("start: mode %u unhandled",
(unsigned) BX_PIT_THIS s.timer[timerid].mode));
break;
case 5: /* hardware retriggerable strobe */
BX_PANIC(("start: mode %u unhandled",
(unsigned) BX_PIT_THIS s.timer[timerid].mode));
break;
default:
BX_PANIC(("start: timer%u has bad mode",
(unsigned) BX_PIT_THIS s.timer[timerid].mode));
}
}
- Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a "bx_bool" which is always defined as Bit32u on all platforms. In Carbon specific code, Boolean is still used because the Carbon header files define it to unsigned char. - this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95. The bug was that some code in Bochs depends on Boolean to be a 32 bit value. (This should be fixed, but I don't know all the places where it needs to be fixed yet.) Because Carbon defined Boolean as an unsigned char, Bochs just followed along and used the unsigned char definition to avoid compile problems. This exposed the dependency on 32 bit Boolean on MacOS X only and led to major simulation problems, that could only be reproduced and debugged on that platform. - On the mailing list we debated whether to make all Booleans into "bool" or our own type. I chose bx_bool for several reasons. 1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all platforms, which makes it much less likely to have more platform-specific simulation differences in the future. (I spent hours on a borrowed MacOSX machine chasing bug 618388 before discovering that different sized Booleans were the problem, and I don't want to repeat that.) 2. We still have at least one dependency on 32 bit Booleans which must be fixed some time, but I don't want to risk introducing new bugs into the simulation just before the 2.0 release. Modified Files: bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile docs-html/cosimulation.html fpu/wmFPUemu_glue.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h gui/x.cc instrument/example0/instrument.cc instrument/example0/instrument.h instrument/example1/instrument.cc instrument/example1/instrument.h instrument/stubs/instrument.cc instrument/stubs/instrument.h iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc iodev/eth_packetmaker.cc iodev/eth_packetmaker.h iodev/floppy.cc iodev/floppy.h iodev/guest2host.h iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 15:44:41 +04:00
bx_bool
bx_pit_c::periodic( Bit32u usec_delta )
{
- Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a "bx_bool" which is always defined as Bit32u on all platforms. In Carbon specific code, Boolean is still used because the Carbon header files define it to unsigned char. - this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95. The bug was that some code in Bochs depends on Boolean to be a 32 bit value. (This should be fixed, but I don't know all the places where it needs to be fixed yet.) Because Carbon defined Boolean as an unsigned char, Bochs just followed along and used the unsigned char definition to avoid compile problems. This exposed the dependency on 32 bit Boolean on MacOS X only and led to major simulation problems, that could only be reproduced and debugged on that platform. - On the mailing list we debated whether to make all Booleans into "bool" or our own type. I chose bx_bool for several reasons. 1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all platforms, which makes it much less likely to have more platform-specific simulation differences in the future. (I spent hours on a borrowed MacOSX machine chasing bug 618388 before discovering that different sized Booleans were the problem, and I don't want to repeat that.) 2. We still have at least one dependency on 32 bit Booleans which must be fixed some time, but I don't want to risk introducing new bugs into the simulation just before the 2.0 release. Modified Files: bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile docs-html/cosimulation.html fpu/wmFPUemu_glue.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h gui/x.cc instrument/example0/instrument.cc instrument/example0/instrument.h instrument/example1/instrument.cc instrument/example1/instrument.h instrument/stubs/instrument.cc instrument/stubs/instrument.h iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc iodev/eth_packetmaker.cc iodev/eth_packetmaker.h iodev/floppy.cc iodev/floppy.h iodev/guest2host.h iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 15:44:41 +04:00
bx_bool prev_timer0_out;
prev_timer0_out = BX_PIT_THIS s.timer[0].OUT;
for (unsigned i = 0; i < 3; i++) {
// is timer enabled and active?
if ( BX_PIT_THIS s.timer[i].GATE && BX_PIT_THIS s.timer[i].active ) {
switch ( BX_PIT_THIS s.timer[i].mode ) {
case 0: // Mode 0: Single Timeout
// wraps after count expires
if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
// counter previously expired, wrap counter
BX_PIT_THIS s.timer[i].counter = 0xffff;
}
else if ( usec_delta >= BX_PIT_THIS s.timer[i].counter ) {
// counter expired
BX_PIT_THIS s.timer[i].counter = 0;
BX_PIT_THIS s.timer[i].OUT = 1;
}
else {
// decrement counter by elapsed useconds
BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
}
break;
case 1: // Mode 1: Retriggerable One-Shot
// wraps after count expires
BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
i, (unsigned) BX_PIT_THIS s.timer[i].mode));
break;
case 2: // Mode 2: Rate Generator
// reloads after count expires
// OUT is low when counter=1, high otherwise
// min count=2, max count=0
if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
// max counter val, just wrap
BX_PIT_THIS s.timer[i].counter = 0xffff;
BX_PIT_THIS s.timer[i].OUT = 1;
}
else if ( BX_PIT_THIS s.timer[i].counter == 1 ) {
// counter previously expired, reload
BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
BX_PIT_THIS s.timer[i].OUT = 1;
}
else if ( (BX_PIT_THIS s.timer[i].counter == 2) ||
(usec_delta >= (Bit32u(BX_PIT_THIS s.timer[i].counter) - 1)) ) {
// in either case, counter will reach 1
BX_PIT_THIS s.timer[i].counter = 1;
BX_PIT_THIS s.timer[i].OUT = 0;
}
else {
// decrement counter by elapsed useconds
BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
}
break;
case 3: // Mode 3: Square Wave Mode
// reloads after count expires
// min count=2, max count=0
if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
// max count, dec by 2
BX_PIT_THIS s.timer[i].counter = 0xfffe;
}
else if ( (BX_PIT_THIS s.timer[i].counter <= 2) ||
( (usec_delta*2) >= BX_PIT_THIS s.timer[i].counter ) ) {
// counter expired, reload
BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
BX_PIT_THIS s.timer[i].OUT = !BX_PIT_THIS s.timer[i].OUT;
//BX_INFO(("CV: reload t%u to %04x", (unsigned) i, (unsigned)
// BX_PIT_THIS s.timer[i].counter));
}
else {
// decrement counter by elapsed useconds
BX_PIT_THIS s.timer[i].counter -= (Bit16u ) ( 2*usec_delta );
//BX_INFO(("CV: dec count to %04x",
// (unsigned) BX_PIT_THIS s.timer[i].counter));
}
break;
case 4: // Mode 4: Software Triggered Strobe
// wraps after count expires
BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
i, (unsigned) BX_PIT_THIS s.timer[i].mode));
break;
case 5: // Mode 5: Hardware Retriggerable Strobe
// wraps after count expires
BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
i, (unsigned) BX_PIT_THIS s.timer[i].mode));
break;
default:
BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
i, (unsigned) BX_PIT_THIS s.timer[i].mode));
break;
} // switch ( BX_PIT_THIS s.tim...
} // if ( BX_PIT_THIS s.timer[i]...
} // for (unsigned i...
// see if there's a rising edge on timer0's output to trigger an IRQ0.
if ( (prev_timer0_out==0) && (BX_PIT_THIS s.timer[0].OUT==1) )
return(1); // request IRQ 0
else
return(0);
}
#endif // #if (BX_USE_NEW_PIT==0)