diff --git a/src/Makefile.am b/src/Makefile.am index 94f6aeb..70e1cd5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing dac.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \ hdd.c headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c joystick_ch_flightstick_pro.c joystick_standard.c joystick_sw_pad.c \ joystick_tm_fcs.c keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ -lpt.c mcr.c mem.c mfm_at.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c \ +lpt.c mcr.c mem.c mfm_at.c mfm_xebec.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c \ opti495.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c rom.c rtc.c scat.c serial.c sis496.c sound.c \ sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \ sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \ diff --git a/src/Makefile.linux32 b/src/Makefile.linux32 index 7e05a38..ed8722e 100644 --- a/src/Makefile.linux32 +++ b/src/Makefile.linux32 @@ -10,7 +10,7 @@ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing dac.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ hdd.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ -lpt.o mcr.o mem.o mfm_at.o model.o mouse.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ +lpt.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o rom.o rtc.o scat.o serial.o sis496.o sound.o \ sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ diff --git a/src/Makefile.linux64 b/src/Makefile.linux64 index 7940fbf..d620e19 100644 --- a/src/Makefile.linux64 +++ b/src/Makefile.linux64 @@ -9,7 +9,7 @@ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing dac.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ hdd.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ -lpt.o mcr.o mem.o mfm_at.o model.o mouse.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ +lpt.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o rom.o rtc.o scat.o serial.o sis496.o sound.o \ sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 14e1188..500a222 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -7,7 +7,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o dac.o \ device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o headland.o i430lx.o i430fx.o \ i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ - keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o mfm_at.o model.o mouse.o mouse_ps2.o \ + keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o rom.o rtc.o \ scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index 730662a..25a284b 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -7,7 +7,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o dac.o \ device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o headland.o i430lx.o i430fx.o \ i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ - keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o mfm_at.o model.o mouse.o mouse_ps2.o \ + keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o rom.o rtc.o \ scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ diff --git a/src/allegro-gui.c b/src/allegro-gui.c index 8853d97..ec70b25 100644 --- a/src/allegro-gui.c +++ b/src/allegro-gui.c @@ -6,6 +6,19 @@ #include "ide.h" #include "cdrom-iso.h" +void warning(const char *format, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + + alert("Warning:", buf, NULL, "OK", NULL, 0, 0); +} + + static int file_return(void) { return D_CLOSE; diff --git a/src/hdd.c b/src/hdd.c index 0990409..8128456 100644 --- a/src/hdd.c +++ b/src/hdd.c @@ -3,6 +3,7 @@ #include "hdd.h" #include "mfm_at.h" +#include "mfm_xebec.h" #include "xtide.h" char hdd_controller_name[16]; @@ -19,10 +20,11 @@ static struct int is_mfm; } hdd_controllers[] = { - {"None", "none", &null_hdd_device, 0}, - {"AT Fixed Disk Adapter", "mfm_at", &mfm_at_device, 1}, - {"XTIDE", "xtide", &xtide_device, 0}, - {"XTIDE (AT)", "xtide_at", &xtide_at_device, 0}, + {"None", "none", &null_hdd_device, 0}, + {"AT Fixed Disk Adapter", "mfm_at", &mfm_at_device, 1}, + {"Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1}, + {"XTIDE", "xtide", &xtide_device, 0}, + {"XTIDE (AT)", "xtide_at", &xtide_at_device, 0}, {"", "", NULL, 0} }; diff --git a/src/ibm.h b/src/ibm.h index 88c59f1..f6a521e 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -498,6 +498,7 @@ extern uint32_t atapi_get_cd_volume(int channel); void pclog(const char *format, ...); void fatal(const char *format, ...); +void warning(const char *format, ...); extern int nmi; diff --git a/src/mfm_xebec.c b/src/mfm_xebec.c new file mode 100644 index 0000000..cdae920 --- /dev/null +++ b/src/mfm_xebec.c @@ -0,0 +1,717 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "rom.h" +#include "timer.h" + +#include "mfm_xebec.h" + +#define XEBEC_TIME (2000 * TIMER_USEC) + +extern char ide_fn[4][512]; + +enum +{ + STATE_IDLE, + STATE_RECEIVE_COMMAND, + STATE_START_COMMAND, + STATE_RECEIVE_DATA, + STATE_RECEIVED_DATA, + STATE_SEND_DATA, + STATE_SENT_DATA, + STATE_COMPLETION_BYTE, + STATE_DUNNO +}; + +typedef struct mfm_drive_t +{ + int spt, hpc; + int tracks; + int cfg_spt; + int cfg_hpc; + int cfg_cyl; + int current_cylinder; + FILE *hdfile; +} mfm_drive_t; + +typedef struct xebec_t +{ + rom_t bios_rom; + + int callback; + + int state; + + uint8_t status; + + uint8_t command[6]; + int command_pos; + + uint8_t data[512]; + int data_pos, data_len; + + uint8_t sector_buf[512]; + + uint8_t irq_dma_mask; + + uint8_t completion_byte; + uint8_t error; + +// int cylinder[2]; + + int drive_sel; + +// int max_cylinders[2], max_heads[2]; + + mfm_drive_t drives[2]; + + int sector, head, cylinder; + int sector_count; + + uint8_t switches; +} xebec_t; + +#define STAT_IRQ 0x20 +#define STAT_DRQ 0x10 +#define STAT_BSY 0x08 +#define STAT_CD 0x04 +#define STAT_IO 0x02 +#define STAT_REQ 0x01 + +#define IRQ_ENA 0x02 +#define DMA_ENA 0x01 + +#define CMD_TEST_DRIVE_READY 0x00 +#define CMD_RECALIBRATE 0x01 +#define CMD_READ_STATUS 0x03 +#define CMD_VERIFY_SECTORS 0x05 +#define CMD_READ_SECTORS 0x08 +#define CMD_WRITE_SECTORS 0x0a +#define CMD_INIT_DRIVE_PARAMS 0x0c +#define CMD_WRITE_SECTOR_BUFFER 0x0f +#define CMD_BUFFER_DIAGNOSTIC 0xe0 +#define CMD_CONTROLLER_DIAGNOSTIC 0xe4 + +#define ERR_NOT_READY 0x04 + +static uint8_t xebec_read(uint16_t port, void *p) +{ + xebec_t *xebec = (xebec_t *)p; + uint8_t temp = 0xff; + + switch (port) + { + case 0x320: /*Read data*/ + xebec->status &= ~STAT_IRQ; + switch (xebec->state) + { + case STATE_COMPLETION_BYTE: + if ((xebec->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", xebec->status); + + temp = xebec->completion_byte; +// pclog("Read completion byte %02x\n", temp); + xebec->status = 0; + xebec->state = STATE_IDLE; + break; + + case STATE_SEND_DATA: + if ((xebec->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", xebec->status); + if (xebec->data_pos >= xebec->data_len) + fatal("Data write with full data!\n"); + temp = xebec->data[xebec->data_pos++]; + if (xebec->data_pos == xebec->data_len) + { +// pclog("Read all data\n"); + xebec->status = STAT_BSY; + xebec->state = STATE_SENT_DATA; + xebec->callback = XEBEC_TIME; + } + break; + + default: + fatal("Read data register - %i, %02x\n", xebec->state, xebec->status); + } + break; + + case 0x321: /*Read status*/ + //fatal("Read status\n"); + temp = xebec->status; + break; + + case 0x322: /*Read option jumpers*/ +// pclog("Read option jumpers\n"); + temp = xebec->switches; + break; + } + +// if (port != 0x321) pclog("xebec_read: port=%04x val=%02x\n", port, temp); + return temp; +} + +static void xebec_write(uint16_t port, uint8_t val, void *p) +{ + xebec_t *xebec = (xebec_t *)p; + +// pclog("xebec_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0x320: /*Write data*/ +// pclog("Write data %02x\n"); + switch (xebec->state) + { + case STATE_RECEIVE_COMMAND: + if ((xebec->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) + fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", xebec->status); + if (xebec->command_pos >= 6) + fatal("Command write with full command!\n"); + /*Command data*/ + xebec->command[xebec->command_pos++] = val; + if (xebec->command_pos == 6) + { + xebec->status = STAT_BSY; + xebec->state = STATE_START_COMMAND; + xebec->callback = XEBEC_TIME; +// pclog("Command %02x\n", xebec->command[0]); + } + break; + + case STATE_RECEIVE_DATA: + if ((xebec->status & 0xf) != (STAT_BSY | STAT_REQ)) + fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", xebec->status); + if (xebec->data_pos >= xebec->data_len) + fatal("Data write with full data!\n"); + /*Command data*/ + xebec->data[xebec->data_pos++] = val; + if (xebec->data_pos == xebec->data_len) + { +// pclog("Got data\n"); + xebec->status = STAT_BSY; + xebec->state = STATE_RECEIVED_DATA; + xebec->callback = XEBEC_TIME; + } + break; + + default: + fatal("Write data unknown state - %i %02x\n", xebec->state, xebec->status); + } + break; + + case 0x321: /*Controller reset*/ +// pclog("Write controller reset\n"); + xebec->status = 0; + break; + + case 0x322: /*Generate controller-select-pulse*/ +// pclog("Write controller-select-pulse\n"); + xebec->status = STAT_BSY | STAT_CD | STAT_REQ; + xebec->command_pos = 0; + xebec->state = STATE_RECEIVE_COMMAND; + break; + + case 0x323: /*DMA/IRQ mask register*/ +// pclog("Write DMA/IRQ mask %02x\n", val); + xebec->irq_dma_mask = val; + break; + } +} + +static void xebec_complete(xebec_t *xebec) +{ + xebec->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; + xebec->state = STATE_COMPLETION_BYTE; + if (xebec->irq_dma_mask & IRQ_ENA) + { + xebec->status |= STAT_IRQ; + picint(1 << 5); + } +} + +static void xebec_error(xebec_t *xebec, uint8_t error) +{ + xebec->completion_byte |= 0x02; + xebec->error = error; + pclog("xebec_error - %02x\n", xebec->error); +} + +static int xebec_get_sector(xebec_t *xebec, off64_t *addr) +{ + mfm_drive_t *drive = &xebec->drives[xebec->drive_sel]; + int heads = drive->cfg_hpc; + + if (drive->current_cylinder != xebec->cylinder) + { + pclog("mfm_get_sector: wrong cylinder\n"); + return 1; + } + if (xebec->head > heads) + { + pclog("mfm_get_sector: past end of configured heads\n"); + return 1; + } + if (xebec->head > drive->hpc) + { + pclog("mfm_get_sector: past end of heads\n"); + return 1; + } + if (xebec->sector >= 17) + { + pclog("mfm_get_sector: past end of sectors\n"); + return 1; + } + + *addr = ((((off64_t) xebec->cylinder * heads) + xebec->head) * + 17) + xebec->sector; + + return 0; +} + +static void xebec_next_sector(xebec_t *xebec) +{ + mfm_drive_t *drive = &xebec->drives[xebec->drive_sel]; + + xebec->sector++; + if (xebec->sector >= 17) + { + xebec->sector = 0; + xebec->head++; + if (xebec->head >= drive->cfg_hpc) + { + xebec->head = 0; + xebec->cylinder++; + drive->current_cylinder++; + if (drive->current_cylinder >= drive->cfg_cyl) + drive->current_cylinder = drive->cfg_cyl-1; + } + } +} + +static void xebec_callback(void *p) +{ + xebec_t *xebec = (xebec_t *)p; + mfm_drive_t *drive; + + xebec->callback = 0; + + xebec->drive_sel = (xebec->command[1] & 0x20) ? 1 : 0; + xebec->completion_byte = xebec->drive_sel & 0x20; + + drive = &xebec->drives[xebec->drive_sel]; + + switch (xebec->command[0]) + { + case CMD_TEST_DRIVE_READY: + if (!drive->hdfile) + xebec_error(xebec, ERR_NOT_READY); + xebec_complete(xebec); + break; + + case CMD_RECALIBRATE: + if (!drive->hdfile) + xebec_error(xebec, ERR_NOT_READY); + else + { + xebec->cylinder = 0; + drive->current_cylinder = 0; + } + xebec_complete(xebec); + break; + + case CMD_READ_STATUS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_SEND_DATA; + xebec->data_pos = 0; + xebec->data_len = 4; + xebec->status = STAT_BSY | STAT_IO | STAT_REQ; + xebec->data[0] = xebec->error; + xebec->data[1] = xebec->drive_sel ? 0x20 : 0; + xebec->data[2] = xebec->data[3] = 0; +// pclog("Get status %02x\n", xebec->data[0]); + xebec->error = 0; + break; + + case STATE_SENT_DATA: + xebec_complete(xebec); + break; + } + break; + + case CMD_VERIFY_SECTORS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + xebec->sector = xebec->command[2] & 0x1f; + xebec->sector_count = xebec->command[4]; + do + { + off64_t addr; + +// pclog("xebec Verify %i,%i,%i %i\n", xebec->cylinder, xebec->head, xebec->sector, xebec->sector_count); + if (xebec_get_sector(xebec, &addr)) + fatal("xebec_get_sector failed\n"); + + xebec_next_sector(xebec); + + xebec->sector_count = (xebec->sector_count-1) & 0xff; + } while (xebec->sector_count); + + xebec_complete(xebec); + + readflash = 1; + break; + + default: + fatal("CMD_VERIFY_SECTORS: bad state %i\n", xebec->state); + } + break; + + case CMD_READ_SECTORS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xe0) << 3); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + xebec->sector = xebec->command[2] & 0x1f; + xebec->sector_count = xebec->command[4]; + xebec->state = STATE_SEND_DATA; + xebec->data_pos = 0; + xebec->data_len = 512; + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + fatal("READ_SECTORS no DMA\n"); + break; + + case STATE_SEND_DATA: + if (xebec->irq_dma_mask & DMA_ENA) + { + do + { + if (!xebec->data_pos) + { + off64_t addr; + + if (xebec_get_sector(xebec, &addr)) + fatal("xebec_get_sector failed\n"); + pclog("xebec Read %i,%i,%i %i %08llx %i\n", xebec->cylinder, xebec->head, xebec->sector, xebec->sector_count, addr, xebec->drive_sel); + fseeko64(drive->hdfile, addr * 512, SEEK_SET); + fread(xebec->sector_buf, 512, 1, drive->hdfile); + } + + for (; xebec->data_pos < 512; xebec->data_pos++) + { + int val = dma_channel_write(3, xebec->sector_buf[xebec->data_pos]); + + if (val == DMA_NODATA) + { + pclog("CMD_READ_SECTORS out of data!\n"); + xebec->callback = XEBEC_TIME; + return; + } + } + + xebec_next_sector(xebec); + + xebec->data_pos = 0; + + xebec->sector_count = (xebec->sector_count-1) & 0xff; + + readflash = 1; + } while (xebec->sector_count); + + xebec_complete(xebec); + } + else + fatal("Read sectors no DMA!\n"); + break; + + default: + fatal("CMD_READ_SECTORS: bad state %i\n", xebec->state); + } + break; + + case CMD_WRITE_SECTORS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xe0) << 3); + drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; + xebec->head = xebec->command[1] & 0x1f; + xebec->sector = xebec->command[2] & 0x1f; + xebec->sector_count = xebec->command[4]; + xebec->state = STATE_RECEIVE_DATA; + xebec->data_pos = 0; + xebec->data_len = 512; + if (xebec->irq_dma_mask & DMA_ENA) + xebec->callback = XEBEC_TIME; + else + fatal("READ_SECTORS no DMA\n"); + break; + + case STATE_RECEIVE_DATA: + if (xebec->irq_dma_mask & DMA_ENA) + { + do + { + if (!xebec->data_pos) + { + off64_t addr; + +// pclog("xebec Write %i,%i,%i %i\n", xebec->cylinder, xebec->head, xebec->sector, xebec->sector_count); + if (xebec_get_sector(xebec, &addr)) + fatal("xebec_get_sector failed\n"); + + fseeko64(drive->hdfile, addr * 512, SEEK_SET); + } + + for (; xebec->data_pos < 512; xebec->data_pos++) + { + int val = dma_channel_read(3); + + if (val == DMA_NODATA) + { + pclog("CMD_WRITE_SECTORS out of data!\n"); + xebec->callback = XEBEC_TIME; + return; + } + + xebec->sector_buf[xebec->data_pos] = val & 0xff; + } + + fwrite(xebec->sector_buf, 512, 1, drive->hdfile); + + xebec_next_sector(xebec); + + xebec->data_pos = 0; + + xebec->sector_count = (xebec->sector_count-1) & 0xff; + + readflash = 1; + } while (xebec->sector_count); + + xebec_complete(xebec); + } + else + fatal("Write sectors no DMA!\n"); + break; + + default: + fatal("CMD_WRITE_SECTORS: bad state %i\n", xebec->state); + } + break; + + case CMD_INIT_DRIVE_PARAMS: + switch (xebec->state) + { + case STATE_START_COMMAND: + xebec->state = STATE_RECEIVE_DATA; + xebec->data_pos = 0; + xebec->data_len = 8; + xebec->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVED_DATA: +// pclog("State STATE_RECEIVED_DATA\n"); + drive->cfg_cyl = xebec->data[1] | (xebec->data[0] << 8); + drive->cfg_hpc = xebec->data[2]; + pclog("Drive %i: cylinders=%i, heads=%i\n", xebec->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + xebec_complete(xebec); + break; + + default: + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", xebec->state); + } + break; + + case CMD_WRITE_SECTOR_BUFFER: + switch (xebec->state) + { + case STATE_START_COMMAND: + if (xebec->irq_dma_mask & DMA_ENA) + { + int c; + + for (c = 0; c < 512; c++) + { + int val = dma_channel_read(3); + + if (val == DMA_NODATA) + fatal("CMD_WRITE_SECTOR_DATA out of data!\n"); + + xebec->sector_buf[c] = val & 0xff; + } + + xebec_complete(xebec); + } + else + fatal("CMD_WRITE_SECTOR_BUFFER - no DMA\n"); + break; + + default: + fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", xebec->state); + } + break; + + case CMD_BUFFER_DIAGNOSTIC: + case CMD_CONTROLLER_DIAGNOSTIC: + xebec_complete(xebec); + break; + + default: + fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n", + xebec->command[0], xebec->command[1], + xebec->command[2], xebec->command[3], + xebec->command[4], xebec->command[5]); + } +} + +static void loadhd(xebec_t *xebec, int d, const char *fn) +{ + mfm_drive_t *drive = &xebec->drives[d]; + + if (drive->hdfile == NULL) + { + /* Try to open existing hard disk image */ + drive->hdfile = fopen64(fn, "rb+"); + if (drive->hdfile == NULL) + { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) + { + /* Failed because it does not exist, + so try to create new file */ + drive->hdfile = fopen64(fn, "wb+"); + if (drive->hdfile == NULL) + { + pclog("Cannot create file '%s': %s", + fn, strerror(errno)); + return; + } + } + else + { + /* Failed for another reason */ + pclog("Cannot open file '%s': %s", + fn, strerror(errno)); + return; + } + } + } + + drive->spt = hdc[d].spt; + drive->hpc = hdc[d].hpc; + drive->tracks = hdc[d].tracks; +} + +static struct +{ + int tracks, hpc; +} xebec_hd_types[4] = +{ + {306, 4}, /*Type 0*/ + {612, 4}, /*Type 16*/ + {615, 4}, /*Type 2*/ + {306, 8} /*Type 13*/ +}; + +static void xebec_set_switches(xebec_t *xebec) +{ + int c, d; + + xebec->switches = 0; + + for (d = 0; d < 2; d++) + { + mfm_drive_t *drive = &xebec->drives[d]; + + if (!drive->hdfile) + continue; + + for (c = 0; c < 4; c++) + { + if (drive->spt == 17 && + drive->hpc == xebec_hd_types[c].hpc && + drive->tracks == xebec_hd_types[c].tracks) + { + xebec->switches |= (c << (d ? 0 : 2)); + break; + } + } + + if (c == 4) + warning("Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C'); + } +} + +static void *xebec_init() +{ + xebec_t *xebec = malloc(sizeof(xebec_t)); + memset(xebec, 0, sizeof(xebec_t)); + + loadhd(xebec, 0, ide_fn[0]); + loadhd(xebec, 1, ide_fn[1]); + xebec_set_switches(xebec); + + rom_init(&xebec->bios_rom, "roms/IBM_XEBEC_62X0822_1985.BIN", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x0320, 0x0004, xebec_read, NULL, NULL, xebec_write, NULL, NULL, xebec); + + timer_add(xebec_callback, &xebec->callback, &xebec->callback, xebec); + + return xebec; +} + +static void xebec_close(void *p) +{ + xebec_t *xebec = (xebec_t *)p; + int d; + + for (d = 0; d < 2; d++) + { + mfm_drive_t *drive = &xebec->drives[d]; + + if (drive->hdfile != NULL) + fclose(drive->hdfile); + } + + free(xebec); +} + +static int xebec_available() +{ + return rom_present("roms/IBM_XEBEC_62X0822_1985.BIN"); +} + +device_t mfm_xebec_device = +{ + "IBM PC Fixed Disk Adapter", + 0, + xebec_init, + xebec_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/mfm_xebec.h b/src/mfm_xebec.h new file mode 100644 index 0000000..d7991e7 --- /dev/null +++ b/src/mfm_xebec.h @@ -0,0 +1 @@ +extern device_t mfm_xebec_device; diff --git a/src/win-hdconf.c b/src/win-hdconf.c index 14c011c..f135f90 100644 --- a/src/win-hdconf.c +++ b/src/win-hdconf.c @@ -54,6 +54,9 @@ static void check_hd_type(off64_t sz) return; } } + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; } else { diff --git a/src/win.c b/src/win.c index 455f012..ee11860 100644 --- a/src/win.c +++ b/src/win.c @@ -104,6 +104,18 @@ static int win_doresize = 0; static int leave_fullscreen_flag = 0; +void warning(const char *format, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + + MessageBox(ghwnd, buf, "PCem", MB_OK); +} + void updatewindowsize(int x, int y) { RECT r;