From 4182b10e10bd300e55247a740abb0b1d39d10e37 Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 11 Mar 2018 09:43:54 +0000 Subject: [PATCH] Refactored DMA code. --- src/dma.c | 779 ++++++++++++++++++++++++++++++------------------------ src/ibm.h | 27 +- 2 files changed, 442 insertions(+), 364 deletions(-) diff --git a/src/dma.c b/src/dma.c index bc4aba2..76d88a8 100644 --- a/src/dma.c +++ b/src/dma.c @@ -4,6 +4,7 @@ #include "fdc.h" #include "io.h" #include "mem.h" +#include "ps2_mca.h" #include "video.h" #include "x86.h" @@ -11,57 +12,73 @@ static uint8_t dmaregs[16]; static uint8_t dma16regs[16]; static uint8_t dmapages[16]; +static int dma_wp, dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, dma16_command; + +static struct +{ + int xfr_command, xfr_channel; + int byte_ptr; + + int is_ps2; +} dma_ps2; + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + +static void dma_ps2_run(int channel); + void dma_reset() { int c; - dma.wp = 0; + + dma_wp = dma16_wp = 0; + dma_m = 0; + for (c = 0; c < 16; c++) dmaregs[c] = 0; - for (c = 0; c < 4; c++) + for (c = 0; c < 8; c++) { - dma.mode[c] = 0; - dma.ac[c] = 0; - dma.cc[c] = 0; - dma.ab[c] = 0; - dma.cb[c] = 0; + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 0; } - dma.m = 0; - - dma16.wp = 0; - for (c = 0; c < 16; c++) - dma16regs[c] = 0; - for (c = 0; c < 4; c++) - { - dma16.mode[c] = 0; - dma16.ac[c] = 0; - dma16.cc[c] = 0; - dma16.ab[c] = 0; - dma16.cb[c] = 0; - } - dma16.m = 0; } uint8_t dma_read(uint16_t addr, void *priv) { + int channel = (addr >> 1) & 3; uint8_t temp; // printf("Read DMA %04X %04X:%04X %i %02X\n",addr,CS,pc, pic_intpending, pic.pend); switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma.wp ^= 1; - if (dma.wp) - return dma.ac[(addr >> 1) & 3] & 0xff; - return (dma.ac[(addr >> 1) & 3] >> 8) & 0xff; + dma_wp ^= 1; + if (dma_wp) + return dma[channel].ac & 0xff; + return (dma[channel].ac >> 8) & 0xff; case 1: case 3: case 5: case 7: /*Count registers*/ - dma.wp ^= 1; - if (dma.wp) temp = dma.cc[(addr >> 1) & 3] & 0xff; - else temp = dma.cc[(addr >> 1) & 3] >> 8; + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; return temp; case 8: /*Status register*/ - temp = dma.stat; - dma.stat = 0; + temp = dma_stat & 0xf; + dma_stat &= ~0xf; return temp; case 0xd: @@ -73,122 +90,131 @@ uint8_t dma_read(uint16_t addr, void *priv) void dma_write(uint16_t addr, uint8_t val, void *priv) { + int channel = (addr >> 1) & 3; // printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc); dmaregs[addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma.wp ^= 1; - if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xffff00) | val; - else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); - dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3]; + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; // pclog("Addr = %04x\n", dma.ab[(addr >> 1) & 3]); return; case 1: case 3: case 5: case 7: /*Count registers*/ - dma.wp ^= 1; - if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val; - else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3]; + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; return; case 8: /*Control register*/ - dma.command = val; + dma_command = val; return; case 0xa: /*Mask*/ - if (val & 4) dma.m |= (1 << (val & 3)); - else dma.m &= ~(1 << (val & 3)); + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); return; case 0xb: /*Mode*/ - dma.mode[val & 3] = val; - if (dma.is_ps2) + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) { - dma.ps2_mode[val & 3] &= ~0x1c; + dma[channel].ps2_mode &= ~0x1c; if (val & 0x20) - dma.ps2_mode[val & 3] |= 0x10; + dma[channel].ps2_mode |= 0x10; if ((val & 0xc) == 8) - dma.ps2_mode[val & 3] |= 4; + dma[channel].ps2_mode |= 4; else if ((val & 0xc) == 4) - dma.ps2_mode[val & 3] |= 0xc; + dma[channel].ps2_mode |= 0xc; } return; case 0xc: /*Clear FF*/ - dma.wp = 0; + dma_wp = 0; return; case 0xd: /*Master clear*/ - dma.wp = 0; - dma.m = 0xf; + dma_wp = 0; + dma_m |= 0xf; return; case 0xf: /*Mask write*/ - dma.m = val & 0xf; + dma_m = (dma_m & 0xf0) | (val & 0xf); return; } } static uint8_t dma_ps2_read(uint16_t addr, void *priv) { + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; uint8_t temp = 0xff; switch (addr) { case 0x1a: - switch (dma.xfr_command) + switch (dma_ps2.xfr_command) { case 2: /*Address*/ case 3: - switch (dma.byte_ptr) + switch (dma_ps2.byte_ptr) { case 0: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] & 0xff) : (dma.ac[dma.xfr_channel] & 0xff); - dma.byte_ptr = 1; + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; break; case 1: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 8) : (dma.ac[dma.xfr_channel] >> 8); - dma.byte_ptr = 2; + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; break; case 2: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 16) : (dma.ac[dma.xfr_channel] >> 16); - dma.byte_ptr = 0; + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; break; } break; case 4: /*Count*/ case 5: - if (dma.byte_ptr) - temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] >> 8) : (dma.cc[dma.xfr_channel] >> 8); + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; else - temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] & 0xff) : (dma.cc[dma.xfr_channel] & 0xff); - dma.byte_ptr = (dma.byte_ptr + 1) & 1; + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; break; case 6: /*Read DMA status*/ - if (dma.byte_ptr) + if (dma_ps2.byte_ptr) { - temp = dma16.stat_rq | (dma16.stat << 4); - dma16.stat = 0; - dma16.stat_rq = 0; + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; } else { - temp = dma.stat_rq | (dma.stat << 4); - dma.stat = 0; - dma.stat_rq = 0; + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; } - dma.byte_ptr = (dma.byte_ptr + 1) & 1; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; break; case 7: /*Mode*/ - temp = (dma.xfr_channel & 4) ? dma16.ps2_mode[dma.xfr_channel & 3] : dma.ps2_mode[dma.xfr_channel]; + temp = dma_c->ps2_mode; break; case 8: /*Arbitration Level*/ - temp = (dma.xfr_channel & 4) ? dma16.arb_level[dma.xfr_channel & 3] : dma.arb_level[dma.xfr_channel]; + temp = dma_c->arb_level; break; default: - fatal("Bad XFR Read command %i channel %i\n", dma.xfr_command, dma.xfr_channel); + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); } break; } @@ -200,6 +226,7 @@ static uint8_t dma_ps2_read(uint16_t addr, void *priv) static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) { + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; uint8_t mode; // pclog("Write PS2 DMA %04X %02X %04X:%04X\n",addr,val,CS,cpu_state.pc); @@ -207,114 +234,83 @@ static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) switch (addr) { case 0x18: - dma.xfr_channel = val & 0x7; - dma.xfr_command = val >> 4; - dma.byte_ptr = 0; - switch (dma.xfr_command) + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) { case 9: /*Set DMA mask*/ - if (dma.xfr_channel & 4) - dma16.m |= (1 << (dma.xfr_channel & 3)); - else - dma.m |= (1 << dma.xfr_channel); + dma_m |= (1 << dma_ps2.xfr_channel); break; case 0xa: /*Reset DMA mask*/ - if (dma.xfr_channel & 4) - dma16.m &= ~(1 << (dma.xfr_channel & 3)); - else - dma.m &= ~(1 << dma.xfr_channel); + dma_m &= ~(1 << dma_ps2.xfr_channel); break; + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); + break; + +// case 0xb: output = 3; break; } break; case 0x1a: - switch (dma.xfr_command) + switch (dma_ps2.xfr_command) { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + case 2: /*Address*/ - switch (dma.byte_ptr) + switch (dma_ps2.byte_ptr) { case 0: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xffff00) | val; - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xffff00) | val; - dma.byte_ptr = 1; + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; break; case 1: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xff00ff) | (val << 8); - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xff00ff) | (val << 8); - dma.byte_ptr = 2; + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; break; case 2: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0x00ffff) | (val << 16); - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0x00ffff) | (val << 16); - dma.byte_ptr = 0; + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; break; } - if (dma.xfr_channel & 4) - dma16.ab[dma.xfr_channel & 3] = dma16.ac[dma.xfr_channel & 3]; - else - dma.ab[dma.xfr_channel] = dma.ac[dma.xfr_channel]; + dma_c->ab = dma_c->ac; break; case 4: /*Count*/ - if (dma.byte_ptr) - { - if (dma.xfr_channel & 4) - dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff) | (val << 8); - else - dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff) | (val << 8); - } + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); else - { - if (dma.xfr_channel & 4) - dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff00) | val; - else - dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff00) | val; - } - dma.byte_ptr = (dma.byte_ptr + 1) & 1; - if (dma.xfr_channel & 4) - dma16.cb[dma.xfr_channel & 3] = dma16.cc[dma.xfr_channel & 3]; - else - dma.cb[dma.xfr_channel] = dma.cc[dma.xfr_channel]; + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; break; case 7: /*Mode register*/ mode = 0; - if (val & 0x10) + if (val & DMA_PS2_DEC2) mode |= 0x20; - if ((val & 0xc) == 4) + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) mode |= 8; - else if ((val & 0xc) == 0xc) + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) mode |= 4; - if ((val & 0x40) && !(dma.xfr_channel & 4)) - fatal("16-bit DMA on 8-bit channel\n"); - if (!(val & 0x40) && (dma.xfr_channel & 4)) - fatal("8-bit DMA on 16-bit channel\n"); - if (dma.xfr_channel & 4) - { - dma16.mode[dma.xfr_channel & 3] = (dma16.mode[dma.xfr_channel & 3] & ~0x2c) | mode; - dma16.ps2_mode[dma.xfr_channel & 3] = val; - } - else - { - dma.mode[dma.xfr_channel] = (dma.mode[dma.xfr_channel] & ~0x2c) | mode; - dma.ps2_mode[dma.xfr_channel] = val; - } + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; break; case 8: /*Arbitration Level*/ - if (dma.xfr_channel & 4) - dma16.arb_level[dma.xfr_channel & 3] = val; - else - dma.arb_level[dma.xfr_channel] = val; + dma_c->arb_level = val; break; default: - fatal("Bad XFR command %i channel %i val %02x\n", dma.xfr_command, dma.xfr_channel, val); + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); } break; } @@ -322,32 +318,35 @@ static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) uint8_t dma16_read(uint16_t addr, void *priv) { + int channel = ((addr >> 2) & 3) + 4; uint8_t temp; // printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc); addr >>= 1; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma16.wp ^= 1; - if (dma.is_ps2) + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { - if (dma16.wp) - return dma16.ac[(addr >> 1) & 3] & 0xff; - return (dma16.ac[(addr >> 1) & 3] >> 8) & 0xff; + if (dma16_wp) + return dma[channel].ac; + return (dma[channel].ac >> 8) & 0xff; } - if (dma16.wp) - return (dma16.ac[(addr >> 1) & 3] >> 1) & 0xff; - return (dma16.ac[(addr >> 1) & 3] >> 9) & 0xff; + if (dma16_wp) + return (dma[channel].ac >> 1) & 0xff; + return (dma[channel].ac >> 9) & 0xff; case 1: case 3: case 5: case 7: /*Count registers*/ - dma16.wp ^= 1; - if (dma16.wp) temp = dma16.cc[(addr >> 1) & 3] & 0xff; - else temp = dma16.cc[(addr >> 1) & 3] >> 8; + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; return temp; case 8: /*Status register*/ - temp = dma16.stat; - dma16.stat = 0; + temp = dma_stat >> 4; + dma_stat &= ~0xf0; return temp; } return dma16regs[addr & 0xf]; @@ -355,66 +354,76 @@ uint8_t dma16_read(uint16_t addr, void *priv) void dma16_write(uint16_t addr, uint8_t val, void *priv) { + int channel = ((addr >> 2) & 3) + 4; // printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc); addr >>= 1; dma16regs[addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma16.wp ^= 1; - if (dma.is_ps2) + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xffff00) | val; - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); } else { - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfffe00) | (val << 1); - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfe01ff) | (val << 9); + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); } - dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3]; + dma[channel].ac = dma[channel].ab; return; case 1: case 3: case 5: case 7: /*Count registers*/ - dma16.wp ^= 1; - if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val; - else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3]; + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; return; case 8: /*Control register*/ return; case 0xa: /*Mask*/ - if (val & 4) dma16.m |= (1 << (val & 3)); - else dma16.m &= ~(1 << (val & 3)); + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); return; case 0xb: /*Mode*/ - dma16.mode[val & 3] = val; - if (dma.is_ps2) + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) { - dma16.ps2_mode[val & 3] &= ~0x1c; + dma[channel].ps2_mode &= ~0x1c; if (val & 0x20) - dma16.ps2_mode[val & 3] |= 0x10; + dma[channel].ps2_mode |= 0x10; if ((val & 0xc) == 8) - dma16.ps2_mode[val & 3] |= 4; + dma[channel].ps2_mode |= 4; else if ((val & 0xc) == 4) - dma16.ps2_mode[val & 3] |= 0xc; + dma[channel].ps2_mode |= 0xc; } return; case 0xc: /*Clear FF*/ - dma16.wp = 0; + dma16_wp = 0; return; case 0xd: /*Master clear*/ - dma16.wp = 0; - dma16.m = 0xf; + dma16_wp = 0; + dma_m |= 0xf0; return; case 0xf: /*Mask write*/ - dma16.m = val&0xf; + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); return; } } @@ -426,39 +435,39 @@ void dma_page_write(uint16_t addr, uint8_t val, void *priv) switch (addr & 0xf) { case 1: - dma.page[2] = (AT) ? val : val & 0xf; - dma.ab[2] = (dma.ab[2] & 0xffff) | (dma.page[2] << 16); - dma.ac[2] = (dma.ac[2] & 0xffff) | (dma.page[2] << 16); + 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; case 2: - dma.page[3] = (AT) ? val : val & 0xf; - dma.ab[3] = (dma.ab[3] & 0xffff) | (dma.page[3] << 16); - dma.ac[3] = (dma.ac[3] & 0xffff) | (dma.page[3] << 16); + 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; case 3: - dma.page[1] = (AT) ? val : val & 0xf; - dma.ab[1] = (dma.ab[1] & 0xffff) | (dma.page[1] << 16); - dma.ac[1] = (dma.ac[1] & 0xffff) | (dma.page[1] << 16); + 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; case 7: - dma.page[0] = (AT) ? val : val & 0xf; - dma.ab[0] = (dma.ab[0] & 0xffff) | (dma.page[0] << 16); - dma.ac[0] = (dma.ac[0] & 0xffff) | (dma.page[0] << 16); + 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: - dma16.page[2] = val & 0xfe; - dma16.ab[2] = (dma16.ab[2] & 0x1ffff) | (dma16.page[2] << 16); - dma16.ac[2] = (dma16.ac[2] & 0x1ffff) | (dma16.page[2] << 16); + 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: - dma16.page[3] = val & 0xfe; - dma16.ab[3] = (dma16.ab[3] & 0x1ffff) | (dma16.page[3] << 16); - dma16.ac[3] = (dma16.ac[3] & 0x1ffff) | (dma16.page[3] << 16); + 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: - dma16.page[1] = val & 0xfe; - dma16.ab[1] = (dma16.ab[1] & 0x1ffff) | (dma16.page[1] << 16); - dma16.ac[1] = (dma16.ac[1] & 0x1ffff) | (dma16.page[1] << 16); + 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; } } @@ -472,7 +481,7 @@ void dma_init() { io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); - dma.is_ps2 = 0; + dma_ps2.is_ps2 = 0; } void dma16_init() @@ -485,7 +494,7 @@ void ps2_dma_init() { io_sethandler(0x0018, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); io_sethandler(0x001a, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); - dma.is_ps2 = 1; + dma_ps2.is_ps2 = 1; } @@ -503,195 +512,267 @@ void _dma_write(uint32_t addr, uint8_t val) int dma_channel_read(int channel) { + dma_t *dma_c = &dma[channel]; uint16_t temp; int tc = 0; - if (dma.command & 0x04) - return DMA_NODATA; - - if (!AT) - refreshread(); - if (channel < 4) { - if (dma.m & (1 << channel)) - return DMA_NODATA; - if ((dma.mode[channel] & 0xC) != 8) - return DMA_NODATA; - - temp = _dma_read(dma.ac[channel]); - dma.stat_rq |= (1 << channel); - - if (dma.mode[channel] & 0x20) - { - if (dma.is_ps2) - dma.ac[channel]--; - else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); - } - else - { - if (dma.is_ps2) - dma.ac[channel]++; - else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); - } - dma.cc[channel]--; - if (dma.cc[channel] < 0) - { - tc = 1; - if (dma.mode[channel] & 0x10) /*Auto-init*/ - { - dma.cc[channel] = dma.cb[channel]; - dma.ac[channel] = dma.ab[channel]; - } - else - dma.m |= (1 << channel); - dma.stat |= (1 << channel); - } - - if (tc) - return temp | DMA_OVER; - return temp; + if (dma_command & 0x04) + return DMA_NODATA; } else { - channel &= 3; - if (dma16.m & (1 << channel)) - return DMA_NODATA; - if ((dma16.mode[channel] & 0xC) != 8) - return DMA_NODATA; + if (dma16_command & 0x04) + return DMA_NODATA; + } + + if (!AT) + refreshread(); - temp = _dma_read(dma16.ac[channel]) | - (_dma_read(dma16.ac[channel] + 1) << 8); - dma16.stat_rq |= (1 << channel); + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 8) + return DMA_NODATA; + + if (!dma_c->size) + { + temp = _dma_read(dma_c->ac); - if (dma16.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma16.ac[channel] -= 2; + if (dma_ps2.is_ps2) + dma_c->ac--; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { - if (dma.is_ps2) - dma16.ac[channel] += 2; + if (dma_ps2.is_ps2) + dma_c->ac++; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } - - dma16.cc[channel]--; - if (dma16.cc[channel] < 0) - { - tc = 1; - if (dma16.mode[channel] & 0x10) /*Auto-init*/ - { - dma16.cc[channel] = dma16.cb[channel]; - dma16.ac[channel] = dma16.ab[channel]; - } - else - dma16.m |= (1 << channel); - dma16.stat |= (1 << channel); - } - - if (tc) - return temp | DMA_OVER; - return temp; } + else + { + temp = _dma_read(dma_c->ac) | + (_dma_read(dma_c->ac + 1) << 8); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << 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 (tc) + return temp | DMA_OVER; + return temp; } int dma_channel_write(int channel, uint16_t val) { - if (dma.command & 0x04) - return DMA_NODATA; + dma_t *dma_c = &dma[channel]; + + if (channel < 4) + { + if (dma_command & 0x04) + return DMA_NODATA; + } + else + { + if (dma16_command & 0x04) + return DMA_NODATA; + } if (!AT) refreshread(); - if (channel < 4) - { - if (dma.m & (1 << channel)) - return DMA_NODATA; - if ((dma.mode[channel] & 0xC) != 4) - return DMA_NODATA; + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 4) + return DMA_NODATA; - _dma_write(dma.ac[channel], val); - dma.stat_rq |= (1 << channel); + if (!dma_c->size) + { + _dma_write(dma_c->ac, val); - if (dma.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma.ac[channel]--; + if (dma_ps2.is_ps2) + dma_c->ac--; else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { - if (dma.is_ps2) - dma.ac[channel]++; + if (dma_ps2.is_ps2) + dma_c->ac++; else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } - - dma.cc[channel]--; - if (dma.cc[channel] < 0) - { - if (dma.mode[channel] & 0x10) /*Auto-init*/ - { - dma.cc[channel] = dma.cb[channel]; - dma.ac[channel] = dma.ab[channel]; - } - else - dma.m |= (1 << channel); - dma.stat |= (1 << channel); - } - - if (dma.m & (1 << channel)) - return DMA_OVER; } else { - channel &= 3; - if (dma16.m & (1 << channel)) - return DMA_NODATA; - if ((dma16.mode[channel] & 0xC) != 4) - return DMA_NODATA; + _dma_write(dma_c->ac, val); + _dma_write(dma_c->ac + 1, val >> 8); - _dma_write(dma16.ac[channel], val); - _dma_write(dma16.ac[channel] + 1, val >> 8); - dma16.stat_rq |= (1 << channel); - - if (dma16.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma16.ac[channel] -= 2; + if (dma_ps2.is_ps2) + dma_c->ac -= 2; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); } else { - if (dma.is_ps2) - dma16.ac[channel] += 2; + if (dma_ps2.is_ps2) + dma_c->ac += 2; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } - - dma16.cc[channel]--; - if (dma16.cc[channel] < 0) - { - if (dma16.mode[channel] & 0x10) /*Auto-init*/ - { - dma16.cc[channel] = dma16.cb[channel]; - dma16.ac[channel] = dma16.ab[channel]; - } - else - dma16.m |= (1 << channel); - dma16.stat |= (1 << channel); - } - - if (dma16.m & (1 << channel)) - return DMA_OVER; } + + dma_stat_rq |= (1 << channel); + + 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_m & (1 << channel)) + return DMA_OVER; + return 0; } + +static void dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) + { + case DMA_PS2_XFER_MEM_TO_IO: + do + { + if (!dma_c->size) + { + uint8_t temp = _dma_read(dma_c->ac); + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do + { + if (!dma_c->size) + { + uint8_t temp = inb(dma_c->io_addr); + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = inw(dma_c->io_addr); + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do + { + if (!dma_c->size) + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + } +} diff --git a/src/ibm.h b/src/ibm.h index be6c68a..6f1c001 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -328,27 +328,24 @@ float pit_timer0_freq(); /*DMA*/ -typedef struct DMA +typedef struct dma_t { - uint32_t ab[4],ac[4]; - uint16_t cb[4]; - int cc[4]; + uint32_t ab, ac; + uint16_t cb; + int cc; int wp; - uint8_t m,mode[4]; - uint8_t page[4]; + uint8_t m, mode; + uint8_t page; uint8_t stat, stat_rq; uint8_t command; + int size; - int xfr_command, xfr_channel; - int byte_ptr; - - int is_ps2; - uint8_t arb_level[4]; - uint8_t ps2_mode[4]; -} DMA; - -DMA dma,dma16; + uint8_t ps2_mode; + uint8_t arb_level; + uint16_t io_addr; +} dma_t; +dma_t dma[8]; /*PPI*/ typedef struct PPI