2002-06-23 22:04:07 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2004-02-07 17:34:35 +03:00
|
|
|
// $Id: floppy.cc,v 1.70 2004-02-07 14:34:34 vruppert Exp $
|
2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2002-01-18 00:20:12 +03:00
|
|
|
// Copyright (C) 2002 MandrakeSoft S.A.
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
|
|
|
// 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
|
2001-06-13 11:06:10 +04:00
|
|
|
//
|
|
|
|
//
|
|
|
|
// Floppy Disk Controller Docs:
|
|
|
|
// Intel 82077A Data sheet
|
|
|
|
// ftp://void-core.2y.net/pub/docs/fdc/82077AA_FloppyControllerDatasheet.pdf
|
|
|
|
// Intel 82078 Data sheet
|
|
|
|
// ftp://download.intel.com/design/periphrl/datashts/29047403.PDF
|
|
|
|
// Other FDC references
|
|
|
|
// http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html
|
|
|
|
// And a port list:
|
|
|
|
// http://mudlist.eorbit.net/~adam/pickey/ports.html
|
|
|
|
//
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
// 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
|
|
|
|
|
|
|
|
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
extern "C" {
|
|
|
|
#include <errno.h>
|
|
|
|
}
|
2003-12-07 18:59:32 +03:00
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
extern "C" {
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <linux/fd.h>
|
|
|
|
}
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
#include "bochs.h"
|
2002-10-04 01:07:04 +04:00
|
|
|
// windows.h included by bochs.h
|
2003-12-07 18:59:32 +03:00
|
|
|
#ifdef WIN32
|
|
|
|
extern "C" {
|
|
|
|
#include <winioctl.h>
|
|
|
|
}
|
|
|
|
#endif
|
2002-10-25 01:07:56 +04:00
|
|
|
#define LOG_THIS theFloppyController->
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
bx_floppy_ctrl_c *theFloppyController;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* for main status register */
|
|
|
|
#define FD_MS_MRQ 0x80
|
|
|
|
#define FD_MS_DIO 0x40
|
|
|
|
#define FD_MS_NDMA 0x20
|
|
|
|
#define FD_MS_BUSY 0x10
|
|
|
|
#define FD_MS_ACTD 0x08
|
|
|
|
#define FD_MS_ACTC 0x04
|
|
|
|
#define FD_MS_ACTB 0x02
|
|
|
|
#define FD_MS_ACTA 0x01
|
|
|
|
|
|
|
|
#define FROM_FLOPPY 10
|
|
|
|
#define TO_FLOPPY 11
|
|
|
|
|
|
|
|
#define FLOPPY_DMA_CHAN 2
|
|
|
|
|
2003-11-24 00:54:59 +03:00
|
|
|
typedef struct {
|
|
|
|
unsigned id;
|
|
|
|
Bit8u trk;
|
|
|
|
Bit8u hd;
|
|
|
|
Bit8u spt;
|
|
|
|
unsigned sectors;
|
|
|
|
} floppy_type_t;
|
|
|
|
|
|
|
|
static floppy_type_t floppy_type[8] = {
|
|
|
|
{BX_FLOPPY_160K, 40, 1, 8, 320},
|
|
|
|
{BX_FLOPPY_180K, 40, 1, 9, 360},
|
|
|
|
{BX_FLOPPY_320K, 40, 2, 8, 640},
|
|
|
|
{BX_FLOPPY_360K, 40, 2, 9, 720},
|
|
|
|
{BX_FLOPPY_720K, 80, 2, 9, 1440},
|
|
|
|
{BX_FLOPPY_1_2, 80, 2, 15, 2400},
|
|
|
|
{BX_FLOPPY_1_44, 80, 2, 18, 2880},
|
|
|
|
{BX_FLOPPY_2_88, 80, 2, 36, 5760}
|
|
|
|
};
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
int
|
|
|
|
libfloppy_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
theFloppyController = new bx_floppy_ctrl_c ();
|
|
|
|
bx_devices.pluginFloppyDevice = theFloppyController;
|
|
|
|
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theFloppyController, BX_PLUGIN_FLOPPY);
|
|
|
|
return(0); // Success
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
libfloppy_LTX_plugin_fini(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
bx_floppy_ctrl_c::bx_floppy_ctrl_c(void)
|
|
|
|
{
|
2002-10-06 23:04:47 +04:00
|
|
|
put("FDD");
|
|
|
|
settype(FDLOG);
|
2002-10-25 01:07:56 +04:00
|
|
|
s.floppy_timer_index = BX_NULL_TIMER_HANDLE;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bx_floppy_ctrl_c::~bx_floppy_ctrl_c(void)
|
|
|
|
{
|
2002-10-06 23:04:47 +04:00
|
|
|
// nothing for now
|
|
|
|
BX_DEBUG(("Exit."));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2002-10-25 01:07:56 +04:00
|
|
|
bx_floppy_ctrl_c::init(void)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-07-20 23:53:50 +04:00
|
|
|
Bit8u i;
|
|
|
|
|
2004-02-07 17:34:35 +03:00
|
|
|
BX_DEBUG(("Init $Id: floppy.cc,v 1.70 2004-02-07 14:34:34 vruppert Exp $"));
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_register_8bit_channel(2, dma_read, dma_write, "Floppy Drive");
|
|
|
|
DEV_register_irq(6, "Floppy Drive");
|
2001-04-10 05:04:59 +04:00
|
|
|
for (unsigned addr=0x03F2; addr<=0x03F7; addr++) {
|
2003-07-31 23:51:42 +04:00
|
|
|
DEV_register_ioread_handler(this, read_handler, addr, "Floppy Drive", 1);
|
|
|
|
DEV_register_iowrite_handler(this, write_handler, addr, "Floppy Drive", 1);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, 0x00); /* start out with: no drive 0, no drive 1 */
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
BX_FD_THIS s.num_supported_floppies = 0;
|
|
|
|
|
2002-07-20 23:53:50 +04:00
|
|
|
for (i=0; i<4; i++) {
|
2002-08-04 12:42:34 +04:00
|
|
|
BX_FD_THIS s.device_type[i] = BX_FLOPPY_NONE;
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_FD_THIS s.media[i].type = BX_FLOPPY_NONE;
|
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
|
|
|
// Floppy A setup
|
|
|
|
//
|
|
|
|
BX_FD_THIS s.media[0].sectors_per_track = 0;
|
|
|
|
BX_FD_THIS s.media[0].tracks = 0;
|
|
|
|
BX_FD_THIS s.media[0].heads = 0;
|
|
|
|
BX_FD_THIS s.media[0].sectors = 0;
|
|
|
|
BX_FD_THIS s.media[0].fd = -1;
|
|
|
|
BX_FD_THIS s.media_present[0] = 0;
|
2002-08-04 12:42:34 +04:00
|
|
|
BX_FD_THIS s.device_type[0] = bx_options.floppya.Odevtype->get ();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-08-04 12:42:34 +04:00
|
|
|
switch (BX_FD_THIS s.device_type[0]) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case BX_FLOPPY_NONE:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x00);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2002-08-01 11:37:56 +04:00
|
|
|
case BX_FLOPPY_360K:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x10);
|
2002-08-01 11:37:56 +04:00
|
|
|
break;
|
2001-04-10 05:04:59 +04:00
|
|
|
case BX_FLOPPY_1_2:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x20);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case BX_FLOPPY_720K:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x30);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case BX_FLOPPY_1_44:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x40);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case BX_FLOPPY_2_88:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x50);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2003-02-07 02:16:56 +03:00
|
|
|
|
|
|
|
// use CMOS reserved types
|
|
|
|
case BX_FLOPPY_160K:
|
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x60);
|
|
|
|
BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 6"));
|
|
|
|
break;
|
|
|
|
case BX_FLOPPY_180K:
|
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x70);
|
|
|
|
BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 7"));
|
|
|
|
break;
|
|
|
|
case BX_FLOPPY_320K:
|
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x80);
|
|
|
|
BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 8"));
|
|
|
|
break;
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
default:
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_PANIC(("unknown floppya type"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2004-02-07 17:34:35 +03:00
|
|
|
if (BX_FD_THIS s.device_type[0] != BX_FLOPPY_NONE) {
|
2002-08-04 12:42:34 +04:00
|
|
|
BX_FD_THIS s.num_supported_floppies++;
|
2004-02-07 17:34:35 +03:00
|
|
|
BX_FD_THIS s.statusbar_id[0] = bx_gui->register_statusitem("A:");
|
|
|
|
} else {
|
|
|
|
BX_FD_THIS s.statusbar_id[0] = -1;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-06-20 18:01:39 +04:00
|
|
|
if (bx_options.floppya.Otype->get () != BX_FLOPPY_NONE) {
|
2002-08-04 12:42:34 +04:00
|
|
|
if ( bx_options.floppya.Ostatus->get () == BX_INSERTED) {
|
2001-06-20 18:01:39 +04:00
|
|
|
if (evaluate_media(bx_options.floppya.Otype->get (), bx_options.floppya.Opath->getptr (),
|
2001-04-10 05:04:59 +04:00
|
|
|
& BX_FD_THIS s.media[0]))
|
|
|
|
BX_FD_THIS s.media_present[0] = 1;
|
2002-07-20 23:53:50 +04:00
|
|
|
else
|
2002-11-30 12:39:29 +03:00
|
|
|
bx_options.floppya.Ostatus->set(BX_EJECTED);
|
2001-08-31 20:06:32 +04:00
|
|
|
#define MED (BX_FD_THIS s.media[0])
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
|
|
|
|
MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
|
2001-08-31 20:06:32 +04:00
|
|
|
#undef MED
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Floppy B setup
|
|
|
|
//
|
|
|
|
BX_FD_THIS s.media[1].sectors_per_track = 0;
|
|
|
|
BX_FD_THIS s.media[1].tracks = 0;
|
|
|
|
BX_FD_THIS s.media[1].heads = 0;
|
|
|
|
BX_FD_THIS s.media[1].sectors = 0;
|
|
|
|
BX_FD_THIS s.media[1].fd = -1;
|
|
|
|
BX_FD_THIS s.media_present[1] = 0;
|
2002-08-04 12:42:34 +04:00
|
|
|
BX_FD_THIS s.device_type[1] = bx_options.floppyb.Odevtype->get ();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-08-04 12:42:34 +04:00
|
|
|
switch (BX_FD_THIS s.device_type[1]) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case BX_FLOPPY_NONE:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x00);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2002-08-01 11:37:56 +04:00
|
|
|
case BX_FLOPPY_360K:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x01);
|
2002-08-01 11:37:56 +04:00
|
|
|
break;
|
2001-04-10 05:04:59 +04:00
|
|
|
case BX_FLOPPY_1_2:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x02);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case BX_FLOPPY_720K:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x03);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case BX_FLOPPY_1_44:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x04);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case BX_FLOPPY_2_88:
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x05);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2003-02-07 02:16:56 +03:00
|
|
|
|
|
|
|
// use CMOS reserved types
|
|
|
|
case BX_FLOPPY_160K:
|
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x06);
|
|
|
|
BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 6"));
|
|
|
|
break;
|
|
|
|
case BX_FLOPPY_180K:
|
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x07);
|
|
|
|
BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 7"));
|
|
|
|
break;
|
|
|
|
case BX_FLOPPY_320K:
|
|
|
|
DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x08);
|
|
|
|
BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 8"));
|
|
|
|
break;
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
default:
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("unknown floppyb type"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2004-02-07 17:34:35 +03:00
|
|
|
if (BX_FD_THIS s.device_type[1] != BX_FLOPPY_NONE) {
|
2002-08-04 12:42:34 +04:00
|
|
|
BX_FD_THIS s.num_supported_floppies++;
|
2004-02-07 17:34:35 +03:00
|
|
|
BX_FD_THIS s.statusbar_id[1] = bx_gui->register_statusitem("B:");
|
|
|
|
} else {
|
|
|
|
BX_FD_THIS s.statusbar_id[1] = -1;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-06-20 18:01:39 +04:00
|
|
|
if (bx_options.floppyb.Otype->get () != BX_FLOPPY_NONE) {
|
2002-08-04 12:42:34 +04:00
|
|
|
if ( bx_options.floppyb.Ostatus->get () == BX_INSERTED) {
|
2001-06-20 18:01:39 +04:00
|
|
|
if (evaluate_media(bx_options.floppyb.Otype->get (), bx_options.floppyb.Opath->getptr (),
|
2001-04-10 05:04:59 +04:00
|
|
|
& BX_FD_THIS s.media[1]))
|
|
|
|
BX_FD_THIS s.media_present[1] = 1;
|
2002-07-20 23:53:50 +04:00
|
|
|
else
|
2002-11-30 12:39:29 +03:00
|
|
|
bx_options.floppyb.Ostatus->set(BX_EJECTED);
|
2001-08-31 20:06:32 +04:00
|
|
|
#define MED (BX_FD_THIS s.media[1])
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
|
|
|
|
MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
|
2001-08-31 20:06:32 +04:00
|
|
|
#undef MED
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* CMOS Equipment Byte register */
|
2003-02-07 02:16:56 +03:00
|
|
|
if (BX_FD_THIS s.num_supported_floppies > 0) {
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e) |
|
|
|
|
((BX_FD_THIS s.num_supported_floppies-1) << 6) | 1);
|
2003-02-07 02:16:56 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
2002-10-06 23:04:47 +04:00
|
|
|
if (BX_FD_THIS s.floppy_timer_index == BX_NULL_TIMER_HANDLE) {
|
|
|
|
BX_FD_THIS s.floppy_timer_index =
|
|
|
|
bx_pc_system.register_timer( this, timer_handler,
|
2002-11-30 12:39:29 +03:00
|
|
|
bx_options.Ofloppy_command_delay->get (), 0,0, "floppy");
|
2002-10-06 23:04:47 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("bx_options.Ofloppy_command_delay = %u",
|
2001-06-20 18:01:39 +04:00
|
|
|
(unsigned) bx_options.Ofloppy_command_delay->get ()));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2002-08-27 23:54:46 +04:00
|
|
|
bx_floppy_ctrl_c::reset(unsigned type)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit32u i;
|
|
|
|
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.pending_irq = 0;
|
2002-02-06 21:51:48 +03:00
|
|
|
BX_FD_THIS s.reset_sensei = 0; /* no reset result present */
|
2001-12-27 12:30:31 +03:00
|
|
|
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.main_status_reg = 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.status_reg0 = 0;
|
|
|
|
BX_FD_THIS s.status_reg1 = 0;
|
|
|
|
BX_FD_THIS s.status_reg2 = 0;
|
|
|
|
BX_FD_THIS s.status_reg3 = 0;
|
|
|
|
|
|
|
|
// software reset (via DOR port 0x3f2 bit 2) does not change DOR
|
2002-08-27 23:54:46 +04:00
|
|
|
if (type == BX_RESET_HARDWARE) {
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.DOR = 0x0c;
|
|
|
|
// motor off, drive 3..0
|
|
|
|
// DMA/INT enabled
|
|
|
|
// normal operation
|
|
|
|
// drive select 0
|
|
|
|
|
2002-01-23 23:23:07 +03:00
|
|
|
// DIR and CCR affected only by hard reset
|
2002-08-13 16:02:37 +04:00
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
BX_FD_THIS s.DIR[i] |= 0x80; // disk changed
|
|
|
|
}
|
2002-01-23 23:23:07 +03:00
|
|
|
BX_FD_THIS s.data_rate = 0; /* 500 Kbps */
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
BX_FD_THIS s.cylinder[i] = 0;
|
|
|
|
BX_FD_THIS s.head[i] = 0;
|
|
|
|
BX_FD_THIS s.sector[i] = 0;
|
|
|
|
}
|
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_pic_lower_irq(6);
|
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_idle_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// static IO port read callback handler
|
|
|
|
// redirects to non-static class handler to avoid virtual functions
|
|
|
|
|
|
|
|
Bit32u
|
|
|
|
bx_floppy_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
|
|
|
{
|
|
|
|
#if !BX_USE_FD_SMF
|
|
|
|
bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
|
|
|
|
|
|
|
|
return( class_ptr->read(address, io_len) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* reads from the floppy io ports */
|
|
|
|
Bit32u
|
|
|
|
bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len)
|
|
|
|
{
|
|
|
|
#else
|
|
|
|
UNUSED(this_ptr);
|
|
|
|
#endif // !BX_USE_FD_SMF
|
|
|
|
Bit8u status, value;
|
|
|
|
|
|
|
|
if (bx_dbg.floppy)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("read access to port %04x", (unsigned) address));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
switch (address) {
|
|
|
|
#if BX_DMA_FLOPPY_IO
|
|
|
|
case 0x3F2: // diskette controller digital output register
|
|
|
|
value = BX_FD_THIS s.DOR;
|
|
|
|
return(value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3F4: /* diskette controller main status register */
|
|
|
|
status = BX_FD_THIS s.main_status_reg;
|
|
|
|
return(status);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3F5: /* diskette controller data */
|
|
|
|
if (BX_FD_THIS s.result_size == 0) {
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_ERROR(("port 0x3f5: no results to read"));
|
|
|
|
BX_FD_THIS s.main_status_reg = 0;
|
|
|
|
return BX_FD_THIS s.result[0];
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++];
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.main_status_reg &= 0xF0;
|
2001-04-10 05:04:59 +04:00
|
|
|
if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) {
|
2002-02-06 21:51:48 +03:00
|
|
|
if (!BX_FD_THIS s.reset_sensei) BX_FD_THIS s.pending_irq = 0;
|
2002-11-30 12:39:29 +03:00
|
|
|
DEV_pic_lower_irq(6);
|
|
|
|
enter_idle_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
return(value);
|
|
|
|
break;
|
|
|
|
#endif // #if BX_DMA_FLOPPY_IO
|
|
|
|
|
2002-04-11 06:21:59 +04:00
|
|
|
case 0x3F3: // Tape Drive Register
|
|
|
|
// see http://www.smsc.com/main/datasheets/37c93x.pdf page 18 for more details
|
|
|
|
|
|
|
|
switch( BX_FD_THIS s.DOR & 0x03 )
|
|
|
|
{
|
2002-11-30 12:39:29 +03:00
|
|
|
case 0x00:
|
|
|
|
if( (BX_FD_THIS s.DOR & 0x10) == 0) break;
|
|
|
|
return(2);
|
|
|
|
case 0x01:
|
|
|
|
if( (BX_FD_THIS s.DOR & 0x20) == 0) break;
|
|
|
|
return(1);
|
2002-04-11 06:21:59 +04:00
|
|
|
}
|
|
|
|
return(3);
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0x3F6: // Reserved for future floppy controllers
|
|
|
|
// This address shared with the hard drive controller
|
2002-10-25 01:07:56 +04:00
|
|
|
value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len);
|
2001-04-10 05:04:59 +04:00
|
|
|
return( value );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3F7: // diskette controller digital input register
|
|
|
|
// This address shared with the hard drive controller:
|
|
|
|
// Bit 7 : floppy
|
|
|
|
// Bits 6..0: hard drive
|
2002-10-25 01:07:56 +04:00
|
|
|
value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len);
|
2001-04-10 05:04:59 +04:00
|
|
|
value &= 0x7f;
|
|
|
|
// add in diskette change line
|
2002-08-13 16:02:37 +04:00
|
|
|
value |= (BX_FD_THIS s.DIR[BX_FD_THIS s.DOR & 0x03] & 0x80);
|
2001-04-10 05:04:59 +04:00
|
|
|
return( value );
|
|
|
|
break;
|
2002-01-18 00:20:12 +03:00
|
|
|
default:
|
|
|
|
BX_ERROR(("io_read: unsupported address 0x%04x", (unsigned) address));
|
|
|
|
return(0);
|
|
|
|
break;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// static IO port write callback handler
|
|
|
|
// redirects to non-static class handler to avoid virtual functions
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
|
|
|
{
|
|
|
|
#if !BX_USE_FD_SMF
|
|
|
|
bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
|
|
|
|
|
|
|
|
class_ptr->write(address, value, io_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* writes to the floppy io ports */
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
|
|
|
{
|
|
|
|
#else
|
|
|
|
UNUSED(this_ptr);
|
|
|
|
#endif // !BX_USE_FD_SMF
|
|
|
|
Bit8u dma_and_interrupt_enable;
|
|
|
|
Bit8u normal_operation, prev_normal_operation;
|
|
|
|
Bit8u drive_select;
|
|
|
|
Bit8u motor_on_drive0, motor_on_drive1;
|
|
|
|
|
|
|
|
if (bx_dbg.floppy)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("write access to port %04x, value=%02x",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) address, (unsigned) value));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
switch (address) {
|
|
|
|
#if BX_DMA_FLOPPY_IO
|
|
|
|
case 0x3F2: /* diskette controller digital output register */
|
|
|
|
motor_on_drive1 = value & 0x20;
|
|
|
|
motor_on_drive0 = value & 0x10;
|
2004-02-07 17:34:35 +03:00
|
|
|
/* set status bar conditions for Floppy 0 and Floppy 1 */
|
|
|
|
if (BX_FD_THIS s.statusbar_id[0] >= 0)
|
|
|
|
bx_gui->statusbar_setitem(BX_FD_THIS s.statusbar_id[0], motor_on_drive0);
|
|
|
|
if (BX_FD_THIS s.statusbar_id[1] >= 0)
|
|
|
|
bx_gui->statusbar_setitem(BX_FD_THIS s.statusbar_id[1], motor_on_drive1);
|
2001-04-10 05:04:59 +04:00
|
|
|
dma_and_interrupt_enable = value & 0x08;
|
|
|
|
if (!dma_and_interrupt_enable)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(("DMA and interrupt capabilities disabled"));
|
2001-04-10 05:04:59 +04:00
|
|
|
normal_operation = value & 0x04;
|
|
|
|
drive_select = value & 0x03;
|
|
|
|
|
|
|
|
prev_normal_operation = BX_FD_THIS s.DOR & 0x04;
|
|
|
|
BX_FD_THIS s.DOR = value;
|
|
|
|
|
|
|
|
if (prev_normal_operation==0 && normal_operation) {
|
|
|
|
// transition from RESET to NORMAL
|
|
|
|
bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
|
2001-06-20 18:01:39 +04:00
|
|
|
bx_options.Ofloppy_command_delay->get (), 0 );
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
else if (prev_normal_operation && normal_operation==0) {
|
|
|
|
// transition from NORMAL to RESET
|
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
|
|
|
|
BX_FD_THIS s.pending_command = 0xfe; // RESET pending
|
|
|
|
|
|
|
|
}
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("io_write: digital output register"));
|
|
|
|
BX_DEBUG((" motor on, drive1 = %d", motor_on_drive1 > 0));
|
|
|
|
BX_DEBUG((" motor on, drive0 = %d", motor_on_drive0 > 0));
|
|
|
|
BX_DEBUG((" dma_and_interrupt_enable=%02x",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) dma_and_interrupt_enable));
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG((" normal_operation=%02x",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) normal_operation));
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG((" drive_select=%02x",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) drive_select));
|
2002-08-04 12:42:34 +04:00
|
|
|
if (BX_FD_THIS s.device_type[drive_select] == BX_FLOPPY_NONE) {
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_DEBUG(("WARNING: not existing drive selected"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3f4: /* diskette controller data rate select register */
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_ERROR(("io_write: data rate select register unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3F5: /* diskette controller data */
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("command = %02x", (unsigned) value));
|
2001-04-10 05:04:59 +04:00
|
|
|
if (BX_FD_THIS s.command_complete) {
|
|
|
|
if (BX_FD_THIS s.pending_command!=0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("io: 3f5: receiving new comm, old one (%02x) pending",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) BX_FD_THIS s.pending_command));
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.command[0] = value;
|
|
|
|
BX_FD_THIS s.command_complete = 0;
|
|
|
|
BX_FD_THIS s.command_index = 1;
|
|
|
|
/* read/write command in progress */
|
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_BUSY;
|
|
|
|
switch (value) {
|
|
|
|
case 0x03: /* specify */
|
|
|
|
BX_FD_THIS s.command_size = 3;
|
|
|
|
break;
|
|
|
|
case 0x04: // get status
|
|
|
|
BX_FD_THIS s.command_size = 2;
|
|
|
|
break;
|
|
|
|
case 0x07: /* recalibrate */
|
|
|
|
BX_FD_THIS s.command_size = 2;
|
|
|
|
break;
|
|
|
|
case 0x08: /* sense interrupt status */
|
|
|
|
BX_FD_THIS s.command_size = 1;
|
|
|
|
break;
|
|
|
|
case 0x0f: /* seek */
|
|
|
|
BX_FD_THIS s.command_size = 3;
|
|
|
|
break;
|
|
|
|
case 0x4a: /* read ID */
|
|
|
|
BX_FD_THIS s.command_size = 2;
|
|
|
|
break;
|
2001-12-28 19:38:13 +03:00
|
|
|
case 0x4d: /* format track */
|
|
|
|
BX_FD_THIS s.command_size = 6;
|
|
|
|
break;
|
|
|
|
case 0x45:
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0xc5: /* write normal data */
|
|
|
|
BX_FD_THIS s.command_size = 9;
|
|
|
|
break;
|
2002-07-16 00:11:33 +04:00
|
|
|
case 0x46:
|
2001-12-28 19:38:13 +03:00
|
|
|
case 0x66:
|
2002-07-16 00:11:33 +04:00
|
|
|
case 0xc6:
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0xe6: /* read normal data */
|
|
|
|
BX_FD_THIS s.command_size = 9;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x13: // Configure command (Enhanced)
|
2002-01-18 00:20:12 +03:00
|
|
|
BX_FD_THIS s.command_size = 4;
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0e: // dump registers (Enhanced drives)
|
|
|
|
case 0x10: // Version command, standard controller returns 80h
|
|
|
|
case 0x18: // National Semiconductor version command; return 80h
|
|
|
|
// These commands are not implemented on the standard
|
|
|
|
// controller and return an error. They are available on
|
|
|
|
// the enhanced controller.
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_DEBUG(("io_write: 0x3f5: unsupported floppy command 0x%02x",
|
|
|
|
(unsigned) value));
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) value));
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_FD_THIS s.command[BX_FD_THIS s.command_index++] =
|
|
|
|
value;
|
2001-12-27 12:30:31 +03:00
|
|
|
}
|
|
|
|
if (BX_FD_THIS s.command_index ==
|
|
|
|
BX_FD_THIS s.command_size) {
|
|
|
|
/* read/write command not in progress any more */
|
|
|
|
floppy_command();
|
|
|
|
BX_FD_THIS s.command_complete = 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("io_write: diskette controller data"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
#endif // #if BX_DMA_FLOPPY_IO
|
|
|
|
|
|
|
|
case 0x3F6: /* diskette controller (reserved) */
|
2002-10-21 20:57:35 +04:00
|
|
|
BX_DEBUG(("io_write: reserved register 0x3f6 unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
// this address shared with the hard drive controller
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_hd_write_handler(bx_devices.pluginHardDrive, address, value, io_len);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
#if BX_DMA_FLOPPY_IO
|
|
|
|
case 0x3F7: /* diskette controller configuration control register */
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("io_write: config control register"));
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.data_rate = value & 0x03;
|
2001-08-31 20:06:32 +04:00
|
|
|
switch (BX_FD_THIS s.data_rate) {
|
|
|
|
case 0: BX_DEBUG((" 500 Kbps")); break;
|
|
|
|
case 1: BX_DEBUG((" 300 Kbps")); break;
|
|
|
|
case 2: BX_DEBUG((" 250 Kbps")); break;
|
|
|
|
case 3: BX_DEBUG((" 1 Mbps")); break;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2002-10-06 23:38:54 +04:00
|
|
|
BX_ERROR(("io_write ignored: 0x%04x = 0x%02x", (unsigned) address, (unsigned) value));
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
#endif // #if BX_DMA_FLOPPY_IO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::floppy_command(void)
|
|
|
|
{
|
|
|
|
#if BX_PROVIDE_CPU_MEMORY==0
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
BX_PANIC(("floppy_command(): uses DMA: not supported for"
|
2001-05-30 22:56:02 +04:00
|
|
|
" external environment"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
unsigned i;
|
|
|
|
Bit8u step_rate_time;
|
|
|
|
Bit8u head_unload_time;
|
|
|
|
Bit8u head_load_time;
|
|
|
|
Bit8u motor_on;
|
|
|
|
Bit8u head, drive, cylinder, sector, eot;
|
|
|
|
Bit8u sector_size, data_length;
|
|
|
|
Bit32u logical_sector;
|
|
|
|
|
|
|
|
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("FLOPPY COMMAND: "));
|
|
|
|
for (i=0; i<BX_FD_THIS s.command_size; i++)
|
|
|
|
BX_DEBUG(("[%02x] ", (unsigned) BX_FD_THIS s.command[i]));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* execute phase of command is in progress (non DMA mode) */
|
|
|
|
BX_FD_THIS s.main_status_reg |= 20;
|
|
|
|
#endif
|
|
|
|
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
|
|
|
|
switch (BX_FD_THIS s.pending_command) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0x03: // specify
|
|
|
|
// execution: specified parameters are loaded
|
|
|
|
// result: no result bytes, no interrupt
|
|
|
|
step_rate_time = BX_FD_THIS s.command[1] >> 4;
|
|
|
|
head_unload_time = BX_FD_THIS s.command[1] & 0x0f;
|
|
|
|
head_load_time = BX_FD_THIS s.command[2] >> 1;
|
2001-12-27 12:30:31 +03:00
|
|
|
if (BX_FD_THIS s.command[2] & 0x01)
|
|
|
|
BX_ERROR(("non DMA mode selected"));
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_idle_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x04: // get status
|
2001-06-13 11:06:10 +04:00
|
|
|
drive = (BX_FD_THIS s.command[1] & 0x03);
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg3 = 0x28 | (BX_FD_THIS s.head[drive]<<2) | drive
|
2001-12-28 19:38:13 +03:00
|
|
|
| (BX_FD_THIS s.media[drive].write_protected ? 0x40 : 0x00);
|
2002-11-30 12:39:29 +03:00
|
|
|
if (BX_FD_THIS s.cylinder[drive] == 0) BX_FD_THIS s.status_reg3 |= 0x10;
|
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x07: // recalibrate
|
|
|
|
drive = (BX_FD_THIS s.command[1] & 0x03);
|
|
|
|
BX_FD_THIS s.DOR &= 0xfc;
|
|
|
|
BX_FD_THIS s.DOR |= drive;
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("floppy_command(): recalibrate drive %u",
|
|
|
|
(unsigned) drive));
|
2001-04-10 05:04:59 +04:00
|
|
|
motor_on = ( (BX_FD_THIS s.DOR>>(drive+4))
|
|
|
|
& 0x01 );
|
|
|
|
if (motor_on == 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("floppy_command(): recal drive with motor off"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
if (drive==0)
|
|
|
|
BX_FD_THIS s.DOR |= 0x10; // turn on MOTA
|
|
|
|
else
|
|
|
|
BX_FD_THIS s.DOR |= 0x20; // turn on MOTB
|
|
|
|
bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
|
2001-06-20 18:01:39 +04:00
|
|
|
bx_options.Ofloppy_command_delay->get (), 0 );
|
2001-04-10 05:04:59 +04:00
|
|
|
/* command head to track 0
|
|
|
|
* controller set to non-busy
|
|
|
|
* error condition noted in Status reg 0's equipment check bit
|
|
|
|
* seek end bit set to 1 in Status reg 0 regardless of outcome
|
2002-11-30 12:39:29 +03:00
|
|
|
* The last two are taken care of in timer().
|
2001-04-10 05:04:59 +04:00
|
|
|
*/
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.cylinder[drive] = 0;
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_FD_THIS s.main_status_reg = (1 << drive);
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08: /* sense interrupt status */
|
|
|
|
/* execution:
|
|
|
|
* get status
|
|
|
|
* result:
|
|
|
|
* no interupt
|
|
|
|
* byte0 = status reg0
|
|
|
|
* byte1 = current cylinder number (0 to 79)
|
|
|
|
*/
|
|
|
|
drive = BX_FD_THIS s.DOR & 0x03;
|
2002-01-23 23:23:07 +03:00
|
|
|
if (!BX_FD_THIS s.pending_irq) {
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x80;
|
2002-02-06 21:51:48 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (BX_FD_THIS s.reset_sensei > 0) {
|
|
|
|
drive = 4 - BX_FD_THIS s.reset_sensei;
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_FD_THIS s.status_reg0 &= 0xf8;
|
2002-07-16 23:36:40 +04:00
|
|
|
BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2) | drive;
|
2002-02-06 21:51:48 +03:00
|
|
|
BX_FD_THIS s.reset_sensei--;
|
2002-11-30 12:39:29 +03:00
|
|
|
}
|
2001-12-27 12:30:31 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("sense interrupt status"));
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0f: /* seek */
|
|
|
|
/* command:
|
|
|
|
* byte0 = 0F
|
|
|
|
* byte1 = drive & head select
|
|
|
|
* byte2 = cylinder number
|
|
|
|
* execution:
|
|
|
|
* postion head over specified cylinder
|
|
|
|
* result:
|
|
|
|
* no result bytes, issues an interrupt
|
|
|
|
*/
|
|
|
|
drive = BX_FD_THIS s.command[1] & 0x03;
|
|
|
|
BX_FD_THIS s.DOR &= 0xfc;
|
|
|
|
BX_FD_THIS s.DOR |= drive;
|
|
|
|
|
|
|
|
BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
|
|
|
|
BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.command[2];
|
|
|
|
/* ??? should also check cylinder validity */
|
|
|
|
bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
|
2001-06-20 18:01:39 +04:00
|
|
|
bx_options.Ofloppy_command_delay->get (), 0 );
|
2002-07-20 23:53:50 +04:00
|
|
|
/* data reg not ready, drive busy */
|
|
|
|
BX_FD_THIS s.main_status_reg = (1 << drive);
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x13: // Configure
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_DEBUG(("configure (eis = 0x%02x)", BX_FD_THIS s.command[2] & 0x40 ));
|
|
|
|
BX_DEBUG(("configure (efifo = 0x%02x)", BX_FD_THIS s.command[2] & 0x20 ));
|
|
|
|
BX_DEBUG(("configure (no poll = 0x%02x)", BX_FD_THIS s.command[2] & 0x10 ));
|
|
|
|
BX_DEBUG(("configure (fifothr = 0x%02x)", BX_FD_THIS s.command[2] & 0x0f ));
|
|
|
|
BX_DEBUG(("configure (pretrk = 0x%02x)", BX_FD_THIS s.command[3] ));
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_idle_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x4a: // read ID
|
|
|
|
drive = BX_FD_THIS s.command[1] & 0x03;
|
2002-07-16 23:36:40 +04:00
|
|
|
BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.DOR &= 0xfc;
|
|
|
|
BX_FD_THIS s.DOR |= drive;
|
|
|
|
|
|
|
|
motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
|
2001-12-27 12:30:31 +03:00
|
|
|
if (motor_on == 0) {
|
|
|
|
BX_ERROR(("floppy_command(): 0x4a: motor not on"));
|
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
|
|
|
|
return;
|
|
|
|
}
|
2002-08-04 12:42:34 +04:00
|
|
|
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_PANIC(("floppy_command(): read ID: bad drive #%d", drive));
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive;
|
2001-04-10 05:04:59 +04:00
|
|
|
bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
|
2001-06-20 18:01:39 +04:00
|
|
|
bx_options.Ofloppy_command_delay->get (), 0 );
|
2001-04-10 05:04:59 +04:00
|
|
|
/* data reg not ready, controller busy */
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
2001-12-28 19:38:13 +03:00
|
|
|
case 0x4d: // format track
|
|
|
|
drive = BX_FD_THIS s.command[1] & 0x03;
|
|
|
|
BX_FD_THIS s.DOR &= 0xfc;
|
|
|
|
BX_FD_THIS s.DOR |= drive;
|
|
|
|
|
|
|
|
motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
|
|
|
|
if (motor_on == 0)
|
|
|
|
BX_PANIC(("floppy_command(): format track: motor not on"));
|
|
|
|
BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
|
|
|
|
sector_size = BX_FD_THIS s.command[2];
|
|
|
|
BX_FD_THIS s.format_count = BX_FD_THIS s.command[3];
|
|
|
|
BX_FD_THIS s.format_fillbyte = BX_FD_THIS s.command[5];
|
2002-08-04 12:42:34 +04:00
|
|
|
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_PANIC(("floppy_command(): format track: bad drive #%d", drive));
|
2001-12-28 19:38:13 +03:00
|
|
|
|
|
|
|
if (sector_size != 0x02) { // 512 bytes
|
2003-06-20 20:28:00 +04:00
|
|
|
BX_PANIC(("format track: sector size %d not supported", 128<<sector_size));
|
2001-12-28 19:38:13 +03:00
|
|
|
}
|
|
|
|
if (BX_FD_THIS s.format_count != BX_FD_THIS s.media[drive].sectors_per_track) {
|
2003-06-20 20:28:00 +04:00
|
|
|
BX_PANIC(("format track: %d sectors/track requested (%d expected)",
|
|
|
|
BX_FD_THIS s.format_count, BX_FD_THIS s.media[drive].sectors_per_track));
|
2001-12-28 19:38:13 +03:00
|
|
|
}
|
|
|
|
if ( BX_FD_THIS s.media_present[drive] == 0 ) {
|
|
|
|
// media not in drive, return error
|
|
|
|
BX_INFO(("attempt to format track with media not present"));
|
|
|
|
BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
|
|
|
|
BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
|
|
|
|
enter_result_phase();
|
2001-12-28 19:38:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (BX_FD_THIS s.media[drive].write_protected) {
|
|
|
|
// media write-protected, return error
|
|
|
|
BX_INFO(("attempt to format track with media write-protected"));
|
|
|
|
BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
|
|
|
|
BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
|
|
|
|
enter_result_phase();
|
2001-12-28 19:38:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 4 header bytes per sector are required */
|
|
|
|
BX_FD_THIS s.format_count <<= 2;
|
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
|
2001-12-28 19:38:13 +03:00
|
|
|
|
|
|
|
/* data reg not ready, controller busy */
|
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
|
|
|
|
BX_DEBUG(("format track"));
|
|
|
|
return;
|
|
|
|
break;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-07-16 00:11:33 +04:00
|
|
|
case 0x46: // read normal data, MT=0, SK=0
|
|
|
|
case 0x66: // read normal data, MT=0, SK=1
|
|
|
|
case 0xc6: // read normal data, MT=1, SK=0
|
|
|
|
case 0xe6: // read normal data, MT=1, SK=1
|
2001-12-28 19:38:13 +03:00
|
|
|
case 0x45: // write normal data, MT=0
|
|
|
|
case 0xc5: // write normal data, MT=1
|
|
|
|
BX_FD_THIS s.multi_track = (BX_FD_THIS s.command[0] >> 7);
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( (BX_FD_THIS s.DOR & 0x08) == 0 )
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("read/write command with DMA and int disabled"));
|
2001-04-10 05:04:59 +04:00
|
|
|
drive = BX_FD_THIS s.command[1] & 0x03;
|
|
|
|
BX_FD_THIS s.DOR &= 0xfc;
|
|
|
|
BX_FD_THIS s.DOR |= drive;
|
|
|
|
|
|
|
|
motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
|
|
|
|
if (motor_on == 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("floppy_command(): read/write: motor not on"));
|
2001-04-10 05:04:59 +04:00
|
|
|
head = BX_FD_THIS s.command[3] & 0x01;
|
|
|
|
cylinder = BX_FD_THIS s.command[2]; /* 0..79 depending */
|
|
|
|
sector = BX_FD_THIS s.command[4]; /* 1..36 depending */
|
|
|
|
eot = BX_FD_THIS s.command[6]; /* 1..36 depending */
|
|
|
|
sector_size = BX_FD_THIS s.command[5];
|
|
|
|
data_length = BX_FD_THIS s.command[8];
|
2001-08-31 20:06:32 +04:00
|
|
|
BX_DEBUG(("read/write normal data"));
|
|
|
|
BX_DEBUG(("BEFORE"));
|
|
|
|
BX_DEBUG((" drive = %u", (unsigned) drive));
|
|
|
|
BX_DEBUG((" head = %u", (unsigned) head));
|
|
|
|
BX_DEBUG((" cylinder = %u", (unsigned) cylinder));
|
|
|
|
BX_DEBUG((" sector = %u", (unsigned) sector));
|
|
|
|
BX_DEBUG((" eot = %u", (unsigned) eot));
|
2002-08-04 12:42:34 +04:00
|
|
|
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_PANIC(("floppy_command(): read/write: bad drive #%d", drive));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-09-29 07:29:27 +04:00
|
|
|
// check that head number in command[1] bit two matches the head
|
|
|
|
// reported in the head number field. Real floppy drives are
|
2001-12-28 19:38:13 +03:00
|
|
|
// picky about this, as reported in SF bug #439945, (Floppy drive
|
2001-09-29 07:29:27 +04:00
|
|
|
// read input error checking).
|
2002-06-23 22:04:07 +04:00
|
|
|
if (head != ((BX_FD_THIS s.command[1]>>2)&1)) {
|
2001-09-29 07:29:27 +04:00
|
|
|
BX_ERROR(("head number in command[1] doesn't match head field"));
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0x04; // 0000 0100
|
|
|
|
BX_FD_THIS s.status_reg2 = 0x00; // 0000 0000
|
|
|
|
enter_result_phase();
|
2001-09-29 07:29:27 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( BX_FD_THIS s.media_present[drive] == 0 ) {
|
|
|
|
// media not in drive, return error
|
|
|
|
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
BX_INFO(("attempt to read/write sector %u,"
|
2002-12-11 18:45:10 +03:00
|
|
|
" sectors/track=%u with media not present",
|
2003-02-07 02:16:56 +03:00
|
|
|
(unsigned) sector,
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
|
2002-07-26 20:39:18 +04:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
|
|
|
|
BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
|
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sector_size != 0x02) { // 512 bytes
|
2003-06-20 20:28:00 +04:00
|
|
|
BX_PANIC(("read/write command: sector size %d not supported", 128<<sector_size));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
if ( cylinder >= BX_FD_THIS s.media[drive].tracks ) {
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_PANIC(("io: norm r/w parms out of range: sec#%02xh cyl#%02xh eot#%02xh head#%02xh",
|
|
|
|
(unsigned) sector, (unsigned) cylinder, (unsigned) eot,
|
|
|
|
(unsigned) head));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2001-08-31 20:06:32 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (sector > BX_FD_THIS s.media[drive].sectors_per_track) {
|
|
|
|
// requested sector > last sector on track
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
BX_INFO(("attempt to read/write sector %u,"
|
2001-05-30 22:56:02 +04:00
|
|
|
" sectors/track=%u", (unsigned) sector,
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
|
2001-04-10 05:04:59 +04:00
|
|
|
// set controller to where drive would have left off
|
|
|
|
// after it discovered the sector was past EOT
|
|
|
|
BX_FD_THIS s.cylinder[drive] = cylinder;
|
|
|
|
BX_FD_THIS s.head[drive] = head;
|
|
|
|
BX_FD_THIS s.sector[drive] = BX_FD_THIS s.media[drive].sectors_per_track;
|
|
|
|
|
|
|
|
// 0100 0HDD abnormal termination
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
|
2001-04-10 05:04:59 +04:00
|
|
|
// 1000 0101 end of cyl/NDAT/NID
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0x85;
|
2001-04-10 05:04:59 +04:00
|
|
|
// 0000 0000
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg2 = 0x00;
|
2002-12-11 18:41:24 +03:00
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cylinder != BX_FD_THIS s.cylinder[drive])
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(("io: cylinder request != current cylinder"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-02-07 02:16:56 +03:00
|
|
|
// original assumed all floppies had two sides...now it does not *delete this comment line*
|
|
|
|
logical_sector = (cylinder * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
|
2001-04-10 05:04:59 +04:00
|
|
|
(head * BX_FD_THIS s.media[drive].sectors_per_track) +
|
|
|
|
(sector - 1);
|
|
|
|
|
|
|
|
if (logical_sector >= BX_FD_THIS s.media[drive].sectors) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("io: logical sector out of bounds"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
BX_FD_THIS s.cylinder[drive] = cylinder;
|
|
|
|
BX_FD_THIS s.sector[drive] = sector;
|
|
|
|
BX_FD_THIS s.head[drive] = head;
|
|
|
|
|
2002-07-16 00:11:33 +04:00
|
|
|
if ((BX_FD_THIS s.command[0] & 0x4f) == 0x46) { // read
|
2001-04-10 05:04:59 +04:00
|
|
|
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
|
|
|
|
512, FROM_FLOPPY);
|
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* data reg not ready, controller busy */
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
2001-12-28 19:38:13 +03:00
|
|
|
else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* data reg not ready, controller busy */
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("floppy_command(): unknown read/write command"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
2002-11-30 12:39:29 +03:00
|
|
|
default: // invalid or unsupported command; these are captured in write() above
|
|
|
|
BX_PANIC(("You should never get here! cmd = 0x%02x",
|
|
|
|
BX_FD_THIS s.command[0]));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2001-06-13 11:08:04 +04:00
|
|
|
void
|
2001-04-10 05:04:59 +04:00
|
|
|
bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer,
|
|
|
|
Bit32u bytes, Bit8u direction)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2002-08-04 12:42:34 +04:00
|
|
|
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_PANIC(("floppy_xfer: bad drive #%d", drive));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (bx_dbg.floppy) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("drive=%u", (unsigned) drive));
|
|
|
|
BX_INFO(("offset=%u", (unsigned) offset));
|
|
|
|
BX_INFO(("bytes=%u", (unsigned) bytes));
|
|
|
|
BX_INFO(("direction=%s", (direction==FROM_FLOPPY)? "from" : "to"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2001-09-26 04:19:44 +04:00
|
|
|
#if BX_WITH_MACOS
|
2001-06-20 18:01:39 +04:00
|
|
|
if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ret = lseek(BX_FD_THIS s.media[drive].fd, offset, SEEK_SET);
|
|
|
|
if (ret < 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("could not perform lseek() on floppy image file"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (direction == FROM_FLOPPY) {
|
2001-09-26 04:19:44 +04:00
|
|
|
#if BX_WITH_MACOS
|
2001-06-20 18:01:39 +04:00
|
|
|
if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
|
2001-04-10 05:04:59 +04:00
|
|
|
ret = fd_read((char *) buffer, offset, bytes);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
ret = ::read(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
|
|
|
|
if (ret < int(bytes)) {
|
|
|
|
/* ??? */
|
|
|
|
if (ret > 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("partial read() on floppy image returns %u/%u",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) ret, (unsigned) bytes));
|
2001-04-10 05:04:59 +04:00
|
|
|
memset(buffer + ret, 0, bytes - ret);
|
|
|
|
}
|
|
|
|
else {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("read() on floppy image returns 0"));
|
2001-04-10 05:04:59 +04:00
|
|
|
memset(buffer, 0, bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else { // TO_FLOPPY
|
2001-06-13 11:06:10 +04:00
|
|
|
BX_ASSERT (!BX_FD_THIS s.media[drive].write_protected);
|
2001-09-26 21:35:51 +04:00
|
|
|
#if BX_WITH_MACOS
|
2001-06-20 18:01:39 +04:00
|
|
|
if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
|
2001-04-10 05:04:59 +04:00
|
|
|
ret = fd_write((char *) buffer, offset, bytes);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
ret = ::write(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
|
|
|
|
if (ret < int(bytes)) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("could not perform write() on floppy image file"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2001-06-13 04:30:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::timer_handler(void *this_ptr)
|
|
|
|
{
|
|
|
|
|
|
|
|
bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
|
|
|
|
|
|
|
|
class_ptr->timer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::timer()
|
|
|
|
{
|
2001-12-27 12:30:31 +03:00
|
|
|
Bit8u drive;
|
|
|
|
|
|
|
|
drive = BX_FD_THIS s.DOR & 0x03;
|
2001-04-10 05:04:59 +04:00
|
|
|
switch ( BX_FD_THIS s.pending_command ) {
|
|
|
|
case 0x07: // recal
|
|
|
|
case 0x0f: // seek
|
2002-07-16 23:36:40 +04:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive]<<2) | drive;
|
2002-08-04 12:42:34 +04:00
|
|
|
if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE) {
|
2002-07-20 23:53:50 +04:00
|
|
|
BX_FD_THIS s.status_reg0 |= 0x50;
|
|
|
|
}
|
|
|
|
else if (BX_FD_THIS s.media_present[drive] == 0) {
|
|
|
|
BX_FD_THIS s.status_reg0 |= 0x40;
|
|
|
|
BX_FD_THIS s.status_reg1 = 0x25;
|
|
|
|
BX_FD_THIS s.status_reg2 = 0x31;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-11-30 12:39:29 +03:00
|
|
|
/* reset changeline */
|
|
|
|
if (drive > 1) return;
|
|
|
|
if (BX_FD_THIS s.media_present[drive])
|
|
|
|
BX_FD_THIS s.DIR[drive] &= ~0x80; // clear disk change line
|
|
|
|
|
|
|
|
enter_idle_phase();
|
2002-02-06 21:51:48 +03:00
|
|
|
raise_interrupt();
|
2001-12-27 12:30:31 +03:00
|
|
|
break;
|
|
|
|
|
2002-11-30 12:39:29 +03:00
|
|
|
case 0x4a: /* read ID */
|
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xfe: // (contrived) RESET
|
2002-10-25 01:07:56 +04:00
|
|
|
theFloppyController->reset(BX_RESET_SOFTWARE);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.pending_command = 0;
|
2001-12-27 12:30:31 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0xc0;
|
2002-02-06 21:51:48 +03:00
|
|
|
raise_interrupt();
|
|
|
|
BX_FD_THIS s.reset_sensei = 4;
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2002-02-27 21:16:30 +03:00
|
|
|
|
|
|
|
case 0x00: // nothing pending?
|
|
|
|
break;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
default:
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("floppy:timer(): unknown case %02x",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(unsigned) BX_FD_THIS s.pending_command));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
|
|
|
|
{
|
|
|
|
// A DMA write is from I/O to Memory
|
|
|
|
// We need to return then next data byte from the floppy buffer
|
|
|
|
// to be transfered via the DMA to memory. (read block from floppy)
|
|
|
|
|
|
|
|
|
|
|
|
*data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
|
|
|
|
|
|
|
|
if (BX_FD_THIS s.floppy_buffer_index >= 512) {
|
|
|
|
Bit8u drive;
|
|
|
|
|
|
|
|
drive = BX_FD_THIS s.DOR & 0x03;
|
|
|
|
increment_sector(); // increment to next sector before retrieving next one
|
|
|
|
BX_FD_THIS s.floppy_buffer_index = 0;
|
2002-10-25 01:07:56 +04:00
|
|
|
if (DEV_dma_get_tc()) { // Terminal Count line, done
|
2002-07-26 20:39:18 +04:00
|
|
|
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0;
|
|
|
|
BX_FD_THIS s.status_reg2 = 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (bx_dbg.floppy) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("<<READ DONE>>"));
|
|
|
|
BX_INFO(("AFTER"));
|
|
|
|
BX_INFO((" drive = %u", (unsigned) drive));
|
|
|
|
BX_INFO((" head = %u", (unsigned) BX_FD_THIS s.head[drive]));
|
|
|
|
BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
|
|
|
|
BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
else { // more data to transfer
|
|
|
|
Bit32u logical_sector;
|
2003-02-07 02:16:56 +03:00
|
|
|
|
|
|
|
// original assumed all floppies had two sides...now it does not *delete this comment line*
|
|
|
|
logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads *
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.media[drive].sectors_per_track) +
|
|
|
|
(BX_FD_THIS s.head[drive] *
|
|
|
|
BX_FD_THIS s.media[drive].sectors_per_track) +
|
|
|
|
(BX_FD_THIS s.sector[drive] - 1);
|
2003-02-07 02:16:56 +03:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
|
|
|
|
512, FROM_FLOPPY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
|
|
|
|
{
|
|
|
|
// A DMA read is from Memory to I/O
|
|
|
|
// We need to write the data_byte which was already transfered from memory
|
|
|
|
// via DMA to I/O (write block to floppy)
|
|
|
|
|
|
|
|
Bit8u drive;
|
|
|
|
Bit32u logical_sector;
|
|
|
|
|
2001-12-28 19:38:13 +03:00
|
|
|
drive = BX_FD_THIS s.DOR & 0x03;
|
|
|
|
if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
|
|
|
|
--BX_FD_THIS s.format_count;
|
|
|
|
switch (3 - (BX_FD_THIS s.format_count & 0x03)) {
|
|
|
|
case 0:
|
|
|
|
BX_FD_THIS s.cylinder[drive] = *data_byte;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (*data_byte != BX_FD_THIS s.head[drive])
|
|
|
|
BX_ERROR(("head number does not match head field"));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
BX_FD_THIS s.sector[drive] = *data_byte;
|
|
|
|
break;
|
|
|
|
case 3:
|
2003-06-20 20:28:00 +04:00
|
|
|
if (*data_byte != 2) BX_ERROR(("dma_read: sector size %d not supported", 128<<(*data_byte)));
|
2001-12-28 19:38:13 +03:00
|
|
|
BX_DEBUG(("formatting cylinder %u head %u sector %u",
|
|
|
|
BX_FD_THIS s.cylinder[drive], BX_FD_THIS s.head[drive],
|
|
|
|
BX_FD_THIS s.sector[drive]));
|
|
|
|
for (unsigned i = 0; i < 512; i++) {
|
|
|
|
BX_FD_THIS s.floppy_buffer[i] = BX_FD_THIS s.format_fillbyte;
|
|
|
|
}
|
2003-02-07 02:16:56 +03:00
|
|
|
// original assumed all floppies had two sides...now it does not *delete this comment line*
|
|
|
|
logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
|
2001-12-28 19:38:13 +03:00
|
|
|
(BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
|
|
|
|
(BX_FD_THIS s.sector[drive] - 1);
|
|
|
|
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
|
|
|
|
512, TO_FLOPPY);
|
|
|
|
break;
|
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
if ((BX_FD_THIS s.format_count == 0) || (DEV_dma_get_tc())) {
|
2001-12-28 19:38:13 +03:00
|
|
|
BX_FD_THIS s.format_count = 0;
|
|
|
|
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_result_phase();
|
2001-12-28 19:38:13 +03:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
|
|
|
|
|
|
|
|
if (BX_FD_THIS s.floppy_buffer_index >= 512) {
|
2003-02-07 02:16:56 +03:00
|
|
|
// original assumed all floppies had two sides...now it does not *delete this comment line*
|
|
|
|
logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
|
2001-04-10 05:04:59 +04:00
|
|
|
(BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
|
|
|
|
(BX_FD_THIS s.sector[drive] - 1);
|
2001-06-13 11:06:10 +04:00
|
|
|
if ( BX_FD_THIS s.media[drive].write_protected ) {
|
|
|
|
// write protected error
|
|
|
|
BX_INFO(("tried to write disk %u, which is write-protected", drive));
|
|
|
|
// ST0: IC1,0=01 (abnormal termination: started execution but failed)
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
|
2001-06-13 11:06:10 +04:00
|
|
|
// ST1: DataError=1, NDAT=1, NotWritable=1, NID=1
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
|
2001-06-13 11:06:10 +04:00
|
|
|
// ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
|
|
|
|
enter_result_phase();
|
2001-06-13 11:06:10 +04:00
|
|
|
return;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
|
|
|
|
512, TO_FLOPPY);
|
|
|
|
increment_sector(); // increment to next sector after writing current one
|
|
|
|
BX_FD_THIS s.floppy_buffer_index = 0;
|
2002-10-25 01:07:56 +04:00
|
|
|
if (DEV_dma_get_tc()) { // Terminal Count line, done
|
2002-07-26 20:39:18 +04:00
|
|
|
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
|
2002-11-30 12:39:29 +03:00
|
|
|
BX_FD_THIS s.status_reg1 = 0;
|
|
|
|
BX_FD_THIS s.status_reg2 = 0;
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
if (bx_dbg.floppy) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("<<WRITE DONE>>"));
|
|
|
|
BX_INFO(("AFTER"));
|
|
|
|
BX_INFO((" drive = %u", (unsigned) drive));
|
|
|
|
BX_INFO((" head = %u", (unsigned) BX_FD_THIS s.head[drive]));
|
|
|
|
BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
|
|
|
|
BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
|
2002-11-30 12:39:29 +03:00
|
|
|
enter_result_phase();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
else { // more data to transfer
|
|
|
|
} // else
|
|
|
|
} // if BX_FD_THIS s.floppy_buffer_index >= 512
|
|
|
|
}
|
|
|
|
|
2002-02-06 21:51:48 +03:00
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::raise_interrupt(void)
|
|
|
|
{
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_pic_raise_irq(6);
|
2002-02-06 21:51:48 +03:00
|
|
|
BX_FD_THIS s.pending_irq = 1;
|
|
|
|
BX_FD_THIS s.reset_sensei = 0;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::increment_sector(void)
|
|
|
|
{
|
|
|
|
Bit8u drive;
|
|
|
|
|
|
|
|
drive = BX_FD_THIS s.DOR & 0x03;
|
|
|
|
|
|
|
|
// values after completion of data xfer
|
|
|
|
// ??? calculation depends on base_count being multiple of 512
|
|
|
|
BX_FD_THIS s.sector[drive] ++;
|
|
|
|
if (BX_FD_THIS s.sector[drive] > BX_FD_THIS s.media[drive].sectors_per_track) {
|
2001-12-28 19:38:13 +03:00
|
|
|
BX_FD_THIS s.sector[drive] = 1;
|
|
|
|
if (BX_FD_THIS s.multi_track) {
|
|
|
|
BX_FD_THIS s.head[drive] ++;
|
|
|
|
if (BX_FD_THIS s.head[drive] > 1) {
|
|
|
|
BX_FD_THIS s.head[drive] = 0;
|
|
|
|
BX_FD_THIS s.cylinder[drive] ++;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
2001-12-28 19:38:13 +03:00
|
|
|
else {
|
|
|
|
BX_FD_THIS s.cylinder[drive] ++;
|
|
|
|
}
|
|
|
|
if (BX_FD_THIS s.cylinder[drive] >= BX_FD_THIS s.media[drive].tracks) {
|
|
|
|
// Set to 1 past last possible cylinder value.
|
|
|
|
// I notice if I set it to tracks-1, prama linux won't boot.
|
|
|
|
BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.media[drive].tracks;
|
|
|
|
BX_INFO(("increment_sector: clamping cylinder to max"));
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
bx_floppy_ctrl_c::set_media_status(unsigned drive, unsigned status)
|
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
unsigned type;
|
|
|
|
|
2002-08-04 12:42:34 +04:00
|
|
|
if (drive == 0)
|
|
|
|
type = bx_options.floppya.Otype->get ();
|
|
|
|
else
|
|
|
|
type = bx_options.floppyb.Otype->get ();
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// if setting to the current value, nothing to do
|
2002-08-04 12:42:34 +04:00
|
|
|
if ((status == BX_FD_THIS s.media_present[drive]) &&
|
|
|
|
((status == 0) || (type == BX_FD_THIS s.media[drive].type)))
|
2001-04-10 05:04:59 +04:00
|
|
|
return(status);
|
|
|
|
|
|
|
|
if (status == 0) {
|
|
|
|
// eject floppy
|
|
|
|
if (BX_FD_THIS s.media[drive].fd >= 0) {
|
|
|
|
close( BX_FD_THIS s.media[drive].fd );
|
|
|
|
BX_FD_THIS s.media[drive].fd = -1;
|
|
|
|
}
|
|
|
|
BX_FD_THIS s.media_present[drive] = 0;
|
2002-03-17 23:55:27 +03:00
|
|
|
if (drive == 0) {
|
2002-08-04 12:42:34 +04:00
|
|
|
bx_options.floppya.Ostatus->set(BX_EJECTED);
|
2002-03-17 23:55:27 +03:00
|
|
|
} else {
|
2002-08-04 12:42:34 +04:00
|
|
|
bx_options.floppyb.Ostatus->set(BX_EJECTED);
|
2002-03-17 23:55:27 +03:00
|
|
|
}
|
2002-08-13 16:02:37 +04:00
|
|
|
BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// insert floppy
|
|
|
|
if (drive == 0) {
|
2001-06-20 18:01:39 +04:00
|
|
|
path = bx_options.floppya.Opath->getptr ();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
else {
|
2001-06-20 18:01:39 +04:00
|
|
|
path = bx_options.floppyb.Opath->getptr ();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2003-11-22 21:22:45 +03:00
|
|
|
if (!strcmp(path, "none"))
|
|
|
|
return(0);
|
2001-04-10 05:04:59 +04:00
|
|
|
if (evaluate_media(type, path, & BX_FD_THIS s.media[drive])) {
|
|
|
|
BX_FD_THIS s.media_present[drive] = 1;
|
2002-03-17 23:55:27 +03:00
|
|
|
if (drive == 0) {
|
2003-12-18 23:04:49 +03:00
|
|
|
#define MED (BX_FD_THIS s.media[0])
|
|
|
|
BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
|
|
|
|
MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
|
|
|
|
#undef MED
|
2002-08-04 12:42:34 +04:00
|
|
|
bx_options.floppya.Ostatus->set(BX_INSERTED);
|
2002-03-17 23:55:27 +03:00
|
|
|
} else {
|
2003-12-18 23:04:49 +03:00
|
|
|
#define MED (BX_FD_THIS s.media[1])
|
|
|
|
BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
|
|
|
|
MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
|
|
|
|
#undef MED
|
2002-08-04 12:42:34 +04:00
|
|
|
bx_options.floppyb.Ostatus->set(BX_INSERTED);
|
2002-03-17 23:55:27 +03:00
|
|
|
}
|
2002-08-13 16:02:37 +04:00
|
|
|
BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line
|
2001-04-10 05:04:59 +04:00
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_FD_THIS s.media_present[drive] = 0;
|
2002-03-17 23:55:27 +03:00
|
|
|
if (drive == 0) {
|
2002-08-04 12:42:34 +04:00
|
|
|
bx_options.floppya.Ostatus->set(BX_EJECTED);
|
2002-03-17 23:55:27 +03:00
|
|
|
} else {
|
2002-08-04 12:42:34 +04:00
|
|
|
bx_options.floppyb.Ostatus->set(BX_EJECTED);
|
2002-03-17 23:55:27 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
bx_floppy_ctrl_c::get_media_status(unsigned drive)
|
|
|
|
{
|
|
|
|
return( BX_FD_THIS s.media_present[drive] );
|
|
|
|
}
|
|
|
|
|
2001-10-01 21:20:08 +04:00
|
|
|
#ifdef O_BINARY
|
|
|
|
#define BX_RDONLY O_RDONLY | O_BINARY
|
|
|
|
#define BX_RDWR O_RDWR | O_BINARY
|
|
|
|
#else
|
|
|
|
#define BX_RDONLY O_RDONLY
|
|
|
|
#define BX_RDWR O_RDWR
|
|
|
|
#endif
|
|
|
|
|
2002-10-25 15:44:41 +04:00
|
|
|
bx_bool
|
2001-04-10 05:04:59 +04:00
|
|
|
bx_floppy_ctrl_c::evaluate_media(unsigned type, char *path, floppy_t *media)
|
|
|
|
{
|
|
|
|
struct stat stat_buf;
|
2003-11-24 00:54:59 +03:00
|
|
|
int i, ret;
|
|
|
|
int idx = -1;
|
2003-12-07 18:59:32 +03:00
|
|
|
#ifdef __linux__
|
|
|
|
struct floppy_struct floppy_geom;
|
|
|
|
#endif
|
2002-10-13 13:40:05 +04:00
|
|
|
#ifdef WIN32
|
2001-04-10 05:04:59 +04:00
|
|
|
char sTemp[1024];
|
2003-11-22 21:22:45 +03:00
|
|
|
bx_bool raw_floppy = 0;
|
2003-12-07 18:59:32 +03:00
|
|
|
HANDLE hFile;
|
|
|
|
DWORD bytes;
|
|
|
|
DISK_GEOMETRY dg;
|
|
|
|
unsigned tracks, heads, spt;
|
2001-12-27 12:30:31 +03:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (type == BX_FLOPPY_NONE)
|
|
|
|
return(0);
|
|
|
|
|
2001-08-23 17:02:50 +04:00
|
|
|
//If media file is already open, close it before reopening.
|
|
|
|
if(media->fd >=0) {
|
|
|
|
close(media->fd);
|
|
|
|
media->fd=-1;
|
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// open media file (image file or device)
|
2001-06-13 11:06:10 +04:00
|
|
|
media->write_protected = 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
#ifdef macintosh
|
|
|
|
media->fd = 0;
|
2001-06-20 18:01:39 +04:00
|
|
|
if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
2002-10-13 13:40:05 +04:00
|
|
|
#ifdef WIN32
|
2003-11-22 21:22:45 +03:00
|
|
|
if ( (isalpha(path[0])) && (path[1] == ':') && (strlen(path) == 2) ) {
|
|
|
|
raw_floppy = 1;
|
2002-11-30 12:39:29 +03:00
|
|
|
wsprintf(sTemp, "\\\\.\\%s", path);
|
2003-12-07 18:59:32 +03:00
|
|
|
hFile = CreateFile(sTemp, GENERIC_READ, FILE_SHARE_WRITE, NULL,
|
|
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
|
|
BX_ERROR(("Cannot open floppy drive"));
|
|
|
|
return(0);
|
|
|
|
} else {
|
|
|
|
if (!DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytes, NULL)) {
|
|
|
|
BX_ERROR(("No media in floppy drive"));
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return(0);
|
|
|
|
} else {
|
|
|
|
tracks = (unsigned)dg.Cylinders.QuadPart;
|
|
|
|
heads = (unsigned)dg.TracksPerCylinder;
|
|
|
|
spt = (unsigned)dg.SectorsPerTrack;
|
|
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
|
|
}
|
2002-11-30 12:39:29 +03:00
|
|
|
media->fd = open(sTemp, BX_RDWR);
|
|
|
|
} else {
|
|
|
|
media->fd = open(path, BX_RDWR);
|
|
|
|
}
|
2001-10-01 21:20:08 +04:00
|
|
|
#else
|
|
|
|
media->fd = open(path, BX_RDWR);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (media->fd < 0) {
|
2003-11-24 00:54:59 +03:00
|
|
|
BX_INFO(( "tried to open '%s' read/write: %s",path,strerror(errno) ));
|
2001-06-13 04:30:34 +04:00
|
|
|
// try opening the file read-only
|
2001-06-13 11:06:10 +04:00
|
|
|
media->write_protected = 1;
|
2001-06-13 04:30:34 +04:00
|
|
|
#ifdef macintosh
|
|
|
|
media->fd = 0;
|
2001-06-20 18:01:39 +04:00
|
|
|
if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
|
2001-06-13 04:30:34 +04:00
|
|
|
#endif
|
2002-10-13 13:40:05 +04:00
|
|
|
#ifdef WIN32
|
2003-11-22 21:22:45 +03:00
|
|
|
if (raw_floppy == 1) {
|
2002-11-30 12:39:29 +03:00
|
|
|
media->fd = open(sTemp, BX_RDONLY);
|
|
|
|
} else {
|
|
|
|
media->fd = open(path, BX_RDONLY);
|
|
|
|
}
|
2001-10-01 21:20:08 +04:00
|
|
|
#else
|
|
|
|
media->fd = open(path, BX_RDONLY);
|
2001-06-13 04:30:34 +04:00
|
|
|
#endif
|
|
|
|
if (media->fd < 0) {
|
|
|
|
// failed to open read-only too
|
2003-11-24 00:54:59 +03:00
|
|
|
BX_INFO(( "tried to open '%s' read only: %s",path,strerror(errno) ));
|
2002-07-20 23:53:50 +04:00
|
|
|
media->type = type;
|
2001-06-13 04:30:34 +04:00
|
|
|
return(0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2001-06-13 04:30:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-04-10 06:17:43 +04:00
|
|
|
#if BX_WITH_MACOS
|
2001-06-20 18:01:39 +04:00
|
|
|
if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
|
2001-04-10 05:04:59 +04:00
|
|
|
ret = fd_stat(&stat_buf);
|
|
|
|
else
|
|
|
|
ret = fstat(media->fd, &stat_buf);
|
2002-10-13 13:40:05 +04:00
|
|
|
#elif defined(WIN32)
|
2003-11-22 21:22:45 +03:00
|
|
|
if (raw_floppy) {
|
2003-12-11 01:14:01 +03:00
|
|
|
memset (&stat_buf, 0, sizeof(stat_buf));
|
2001-10-01 21:20:08 +04:00
|
|
|
stat_buf.st_mode = S_IFCHR;
|
2003-12-07 18:59:32 +03:00
|
|
|
ret = 0;
|
2003-11-22 21:22:45 +03:00
|
|
|
} else {
|
|
|
|
ret = fstat(media->fd, &stat_buf);
|
|
|
|
}
|
2001-04-10 06:17:43 +04:00
|
|
|
#else
|
|
|
|
// unix
|
|
|
|
ret = fstat(media->fd, &stat_buf);
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
if (ret) {
|
2001-10-07 07:28:45 +04:00
|
|
|
BX_PANIC(("fstat floppy 0 drive image file returns error: %s", strerror(errno)));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2003-11-24 00:54:59 +03:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if (type == floppy_type[i].id) idx = i;
|
|
|
|
}
|
|
|
|
if (idx == -1 ) {
|
|
|
|
BX_PANIC(("evaluate_media: unknown media type"));
|
|
|
|
return(0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( S_ISREG(stat_buf.st_mode) ) {
|
|
|
|
// regular file
|
|
|
|
switch (type) {
|
2003-02-07 02:16:56 +03:00
|
|
|
// use CMOS reserved types
|
|
|
|
case BX_FLOPPY_160K: // 160K 5.25"
|
|
|
|
case BX_FLOPPY_180K: // 180K 5.25"
|
|
|
|
case BX_FLOPPY_320K: // 320K 5.25"
|
2003-11-24 00:54:59 +03:00
|
|
|
// standard floppy types
|
2002-08-01 11:37:56 +04:00
|
|
|
case BX_FLOPPY_360K: // 360K 5.25"
|
2001-04-10 05:04:59 +04:00
|
|
|
case BX_FLOPPY_720K: // 720K 3.5"
|
|
|
|
case BX_FLOPPY_1_2: // 1.2M 5.25"
|
2003-11-24 00:54:59 +03:00
|
|
|
case BX_FLOPPY_2_88: // 2.88M 3.5"
|
|
|
|
media->type = type;
|
|
|
|
media->tracks = floppy_type[idx].trk;
|
|
|
|
media->heads = floppy_type[idx].hd;
|
|
|
|
media->sectors_per_track = floppy_type[idx].spt;
|
|
|
|
media->sectors = floppy_type[idx].sectors;
|
|
|
|
if (stat_buf.st_size > (media->sectors * 512)) {
|
|
|
|
BX_INFO(("evaluate_media: size of file '%s' (%lu) too large for selected type",
|
|
|
|
path, (unsigned long) stat_buf.st_size));
|
|
|
|
return(0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2003-11-24 00:54:59 +03:00
|
|
|
default: // 1.44M 3.5"
|
|
|
|
media->type = type;
|
2001-04-10 05:04:59 +04:00
|
|
|
if (stat_buf.st_size <= 1474560) {
|
2003-11-24 00:54:59 +03:00
|
|
|
media->tracks = floppy_type[idx].trk;
|
|
|
|
media->heads = floppy_type[idx].hd;
|
|
|
|
media->sectors_per_track = floppy_type[idx].spt;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
else if (stat_buf.st_size == 1720320) {
|
|
|
|
media->sectors_per_track = 21;
|
|
|
|
media->tracks = 80;
|
|
|
|
media->heads = 2;
|
|
|
|
}
|
2002-11-30 12:39:29 +03:00
|
|
|
else if (stat_buf.st_size == 1763328) {
|
2001-04-10 05:04:59 +04:00
|
|
|
media->sectors_per_track = 21;
|
|
|
|
media->tracks = 82;
|
|
|
|
media->heads = 2;
|
2002-11-30 12:39:29 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("evaluate_media: file '%s' of unknown size %lu",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
path, (unsigned long) stat_buf.st_size));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
}
|
2003-11-24 00:54:59 +03:00
|
|
|
media->sectors = media->heads * media->tracks * media->sectors_per_track;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
return(1); // success
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ( S_ISCHR(stat_buf.st_mode)
|
|
|
|
#if BX_WITH_MACOS == 0
|
|
|
|
#ifdef S_ISBLK
|
2001-10-01 21:23:45 +04:00
|
|
|
|| S_ISBLK(stat_buf.st_mode)
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
// character or block device
|
|
|
|
// assume media is formatted to typical geometry for drive
|
2003-12-06 16:59:30 +03:00
|
|
|
media->type = type;
|
2003-12-07 18:59:32 +03:00
|
|
|
#ifdef __linux__
|
|
|
|
if (ioctl(media->fd, FDGETPRM, &floppy_geom) < 0) {
|
|
|
|
BX_ERROR(("cannot determine media geometry"));
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
media->tracks = floppy_geom.track;
|
|
|
|
media->heads = floppy_geom.head;
|
|
|
|
media->sectors_per_track = floppy_geom.sect;
|
|
|
|
media->sectors = floppy_geom.size;
|
|
|
|
#elif defined(WIN32)
|
|
|
|
media->tracks = tracks;
|
|
|
|
media->heads = heads;
|
|
|
|
media->sectors_per_track = spt;
|
|
|
|
media->sectors = media->heads * media->tracks * media->sectors_per_track;
|
|
|
|
#else
|
2003-12-06 16:59:30 +03:00
|
|
|
media->tracks = floppy_type[idx].trk;
|
|
|
|
media->heads = floppy_type[idx].hd;
|
|
|
|
media->sectors_per_track = floppy_type[idx].spt;
|
|
|
|
media->sectors = floppy_type[idx].sectors;
|
2003-12-07 18:59:32 +03:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
return(1); // success
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// unknown file type
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("unknown mode type"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
}
|
2001-10-01 21:20:08 +04:00
|
|
|
|
2002-11-30 12:39:29 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::enter_result_phase(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
Bit8u drive;
|
|
|
|
|
|
|
|
drive = BX_FD_THIS s.DOR & 0x03;
|
|
|
|
|
|
|
|
/* these are always the same */
|
|
|
|
BX_FD_THIS s.result_index = 0;
|
|
|
|
BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
|
|
|
|
|
|
|
|
/* invalid command */
|
|
|
|
if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x80) {
|
|
|
|
BX_FD_THIS s.result_size = 1;
|
|
|
|
BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (BX_FD_THIS s.pending_command) {
|
|
|
|
case 0x04: // get status
|
|
|
|
BX_FD_THIS s.result_size = 1;
|
|
|
|
BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg3;
|
|
|
|
break;
|
|
|
|
case 0x08: // sense interrupt
|
|
|
|
BX_FD_THIS s.result_size = 2;
|
|
|
|
BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
|
|
|
|
BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
|
|
|
|
break;
|
|
|
|
case 0x4a: // read ID
|
|
|
|
case 0x4d: // format track
|
|
|
|
case 0x46: // read normal data
|
|
|
|
case 0x66:
|
|
|
|
case 0xc6:
|
|
|
|
case 0xe6:
|
|
|
|
case 0x45: // write normal data
|
|
|
|
case 0xc5:
|
|
|
|
BX_FD_THIS s.result_size = 7;
|
|
|
|
BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
|
|
|
|
BX_FD_THIS s.result[1] = BX_FD_THIS s.status_reg1;
|
|
|
|
BX_FD_THIS s.result[2] = BX_FD_THIS s.status_reg2;
|
|
|
|
BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
|
|
|
|
BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
|
|
|
|
BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
|
|
|
|
BX_FD_THIS s.result[6] = 2; /* sector size code */
|
|
|
|
raise_interrupt();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bx_floppy_ctrl_c::enter_idle_phase(void)
|
|
|
|
{
|
|
|
|
BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched
|
|
|
|
BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready
|
|
|
|
|
|
|
|
BX_FD_THIS s.command_complete = 1; /* waiting for new command */
|
|
|
|
BX_FD_THIS s.command_index = 0;
|
|
|
|
BX_FD_THIS s.command_size = 0;
|
|
|
|
BX_FD_THIS s.pending_command = 0;
|
|
|
|
|
|
|
|
BX_FD_THIS s.floppy_buffer_index = 0;
|
|
|
|
}
|
|
|
|
|