clang-format in src/disk/

This commit is contained in:
Jasmine Iwanek
2022-09-18 17:13:50 -04:00
parent 9a3cabbe85
commit 696f6f7e2f
17 changed files with 8516 additions and 8938 deletions

View File

@@ -29,33 +29,30 @@
#include <86box/hdc_ide.h> #include <86box/hdc_ide.h>
#include <86box/hdd.h> #include <86box/hdd.h>
int hdc_current;
int hdc_current;
#ifdef ENABLE_HDC_LOG #ifdef ENABLE_HDC_LOG
int hdc_do_log = ENABLE_HDC_LOG; int hdc_do_log = ENABLE_HDC_LOG;
static void static void
hdc_log(const char *fmt, ...) hdc_log(const char *fmt, ...)
{ {
va_list ap; va_list ap;
if (hdc_do_log) { if (hdc_do_log) {
va_start(ap, fmt); va_start(ap, fmt);
pclog_ex(fmt, ap); pclog_ex(fmt, ap);
va_end(ap); va_end(ap);
} }
} }
#else #else
#define hdc_log(fmt, ...) # define hdc_log(fmt, ...)
#endif #endif
static void * static void *
nullhdc_init(const device_t *info) nullhdc_init(const device_t *info)
{ {
return(NULL); return (NULL);
} }
static void static void
@@ -66,7 +63,7 @@ nullhdc_close(void *priv)
static void * static void *
inthdc_init(const device_t *info) inthdc_init(const device_t *info)
{ {
return(NULL); return (NULL);
} }
static void static void
@@ -75,37 +72,37 @@ inthdc_close(void *priv)
} }
static const device_t hdc_none_device = { static const device_t hdc_none_device = {
.name = "None", .name = "None",
.internal_name = "none", .internal_name = "none",
.flags = 0, .flags = 0,
.local = 0, .local = 0,
.init = nullhdc_init, .init = nullhdc_init,
.close = nullhdc_close, .close = nullhdc_close,
.reset = NULL, .reset = NULL,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
static const device_t hdc_internal_device = { static const device_t hdc_internal_device = {
.name = "Internal", .name = "Internal",
.internal_name = "internal", .internal_name = "internal",
.flags = 0, .flags = 0,
.local = 0, .local = 0,
.init = inthdc_init, .init = inthdc_init,
.close = inthdc_close, .close = inthdc_close,
.reset = NULL, .reset = NULL,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
static const struct { static const struct {
const device_t *device; const device_t *device;
} controllers[] = { } controllers[] = {
// clang-format off // clang-format off
{ &hdc_none_device }, { &hdc_none_device },
{ &hdc_internal_device }, { &hdc_internal_device },
{ &st506_xt_xebec_device }, { &st506_xt_xebec_device },
@@ -133,7 +130,7 @@ static const struct {
{ &ide_vlb_device }, { &ide_vlb_device },
{ &ide_vlb_2ch_device }, { &ide_vlb_2ch_device },
{ NULL } { NULL }
// clang-format on // clang-format on
}; };
/* Initialize the 'hdc_current' value based on configured HDC name. */ /* Initialize the 'hdc_current' value based on configured HDC name. */
@@ -146,77 +143,72 @@ hdc_init(void)
hdd_image_init(); hdd_image_init();
} }
/* Reset the HDC, whichever one that is. */ /* Reset the HDC, whichever one that is. */
void void
hdc_reset(void) hdc_reset(void)
{ {
hdc_log("HDC: reset(current=%d, internal=%d)\n", hdc_log("HDC: reset(current=%d, internal=%d)\n",
hdc_current, (machines[machine].flags & MACHINE_HDC) ? 1 : 0); hdc_current, (machines[machine].flags & MACHINE_HDC) ? 1 : 0);
/* If we have a valid controller, add its device. */ /* If we have a valid controller, add its device. */
if (hdc_current > 1) if (hdc_current > 1)
device_add(controllers[hdc_current].device); device_add(controllers[hdc_current].device);
/* Now, add the tertiary and/or quaternary IDE controllers. */ /* Now, add the tertiary and/or quaternary IDE controllers. */
if (ide_ter_enabled) if (ide_ter_enabled)
device_add(&ide_ter_device); device_add(&ide_ter_device);
if (ide_qua_enabled) if (ide_qua_enabled)
device_add(&ide_qua_device); device_add(&ide_qua_device);
} }
char * char *
hdc_get_internal_name(int hdc) hdc_get_internal_name(int hdc)
{ {
return device_get_internal_name(controllers[hdc].device); return device_get_internal_name(controllers[hdc].device);
} }
int int
hdc_get_from_internal_name(char *s) hdc_get_from_internal_name(char *s)
{ {
int c = 0; int c = 0;
while (controllers[c].device != NULL) { while (controllers[c].device != NULL) {
if (!strcmp((char *) controllers[c].device->internal_name, s)) if (!strcmp((char *) controllers[c].device->internal_name, s))
return c; return c;
c++; c++;
} }
return 0; return 0;
} }
const device_t * const device_t *
hdc_get_device(int hdc) hdc_get_device(int hdc)
{ {
return(controllers[hdc].device); return (controllers[hdc].device);
} }
int int
hdc_has_config(int hdc) hdc_has_config(int hdc)
{ {
const device_t *dev = hdc_get_device(hdc); const device_t *dev = hdc_get_device(hdc);
if (dev == NULL) return(0); if (dev == NULL)
return (0);
if (!device_has_config(dev)) return(0); if (!device_has_config(dev))
return (0);
return(1); return (1);
} }
int int
hdc_get_flags(int hdc) hdc_get_flags(int hdc)
{ {
return(controllers[hdc].device->flags); return (controllers[hdc].device->flags);
} }
int int
hdc_available(int hdc) hdc_available(int hdc)
{ {
return(device_available(controllers[hdc].device)); return (device_available(controllers[hdc].device));
} }

File diff suppressed because it is too large Load Diff

View File

@@ -243,7 +243,7 @@ static double
esdi_mca_get_xfer_time(esdi_t *esdi, int size) esdi_mca_get_xfer_time(esdi_t *esdi, int size)
{ {
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
return (3125.0 / 8.0) * (double)size; return (3125.0 / 8.0) * (double) size;
} }
static void static void
@@ -352,7 +352,7 @@ esdi_callback(void *priv)
esdi_t *dev = (esdi_t *) priv; esdi_t *dev = (esdi_t *) priv;
drive_t *drive; drive_t *drive;
int val; int val;
double cmd_time = 0.0; double cmd_time = 0.0;
esdi_mca_set_callback(dev, 0); esdi_mca_set_callback(dev, 0);
@@ -525,7 +525,7 @@ esdi_callback(void *priv)
switch (dev->cmd_state) { switch (dev->cmd_state) {
case 0: case 0:
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
dev->sector_count = dev->cmd_data[1]; dev->sector_count = dev->cmd_data[1];
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {

File diff suppressed because it is too large Load Diff

View File

@@ -37,20 +37,17 @@
#include <86box/zip.h> #include <86box/zip.h>
#include <86box/mo.h> #include <86box/mo.h>
typedef struct typedef struct
{ {
uint8_t vlb_idx, id, uint8_t vlb_idx, id,
in_cfg, single_channel, in_cfg, single_channel,
pci, regs[256]; pci, regs[256];
uint32_t local; uint32_t local;
int slot, irq_mode[2], int slot, irq_mode[2],
irq_pin, irq_line; irq_pin, irq_line;
} cmd640_t; } cmd640_t;
static int next_id = 0;
static int next_id = 0;
#ifdef ENABLE_CMD640_LOG #ifdef ENABLE_CMD640_LOG
int cmd640_do_log = ENABLE_CMD640_LOG; int cmd640_do_log = ENABLE_CMD640_LOG;
@@ -59,51 +56,48 @@ cmd640_log(const char *fmt, ...)
{ {
va_list ap; va_list ap;
if (cmd640_do_log) if (cmd640_do_log) {
{ va_start(ap, fmt);
va_start(ap, fmt); pclog_ex(fmt, ap);
pclog_ex(fmt, ap); va_end(ap);
va_end(ap);
} }
} }
#else #else
#define cmd640_log(fmt, ...) # define cmd640_log(fmt, ...)
#endif #endif
void void
cmd640_set_irq(int channel, void *priv) cmd640_set_irq(int channel, void *priv)
{ {
cmd640_t *dev = (cmd640_t *) priv; cmd640_t *dev = (cmd640_t *) priv;
int irq = !!(channel & 0x40); int irq = !!(channel & 0x40);
if (channel & 0x01) { if (channel & 0x01) {
if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) { if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) {
dev->regs[0x57] &= ~0x10; dev->regs[0x57] &= ~0x10;
dev->regs[0x57] |= (channel >> 2); dev->regs[0x57] |= (channel >> 2);
} }
} else { } else {
if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) { if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) {
dev->regs[0x50] &= ~0x04; dev->regs[0x50] &= ~0x04;
dev->regs[0x50] |= (channel >> 4); dev->regs[0x50] |= (channel >> 4);
} }
} }
channel &= 0x01; channel &= 0x01;
if (irq) { if (irq) {
if (dev->irq_mode[channel] == 1) if (dev->irq_mode[channel] == 1)
pci_set_irq(dev->slot, dev->irq_pin); pci_set_irq(dev->slot, dev->irq_pin);
else else
picint(1 << (14 + channel)); picint(1 << (14 + channel));
} else { } else {
if (dev->irq_mode[channel] == 1) if (dev->irq_mode[channel] == 1)
pci_clear_irq(dev->slot, dev->irq_pin); pci_clear_irq(dev->slot, dev->irq_pin);
else else
picintc(1 << (14 + channel)); picintc(1 << (14 + channel));
} }
} }
static void static void
cmd640_ide_handlers(cmd640_t *dev) cmd640_ide_handlers(cmd640_t *dev)
{ {
@@ -112,65 +106,67 @@ cmd640_ide_handlers(cmd640_t *dev)
ide_pri_disable(); ide_pri_disable();
if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) { if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) {
main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8); main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8);
side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2; side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2;
} else { } else {
main = 0x1f0; main = 0x1f0;
side = 0x3f6; side = 0x3f6;
} }
ide_set_base(0, main); ide_set_base(0, main);
ide_set_side(0, side); ide_set_side(0, side);
if (dev->regs[0x04] & 0x01) if (dev->regs[0x04] & 0x01)
ide_pri_enable(); ide_pri_enable();
if (dev->single_channel) if (dev->single_channel)
return; return;
ide_sec_disable(); ide_sec_disable();
if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) { if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) {
main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8); main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8);
side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2; side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2;
} else { } else {
main = 0x170; main = 0x170;
side = 0x376; side = 0x376;
} }
ide_set_base(1, main); ide_set_base(1, main);
ide_set_side(1, side); ide_set_side(1, side);
if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08)) if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08))
ide_sec_enable(); ide_sec_enable();
} }
static void static void
cmd640_common_write(int addr, uint8_t val, cmd640_t *dev) cmd640_common_write(int addr, uint8_t val, cmd640_t *dev)
{ {
switch (addr) { switch (addr) {
case 0x51: case 0x51:
dev->regs[addr] = val; dev->regs[addr] = val;
cmd640_ide_handlers(dev); cmd640_ide_handlers(dev);
break; break;
case 0x52: case 0x54: case 0x56: case 0x58: case 0x52:
case 0x59: case 0x54:
dev->regs[addr] = val; case 0x56:
break; case 0x58:
case 0x53: case 0x55: case 0x59:
dev->regs[addr] = val & 0xc0; dev->regs[addr] = val;
break; break;
case 0x57: case 0x53:
dev->regs[addr] = val & 0xdc; case 0x55:
break; dev->regs[addr] = val & 0xc0;
case 0x5b: /* Undocumented register that Linux attempts to use! */ break;
dev->regs[addr] = val; case 0x57:
break; dev->regs[addr] = val & 0xdc;
break;
case 0x5b: /* Undocumented register that Linux attempts to use! */
dev->regs[addr] = val;
break;
} }
} }
static void static void
cmd640_vlb_write(uint16_t addr, uint8_t val, void *priv) cmd640_vlb_write(uint16_t addr, uint8_t val, void *priv)
{ {
@@ -179,21 +175,20 @@ cmd640_vlb_write(uint16_t addr, uint8_t val, void *priv)
addr &= 0x00ff; addr &= 0x00ff;
switch (addr) { switch (addr) {
case 0x0078: case 0x0078:
if (dev->in_cfg) if (dev->in_cfg)
dev->vlb_idx = val; dev->vlb_idx = val;
else if ((dev->regs[0x50] & 0x80) && (val == dev->id)) else if ((dev->regs[0x50] & 0x80) && (val == dev->id))
dev->in_cfg = 1; dev->in_cfg = 1;
break; break;
case 0x007c: case 0x007c:
cmd640_common_write(dev->vlb_idx, val, dev); cmd640_common_write(dev->vlb_idx, val, dev);
if (dev->regs[0x50] & 0x80) if (dev->regs[0x50] & 0x80)
dev->in_cfg = 0; dev->in_cfg = 0;
break; break;
} }
} }
static void static void
cmd640_vlb_writew(uint16_t addr, uint16_t val, void *priv) cmd640_vlb_writew(uint16_t addr, uint16_t val, void *priv)
{ {
@@ -201,7 +196,6 @@ cmd640_vlb_writew(uint16_t addr, uint16_t val, void *priv)
cmd640_vlb_write(addr + 1, val >> 8, priv); cmd640_vlb_write(addr + 1, val >> 8, priv);
} }
static void static void
cmd640_vlb_writel(uint16_t addr, uint32_t val, void *priv) cmd640_vlb_writel(uint16_t addr, uint32_t val, void *priv)
{ {
@@ -209,35 +203,33 @@ cmd640_vlb_writel(uint16_t addr, uint32_t val, void *priv)
cmd640_vlb_writew(addr + 2, val >> 16, priv); cmd640_vlb_writew(addr + 2, val >> 16, priv);
} }
static uint8_t static uint8_t
cmd640_vlb_read(uint16_t addr, void *priv) cmd640_vlb_read(uint16_t addr, void *priv)
{ {
uint8_t ret = 0xff; uint8_t ret = 0xff;
cmd640_t *dev = (cmd640_t *) priv; cmd640_t *dev = (cmd640_t *) priv;
addr &= 0x00ff; addr &= 0x00ff;
switch (addr) { switch (addr) {
case 0x0078: case 0x0078:
if (dev->in_cfg) if (dev->in_cfg)
ret = dev->vlb_idx; ret = dev->vlb_idx;
break; break;
case 0x007c: case 0x007c:
ret = dev->regs[dev->vlb_idx]; ret = dev->regs[dev->vlb_idx];
if (dev->vlb_idx == 0x50) if (dev->vlb_idx == 0x50)
dev->regs[0x50] &= ~0x04; dev->regs[0x50] &= ~0x04;
else if (dev->vlb_idx == 0x57) else if (dev->vlb_idx == 0x57)
dev->regs[0x57] &= ~0x10; dev->regs[0x57] &= ~0x10;
if (dev->regs[0x50] & 0x80) if (dev->regs[0x50] & 0x80)
dev->in_cfg = 0; dev->in_cfg = 0;
break; break;
} }
return ret; return ret;
} }
static uint16_t static uint16_t
cmd640_vlb_readw(uint16_t addr, void *priv) cmd640_vlb_readw(uint16_t addr, void *priv)
{ {
@@ -249,7 +241,6 @@ cmd640_vlb_readw(uint16_t addr, void *priv)
return ret; return ret;
} }
static uint32_t static uint32_t
cmd640_vlb_readl(uint16_t addr, void *priv) cmd640_vlb_readl(uint16_t addr, void *priv)
{ {
@@ -261,7 +252,6 @@ cmd640_vlb_readl(uint16_t addr, void *priv)
return ret; return ret;
} }
static void static void
cmd640_pci_write(int func, int addr, uint8_t val, void *priv) cmd640_pci_write(int func, int addr, uint8_t val, void *priv)
{ {
@@ -269,89 +259,89 @@ cmd640_pci_write(int func, int addr, uint8_t val, void *priv)
cmd640_log("cmd640_pci_write(%i, %02X, %02X)\n", func, addr, val); cmd640_log("cmd640_pci_write(%i, %02X, %02X)\n", func, addr, val);
if (func == 0x00) switch (addr) { if (func == 0x00)
case 0x04: switch (addr) {
dev->regs[addr] = (val & 0x41); case 0x04:
cmd640_ide_handlers(dev); dev->regs[addr] = (val & 0x41);
break; cmd640_ide_handlers(dev);
case 0x07: break;
dev->regs[addr] &= ~(val & 0x80); case 0x07:
break; dev->regs[addr] &= ~(val & 0x80);
case 0x09: break;
if ((dev->regs[addr] & 0x0a) == 0x0a) { case 0x09:
dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05); if ((dev->regs[addr] & 0x0a) == 0x0a) {
dev->irq_mode[0] = !!(val & 0x01); dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05);
dev->irq_mode[1] = !!(val & 0x04); dev->irq_mode[0] = !!(val & 0x01);
cmd640_ide_handlers(dev); dev->irq_mode[1] = !!(val & 0x04);
} cmd640_ide_handlers(dev);
break; }
case 0x10: break;
if (dev->regs[0x50] & 0x40) { case 0x10:
dev->regs[0x10] = (val & 0xf8) | 1; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x10] = (val & 0xf8) | 1;
} cmd640_ide_handlers(dev);
break; }
case 0x11: break;
if (dev->regs[0x50] & 0x40) { case 0x11:
dev->regs[0x11] = val; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x11] = val;
} cmd640_ide_handlers(dev);
break; }
case 0x14: break;
if (dev->regs[0x50] & 0x40) { case 0x14:
dev->regs[0x14] = (val & 0xfc) | 1; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x14] = (val & 0xfc) | 1;
} cmd640_ide_handlers(dev);
break; }
case 0x15: break;
if (dev->regs[0x50] & 0x40) { case 0x15:
dev->regs[0x15] = val; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x15] = val;
} cmd640_ide_handlers(dev);
break; }
case 0x18: break;
if (dev->regs[0x50] & 0x40) { case 0x18:
dev->regs[0x18] = (val & 0xf8) | 1; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x18] = (val & 0xf8) | 1;
} cmd640_ide_handlers(dev);
break; }
case 0x19: break;
if (dev->regs[0x50] & 0x40) { case 0x19:
dev->regs[0x19] = val; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x19] = val;
} cmd640_ide_handlers(dev);
break; }
case 0x1c: break;
if (dev->regs[0x50] & 0x40) { case 0x1c:
dev->regs[0x1c] = (val & 0xfc) | 1; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x1c] = (val & 0xfc) | 1;
} cmd640_ide_handlers(dev);
break; }
case 0x1d: break;
if (dev->regs[0x50] & 0x40) { case 0x1d:
dev->regs[0x1d] = val; if (dev->regs[0x50] & 0x40) {
cmd640_ide_handlers(dev); dev->regs[0x1d] = val;
} cmd640_ide_handlers(dev);
break; }
default: break;
cmd640_common_write(addr, val, dev); default:
break; cmd640_common_write(addr, val, dev);
} break;
}
} }
static uint8_t static uint8_t
cmd640_pci_read(int func, int addr, void *priv) cmd640_pci_read(int func, int addr, void *priv)
{ {
cmd640_t *dev = (cmd640_t *) priv; cmd640_t *dev = (cmd640_t *) priv;
uint8_t ret = 0xff; uint8_t ret = 0xff;
if (func == 0x00) { if (func == 0x00) {
ret = dev->regs[addr]; ret = dev->regs[addr];
if (addr == 0x50) if (addr == 0x50)
dev->regs[0x50] &= ~0x04; dev->regs[0x50] &= ~0x04;
else if (addr == 0x57) else if (addr == 0x57)
dev->regs[0x57] &= ~0x10; dev->regs[0x57] &= ~0x10;
} }
cmd640_log("cmd640_pci_read(%i, %02X, %02X)\n", func, addr, ret); cmd640_log("cmd640_pci_read(%i, %02X, %02X)\n", func, addr, ret);
@@ -359,84 +349,83 @@ cmd640_pci_read(int func, int addr, void *priv)
return ret; return ret;
} }
static void static void
cmd640_reset(void *priv) cmd640_reset(void *priv)
{ {
cmd640_t *dev = (cmd640_t *) priv; cmd640_t *dev = (cmd640_t *) priv;
int i = 0; int i = 0;
for (i = 0; i < CDROM_NUM; i++) { for (i = 0; i < CDROM_NUM; i++) {
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel < 4) && cdrom[i].priv)
(cdrom[i].ide_channel < 4) && cdrom[i].priv) scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
} }
for (i = 0; i < ZIP_NUM; i++) { for (i = 0; i < ZIP_NUM; i++) {
if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel < 4) && zip_drives[i].priv)
(zip_drives[i].ide_channel < 4) && zip_drives[i].priv) zip_reset((scsi_common_t *) zip_drives[i].priv);
zip_reset((scsi_common_t *) zip_drives[i].priv); }
for (i = 0; i < MO_NUM; i++) {
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel < 4) && mo_drives[i].priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
} }
for (i = 0; i < MO_NUM; i++) {
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) &&
(mo_drives[i].ide_channel < 4) && mo_drives[i].priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
}
cmd640_set_irq(0x00, priv); cmd640_set_irq(0x00, priv);
cmd640_set_irq(0x01, priv); cmd640_set_irq(0x01, priv);
memset(dev->regs, 0x00, sizeof(dev->regs)); memset(dev->regs, 0x00, sizeof(dev->regs));
dev->regs[0x50] = 0x02; /* Revision 02 */ dev->regs[0x50] = 0x02; /* Revision 02 */
dev->regs[0x50] |= (dev->id << 3); /* Device ID: 00 = 60h, 01 = 61h, 10 = 62h, 11 = 63h */ dev->regs[0x50] |= (dev->id << 3); /* Device ID: 00 = 60h, 01 = 61h, 10 = 62h, 11 = 63h */
dev->regs[0x59] = 0x40; dev->regs[0x59] = 0x40;
if (dev->pci) { if (dev->pci) {
cmd640_log("dev->local = %08X\n", dev->local); cmd640_log("dev->local = %08X\n", dev->local);
if ((dev->local & 0xffff) == 0x0a) { if ((dev->local & 0xffff) == 0x0a) {
dev->regs[0x50] |= 0x40; /* Enable Base address register R/W; dev->regs[0x50] |= 0x40; /* Enable Base address register R/W;
If 0, they return 0 and are read-only 8 */ If 0, they return 0 and are read-only 8 */
} }
dev->regs[0x00] = 0x95; /* CMD */ dev->regs[0x00] = 0x95; /* CMD */
dev->regs[0x01] = 0x10; dev->regs[0x01] = 0x10;
dev->regs[0x02] = 0x40; /* PCI-0640B */ dev->regs[0x02] = 0x40; /* PCI-0640B */
dev->regs[0x03] = 0x06; dev->regs[0x03] = 0x06;
dev->regs[0x04] = 0x01; /* Apparently required by the ASUS PCI/I-P5SP4 AND PCI/I-P54SP4 */ dev->regs[0x04] = 0x01; /* Apparently required by the ASUS PCI/I-P5SP4 AND PCI/I-P54SP4 */
dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */
dev->regs[0x08] = 0x02; /* Revision 02 */ dev->regs[0x08] = 0x02; /* Revision 02 */
dev->regs[0x09] = dev->local; /* Programming interface */ dev->regs[0x09] = dev->local; /* Programming interface */
dev->regs[0x0a] = 0x01; /* IDE controller */ dev->regs[0x0a] = 0x01; /* IDE controller */
dev->regs[0x0b] = 0x01; /* Mass storage controller */ dev->regs[0x0b] = 0x01; /* Mass storage controller */
/* Base addresses (1F0, 3F4, 170, 374) */ /* Base addresses (1F0, 3F4, 170, 374) */
if (dev->regs[0x50] & 0x40) { if (dev->regs[0x50] & 0x40) {
dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; dev->regs[0x10] = 0xf1;
dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; dev->regs[0x11] = 0x01;
dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; dev->regs[0x14] = 0xf5;
dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; dev->regs[0x15] = 0x03;
} dev->regs[0x18] = 0x71;
dev->regs[0x19] = 0x01;
dev->regs[0x1c] = 0x75;
dev->regs[0x1d] = 0x03;
}
dev->regs[0x3c] = 0x14; /* IRQ 14 */ dev->regs[0x3c] = 0x14; /* IRQ 14 */
dev->regs[0x3d] = 0x01; /* INTA */ dev->regs[0x3d] = 0x01; /* INTA */
dev->irq_mode[0] = dev->irq_mode[1] = 0; dev->irq_mode[0] = dev->irq_mode[1] = 0;
dev->irq_pin = PCI_INTA; dev->irq_pin = PCI_INTA;
dev->irq_line = 14; dev->irq_line = 14;
} else { } else {
if ((dev->local & 0xffff) == 0x0078) if ((dev->local & 0xffff) == 0x0078)
dev->regs[0x50] |= 0x20; /* 0 = 178h, 17Ch; 1 = 078h, 07Ch */ dev->regs[0x50] |= 0x20; /* 0 = 178h, 17Ch; 1 = 078h, 07Ch */
/* If bit 7 is 1, then device ID has to be written on port x78h before /* If bit 7 is 1, then device ID has to be written on port x78h before
accessing the configuration registers */ accessing the configuration registers */
dev->in_cfg = 1; /* Configuration registers are accessible */ dev->in_cfg = 1; /* Configuration registers are accessible */
} }
cmd640_ide_handlers(dev); cmd640_ide_handlers(dev);
} }
static void static void
cmd640_close(void *priv) cmd640_close(void *priv)
{ {
@@ -447,7 +436,6 @@ cmd640_close(void *priv)
next_id = 0; next_id = 0;
} }
static void * static void *
cmd640_init(const device_t *info) cmd640_init(const device_t *info)
{ {
@@ -456,30 +444,30 @@ cmd640_init(const device_t *info)
dev->id = next_id | 0x60; dev->id = next_id | 0x60;
dev->pci = !!(info->flags & DEVICE_PCI); dev->pci = !!(info->flags & DEVICE_PCI);
dev->local = info->local; dev->local = info->local;
if (info->flags & DEVICE_PCI) { if (info->flags & DEVICE_PCI) {
device_add(&ide_pci_2ch_device); device_add(&ide_pci_2ch_device);
dev->slot = pci_add_card(PCI_ADD_IDE, cmd640_pci_read, cmd640_pci_write, dev); dev->slot = pci_add_card(PCI_ADD_IDE, cmd640_pci_read, cmd640_pci_write, dev);
ide_set_bus_master(0, NULL, cmd640_set_irq, dev); ide_set_bus_master(0, NULL, cmd640_set_irq, dev);
ide_set_bus_master(1, NULL, cmd640_set_irq, dev); ide_set_bus_master(1, NULL, cmd640_set_irq, dev);
/* The CMD PCI-0640B IDE controller has no DMA capability, /* The CMD PCI-0640B IDE controller has no DMA capability,
so set our devices IDE devices to force ATA-3 (no DMA). */ so set our devices IDE devices to force ATA-3 (no DMA). */
ide_board_set_force_ata3(0, 1); ide_board_set_force_ata3(0, 1);
ide_board_set_force_ata3(1, 1); ide_board_set_force_ata3(1, 1);
// ide_pri_disable(); // ide_pri_disable();
} else if (info->flags & DEVICE_VLB) { } else if (info->flags & DEVICE_VLB) {
device_add(&ide_vlb_2ch_device); device_add(&ide_vlb_2ch_device);
io_sethandler(info->local & 0xffff, 0x0008, io_sethandler(info->local & 0xffff, 0x0008,
cmd640_vlb_read, cmd640_vlb_readw, cmd640_vlb_readl, cmd640_vlb_read, cmd640_vlb_readw, cmd640_vlb_readl,
cmd640_vlb_write, cmd640_vlb_writew, cmd640_vlb_writel, cmd640_vlb_write, cmd640_vlb_writew, cmd640_vlb_writel,
dev); dev);
} }
dev->single_channel = !!(info->local & 0x20000); dev->single_channel = !!(info->local & 0x20000);
@@ -492,71 +480,71 @@ cmd640_init(const device_t *info)
} }
const device_t ide_cmd640_vlb_device = { const device_t ide_cmd640_vlb_device = {
.name = "CMD PCI-0640B VLB", .name = "CMD PCI-0640B VLB",
.internal_name = "ide_cmd640_vlb", .internal_name = "ide_cmd640_vlb",
.flags = DEVICE_VLB, .flags = DEVICE_VLB,
.local = 0x0078, .local = 0x0078,
.init = cmd640_init, .init = cmd640_init,
.close = cmd640_close, .close = cmd640_close,
.reset = cmd640_reset, .reset = cmd640_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t ide_cmd640_vlb_178_device = { const device_t ide_cmd640_vlb_178_device = {
.name = "CMD PCI-0640B VLB (Port 178h)", .name = "CMD PCI-0640B VLB (Port 178h)",
.internal_name = "ide_cmd640_vlb_178", .internal_name = "ide_cmd640_vlb_178",
.flags = DEVICE_VLB, .flags = DEVICE_VLB,
.local = 0x0178, .local = 0x0178,
.init = cmd640_init, .init = cmd640_init,
.close = cmd640_close, .close = cmd640_close,
.reset = cmd640_reset, .reset = cmd640_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t ide_cmd640_pci_device = { const device_t ide_cmd640_pci_device = {
.name = "CMD PCI-0640B PCI", .name = "CMD PCI-0640B PCI",
.internal_name = "ide_cmd640_pci", .internal_name = "ide_cmd640_pci",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0x0a, .local = 0x0a,
.init = cmd640_init, .init = cmd640_init,
.close = cmd640_close, .close = cmd640_close,
.reset = cmd640_reset, .reset = cmd640_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t ide_cmd640_pci_legacy_only_device = { const device_t ide_cmd640_pci_legacy_only_device = {
.name = "CMD PCI-0640B PCI (Legacy Mode Only)", .name = "CMD PCI-0640B PCI (Legacy Mode Only)",
.internal_name = "ide_cmd640_pci_legacy_only", .internal_name = "ide_cmd640_pci_legacy_only",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0x00, .local = 0x00,
.init = cmd640_init, .init = cmd640_init,
.close = cmd640_close, .close = cmd640_close,
.reset = cmd640_reset, .reset = cmd640_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t ide_cmd640_pci_single_channel_device = { const device_t ide_cmd640_pci_single_channel_device = {
.name = "CMD PCI-0640B PCI", .name = "CMD PCI-0640B PCI",
.internal_name = "ide_cmd640_pci_single_channel", .internal_name = "ide_cmd640_pci_single_channel",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0x2000a, .local = 0x2000a,
.init = cmd640_init, .init = cmd640_init,
.close = cmd640_close, .close = cmd640_close,
.reset = cmd640_reset, .reset = cmd640_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };

View File

@@ -37,18 +37,16 @@
#include <86box/zip.h> #include <86box/zip.h>
#include <86box/mo.h> #include <86box/mo.h>
typedef struct typedef struct
{ {
uint8_t vlb_idx, single_channel, uint8_t vlb_idx, single_channel,
in_cfg, regs[256]; in_cfg, regs[256];
uint32_t local; uint32_t local;
int slot, irq_mode[2], int slot, irq_mode[2],
irq_pin; irq_pin;
sff8038i_t *bm[2]; sff8038i_t *bm[2];
} cmd646_t; } cmd646_t;
#ifdef ENABLE_CMD646_LOG #ifdef ENABLE_CMD646_LOG
int cmd646_do_log = ENABLE_CMD646_LOG; int cmd646_do_log = ENABLE_CMD646_LOG;
static void static void
@@ -56,39 +54,36 @@ cmd646_log(const char *fmt, ...)
{ {
va_list ap; va_list ap;
if (cmd646_do_log) if (cmd646_do_log) {
{ va_start(ap, fmt);
va_start(ap, fmt); pclog_ex(fmt, ap);
pclog_ex(fmt, ap); va_end(ap);
va_end(ap);
} }
} }
#else #else
#define cmd646_log(fmt, ...) # define cmd646_log(fmt, ...)
#endif #endif
static void static void
cmd646_set_irq(int channel, void *priv) cmd646_set_irq(int channel, void *priv)
{ {
cmd646_t *dev = (cmd646_t *) priv; cmd646_t *dev = (cmd646_t *) priv;
if (channel & 0x01) { if (channel & 0x01) {
if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) { if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) {
dev->regs[0x57] &= ~0x10; dev->regs[0x57] &= ~0x10;
dev->regs[0x57] |= (channel >> 2); dev->regs[0x57] |= (channel >> 2);
} }
} else { } else {
if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) { if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) {
dev->regs[0x50] &= ~0x04; dev->regs[0x50] &= ~0x04;
dev->regs[0x50] |= (channel >> 4); dev->regs[0x50] |= (channel >> 4);
} }
} }
sff_bus_master_set_irq(channel, dev->bm[channel & 0x01]); sff_bus_master_set_irq(channel, dev->bm[channel & 0x01]);
} }
static int static int
cmd646_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) cmd646_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv)
{ {
@@ -97,63 +92,60 @@ cmd646_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out,
return sff_bus_master_dma(channel, data, transfer_length, out, dev->bm[channel & 0x01]); return sff_bus_master_dma(channel, data, transfer_length, out, dev->bm[channel & 0x01]);
} }
static void static void
cmd646_ide_handlers(cmd646_t *dev) cmd646_ide_handlers(cmd646_t *dev)
{ {
uint16_t main, side; uint16_t main, side;
int irq_mode[2] = { 0, 0 }; int irq_mode[2] = { 0, 0 };
ide_pri_disable(); ide_pri_disable();
if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) { if ((dev->regs[0x09] & 0x01) && (dev->regs[0x50] & 0x40)) {
main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8); main = (dev->regs[0x11] << 8) | (dev->regs[0x10] & 0xf8);
side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2; side = ((dev->regs[0x15] << 8) | (dev->regs[0x14] & 0xfc)) + 2;
} else { } else {
main = 0x1f0; main = 0x1f0;
side = 0x3f6; side = 0x3f6;
} }
ide_set_base(0, main); ide_set_base(0, main);
ide_set_side(0, side); ide_set_side(0, side);
if (dev->regs[0x09] & 0x01) if (dev->regs[0x09] & 0x01)
irq_mode[0] = 1; irq_mode[0] = 1;
sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]); sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]); sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]);
if (dev->regs[0x04] & 0x01) if (dev->regs[0x04] & 0x01)
ide_pri_enable(); ide_pri_enable();
if (dev->single_channel) if (dev->single_channel)
return; return;
ide_sec_disable(); ide_sec_disable();
if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) { if ((dev->regs[0x09] & 0x04) && (dev->regs[0x50] & 0x40)) {
main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8); main = (dev->regs[0x19] << 8) | (dev->regs[0x18] & 0xf8);
side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2; side = ((dev->regs[0x1d] << 8) | (dev->regs[0x1c] & 0xfc)) + 2;
} else { } else {
main = 0x170; main = 0x170;
side = 0x376; side = 0x376;
} }
ide_set_base(1, main); ide_set_base(1, main);
ide_set_side(1, side); ide_set_side(1, side);
if (dev->regs[0x09] & 0x04) if (dev->regs[0x09] & 0x04)
irq_mode[1] = 1; irq_mode[1] = 1;
sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]); sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]); sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]);
if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08)) if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08))
ide_sec_enable(); ide_sec_enable();
} }
static void static void
cmd646_ide_bm_handlers(cmd646_t *dev) cmd646_ide_bm_handlers(cmd646_t *dev)
{ {
@@ -163,7 +155,6 @@ cmd646_ide_bm_handlers(cmd646_t *dev)
sff_bus_master_handler(dev->bm[1], (dev->regs[0x04] & 1), base + 8); sff_bus_master_handler(dev->bm[1], (dev->regs[0x04] & 1), base + 8);
} }
static void static void
cmd646_pci_write(int func, int addr, uint8_t val, void *priv) cmd646_pci_write(int func, int addr, uint8_t val, void *priv)
{ {
@@ -171,119 +162,124 @@ cmd646_pci_write(int func, int addr, uint8_t val, void *priv)
cmd646_log("[%04X:%08X] (%08X) cmd646_pci_write(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, val); cmd646_log("[%04X:%08X] (%08X) cmd646_pci_write(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, val);
if (func == 0x00) switch (addr) { if (func == 0x00)
case 0x04: switch (addr) {
dev->regs[addr] = (val & 0x45); case 0x04:
cmd646_ide_handlers(dev); dev->regs[addr] = (val & 0x45);
break; cmd646_ide_handlers(dev);
case 0x07: break;
dev->regs[addr] &= ~(val & 0xb1); case 0x07:
break; dev->regs[addr] &= ~(val & 0xb1);
case 0x09: break;
if ((dev->regs[addr] & 0x0a) == 0x0a) { case 0x09:
dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05); if ((dev->regs[addr] & 0x0a) == 0x0a) {
dev->irq_mode[0] = !!(val & 0x01); dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05);
dev->irq_mode[1] = !!(val & 0x04); dev->irq_mode[0] = !!(val & 0x01);
cmd646_ide_handlers(dev); dev->irq_mode[1] = !!(val & 0x04);
} cmd646_ide_handlers(dev);
break; }
case 0x10: break;
if (dev->regs[0x50] & 0x40) { case 0x10:
dev->regs[0x10] = (val & 0xf8) | 1; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x10] = (val & 0xf8) | 1;
} cmd646_ide_handlers(dev);
break; }
case 0x11: break;
if (dev->regs[0x50] & 0x40) { case 0x11:
dev->regs[0x11] = val; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x11] = val;
} cmd646_ide_handlers(dev);
break; }
case 0x14: break;
if (dev->regs[0x50] & 0x40) { case 0x14:
dev->regs[0x14] = (val & 0xfc) | 1; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x14] = (val & 0xfc) | 1;
} cmd646_ide_handlers(dev);
break; }
case 0x15: break;
if (dev->regs[0x50] & 0x40) { case 0x15:
dev->regs[0x15] = val; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x15] = val;
} cmd646_ide_handlers(dev);
break; }
case 0x18: break;
if (dev->regs[0x50] & 0x40) { case 0x18:
dev->regs[0x18] = (val & 0xf8) | 1; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x18] = (val & 0xf8) | 1;
} cmd646_ide_handlers(dev);
break; }
case 0x19: break;
if (dev->regs[0x50] & 0x40) { case 0x19:
dev->regs[0x19] = val; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x19] = val;
} cmd646_ide_handlers(dev);
break; }
case 0x1c: break;
if (dev->regs[0x50] & 0x40) { case 0x1c:
dev->regs[0x1c] = (val & 0xfc) | 1; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x1c] = (val & 0xfc) | 1;
} cmd646_ide_handlers(dev);
break; }
case 0x1d: break;
if (dev->regs[0x50] & 0x40) { case 0x1d:
dev->regs[0x1d] = val; if (dev->regs[0x50] & 0x40) {
cmd646_ide_handlers(dev); dev->regs[0x1d] = val;
} cmd646_ide_handlers(dev);
break; }
case 0x20: break;
dev->regs[0x20] = (val & 0xf0) | 1; case 0x20:
cmd646_ide_bm_handlers(dev); dev->regs[0x20] = (val & 0xf0) | 1;
break; cmd646_ide_bm_handlers(dev);
case 0x21: break;
dev->regs[0x21] = val; case 0x21:
cmd646_ide_bm_handlers(dev); dev->regs[0x21] = val;
break; cmd646_ide_bm_handlers(dev);
case 0x51: break;
dev->regs[addr] = val & 0xc8; case 0x51:
cmd646_ide_handlers(dev); dev->regs[addr] = val & 0xc8;
break; cmd646_ide_handlers(dev);
case 0x52: case 0x54: case 0x56: case 0x58: break;
case 0x59: case 0x5b: case 0x52:
dev->regs[addr] = val; case 0x54:
break; case 0x56:
case 0x53: case 0x55: case 0x58:
dev->regs[addr] = val & 0xc0; case 0x59:
break; case 0x5b:
case 0x57: dev->regs[addr] = val;
dev->regs[addr] = (dev->regs[addr] & 0x10) | (val & 0xcc); break;
break; case 0x53:
case 0x70 ... 0x77: case 0x55:
sff_bus_master_write(addr & 0x0f, val, dev->bm[0]); dev->regs[addr] = val & 0xc0;
break; break;
case 0x78 ... 0x7f: case 0x57:
sff_bus_master_write(addr & 0x0f, val, dev->bm[1]); dev->regs[addr] = (dev->regs[addr] & 0x10) | (val & 0xcc);
break; break;
} case 0x70 ... 0x77:
sff_bus_master_write(addr & 0x0f, val, dev->bm[0]);
break;
case 0x78 ... 0x7f:
sff_bus_master_write(addr & 0x0f, val, dev->bm[1]);
break;
}
} }
static uint8_t static uint8_t
cmd646_pci_read(int func, int addr, void *priv) cmd646_pci_read(int func, int addr, void *priv)
{ {
cmd646_t *dev = (cmd646_t *) priv; cmd646_t *dev = (cmd646_t *) priv;
uint8_t ret = 0xff; uint8_t ret = 0xff;
if (func == 0x00) { if (func == 0x00) {
ret = dev->regs[addr]; ret = dev->regs[addr];
if (addr == 0x50) if (addr == 0x50)
dev->regs[0x50] &= ~0x04; dev->regs[0x50] &= ~0x04;
else if (addr == 0x57) else if (addr == 0x57)
dev->regs[0x57] &= ~0x10; dev->regs[0x57] &= ~0x10;
else if ((addr >= 0x70) && (addr <= 0x77)) else if ((addr >= 0x70) && (addr <= 0x77))
ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]); ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]);
else if ((addr >= 0x78) && (addr <= 0x7f)) else if ((addr >= 0x78) && (addr <= 0x7f))
ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]); ret = sff_bus_master_read(addr & 0x0f, dev->bm[0]);
} }
cmd646_log("[%04X:%08X] (%08X) cmd646_pci_read(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, ret); cmd646_log("[%04X:%08X] (%08X) cmd646_pci_read(%i, %02X, %02X)\n", CS, cpu_state.pc, ESI, func, addr, ret);
@@ -291,77 +287,76 @@ cmd646_pci_read(int func, int addr, void *priv)
return ret; return ret;
} }
static void static void
cmd646_reset(void *priv) cmd646_reset(void *priv)
{ {
cmd646_t *dev = (cmd646_t *) priv; cmd646_t *dev = (cmd646_t *) priv;
int i = 0; int i = 0;
for (i = 0; i < CDROM_NUM; i++) { for (i = 0; i < CDROM_NUM; i++) {
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel < 4) && cdrom[i].priv)
(cdrom[i].ide_channel < 4) && cdrom[i].priv) scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
} }
for (i = 0; i < ZIP_NUM; i++) { for (i = 0; i < ZIP_NUM; i++) {
if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel < 4) && zip_drives[i].priv)
(zip_drives[i].ide_channel < 4) && zip_drives[i].priv) zip_reset((scsi_common_t *) zip_drives[i].priv);
zip_reset((scsi_common_t *) zip_drives[i].priv); }
for (i = 0; i < MO_NUM; i++) {
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel < 4) && mo_drives[i].priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
} }
for (i = 0; i < MO_NUM; i++) {
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) &&
(mo_drives[i].ide_channel < 4) && mo_drives[i].priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
}
cmd646_set_irq(0x00, priv); cmd646_set_irq(0x00, priv);
cmd646_set_irq(0x01, priv); cmd646_set_irq(0x01, priv);
memset(dev->regs, 0x00, sizeof(dev->regs)); memset(dev->regs, 0x00, sizeof(dev->regs));
dev->regs[0x00] = 0x95; /* CMD */ dev->regs[0x00] = 0x95; /* CMD */
dev->regs[0x01] = 0x10; dev->regs[0x01] = 0x10;
dev->regs[0x02] = 0x46; /* PCI-0646 */ dev->regs[0x02] = 0x46; /* PCI-0646 */
dev->regs[0x03] = 0x06; dev->regs[0x03] = 0x06;
dev->regs[0x04] = 0x00; dev->regs[0x04] = 0x00;
dev->regs[0x06] = 0x80; dev->regs[0x06] = 0x80;
dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */
dev->regs[0x09] = dev->local; /* Programming interface */ dev->regs[0x09] = dev->local; /* Programming interface */
dev->regs[0x0a] = 0x01; /* IDE controller */ dev->regs[0x0a] = 0x01; /* IDE controller */
dev->regs[0x0b] = 0x01; /* Mass storage controller */ dev->regs[0x0b] = 0x01; /* Mass storage controller */
if ((dev->local & 0xffff) == 0x8a) { if ((dev->local & 0xffff) == 0x8a) {
dev->regs[0x50] = 0x40; /* Enable Base address register R/W; dev->regs[0x50] = 0x40; /* Enable Base address register R/W;
If 0, they return 0 and are read-only 8 */ If 0, they return 0 and are read-only 8 */
/* Base addresses (1F0, 3F4, 170, 374) */ /* Base addresses (1F0, 3F4, 170, 374) */
dev->regs[0x10] = 0xf1; dev->regs[0x11] = 0x01; dev->regs[0x10] = 0xf1;
dev->regs[0x14] = 0xf5; dev->regs[0x15] = 0x03; dev->regs[0x11] = 0x01;
dev->regs[0x18] = 0x71; dev->regs[0x19] = 0x01; dev->regs[0x14] = 0xf5;
dev->regs[0x1c] = 0x75; dev->regs[0x1d] = 0x03; dev->regs[0x15] = 0x03;
dev->regs[0x18] = 0x71;
dev->regs[0x19] = 0x01;
dev->regs[0x1c] = 0x75;
dev->regs[0x1d] = 0x03;
} }
dev->regs[0x20] = 0x01; dev->regs[0x20] = 0x01;
dev->regs[0x3c] = 0x0e; /* IRQ 14 */ dev->regs[0x3c] = 0x0e; /* IRQ 14 */
dev->regs[0x3d] = 0x01; /* INTA */ dev->regs[0x3d] = 0x01; /* INTA */
dev->regs[0x3e] = 0x02; /* Min_Gnt */ dev->regs[0x3e] = 0x02; /* Min_Gnt */
dev->regs[0x3f] = 0x04; /* Max_Iat */ dev->regs[0x3f] = 0x04; /* Max_Iat */
if (!dev->single_channel) if (!dev->single_channel)
dev->regs[0x51] = 0x08; dev->regs[0x51] = 0x08;
dev->regs[0x57] = 0x0c; dev->regs[0x57] = 0x0c;
dev->regs[0x59] = 0x40; dev->regs[0x59] = 0x40;
dev->irq_mode[0] = dev->irq_mode[1] = 0; dev->irq_mode[0] = dev->irq_mode[1] = 0;
dev->irq_pin = PCI_INTA; dev->irq_pin = PCI_INTA;
cmd646_ide_handlers(dev); cmd646_ide_handlers(dev);
cmd646_ide_bm_handlers(dev); cmd646_ide_bm_handlers(dev);
} }
static void static void
cmd646_close(void *priv) cmd646_close(void *priv)
{ {
@@ -370,7 +365,6 @@ cmd646_close(void *priv)
free(dev); free(dev);
} }
static void * static void *
cmd646_init(const device_t *info) cmd646_init(const device_t *info)
{ {
@@ -387,18 +381,18 @@ cmd646_init(const device_t *info)
dev->bm[0] = device_add_inst(&sff8038i_device, 1); dev->bm[0] = device_add_inst(&sff8038i_device, 1);
if (!dev->single_channel) if (!dev->single_channel)
dev->bm[1] = device_add_inst(&sff8038i_device, 2); dev->bm[1] = device_add_inst(&sff8038i_device, 2);
ide_set_bus_master(0, cmd646_bus_master_dma, cmd646_set_irq, dev); ide_set_bus_master(0, cmd646_bus_master_dma, cmd646_set_irq, dev);
if (!dev->single_channel) if (!dev->single_channel)
ide_set_bus_master(1, cmd646_bus_master_dma, cmd646_set_irq, dev); ide_set_bus_master(1, cmd646_bus_master_dma, cmd646_set_irq, dev);
sff_set_irq_mode(dev->bm[0], 0, 0); sff_set_irq_mode(dev->bm[0], 0, 0);
sff_set_irq_mode(dev->bm[0], 1, 0); sff_set_irq_mode(dev->bm[0], 1, 0);
if (!dev->single_channel) { if (!dev->single_channel) {
sff_set_irq_mode(dev->bm[1], 0, 0); sff_set_irq_mode(dev->bm[1], 0, 0);
sff_set_irq_mode(dev->bm[1], 1, 0); sff_set_irq_mode(dev->bm[1], 1, 0);
} }
cmd646_reset(dev); cmd646_reset(dev);
@@ -407,43 +401,43 @@ cmd646_init(const device_t *info)
} }
const device_t ide_cmd646_device = { const device_t ide_cmd646_device = {
.name = "CMD PCI-0646", .name = "CMD PCI-0646",
.internal_name = "ide_cmd646", .internal_name = "ide_cmd646",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0x8a, .local = 0x8a,
.init = cmd646_init, .init = cmd646_init,
.close = cmd646_close, .close = cmd646_close,
.reset = cmd646_reset, .reset = cmd646_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t ide_cmd646_legacy_only_device = { const device_t ide_cmd646_legacy_only_device = {
.name = "CMD PCI-0646 (Legacy Mode Only)", .name = "CMD PCI-0646 (Legacy Mode Only)",
.internal_name = "ide_cmd646_legacy_only", .internal_name = "ide_cmd646_legacy_only",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0x80, .local = 0x80,
.init = cmd646_init, .init = cmd646_init,
.close = cmd646_close, .close = cmd646_close,
.reset = cmd646_reset, .reset = cmd646_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t ide_cmd646_single_channel_device = { const device_t ide_cmd646_single_channel_device = {
.name = "CMD PCI-0646", .name = "CMD PCI-0646",
.internal_name = "ide_cmd646_single_channel", .internal_name = "ide_cmd646_single_channel",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0x2008a, .local = 0x2008a,
.init = cmd646_init, .init = cmd646_init,
.close = cmd646_close, .close = cmd646_close,
.reset = cmd646_reset, .reset = cmd646_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };

View File

@@ -29,17 +29,14 @@
#include <86box/hdc.h> #include <86box/hdc.h>
#include <86box/hdc_ide.h> #include <86box/hdc_ide.h>
typedef struct typedef struct
{ {
uint8_t tries, uint8_t tries,
in_cfg, cfg_locked, in_cfg, cfg_locked,
regs[19]; regs[19];
} opti611_t; } opti611_t;
static void opti611_ide_handler(opti611_t *dev);
static void opti611_ide_handler(opti611_t *dev);
static void static void
opti611_cfg_write(uint16_t addr, uint8_t val, void *priv) opti611_cfg_write(uint16_t addr, uint8_t val, void *priv)
@@ -49,32 +46,31 @@ opti611_cfg_write(uint16_t addr, uint8_t val, void *priv)
addr &= 0x0007; addr &= 0x0007;
switch (addr) { switch (addr) {
case 0x0000: case 0x0000:
case 0x0001: case 0x0001:
dev->regs[((dev->regs[0x06] & 0x01) << 4) + addr] = val; dev->regs[((dev->regs[0x06] & 0x01) << 4) + addr] = val;
break; break;
case 0x0002: case 0x0002:
dev->regs[0x12] = (val & 0xc1) | 0x02; dev->regs[0x12] = (val & 0xc1) | 0x02;
if (val & 0xc0) { if (val & 0xc0) {
if (val & 0x40) if (val & 0x40)
dev->cfg_locked = 1; dev->cfg_locked = 1;
dev->in_cfg = 0; dev->in_cfg = 0;
opti611_ide_handler(dev); opti611_ide_handler(dev);
} }
break; break;
case 0x0003: case 0x0003:
dev->regs[0x03] = (val & 0xdf); dev->regs[0x03] = (val & 0xdf);
break; break;
case 0x0005: case 0x0005:
dev->regs[0x05] = (dev->regs[0x05] & 0x78) | (val & 0x87); dev->regs[0x05] = (dev->regs[0x05] & 0x78) | (val & 0x87);
break; break;
case 0x0006: case 0x0006:
dev->regs[0x06] = val; dev->regs[0x06] = val;
break; break;
} }
} }
static void static void
opti611_cfg_writew(uint16_t addr, uint16_t val, void *priv) opti611_cfg_writew(uint16_t addr, uint16_t val, void *priv)
{ {
@@ -82,7 +78,6 @@ opti611_cfg_writew(uint16_t addr, uint16_t val, void *priv)
opti611_cfg_write(addr + 1, val >> 8, priv); opti611_cfg_write(addr + 1, val >> 8, priv);
} }
static void static void
opti611_cfg_writel(uint16_t addr, uint32_t val, void *priv) opti611_cfg_writel(uint16_t addr, uint32_t val, void *priv)
{ {
@@ -90,34 +85,35 @@ opti611_cfg_writel(uint16_t addr, uint32_t val, void *priv)
opti611_cfg_writew(addr + 2, val >> 16, priv); opti611_cfg_writew(addr + 2, val >> 16, priv);
} }
static uint8_t static uint8_t
opti611_cfg_read(uint16_t addr, void *priv) opti611_cfg_read(uint16_t addr, void *priv)
{ {
uint8_t ret = 0xff; uint8_t ret = 0xff;
opti611_t *dev = (opti611_t *) priv; opti611_t *dev = (opti611_t *) priv;
addr &= 0x0007; addr &= 0x0007;
switch (addr) { switch (addr) {
case 0x0000: case 0x0000:
case 0x0001: case 0x0001:
ret = dev->regs[((dev->regs[0x06] & 0x01) << 4) + addr]; ret = dev->regs[((dev->regs[0x06] & 0x01) << 4) + addr];
break; break;
case 0x0002: case 0x0002:
ret = ((!!in_smm) << 7); ret = ((!!in_smm) << 7);
if (ret & 0x80) if (ret & 0x80)
ret |= (dev->regs[addr] & 0x7f); ret |= (dev->regs[addr] & 0x7f);
break; break;
case 0x0003: case 0x0004: case 0x0005: case 0x0006: case 0x0003:
ret = dev->regs[addr]; case 0x0004:
break; case 0x0005:
case 0x0006:
ret = dev->regs[addr];
break;
} }
return ret; return ret;
} }
static uint16_t static uint16_t
opti611_cfg_readw(uint16_t addr, void *priv) opti611_cfg_readw(uint16_t addr, void *priv)
{ {
@@ -129,7 +125,6 @@ opti611_cfg_readw(uint16_t addr, void *priv)
return ret; return ret;
} }
static uint32_t static uint32_t
opti611_cfg_readl(uint16_t addr, void *priv) opti611_cfg_readl(uint16_t addr, void *priv)
{ {
@@ -141,7 +136,6 @@ opti611_cfg_readl(uint16_t addr, void *priv)
return ret; return ret;
} }
static void static void
opti611_ide_write(uint16_t addr, uint8_t val, void *priv) opti611_ide_write(uint16_t addr, uint8_t val, void *priv)
{ {
@@ -152,13 +146,12 @@ opti611_ide_write(uint16_t addr, uint8_t val, void *priv)
uint8_t smibe = (addr & 0x0003); uint8_t smibe = (addr & 0x0003);
if (dev->regs[0x03] & 0x02) { if (dev->regs[0x03] & 0x02) {
smi_raise(); smi_raise();
dev->regs[0x02] = smia9 | smia2 | smibe; dev->regs[0x02] = smia9 | smia2 | smibe;
dev->regs[0x04] = val; dev->regs[0x04] = val;
} }
} }
static void static void
opti611_ide_writew(uint16_t addr, uint16_t val, void *priv) opti611_ide_writew(uint16_t addr, uint16_t val, void *priv)
{ {
@@ -169,13 +162,12 @@ opti611_ide_writew(uint16_t addr, uint16_t val, void *priv)
uint8_t smibe = (addr & 0x0002) | 0x0001; uint8_t smibe = (addr & 0x0002) | 0x0001;
if (dev->regs[0x03] & 0x02) { if (dev->regs[0x03] & 0x02) {
smi_raise(); smi_raise();
dev->regs[0x02] = smia9 | smia2 | smibe; dev->regs[0x02] = smia9 | smia2 | smibe;
dev->regs[0x04] = 0x00; dev->regs[0x04] = 0x00;
} }
} }
static void static void
opti611_ide_writel(uint16_t addr, uint32_t val, void *priv) opti611_ide_writel(uint16_t addr, uint32_t val, void *priv)
{ {
@@ -185,13 +177,12 @@ opti611_ide_writel(uint16_t addr, uint32_t val, void *priv)
uint8_t smia2 = (!!(addr & 0x0004)) << 4; uint8_t smia2 = (!!(addr & 0x0004)) << 4;
if (dev->regs[0x03] & 0x02) { if (dev->regs[0x03] & 0x02) {
smi_raise(); smi_raise();
dev->regs[0x02] = smia9 | smia2 | 0x0003; dev->regs[0x02] = smia9 | smia2 | 0x0003;
dev->regs[0x04] = 0x00; dev->regs[0x04] = 0x00;
} }
} }
static uint8_t static uint8_t
opti611_ide_read(uint16_t addr, void *priv) opti611_ide_read(uint16_t addr, void *priv)
{ {
@@ -202,15 +193,14 @@ opti611_ide_read(uint16_t addr, void *priv)
uint8_t smibe = (addr & 0x0003); uint8_t smibe = (addr & 0x0003);
if (dev->regs[0x03] & 0x02) { if (dev->regs[0x03] & 0x02) {
smi_raise(); smi_raise();
dev->regs[0x02] = smia9 | smia2 | smibe; dev->regs[0x02] = smia9 | smia2 | smibe;
dev->regs[0x04] = 0x00; dev->regs[0x04] = 0x00;
} }
return 0xff; return 0xff;
} }
static uint16_t static uint16_t
opti611_ide_readw(uint16_t addr, void *priv) opti611_ide_readw(uint16_t addr, void *priv)
{ {
@@ -221,23 +211,22 @@ opti611_ide_readw(uint16_t addr, void *priv)
uint8_t smibe = (addr & 0x0002) | 0x0001; uint8_t smibe = (addr & 0x0002) | 0x0001;
if ((addr & 0x0007) == 0x0001) { if ((addr & 0x0007) == 0x0001) {
dev->tries = (dev->tries + 1) & 0x01; dev->tries = (dev->tries + 1) & 0x01;
if ((dev->tries == 0x00) && !dev->cfg_locked) { if ((dev->tries == 0x00) && !dev->cfg_locked) {
dev->in_cfg = 1; dev->in_cfg = 1;
opti611_ide_handler(dev); opti611_ide_handler(dev);
} }
} }
if (dev->regs[0x03] & 0x02) { if (dev->regs[0x03] & 0x02) {
smi_raise(); smi_raise();
dev->regs[0x02] = smia9 | smia2 | smibe; dev->regs[0x02] = smia9 | smia2 | smibe;
dev->regs[0x04] = 0x00; dev->regs[0x04] = 0x00;
} }
return 0xffff; return 0xffff;
} }
static uint32_t static uint32_t
opti611_ide_readl(uint16_t addr, void *priv) opti611_ide_readl(uint16_t addr, void *priv)
{ {
@@ -247,44 +236,42 @@ opti611_ide_readl(uint16_t addr, void *priv)
uint8_t smia2 = (!!(addr & 0x0004)) << 4; uint8_t smia2 = (!!(addr & 0x0004)) << 4;
if (dev->regs[0x03] & 0x02) { if (dev->regs[0x03] & 0x02) {
smi_raise(); smi_raise();
dev->regs[0x02] = smia9 | smia2 | 0x0003; dev->regs[0x02] = smia9 | smia2 | 0x0003;
dev->regs[0x04] = 0x00; dev->regs[0x04] = 0x00;
} }
return 0xffffffff; return 0xffffffff;
} }
static void static void
opti611_ide_handler(opti611_t *dev) opti611_ide_handler(opti611_t *dev)
{ {
ide_pri_disable(); ide_pri_disable();
io_removehandler(0x01f0, 0x0007, io_removehandler(0x01f0, 0x0007,
opti611_ide_read, opti611_ide_readw, opti611_ide_readl, opti611_ide_read, opti611_ide_readw, opti611_ide_readl,
opti611_ide_write, opti611_ide_writew, opti611_ide_writel, opti611_ide_write, opti611_ide_writew, opti611_ide_writel,
dev); dev);
io_removehandler(0x01f0, 0x0007, io_removehandler(0x01f0, 0x0007,
opti611_cfg_read, opti611_cfg_readw, opti611_cfg_readl, opti611_cfg_read, opti611_cfg_readw, opti611_cfg_readl,
opti611_cfg_write, opti611_cfg_writew, opti611_cfg_writel, opti611_cfg_write, opti611_cfg_writew, opti611_cfg_writel,
dev); dev);
if (dev->in_cfg && !dev->cfg_locked) { if (dev->in_cfg && !dev->cfg_locked) {
io_sethandler(0x01f0, 0x0007, io_sethandler(0x01f0, 0x0007,
opti611_cfg_read, opti611_cfg_readw, opti611_cfg_readl, opti611_cfg_read, opti611_cfg_readw, opti611_cfg_readl,
opti611_cfg_write, opti611_cfg_writew, opti611_cfg_writel, opti611_cfg_write, opti611_cfg_writew, opti611_cfg_writel,
dev); dev);
} else { } else {
if (dev->regs[0x03] & 0x01) if (dev->regs[0x03] & 0x01)
ide_pri_enable(); ide_pri_enable();
io_sethandler(0x01f0, 0x0007, io_sethandler(0x01f0, 0x0007,
opti611_ide_read, opti611_ide_readw, opti611_ide_readl, opti611_ide_read, opti611_ide_readw, opti611_ide_readl,
opti611_ide_write, opti611_ide_writew, opti611_ide_writel, opti611_ide_write, opti611_ide_writew, opti611_ide_writel,
dev); dev);
} }
} }
static void static void
opti611_close(void *priv) opti611_close(void *priv)
{ {
@@ -293,7 +280,6 @@ opti611_close(void *priv)
free(dev); free(dev);
} }
static void * static void *
opti611_init(const device_t *info) opti611_init(const device_t *info)
{ {
@@ -312,15 +298,15 @@ opti611_init(const device_t *info)
} }
const device_t ide_opti611_vlb_device = { const device_t ide_opti611_vlb_device = {
.name = "OPTi 82C611/82C611A VLB", .name = "OPTi 82C611/82C611A VLB",
.internal_name = "ide_opti611_vlb", .internal_name = "ide_opti611_vlb",
.flags = DEVICE_VLB, .flags = DEVICE_VLB,
.local = 0, .local = 0,
.init = opti611_init, .init = opti611_init,
.close = opti611_close, .close = opti611_close,
.reset = NULL, .reset = NULL,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };

View File

@@ -43,75 +43,68 @@
#include <86box/zip.h> #include <86box/zip.h>
#include <86box/mo.h> #include <86box/mo.h>
static int next_id = 0;
static int next_id = 0; uint8_t sff_bus_master_read(uint16_t port, void *priv);
static uint16_t sff_bus_master_readw(uint16_t port, void *priv);
static uint32_t sff_bus_master_readl(uint16_t port, void *priv);
uint8_t sff_bus_master_read(uint16_t port, void *priv); void sff_bus_master_write(uint16_t port, uint8_t val, void *priv);
static uint16_t sff_bus_master_readw(uint16_t port, void *priv); static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv);
static uint32_t sff_bus_master_readl(uint16_t port, void *priv); static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv);
void sff_bus_master_write(uint16_t port, uint8_t val, void *priv);
static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv);
static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv);
#ifdef ENABLE_SFF_LOG #ifdef ENABLE_SFF_LOG
int sff_do_log = ENABLE_SFF_LOG; int sff_do_log = ENABLE_SFF_LOG;
static void static void
sff_log(const char *fmt, ...) sff_log(const char *fmt, ...)
{ {
va_list ap; va_list ap;
if (sff_do_log) { if (sff_do_log) {
va_start(ap, fmt); va_start(ap, fmt);
pclog_ex(fmt, ap); pclog_ex(fmt, ap);
va_end(ap); va_end(ap);
} }
} }
#else #else
#define sff_log(fmt, ...) # define sff_log(fmt, ...)
#endif #endif
void void
sff_bus_master_handler(sff8038i_t *dev, int enabled, uint16_t base) sff_bus_master_handler(sff8038i_t *dev, int enabled, uint16_t base)
{ {
if (dev->base != 0x0000) { if (dev->base != 0x0000) {
io_removehandler(dev->base, 0x08, io_removehandler(dev->base, 0x08,
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
dev); dev);
} }
if (enabled && (base != 0x0000)) { if (enabled && (base != 0x0000)) {
io_sethandler(base, 0x08, io_sethandler(base, 0x08,
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
dev); dev);
} }
dev->enabled = enabled; dev->enabled = enabled;
dev->base = base; dev->base = base;
} }
static void static void
sff_bus_master_next_addr(sff8038i_t *dev) sff_bus_master_next_addr(sff8038i_t *dev)
{ {
dma_bm_read(dev->ptr_cur, (uint8_t *)&(dev->addr), 4, 4); dma_bm_read(dev->ptr_cur, (uint8_t *) &(dev->addr), 4, 4);
dma_bm_read(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4, 4); dma_bm_read(dev->ptr_cur + 4, (uint8_t *) &(dev->count), 4, 4);
sff_log("SFF-8038i Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); sff_log("SFF-8038i Bus master DWORDs: %08X %08X\n", dev->addr, dev->count);
dev->eot = dev->count >> 31; dev->eot = dev->count >> 31;
dev->count &= 0xfffe; dev->count &= 0xfffe;
if (!dev->count) if (!dev->count)
dev->count = 65536; dev->count = 65536;
dev->addr &= 0xfffffffe; dev->addr &= 0xfffffffe;
dev->ptr_cur += 8; dev->ptr_cur += 8;
} }
void void
sff_bus_master_write(uint16_t port, uint8_t val, void *priv) sff_bus_master_write(uint16_t port, uint8_t val, void *priv)
{ {
@@ -123,54 +116,53 @@ sff_bus_master_write(uint16_t port, uint8_t val, void *priv)
sff_log("SFF-8038i Bus master BYTE write: %04X %02X\n", port, val); sff_log("SFF-8038i Bus master BYTE write: %04X %02X\n", port, val);
switch (port & 7) { switch (port & 7) {
case 0: case 0:
sff_log("sff Cmd : val = %02X, old = %02X\n", val, dev->command); sff_log("sff Cmd : val = %02X, old = %02X\n", val, dev->command);
if ((val & 1) && !(dev->command & 1)) { /*Start*/ if ((val & 1) && !(dev->command & 1)) { /*Start*/
sff_log("sff Bus Master start on channel %i\n", channel); sff_log("sff Bus Master start on channel %i\n", channel);
dev->ptr_cur = dev->ptr; dev->ptr_cur = dev->ptr;
sff_bus_master_next_addr(dev); sff_bus_master_next_addr(dev);
dev->status |= 1; dev->status |= 1;
} }
if (!(val & 1) && (dev->command & 1)) { /*Stop*/ if (!(val & 1) && (dev->command & 1)) { /*Stop*/
sff_log("sff Bus Master stop on channel %i\n", channel); sff_log("sff Bus Master stop on channel %i\n", channel);
dev->status &= ~1; dev->status &= ~1;
} }
dev->command = val; dev->command = val;
break; break;
case 1: case 1:
dev->dma_mode = val & 0x03; dev->dma_mode = val & 0x03;
break; break;
case 2: case 2:
sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status); sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status);
dev->status &= 0x07; dev->status &= 0x07;
dev->status |= (val & 0x60); dev->status |= (val & 0x60);
if (val & 0x04) if (val & 0x04)
dev->status &= ~0x04; dev->status &= ~0x04;
if (val & 0x02) if (val & 0x02)
dev->status &= ~0x02; dev->status &= ~0x02;
break; break;
case 4: case 4:
dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
dev->ptr0 = val; dev->ptr0 = val;
break; break;
case 5: case 5:
dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
break; break;
case 6: case 6:
dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
break; break;
case 7: case 7:
dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
break; break;
} }
} }
static void static void
sff_bus_master_writew(uint16_t port, uint16_t val, void *priv) sff_bus_master_writew(uint16_t port, uint16_t val, void *priv)
{ {
@@ -179,24 +171,23 @@ sff_bus_master_writew(uint16_t port, uint16_t val, void *priv)
sff_log("SFF-8038i Bus master WORD write: %04X %04X\n", port, val); sff_log("SFF-8038i Bus master WORD write: %04X %04X\n", port, val);
switch (port & 7) { switch (port & 7) {
case 0: case 0:
case 1: case 1:
case 2: case 2:
sff_bus_master_write(port, val & 0xff, priv); sff_bus_master_write(port, val & 0xff, priv);
break; break;
case 4: case 4:
dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
dev->ptr0 = val & 0xff; dev->ptr0 = val & 0xff;
break; break;
case 6: case 6:
dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
break; break;
} }
} }
static void static void
sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) sff_bus_master_writel(uint16_t port, uint32_t val, void *priv)
{ {
@@ -205,20 +196,19 @@ sff_bus_master_writel(uint16_t port, uint32_t val, void *priv)
sff_log("SFF-8038i Bus master DWORD write: %04X %08X\n", port, val); sff_log("SFF-8038i Bus master DWORD write: %04X %08X\n", port, val);
switch (port & 7) { switch (port & 7) {
case 0: case 0:
case 1: case 1:
case 2: case 2:
sff_bus_master_write(port, val & 0xff, priv); sff_bus_master_write(port, val & 0xff, priv);
break; break;
case 4: case 4:
dev->ptr = (val & 0xfffffffc); dev->ptr = (val & 0xfffffffc);
dev->ptr %= (mem_size * 1024); dev->ptr %= (mem_size * 1024);
dev->ptr0 = val & 0xff; dev->ptr0 = val & 0xff;
break; break;
} }
} }
uint8_t uint8_t
sff_bus_master_read(uint16_t port, void *priv) sff_bus_master_read(uint16_t port, void *priv)
{ {
@@ -227,27 +217,27 @@ sff_bus_master_read(uint16_t port, void *priv)
uint8_t ret = 0xff; uint8_t ret = 0xff;
switch (port & 7) { switch (port & 7) {
case 0: case 0:
ret = dev->command; ret = dev->command;
break; break;
case 1: case 1:
ret = dev->dma_mode & 0x03; ret = dev->dma_mode & 0x03;
break; break;
case 2: case 2:
ret = dev->status & 0x67; ret = dev->status & 0x67;
break; break;
case 4: case 4:
ret = dev->ptr0; ret = dev->ptr0;
break; break;
case 5: case 5:
ret = dev->ptr >> 8; ret = dev->ptr >> 8;
break; break;
case 6: case 6:
ret = dev->ptr >> 16; ret = dev->ptr >> 16;
break; break;
case 7: case 7:
ret = dev->ptr >> 24; ret = dev->ptr >> 24;
break; break;
} }
sff_log("SFF-8038i Bus master BYTE read : %04X %02X\n", port, ret); sff_log("SFF-8038i Bus master BYTE read : %04X %02X\n", port, ret);
@@ -255,7 +245,6 @@ sff_bus_master_read(uint16_t port, void *priv)
return ret; return ret;
} }
static uint16_t static uint16_t
sff_bus_master_readw(uint16_t port, void *priv) sff_bus_master_readw(uint16_t port, void *priv)
{ {
@@ -264,17 +253,17 @@ sff_bus_master_readw(uint16_t port, void *priv)
uint16_t ret = 0xffff; uint16_t ret = 0xffff;
switch (port & 7) { switch (port & 7) {
case 0: case 0:
case 1: case 1:
case 2: case 2:
ret = (uint16_t) sff_bus_master_read(port, priv); ret = (uint16_t) sff_bus_master_read(port, priv);
break; break;
case 4: case 4:
ret = dev->ptr0 | (dev->ptr & 0xff00); ret = dev->ptr0 | (dev->ptr & 0xff00);
break; break;
case 6: case 6:
ret = dev->ptr >> 16; ret = dev->ptr >> 16;
break; break;
} }
sff_log("SFF-8038i Bus master WORD read : %04X %04X\n", port, ret); sff_log("SFF-8038i Bus master WORD read : %04X %04X\n", port, ret);
@@ -282,7 +271,6 @@ sff_bus_master_readw(uint16_t port, void *priv)
return ret; return ret;
} }
static uint32_t static uint32_t
sff_bus_master_readl(uint16_t port, void *priv) sff_bus_master_readl(uint16_t port, void *priv)
{ {
@@ -291,14 +279,14 @@ sff_bus_master_readl(uint16_t port, void *priv)
uint32_t ret = 0xffffffff; uint32_t ret = 0xffffffff;
switch (port & 7) { switch (port & 7) {
case 0: case 0:
case 1: case 1:
case 2: case 2:
ret = (uint32_t) sff_bus_master_read(port, priv); ret = (uint32_t) sff_bus_master_read(port, priv);
break; break;
case 4: case 4:
ret = dev->ptr0 | (dev->ptr & 0xffffff00); ret = dev->ptr0 | (dev->ptr & 0xffffff00);
break; break;
} }
sff_log("sff Bus master DWORD read : %04X %08X\n", port, ret); sff_log("sff Bus master DWORD read : %04X %08X\n", port, ret);
@@ -306,7 +294,6 @@ sff_bus_master_readl(uint16_t port, void *priv)
return ret; return ret;
} }
int int
sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv)
{ {
@@ -322,141 +309,138 @@ sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, voi
#endif #endif
if (!(dev->status & 1)) { if (!(dev->status & 1)) {
sff_log("DMA disabled\n"); sff_log("DMA disabled\n");
return 2; /*DMA disabled*/ return 2; /*DMA disabled*/
} }
sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length); sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length);
while (1) { while (1) {
if (dev->count <= transfer_length) { if (dev->count <= transfer_length) {
sff_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); sff_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr);
if (out) if (out)
dma_bm_read(dev->addr, (uint8_t *)(data + buffer_pos), dev->count, 4); dma_bm_read(dev->addr, (uint8_t *) (data + buffer_pos), dev->count, 4);
else else
dma_bm_write(dev->addr, (uint8_t *)(data + buffer_pos), dev->count, 4); dma_bm_write(dev->addr, (uint8_t *) (data + buffer_pos), dev->count, 4);
transfer_length -= dev->count; transfer_length -= dev->count;
buffer_pos += dev->count; buffer_pos += dev->count;
} else { } else {
sff_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); sff_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr);
if (out) if (out)
dma_bm_read(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length, 4); dma_bm_read(dev->addr, (uint8_t *) (data + buffer_pos), transfer_length, 4);
else else
dma_bm_write(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length, 4); dma_bm_write(dev->addr, (uint8_t *) (data + buffer_pos), transfer_length, 4);
/* Increase addr and decrease count so that resumed transfers do not mess up. */ /* Increase addr and decrease count so that resumed transfers do not mess up. */
dev->addr += transfer_length; dev->addr += transfer_length;
dev->count -= transfer_length; dev->count -= transfer_length;
transfer_length = 0; transfer_length = 0;
force_end = 1; force_end = 1;
} }
if (force_end) { if (force_end) {
sff_log("Total transfer length smaller than sum of all blocks, partial block\n"); sff_log("Total transfer length smaller than sum of all blocks, partial block\n");
dev->status &= ~2; dev->status &= ~2;
return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */
} else { } else {
if (!transfer_length && !dev->eot) { if (!transfer_length && !dev->eot) {
sff_log("Total transfer length smaller than sum of all blocks, full block\n"); sff_log("Total transfer length smaller than sum of all blocks, full block\n");
dev->status &= ~2; dev->status &= ~2;
return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */
} else if (transfer_length && dev->eot) { } else if (transfer_length && dev->eot) {
sff_log("Total transfer length greater than sum of all blocks\n"); sff_log("Total transfer length greater than sum of all blocks\n");
dev->status |= 2; dev->status |= 2;
return 0; /* There is data left to transfer but we have reached EOT - return with error. */ return 0; /* There is data left to transfer but we have reached EOT - return with error. */
} else if (dev->eot) { } else if (dev->eot) {
sff_log("Regular EOT\n"); sff_log("Regular EOT\n");
dev->status &= ~3; dev->status &= ~3;
return 1; /* We have regularly reached EOT - clear status and break. */ return 1; /* We have regularly reached EOT - clear status and break. */
} else { } else {
/* We have more to transfer and there are blocks left, get next block. */ /* We have more to transfer and there are blocks left, get next block. */
sff_bus_master_next_addr(dev); sff_bus_master_next_addr(dev);
} }
} }
} }
return 1; return 1;
} }
void void
sff_bus_master_set_irq(int channel, void *priv) sff_bus_master_set_irq(int channel, void *priv)
{ {
sff8038i_t *dev = (sff8038i_t *) priv; sff8038i_t *dev = (sff8038i_t *) priv;
uint8_t irq = !!(channel & 0x40); uint8_t irq = !!(channel & 0x40);
if (!(dev->status & 0x04) || (channel & 0x40)) { if (!(dev->status & 0x04) || (channel & 0x40)) {
dev->status &= ~0x04; dev->status &= ~0x04;
dev->status |= (channel >> 4); dev->status |= (channel >> 4);
} }
channel &= 0x01; channel &= 0x01;
switch (dev->irq_mode[channel]) { switch (dev->irq_mode[channel]) {
case 0: case 0:
default: default:
/* Legacy IRQ mode. */ /* Legacy IRQ mode. */
if (irq) if (irq)
picint(1 << (14 + channel)); picint(1 << (14 + channel));
else else
picintc(1 << (14 + channel)); picintc(1 << (14 + channel));
break; break;
case 1: case 1:
/* Native PCI IRQ mode with interrupt pin. */ /* Native PCI IRQ mode with interrupt pin. */
if (irq) if (irq)
pci_set_irq(dev->slot, dev->irq_pin); pci_set_irq(dev->slot, dev->irq_pin);
else else
pci_clear_irq(dev->slot, dev->irq_pin); pci_clear_irq(dev->slot, dev->irq_pin);
break; break;
case 2: case 2:
case 5: case 5:
/* MIRQ 0 or 1. */ /* MIRQ 0 or 1. */
if (irq) if (irq)
pci_set_mirq(dev->irq_mode[channel] & 1, 0); pci_set_mirq(dev->irq_mode[channel] & 1, 0);
else else
pci_clear_mirq(dev->irq_mode[channel] & 1, 0); pci_clear_mirq(dev->irq_mode[channel] & 1, 0);
break; break;
case 3: case 3:
/* Native PCI IRQ mode with specified interrupt line. */ /* Native PCI IRQ mode with specified interrupt line. */
if (irq) if (irq)
picintlevel(1 << dev->irq_line); picintlevel(1 << dev->irq_line);
else else
picintc(1 << dev->irq_line); picintc(1 << dev->irq_line);
break; break;
case 4: case 4:
/* ALi Aladdin Native PCI INTAJ mode. */ /* ALi Aladdin Native PCI INTAJ mode. */
if (irq) if (irq)
pci_set_mirq(channel + 2, dev->irq_level[channel]); pci_set_mirq(channel + 2, dev->irq_level[channel]);
else else
pci_clear_mirq(channel + 2, dev->irq_level[channel]); pci_clear_mirq(channel + 2, dev->irq_level[channel]);
break; break;
} }
} }
void void
sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base) sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base)
{ {
if (dev->enabled) { if (dev->enabled) {
io_removehandler(old_base, 0x08, io_removehandler(old_base, 0x08,
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
dev); dev);
dev->enabled = 0; dev->enabled = 0;
} }
dev->command = 0x00; dev->command = 0x00;
dev->status = 0x00; dev->status = 0x00;
dev->ptr = dev->ptr_cur = 0x00000000; dev->ptr = dev->ptr_cur = 0x00000000;
dev->addr = 0x00000000; dev->addr = 0x00000000;
dev->ptr0 = 0x00; dev->ptr0 = 0x00;
dev->count = dev->eot = 0x00000000; dev->count = dev->eot = 0x00000000;
ide_pri_disable(); ide_pri_disable();
ide_sec_disable(); ide_sec_disable();
} }
static void static void
sff_reset(void *p) sff_reset(void *p)
{ {
@@ -467,116 +451,107 @@ sff_reset(void *p)
#endif #endif
for (i = 0; i < CDROM_NUM; i++) { for (i = 0; i < CDROM_NUM; i++) {
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel < 4) && cdrom[i].priv)
(cdrom[i].ide_channel < 4) && cdrom[i].priv) scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
} }
for (i = 0; i < ZIP_NUM; i++) { for (i = 0; i < ZIP_NUM; i++) {
if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel < 4) && zip_drives[i].priv)
(zip_drives[i].ide_channel < 4) && zip_drives[i].priv) zip_reset((scsi_common_t *) zip_drives[i].priv);
zip_reset((scsi_common_t *) zip_drives[i].priv); }
for (i = 0; i < MO_NUM; i++) {
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel < 4) && mo_drives[i].priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
} }
for (i = 0; i < MO_NUM; i++) {
if ((mo_drives[i].bus_type == MO_BUS_ATAPI) &&
(mo_drives[i].ide_channel < 4) && mo_drives[i].priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
}
sff_bus_master_set_irq(0x00, p); sff_bus_master_set_irq(0x00, p);
sff_bus_master_set_irq(0x01, p); sff_bus_master_set_irq(0x01, p);
} }
void void
sff_set_slot(sff8038i_t *dev, int slot) sff_set_slot(sff8038i_t *dev, int slot)
{ {
dev->slot = slot; dev->slot = slot;
} }
void void
sff_set_irq_line(sff8038i_t *dev, int irq_line) sff_set_irq_line(sff8038i_t *dev, int irq_line)
{ {
dev->irq_line = irq_line; dev->irq_line = irq_line;
} }
void void
sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level) sff_set_irq_level(sff8038i_t *dev, int channel, int irq_level)
{ {
dev->irq_level[channel] = 0; dev->irq_level[channel] = 0;
} }
void void
sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode) sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode)
{ {
dev->irq_mode[channel] = irq_mode; dev->irq_mode[channel] = irq_mode;
switch (dev->irq_mode[channel]) { switch (dev->irq_mode[channel]) {
case 0: case 0:
default: default:
/* Legacy IRQ mode. */ /* Legacy IRQ mode. */
sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel); sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel);
break; break;
case 1: case 1:
/* Native PCI IRQ mode with interrupt pin. */ /* Native PCI IRQ mode with interrupt pin. */
sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin); sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin);
break; break;
case 2: case 2:
case 5: case 5:
/* MIRQ 0 or 1. */ /* MIRQ 0 or 1. */
sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1); sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1);
break; break;
case 3: case 3:
/* Native PCI IRQ mode with specified interrupt line. */ /* Native PCI IRQ mode with specified interrupt line. */
sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line); sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line);
break; break;
case 4: case 4:
/* ALi Aladdin Native PCI INTAJ mode. */ /* ALi Aladdin Native PCI INTAJ mode. */
sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel); sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel);
break; break;
} }
} }
void void
sff_set_irq_pin(sff8038i_t *dev, int irq_pin) sff_set_irq_pin(sff8038i_t *dev, int irq_pin)
{ {
dev->irq_pin = irq_pin; dev->irq_pin = irq_pin;
} }
static void static void
sff_close(void *p) sff_close(void *p)
{ {
sff8038i_t *dev = (sff8038i_t *)p; sff8038i_t *dev = (sff8038i_t *) p;
free(dev); free(dev);
next_id--; next_id--;
if (next_id < 0) if (next_id < 0)
next_id = 0; next_id = 0;
} }
static void static void
*sff_init(const device_t *info) *
sff_init(const device_t *info)
{ {
sff8038i_t *dev = (sff8038i_t *) malloc(sizeof(sff8038i_t)); sff8038i_t *dev = (sff8038i_t *) malloc(sizeof(sff8038i_t));
memset(dev, 0, sizeof(sff8038i_t)); memset(dev, 0, sizeof(sff8038i_t));
/* Make sure to only add IDE once. */ /* Make sure to only add IDE once. */
if (next_id == 0) if (next_id == 0)
device_add(&ide_pci_2ch_device); device_add(&ide_pci_2ch_device);
ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev);
dev->slot = 7; dev->slot = 7;
dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */ dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */
dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */ dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */
dev->irq_pin = PCI_INTA; dev->irq_pin = PCI_INTA;
dev->irq_line = 14; dev->irq_line = 14;
dev->irq_level[0] = dev->irq_level[1] = 0; dev->irq_level[0] = dev->irq_level[1] = 0;
next_id++; next_id++;
@@ -584,17 +559,16 @@ static void
return dev; return dev;
} }
const device_t sff8038i_device = const device_t sff8038i_device = {
{ .name = "SFF-8038i IDE Bus Master",
.name = "SFF-8038i IDE Bus Master",
.internal_name = "sff8038i", .internal_name = "sff8038i",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0, .local = 0,
.init = sff_init, .init = sff_init,
.close = sff_close, .close = sff_close,
.reset = sff_reset, .reset = sff_reset,
{ .available = NULL }, { .available = NULL },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -44,90 +44,85 @@
#include <86box/hdc.h> #include <86box/hdc.h>
#include <86box/hdc_ide.h> #include <86box/hdc_ide.h>
#define ROM_PATH_XT "roms/hdd/xtide/ide_xt.bin"
#define ROM_PATH_XT "roms/hdd/xtide/ide_xt.bin" #define ROM_PATH_AT "roms/hdd/xtide/ide_at.bin"
#define ROM_PATH_AT "roms/hdd/xtide/ide_at.bin" #define ROM_PATH_PS2 "roms/hdd/xtide/SIDE1V12.BIN"
#define ROM_PATH_PS2 "roms/hdd/xtide/SIDE1V12.BIN" #define ROM_PATH_PS2AT "roms/hdd/xtide/ide_at_1_1_5.bin"
#define ROM_PATH_PS2AT "roms/hdd/xtide/ide_at_1_1_5.bin" #define ROM_PATH_AT_386 "roms/hdd/xtide/ide_386.bin"
#define ROM_PATH_AT_386 "roms/hdd/xtide/ide_386.bin"
typedef struct { typedef struct {
void *ide_board; void *ide_board;
uint8_t data_high; uint8_t data_high;
rom_t bios_rom; rom_t bios_rom;
} xtide_t; } xtide_t;
static void static void
xtide_write(uint16_t port, uint8_t val, void *priv) xtide_write(uint16_t port, uint8_t val, void *priv)
{ {
xtide_t *xtide = (xtide_t *)priv; xtide_t *xtide = (xtide_t *) priv;
switch (port & 0xf) { switch (port & 0xf) {
case 0x0: case 0x0:
ide_writew(0x0, val | (xtide->data_high << 8), xtide->ide_board); ide_writew(0x0, val | (xtide->data_high << 8), xtide->ide_board);
return; return;
case 0x1: case 0x1:
case 0x2: case 0x2:
case 0x3: case 0x3:
case 0x4: case 0x4:
case 0x5: case 0x5:
case 0x6: case 0x6:
case 0x7: case 0x7:
ide_writeb((port & 0xf), val, xtide->ide_board); ide_writeb((port & 0xf), val, xtide->ide_board);
return; return;
case 0x8: case 0x8:
xtide->data_high = val; xtide->data_high = val;
return; return;
case 0xe: case 0xe:
ide_write_devctl(0x0, val, xtide->ide_board); ide_write_devctl(0x0, val, xtide->ide_board);
return; return;
} }
} }
static uint8_t static uint8_t
xtide_read(uint16_t port, void *priv) xtide_read(uint16_t port, void *priv)
{ {
xtide_t *xtide = (xtide_t *)priv; xtide_t *xtide = (xtide_t *) priv;
uint16_t tempw = 0xffff; uint16_t tempw = 0xffff;
switch (port & 0xf) { switch (port & 0xf) {
case 0x0: case 0x0:
tempw = ide_readw(0x0, xtide->ide_board); tempw = ide_readw(0x0, xtide->ide_board);
xtide->data_high = tempw >> 8; xtide->data_high = tempw >> 8;
break; break;
case 0x1: case 0x1:
case 0x2: case 0x2:
case 0x3: case 0x3:
case 0x4: case 0x4:
case 0x5: case 0x5:
case 0x6: case 0x6:
case 0x7: case 0x7:
tempw = ide_readb((port & 0xf), xtide->ide_board); tempw = ide_readb((port & 0xf), xtide->ide_board);
break; break;
case 0x8: case 0x8:
tempw = xtide->data_high; tempw = xtide->data_high;
break; break;
case 0xe: case 0xe:
tempw = ide_read_alt_status(0x0, xtide->ide_board); tempw = ide_read_alt_status(0x0, xtide->ide_board);
break; break;
default: default:
break; break;
} }
return(tempw & 0xff); return (tempw & 0xff);
} }
static void * static void *
xtide_init(const device_t *info) xtide_init(const device_t *info)
{ {
@@ -136,25 +131,23 @@ xtide_init(const device_t *info)
memset(xtide, 0x00, sizeof(xtide_t)); memset(xtide, 0x00, sizeof(xtide_t));
rom_init(&xtide->bios_rom, ROM_PATH_XT, rom_init(&xtide->bios_rom, ROM_PATH_XT,
0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
xtide->ide_board = ide_xtide_init(); xtide->ide_board = ide_xtide_init();
io_sethandler(0x0300, 16, io_sethandler(0x0300, 16,
xtide_read, NULL, NULL, xtide_read, NULL, NULL,
xtide_write, NULL, NULL, xtide); xtide_write, NULL, NULL, xtide);
return(xtide); return (xtide);
} }
static int static int
xtide_available(void) xtide_available(void)
{ {
return(rom_present(ROM_PATH_XT)); return (rom_present(ROM_PATH_XT));
} }
static void * static void *
xtide_at_init(const device_t *info) xtide_at_init(const device_t *info)
{ {
@@ -163,33 +156,30 @@ xtide_at_init(const device_t *info)
memset(xtide, 0x00, sizeof(xtide_t)); memset(xtide, 0x00, sizeof(xtide_t));
if (info->local == 1) { if (info->local == 1) {
rom_init(&xtide->bios_rom, ROM_PATH_AT_386, rom_init(&xtide->bios_rom, ROM_PATH_AT_386,
0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
} else { } else {
rom_init(&xtide->bios_rom, ROM_PATH_AT, rom_init(&xtide->bios_rom, ROM_PATH_AT,
0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
} }
device_add(&ide_isa_2ch_device); device_add(&ide_isa_2ch_device);
return(xtide); return (xtide);
} }
static int static int
xtide_at_available(void) xtide_at_available(void)
{ {
return(rom_present(ROM_PATH_AT)); return (rom_present(ROM_PATH_AT));
} }
static int static int
xtide_at_386_available(void) xtide_at_386_available(void)
{ {
return(rom_present(ROM_PATH_AT_386)); return (rom_present(ROM_PATH_AT_386));
} }
static void * static void *
xtide_acculogic_init(const device_t *info) xtide_acculogic_init(const device_t *info)
{ {
@@ -198,36 +188,33 @@ xtide_acculogic_init(const device_t *info)
memset(xtide, 0x00, sizeof(xtide_t)); memset(xtide, 0x00, sizeof(xtide_t));
rom_init(&xtide->bios_rom, ROM_PATH_PS2, rom_init(&xtide->bios_rom, ROM_PATH_PS2,
0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
xtide->ide_board = ide_xtide_init(); xtide->ide_board = ide_xtide_init();
io_sethandler(0x0360, 16, io_sethandler(0x0360, 16,
xtide_read, NULL, NULL, xtide_read, NULL, NULL,
xtide_write, NULL, NULL, xtide); xtide_write, NULL, NULL, xtide);
return(xtide); return (xtide);
} }
static int static int
xtide_acculogic_available(void) xtide_acculogic_available(void)
{ {
return(rom_present(ROM_PATH_PS2)); return (rom_present(ROM_PATH_PS2));
} }
static void static void
xtide_close(void *priv) xtide_close(void *priv)
{ {
xtide_t *xtide = (xtide_t *)priv; xtide_t *xtide = (xtide_t *) priv;
free(xtide); free(xtide);
ide_xtide_close(); ide_xtide_close();
} }
static void * static void *
xtide_at_ps2_init(const device_t *info) xtide_at_ps2_init(const device_t *info)
{ {
@@ -236,95 +223,93 @@ xtide_at_ps2_init(const device_t *info)
memset(xtide, 0x00, sizeof(xtide_t)); memset(xtide, 0x00, sizeof(xtide_t));
rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, rom_init(&xtide->bios_rom, ROM_PATH_PS2AT,
0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL);
device_add(&ide_isa_2ch_device); device_add(&ide_isa_2ch_device);
return(xtide); return (xtide);
} }
static int static int
xtide_at_ps2_available(void) xtide_at_ps2_available(void)
{ {
return(rom_present(ROM_PATH_PS2AT)); return (rom_present(ROM_PATH_PS2AT));
} }
static void static void
xtide_at_close(void *priv) xtide_at_close(void *priv)
{ {
xtide_t *xtide = (xtide_t *)priv; xtide_t *xtide = (xtide_t *) priv;
free(xtide); free(xtide);
} }
const device_t xtide_device = { const device_t xtide_device = {
.name = "PC/XT XTIDE", .name = "PC/XT XTIDE",
.internal_name = "xtide", .internal_name = "xtide",
.flags = DEVICE_ISA, .flags = DEVICE_ISA,
.local = 0, .local = 0,
.init = xtide_init, .init = xtide_init,
.close = xtide_close, .close = xtide_close,
.reset = NULL, .reset = NULL,
{ .available = xtide_available }, { .available = xtide_available },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t xtide_at_device = { const device_t xtide_at_device = {
.name = "PC/AT XTIDE", .name = "PC/AT XTIDE",
.internal_name = "xtide_at", .internal_name = "xtide_at",
.flags = DEVICE_ISA | DEVICE_AT, .flags = DEVICE_ISA | DEVICE_AT,
.local = 0, .local = 0,
.init = xtide_at_init, .init = xtide_at_init,
.close = xtide_at_close, .close = xtide_at_close,
.reset = NULL, .reset = NULL,
{ .available = xtide_at_available }, { .available = xtide_at_available },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t xtide_at_386_device = { const device_t xtide_at_386_device = {
.name = "PC/AT XTIDE (386)", .name = "PC/AT XTIDE (386)",
.internal_name = "xtide_at_386", .internal_name = "xtide_at_386",
.flags = DEVICE_ISA | DEVICE_AT, .flags = DEVICE_ISA | DEVICE_AT,
.local = 1, .local = 1,
.init = xtide_at_init, .init = xtide_at_init,
.close = xtide_at_close, .close = xtide_at_close,
.reset = NULL, .reset = NULL,
{ .available = xtide_at_386_available }, { .available = xtide_at_386_available },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t xtide_acculogic_device = { const device_t xtide_acculogic_device = {
.name = "Acculogic XT IDE", .name = "Acculogic XT IDE",
.internal_name = "xtide_acculogic", .internal_name = "xtide_acculogic",
.flags = DEVICE_ISA, .flags = DEVICE_ISA,
.local = 0, .local = 0,
.init = xtide_acculogic_init, .init = xtide_acculogic_init,
.close = xtide_close, .close = xtide_close,
.reset = NULL, .reset = NULL,
{ .available = xtide_acculogic_available }, { .available = xtide_acculogic_available },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };
const device_t xtide_at_ps2_device = { const device_t xtide_at_ps2_device = {
.name = "PS/2 AT XTIDE (1.1.5)", .name = "PS/2 AT XTIDE (1.1.5)",
.internal_name = "xtide_at_ps2", .internal_name = "xtide_at_ps2",
.flags = DEVICE_ISA | DEVICE_AT, .flags = DEVICE_ISA | DEVICE_AT,
.local = 0, .local = 0,
.init = xtide_at_ps2_init, .init = xtide_at_ps2_init,
.close = xtide_at_close, .close = xtide_at_close,
.reset = NULL, .reset = NULL,
{ .available = xtide_at_ps2_available }, { .available = xtide_at_ps2_available },
.speed_changed = NULL, .speed_changed = NULL,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };

View File

@@ -31,12 +31,9 @@
#include <86box/video.h> #include <86box/video.h>
#include "cpu.h" #include "cpu.h"
#define HDD_OVERHEAD_TIME 50.0 #define HDD_OVERHEAD_TIME 50.0
hard_disk_t hdd[HDD_NUM];
hard_disk_t hdd[HDD_NUM];
int int
hdd_init(void) hdd_init(void)
@@ -44,122 +41,119 @@ hdd_init(void)
/* Clear all global data. */ /* Clear all global data. */
memset(hdd, 0x00, sizeof(hdd)); memset(hdd, 0x00, sizeof(hdd));
return(0); return (0);
} }
int int
hdd_string_to_bus(char *str, int cdrom) hdd_string_to_bus(char *str, int cdrom)
{ {
if (! strcmp(str, "none")) if (!strcmp(str, "none"))
return(HDD_BUS_DISABLED); return (HDD_BUS_DISABLED);
if (! strcmp(str, "mfm") || ! strcmp(str, "rll")) { if (!strcmp(str, "mfm") || !strcmp(str, "rll")) {
if (cdrom) { if (cdrom) {
no_cdrom: no_cdrom:
ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2130, (wchar_t *) IDS_4099); ui_msgbox_header(MBX_ERROR, (wchar_t *) IDS_2130, (wchar_t *) IDS_4099);
return(0); return (0);
} }
return(HDD_BUS_MFM); return (HDD_BUS_MFM);
} }
/* FIXME: delete 'rll' in a year or so.. --FvK */ /* FIXME: delete 'rll' in a year or so.. --FvK */
if (!strcmp(str, "esdi") || !strcmp(str, "rll")) { if (!strcmp(str, "esdi") || !strcmp(str, "rll")) {
if (cdrom) goto no_cdrom; if (cdrom)
goto no_cdrom;
return(HDD_BUS_ESDI); return (HDD_BUS_ESDI);
} }
if (! strcmp(str, "ide_pio_only")) if (!strcmp(str, "ide_pio_only"))
return(HDD_BUS_IDE); return (HDD_BUS_IDE);
if (! strcmp(str, "ide")) if (!strcmp(str, "ide"))
return(HDD_BUS_IDE); return (HDD_BUS_IDE);
if (! strcmp(str, "atapi_pio_only")) if (!strcmp(str, "atapi_pio_only"))
return(HDD_BUS_ATAPI); return (HDD_BUS_ATAPI);
if (! strcmp(str, "atapi")) if (!strcmp(str, "atapi"))
return(HDD_BUS_ATAPI); return (HDD_BUS_ATAPI);
if (! strcmp(str, "eide")) if (!strcmp(str, "eide"))
return(HDD_BUS_IDE); return (HDD_BUS_IDE);
if (! strcmp(str, "xta")) if (!strcmp(str, "xta"))
return(HDD_BUS_XTA); return (HDD_BUS_XTA);
if (! strcmp(str, "atide")) if (!strcmp(str, "atide"))
return(HDD_BUS_IDE); return (HDD_BUS_IDE);
if (! strcmp(str, "ide_pio_and_dma")) if (!strcmp(str, "ide_pio_and_dma"))
return(HDD_BUS_IDE); return (HDD_BUS_IDE);
if (! strcmp(str, "atapi_pio_and_dma")) if (!strcmp(str, "atapi_pio_and_dma"))
return(HDD_BUS_ATAPI); return (HDD_BUS_ATAPI);
if (! strcmp(str, "scsi")) if (!strcmp(str, "scsi"))
return(HDD_BUS_SCSI); return (HDD_BUS_SCSI);
return(0); return (0);
} }
char * char *
hdd_bus_to_string(int bus, int cdrom) hdd_bus_to_string(int bus, int cdrom)
{ {
char *s = "none"; char *s = "none";
switch (bus) { switch (bus) {
case HDD_BUS_DISABLED: case HDD_BUS_DISABLED:
default: default:
break; break;
case HDD_BUS_MFM: case HDD_BUS_MFM:
s = "mfm"; s = "mfm";
break; break;
case HDD_BUS_XTA: case HDD_BUS_XTA:
s = "xta"; s = "xta";
break; break;
case HDD_BUS_ESDI: case HDD_BUS_ESDI:
s = "esdi"; s = "esdi";
break; break;
case HDD_BUS_IDE: case HDD_BUS_IDE:
s = "ide"; s = "ide";
break; break;
case HDD_BUS_ATAPI: case HDD_BUS_ATAPI:
s = "atapi"; s = "atapi";
break; break;
case HDD_BUS_SCSI: case HDD_BUS_SCSI:
s = "scsi"; s = "scsi";
break; break;
} }
return(s); return (s);
} }
int int
hdd_is_valid(int c) hdd_is_valid(int c)
{ {
if (hdd[c].bus == HDD_BUS_DISABLED) if (hdd[c].bus == HDD_BUS_DISABLED)
return(0); return (0);
if (strlen(hdd[c].fn) == 0) if (strlen(hdd[c].fn) == 0)
return(0); return (0);
if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0)) if ((hdd[c].tracks == 0) || (hdd[c].hpc == 0) || (hdd[c].spt == 0))
return(0); return (0);
return(1); return (1);
} }
double double
hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time) hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_t continuous, double max_seek_time)
{ {
@@ -168,121 +162,118 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_
hdd_zone_t *zone = NULL; hdd_zone_t *zone = NULL;
for (int i = 0; i < hdd->num_zones; i++) { for (int i = 0; i < hdd->num_zones; i++) {
zone = &hdd->zones[i]; zone = &hdd->zones[i];
if (zone->end_sector >= dst_addr) if (zone->end_sector >= dst_addr)
break; break;
} }
double continuous_times[2][2] = { { hdd->head_switch_usec, hdd->cyl_switch_usec }, double continuous_times[2][2] = {
{ zone->sector_time_usec, zone->sector_time_usec } }; {hdd->head_switch_usec, hdd->cyl_switch_usec },
{ zone->sector_time_usec, zone->sector_time_usec}
};
double times[2] = { HDD_OVERHEAD_TIME, hdd->avg_rotation_lat_usec }; double times[2] = { HDD_OVERHEAD_TIME, hdd->avg_rotation_lat_usec };
uint32_t new_track = zone->start_track + ((dst_addr - zone->start_sector) / zone->sectors_per_track); uint32_t new_track = zone->start_track + ((dst_addr - zone->start_sector) / zone->sectors_per_track);
uint32_t new_cylinder = new_track / hdd->phy_heads; uint32_t new_cylinder = new_track / hdd->phy_heads;
uint32_t cylinder_diff = abs((int)hdd->cur_cylinder - (int)new_cylinder); uint32_t cylinder_diff = abs((int) hdd->cur_cylinder - (int) new_cylinder);
bool sequential = dst_addr == hdd->cur_addr + 1; bool sequential = dst_addr == hdd->cur_addr + 1;
continuous = continuous && sequential; continuous = continuous && sequential;
double seek_time = 0.0; double seek_time = 0.0;
if (continuous) if (continuous)
seek_time = continuous_times[new_track == hdd->cur_track][!!cylinder_diff]; seek_time = continuous_times[new_track == hdd->cur_track][!!cylinder_diff];
else { else {
if (!cylinder_diff) if (!cylinder_diff)
seek_time = times[operation != HDD_OP_SEEK]; seek_time = times[operation != HDD_OP_SEEK];
else { else {
seek_time = hdd->cyl_switch_usec + (hdd->full_stroke_usec * (double)cylinder_diff / (double)hdd->phy_cyl) + seek_time = hdd->cyl_switch_usec + (hdd->full_stroke_usec * (double) cylinder_diff / (double) hdd->phy_cyl) + ((operation != HDD_OP_SEEK) * hdd->avg_rotation_lat_usec);
((operation != HDD_OP_SEEK) * hdd->avg_rotation_lat_usec); }
}
} }
if (!max_seek_time || seek_time <= max_seek_time) { if (!max_seek_time || seek_time <= max_seek_time) {
hdd->cur_addr = dst_addr; hdd->cur_addr = dst_addr;
hdd->cur_track = new_track; hdd->cur_track = new_track;
hdd->cur_cylinder = new_cylinder; hdd->cur_cylinder = new_cylinder;
} }
return seek_time; return seek_time;
} }
static void static void
hdd_readahead_update(hard_disk_t *hdd) hdd_readahead_update(hard_disk_t *hdd)
{ {
uint64_t elapsed_cycles; uint64_t elapsed_cycles;
double elapsed_us, seek_time; double elapsed_us, seek_time;
uint32_t max_read_ahead, i; uint32_t max_read_ahead, i;
uint32_t space_needed; uint32_t space_needed;
hdd_cache_t *cache = &hdd->cache; hdd_cache_t *cache = &hdd->cache;
if (cache->ra_ongoing) { if (cache->ra_ongoing) {
hdd_cache_seg_t *segment = &cache->segments[cache->ra_segment]; hdd_cache_seg_t *segment = &cache->segments[cache->ra_segment];
elapsed_cycles = tsc - cache->ra_start_time; elapsed_cycles = tsc - cache->ra_start_time;
elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0; elapsed_us = (double) elapsed_cycles / cpuclock * 1000000.0;
/* Do not overwrite data not yet read by host */ /* Do not overwrite data not yet read by host */
max_read_ahead = (segment->host_addr + cache->segment_size) - segment->ra_addr; max_read_ahead = (segment->host_addr + cache->segment_size) - segment->ra_addr;
seek_time = 0.0; seek_time = 0.0;
for (i = 0; i < max_read_ahead; i++) { for (i = 0; i < max_read_ahead; i++) {
seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, elapsed_us - seek_time); seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, elapsed_us - seek_time);
if (seek_time > elapsed_us) if (seek_time > elapsed_us)
break; break;
segment->ra_addr++; segment->ra_addr++;
} }
if (segment->ra_addr > segment->lba_addr + cache->segment_size) { if (segment->ra_addr > segment->lba_addr + cache->segment_size) {
space_needed = segment->ra_addr - (segment->lba_addr + cache->segment_size); space_needed = segment->ra_addr - (segment->lba_addr + cache->segment_size);
segment->lba_addr += space_needed; segment->lba_addr += space_needed;
} }
} }
} }
static double static double
hdd_writecache_flush(hard_disk_t *hdd) hdd_writecache_flush(hard_disk_t *hdd)
{ {
double seek_time = 0.0; double seek_time = 0.0;
while (hdd->cache.write_pending) { while (hdd->cache.write_pending) {
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0); seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0);
hdd->cache.write_addr++; hdd->cache.write_addr++;
hdd->cache.write_pending--; hdd->cache.write_pending--;
} }
return seek_time; return seek_time;
} }
static void static void
hdd_writecache_update(hard_disk_t *hdd) hdd_writecache_update(hard_disk_t *hdd)
{ {
uint64_t elapsed_cycles; uint64_t elapsed_cycles;
double elapsed_us, seek_time; double elapsed_us, seek_time;
if (hdd->cache.write_pending) { if (hdd->cache.write_pending) {
elapsed_cycles = tsc - hdd->cache.write_start_time; elapsed_cycles = tsc - hdd->cache.write_start_time;
elapsed_us = (double)elapsed_cycles / cpuclock * 1000000.0; elapsed_us = (double) elapsed_cycles / cpuclock * 1000000.0;
seek_time = 0.0; seek_time = 0.0;
while (hdd->cache.write_pending) { while (hdd->cache.write_pending) {
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, elapsed_us - seek_time); seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, elapsed_us - seek_time);
if (seek_time > elapsed_us) if (seek_time > elapsed_us)
break; break;
hdd->cache.write_addr++; hdd->cache.write_addr++;
hdd->cache.write_pending--; hdd->cache.write_pending--;
} }
} }
} }
double double
hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len) hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
{ {
double seek_time = 0.0; double seek_time = 0.0;
uint32_t flush_needed; uint32_t flush_needed;
if (!hdd->speed_preset) if (!hdd->speed_preset)
@@ -294,31 +285,30 @@ hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len)
hdd->cache.ra_ongoing = 0; hdd->cache.ra_ongoing = 0;
if (hdd->cache.write_pending && (addr != (hdd->cache.write_addr + hdd->cache.write_pending))) { if (hdd->cache.write_pending && (addr != (hdd->cache.write_addr + hdd->cache.write_pending))) {
/* New request is not sequential to existing cache, need to flush it */ /* New request is not sequential to existing cache, need to flush it */
seek_time += hdd_writecache_flush(hdd); seek_time += hdd_writecache_flush(hdd);
} }
if (!hdd->cache.write_pending) { if (!hdd->cache.write_pending) {
/* Cache is empty */ /* Cache is empty */
hdd->cache.write_addr = addr; hdd->cache.write_addr = addr;
} }
hdd->cache.write_pending += len; hdd->cache.write_pending += len;
if (hdd->cache.write_pending > hdd->cache.write_size) { if (hdd->cache.write_pending > hdd->cache.write_size) {
/* If request is bigger than free cache, flush some data first */ /* If request is bigger than free cache, flush some data first */
flush_needed = hdd->cache.write_pending - hdd->cache.write_size; flush_needed = hdd->cache.write_pending - hdd->cache.write_size;
for (uint32_t i = 0; i < flush_needed; i++) { for (uint32_t i = 0; i < flush_needed; i++) {
seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0); seek_time += hdd_seek_get_time(hdd, hdd->cache.write_addr, HDD_OP_WRITE, 1, 0);
hdd->cache.write_addr++; hdd->cache.write_addr++;
} }
} }
hdd->cache.write_start_time = tsc + (uint32_t)(seek_time * cpuclock / 1000000.0); hdd->cache.write_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0);
return seek_time; return seek_time;
} }
double double
hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len) hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
{ {
@@ -332,159 +322,145 @@ hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len)
seek_time += hdd_writecache_flush(hdd); seek_time += hdd_writecache_flush(hdd);
hdd_cache_t *cache = &hdd->cache; hdd_cache_t *cache = &hdd->cache;
hdd_cache_seg_t *active_seg = &cache->segments[0]; hdd_cache_seg_t *active_seg = &cache->segments[0];
for (uint32_t i = 0; i < cache->num_segments; i++) { for (uint32_t i = 0; i < cache->num_segments; i++) {
hdd_cache_seg_t *segment = &cache->segments[i]; hdd_cache_seg_t *segment = &cache->segments[i];
if (!segment->valid) { if (!segment->valid) {
active_seg = segment; active_seg = segment;
continue; continue;
} }
if (segment->lba_addr <= addr && (segment->lba_addr + cache->segment_size) >= addr) { if (segment->lba_addr <= addr && (segment->lba_addr + cache->segment_size) >= addr) {
/* Cache HIT */ /* Cache HIT */
segment->host_addr = addr; segment->host_addr = addr;
active_seg = segment; active_seg = segment;
if (addr + len > segment->ra_addr) { if (addr + len > segment->ra_addr) {
uint32_t need_read = (addr + len) - segment->ra_addr; uint32_t need_read = (addr + len) - segment->ra_addr;
for (uint32_t j = 0; j < need_read; j++) { for (uint32_t j = 0; j < need_read; j++) {
seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, 0.0); seek_time += hdd_seek_get_time(hdd, segment->ra_addr, HDD_OP_READ, 1, 0.0);
segment->ra_addr++; segment->ra_addr++;
} }
} }
if (addr + len > segment->lba_addr + cache->segment_size) { if (addr + len > segment->lba_addr + cache->segment_size) {
/* Need to erase some previously cached data */ /* Need to erase some previously cached data */
uint32_t space_needed = (addr + len) - (segment->lba_addr + cache->segment_size); uint32_t space_needed = (addr + len) - (segment->lba_addr + cache->segment_size);
segment->lba_addr += space_needed; segment->lba_addr += space_needed;
} }
goto update_lru; goto update_lru;
} else { } else {
if (segment->lru > active_seg->lru) if (segment->lru > active_seg->lru)
active_seg = segment; active_seg = segment;
} }
} }
/* Cache MISS */ /* Cache MISS */
active_seg->lba_addr = addr; active_seg->lba_addr = addr;
active_seg->valid = 1; active_seg->valid = 1;
active_seg->host_addr = addr; active_seg->host_addr = addr;
active_seg->ra_addr = addr; active_seg->ra_addr = addr;
for (uint32_t i = 0; i < len; i++) { for (uint32_t i = 0; i < len; i++) {
seek_time += hdd_seek_get_time(hdd, active_seg->ra_addr, HDD_OP_READ, i != 0, 0.0); seek_time += hdd_seek_get_time(hdd, active_seg->ra_addr, HDD_OP_READ, i != 0, 0.0);
active_seg->ra_addr++; active_seg->ra_addr++;
} }
update_lru: update_lru:
for (uint32_t i = 0; i < cache->num_segments; i++) for (uint32_t i = 0; i < cache->num_segments; i++)
cache->segments[i].lru++; cache->segments[i].lru++;
active_seg->lru = 0; active_seg->lru = 0;
cache->ra_ongoing = 1; cache->ra_ongoing = 1;
cache->ra_segment = active_seg->id; cache->ra_segment = active_seg->id;
cache->ra_start_time = tsc + (uint32_t)(seek_time * cpuclock / 1000000.0); cache->ra_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0);
return seek_time; return seek_time;
} }
static void static void
hdd_cache_init(hard_disk_t *hdd) hdd_cache_init(hard_disk_t *hdd)
{ {
hdd_cache_t *cache = &hdd->cache; hdd_cache_t *cache = &hdd->cache;
uint32_t i; uint32_t i;
cache->ra_segment = 0; cache->ra_segment = 0;
cache->ra_ongoing = 0; cache->ra_ongoing = 0;
cache->ra_start_time = 0; cache->ra_start_time = 0;
for (i = 0; i < cache->num_segments; i++) { for (i = 0; i < cache->num_segments; i++) {
cache->segments[i].valid = 0; cache->segments[i].valid = 0;
cache->segments[i].lru = 0; cache->segments[i].lru = 0;
cache->segments[i].id = i; cache->segments[i].id = i;
cache->segments[i].ra_addr = 0; cache->segments[i].ra_addr = 0;
cache->segments[i].host_addr = 0; cache->segments[i].host_addr = 0;
} }
} }
static void static void
hdd_zones_init(hard_disk_t *hdd) hdd_zones_init(hard_disk_t *hdd)
{ {
uint32_t lba = 0, track = 0; uint32_t lba = 0, track = 0;
uint32_t i, tracks; uint32_t i, tracks;
double revolution_usec = 60.0 / (double)hdd->rpm * 1000000.0; double revolution_usec = 60.0 / (double) hdd->rpm * 1000000.0;
hdd_zone_t *zone; hdd_zone_t *zone;
for (i = 0; i < hdd->num_zones; i++) { for (i = 0; i < hdd->num_zones; i++) {
zone = &hdd->zones[i]; zone = &hdd->zones[i];
zone->start_sector = lba; zone->start_sector = lba;
zone->start_track = track; zone->start_track = track;
zone->sector_time_usec = revolution_usec / (double)zone->sectors_per_track; zone->sector_time_usec = revolution_usec / (double) zone->sectors_per_track;
tracks = zone->cylinders * hdd->phy_heads; tracks = zone->cylinders * hdd->phy_heads;
lba += tracks * zone->sectors_per_track; lba += tracks * zone->sectors_per_track;
zone->end_sector = lba - 1; zone->end_sector = lba - 1;
track += tracks - 1; track += tracks - 1;
} }
} }
static hdd_preset_t hdd_speed_presets[] = { static hdd_preset_t hdd_speed_presets[] = {
{ .name = "RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, {.name = "RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32},
{ .name = "[1989] 3500 RPM", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, { .name = "[1989] 3500 RPM", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 },
.full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 },
{ .name = "[1992] 3600 RPM", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, { .name = "[1992] 3600 RPM", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 },
.full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 },
{ .name = "[1994] 4500 RPM", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, { .name = "[1994] 4500 RPM", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 },
.full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 },
{ .name = "[1996] 5400 RPM", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, { .name = "[1996] 5400 RPM", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 },
.full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 },
{ .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, { .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 },
.full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 },
{ .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, { .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 },
.full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 },
{ .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, { .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
.full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 },
}; };
int int
hdd_preset_get_num() hdd_preset_get_num()
{ {
return sizeof(hdd_speed_presets) / sizeof(hdd_preset_t); return sizeof(hdd_speed_presets) / sizeof(hdd_preset_t);
} }
char * char *
hdd_preset_getname(int preset) hdd_preset_getname(int preset)
{ {
return (char *)hdd_speed_presets[preset].name; return (char *) hdd_speed_presets[preset].name;
} }
char * char *
hdd_preset_get_internal_name(int preset) hdd_preset_get_internal_name(int preset)
{ {
return (char *)hdd_speed_presets[preset].internal_name; return (char *) hdd_speed_presets[preset].internal_name;
} }
int int
hdd_preset_get_from_internal_name(char *s) hdd_preset_get_from_internal_name(char *s)
{ {
int c = 0; int c = 0;
for (int i = 0; i < (sizeof(hdd_speed_presets) / sizeof(hdd_preset_t)); i++) { for (int i = 0; i < (sizeof(hdd_speed_presets) / sizeof(hdd_preset_t)); i++) {
if (!strcmp((char *)hdd_speed_presets[c].internal_name, s)) if (!strcmp((char *) hdd_speed_presets[c].internal_name, s))
return c; return c;
c++; c++;
} }
@@ -492,18 +468,17 @@ hdd_preset_get_from_internal_name(char *s)
return 0; return 0;
} }
void void
hdd_preset_apply(int hdd_id) hdd_preset_apply(int hdd_id)
{ {
hard_disk_t *hd = &hdd[hdd_id]; hard_disk_t *hd = &hdd[hdd_id];
double revolution_usec, zone_percent; double revolution_usec, zone_percent;
uint32_t disk_sectors, sectors_per_surface, cylinders, cylinders_per_zone; uint32_t disk_sectors, sectors_per_surface, cylinders, cylinders_per_zone;
uint32_t total_sectors = 0, i; uint32_t total_sectors = 0, i;
uint32_t spt, zone_sectors; uint32_t spt, zone_sectors;
if (hd->speed_preset >= hdd_preset_get_num()) if (hd->speed_preset >= hdd_preset_get_num())
hd->speed_preset = 0; hd->speed_preset = 0;
hdd_preset_t *preset = &hdd_speed_presets[hd->speed_preset]; hdd_preset_t *preset = &hdd_speed_presets[hd->speed_preset];
@@ -512,42 +487,42 @@ hdd_preset_apply(int hdd_id)
hd->max_multiple_block = preset->max_multiple; hd->max_multiple_block = preset->max_multiple;
if (!hd->speed_preset) if (!hd->speed_preset)
return; return;
hd->phy_heads = preset->heads; hd->phy_heads = preset->heads;
hd->rpm = preset->rpm; hd->rpm = preset->rpm;
revolution_usec = 60.0 / (double)hd->rpm * 1000000.0; revolution_usec = 60.0 / (double) hd->rpm * 1000000.0;
hd->avg_rotation_lat_usec = revolution_usec / 2; hd->avg_rotation_lat_usec = revolution_usec / 2;
hd->full_stroke_usec = preset->full_stroke_ms * 1000; hd->full_stroke_usec = preset->full_stroke_ms * 1000;
hd->head_switch_usec = preset->track_seek_ms * 1000; hd->head_switch_usec = preset->track_seek_ms * 1000;
hd->cyl_switch_usec = preset->track_seek_ms * 1000; hd->cyl_switch_usec = preset->track_seek_ms * 1000;
hd->cache.write_size = 64; hd->cache.write_size = 64;
hd->num_zones = preset->zones; hd->num_zones = preset->zones;
disk_sectors = hd->tracks * hd->hpc * hd->spt; disk_sectors = hd->tracks * hd->hpc * hd->spt;
sectors_per_surface = (uint32_t)ceil((double)disk_sectors / (double)hd->phy_heads); sectors_per_surface = (uint32_t) ceil((double) disk_sectors / (double) hd->phy_heads);
cylinders = (uint32_t)ceil((double)sectors_per_surface / (double)preset->avg_spt); cylinders = (uint32_t) ceil((double) sectors_per_surface / (double) preset->avg_spt);
hd->phy_cyl = cylinders; hd->phy_cyl = cylinders;
cylinders_per_zone = cylinders / preset->zones; cylinders_per_zone = cylinders / preset->zones;
for (i = 0; i < preset->zones; i++) { for (i = 0; i < preset->zones; i++) {
zone_percent = i * 100 / (double)preset->zones; zone_percent = i * 100 / (double) preset->zones;
if (i < preset->zones - 1) { if (i < preset->zones - 1) {
/* Function for realistic zone sector density */ /* Function for realistic zone sector density */
double spt_percent = -0.00341684 * pow(zone_percent, 2) - 0.175811 * zone_percent + 118.48; double spt_percent = -0.00341684 * pow(zone_percent, 2) - 0.175811 * zone_percent + 118.48;
spt = (uint32_t)ceil((double)preset->avg_spt * spt_percent / 100); spt = (uint32_t) ceil((double) preset->avg_spt * spt_percent / 100);
} else } else
spt = (uint32_t)ceil((double)(disk_sectors - total_sectors) / (double)(cylinders_per_zone*preset->heads)); spt = (uint32_t) ceil((double) (disk_sectors - total_sectors) / (double) (cylinders_per_zone * preset->heads));
zone_sectors = spt * cylinders_per_zone * preset->heads; zone_sectors = spt * cylinders_per_zone * preset->heads;
total_sectors += zone_sectors; total_sectors += zone_sectors;
hd->zones[i].cylinders = cylinders_per_zone; hd->zones[i].cylinders = cylinders_per_zone;
hd->zones[i].sectors_per_track = spt; hd->zones[i].sectors_per_track = spt;
} }
hdd_zones_init(hd); hdd_zones_init(hd);

File diff suppressed because it is too large Load Diff

View File

@@ -25,8 +25,8 @@
#include <86box/86box.h> #include <86box/86box.h>
#include <86box/hdd.h> #include <86box/hdd.h>
unsigned int hdd_table[128][3] = { unsigned int hdd_table[128][3] = {
// clang-format off
{ 306, 4, 17 }, /* 0 - 7 */ { 306, 4, 17 }, /* 0 - 7 */
{ 615, 2, 17 }, { 615, 2, 17 },
{ 306, 4, 26 }, { 306, 4, 26 },
@@ -170,4 +170,5 @@ unsigned int hdd_table[128][3] = {
{ 1120, 16, 59 }, { 1120, 16, 59 },
{ 1054, 16, 63 }, { 1054, 16, 63 },
{ 0, 0, 0 } { 0, 0, 0 }
// clang-format on
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff