2016-08-14 22:07:17 -04:00
|
|
|
/* Copyright holders: Sarah Walker
|
|
|
|
|
see COPYING for more details
|
|
|
|
|
*/
|
2016-06-26 00:34:39 +02:00
|
|
|
#include "ibm.h"
|
|
|
|
|
|
2016-11-11 03:16:41 +01:00
|
|
|
#include "disc.h"
|
2016-06-26 00:34:39 +02:00
|
|
|
#include "dma.h"
|
|
|
|
|
#include "fdc.h"
|
|
|
|
|
#include "io.h"
|
|
|
|
|
#include "mem.h"
|
|
|
|
|
#include "video.h"
|
|
|
|
|
|
|
|
|
|
static uint8_t dmaregs[16];
|
|
|
|
|
static int dmaon[4];
|
|
|
|
|
static uint8_t dma16regs[16];
|
|
|
|
|
static int dma16on[4];
|
|
|
|
|
static uint8_t dmapages[16];
|
|
|
|
|
|
|
|
|
|
void dma_reset()
|
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
dma.wp = 0;
|
|
|
|
|
for (c = 0; c < 16; c++)
|
|
|
|
|
dmaregs[c] = 0;
|
|
|
|
|
for (c = 0; c < 4; c++)
|
|
|
|
|
{
|
|
|
|
|
dma.mode[c] = 0;
|
|
|
|
|
dma.ac[c] = 0;
|
|
|
|
|
dma.cc[c] = 0;
|
|
|
|
|
dma.ab[c] = 0;
|
|
|
|
|
dma.cb[c] = 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)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
return temp;
|
|
|
|
|
|
|
|
|
|
case 8: /*Status register*/
|
|
|
|
|
temp = dma.stat;
|
|
|
|
|
dma.stat = 0;
|
|
|
|
|
return temp;
|
|
|
|
|
|
|
|
|
|
case 0xd:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc);
|
|
|
|
|
return dmaregs[addr & 0xf];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dma_write(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
// 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] & 0xff00) | val;
|
|
|
|
|
else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8);
|
2016-12-23 03:16:24 +01:00
|
|
|
dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3] & 0xffff;
|
2016-06-26 00:34:39 +02:00
|
|
|
dmaon[(addr >> 1) & 3] = 1;
|
|
|
|
|
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);
|
2016-12-23 03:16:24 +01:00
|
|
|
dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3] & 0xffff;
|
|
|
|
|
// pclog("DMA count for channel %i now: %02X\n", (addr >> 1) & 3, dma.cc[(addr >> 1) & 3]);
|
2016-06-26 00:34:39 +02:00
|
|
|
dmaon[(addr >> 1) & 3] = 1;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 8: /*Control register*/
|
|
|
|
|
dma.command = val;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xa: /*Mask*/
|
|
|
|
|
if (val & 4) dma.m |= (1 << (val & 3));
|
|
|
|
|
else dma.m &= ~(1 << (val & 3));
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xb: /*Mode*/
|
|
|
|
|
dma.mode[val & 3] = val;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xc: /*Clear FF*/
|
|
|
|
|
dma.wp = 0;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xd: /*Master clear*/
|
|
|
|
|
dma.wp = 0;
|
2016-11-14 04:55:48 +01:00
|
|
|
dma.stat = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
dma.m = 0xf;
|
|
|
|
|
return;
|
|
|
|
|
|
2016-11-14 04:55:48 +01:00
|
|
|
case 0xe: /*Mask reset*/
|
|
|
|
|
dma.m = 0;
|
|
|
|
|
return;
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
case 0xf: /*Mask write*/
|
|
|
|
|
dma.m = val & 0xf;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t dma16_read(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
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 (dma16.wp)
|
|
|
|
|
return dma16.ac[(addr >> 1) & 3] & 0xff;
|
|
|
|
|
return dma16.ac[(addr >> 1) & 3] >> 8;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
return temp;
|
|
|
|
|
|
|
|
|
|
case 8: /*Status register*/
|
|
|
|
|
temp = dma16.stat;
|
|
|
|
|
dma16.stat = 0;
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
return dma16regs[addr & 0xf];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dma16_write(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
// 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 (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00) | val;
|
|
|
|
|
else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8);
|
2016-12-23 03:16:24 +01:00
|
|
|
dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3] & 0xffff;
|
2016-06-26 00:34:39 +02:00
|
|
|
dma16on[(addr >> 1) & 3] = 1;
|
|
|
|
|
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);
|
2016-12-23 03:16:24 +01:00
|
|
|
dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3] & 0xffff;
|
2016-06-26 00:34:39 +02:00
|
|
|
dma16on[(addr >> 1) & 3] = 1;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 8: /*Control register*/
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xa: /*Mask*/
|
|
|
|
|
if (val & 4) dma16.m |= (1 << (val & 3));
|
|
|
|
|
else dma16.m &= ~(1 << (val & 3));
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xb: /*Mode*/
|
|
|
|
|
dma16.mode[val & 3] = val;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xc: /*Clear FF*/
|
|
|
|
|
dma16.wp = 0;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0xd: /*Master clear*/
|
|
|
|
|
dma16.wp = 0;
|
2016-11-14 04:55:48 +01:00
|
|
|
dma16.stat = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
dma16.m = 0xf;
|
|
|
|
|
return;
|
|
|
|
|
|
2016-11-14 04:55:48 +01:00
|
|
|
case 0xe: /*Mask reset*/
|
|
|
|
|
dma16.m = 0;
|
|
|
|
|
return;
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
case 0xf: /*Mask write*/
|
|
|
|
|
dma16.m = val&0xf;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void dma_page_write(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
dmapages[addr & 0xf] = val;
|
|
|
|
|
switch (addr & 0xf)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
dma.page[2] = (AT) ? val : val & 0xf;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
dma.page[3] = (AT) ? val : val & 0xf;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
dma.page[1] = (AT) ? val : val & 0xf;
|
|
|
|
|
break;
|
2016-11-13 23:44:16 +01:00
|
|
|
case 0x7:
|
|
|
|
|
if (is386)
|
|
|
|
|
{
|
|
|
|
|
dma.page[0] = (AT) ? val : val & 0xf;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-11-13 23:19:31 +01:00
|
|
|
case 0x9:
|
|
|
|
|
dma16.page[2] = val;
|
|
|
|
|
break;
|
|
|
|
|
case 0xa:
|
|
|
|
|
dma16.page[3] = val;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
case 0xb:
|
|
|
|
|
dma16.page[1] = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t dma_page_read(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return dmapages[addr & 0xf];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dma16_init()
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL);
|
|
|
|
|
io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
void dma_alias_set()
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dma_alias_remove()
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dma_alias_remove_piix()
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(0x0090, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
io_removehandler(0x0094, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
io_removehandler(0x0098, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
io_removehandler(0x009C, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
uint8_t _dma_read(uint32_t addr)
|
|
|
|
|
{
|
|
|
|
|
return mem_readb_phys(addr);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-22 21:22:56 +02:00
|
|
|
uint16_t _dma_readw(uint32_t addr)
|
|
|
|
|
{
|
|
|
|
|
return mem_readw_phys(addr);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
void _dma_write(uint32_t addr, uint8_t val)
|
|
|
|
|
{
|
|
|
|
|
mem_writeb_phys(addr, val);
|
|
|
|
|
mem_invalidate_range(addr, addr);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-22 21:22:56 +02:00
|
|
|
void _dma_writew(uint32_t addr, uint16_t val)
|
|
|
|
|
{
|
|
|
|
|
mem_writew_phys(addr, val);
|
|
|
|
|
mem_invalidate_range(addr, addr + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
int dma_is_masked(int channel)
|
|
|
|
|
{
|
|
|
|
|
if (channel < 4)
|
|
|
|
|
{
|
|
|
|
|
if (dma.m & (1 << channel))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (AT)
|
|
|
|
|
{
|
|
|
|
|
if (dma16.m & 1)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
channel &= 3;
|
|
|
|
|
if (dma16.m & (1 << channel))
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int dma_channel_mode(int channel)
|
|
|
|
|
{
|
|
|
|
|
if (channel < 4)
|
|
|
|
|
{
|
|
|
|
|
return (dma.mode[channel] & 0xC) >> 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
channel &= 3;
|
|
|
|
|
return (dma16.mode[channel] & 0xC) >> 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DMA * get_dma_controller(int channel)
|
|
|
|
|
{
|
|
|
|
|
if (channel < 4)
|
|
|
|
|
{
|
|
|
|
|
return &dma;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return &dma16;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
int dma_channel_read(int channel)
|
|
|
|
|
{
|
|
|
|
|
uint16_t temp;
|
|
|
|
|
int tc = 0;
|
2016-12-23 03:16:24 +01:00
|
|
|
|
|
|
|
|
int cmode = 0;
|
|
|
|
|
int real_channel = channel & 3;
|
|
|
|
|
|
|
|
|
|
int mem_over = 0;
|
|
|
|
|
|
|
|
|
|
DMA *dma_controller;
|
|
|
|
|
|
|
|
|
|
cmode = dma_channel_mode(channel);
|
|
|
|
|
|
|
|
|
|
channel &= 7;
|
|
|
|
|
|
|
|
|
|
if ((channel >= 4) && !AT)
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA read - channel is 4 or higher on a non-AT machine\n");
|
|
|
|
|
return DMA_NODATA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dma_controller = get_dma_controller(channel);
|
|
|
|
|
|
|
|
|
|
if (dma_controller->command & 0x04)
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA read - channel bit 2 of control bit is set\n");
|
2016-06-26 00:34:39 +02:00
|
|
|
return DMA_NODATA;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
if (!AT)
|
|
|
|
|
refreshread();
|
|
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if ((channel == 4) || dma_is_masked(channel))
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA read - channel is 4 or masked\n");
|
|
|
|
|
return DMA_NODATA;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if (cmode)
|
|
|
|
|
{
|
|
|
|
|
if (cmode != 2)
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA read - transfer mode (%i) is 1 or 3\n", cmode);
|
|
|
|
|
return DMA_NODATA;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (channel < 4)
|
2016-11-13 23:44:16 +01:00
|
|
|
{
|
2016-12-23 03:16:24 +01:00
|
|
|
temp = _dma_read(dma_controller->ac[real_channel] + (dma_controller->page[real_channel] << 16));
|
2016-11-13 23:44:16 +01:00
|
|
|
}
|
2016-12-23 03:16:24 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = _dma_readw((dma_controller->ac[real_channel] << 1) + ((dma_controller->page[real_channel] & ~1) << 16));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if (dma_controller->mode[real_channel] & 0x20)
|
|
|
|
|
{
|
|
|
|
|
if (dma_controller->ac[real_channel] == 0)
|
|
|
|
|
{
|
|
|
|
|
mem_over = 1;
|
|
|
|
|
}
|
|
|
|
|
dma_controller->ac[real_channel]--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (dma_controller->ac[real_channel] == 0xFFFF)
|
|
|
|
|
{
|
|
|
|
|
mem_over = 1;
|
|
|
|
|
}
|
|
|
|
|
dma_controller->ac[real_channel]++;
|
|
|
|
|
}
|
|
|
|
|
dma_controller->ac[real_channel] &= 0xffff;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
dma_controller->cc[real_channel]--;
|
|
|
|
|
if ((dma_controller->cc[real_channel] < 0) || mem_over)
|
2016-09-22 21:22:56 +02:00
|
|
|
{
|
2016-12-23 03:16:24 +01:00
|
|
|
tc = 1;
|
|
|
|
|
if (dma_controller->mode[real_channel] & 0x10) /*Auto-init*/
|
|
|
|
|
{
|
|
|
|
|
// pclog("DMA read auto-init\n");
|
|
|
|
|
dma_controller->cc[real_channel] = dma_controller->cb[real_channel] & 0xffff;
|
|
|
|
|
dma_controller->ac[real_channel] = dma_controller->ab[real_channel] & 0xffff;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dma_controller->cc[real_channel] &= 0xffff;
|
|
|
|
|
dma_controller->m |= (1 << real_channel);
|
|
|
|
|
}
|
|
|
|
|
dma_controller->stat |= (1 << real_channel);
|
2016-09-22 21:22:56 +02:00
|
|
|
}
|
2016-12-23 03:16:24 +01:00
|
|
|
|
|
|
|
|
if (tc)
|
|
|
|
|
{
|
|
|
|
|
// pclog("DMA read over in transfer mode %i (value %04X)!\n", cmode, temp);
|
|
|
|
|
return temp | DMA_OVER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pclog("DMA read success (value %04X)\n", temp);
|
|
|
|
|
return temp;
|
2016-09-22 21:22:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
int dma_channel_write(int channel, uint16_t val)
|
|
|
|
|
{
|
2016-12-23 03:16:24 +01:00
|
|
|
int tc = 0;
|
|
|
|
|
|
|
|
|
|
int cmode = 0;
|
|
|
|
|
int real_channel = channel & 3;
|
|
|
|
|
|
|
|
|
|
int mem_over = 0;
|
|
|
|
|
|
|
|
|
|
DMA *dma_controller;
|
|
|
|
|
|
|
|
|
|
cmode = dma_channel_mode(channel);
|
|
|
|
|
|
|
|
|
|
channel &= 7;
|
|
|
|
|
|
|
|
|
|
if ((channel >= 4) && !AT)
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA write - channel is 4 or higher on a non-AT machine\n");
|
|
|
|
|
return DMA_NODATA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dma_controller = get_dma_controller(channel);
|
|
|
|
|
|
|
|
|
|
if (dma_controller->command & 0x04)
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA write - channel bit 2 of control bit is set\n");
|
2016-06-26 00:34:39 +02:00
|
|
|
return DMA_NODATA;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
if (!AT)
|
|
|
|
|
refreshread();
|
|
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if ((channel == 4) || dma_is_masked(channel))
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA write - channel is 4 or masked\n");
|
|
|
|
|
return DMA_NODATA;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if (cmode)
|
|
|
|
|
{
|
|
|
|
|
if (cmode != 1)
|
|
|
|
|
{
|
|
|
|
|
// pclog ("DMA write - transfer mode (%i) is 2 or 3\n", cmode);
|
2016-06-26 00:34:39 +02:00
|
|
|
return DMA_NODATA;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if (channel < 4)
|
|
|
|
|
{
|
|
|
|
|
_dma_write(dma_controller->ac[real_channel] + (dma_controller->page[real_channel] << 16), val);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_dma_writew((dma_controller->ac[real_channel] << 1) + ((dma_controller->page[real_channel] & ~1) << 16), val);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
if (dma_controller->mode[real_channel] & 0x20)
|
|
|
|
|
{
|
|
|
|
|
if (dma_controller->ac[real_channel] == 0)
|
|
|
|
|
{
|
|
|
|
|
mem_over = 1;
|
|
|
|
|
}
|
|
|
|
|
dma_controller->ac[real_channel]--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (dma_controller->ac[real_channel] == 0xFFFF)
|
|
|
|
|
{
|
|
|
|
|
mem_over = 1;
|
|
|
|
|
}
|
|
|
|
|
dma_controller->ac[real_channel]++;
|
|
|
|
|
}
|
|
|
|
|
dma_controller->ac[real_channel] &= 0xffff;
|
|
|
|
|
|
|
|
|
|
dma_controller->cc[real_channel]--;
|
|
|
|
|
if ((dma_controller->cc[real_channel] < 0) || mem_over)
|
|
|
|
|
{
|
|
|
|
|
tc = 1;
|
|
|
|
|
if (dma_controller->mode[real_channel] & 0x10) /*Auto-init*/
|
|
|
|
|
{
|
|
|
|
|
// pclog("DMA write auto-init\n");
|
|
|
|
|
dma_controller->cc[real_channel] = dma_controller->cb[real_channel] & 0xffff;
|
|
|
|
|
dma_controller->ac[real_channel] = dma_controller->ab[real_channel] & 0xffff;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dma_controller->cc[real_channel] &= 0xffff;
|
|
|
|
|
dma_controller->m |= (1 << real_channel);
|
|
|
|
|
}
|
|
|
|
|
dma_controller->stat |= (1 << real_channel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (dma_is_masked(channel))
|
|
|
|
|
if (tc)
|
|
|
|
|
{
|
|
|
|
|
// pclog("DMA write over in transfer mode %i (value %04X)\n", cmode, val);
|
|
|
|
|
return DMA_OVER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pclog("DMA write success (value %04X)\n", val);
|
|
|
|
|
return 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2017-01-16 01:49:19 +01:00
|
|
|
#if 0
|
2016-12-23 17:11:59 +01:00
|
|
|
static uint32_t PageLengthReadWrite(uint32_t PhysAddress, uint32_t TotalSize)
|
2016-11-12 15:06:38 +01:00
|
|
|
{
|
2016-12-23 17:11:59 +01:00
|
|
|
uint32_t LengthSize;
|
2016-11-12 15:06:38 +01:00
|
|
|
uint32_t Page;
|
|
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
Page = PhysAddress & 4095;
|
|
|
|
|
|
2017-01-16 01:49:19 +01:00
|
|
|
if ((Page + TotalSize - 1) >= 4096)
|
|
|
|
|
{
|
|
|
|
|
TotalSize = 4096 - Page;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TotalSize;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2017-01-16 01:49:19 +01:00
|
|
|
#endif
|
2016-12-23 03:16:24 +01:00
|
|
|
|
|
|
|
|
//DMA Bus Master Page Read/Write
|
2016-12-23 17:11:59 +01:00
|
|
|
void DMAPageRead(uint32_t PhysAddress, void *DataRead, uint32_t TotalSize)
|
2016-12-23 03:16:24 +01:00
|
|
|
{
|
2017-01-16 01:49:19 +01:00
|
|
|
// uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize);
|
|
|
|
|
memcpy(DataRead, &ram[PhysAddress], TotalSize);
|
|
|
|
|
// DataRead -= PageLen;
|
|
|
|
|
DataRead -= TotalSize;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-23 17:11:59 +01:00
|
|
|
void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, uint32_t TotalSize)
|
2016-12-23 03:16:24 +01:00
|
|
|
{
|
2017-01-16 01:49:19 +01:00
|
|
|
// uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize);
|
|
|
|
|
mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1);
|
2017-01-24 01:03:23 +01:00
|
|
|
memcpy(&ram[PhysAddress], DataWrite, TotalSize);
|
2017-01-16 01:49:19 +01:00
|
|
|
// DataWrite -= PageLen;
|
|
|
|
|
DataWrite -= TotalSize;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
int dma_mode(int channel)
|
|
|
|
|
{
|
|
|
|
|
if (channel < 4)
|
|
|
|
|
{
|
|
|
|
|
return dma.mode[channel];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return dma16.mode[channel & 3];
|
|
|
|
|
}
|
2016-11-12 15:06:38 +01:00
|
|
|
}
|
2016-12-23 03:16:24 +01:00
|
|
|
|
|
|
|
|
/* void dma_c2_mode()
|
|
|
|
|
{
|
|
|
|
|
printf("DMA Channel 2 mode: %02X\n", dma.mode[2]);
|
|
|
|
|
} */
|