- added the capability to transfer more then one byte per ISA DMA cycle.

- use this feature for floppy read and write operations. This does not mean that
  the floppy now works faster than realtime, but it reduces the number of DMA
  calls from the CPU.
- removed outdated file: patch.fast-dma-cbothamy
- TODO: implement this feature in the SB16 (8 and 16 bit)
This commit is contained in:
Volker Ruppert 2012-07-12 21:20:46 +00:00
parent 5d66e8450e
commit c6a9f8eb0d
8 changed files with 113 additions and 669 deletions

View File

@ -66,8 +66,8 @@ bx_dma_c::~bx_dma_c()
}
unsigned bx_dma_c::registerDMA8Channel(unsigned channel,
void (* dmaRead)(Bit8u *data_byte),
void (* dmaWrite)(Bit8u *data_byte),
Bit16u (* dmaRead)(Bit8u *data_byte, Bit16u maxlen),
Bit16u (* dmaWrite)(Bit8u *data_byte, Bit16u maxlen),
const char *name)
{
if (channel > 3) {
@ -86,8 +86,8 @@ unsigned bx_dma_c::registerDMA8Channel(unsigned channel,
}
unsigned bx_dma_c::registerDMA16Channel(unsigned channel,
void (* dmaRead)(Bit16u *data_word),
void (* dmaWrite)(Bit16u *data_word),
Bit16u (* dmaRead)(Bit16u *data_word, Bit16u maxlen),
Bit16u (* dmaWrite)(Bit16u *data_word, Bit16u maxlen),
const char *name)
{
if ((channel < 4) || (channel > 7)) {
@ -661,8 +661,10 @@ void bx_dma_c::raise_HLDA(void)
{
unsigned channel;
bx_phy_address phy_addr;
bx_bool count_expired = 0;
bx_bool ma_sl = 0;
Bit16u maxlen, len = 1;
Bit8u buffer[512];
Bit16u data_word;
BX_DMA_THIS HLDA = 1;
// find highest priority channel
@ -691,53 +693,32 @@ void bx_dma_c::raise_HLDA(void)
phy_addr = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
(BX_DMA_THIS s[ma_sl].chan[channel].current_address << ma_sl);
BX_DMA_THIS s[ma_sl].DACK[channel] = 1;
// check for expiration of count, so we can signal TC and DACK(n)
// at the same time.
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0)
BX_DMA_THIS s[ma_sl].chan[channel].current_address++;
else
BX_DMA_THIS s[ma_sl].chan[channel].current_address--;
BX_DMA_THIS s[ma_sl].chan[channel].current_count--;
if (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0xffff) {
// count expired, done with transfer
// assert TC, deassert HRQ & DACK(n) lines
BX_DMA_THIS s[ma_sl].status_reg |= (1 << channel); // hold TC in status reg
BX_DMA_THIS TC = 1;
count_expired = 1;
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable == 0) {
// set mask bit if not in autoinit mode
BX_DMA_THIS s[ma_sl].mask[channel] = 1;
}
else {
// count expired, but in autoinit mode
// reload count and base address
BX_DMA_THIS s[ma_sl].chan[channel].current_address =
BX_DMA_THIS s[ma_sl].chan[channel].base_address;
BX_DMA_THIS s[ma_sl].chan[channel].current_count =
BX_DMA_THIS s[ma_sl].chan[channel].base_count;
if (!BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement) {
maxlen = BX_DMA_THIS s[ma_sl].chan[channel].current_count + 1;
BX_DMA_THIS TC = (maxlen <= 512);
if (maxlen > 512) {
maxlen = 512;
}
} else {
BX_DMA_THIS TC = (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0);
maxlen = 1;
}
Bit8u data_byte;
Bit16u data_word;
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 1) { // write
// DMA controlled xfer of byte from I/O to Memory
if (!ma_sl) {
if (BX_DMA_THIS h[channel].dmaWrite8)
BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
len = BX_DMA_THIS h[channel].dmaWrite8(buffer, maxlen);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
DEV_MEM_WRITE_PHYSICAL(phy_addr, 1, &data_byte);
DEV_MEM_WRITE_PHYSICAL_DMA(phy_addr, len, buffer);
BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, data_byte);
}
else {
BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, buffer[0]);
} else {
if (BX_DMA_THIS h[channel].dmaWrite16)
BX_DMA_THIS h[channel].dmaWrite16(&data_word);
len = BX_DMA_THIS h[channel].dmaWrite16(&data_word, 1);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
@ -745,48 +726,65 @@ void bx_dma_c::raise_HLDA(void)
BX_DBG_DMA_REPORT(phy_addr, 2, BX_WRITE, data_word);
}
}
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 2) { // read
} else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 2) { // read
// DMA controlled xfer of byte from Memory to I/O
if (!ma_sl) {
DEV_MEM_READ_PHYSICAL(phy_addr, 1, &data_byte);
DEV_MEM_READ_PHYSICAL_DMA(phy_addr, maxlen, buffer);
if (BX_DMA_THIS h[channel].dmaRead8)
BX_DMA_THIS h[channel].dmaRead8(&data_byte);
len = BX_DMA_THIS h[channel].dmaRead8(buffer, maxlen);
BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, data_byte);
}
else {
BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, buffer[0]);
} else {
DEV_MEM_READ_PHYSICAL(phy_addr, 2, (Bit8u*) &data_word);
if (BX_DMA_THIS h[channel].dmaRead16)
BX_DMA_THIS h[channel].dmaRead16(&data_word);
len = BX_DMA_THIS h[channel].dmaRead16(&data_word, 1);
BX_DBG_DMA_REPORT(phy_addr, 2, BX_READ, data_word);
}
}
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 0) {
} else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 0) {
// verify
if (!ma_sl) {
if (BX_DMA_THIS h[channel].dmaWrite8)
BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
len = BX_DMA_THIS h[channel].dmaWrite8(buffer, 1);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
}
else {
} else {
if (BX_DMA_THIS h[channel].dmaWrite16)
BX_DMA_THIS h[channel].dmaWrite16(&data_word);
len = BX_DMA_THIS h[channel].dmaWrite16(&data_word, 1);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
}
}
else {
} else {
BX_PANIC(("hlda: transfer_type 3 is undefined"));
}
if (count_expired) {
BX_DMA_THIS s[ma_sl].DACK[channel] = 1;
// check for expiration of count, so we can signal TC and DACK(n)
// at the same time.
if (!BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement)
BX_DMA_THIS s[ma_sl].chan[channel].current_address += len;
else
BX_DMA_THIS s[ma_sl].chan[channel].current_address--;
BX_DMA_THIS s[ma_sl].chan[channel].current_count -= len;
if (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0xffff) {
// count expired, done with transfer
// assert TC, deassert HRQ & DACK(n) lines
BX_DMA_THIS s[ma_sl].status_reg |= (1 << channel); // hold TC in status reg
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable == 0) {
// set mask bit if not in autoinit mode
BX_DMA_THIS s[ma_sl].mask[channel] = 1;
} else {
// count expired, but in autoinit mode
// reload count and base address
BX_DMA_THIS s[ma_sl].chan[channel].current_address =
BX_DMA_THIS s[ma_sl].chan[channel].base_address;
BX_DMA_THIS s[ma_sl].chan[channel].current_count =
BX_DMA_THIS s[ma_sl].chan[channel].base_count;
}
BX_DMA_THIS TC = 0; // clear TC, adapter card already notified
BX_DMA_THIS HLDA = 0;
bx_pc_system.set_HRQ(0); // clear HRQ to CPU

View File

@ -46,12 +46,12 @@ public:
#endif
virtual unsigned registerDMA8Channel(unsigned channel,
void (* dmaRead)(Bit8u *data_byte),
void (* dmaWrite)(Bit8u *data_byte),
Bit16u (* dmaRead)(Bit8u *data_byte, Bit16u maxlen),
Bit16u (* dmaWrite)(Bit8u *data_byte, Bit16u maxlen),
const char *name);
virtual unsigned registerDMA16Channel(unsigned channel,
void (* dmaRead)(Bit16u *data_word),
void (* dmaWrite)(Bit16u *data_word),
Bit16u (* dmaRead)(Bit16u *data_word, Bit16u maxlen),
Bit16u (* dmaWrite)(Bit16u *data_word, Bit16u maxlen),
const char *name);
virtual unsigned unregisterDMAChannel(unsigned channel);
@ -97,10 +97,10 @@ private:
Bit8u ext_page_reg[16]; // Extra page registers (unused)
struct {
void (* dmaRead8)(Bit8u *data_byte);
void (* dmaWrite8)(Bit8u *data_byte);
void (* dmaRead16)(Bit16u *data_word);
void (* dmaWrite16)(Bit16u *data_word);
Bit16u (* dmaRead8)(Bit8u *data_byte, Bit16u maxlen);
Bit16u (* dmaWrite8)(Bit8u *data_byte, Bit16u maxlen);
Bit16u (* dmaRead16)(Bit16u *data_word, Bit16u maxlen);
Bit16u (* dmaWrite16)(Bit16u *data_word, Bit16u maxlen);
} h[4]; // DMA read and write handlers
};

View File

@ -444,7 +444,7 @@ Bit32u bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len)
case 0x3F5: /* diskette controller data */
if ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) &&
((BX_FD_THIS s.pending_command & 0x4f) == 0x46)) {
dma_write(&value);
dma_write(&value, 1);
lower_interrupt();
// don't enter idle phase until we've given CPU last data byte
if (BX_FD_THIS s.TC) enter_idle_phase();
@ -603,7 +603,7 @@ void bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
case 0x3F5: /* diskette controller data */
BX_DEBUG(("command = 0x%02x", (unsigned) value));
if ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) && ((BX_FD_THIS s.pending_command & 0x4f) == 0x45)) {
BX_FD_THIS dma_read((Bit8u *) &value);
BX_FD_THIS dma_read((Bit8u *) &value, 1);
BX_FD_THIS lower_interrupt();
break;
} else if (BX_FD_THIS s.command_complete) {
@ -1222,18 +1222,21 @@ void bx_floppy_ctrl_c::timer()
}
}
void bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
Bit16u bx_floppy_ctrl_c::dma_write(Bit8u *buffer, Bit16u maxlen)
{
// A DMA write is from I/O to Memory
// We need to return the next data byte from the floppy buffer
// We need to return the next data byte(s) from the floppy buffer
// to be transfered via the DMA to memory. (read block from floppy)
//
// maxlen is the maximum length of the DMA transfer
Bit8u drive;
Bit8u drive = BX_FD_THIS s.DOR & 0x03;
Bit16u len = 512 - BX_FD_THIS s.floppy_buffer_index;
if (len > maxlen) len = maxlen;
memcpy(buffer, &BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index], len);
BX_FD_THIS s.floppy_buffer_index += len;
BX_FD_THIS s.TC = get_tc() && (len == maxlen);
drive = BX_FD_THIS s.DOR & 0x03;
*data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
BX_FD_THIS s.TC = get_tc();
if ((BX_FD_THIS s.floppy_buffer_index >= 512) || (BX_FD_THIS s.TC)) {
if (BX_FD_THIS s.floppy_buffer_index >= 512) {
@ -1277,33 +1280,35 @@ void bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
sector_time , 0);
}
}
return len;
}
void bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
Bit16u bx_floppy_ctrl_c::dma_read(Bit8u *buffer, Bit16u maxlen)
{
// A DMA read is from Memory to I/O
// We need to write the data_byte which was already transfered from memory
// via DMA to I/O (write block to floppy)
//
// maxlen is the length of the DMA transfer (not implemented yet)
Bit8u drive;
Bit8u drive = BX_FD_THIS s.DOR & 0x03;
Bit32u logical_sector, sector_time;
drive = BX_FD_THIS s.DOR & 0x03;
if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
BX_FD_THIS s.format_count--;
switch (3 - (BX_FD_THIS s.format_count & 0x03)) {
case 0:
BX_FD_THIS s.cylinder[drive] = *data_byte;
BX_FD_THIS s.cylinder[drive] = *buffer;
break;
case 1:
if (*data_byte != BX_FD_THIS s.head[drive])
if (*buffer != BX_FD_THIS s.head[drive])
BX_ERROR(("head number does not match head field"));
break;
case 2:
BX_FD_THIS s.sector[drive] = *data_byte;
BX_FD_THIS s.sector[drive] = *buffer;
break;
case 3:
if (*data_byte != 2) BX_ERROR(("dma_read: sector size %d not supported", 128<<(*data_byte)));
if (*buffer != 2) BX_ERROR(("dma_read: sector size %d not supported", 128<<(*buffer)));
BX_DEBUG(("formatting cylinder %u head %u sector %u",
BX_FD_THIS s.cylinder[drive], BX_FD_THIS s.head[drive],
BX_FD_THIS s.sector[drive]));
@ -1324,10 +1329,14 @@ void bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
sector_time , 0);
break;
}
return 1;
} else { // write normal data
BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
Bit16u len = 512 - BX_FD_THIS s.floppy_buffer_index;
if (len > maxlen) len = maxlen;
memcpy(&BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index], buffer, len);
BX_FD_THIS s.floppy_buffer_index += len;
BX_FD_THIS s.TC = get_tc() && (len == maxlen);
BX_FD_THIS s.TC = get_tc();
if ((BX_FD_THIS s.floppy_buffer_index >= 512) || (BX_FD_THIS s.TC)) {
logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
(BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
@ -1342,7 +1351,7 @@ void bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
// ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
enter_result_phase();
return;
return 1;
}
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
512, TO_FLOPPY);
@ -1360,6 +1369,7 @@ void bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
enter_result_phase();
}
}
return len;
}
}

View File

@ -134,8 +134,8 @@ private:
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
BX_FD_SMF void dma_write(Bit8u *data_byte);
BX_FD_SMF void dma_read(Bit8u *data_byte);
BX_FD_SMF Bit16u dma_write(Bit8u *buffer, Bit16u maxlen);
BX_FD_SMF Bit16u dma_read(Bit8u *buffer, Bit16u maxlen);
BX_FD_SMF void floppy_command(void);
BX_FD_SMF void floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
BX_FD_SMF void raise_interrupt(void);

View File

@ -192,16 +192,16 @@ class BOCHSAPI bx_dma_stub_c : public bx_devmodel_c {
public:
virtual unsigned registerDMA8Channel(
unsigned channel,
void (* dmaRead)(Bit8u *data_byte),
void (* dmaWrite)(Bit8u *data_byte),
Bit16u (* dmaRead)(Bit8u *data_byte, Bit16u maxlen),
Bit16u (* dmaWrite)(Bit8u *data_byte, Bit16u maxlen),
const char *name)
{
STUBFUNC(dma, registerDMA8Channel); return 0;
}
virtual unsigned registerDMA16Channel(
unsigned channel,
void (* dmaRead)(Bit16u *data_word),
void (* dmaWrite)(Bit16u *data_word),
Bit16u (* dmaRead)(Bit16u *data_word, Bit16u maxlen),
Bit16u (* dmaWrite)(Bit16u *data_word, Bit16u maxlen),
const char *name)
{
STUBFUNC(dma, registerDMA16Channel); return 0;

View File

@ -1564,7 +1564,7 @@ void bx_sb16_c::dsp_dmadone()
// now the actual transfer routines, called by the DMA controller
// note that read = from application to soundcard (output),
// and write = from soundcard to application (input)
void bx_sb16_c::dma_read8(Bit8u *data_byte)
Bit16u bx_sb16_c::dma_read8(Bit8u *data_byte, Bit16u maxlen)
{
DEV_dma_set_drq(BX_SB16_DMAL, 0); // the timer will raise it again
@ -1577,9 +1577,11 @@ void bx_sb16_c::dma_read8(Bit8u *data_byte)
if (DSP.dma.count == 0xffff) // last byte received
dsp_dmadone();
return 1;
}
void bx_sb16_c::dma_write8(Bit8u *data_byte)
Bit16u bx_sb16_c::dma_write8(Bit8u *data_byte, Bit16u maxlen)
{
DEV_dma_set_drq(BX_SB16_DMAL, 0); // the timer will raise it again
@ -1593,9 +1595,11 @@ void bx_sb16_c::dma_write8(Bit8u *data_byte)
if (DSP.dma.count == 0xffff) // last byte sent
dsp_dmadone();
return 1;
}
void bx_sb16_c::dma_read16(Bit16u *data_word)
Bit16u bx_sb16_c::dma_read16(Bit16u *data_word, Bit16u maxlen)
{
DEV_dma_set_drq(BX_SB16_DMAH, 0); // the timer will raise it again
@ -1610,9 +1614,11 @@ void bx_sb16_c::dma_read16(Bit16u *data_word)
if (DSP.dma.count == 0xffff) // last word received
dsp_dmadone();
return 1;
}
void bx_sb16_c::dma_write16(Bit16u *data_word)
Bit16u bx_sb16_c::dma_write16(Bit16u *data_word, Bit16u maxlen)
{
Bit8u byte1, byte2;
@ -1632,6 +1638,8 @@ void bx_sb16_c::dma_write16(Bit16u *data_word)
if (DSP.dma.count == 0xffff) // last word sent
dsp_dmadone();
return 1;
}
// the mixer, supported type is CT1745 (as in an SB16)

View File

@ -286,10 +286,10 @@ private:
} emuldata;
/* DMA input and output, 8 and 16 bit */
BX_SB16_SMF void dma_write8(Bit8u *data_byte);
BX_SB16_SMF void dma_read8(Bit8u *data_byte);
BX_SB16_SMF void dma_write16(Bit16u *data_word);
BX_SB16_SMF void dma_read16(Bit16u *data_word);
BX_SB16_SMF Bit16u dma_write8(Bit8u *data_byte, Bit16u maxlen);
BX_SB16_SMF Bit16u dma_read8(Bit8u *data_byte, Bit16u maxlen);
BX_SB16_SMF Bit16u dma_write16(Bit16u *data_word, Bit16u maxlen);
BX_SB16_SMF Bit16u dma_read16(Bit16u *data_word, Bit16u maxlen);
/* the MPU 401 part of the emulator */
BX_SB16_SMF Bit32u mpu_status(); // read status port 3x1

View File

@ -1,572 +0,0 @@
----------------------------------------------------------------------
Patch name: patch.fast-dma-cbothamy
Author: Christophe Bothamy
Date: Wed Feb 18 14:00:40 CET 2004
Status: Proposed changes
Detailed description:
This patch improves DMA transfers by moving more than one byte
on each cpu tick. This works only on address-incrementing DMA
transfers. The number of transferred bytes is currently
limited to 512 on each cpu tick, but can be easily increased.
Only floppy DMA transfers are impacted right now, and DOS 6.2
and Win95 seems to work fine with the patch applied.
The performance increase is (measured on a 1GHz PIII, with
all optimizations enabled) :
command without patch with patch
format a: 4s 3s
surface scan of scandisk 17s 10s
xcopy a: b: 14s 4s
These tests prefigures what kind of performance increase we
can get by implementing the IDE BusMaster feature.
More test on more guest os are needed to find probable
incompatibilities.
Todo:
- implement similar changes for sb16
- fix BX_DBG_DMA_REPORT to report data from buffer
Patch was created with:
cvs diff -u
Apply patch to what version:
cvs checked out on DATE, release version VER
Instructions:
To patch, go to main bochs directory.
Type "patch -p0 < THIS_PATCH_FILE".
----------------------------------------------------------------------
Index: bochs.h
===================================================================
RCS file: /cvsroot/bochs/bochs/bochs.h,v
retrieving revision 1.136
diff -u -r1.136 bochs.h
--- bochs.h 6 Feb 2004 22:27:59 -0000 1.136
+++ bochs.h 18 Feb 2004 13:41:55 -0000
@@ -491,6 +491,8 @@
#define BX_RW 2
+#define BX_MEM_GET_HOST_MEM_ADDR_READ(addr) BX_MEM(0)->getHostMemAddr(NULL, addr, BX_READ)
+#define BX_MEM_GET_HOST_MEM_ADDR_WRITE(addr) BX_MEM(0)->getHostMemAddr(NULL, addr, BX_WRITE)
Index: iodev/dma.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/dma.cc,v
retrieving revision 1.30
diff -u -r1.30 dma.cc
--- iodev/dma.cc 31 Jul 2003 15:29:34 -0000 1.30
+++ iodev/dma.cc 18 Feb 2004 13:41:59 -0000
@@ -70,8 +70,8 @@
unsigned
bx_dma_c::registerDMA8Channel(
unsigned channel,
- void (* dmaRead)(Bit8u *data_byte),
- void (* dmaWrite)(Bit8u *data_byte),
+ void (* dmaRead)(Bit8u *data_byte, Bit16u len),
+ void (* dmaWrite)(Bit8u *data_byte, Bit16u len),
const char *name
)
{
@@ -93,8 +93,8 @@
unsigned
bx_dma_c::registerDMA16Channel(
unsigned channel,
- void (* dmaRead)(Bit16u *data_word),
- void (* dmaWrite)(Bit16u *data_word),
+ void (* dmaRead)(Bit16u *data_word, Bit16u len),
+ void (* dmaWrite)(Bit16u *data_word, Bit16u len),
const char *name
)
{
@@ -709,12 +709,26 @@
(BX_DMA_THIS s[ma_sl].chan[channel].current_address << ma_sl);
BX_DMA_THIS s[ma_sl].DACK[channel] = 1;
- // check for expiration of count, so we can signal TC and DACK(n)
- // at the same time.
- if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0)
+
+ Bit16u length;
+ if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0) {
+ // Maxout length, it could be per device selectable
+ length=BX_DMA_THIS s[ma_sl].chan[channel].current_count;
+ if (length > 511) length=511;
+
+ BX_DMA_THIS s[ma_sl].chan[channel].current_address+=length;
BX_DMA_THIS s[ma_sl].chan[channel].current_address++;
- else
+ }
+ else {
+ // When decrementing it is easier to do it 1 byte at a time
+ length=0;
+ //BX_DMA_THIS s[ma_sl].chan[channel].current_address-=length;
BX_DMA_THIS s[ma_sl].chan[channel].current_address--;
+ }
+
+ // check for expiration of count, so we can signal TC and DACK(n)
+ // at the same time.
+ BX_DMA_THIS s[ma_sl].chan[channel].current_count-=length;
BX_DMA_THIS s[ma_sl].chan[channel].current_count--;
if (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0xffff) {
// count expired, done with transfer
@@ -736,65 +750,86 @@
}
}
- Bit8u data_byte;
- Bit16u data_word;
+ Bit8u *data8;
+ Bit16u *data16;
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 1) { // write
// DMA controlled xfer of byte from I/O to Memory
if (!ma_sl) {
- if (BX_DMA_THIS h[channel].dmaWrite8)
- BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
- else
- BX_PANIC(("no dmaWrite handler for channel %u.", channel));
- BX_MEM_WRITE_PHYSICAL(phy_addr, 1, &data_byte);
+ data8 = BX_MEM_GET_HOST_MEM_ADDR_WRITE(phy_addr);
+ if (data8 == NULL)
+ BX_PANIC(("dma8 tries to write outside memory"));
+ else
+ if (BX_DMA_THIS h[channel].dmaWrite8)
+ BX_DMA_THIS h[channel].dmaWrite8(data8, length);
+ else
+ BX_PANIC(("no dmaWrite handler for channel %u.", channel));
- BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, data_byte);
+ //BX_MEM_WRITE_PHYSICAL(phy_addr, 1+(Bit32u)length, &data_byte);
+
+ //BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, &data_byte);
}
else {
- if (BX_DMA_THIS h[channel].dmaWrite16)
- BX_DMA_THIS h[channel].dmaWrite16(&data_word);
+
+ data16 = (Bit16u*)BX_MEM_GET_HOST_MEM_ADDR_WRITE(phy_addr);
+ if (data16 == NULL)
+ BX_PANIC(("dma16 tries to write outside memory"));
else
- BX_PANIC(("no dmaWrite handler for channel %u.", channel));
+ if (BX_DMA_THIS h[channel].dmaWrite16)
+ BX_DMA_THIS h[channel].dmaWrite16(data16, length);
+ else
+ BX_PANIC(("no dmaWrite handler for channel %u.", channel));
- BX_MEM_WRITE_PHYSICAL(phy_addr, 2, &data_word);
+ //BX_MEM_WRITE_PHYSICAL(phy_addr, 2*(1+(Bit32u)length), data_word);
- BX_DBG_DMA_REPORT(phy_addr, 2, BX_WRITE, data_word);
+ //BX_DBG_DMA_REPORT(phy_addr, 2, BX_WRITE, data_word);
}
}
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 2) { // read
// DMA controlled xfer of byte from Memory to I/O
if (!ma_sl) {
- BX_MEM_READ_PHYSICAL(phy_addr, 1, &data_byte);
+ //BX_MEM_READ_PHYSICAL(phy_addr, 1+(Bit32u)length, &data_byte);
- if (BX_DMA_THIS h[channel].dmaRead8)
- BX_DMA_THIS h[channel].dmaRead8(&data_byte);
+ data8 = BX_MEM_GET_HOST_MEM_ADDR_READ(phy_addr);
+ if (data8 == NULL)
+ BX_PANIC(("dma8 tries to read outside memory"));
+ else
+ if (BX_DMA_THIS h[channel].dmaRead8)
+ BX_DMA_THIS h[channel].dmaRead8(data8, length);
- BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, data_byte);
+ //BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, &data_byte);
}
else {
- BX_MEM_READ_PHYSICAL(phy_addr, 2, &data_word);
+ // BX_MEM_READ_PHYSICAL(phy_addr, 2*(1+(Bit32u)length), data_word);
- if (BX_DMA_THIS h[channel].dmaRead16)
- BX_DMA_THIS h[channel].dmaRead16(&data_word);
+ data16 = (Bit16u*)BX_MEM_GET_HOST_MEM_ADDR_WRITE(phy_addr);
+ if (data16 == NULL)
+ BX_PANIC(("dma16 tries to read outside memory"));
+ else
+ if (BX_DMA_THIS h[channel].dmaRead16)
+ BX_DMA_THIS h[channel].dmaRead16(data16,length);
- BX_DBG_DMA_REPORT(phy_addr, 2, BX_READ, data_word);
+ //BX_DBG_DMA_REPORT(phy_addr, 2, BX_READ, data_word);
}
}
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 0) {
// verify
+ // Buffer for verify, max 64k words
+ Bit16u buffer[64*1024];
+
if (!ma_sl) {
if (BX_DMA_THIS h[channel].dmaWrite8)
- BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
+ BX_DMA_THIS h[channel].dmaWrite8((Bit8u*)buffer, length);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
}
else {
if (BX_DMA_THIS h[channel].dmaWrite16)
- BX_DMA_THIS h[channel].dmaWrite16(&data_word);
+ BX_DMA_THIS h[channel].dmaWrite16(buffer, length);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
}
Index: iodev/dma.h
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/dma.h,v
retrieving revision 1.15
diff -u -r1.15 dma.h
--- iodev/dma.h 3 May 2003 07:41:27 -0000 1.15
+++ iodev/dma.h 18 Feb 2004 13:41:59 -0000
@@ -52,12 +52,12 @@
virtual unsigned get_TC(void);
virtual unsigned registerDMA8Channel(unsigned channel,
- void (* dmaRead)(Bit8u *data_byte),
- void (* dmaWrite)(Bit8u *data_byte),
+ void (* dmaRead)(Bit8u *data_byte, Bit16u len),
+ void (* dmaWrite)(Bit8u *data_byte, Bit16u len),
const char *name);
virtual unsigned registerDMA16Channel(unsigned channel,
- void (* dmaRead)(Bit16u *data_word),
- void (* dmaWrite)(Bit16u *data_word),
+ void (* dmaRead)(Bit16u *data_word, Bit16u len),
+ void (* dmaWrite)(Bit16u *data_word, Bit16u len),
const char *name);
virtual unsigned unregisterDMAChannel(unsigned channel);
@@ -102,10 +102,10 @@
bx_bool TC; // Terminal Count
struct {
- void (* dmaRead8)(Bit8u *data_byte);
- void (* dmaWrite8)(Bit8u *data_byte);
- void (* dmaRead16)(Bit16u *data_word);
- void (* dmaWrite16)(Bit16u *data_word);
+ void (* dmaRead8)(Bit8u *data_byte, Bit16u len);
+ void (* dmaWrite8)(Bit8u *data_byte, Bit16u len);
+ void (* dmaRead16)(Bit16u *data_word, Bit16u len);
+ void (* dmaWrite16)(Bit16u *data_word, Bit16u len);
} h[4]; // DMA read and write handlers
};
Index: iodev/floppy.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/floppy.cc,v
retrieving revision 1.72
diff -u -r1.72 floppy.cc
--- iodev/floppy.cc 8 Feb 2004 18:38:26 -0000 1.72
+++ iodev/floppy.cc 18 Feb 2004 13:42:04 -0000
@@ -1110,66 +1110,91 @@
}
void
-bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
+bx_floppy_ctrl_c::dma_write(Bit8u *data_byte, Bit16u len)
{
// A DMA write is from I/O to Memory
// We need to return then next data byte from the floppy buffer
// to be transfered via the DMA to memory. (read block from floppy)
+ //
+ // len is the length of the DMA transfert minus 1 byte
+ Bit32u xfer_len;
+ Bit8u drive = BX_FD_THIS s.DOR & 0x03;
- *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
+ if ( BX_FD_THIS s.floppy_buffer_index >= 512)
+ BX_PANIC(("Index should not be >= 512"));
- if (BX_FD_THIS s.floppy_buffer_index >= 512) {
- Bit8u drive;
+ do {
+ xfer_len = 512 - BX_FD_THIS s.floppy_buffer_index;
+ if (xfer_len > ((Bit32u)len + 1)) xfer_len = (Bit32u)len + 1;
+ if (xfer_len == 1)
+ *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
+ else {
+ memcpy(data_byte, &BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index],xfer_len);
+ BX_FD_THIS s.floppy_buffer_index += xfer_len;
+ }
- drive = BX_FD_THIS s.DOR & 0x03;
- increment_sector(); // increment to next sector before retrieving next one
- BX_FD_THIS s.floppy_buffer_index = 0;
- if (DEV_dma_get_tc()) { // Terminal Count line, done
- BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
- BX_FD_THIS s.status_reg1 = 0;
- BX_FD_THIS s.status_reg2 = 0;
+ data_byte += xfer_len;
+ len -= (Bit16u)xfer_len;
- if (bx_dbg.floppy) {
- BX_INFO(("<<READ DONE>>"));
- BX_INFO(("AFTER"));
- BX_INFO((" drive = %u", (unsigned) drive));
- BX_INFO((" head = %u", (unsigned) BX_FD_THIS s.head[drive]));
- BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
- BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
- }
+ if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+ increment_sector(); // increment to next sector before retrieving next one
+ BX_FD_THIS s.floppy_buffer_index = 0;
+
+ // Only needed if more data to transfer
+ if (!DEV_dma_get_tc()) {
+ Bit32u logical_sector;
+
+ // original assumed all floppies had two sides...now it does not *delete this comment line*
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
- DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
- enter_result_phase();
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, FROM_FLOPPY);
+ }
}
- else { // more data to transfer
- Bit32u logical_sector;
-
- // original assumed all floppies had two sides...now it does not *delete this comment line*
- logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads *
- BX_FD_THIS s.media[drive].sectors_per_track) +
- (BX_FD_THIS s.head[drive] *
- BX_FD_THIS s.media[drive].sectors_per_track) +
- (BX_FD_THIS s.sector[drive] - 1);
+ } while (len!=0xffff);
+
+ // If DMA transfer is over
+ if (DEV_dma_get_tc()) { // Terminal Count line, done
+ BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+ BX_FD_THIS s.status_reg1 = 0;
+ BX_FD_THIS s.status_reg2 = 0;
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("<<READ DONE>>"));
+ BX_INFO(("AFTER"));
+ BX_INFO((" drive = %u", (unsigned) drive));
+ BX_INFO((" head = %u", (unsigned) BX_FD_THIS s.head[drive]));
+ BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
+ BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
+ }
- floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
- 512, FROM_FLOPPY);
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
}
- }
+ return;
}
void
-bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
+bx_floppy_ctrl_c::dma_read(Bit8u *data_byte, Bit16u len)
{
// A DMA read is from Memory to I/O
// We need to write the data_byte which was already transfered from memory
// via DMA to I/O (write block to floppy)
+ //
+ // len is the length of the DMA transfert minus 1 byte
Bit8u drive;
Bit32u logical_sector;
drive = BX_FD_THIS s.DOR & 0x03;
+
if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
+ do {
--BX_FD_THIS s.format_count;
switch (3 - (BX_FD_THIS s.format_count & 0x03)) {
case 0:
@@ -1187,50 +1212,76 @@
BX_DEBUG(("formatting cylinder %u head %u sector %u",
BX_FD_THIS s.cylinder[drive], BX_FD_THIS s.head[drive],
BX_FD_THIS s.sector[drive]));
- for (unsigned i = 0; i < 512; i++) {
- BX_FD_THIS s.floppy_buffer[i] = BX_FD_THIS s.format_fillbyte;
- }
+ memset(BX_FD_THIS s.floppy_buffer, BX_FD_THIS s.format_fillbyte, 512);
// original assumed all floppies had two sides...now it does not *delete this comment line*
- logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
(BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
(BX_FD_THIS s.sector[drive] - 1);
floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
512, TO_FLOPPY);
break;
}
+
+ len --;
+ data_byte++;
+ } while (len != 0xffff);
+
if ((BX_FD_THIS s.format_count == 0) || (DEV_dma_get_tc())) {
BX_FD_THIS s.format_count = 0;
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
enter_result_phase();
}
+
return;
}
+ else { // format track not in progress
+ if ( BX_FD_THIS s.media[drive].write_protected ) {
+ // write protected error
+ BX_INFO(("tried to write disk %u, which is write-protected", drive));
+ // ST0: IC1,0=01 (abnormal termination: started execution but failed)
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+ // ST1: DataError=1, NDAT=1, NotWritable=1, NID=1
+ BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
+ // ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
+ return;
+ }
- BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
+ Bit32u xfer_len;
- if (BX_FD_THIS s.floppy_buffer_index >= 512) {
- // original assumed all floppies had two sides...now it does not *delete this comment line*
- logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
- (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
- (BX_FD_THIS s.sector[drive] - 1);
- if ( BX_FD_THIS s.media[drive].write_protected ) {
- // write protected error
- BX_INFO(("tried to write disk %u, which is write-protected", drive));
- // ST0: IC1,0=01 (abnormal termination: started execution but failed)
- BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
- // ST1: DataError=1, NDAT=1, NotWritable=1, NID=1
- BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
- // ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
- BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
- enter_result_phase();
- return;
+ if ( BX_FD_THIS s.floppy_buffer_index >= 512)
+ BX_PANIC(("Index should not be >= 512"));
+
+ do {
+
+ xfer_len = 512 - BX_FD_THIS s.floppy_buffer_index;
+ if (xfer_len > ((Bit32u)len + 1)) xfer_len = (Bit32u)len + 1;
+ if (xfer_len == 1)
+ BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
+ else {
+ memcpy(&BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index],data_byte,xfer_len);
+ BX_FD_THIS s.floppy_buffer_index += xfer_len;
}
- floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+
+ data_byte += xfer_len;
+ len -= (Bit16u)xfer_len;
+
+ if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+ // original assumed all floppies had two sides...now it does not *delete this comment line*
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
512, TO_FLOPPY);
- increment_sector(); // increment to next sector after writing current one
- BX_FD_THIS s.floppy_buffer_index = 0;
- if (DEV_dma_get_tc()) { // Terminal Count line, done
+ increment_sector(); // increment to next sector after writing current one
+ BX_FD_THIS s.floppy_buffer_index = 0;
+ } // if BX_FD_THIS s.floppy_buffer_index >= 512
+ } while (len != 0xffff);
+
+ if (DEV_dma_get_tc()) { // Terminal Count line, done
BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
BX_FD_THIS s.status_reg1 = 0;
BX_FD_THIS s.status_reg2 = 0;
@@ -1243,13 +1294,11 @@
BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
}
-
+
DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
enter_result_phase();
- }
- else { // more data to transfer
- } // else
- } // if BX_FD_THIS s.floppy_buffer_index >= 512
+ }
+ }
}
void
@@ -1286,8 +1335,8 @@
if (BX_FD_THIS s.cylinder[drive] >= BX_FD_THIS s.media[drive].tracks) {
// Set to 1 past last possible cylinder value.
// I notice if I set it to tracks-1, prama linux won't boot.
+ BX_INFO(("increment_sector: clamping cylinder %x to max",BX_FD_THIS s.cylinder[drive]));
BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.media[drive].tracks;
- BX_INFO(("increment_sector: clamping cylinder to max"));
}
}
}
Index: iodev/floppy.h
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/floppy.h,v
retrieving revision 1.17
diff -u -r1.17 floppy.h
--- iodev/floppy.h 7 Feb 2004 14:34:34 -0000 1.17
+++ iodev/floppy.h 18 Feb 2004 13:42:04 -0000
@@ -123,8 +123,8 @@
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
- BX_FD_SMF void dma_write(Bit8u *data_byte);
- BX_FD_SMF void dma_read(Bit8u *data_byte);
+ BX_FD_SMF void dma_write(Bit8u *data_byte, Bit16u len);
+ BX_FD_SMF void dma_read(Bit8u *data_byte, Bit16u len);
BX_FD_SMF void floppy_command(void);
BX_FD_SMF void floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
BX_FD_SMF void raise_interrupt(void);
Index: iodev/iodev.h
===================================================================
RCS file: /cvsroot/bochs/bochs/iodev/iodev.h,v
retrieving revision 1.41
diff -u -r1.41 iodev.h
--- iodev/iodev.h 2 Feb 2004 21:47:26 -0000 1.41
+++ iodev/iodev.h 18 Feb 2004 13:42:05 -0000
@@ -176,16 +176,16 @@
public:
virtual unsigned registerDMA8Channel(
unsigned channel,
- void (* dmaRead)(Bit8u *data_byte),
- void (* dmaWrite)(Bit8u *data_byte),
+ void (* dmaRead)(Bit8u *data_byte, Bit16u len),
+ void (* dmaWrite)(Bit8u *data_byte, Bit16u len),
const char *name
) {
STUBFUNC(dma, registerDMA8Channel); return 0;
}
virtual unsigned registerDMA16Channel(
unsigned channel,
- void (* dmaRead)(Bit16u *data_word),
- void (* dmaWrite)(Bit16u *data_word),
+ void (* dmaRead)(Bit16u *data_word, Bit16u len),
+ void (* dmaWrite)(Bit16u *data_word, Bit16u len),
const char *name
) {
STUBFUNC(dma, registerDMA16Channel); return 0;