Fixes to DMA writing (still unverified) and added serialize/unserialize
dev/ide_ctrl.cc: Added serialize/unserialize functions and move some inlined functions to regular functions dev/ide_ctrl.hh: Change inlined functions to regular functions dev/ide_disk.cc: Changes to dmaWrite and also add serialize/unserialize functions dev/ide_disk.hh: Support for serializing/unserializing --HG-- extra : convert_revision : 40e016dc7f6637b033fe33409338437c985a05f4
This commit is contained in:
parent
c5ec5bf3a7
commit
ab9415a2bd
4 changed files with 332 additions and 80 deletions
108
dev/ide_ctrl.cc
108
dev/ide_ctrl.cc
|
@ -126,6 +126,72 @@ IdeController::~IdeController()
|
||||||
delete disks[i];
|
delete disks[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// Utility functions
|
||||||
|
///
|
||||||
|
|
||||||
|
void
|
||||||
|
IdeController::parseAddr(const Addr &addr, Addr &offset, bool &primary,
|
||||||
|
RegType_t &type)
|
||||||
|
{
|
||||||
|
offset = addr;
|
||||||
|
|
||||||
|
if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
|
||||||
|
offset -= pri_cmd_addr;
|
||||||
|
type = COMMAND_BLOCK;
|
||||||
|
primary = true;
|
||||||
|
} else if (addr >= pri_ctrl_addr &&
|
||||||
|
addr < (pri_ctrl_addr + pri_ctrl_size)) {
|
||||||
|
offset -= pri_ctrl_addr;
|
||||||
|
type = CONTROL_BLOCK;
|
||||||
|
primary = true;
|
||||||
|
} else if (addr >= sec_cmd_addr &&
|
||||||
|
addr < (sec_cmd_addr + sec_cmd_size)) {
|
||||||
|
offset -= sec_cmd_addr;
|
||||||
|
type = COMMAND_BLOCK;
|
||||||
|
primary = false;
|
||||||
|
} else if (addr >= sec_ctrl_addr &&
|
||||||
|
addr < (sec_ctrl_addr + sec_ctrl_size)) {
|
||||||
|
offset -= sec_ctrl_addr;
|
||||||
|
type = CONTROL_BLOCK;
|
||||||
|
primary = false;
|
||||||
|
} else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
|
||||||
|
offset -= bmi_addr;
|
||||||
|
type = BMI_BLOCK;
|
||||||
|
primary = (offset < BMIC1) ? true : false;
|
||||||
|
} else {
|
||||||
|
panic("IDE controller access to invalid address: %#x\n", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IdeController::getDisk(bool primary)
|
||||||
|
{
|
||||||
|
int disk = 0;
|
||||||
|
uint8_t *devBit = &dev[0];
|
||||||
|
|
||||||
|
if (!primary) {
|
||||||
|
disk += 2;
|
||||||
|
devBit = &dev[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
disk += *devBit;
|
||||||
|
|
||||||
|
assert(*devBit == 0 || *devBit == 1);
|
||||||
|
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IdeController::getDisk(IdeDisk *diskPtr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if ((long)diskPtr == (long)disks[i])
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
// Command completion
|
// Command completion
|
||||||
////
|
////
|
||||||
|
@ -523,11 +589,53 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||||
void
|
void
|
||||||
IdeController::serialize(std::ostream &os)
|
IdeController::serialize(std::ostream &os)
|
||||||
{
|
{
|
||||||
|
// Serialize register addresses and sizes
|
||||||
|
SERIALIZE_SCALAR(pri_cmd_addr);
|
||||||
|
SERIALIZE_SCALAR(pri_cmd_size);
|
||||||
|
SERIALIZE_SCALAR(pri_ctrl_addr);
|
||||||
|
SERIALIZE_SCALAR(pri_ctrl_size);
|
||||||
|
SERIALIZE_SCALAR(sec_cmd_addr);
|
||||||
|
SERIALIZE_SCALAR(sec_cmd_size);
|
||||||
|
SERIALIZE_SCALAR(sec_ctrl_addr);
|
||||||
|
SERIALIZE_SCALAR(sec_ctrl_size);
|
||||||
|
SERIALIZE_SCALAR(bmi_addr);
|
||||||
|
SERIALIZE_SCALAR(bmi_size);
|
||||||
|
|
||||||
|
// Serialize registers
|
||||||
|
SERIALIZE_ARRAY(bmi_regs, 16);
|
||||||
|
SERIALIZE_ARRAY(dev, 2);
|
||||||
|
SERIALIZE_ARRAY(pci_regs, 8);
|
||||||
|
|
||||||
|
// Serialize internal state
|
||||||
|
SERIALIZE_SCALAR(io_enabled);
|
||||||
|
SERIALIZE_SCALAR(bm_enabled);
|
||||||
|
SERIALIZE_ARRAY(cmd_in_progress, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeController::unserialize(Checkpoint *cp, const std::string §ion)
|
IdeController::unserialize(Checkpoint *cp, const std::string §ion)
|
||||||
{
|
{
|
||||||
|
// Unserialize register addresses and sizes
|
||||||
|
UNSERIALIZE_SCALAR(pri_cmd_addr);
|
||||||
|
UNSERIALIZE_SCALAR(pri_cmd_size);
|
||||||
|
UNSERIALIZE_SCALAR(pri_ctrl_addr);
|
||||||
|
UNSERIALIZE_SCALAR(pri_ctrl_size);
|
||||||
|
UNSERIALIZE_SCALAR(sec_cmd_addr);
|
||||||
|
UNSERIALIZE_SCALAR(sec_cmd_size);
|
||||||
|
UNSERIALIZE_SCALAR(sec_ctrl_addr);
|
||||||
|
UNSERIALIZE_SCALAR(sec_ctrl_size);
|
||||||
|
UNSERIALIZE_SCALAR(bmi_addr);
|
||||||
|
UNSERIALIZE_SCALAR(bmi_size);
|
||||||
|
|
||||||
|
// Unserialize registers
|
||||||
|
UNSERIALIZE_ARRAY(bmi_regs, 16);
|
||||||
|
UNSERIALIZE_ARRAY(dev, 2);
|
||||||
|
UNSERIALIZE_ARRAY(pci_regs, 8);
|
||||||
|
|
||||||
|
// Unserialize internal state
|
||||||
|
UNSERIALIZE_SCALAR(io_enabled);
|
||||||
|
UNSERIALIZE_SCALAR(bm_enabled);
|
||||||
|
UNSERIALIZE_ARRAY(cmd_in_progress, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* Simple PCI IDE controller with bus mastering capability
|
* Simple PCI IDE controller with bus mastering capability and UDMA
|
||||||
|
* modeled after controller in the Intel PIIX4 chip
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __IDE_CTRL_HH__
|
#ifndef __IDE_CTRL_HH__
|
||||||
|
@ -139,65 +140,13 @@ class IdeController : public PciDev
|
||||||
private:
|
private:
|
||||||
/** Parse the access address to pass on to device */
|
/** Parse the access address to pass on to device */
|
||||||
void parseAddr(const Addr &addr, Addr &offset, bool &primary,
|
void parseAddr(const Addr &addr, Addr &offset, bool &primary,
|
||||||
RegType_t &type)
|
RegType_t &type);
|
||||||
{
|
|
||||||
offset = addr;
|
|
||||||
|
|
||||||
if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
|
|
||||||
offset -= pri_cmd_addr;
|
|
||||||
type = COMMAND_BLOCK;
|
|
||||||
primary = true;
|
|
||||||
} else if (addr >= pri_ctrl_addr &&
|
|
||||||
addr < (pri_ctrl_addr + pri_ctrl_size)) {
|
|
||||||
offset -= pri_ctrl_addr;
|
|
||||||
type = CONTROL_BLOCK;
|
|
||||||
primary = true;
|
|
||||||
} else if (addr >= sec_cmd_addr &&
|
|
||||||
addr < (sec_cmd_addr + sec_cmd_size)) {
|
|
||||||
offset -= sec_cmd_addr;
|
|
||||||
type = COMMAND_BLOCK;
|
|
||||||
primary = false;
|
|
||||||
} else if (addr >= sec_ctrl_addr &&
|
|
||||||
addr < (sec_ctrl_addr + sec_ctrl_size)) {
|
|
||||||
offset -= sec_ctrl_addr;
|
|
||||||
type = CONTROL_BLOCK;
|
|
||||||
primary = false;
|
|
||||||
} else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
|
|
||||||
offset -= bmi_addr;
|
|
||||||
type = BMI_BLOCK;
|
|
||||||
primary = (offset < BMIC1) ? true : false;
|
|
||||||
} else {
|
|
||||||
panic("IDE controller access to invalid address: %#x\n", addr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Select the disk based on the channel and device bit */
|
/** Select the disk based on the channel and device bit */
|
||||||
int getDisk(bool primary)
|
int getDisk(bool primary);
|
||||||
{
|
|
||||||
int disk = 0;
|
|
||||||
uint8_t *devBit = &dev[0];
|
|
||||||
|
|
||||||
if (!primary) {
|
|
||||||
disk += 2;
|
|
||||||
devBit = &dev[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
disk += *devBit;
|
|
||||||
|
|
||||||
assert(*devBit == 0 || *devBit == 1);
|
|
||||||
|
|
||||||
return disk;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Select the disk based on a pointer */
|
/** Select the disk based on a pointer */
|
||||||
int getDisk(IdeDisk *diskPtr)
|
int getDisk(IdeDisk *diskPtr);
|
||||||
{
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
if ((long)diskPtr == (long)disks[i])
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
223
dev/ide_disk.cc
223
dev/ide_disk.cc
|
@ -61,6 +61,7 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
|
||||||
dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
|
dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
|
||||||
dmaReadEvent(this), dmaWriteEvent(this)
|
dmaReadEvent(this), dmaWriteEvent(this)
|
||||||
{
|
{
|
||||||
|
// calculate disk delay in microseconds
|
||||||
diskDelay = (delay * ticksPerSecond / 100000);
|
diskDelay = (delay * ticksPerSecond / 100000);
|
||||||
|
|
||||||
// initialize the data buffer and shadow registers
|
// initialize the data buffer and shadow registers
|
||||||
|
@ -70,6 +71,7 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
|
||||||
memset(&cmdReg, 0, sizeof(CommandReg_t));
|
memset(&cmdReg, 0, sizeof(CommandReg_t));
|
||||||
memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
|
memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
|
||||||
|
|
||||||
|
dmaInterfaceBytes = 0;
|
||||||
curPrdAddr = 0;
|
curPrdAddr = 0;
|
||||||
curSector = 0;
|
curSector = 0;
|
||||||
curCommand = 0;
|
curCommand = 0;
|
||||||
|
@ -154,8 +156,12 @@ IdeDisk::~IdeDisk()
|
||||||
delete [] dataBuffer;
|
delete [] dataBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// Utility functions
|
||||||
|
////
|
||||||
|
|
||||||
Addr
|
Addr
|
||||||
IdeDisk::pciToDma(Addr &pciAddr)
|
IdeDisk::pciToDma(Addr pciAddr)
|
||||||
{
|
{
|
||||||
if (ctrl)
|
if (ctrl)
|
||||||
return ctrl->tsunami->pchip->translatePciToDma(pciAddr);
|
return ctrl->tsunami->pchip->translatePciToDma(pciAddr);
|
||||||
|
@ -163,6 +169,29 @@ IdeDisk::pciToDma(Addr &pciAddr)
|
||||||
panic("Access to unset controller!\n");
|
panic("Access to unset controller!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
|
||||||
|
{
|
||||||
|
uint32_t bytesInPage = 0;
|
||||||
|
|
||||||
|
// First calculate how many bytes could be in the page
|
||||||
|
if (bytesLeft > ALPHA_PGBYTES)
|
||||||
|
bytesInPage = ALPHA_PGBYTES;
|
||||||
|
else
|
||||||
|
bytesInPage = bytesLeft;
|
||||||
|
|
||||||
|
// Next, see if we have crossed a page boundary, and adjust
|
||||||
|
Addr upperBound = curAddr + bytesInPage;
|
||||||
|
Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES;
|
||||||
|
|
||||||
|
assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
|
||||||
|
|
||||||
|
if (upperBound >= pageBound)
|
||||||
|
bytesInPage = pageBound - curAddr;
|
||||||
|
|
||||||
|
return bytesInPage;
|
||||||
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
// Device registers read/write
|
// Device registers read/write
|
||||||
////
|
////
|
||||||
|
@ -297,7 +326,7 @@ IdeDisk::dmaPrdReadDone()
|
||||||
void
|
void
|
||||||
IdeDisk::doDmaRead()
|
IdeDisk::doDmaRead()
|
||||||
{
|
{
|
||||||
Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
|
Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
|
||||||
|
|
||||||
if (dmaInterface) {
|
if (dmaInterface) {
|
||||||
if (dmaInterface->busy()) {
|
if (dmaInterface->busy()) {
|
||||||
|
@ -306,9 +335,14 @@ IdeDisk::doDmaRead()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Addr dmaAddr =
|
Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
|
||||||
ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
|
|
||||||
dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(),
|
uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
|
||||||
|
(uint32_t)curPrd.getByteCount());
|
||||||
|
|
||||||
|
dmaInterfaceBytes = bytesInPage;
|
||||||
|
|
||||||
|
dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
|
||||||
curTick + totalDiskDelay, &dmaReadEvent);
|
curTick + totalDiskDelay, &dmaReadEvent);
|
||||||
} else {
|
} else {
|
||||||
// schedule dmaReadEvent with sectorDelay (dmaReadDone)
|
// schedule dmaReadEvent with sectorDelay (dmaReadDone)
|
||||||
|
@ -323,6 +357,28 @@ IdeDisk::dmaReadDone()
|
||||||
Addr curAddr = 0, dmaAddr = 0;
|
Addr curAddr = 0, dmaAddr = 0;
|
||||||
uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
|
uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
|
||||||
|
|
||||||
|
// continue to use the DMA interface until all pages are read
|
||||||
|
if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
|
||||||
|
// see if the interface is busy
|
||||||
|
if (dmaInterface->busy()) {
|
||||||
|
// reschedule after waiting period
|
||||||
|
dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
|
||||||
|
curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
|
||||||
|
dmaAddr = pciToDma(curAddr);
|
||||||
|
|
||||||
|
bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
|
||||||
|
dmaInterfaceBytes += bytesInPage;
|
||||||
|
|
||||||
|
dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
|
||||||
|
curTick, &dmaReadEvent);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// set initial address
|
// set initial address
|
||||||
curAddr = curPrd.getBaseAddr();
|
curAddr = curPrd.getBaseAddr();
|
||||||
|
|
||||||
|
@ -338,15 +394,9 @@ IdeDisk::dmaReadDone()
|
||||||
|
|
||||||
// calculate how many bytes are in the current page
|
// calculate how many bytes are in the current page
|
||||||
bytesLeft = curPrd.getByteCount() - bytesWritten;
|
bytesLeft = curPrd.getByteCount() - bytesWritten;
|
||||||
bytesInPage = (bytesLeft > ALPHA_PGBYTES) ? ALPHA_PGBYTES : bytesLeft;
|
bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
|
||||||
// check to make sure we don't cross a page boundary
|
|
||||||
if ((curAddr + bytesInPage) >
|
|
||||||
(alpha_trunc_page(curAddr) + ALPHA_PGBYTES))
|
|
||||||
|
|
||||||
bytesInPage = alpha_round_page(curAddr) - curAddr;
|
|
||||||
|
|
||||||
// copy the data from memory into the data buffer
|
// copy the data from memory into the data buffer
|
||||||
/** @todo Use real DMA with interfaces here */
|
|
||||||
memcpy((void *)(dataBuffer + bytesWritten),
|
memcpy((void *)(dataBuffer + bytesWritten),
|
||||||
physmem->dma_addr(dmaAddr, bytesInPage),
|
physmem->dma_addr(dmaAddr, bytesInPage),
|
||||||
bytesInPage);
|
bytesInPage);
|
||||||
|
@ -359,9 +409,10 @@ IdeDisk::dmaReadDone()
|
||||||
// write the data to the disk image
|
// write the data to the disk image
|
||||||
for (bytesWritten = 0;
|
for (bytesWritten = 0;
|
||||||
bytesWritten < curPrd.getByteCount();
|
bytesWritten < curPrd.getByteCount();
|
||||||
bytesWritten += SectorSize)
|
bytesWritten += SectorSize) {
|
||||||
|
|
||||||
writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
|
writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// actually copy the data from memory to data buffer
|
// actually copy the data from memory to data buffer
|
||||||
|
@ -397,7 +448,7 @@ IdeDisk::dmaReadDone()
|
||||||
void
|
void
|
||||||
IdeDisk::doDmaWrite()
|
IdeDisk::doDmaWrite()
|
||||||
{
|
{
|
||||||
Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
|
Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
|
||||||
|
|
||||||
if (dmaInterface) {
|
if (dmaInterface) {
|
||||||
if (dmaInterface->busy()) {
|
if (dmaInterface->busy()) {
|
||||||
|
@ -406,10 +457,15 @@ IdeDisk::doDmaWrite()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Addr dmaAddr =
|
Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
|
||||||
ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
|
|
||||||
|
uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
|
||||||
|
(uint32_t)curPrd.getByteCount());
|
||||||
|
|
||||||
|
dmaInterfaceBytes = bytesInPage;
|
||||||
|
|
||||||
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
|
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
|
||||||
curPrd.getByteCount(), curTick + totalDiskDelay,
|
bytesInPage, curTick + totalDiskDelay,
|
||||||
&dmaWriteEvent);
|
&dmaWriteEvent);
|
||||||
} else {
|
} else {
|
||||||
// schedule event with disk delay (dmaWriteDone)
|
// schedule event with disk delay (dmaWriteDone)
|
||||||
|
@ -423,6 +479,29 @@ IdeDisk::dmaWriteDone()
|
||||||
Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
|
Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
|
||||||
uint32_t bytesRead = 0, bytesInPage = 0;
|
uint32_t bytesRead = 0, bytesInPage = 0;
|
||||||
|
|
||||||
|
// continue to use the DMA interface until all pages are read
|
||||||
|
if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
|
||||||
|
// see if the interface is busy
|
||||||
|
if (dmaInterface->busy()) {
|
||||||
|
// reschedule after waiting period
|
||||||
|
dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
|
||||||
|
curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
|
||||||
|
dmaAddr = pciToDma(curAddr);
|
||||||
|
|
||||||
|
bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
|
||||||
|
dmaInterfaceBytes += bytesInPage;
|
||||||
|
|
||||||
|
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
|
||||||
|
bytesInPage, curTick,
|
||||||
|
&dmaWriteEvent);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// setup the initial page and DMA address
|
// setup the initial page and DMA address
|
||||||
curAddr = curPrd.getBaseAddr();
|
curAddr = curPrd.getBaseAddr();
|
||||||
pageAddr = alpha_trunc_page(curAddr);
|
pageAddr = alpha_trunc_page(curAddr);
|
||||||
|
@ -435,7 +514,6 @@ IdeDisk::dmaWriteDone()
|
||||||
// see if we have crossed into a new page
|
// see if we have crossed into a new page
|
||||||
if (pageAddr != alpha_trunc_page(curAddr)) {
|
if (pageAddr != alpha_trunc_page(curAddr)) {
|
||||||
// write the data to memory
|
// write the data to memory
|
||||||
/** @todo Do real DMA using interfaces here */
|
|
||||||
memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
|
memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
|
||||||
(void *)(dataBuffer + (bytesRead - bytesInPage)),
|
(void *)(dataBuffer + (bytesRead - bytesInPage)),
|
||||||
bytesInPage);
|
bytesInPage);
|
||||||
|
@ -459,7 +537,6 @@ IdeDisk::dmaWriteDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the last page worth read to memory
|
// write the last page worth read to memory
|
||||||
/** @todo Do real DMA using interfaces here */
|
|
||||||
if (bytesInPage != 0) {
|
if (bytesInPage != 0) {
|
||||||
memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
|
memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
|
||||||
(void *)(dataBuffer + (bytesRead - bytesInPage)),
|
(void *)(dataBuffer + (bytesRead - bytesInPage)),
|
||||||
|
@ -521,7 +598,7 @@ IdeDisk::startDma(const uint32_t &prdTableBase)
|
||||||
if (devState != Transfer_Data_Dma)
|
if (devState != Transfer_Data_Dma)
|
||||||
panic("Inconsistent device state for DMA start!\n");
|
panic("Inconsistent device state for DMA start!\n");
|
||||||
|
|
||||||
curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase);
|
curPrdAddr = pciToDma((Addr)prdTableBase);
|
||||||
|
|
||||||
dmaState = Dma_Transfer;
|
dmaState = Dma_Transfer;
|
||||||
|
|
||||||
|
@ -927,11 +1004,115 @@ IdeDisk::updateState(DevAction_t action)
|
||||||
void
|
void
|
||||||
IdeDisk::serialize(ostream &os)
|
IdeDisk::serialize(ostream &os)
|
||||||
{
|
{
|
||||||
|
// Check all outstanding events to see if they are scheduled
|
||||||
|
// these are all mutually exclusive
|
||||||
|
Tick reschedule = 0;
|
||||||
|
Events_t event = None;
|
||||||
|
|
||||||
|
if (dmaTransferEvent.scheduled()) {
|
||||||
|
reschedule = dmaTransferEvent.when();
|
||||||
|
event = Transfer;
|
||||||
|
} else if (dmaReadWaitEvent.scheduled()) {
|
||||||
|
reschedule = dmaReadWaitEvent.when();
|
||||||
|
event = ReadWait;
|
||||||
|
} else if (dmaWriteWaitEvent.scheduled()) {
|
||||||
|
reschedule = dmaWriteWaitEvent.when();
|
||||||
|
event = WriteWait;
|
||||||
|
} else if (dmaPrdReadEvent.scheduled()) {
|
||||||
|
reschedule = dmaPrdReadEvent.when();
|
||||||
|
event = PrdRead;
|
||||||
|
} else if (dmaReadEvent.scheduled()) {
|
||||||
|
reschedule = dmaReadEvent.when();
|
||||||
|
event = DmaRead;
|
||||||
|
} else if (dmaWriteEvent.scheduled()) {
|
||||||
|
reschedule = dmaWriteEvent.when();
|
||||||
|
event = DmaWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
SERIALIZE_SCALAR(reschedule);
|
||||||
|
SERIALIZE_ENUM(event);
|
||||||
|
|
||||||
|
// Serialize device registers
|
||||||
|
SERIALIZE_SCALAR(cmdReg.data0);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.data1);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.sec_count);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.sec_num);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.cyl_low);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.cyl_high);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.drive);
|
||||||
|
SERIALIZE_SCALAR(cmdReg.status);
|
||||||
|
SERIALIZE_SCALAR(nIENBit);
|
||||||
|
SERIALIZE_SCALAR(devID);
|
||||||
|
|
||||||
|
// Serialize the PRD related information
|
||||||
|
SERIALIZE_SCALAR(curPrd.entry.baseAddr);
|
||||||
|
SERIALIZE_SCALAR(curPrd.entry.byteCount);
|
||||||
|
SERIALIZE_SCALAR(curPrd.entry.endOfTable);
|
||||||
|
SERIALIZE_SCALAR(curPrdAddr);
|
||||||
|
|
||||||
|
// Serialize current transfer related information
|
||||||
|
SERIALIZE_SCALAR(cmdBytesLeft);
|
||||||
|
SERIALIZE_SCALAR(drqBytesLeft);
|
||||||
|
SERIALIZE_SCALAR(curSector);
|
||||||
|
SERIALIZE_SCALAR(curCommand);
|
||||||
|
SERIALIZE_SCALAR(dmaRead);
|
||||||
|
SERIALIZE_SCALAR(dmaInterfaceBytes);
|
||||||
|
SERIALIZE_SCALAR(intrPending);
|
||||||
|
SERIALIZE_ENUM(devState);
|
||||||
|
SERIALIZE_ENUM(dmaState);
|
||||||
|
SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IdeDisk::unserialize(Checkpoint *cp, const string §ion)
|
IdeDisk::unserialize(Checkpoint *cp, const string §ion)
|
||||||
{
|
{
|
||||||
|
// Reschedule events that were outstanding
|
||||||
|
// these are all mutually exclusive
|
||||||
|
Tick reschedule = 0;
|
||||||
|
Events_t event = None;
|
||||||
|
|
||||||
|
UNSERIALIZE_SCALAR(reschedule);
|
||||||
|
UNSERIALIZE_ENUM(event);
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case None : break;
|
||||||
|
case Transfer : dmaTransferEvent.schedule(reschedule); break;
|
||||||
|
case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
|
||||||
|
case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
|
||||||
|
case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
|
||||||
|
case DmaRead : dmaReadEvent.schedule(reschedule); break;
|
||||||
|
case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unserialize device registers
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.data0);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.data1);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.sec_count);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.sec_num);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.cyl_low);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.cyl_high);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.drive);
|
||||||
|
UNSERIALIZE_SCALAR(cmdReg.status);
|
||||||
|
UNSERIALIZE_SCALAR(nIENBit);
|
||||||
|
UNSERIALIZE_SCALAR(devID);
|
||||||
|
|
||||||
|
// Unserialize the PRD related information
|
||||||
|
UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
|
||||||
|
UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
|
||||||
|
UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
|
||||||
|
UNSERIALIZE_SCALAR(curPrdAddr);
|
||||||
|
|
||||||
|
// Unserialize current transfer related information
|
||||||
|
UNSERIALIZE_SCALAR(cmdBytesLeft);
|
||||||
|
UNSERIALIZE_SCALAR(drqBytesLeft);
|
||||||
|
UNSERIALIZE_SCALAR(curSector);
|
||||||
|
UNSERIALIZE_SCALAR(curCommand);
|
||||||
|
UNSERIALIZE_SCALAR(dmaRead);
|
||||||
|
UNSERIALIZE_SCALAR(dmaInterfaceBytes);
|
||||||
|
UNSERIALIZE_SCALAR(intrPending);
|
||||||
|
UNSERIALIZE_ENUM(devState);
|
||||||
|
UNSERIALIZE_ENUM(dmaState);
|
||||||
|
UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
@ -950,7 +1131,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
|
||||||
INIT_PARAM(image, "Disk image"),
|
INIT_PARAM(image, "Disk image"),
|
||||||
INIT_PARAM(physmem, "Physical memory"),
|
INIT_PARAM(physmem, "Physical memory"),
|
||||||
INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
|
INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
|
||||||
INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0)
|
INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in microseconds", 1)
|
||||||
|
|
||||||
END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
|
END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,16 @@ typedef struct CommandReg {
|
||||||
};
|
};
|
||||||
} CommandReg_t;
|
} CommandReg_t;
|
||||||
|
|
||||||
|
typedef enum Events {
|
||||||
|
None = 0,
|
||||||
|
Transfer,
|
||||||
|
ReadWait,
|
||||||
|
WriteWait,
|
||||||
|
PrdRead,
|
||||||
|
DmaRead,
|
||||||
|
DmaWrite
|
||||||
|
} Events_t;
|
||||||
|
|
||||||
typedef enum DevAction {
|
typedef enum DevAction {
|
||||||
ACT_NONE = 0,
|
ACT_NONE = 0,
|
||||||
ACT_CMD_WRITE,
|
ACT_CMD_WRITE,
|
||||||
|
@ -184,7 +194,7 @@ class IdeDisk : public SimObject
|
||||||
PhysicalMemory *physmem;
|
PhysicalMemory *physmem;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** The disk delay in milliseconds. */
|
/** The disk delay in microseconds. */
|
||||||
int diskDelay;
|
int diskDelay;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -214,6 +224,8 @@ class IdeDisk : public SimObject
|
||||||
uint32_t curPrdAddr;
|
uint32_t curPrdAddr;
|
||||||
/** PRD entry */
|
/** PRD entry */
|
||||||
PrdTableEntry curPrd;
|
PrdTableEntry curPrd;
|
||||||
|
/** Number of bytes transfered by DMA interface for current transfer */
|
||||||
|
uint32_t dmaInterfaceBytes;
|
||||||
/** Device ID (master=0/slave=1) */
|
/** Device ID (master=0/slave=1) */
|
||||||
int devID;
|
int devID;
|
||||||
/** Interrupt pending */
|
/** Interrupt pending */
|
||||||
|
@ -313,7 +325,9 @@ class IdeDisk : public SimObject
|
||||||
(cmdReg.cyl_low << 8) | (cmdReg.sec_num));
|
(cmdReg.cyl_low << 8) | (cmdReg.sec_num));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Addr pciToDma(Addr &pciAddr);
|
inline Addr pciToDma(Addr pciAddr);
|
||||||
|
|
||||||
|
uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize this object to the given output stream.
|
* Serialize this object to the given output stream.
|
||||||
|
|
Loading…
Reference in a new issue