Added WD1007V-SE1 ESDI emulation.

This commit is contained in:
SarahW 2017-07-05 21:00:50 +01:00
commit 5d6c3fb9ea
16 changed files with 891 additions and 29 deletions

View file

@ -12,7 +12,7 @@ amrefresh:
pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acer386sx.c ali1429.c amstrad.c cdrom-ioctl-linux.c cdrom-image.cc cdrom-null.c \
codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c \
dac.c dells200.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 \
dac.c dells200.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c esdi_at.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \
hdd.c hdd_esdi.c hdd_file.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 \
laserxt.c lpt.c mca.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 \

View file

@ -7,7 +7,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o allegro
allegro-gui-configure.o allegro-gui-config-sel.o allegro-gui-deviceconfig.o allegro-gui-hdconf.o allegro-joystick.o allegro-keyboard.o allegro-main.o \
allegro-midi.o allegro-mouse.o allegro-video.o amstrad.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.c compaq.o config.o cpu.o \
dac.o dells200.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 \
dac.o dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
hdd.o hdd_esdi.o hdd_file.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 \
laserxt.o lpt.o mca.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 \

View file

@ -5,7 +5,7 @@ WXRC = wxrc
CFLAGS = -O3 -fomit-frame-pointer -msse2 -m32 $(shell wx-config --cxxflags) $(shell sdl2-config --cflags)
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.c compaq.o config.o cpu.o \
dac.o dells200.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 \
dac.o dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
hdd.o hdd_esdi.o hdd_file.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 \
laserxt.o lpt.o mca.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 \

View file

@ -6,7 +6,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o allegro
allegro-gui-configure.o allegro-gui-config-sel.o allegro-gui-deviceconfig.o allegro-gui-hdconf.o allegro-joystick.o allegro-keyboard.o allegro-main.o \
allegro-midi.o allegro-mouse.o allegro-video.o amstrad.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \
dac.o dells200.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 \
dac.o dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
hdd.o hdd_esdi.o hdd_file.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 \
laserxt.o lpt.o mca.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 \

View file

@ -5,7 +5,7 @@ WXRC = wxrc
CFLAGS = -Doff64_t=__off64_t -O3 -fomit-frame-pointer -msse2 -m64 $(shell wx-config --cxxflags) $(shell sdl2-config --cflags)
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \
codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \
dac.o dells200.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 \
dac.o dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
hdd.o hdd_esdi.o hdd_file.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 \
laserxt.o lpt.o mca.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 \

View file

@ -5,7 +5,7 @@ WINDRES = windres.exe
CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Wall -Werror -fno-strict-aliasing
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-image.o \
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 \
dells200.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 hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \
dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.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 laserxt.o lpt.o mca.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 ps2_mca.o ps2_nvr.o rom.o rtc.o \

View file

@ -5,7 +5,7 @@ WXRC = wxrc
CFLAGS = -DRELEASE_BUILD -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-image.o \
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 dells200.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 hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \
device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.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 laserxt.o lpt.o mca.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 ps2_mca.o ps2_nvr.o rom.o rtc.o \

View file

@ -5,7 +5,7 @@ WINDRES = windres.exe
CFLAGS = -O3 -fomit-frame-pointer -msse2 -Wall -Werror -fno-strict-aliasing
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-image.o \
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 \
dells200.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 hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \
dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.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 laserxt.o lpt.o mca.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 ps2_mca.o ps2_nvr.o rom.o rtc.o \

View file

@ -5,7 +5,7 @@ WXRC = wxrc
CFLAGS = -D__unix=1 -DPCEM_RENDER_WITH_TIMER -DPCEM_RENDER_TIMER_LOOP -Dfopen64=fopen -Dfseeko64=fseeko -Dftello64=ftello -Doff64_t=off_t -O3 -fomit-frame-pointer -msse2 -m64 $(shell wx-config --cxxflags) $(shell sdl2-config --cflags) -I/usr/local/opt/openal-soft/include -I/usr/local/include
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl-osx.o cdrom-image.o cdrom-null.o \
codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \
dac.o device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
dac.o device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \
hdd.o hdd_esdi.o hdd_file.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 \
laserxt.o lpt.o mca.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 \

834
src/esdi_at.c Normal file
View file

@ -0,0 +1,834 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include "ibm.h"
#include "device.h"
#include "hdd_file.h"
#include "io.h"
#include "mem.h"
#include "pic.h"
#include "rom.h"
#include "timer.h"
#include "esdi_at.h"
#define IDE_TIME (TIMER_USEC*10)//(5 * 100 * (1 << TIMER_SHIFT))
#define STAT_ERR 0x01
#define STAT_INDEX 0x02
#define STAT_CORRECTED_DATA 0x04
#define STAT_DRQ 0x08 /* Data request */
#define STAT_DSC 0x10
#define STAT_SEEK_COMPLETE 0x20
#define STAT_READY 0x40
#define STAT_BUSY 0x80
#define ERR_DAM_NOT_FOUND 0x01 /*Data Address Mark not found*/
#define ERR_TR000 0x02 /*Track 0 not found*/
#define ERR_ABRT 0x04 /*Command aborted*/
#define ERR_ID_NOT_FOUND 0x10 /*ID not found*/
#define ERR_DATA_CRC 0x40 /*Data CRC error*/
#define ERR_BAD_BLOCK 0x80 /*Bad Block detected*/
#define CMD_NOP 0x00
#define CMD_RESTORE 0x10
#define CMD_READ 0x20
#define CMD_WRITE 0x30
#define CMD_VERIFY 0x40
#define CMD_FORMAT 0x50
#define CMD_SEEK 0x70
#define CMD_DIAGNOSE 0x90
#define CMD_SET_PARAMETERS 0x91
#define CMD_READ_PARAMETERS 0xec
extern char ide_fn[4][512];
typedef struct esdi_drive_t
{
int cfg_spt;
int cfg_hpc;
int current_cylinder;
hdd_file_t hdd_file;
} esdi_drive_t;
typedef struct esdi_t
{
uint8_t status;
uint8_t error;
int secount,sector,cylinder,head,cylprecomp;
uint8_t command;
uint8_t fdisk;
int pos;
int drive_sel;
int reset;
uint16_t buffer[256];
int irqstat;
int callback;
esdi_drive_t drives[2];
rom_t bios_rom;
} esdi_t;
uint16_t esdi_readw(uint16_t port, void *p);
void esdi_writew(uint16_t port, uint16_t val, void *p);
static inline void esdi_irq_raise(esdi_t *esdi)
{
// pclog("IDE_IRQ_RAISE\n");
if (!(esdi->fdisk&2))
picint(1 << 14);
esdi->irqstat=1;
}
static inline void esdi_irq_lower(esdi_t *esdi)
{
picintc(1 << 14);
}
void esdi_irq_update(esdi_t *esdi)
{
if (esdi->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(esdi->fdisk & 2))
picint(1 << 14);
}
/*
* Return the sector offset for the current register values
*/
int esdi_get_sector(esdi_t *esdi, off64_t *addr)
{
esdi_drive_t *drive = &esdi->drives[esdi->drive_sel];
int heads = drive->cfg_hpc;
int sectors = drive->cfg_spt;
if (esdi->head > heads)
{
pclog("esdi_get_sector: past end of configured heads\n");
return 1;
}
if (esdi->sector >= sectors+1)
{
pclog("esdi_get_sector: past end of configured sectors\n");
return 1;
}
if (drive->cfg_spt == drive->hdd_file.spt && drive->cfg_hpc == drive->hdd_file.hpc)
{
*addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) *
sectors) + (esdi->sector - 1);
}
else
{
/*When performing translation, the firmware seems to leave 1
sector per track inaccessible (spare sector)*/
int c, h, s;
*addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) *
sectors) + (esdi->sector - 1);
s = *addr % (drive->hdd_file.spt - 1);
h = (*addr / (drive->hdd_file.spt - 1)) % drive->hdd_file.hpc;
c = (*addr / (drive->hdd_file.spt - 1)) / drive->hdd_file.hpc;
*addr = ((((off64_t) c * drive->hdd_file.hpc) + h) *
drive->hdd_file.spt) + s;
}
return 0;
}
/**
* Move to the next sector using CHS addressing
*/
void esdi_next_sector(esdi_t *esdi)
{
esdi_drive_t *drive = &esdi->drives[esdi->drive_sel];
esdi->sector++;
if (esdi->sector == (drive->cfg_spt + 1))
{
esdi->sector = 1;
esdi->head++;
if (esdi->head == drive->cfg_hpc)
{
esdi->head = 0;
esdi->cylinder++;
if (drive->current_cylinder < drive->hdd_file.tracks)
drive->current_cylinder++;
}
}
}
void esdi_write(uint16_t port, uint8_t val, void *p)
{
esdi_t *esdi = (esdi_t *)p;
// pclog("esdi_write: addr=%04x val=%02x\n", port, val);
switch (port)
{
case 0x1F0: /* Data */
esdi_writew(port, val | (val << 8), p);
return;
case 0x1F1: /* Write precompenstation */
esdi->cylprecomp = val;
return;
case 0x1F2: /* Sector count */
esdi->secount = val;
return;
case 0x1F3: /* Sector */
esdi->sector = val;
return;
case 0x1F4: /* Cylinder low */
esdi->cylinder = (esdi->cylinder & 0xFF00) | val;
return;
case 0x1F5: /* Cylinder high */
esdi->cylinder = (esdi->cylinder & 0xFF) | (val << 8);
return;
case 0x1F6: /* Drive/Head */
esdi->head = val & 0xF;
esdi->drive_sel = (val & 0x10) ? 1 : 0;
if (esdi->drives[esdi->drive_sel].hdd_file.f == NULL)
esdi->status = 0;
else
esdi->status = STAT_READY | STAT_DSC;
return;
case 0x1F7: /* Command register */
// if (esdi->drives[esdi->drive_sel].hdd_file.f == NULL && val != CMD_SET_PARAMETERS && val != CMD_NOP && val != 0xe0 && (val & ~3) != 0x20 && (val & ~3) != 0x30 && (val & ~3) != 0x40 && val != 0x90 && val != CMD_READ_PARAMETERS)
// fatal("Command %02x on non-present drive\n", val);
esdi_irq_lower(esdi);
esdi->command = val;
esdi->error = 0;
switch (val & 0xf0)
{
case CMD_RESTORE:
// pclog("Restore\n");
esdi->command &= ~0x0f; /*Mask off step rate*/
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
case CMD_SEEK:
// pclog("Seek to cylinder %i\n", esdi->cylinder);
esdi->command &= ~0x0f; /*Mask off step rate*/
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
default:
switch (val)
{
case CMD_NOP:
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
case CMD_READ: case CMD_READ+1:
case CMD_READ+2: case CMD_READ+3:
// pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head,ins);
esdi->command &= ~3;
if (val & 2)
fatal("Read with ECC\n");
case 0xa0:
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
case CMD_WRITE: case CMD_WRITE+1:
case CMD_WRITE+2: case CMD_WRITE+3:
// pclog("Write %i sectors to sector %i cylinder %i head %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head);
esdi->command &= ~3;
if (val & 2)
fatal("Write with ECC\n");
esdi->status = STAT_DRQ | STAT_DSC;// | STAT_BUSY;
esdi->pos=0;
break;
case CMD_VERIFY: case CMD_VERIFY+1:
// pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head);
esdi->command &= ~1;
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200 * IDE_TIME;
timer_update_outstanding();
break;
case CMD_FORMAT:
// pclog("Format track %i head %i\n", esdi->cylinder, esdi->head);
esdi->status = STAT_DRQ;// | STAT_BUSY;
esdi->pos=0;
break;
case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 30*IDE_TIME;
timer_update_outstanding();
break;
case CMD_DIAGNOSE: /* Execute Drive Diagnostics */
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
case 0xe0: /*???*/
case CMD_READ_PARAMETERS:
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
default:
pclog("Bad esdi command %02X\n", val);
case 0xe8: /*???*/
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 200*IDE_TIME;
timer_update_outstanding();
break;
}
}
break;
case 0x3F6: /* Device control */
if ((esdi->fdisk & 4) && !(val & 4))
{
timer_process();
esdi->callback = 500*IDE_TIME;
timer_update_outstanding();
esdi->reset = 1;
esdi->status = STAT_BUSY;
// pclog("esdi Reset\n");
}
if (val & 4)
{
/*Drive held in reset*/
timer_process();
esdi->callback = 0;
timer_update_outstanding();
esdi->status = STAT_BUSY;
}
esdi->fdisk = val;
esdi_irq_update(esdi);
return;
}
// fatal("Bad ESDI write %04X %02X\n", port, val);
}
void esdi_writew(uint16_t port, uint16_t val, void *p)
{
esdi_t *esdi = (esdi_t *)p;
// pclog("Write ESDIw %04X\n",val);
esdi->buffer[esdi->pos >> 1] = val;
esdi->pos += 2;
if (esdi->pos >= 512)
{
esdi->pos = 0;
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 6*IDE_TIME;
timer_update_outstanding();
}
}
uint8_t esdi_read(uint16_t port, void *p)
{
esdi_t *esdi = (esdi_t *)p;
uint8_t temp = 0xff;
switch (port)
{
case 0x1F0: /* Data */
temp = esdi_readw(port, esdi) & 0xff;
break;
case 0x1F1: /* Error */
temp = esdi->error;
break;
case 0x1F2: /* Sector count */
temp = (uint8_t)esdi->secount;
break;
case 0x1F3: /* Sector */
temp = (uint8_t)esdi->sector;
break;
case 0x1F4: /* Cylinder low */
temp = (uint8_t)(esdi->cylinder&0xFF);
break;
case 0x1F5: /* Cylinder high */
temp = (uint8_t)(esdi->cylinder>>8);
break;
case 0x1F6: /* Drive/Head */
temp = (uint8_t)(esdi->head | (esdi->drive_sel ? 0x10 : 0) | 0xa0);
break;
case 0x1F7: /* Status */
esdi_irq_lower(esdi);
temp = esdi->status;
break;
}
// if (port != 0x1f7) pclog("esdi_read: addr=%04x val=%02x %04X:%04x\n", port, temp, CS, cpu_state.pc);
return temp;
}
uint16_t esdi_readw(uint16_t port, void *p)
{
esdi_t *esdi = (esdi_t *)p;
uint16_t temp;
temp = esdi->buffer[esdi->pos >> 1];
esdi->pos += 2;
if (esdi->pos >= 512)
{
// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos);
esdi->pos=0;
esdi->status = STAT_READY | STAT_DSC;
if (esdi->command == CMD_READ || esdi->command == 0xa0)
{
esdi->secount = (esdi->secount - 1) & 0xff;
if (esdi->secount)
{
esdi_next_sector(esdi);
esdi->status = STAT_BUSY;
timer_process();
esdi->callback = 6*IDE_TIME;
timer_update_outstanding();
}
}
}
// pclog("esdi_readw: temp=%04x %i\n", temp, esdi->pos);
return temp;
}
void esdi_callback(void *p)
{
esdi_t *esdi = (esdi_t *)p;
esdi_drive_t *drive = &esdi->drives[esdi->drive_sel];
off64_t addr;
// pclog("esdi_callback: command=%02x reset=%i\n", esdi->command, esdi->reset);
esdi->callback = 0;
if (esdi->reset)
{
esdi->status = STAT_READY | STAT_DSC;
esdi->error = 1;
esdi->secount = 1;
esdi->sector = 1;
esdi->head = 0;
esdi->cylinder = 0;
esdi->reset = 0;
// pclog("Reset callback\n");
return;
}
switch (esdi->command)
{
case CMD_RESTORE:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
drive->current_cylinder = 0;
esdi->status = STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
}
break;
case CMD_SEEK:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
esdi->status = STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
}
break;
case CMD_READ:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
if (esdi_get_sector(esdi, &addr))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
if (hdd_read_sectors(&drive->hdd_file, addr, 1, esdi->buffer))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
esdi->pos = 0;
esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
// pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]);
// if (addr) output=3;
esdi_irq_raise(esdi);
readflash_set(READFLASH_HDC, esdi->drive_sel);
}
break;
case CMD_WRITE:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
if (esdi_get_sector(esdi, &addr))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
if (hdd_write_sectors(&drive->hdd_file, addr, 1, esdi->buffer))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
esdi_irq_raise(esdi);
esdi->secount = (esdi->secount - 1) & 0xff;
if (esdi->secount)
{
esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
esdi->pos = 0;
esdi_next_sector(esdi);
}
else
esdi->status = STAT_READY | STAT_DSC;
readflash_set(READFLASH_HDC, esdi->drive_sel);
}
break;
case CMD_VERIFY:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
if (esdi_get_sector(esdi, &addr))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
if (hdd_read_sectors(&drive->hdd_file, addr, 1, esdi->buffer))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
readflash_set(READFLASH_HDC, esdi->drive_sel);
esdi_next_sector(esdi);
esdi->secount = (esdi->secount - 1) & 0xff;
if (esdi->secount)
esdi->callback = 6*IDE_TIME;
else
{
esdi->pos = 0;
esdi->status = STAT_READY | STAT_DSC;
// pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount);
esdi_irq_raise(esdi);
}
}
break;
case CMD_FORMAT:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
if (esdi_get_sector(esdi, &addr))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
if (hdd_format_sectors(&drive->hdd_file, addr, esdi->secount))
{
esdi->error = ERR_ID_NOT_FOUND;
esdi->status = STAT_READY | STAT_DSC | STAT_ERR;
esdi_irq_raise(esdi);
break;
}
esdi->status = STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
readflash_set(READFLASH_HDC, esdi->drive_sel);
}
break;
case CMD_DIAGNOSE:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
esdi->error = 1; /*No error detected*/
esdi->status = STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
}
break;
case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
drive->cfg_spt = esdi->secount;
drive->cfg_hpc = esdi->head+1;
pclog("Parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc);
if (!esdi->secount)
fatal("secount=0\n");
esdi->status = STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
}
break;
case CMD_NOP:
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
break;
case 0xe0:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
switch (esdi->cylinder >> 8)
{
case 0x31:
esdi->cylinder = drive->hdd_file.tracks;
break;
case 0x33:
esdi->cylinder = drive->hdd_file.hpc;
break;
case 0x35:
esdi->cylinder = 0x200;
break;
case 0x36:
esdi->cylinder = drive->hdd_file.spt;
break;
default:
pclog("EDSI Bad read config %02x\n", esdi->cylinder >> 8);
}
esdi->status = STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
}
break;
case 0xa0:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
memset(esdi->buffer, 0, 512);
memset(&esdi->buffer[3], 0xff, 512-6);
esdi->pos = 0;
esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
// pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]);
// if (addr) output=3;
esdi_irq_raise(esdi);
}
break;
case CMD_READ_PARAMETERS:
if (!drive->hdd_file.f)
{
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
}
else
{
memset(esdi->buffer, 0, 512);
esdi->buffer[0] = 0x44; /* general configuration */
esdi->buffer[1] = drive->hdd_file.tracks; /* number of non-removable cylinders */
esdi->buffer[2] = 0; /* number of removable cylinders */
esdi->buffer[3] = drive->hdd_file.hpc; /* number of heads */
esdi->buffer[5] = esdi->buffer[4] * drive->hdd_file.spt; /* number of unformatted bytes/sector */
esdi->buffer[4] = 600; /* number of unformatted bytes/track */
esdi->buffer[6] = drive->hdd_file.spt; /* number of sectors */
esdi->buffer[7] = 0; /*minimum bytes in inter-sector gap*/
esdi->buffer[8] = 0; /* minimum bytes in postamble */
esdi->buffer[9] = 0; /* number of words of vendor status */
/* controller info */
// char wdp_cnsn[20]; /* controller serial number */
esdi->buffer[20] = 2; /* controller type */
esdi->buffer[21] = 1; /* sector buffer size, in sectors */
esdi->buffer[22] = 0; /* ecc bytes appended */
// char wdp_rev[8]; /* firmware revision */
//27
esdi->buffer[27] = 'W' | ('D' << 8);
esdi->buffer[28] = '1' | ('0' << 8);
esdi->buffer[29] = '0' | ('7' << 8);
esdi->buffer[30] = 'V' | ('-' << 8);
esdi->buffer[31] = 'S' | ('E' << 8);
esdi->buffer[32] = '1';
esdi->buffer[47] = 0; /* sectors per interrupt */
esdi->buffer[48] = 0;/* can use double word read/write? */
esdi->pos = 0;
esdi->status = STAT_DRQ | STAT_READY | STAT_DSC;
esdi_irq_raise(esdi);
}
break;
default:
pclog("ESDI Callback on unknown command %02x\n", esdi->command);
case 0xe8:
esdi->status = STAT_READY | STAT_ERR | STAT_DSC;
esdi->error = ERR_ABRT;
esdi_irq_raise(esdi);
break;
}
}
static void esdi_rom_write(uint32_t addr, uint8_t val, void *p)
{
rom_t *rom = (rom_t *)p;
addr &= rom->mask;
if (addr >= 0x1f00 && addr < 0x2000)
rom->rom[addr] = val;
}
void *wd1007vse1_init()
{
esdi_t *esdi = malloc(sizeof(esdi_t));
memset(esdi, 0, sizeof(esdi_t));
hdd_load(&esdi->drives[0].hdd_file, 0, ide_fn[0]);
hdd_load(&esdi->drives[1].hdd_file, 1, ide_fn[1]);
esdi->drives[0].cfg_spt = esdi->drives[0].hdd_file.spt;
esdi->drives[0].cfg_hpc = esdi->drives[0].hdd_file.hpc;
esdi->drives[1].cfg_spt = esdi->drives[1].hdd_file.spt;
esdi->drives[1].cfg_hpc = esdi->drives[1].hdd_file.hpc;
esdi->status = STAT_READY | STAT_DSC;
esdi->error = 1; /*No errors*/
rom_init(&esdi->bios_rom, "roms/62-000279-061.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
mem_mapping_set_handler(&esdi->bios_rom.mapping,
rom_read, rom_readw, rom_readl,
esdi_rom_write, NULL, NULL);
io_sethandler(0x01f0, 0x0001, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi);
io_sethandler(0x01f1, 0x0007, esdi_read, NULL, NULL, esdi_write, NULL, NULL, esdi);
io_sethandler(0x03f6, 0x0001, NULL, NULL, NULL, esdi_write, NULL, NULL, esdi);
timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi);
return esdi;
}
void wd1007vse1_close(void *p)
{
esdi_t *esdi = (esdi_t *)p;
hdd_close(&esdi->drives[0].hdd_file);
hdd_close(&esdi->drives[1].hdd_file);
free(esdi);
}
static int wd1007vse1_available()
{
return rom_present("roms/62-000279-061.bin");
}
device_t wd1007vse1_device =
{
"Western Digital WD1007V-SE1 (ESDI)",
DEVICE_AT,
wd1007vse1_init,
wd1007vse1_close,
wd1007vse1_available,
NULL,
NULL,
NULL,
NULL
};

1
src/esdi_at.h Normal file
View file

@ -0,0 +1 @@
extern device_t wd1007vse1_device;

View file

@ -2,6 +2,7 @@
#include "device.h"
#include "hdd.h"
#include "esdi_at.h"
#include "hdd_esdi.h"
#include "mfm_at.h"
#include "mfm_xebec.h"
@ -21,13 +22,14 @@ static struct
int is_mfm;
} hdd_controllers[] =
{
{"None", "none", &null_hdd_device, 0},
{"AT Fixed Disk Adapter", "mfm_at", &mfm_at_device, 1},
{"DTC 5150X", "dtc5150x", &dtc_5150x_device, 1},
{"Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1},
{"IBM ESDI Fixed Disk Adapter (MCA)", "esdi_mca", &hdd_esdi_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},
{"DTC 5150X", "dtc5150x", &dtc_5150x_device, 1},
{"Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1},
{"IBM ESDI Fixed Disk Adapter (MCA)", "esdi_mca", &hdd_esdi_device, 1},
{"Western Digital WD1007V-SE1 (ESDI)","wd1007vse1", &wd1007vse1_device, 0},
{"XTIDE", "xtide", &xtide_device, 0},
{"XTIDE (AT)", "xtide_at", &xtide_at_device, 0},
{"", "", NULL, 0}
};

View file

@ -52,34 +52,55 @@ void hdd_close(hdd_file_t *hdd)
}
}
void hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
{
off64_t addr;
int transfer_sectors = nr_sectors;
if ((hdd->sectors - offset) < transfer_sectors)
transfer_sectors = hdd->sectors - offset;
addr = offset * 512;
fseeko64(hdd->f, addr, SEEK_SET);
fread(buffer, nr_sectors*512, 1, hdd->f);
fread(buffer, transfer_sectors*512, 1, hdd->f);
if (nr_sectors != transfer_sectors)
return 1;
return 0;
}
void hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
{
off64_t addr;
int transfer_sectors = nr_sectors;
if ((hdd->sectors - offset) < transfer_sectors)
transfer_sectors = hdd->sectors - offset;
addr = offset * 512;
fseeko64(hdd->f, addr, SEEK_SET);
fwrite(buffer, nr_sectors*512, 1, hdd->f);
fwrite(buffer, transfer_sectors*512, 1, hdd->f);
if (nr_sectors != transfer_sectors)
return 1;
return 0;
}
void hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors)
int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors)
{
off64_t addr;
int c;
uint8_t zero_buffer[512];
int transfer_sectors = nr_sectors;
memset(zero_buffer, 0, 512);
if ((hdd->sectors - offset) < transfer_sectors)
transfer_sectors = hdd->sectors - offset;
addr = offset * 512;
fseeko64(hdd->f, addr, SEEK_SET);
for (c = 0; c < nr_sectors; c++)
for (c = 0; c < transfer_sectors; c++)
fwrite(zero_buffer, 512, 1, hdd->f);
if (nr_sectors != transfer_sectors)
return 1;
return 0;
}

View file

@ -9,6 +9,6 @@ typedef struct hdd_file_t
void hdd_load(hdd_file_t *hdd, int d, const char *fn);
void hdd_close(hdd_file_t *hdd);
void hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer);
void hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer);
void hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors);
int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer);
int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer);
int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors);

View file

@ -31,7 +31,7 @@ int rom_present(char *fn)
return 0;
}
static uint8_t rom_read(uint32_t addr, void *p)
uint8_t rom_read(uint32_t addr, void *p)
{
rom_t *rom = (rom_t *)p;
// pclog("rom_read : %08x %08x %02x\n", addr, rom->mask, rom->rom[addr & rom->mask]);

View file

@ -10,3 +10,7 @@ typedef struct rom_t
int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags);
int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags);
uint8_t rom_read(uint32_t addr, void *p);
uint16_t rom_readw(uint32_t addr, void *p);
uint32_t rom_readl(uint32_t addr, void *p);