From 464a6da62fba585cfcb11081795c25a1c2e4f17f Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 11 Jun 2020 12:52:50 +0200 Subject: [PATCH] Intel SIO overhaul, slight DMA clean-ups and SIO-related additions, made the PIIX/SMSC series of southbridges aware of CPU speed changes, and fixed a bug in the 86F loading code. --- src/dma.c | 886 ++++++++++++++++++++++++++++++++++------ src/floppy/fdd_86f.c | 2 +- src/include/86box/dma.h | 36 +- src/intel_piix.c | 26 +- src/intel_sio.c | 324 +++++++++++---- src/pci.c | 1 + 6 files changed, 1050 insertions(+), 225 deletions(-) diff --git a/src/dma.c b/src/dma.c index 7a424c50b..7e4e80e40 100644 --- a/src/dma.c +++ b/src/dma.c @@ -29,6 +29,7 @@ #include <86box/mca.h> #include <86box/mem.h> #include <86box/io.h> +#include <86box/pic.h> #include <86box/dma.h> @@ -36,20 +37,19 @@ dma_t dma[8]; uint8_t dma_e; -static uint8_t dmaregs[16]; -static uint8_t dma16regs[16]; -static uint8_t dmapages[16]; -static int dma_wp, - dma16_wp; +static uint8_t dmaregs[3][16]; +static int dma_wp[2]; static uint8_t dma_m; static uint8_t dma_stat; static uint8_t dma_stat_rq; static uint8_t dma_stat_rq_pc; -static uint8_t dma_command, - dma16_command; +static uint8_t dma_command[2]; static uint8_t dma_req_is_soft; +static uint8_t dma_advanced; static uint8_t dma_buffer[65536]; +static uint16_t dma_sg_base; static uint16_t dma16_buffer[65536]; +static uint32_t dma_mask; static struct { int xfr_command, @@ -68,6 +68,26 @@ static struct { #define DMA_PS2_SIZE16 (1 << 6) +#ifdef ENABLE_DMA_LOG +int dma_do_log = ENABLE_DMA_LOG; + + +static void +dma_log(const char *fmt, ...) +{ + va_list ap; + + if (dma_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define dma_log(fmt, ...) +#endif + + static void dma_ps2_run(int channel); @@ -87,6 +107,37 @@ dma_set_drq(int channel, int set) } +static int +dma_transfer_size(dma_t *dev) +{ + return dev->transfer_mode & 0xff; +} + + +static void +dma_sg_next_addr(dma_t *dev) +{ + int ts = dma_transfer_size(dev); + + dma_bm_read(dev->ptr_cur, (uint8_t *)&(dev->addr), 4, ts); + dma_bm_read(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4, ts); + dma_log("DMA S/G DWORDs: %08X %08X\n", dev->addr, dev->count); + dev->eot = dev->count >> 31; + dev->count &= 0xfffe; + dev->cb = (uint16_t) dev->count; + dev->cc = (int) dev->count; + if (!dev->count) + dev->count = 65536; + if (ts == 2) + dev->addr &= 0xfffffffe; + dev->ab = dev->addr & dma_mask; + dev->ac = dev->addr & dma_mask; + dev->page = dev->page_l = (dev->ac >> 16) & 0xff; + dev->page_h = (dev->ac >> 24) & 0xff; + dev->ptr_cur += 8; +} + + static void dma_block_transfer(int channel) { @@ -94,6 +145,9 @@ dma_block_transfer(int channel) bit16 = (channel >= 4); + if (dma_advanced) + bit16 = !!(dma_transfer_size(&(dma[channel])) == 2); + dma_req_is_soft = 1; for (i = 0; i <= dma[channel].cb; i++) { if ((dma[channel].mode & 0x8c) == 0x84) { @@ -112,6 +166,270 @@ dma_block_transfer(int channel) } +static void +dma_sg_write(uint16_t port, uint8_t val, void *priv) +{ + dma_t *dev = (dma_t *) priv; + + dma_log("DMA S/G BYTE write: %04X %02X\n", port, val); + + port &= 0xff; + + if (port < 0x20) + port &= 0xf8; + else + port &= 0xe3; + + switch (port) { + case 0x00: + dma_log("DMA S/G Cmd : val = %02X, old = %02X\n", val, dev->sg_command); + if ((val & 1) && !(dev->sg_command & 1)) { /*Start*/ +#ifdef ENABLE_DMA_LOG + dma_log("DMA S/G start\n"); +#endif + dev->ptr_cur = dev->ptr; + dma_sg_next_addr(dev); + dev->sg_status = (dev->sg_status & 0xf7) | 0x01; + } + if (!(val & 1) && (dev->sg_command & 1)) { /*Stop*/ +#ifdef ENABLE_DMA_LOG + dma_log("DMA S/G stop\n"); +#endif + dev->sg_status &= ~0x81; + } + + dev->sg_command = val; + break; + case 0x20: + dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val; + break; + case 0x21: + dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); + dev->ptr %= (mem_size * 1024); + break; + case 0x22: + dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + case 0x23: + dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +dma_sg_writew(uint16_t port, uint16_t val, void *priv) +{ + dma_t *dev = (dma_t *) priv; + + dma_log("DMA S/G WORD write: %04X %04X\n", port, val); + + port &= 0xff; + + if (port < 0x20) + port &= 0xf8; + else + port &= 0xe3; + + switch (port) { + case 0x00: + dma_sg_write(port, val & 0xff, priv); + break; + case 0x20: + dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + case 0x22: + dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +dma_sg_writel(uint16_t port, uint32_t val, void *priv) +{ + dma_t *dev = (dma_t *) priv; + + dma_log("DMA S/G DWORD write: %04X %08X\n", port, val); + + port &= 0xff; + + if (port < 0x20) + port &= 0xf8; + else + port &= 0xe3; + + switch (port) { + case 0x00: + dma_sg_write(port, val & 0xff, priv); + break; + case 0x20: + dev->ptr = (val & 0xfffffffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + } +} + + +static uint8_t +dma_sg_read(uint16_t port, void *priv) +{ + dma_t *dev = (dma_t *) priv; + + uint8_t ret = 0xff; + + port &= 0xff; + + if (port < 0x20) + port &= 0xf8; + else + port &= 0xe3; + + switch (port) { + case 0x08: + ret = (dev->sg_status & 0x01); + if (dev->eot) + ret |= 0x80; + if ((dev->sg_command & 0xc0) == 0x40) + ret |= 0x20; + if (dev->ab != 0x00000000) + ret |= 0x08; + if (dev->ac != 0x00000000) + ret |= 0x04; + break; + case 0x20: + ret = dev->ptr0; + break; + case 0x21: + ret = dev->ptr >> 8; + break; + case 0x22: + ret = dev->ptr >> 16; + break; + case 0x23: + ret = dev->ptr >> 24; + break; + } + + dma_log("DMA S/G BYTE read : %04X %02X\n", port, ret); + + return ret; +} + + +static uint16_t +dma_sg_readw(uint16_t port, void *priv) +{ + dma_t *dev = (dma_t *) priv; + + uint16_t ret = 0xffff; + + port &= 0xff; + + if (port < 0x20) + port &= 0xf8; + else + port &= 0xe3; + + switch (port) { + case 0x08: + ret = (uint16_t) dma_sg_read(port, priv); + break; + case 0x20: + ret = dev->ptr0 | (dev->ptr & 0xff00); + break; + case 0x22: + ret = dev->ptr >> 16; + break; + } + + dma_log("DMA S/G WORD read : %04X %04X\n", port, ret); + + return ret; +} + + +static uint32_t +dma_sg_readl(uint16_t port, void *priv) +{ + dma_t *dev = (dma_t *) priv; + + uint32_t ret = 0xffffffff; + + port &= 0xff; + + if (port < 0x20) + port &= 0xf8; + else + port &= 0xe3; + + switch (port) { + case 0x08: + ret = (uint32_t) dma_sg_read(port, priv); + break; + case 0x20: + ret = dev->ptr0 | (dev->ptr & 0xffffff00); + break; + } + + dma_log("DMA S/G DWORD read : %04X %08X\n", port, ret); + + return ret; +} + + +static void +dma_ext_mode_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = (val & 0x03); + + if (addr == 0x4d6) + channel |= 4; + + dma[channel].ext_mode = val & 0x7c; + + switch ((val > 2) & 0x03) { + case 0x00: + dma[channel].transfer_mode = 0x0101; + break; + case 0x01: + dma[channel].transfer_mode = 0x0202; + break; + case 0x02: /* 0x02 is reserved. */ + /* Logic says this should be an undocumented mode that counts by words, + but is 8-bit I/O, thus only transferring every second byte. */ + dma[channel].transfer_mode = 0x0201; + break; + case 0x03: + dma[channel].transfer_mode = 0x0102; + break; + } +} + + +static uint8_t +dma_sg_int_status_read(uint16_t addr, void *priv) +{ + int i; + uint8_t ret = 0x00; + + for (i = 0; i < 8; i++) { + if (i != 4) + ret = (!!(dma[i].sg_status & 8)) << i; + } + + return ret; +} + + static uint8_t dma_read(uint16_t addr, void *priv) { @@ -123,8 +441,8 @@ dma_read(uint16_t addr, void *priv) case 2: case 4: case 6: /*Address registers*/ - dma_wp ^= 1; - if (dma_wp) + dma_wp[0] ^= 1; + if (dma_wp[0]) return(dma[channel].ac & 0xff); return((dma[channel].ac >> 8) & 0xff); @@ -132,8 +450,8 @@ dma_read(uint16_t addr, void *priv) case 3: case 5: case 7: /*Count registers*/ - dma_wp ^= 1; - if (dma_wp) + dma_wp[0] ^= 1; + if (dma_wp[0]) temp = dma[channel].cc & 0xff; else temp = dma[channel].cc >> 8; @@ -150,7 +468,7 @@ dma_read(uint16_t addr, void *priv) return(0); } - return(dmaregs[addr & 0xf]); + return(dmaregs[0][addr & 0xf]); } @@ -159,14 +477,14 @@ dma_write(uint16_t addr, uint8_t val, void *priv) { int channel = (addr >> 1) & 3; - dmaregs[addr & 0xf] = val; + dmaregs[0][addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma_wp ^= 1; - if (dma_wp) + dma_wp[0] ^= 1; + if (dma_wp[0]) dma[channel].ab = (dma[channel].ab & 0xffff00) | val; else dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); @@ -177,8 +495,8 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 3: case 5: case 7: /*Count registers*/ - dma_wp ^= 1; - if (dma_wp) + dma_wp[0] ^= 1; + if (dma_wp[0]) dma[channel].cb = (dma[channel].cb & 0xff00) | val; else dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); @@ -186,7 +504,7 @@ dma_write(uint16_t addr, uint8_t val, void *priv) return; case 8: /*Control register*/ - dma_command = val; + dma_command[0] = val; if (val & 0x01) fatal("Memory-to-memory enable\n"); return; @@ -223,11 +541,11 @@ dma_write(uint16_t addr, uint8_t val, void *priv) return; case 0xc: /*Clear FF*/ - dma_wp = 0; + dma_wp[0] = 0; return; case 0xd: /*Master clear*/ - dma_wp = 0; + dma_wp[0] = 0; dma_m |= 0xf; dma_stat_rq_pc &= ~0x0f; return; @@ -413,13 +731,13 @@ dma16_read(uint16_t addr, void *priv) case 2: case 4: case 6: /*Address registers*/ - dma16_wp ^= 1; + dma_wp[1] ^= 1; if (dma_ps2.is_ps2) { - if (dma16_wp) + if (dma_wp[1]) return(dma[channel].ac); return((dma[channel].ac >> 8) & 0xff); } - if (dma16_wp) + if (dma_wp[1]) return((dma[channel].ac >> 1) & 0xff); return((dma[channel].ac >> 9) & 0xff); @@ -427,8 +745,8 @@ dma16_read(uint16_t addr, void *priv) case 3: case 5: case 7: /*Count registers*/ - dma16_wp ^= 1; - if (dma16_wp) + dma_wp[1] ^= 1; + if (dma_wp[1]) temp = dma[channel].cc & 0xff; else temp = dma[channel].cc >> 8; @@ -441,7 +759,7 @@ dma16_read(uint16_t addr, void *priv) return(temp); } - return(dma16regs[addr & 0xf]); + return(dmaregs[1][addr & 0xf]); } @@ -451,20 +769,20 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) int channel = ((addr >> 2) & 3) + 4; addr >>= 1; - dma16regs[addr & 0xf] = val; + dmaregs[1][addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma16_wp ^= 1; + dma_wp[1] ^= 1; if (dma_ps2.is_ps2) { - if (dma16_wp) + if (dma_wp[1]) dma[channel].ab = (dma[channel].ab & 0xffff00) | val; else dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); } else { - if (dma16_wp) + if (dma_wp[1]) dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); else dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); @@ -476,8 +794,8 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) case 3: case 5: case 7: /*Count registers*/ - dma16_wp ^= 1; - if (dma16_wp) + dma_wp[1] ^= 1; + if (dma_wp[1]) dma[channel].cb = (dma[channel].cb & 0xff00) | val; else dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); @@ -519,11 +837,11 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) return; case 0xc: /*Clear FF*/ - dma16_wp = 0; + dma_wp[1] = 0; return; case 0xd: /*Master clear*/ - dma16_wp = 0; + dma_wp[1] = 0; dma_m |= 0xf0; dma_stat_rq_pc &= ~0xf0; return; @@ -539,59 +857,36 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) } +#define CHANNELS { 8, 2, 3, 1, 8, 8, 8, 0 } + + static void dma_page_write(uint16_t addr, uint8_t val, void *priv) { - dmapages[addr & 0xf] = val; + uint8_t convert[8] = CHANNELS; - switch (addr & 0xf) { - case 1: - dma[2].page = (AT) ? val : val & 0xf; - dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); - dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); - break; + pclog("[W] addr = old %04X, ", addr); + addr &= 0x0f; + dmaregs[2][addr] = val; - case 2: - dma[3].page = (AT) ? val : val & 0xf; - dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); - dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); - break; + if (addr >= 8) + addr = convert[addr & 0x07] | 4; + else + addr = convert[addr & 0x07]; + pclog("new %04X\n", addr); - case 3: - dma[1].page = (AT) ? val : val & 0xf; - dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); - dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); - break; + if (addr < 8) { + dma[addr].page_l = val; - case 7: - dma[0].page = (AT) ? val : val & 0xf; - dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); - dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); - break; - - case 0x9: - dma[6].page = val & 0xfe; - dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); - dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); - break; - - case 0xa: - dma[7].page = val & 0xfe; - dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); - dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); - break; - - case 0xb: - dma[5].page = val & 0xfe; - dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); - dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); - break; - - case 0xf: - dma[4].page = val & 0xfe; - dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); - dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); - break; + if (addr > 4) { + dma[addr].page = val & 0xfe; + dma[addr].ab = (dma[addr].ab & 0x1ffff) | (dma[addr].page << 16); + dma[addr].ac = (dma[addr].ac & 0x1ffff) | (dma[addr].page << 16); + } else { + dma[addr].page = (AT) ? val : val & 0xf; + dma[addr].ab = (dma[addr].ab & 0xffff) | (dma[addr].page << 16); + dma[addr].ac = (dma[addr].ac & 0xffff) | (dma[addr].page << 16); + } } } @@ -599,7 +894,72 @@ dma_page_write(uint16_t addr, uint8_t val, void *priv) static uint8_t dma_page_read(uint16_t addr, void *priv) { - return(dmapages[addr & 0xf]); + uint8_t convert[8] = CHANNELS; + uint8_t ret = 0xff; + + pclog("[R] addr = old %04X, ", addr); + addr &= 0x0f; + ret = dmaregs[2][addr]; + + if (addr >= 8) + addr = convert[addr & 0x07] | 4; + else + addr = convert[addr & 0x07]; + pclog("new %04X\n", addr); + + if (addr < 8) + ret = dma[addr].page_l; + + return ret; +} + + +static void +dma_high_page_write(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t convert[8] = CHANNELS; + + addr &= 0x0f; + + if (addr >= 8) + addr = convert[addr & 0x07] | 4; + else + addr = convert[addr & 0x07]; + + if (addr < 8) { + dma[addr].page_h = val; + + dma[addr].ab = ((dma[addr].ab & 0xffffff) | (dma[addr].page << 24)) & dma_mask; + dma[addr].ac = ((dma[addr].ac & 0xffffff) | (dma[addr].page << 24)) & dma_mask; + } +} + + +static uint8_t +dma_high_page_read(uint16_t addr, void *priv) +{ + uint8_t convert[8] = CHANNELS; + uint8_t ret = 0xff; + + addr &= 0x0f; + + if (addr >= 8) + addr = convert[addr & 0x07] | 4; + else + addr = convert[addr & 0x07]; + + if (addr < 8) + ret = dma[addr].page_h; + + return ret; +} + + +void +dma_set_params(uint8_t advanced, uint32_t mask) +{ + dma_advanced = advanced; + dma_mask = mask; } @@ -608,29 +968,107 @@ dma_reset(void) { int c; - dma_wp = dma16_wp = 0; + dma_wp[0] = dma_wp[1] = 0; dma_m = 0; dma_e = 0xff; for (c = 0; c < 16; c++) - dmaregs[c] = dma16regs[c] = 0; + dmaregs[0][c] = dmaregs[1][c] = 0; + for (c = 0; c < 8; c++) { - dma[c].mode = 0; - dma[c].ac = 0; - dma[c].cc = 0; - dma[c].ab = 0; - dma[c].cb = 0; + memset(&(dma[c]), 0x00, sizeof(dma_t)); dma[c].size = (c & 4) ? 1 : 0; + dma[c].transfer_mode = (c & 4) ? 0x0202 : 0x0101; } dma_stat = 0x00; dma_stat_rq = 0x00; dma_stat_rq_pc = 0x00; dma_req_is_soft = 0; + dma_advanced = 0; memset(dma_buffer, 0x00, sizeof(dma_buffer)); memset(dma16_buffer, 0x00, sizeof(dma16_buffer)); + + dma_remove_sg(); + dma_sg_base = 0x0400; + + dma_mask = 0x00ffffff; +} + + +void +dma_remove_sg(void) +{ + int i; + + io_removehandler(dma_sg_base + 0x0a, 0x01, + dma_sg_int_status_read, NULL, NULL, + NULL, NULL, NULL, + NULL); + + for (i = 0; i < 8; i++) { + io_removehandler(dma_sg_base + 0x10 + i, 0x01, + dma_sg_read, dma_sg_readw, dma_sg_readl, + dma_sg_write, dma_sg_writew, dma_sg_writel, + &dma[i]); + io_removehandler(dma_sg_base + 0x18 + i, 0x01, + dma_sg_read, dma_sg_readw, dma_sg_readl, + dma_sg_write, dma_sg_writew, dma_sg_writel, + &dma[i]); + io_removehandler(dma_sg_base + 0x20 + i, 0x04, + dma_sg_read, dma_sg_readw, dma_sg_readl, + dma_sg_write, dma_sg_writew, dma_sg_writel, + &dma[i]); + } +} + + +void +dma_set_sg_base(uint8_t sg_base) +{ + int i; + + dma_sg_base = sg_base << 8; + + io_sethandler(dma_sg_base + 0x0a, 0x01, + dma_sg_int_status_read, NULL, NULL, + NULL, NULL, NULL, + NULL); + + for (i = 0; i < 8; i++) { + io_sethandler(dma_sg_base + 0x10 + i, 0x01, + dma_sg_read, dma_sg_readw, dma_sg_readl, + dma_sg_write, dma_sg_writew, dma_sg_writel, + &dma[i]); + io_sethandler(dma_sg_base + 0x18 + i, 0x01, + dma_sg_read, dma_sg_readw, dma_sg_readl, + dma_sg_write, dma_sg_writew, dma_sg_writel, + &dma[i]); + io_sethandler(dma_sg_base + 0x20 + i, 0x04, + dma_sg_read, dma_sg_readw, dma_sg_readl, + dma_sg_write, dma_sg_writew, dma_sg_writel, + &dma[i]); + } +} + + +void +dma_ext_mode_init(void) +{ + io_sethandler(0x040b, 0x01, + NULL,NULL,NULL, dma_ext_mode_write,NULL,NULL, NULL); + io_sethandler(0x04d6, 0x01, + NULL,NULL,NULL, dma_ext_mode_write,NULL,NULL, NULL); +} + + +void +dma_high_page_init(void) +{ + io_sethandler(0x0480, 8, + dma_high_page_read,NULL,NULL, dma_high_page_write,NULL,NULL, NULL); } @@ -720,20 +1158,170 @@ ps2_dma_init(void) } -uint8_t -_dma_read(uint32_t addr) +extern void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize); +extern void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize); + + +static int +dma_sg(uint8_t *data, int transfer_length, int out, void *priv) { - uint8_t temp = mem_readb_phys(addr); + dma_t *dev = (dma_t *) priv; +#ifdef ENABLE_DMA_LOG + char *sop; +#endif + + int force_end = 0, buffer_pos = 0; + +#ifdef ENABLE_DMA_LOG + sop = out ? "Read" : "Writ"; +#endif + + if (!(dev->sg_status & 1)) + return 2; /*S/G disabled*/ + + dma_log("DMA S/G %s: %i bytes\n", out ? "write" : "read", transfer_length); + + while (1) { + if (dev->count <= transfer_length) { + dma_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); + if (out) + dma_bm_read(dev->addr, (uint8_t *)(data + buffer_pos), dev->count, 4); + else + dma_bm_write(dev->addr, (uint8_t *)(data + buffer_pos), dev->count, 4); + transfer_length -= dev->count; + buffer_pos += dev->count; + } else { + dma_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); + if (out) + dma_bm_read(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length, 4); + else + 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. */ + dev->addr += transfer_length; + dev->count -= transfer_length; + transfer_length = 0; + force_end = 1; + } + + if (force_end) { + dma_log("Total transfer length smaller than sum of all blocks, partial block\n"); + return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + } else { + if (!transfer_length && !dev->eot) { + dma_log("Total transfer length smaller than sum of all blocks, full block\n"); + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else if (transfer_length && dev->eot) { + dma_log("Total transfer length greater than sum of all blocks\n"); + return 4; /* There is data left to transfer but we have reached EOT - return with error. */ + } else if (dev->eot) { + dma_log("Regular EOT\n"); + return 5; /* We have regularly reached EOT - clear status and break. */ + } else { + /* We have more to transfer and there are blocks left, get next block. */ + dma_sg_next_addr(dev); + } + } + } + + return 1; +} + + +uint8_t +_dma_read(uint32_t addr, dma_t *dma_c) +{ + uint8_t temp; + + if (dma_advanced) { + if (dma_c->sg_status & 1) + dma_c->sg_status = (dma_c->sg_status & 0x0f) | (dma_sg(&temp, 1, 1, dma_c) << 4); + else + dma_bm_read(addr, &temp, 1, dma_transfer_size(dma_c)); + } else + temp = mem_readb_phys(addr); return(temp); } -void -_dma_write(uint32_t addr, uint8_t val) +static uint16_t +_dma_readw(uint32_t addr, dma_t *dma_c) { - mem_writeb_phys(addr, val); - mem_invalidate_range(addr, addr); + uint8_t temp; + + if (dma_advanced) { + if (dma_c->sg_status & 1) + dma_c->sg_status = (dma_c->sg_status & 0x0f) | (dma_sg(&temp, 2, 1, dma_c) << 4); + else + dma_bm_read(addr, &temp, 2, dma_transfer_size(dma_c)); + } else + temp = _dma_read(addr, dma_c) | (_dma_read(addr + 1, dma_c) << 8); + + return(temp); +} + + +static void +_dma_write(uint32_t addr, uint8_t val, dma_t *dma_c) +{ + if (dma_advanced) { + if (dma_c->sg_status & 1) + dma_c->sg_status = (dma_c->sg_status & 0x0f) | (dma_sg(&val, 1, 0, dma_c) << 4); + else + dma_bm_write(addr, &val, 1, dma_transfer_size(dma_c)); + } else { + mem_writeb_phys(addr, val); + mem_invalidate_range(addr, addr); + } +} + + +static void +_dma_writew(uint32_t addr, uint16_t val, dma_t *dma_c) +{ + if (dma_advanced) { + if (dma_c->sg_status & 1) + dma_c->sg_status = (dma_c->sg_status & 0x0f) | (dma_sg((uint8_t *) &val, 2, 0, dma_c) << 4); + else + dma_bm_write(addr, (uint8_t *) &val, 2, dma_transfer_size(dma_c)); + } else { + _dma_write(addr, val & 0xff, dma_c); + _dma_write(addr + 1, val >> 8, dma_c); + } +} + + +static void +dma_retreat(dma_t *dma_c) +{ + int as = dma_c->transfer_mode >> 8; + + if (dma->sg_status & 1) { + dma_c->ac = (dma_c->ac - as) & dma_mask; + + dma_c->page = dma_c->page_l = (dma_c->ac >> 16) & 0xff; + dma_c->page_h = (dma_c->ac >> 24) & 0xff; + } else if (as == 2) + dma_c->ac = ((dma_c->ac & 0xfffe0000) & dma_mask) | ((dma_c->ac - as) & 0xffff); + else + dma_c->ac = ((dma_c->ac & 0xffff0000) & dma_mask) | ((dma_c->ac - as) & 0xffff); +} + + +void +dma_advance(dma_t *dma_c) +{ + int as = dma_c->transfer_mode >> 8; + + if (dma->sg_status & 1) { + dma_c->ac = (dma_c->ac + as) & dma_mask; + + dma_c->page = dma_c->page_l = (dma_c->ac >> 16) & 0xff; + dma_c->page_h = (dma_c->ac >> 24) & 0xff; + } else if (as == 2) + dma_c->ac = ((dma_c->ac & 0xfffe0000) & dma_mask) | ((dma_c->ac + as) & 0xffff); + else + dma_c->ac = ((dma_c->ac & 0xffff0000) & dma_mask) | ((dma_c->ac + as) & 0xffff); } @@ -745,10 +1333,10 @@ dma_channel_read(int channel) int tc = 0; if (channel < 4) { - if (dma_command & 0x04) + if (dma_command[0] & 0x04) return(DMA_NODATA); } else { - if (dma16_command & 0x04) + if (dma_command[1] & 0x04) return(DMA_NODATA); } @@ -763,31 +1351,39 @@ dma_channel_read(int channel) refreshread(); if (! dma_c->size) { - temp = _dma_read(dma_c->ac); + temp = _dma_read(dma_c->ac, dma_c); if (dma_c->mode & 0x20) { if (dma_ps2.is_ps2) dma_c->ac--; - else + else if (dma_advanced) + dma_retreat(dma_c); + else dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { if (dma_ps2.is_ps2) dma_c->ac++; - else + else if (dma_advanced) + dma_advance(dma_c); + else dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } } else { - temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + temp = _dma_readw(dma_c->ac, dma_c); if (dma_c->mode & 0x20) { if (dma_ps2.is_ps2) dma_c->ac -= 2; - else + else if (dma_advanced) + dma_retreat(dma_c); + else dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); } else { if (dma_ps2.is_ps2) dma_c->ac += 2; - else + else if (dma_advanced) + dma_advance(dma_c); + else dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } } @@ -796,17 +1392,27 @@ dma_channel_read(int channel) dma_c->cc--; if (dma_c->cc < 0) { - tc = 1; - if (dma_c->mode & 0x10) { /*Auto-init*/ - dma_c->cc = dma_c->cb; - dma_c->ac = dma_c->ab; - } else - dma_m |= (1 << channel); - dma_stat |= (1 << channel); + if (dma_advanced && (dma_c->sg_status & 1) && !(dma_c->sg_status & 6)) + dma_sg_next_addr(dma_c); + else { + tc = 1; + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } } - if (tc) + if (tc) { + if (dma_advanced && (dma_c->sg_status & 1) && ((dma_c->sg_command & 0xc0) == 0x40)) { + picint(1 << 13); + dma_c->sg_status |= 8; + } + return(temp | DMA_OVER); + } return(temp); } @@ -818,10 +1424,10 @@ dma_channel_write(int channel, uint16_t val) dma_t *dma_c = &dma[channel]; if (channel < 4) { - if (dma_command & 0x04) + if (dma_command[0] & 0x04) return(DMA_NODATA); } else { - if (dma16_command & 0x04) + if (dma_command[1] & 0x04) return(DMA_NODATA); } @@ -833,33 +1439,40 @@ dma_channel_write(int channel, uint16_t val) return(DMA_NODATA); if (! dma_c->size) { - _dma_write(dma_c->ac, val & 0xff); + _dma_write(dma_c->ac, val & 0xff, dma_c); if (dma_c->mode & 0x20) { if (dma_ps2.is_ps2) dma_c->ac--; - else + else if (dma_advanced) + dma_retreat(dma_c); + else dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { if (dma_ps2.is_ps2) dma_c->ac++; - else + else if (dma_advanced) + dma_advance(dma_c); + else dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } } else { - _dma_write(dma_c->ac, val & 0xff); - _dma_write(dma_c->ac + 1, val >> 8); + _dma_writew(dma_c->ac, val, dma_c); if (dma_c->mode & 0x20) { if (dma_ps2.is_ps2) dma_c->ac -= 2; - else + else if (dma_advanced) + dma_retreat(dma_c); + else dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); } else { if (dma_ps2.is_ps2) dma_c->ac += 2; - else + else if (dma_advanced) + dma_advance(dma_c); + else dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } } @@ -868,16 +1481,26 @@ dma_channel_write(int channel, uint16_t val) dma_c->cc--; if (dma_c->cc < 0) { - if (dma_c->mode & 0x10) { /*Auto-init*/ - dma_c->cc = dma_c->cb; - dma_c->ac = dma_c->ab; - } else - dma_m |= (1 << channel); - dma_stat |= (1 << channel); + if (dma_advanced && (dma_c->sg_status & 1) && !(dma_c->sg_status & 6)) + dma_sg_next_addr(dma_c); + else { + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } } - if (dma_m & (1 << channel)) + if (dma_m & (1 << channel)) { + if (dma_advanced && (dma_c->sg_status & 1) && ((dma_c->sg_command & 0xc0) == 0x40)) { + picint(1 << 13); + dma_c->sg_status |= 8; + } + return(DMA_OVER); + } return(0); } @@ -892,7 +1515,7 @@ dma_ps2_run(int channel) case DMA_PS2_XFER_MEM_TO_IO: do { if (! dma_c->size) { - uint8_t temp = _dma_read(dma_c->ac); + uint8_t temp = _dma_read(dma_c->ac, dma_c); outb(dma_c->io_addr, temp); @@ -901,7 +1524,7 @@ dma_ps2_run(int channel) else dma_c->ac++; } else { - uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + uint16_t temp = _dma_readw(dma_c->ac, dma_c); outw(dma_c->io_addr, temp); @@ -923,7 +1546,7 @@ dma_ps2_run(int channel) if (! dma_c->size) { uint8_t temp = inb(dma_c->io_addr); - _dma_write(dma_c->ac, temp); + _dma_write(dma_c->ac, temp, dma_c); if (dma_c->ps2_mode & DMA_PS2_DEC2) dma_c->ac--; @@ -932,8 +1555,7 @@ dma_ps2_run(int channel) } else { uint16_t temp = inw(dma_c->io_addr); - _dma_write(dma_c->ac, temp & 0xff); - _dma_write(dma_c->ac + 1, temp >> 8); + _dma_writew(dma_c->ac, temp, dma_c); if (dma_c->ps2_mode & DMA_PS2_DEC2) dma_c->ac -= 2; diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index d3fbd2a06..ddcc515f0 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -3811,7 +3811,7 @@ d86f_load(int drive, wchar_t *fn) if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; } } else { - dev->extra_bit_cells[0] = 0; + dev->extra_bit_cells[1] = 0; } } else { switch ((dev->disk_flags >> 1) >> 3) { diff --git a/src/include/86box/dma.h b/src/include/86box/dma.h index 5a2fbe701..d5ee9fcb3 100644 --- a/src/include/86box/dma.h +++ b/src/include/86box/dma.h @@ -46,19 +46,21 @@ typedef struct { - uint32_t ab, ac; - uint16_t cb; - int cc; - int wp; - uint8_t m, mode; - uint8_t page; - uint8_t stat, stat_rq; - uint8_t command; - int size; - - uint8_t ps2_mode; - uint8_t arb_level; - uint16_t io_addr; + uint8_t m, mode, page, stat, + stat_rq, command, + ps2_mode, arb_level, + sg_command, sg_status, + ptr0, enabled, + ext_mode, page_l, + page_h, pad; + uint16_t cb, io_addr, + base, transfer_mode; + uint32_t ptr, ptr_cur, + addr, + ab, ac; + int cc, wp, + size, count, + eot; } dma_t; @@ -93,5 +95,13 @@ extern void dma_alias_remove_piix(void); extern void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize); extern void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize); +void dma_set_params(uint8_t advanced, uint32_t mask); +void dma_ext_mode_init(void); + +void dma_high_page_init(void); + +void dma_remove_sg(void); +void dma_set_sg_base(uint8_t sg_base); + #endif /*EMU_DMA_H*/ diff --git a/src/intel_piix.c b/src/intel_piix.c index 34ab4eb3b..bc2558c12 100644 --- a/src/intel_piix.c +++ b/src/intel_piix.c @@ -1161,6 +1161,20 @@ piix_close(void *p) } +static void +piix_speed_changed(void *priv) +{ + piix_t *dev = (piix_t *) priv; + int te; + + te = timer_is_enabled(&dev->fast_off_timer); + + timer_stop(&dev->fast_off_timer); + if (te) + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); +} + + static void *piix_init(const device_t *info) { @@ -1300,7 +1314,7 @@ const device_t piix_device = piix_close, piix_reset, NULL, - NULL, + piix_speed_changed, NULL, NULL }; @@ -1314,7 +1328,7 @@ const device_t piix_rev02_device = piix_close, piix_reset, NULL, - NULL, + piix_speed_changed, NULL, NULL }; @@ -1328,7 +1342,7 @@ const device_t piix3_device = piix_close, piix_reset, NULL, - NULL, + piix_speed_changed, NULL, NULL }; @@ -1342,7 +1356,7 @@ const device_t piix4_device = piix_close, piix_reset, NULL, - NULL, + piix_speed_changed, NULL, NULL }; @@ -1356,7 +1370,7 @@ const device_t piix4e_device = piix_close, piix_reset, NULL, - NULL, + piix_speed_changed, NULL, NULL }; @@ -1370,7 +1384,7 @@ const device_t slc90e66_device = piix_close, piix_reset, NULL, - NULL, + piix_speed_changed, NULL, NULL }; diff --git a/src/intel_sio.c b/src/intel_sio.c index 577c9ef50..70ad0ebfc 100644 --- a/src/intel_sio.c +++ b/src/intel_sio.c @@ -41,12 +41,35 @@ typedef struct uint16_t timer_base, timer_latch; - pc_timer_t timer; + double fast_off_period; + pc_timer_t timer, fast_off_timer; + + apm_t * apm; port_92_t * port_92; } sio_t; +#ifdef ENABLE_SIO_LOG +int sio_do_log = ENABLE_SIO_LOG; + + +static void +sio_log(const char *fmt, ...) +{ + va_list ap; + + if (sio_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sio_log(fmt, ...) +#endif + + static void sio_timer_write(uint16_t addr, uint8_t val, void *priv) { @@ -131,39 +154,57 @@ sio_write(int func, int addr, uint8_t val, void *priv) return; old = dev->regs[addr]; - dev->regs[addr] = val; switch (addr) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - case 0x04: /*Command register*/ - val &= 0x08; - val |= 0x07; - break; - case 0x05: - val = 0; + if (dev->id == 0x03) + dev->regs[addr] = (dev->regs[addr] & 0xf7) | (val & 0x08); break; - case 0x06: /*Status*/ - val = 0; - break; case 0x07: - val = 0x02; + dev->regs[addr] &= ~(val & 0x38); break; case 0x40: - if (!((val ^ old) & 0x40)) - return; + if (dev->id == 0x03) { + dev->regs[addr] = (val & 0x7f); - dma_alias_remove(); - if (val & 0x40) - dma_alias_set(); + if (!((val ^ old) & 0x40)) + return; + + dma_alias_remove(); + if (val & 0x40) + dma_alias_set(); + } else + dev->regs[addr] = (val & 0x3f); + break; + case 0x41: case 0x44: + dev->regs[addr] = (val & 0x1f); + break; + case 0x42: + if (dev->id == 0x03) + dev->regs[addr] = val; + else + dev->regs[addr] = (val & 0x77); + break; + case 0x43: + if (dev->id == 0x03) + dev->regs[addr] = (val & 0x01); + break; + case 0x45: case 0x46: + case 0x47: case 0x48: + case 0x49: case 0x4a: + case 0x4b: case 0x4e: + case 0x54: case 0x55: + case 0x56: + dev->regs[addr] = val; + break; + case 0x4c: case 0x4d: + dev->regs[addr] = (val & 0x7f); break; - case 0x4f: + dev->regs[addr] = val; + if (!((val ^ old) & 0x40)) return; @@ -171,34 +212,29 @@ sio_write(int func, int addr, uint8_t val, void *priv) if (val & 0x40) port_92_add(dev->port_92); break; + case 0x57: + dev->regs[addr] = val; - case 0x60: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTA, val & 0xf); + dma_remove_sg(); + dma_set_sg_base(val); break; - case 0x61: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); + case 0x60: case 0x61: case 0x62: case 0x63: + if (dev->id == 0x03) { + sio_log("Set IRQ routing: INT %c -> %02X\n", 0x41 + (addr & 0x03), val); + dev->regs[addr] = val & 0x8f; + if (val & 0x80) + pci_set_irq_routing(PCI_INTA + (addr & 0x03), PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA + (addr & 0x03), val & 0xf); + } break; - case 0x62: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x63: - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - case 0x80: case 0x81: + if (addr == 0x80) + dev->regs[addr] = val & 0xfd; + else + dev->regs[addr] = val; + if (dev->timer_base & 0x01) { io_removehandler(dev->timer_base & 0xfffc, 0x0004, sio_timer_read, sio_timer_readw, NULL, @@ -211,6 +247,67 @@ sio_write(int func, int addr, uint8_t val, void *priv) sio_timer_write, sio_timer_writew, NULL, dev); } break; + case 0xa0: + if (dev->id == 0x03) { + dev->regs[addr] = val & 0x1f; + apm_set_do_smi(dev->apm, !!(val & 0x01) && !!(dev->regs[0xa2] & 0x80)); + switch ((val & 0x18) >> 3) { + case 0x00: + dev->fast_off_period = PCICLK * 32768.0 * 60000.0; + break; + case 0x01: + default: + dev->fast_off_period = 0.0; + break; + case 0x02: + dev->fast_off_period = PCICLK; + break; + case 0x03: + dev->fast_off_period = PCICLK * 32768.0; + break; + } + cpu_fast_off_count = dev->regs[0xa8] + 1; + timer_disable(&dev->fast_off_timer); + if (dev->fast_off_period != 0.0) + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + } + break; + case 0xa2: + if (dev->id == 0x03) { + dev->regs[addr] = val & 0xff; + apm_set_do_smi(dev->apm, !!(dev->regs[0xa0] & 0x01) && !!(val & 0x80)); + } + break; + case 0xaa: case 0xac: case 0xae: + if (dev->id == 0x03) + dev->regs[addr] = val & 0xff; + break; + case 0xa4: + if (dev->id == 0x03) { + dev->regs[addr] = val & 0xfb; + cpu_fast_off_flags = (cpu_fast_off_flags & 0xffffff00) | dev->regs[addr]; + } + break; + case 0xa5: + if (dev->id == 0x03) { + dev->regs[addr] = val & 0xff; + cpu_fast_off_flags = (cpu_fast_off_flags & 0xffff00ff) | (dev->regs[addr] << 8); + } + break; + case 0xa7: + if (dev->id == 0x03) { + dev->regs[addr] = val & 0xa0; + cpu_fast_off_flags = (cpu_fast_off_flags & 0x00ffffff) | (dev->regs[addr] << 24); + } + break; + case 0xa8: + dev->regs[addr] = val & 0xff; + cpu_fast_off_val = val; + cpu_fast_off_count = val + 1; + timer_disable(&dev->fast_off_timer); + if (dev->fast_off_period != 0.0) + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + break; } } @@ -271,7 +368,7 @@ sio_config_read(uint16_t port, void *priv) static void -sio_reset(void *priv) +sio_reset_hard(void *priv) { sio_t *dev = (sio_t *) priv; @@ -279,23 +376,26 @@ sio_reset(void *priv) dev->regs[0x00] = 0x86; dev->regs[0x01] = 0x80; /*Intel*/ dev->regs[0x02] = 0x84; dev->regs[0x03] = 0x04; /*82378IB (SIO)*/ - dev->regs[0x04] = 0x07; dev->regs[0x05] = 0x00; - dev->regs[0x06] = 0x00; dev->regs[0x07] = 0x02; + dev->regs[0x04] = 0x07; + dev->regs[0x07] = 0x02; dev->regs[0x08] = dev->id; dev->regs[0x40] = 0x20; dev->regs[0x41] = 0x00; - dev->regs[0x42] = 0x04; dev->regs[0x43] = 0x00; - dev->regs[0x44] = 0x20; dev->regs[0x45] = 0x10; - dev->regs[0x46] = 0x0f; dev->regs[0x47] = 0x00; - dev->regs[0x48] = 0x01; dev->regs[0x49] = 0x10; + dev->regs[0x42] = 0x04; + dev->regs[0x45] = 0x10; dev->regs[0x46] = 0x0f; + dev->regs[0x48] = 0x01; dev->regs[0x4a] = 0x10; dev->regs[0x4b] = 0x0f; dev->regs[0x4c] = 0x56; dev->regs[0x4d] = 0x40; dev->regs[0x4e] = 0x07; dev->regs[0x4f] = 0x4f; - dev->regs[0x54] = 0x00; dev->regs[0x55] = 0x00; dev->regs[0x56] = 0x00; - dev->regs[0x60] = 0x80; dev->regs[0x61] = 0x80; dev->regs[0x62] = 0x80; dev->regs[0x63] = 0x80; - dev->regs[0x80] = 0x78; dev->regs[0x81] = 0x00; - dev->regs[0xa0] = 0x08; - dev->regs[0xa8] = 0x0f; + dev->regs[0x57] = 0x04; + if (dev->id == 0x03) { + dev->regs[0x60] = 0x80; dev->regs[0x61] = 0x80; dev->regs[0x62] = 0x80; dev->regs[0x63] = 0x80; + } + dev->regs[0x80] = 0x78; + if (dev->id == 0x03) { + dev->regs[0xa0] = 0x08; + dev->regs[0xa8] = 0x0f; + } pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); @@ -312,12 +412,60 @@ sio_reset(void *priv) } +static void +sio_apm_out(uint16_t port, uint8_t val, void *p) +{ + sio_t *dev = (sio_t *) p; + + if (dev->apm->do_smi) + dev->regs[0xaa] |= 0x80; +} + + +static void +sio_fast_off_count(void *priv) +{ + sio_t *dev = (sio_t *) priv; + + cpu_fast_off_count--; + + if (cpu_fast_off_count == 0) { + smi_line = 1; + dev->regs[0xaa] |= 0x20; + cpu_fast_off_count = dev->regs[0xa8] + 1; + } + + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); +} + + +static void +sio_reset(void *p) +{ + sio_t *dev = (sio_t *) p; + + sio_write(0, 0x57, 0x04, p); + + dma_set_params(1, 0xffffffff); + + if (dev->id == 0x03) { + sio_write(0, 0xa0, 0x08, p); + sio_write(0, 0xa2, 0x00, p); + sio_write(0, 0xa4, 0x00, p); + sio_write(0, 0xa5, 0x00, p); + sio_write(0, 0xa6, 0x00, p); + sio_write(0, 0xa7, 0x00, p); + sio_write(0, 0xa8, 0x0f, p); + } +} + + static void sio_close(void *p) { - sio_t *sio = (sio_t *)p; + sio_t *dev = (sio_t *)p; - free(sio); + free(dev); } @@ -332,34 +480,64 @@ sio_speed_changed(void *priv) timer_disable(&dev->timer); if (te) timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); + + if (dev->id == 0x03) { + te = timer_is_enabled(&dev->fast_off_timer); + + timer_stop(&dev->fast_off_timer); + if (te) + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); + } } static void * sio_init(const device_t *info) { - sio_t *sio = (sio_t *) malloc(sizeof(sio_t)); - memset(sio, 0, sizeof(sio_t)); + sio_t *dev = (sio_t *) malloc(sizeof(sio_t)); + memset(dev, 0, sizeof(sio_t)); - pci_add_card(PCI_ADD_SOUTHBRIDGE, sio_read, sio_write, sio); + pci_add_card(PCI_ADD_SOUTHBRIDGE, sio_read, sio_write, dev); - device_add(&apm_device); + dev->id = info->local; - sio->id = info->local; - sio_reset(sio); + if (dev->id == 0x03) + timer_add(&dev->fast_off_timer, sio_fast_off_count, dev, 0); - sio->port_92 = device_add(&port_92_pci_device); + sio_reset_hard(dev); - dma_alias_set(); + cpu_fast_off_flags = 0x00000000; + + if (dev->id == 0x03) { + cpu_fast_off_val = dev->regs[0xa8]; + cpu_fast_off_count = cpu_fast_off_val + 1; + } else + cpu_fast_off_val = cpu_fast_off_count = 0; + + if (dev->id == 0x03) { + dev->apm = device_add(&apm_pci_device); + /* APM intercept handler to update 82378ZB SMI status on APM SMI. */ + io_sethandler(0x00b2, 0x0001, NULL, NULL, NULL, sio_apm_out, NULL, NULL, dev); + } + + dev->port_92 = device_add(&port_92_pci_device); + + dma_set_sg_base(0x04); + dma_set_params(1, 0xffffffff); + dma_ext_mode_init(); + dma_high_page_init(); + + if (dev->id == 0x03) + dma_alias_set(); io_sethandler(0x0073, 0x0001, - sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, sio); + sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, dev); io_sethandler(0x0075, 0x0001, - sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, sio); + sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, dev); - timer_add(&sio->timer, NULL, NULL, 0); + timer_add(&dev->timer, NULL, NULL, 0); - return sio; + return dev; } @@ -370,7 +548,7 @@ const device_t sio_device = 0x00, sio_init, sio_close, - NULL, + sio_reset, NULL, sio_speed_changed, NULL, @@ -385,7 +563,7 @@ const device_t sio_zb_device = 0x03, sio_init, sio_close, - NULL, + sio_reset, NULL, sio_speed_changed, NULL, diff --git a/src/pci.c b/src/pci.c index 283cffedc..15fcd9f1f 100644 --- a/src/pci.c +++ b/src/pci.c @@ -677,6 +677,7 @@ static void trc_reset(uint8_t val) { if (val & 2) { + dma_reset(); device_reset_all_pci(); cpu_alt_reset = 0;