Checkin of latest IDE and some separation between platforms (Tsunami and

Turbolaser)

base/range.hh:
    Change semantics of range to be inclusive of the end value, may need to
    check other users of range to make sure they are semantically correct.
    This was needed for access of last byte in range of address on IDE and
    makes sense for case of range from 0 to all f
dev/ide_ctrl.cc:
dev/ide_ctrl.hh:
dev/ide_disk.cc:
dev/ide_disk.hh:
    Whole mess of changes.. at current state simulator will boot and read
    partition table and then have a bunch of errors and panic
dev/pciconfigall.cc:
dev/pciconfigall.hh:
dev/platform.hh:
    Changes to work with platform separation
dev/tsunami.cc:
dev/tsunami.hh:
    Change to work with platform separation

--HG--
extra : convert_revision : e1de22b54df7fdcf391efc2a8555ada93f46beab
This commit is contained in:
Andrew Schultz 2004-05-03 11:47:52 -04:00
parent 75cef1a801
commit 6807c319b0
10 changed files with 1295 additions and 237 deletions

View file

@ -225,7 +225,7 @@ inline bool
operator==(const T &pos, const Range<U> &range)
{
assert(range.valid());
return pos >= range.start && pos < range.end;
return pos >= range.start && pos <= range.end;
}
/**

View file

@ -38,6 +38,7 @@
#include "dev/pciconfigall.hh"
#include "dev/ide_disk.hh"
#include "dev/ide_ctrl.hh"
#include "dev/tsunami_cchip.hh"
#include "mem/bus/bus.hh"
#include "mem/bus/pio_interface.hh"
#include "mem/bus/pio_interface_impl.hh"
@ -84,13 +85,13 @@ IdeController::IdeController(const string &name, IntrControl *ic,
bmi_size = BARSize[4];
// zero out all of the registers
memset(regs, 0, sizeof(regs));
memset(bmi_regs, 0, sizeof(bmi_regs));
memset(pci_regs, 0, sizeof(pci_regs));
// setup initial values
*(uint32_t *)&pci_regs[IDETIM] = 0x80008000; // enable both channels
*(uint8_t *)&regs[BMI + BMIS0] = 0x60;
*(uint8_t *)&regs[BMI + BMIS1] = 0x60;
*(uint8_t *)&bmi_regs[BMIS0] = 0x60;
*(uint8_t *)&bmi_regs[BMIS1] = 0x60;
// reset all internal variables
io_enabled = false;
@ -114,7 +115,7 @@ IdeController::IdeController(const string &name, IntrControl *ic,
for (int i = 0; i < new_disks.size(); i++) {
disks[i] = new_disks[i];
disks[i]->setController(this);
disks[i]->setController(this, dmaInterface);
}
}
@ -125,6 +126,51 @@ IdeController::~IdeController()
delete disks[i];
}
////
// Command completion
////
void
IdeController::setDmaComplete(IdeDisk *disk)
{
int diskNum = getDisk(disk);
if (diskNum < 0)
panic("Unable to find disk based on pointer %#x\n", disk);
if (diskNum < 2) {
// clear the start/stop bit in the command register
bmi_regs[BMIC0] &= ~SSBM;
// clear the bus master active bit in the status register
bmi_regs[BMIS0] &= ~BMIDEA;
// set the interrupt bit
bmi_regs[BMIS0] |= IDEINTS;
} else {
// clear the start/stop bit in the command register
bmi_regs[BMIC1] &= ~SSBM;
// clear the bus master active bit in the status register
bmi_regs[BMIS1] &= ~BMIDEA;
// set the interrupt bit
bmi_regs[BMIS1] |= IDEINTS;
}
}
////
// Interrupt handling
////
void
IdeController::intrPost()
{
tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
}
void
IdeController::intrClear()
{
tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
}
////
// Bus timing and bus access functions
////
@ -289,7 +335,16 @@ IdeController::WriteConfig(int offset, int size, uint32_t data)
Fault
IdeController::read(MemReqPtr &req, uint8_t *data)
{
Addr offset = getOffset(req->paddr);
Addr offset;
bool primary;
bool byte;
bool cmdBlk;
RegType_t type;
int disk;
parseAddr(req->paddr, offset, primary, type);
byte = (req->size == sizeof(uint8_t)) ? true : false;
cmdBlk = (type == COMMAND_BLOCK) ? true : false;
if (!io_enabled)
return No_Fault;
@ -299,11 +354,18 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
req->size != sizeof(uint32_t))
panic("IDE controller read of invalid size: %#x\n", req->size);
DPRINTF(IdeCtrl, "IDE default read from offset: %#x size: %#x data: %#x\n",
offset, req->size, *(uint32_t *)&regs[offset]);
if (type != BMI_BLOCK) {
assert(req->size != sizeof(uint32_t));
// copy the data from the control registers
memcpy((void *)data, &regs[offset], req->size);
disk = getDisk(primary);
if (disks[disk])
disks[disk]->read(offset, byte, cmdBlk, data);
} else {
memcpy((void *)data, &bmi_regs[offset], req->size);
}
DPRINTF(IdeCtrl, "IDE read from offset: %#x size: %#x data: %#x\n",
offset, req->size, *(uint32_t *)data);
return No_Fault;
}
@ -311,153 +373,144 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
Fault
IdeController::write(MemReqPtr &req, const uint8_t *data)
{
int disk = 0; // selected disk index
uint8_t oldVal, newVal;
Addr offset;
bool primary;
bool byte;
bool cmdBlk;
RegType_t type;
int disk;
Addr offset = getOffset(req->paddr);
parseAddr(req->paddr, offset, primary, type);
byte = (req->size == sizeof(uint8_t)) ? true : false;
cmdBlk = (type == COMMAND_BLOCK) ? true : false;
DPRINTF(IdeCtrl, "IDE write from offset: %#x size: %#x data: %#x\n",
offset, req->size, *(uint32_t *)data);
uint8_t oldVal, newVal;
if (!io_enabled)
return No_Fault;
if (offset >= BMI && !bm_enabled)
if (type == BMI_BLOCK && !bm_enabled)
return No_Fault;
switch (offset) {
// Bus master IDE command register
case (BMI + BMIC1):
case (BMI + BMIC0):
if (req->size != sizeof(uint8_t))
panic("Invalid BMIC write size: %x\n", req->size);
// select the current disk based on DEV bit
disk = getDisk(offset);
oldVal = regs[offset];
newVal = *data;
// if a DMA transfer is in progress, R/W control cannot change
if (oldVal & SSBM) {
if ((oldVal & RWCON) ^ (newVal & RWCON)) {
(oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
}
if (type != BMI_BLOCK) {
// shadow the dev bit
if (type == COMMAND_BLOCK && offset == IDE_SELECT_OFFSET) {
uint8_t *devBit = (primary ? &dev[0] : &dev[1]);
*devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0);
}
// see if the start/stop bit is being changed
if ((oldVal & SSBM) ^ (newVal & SSBM)) {
assert(req->size != sizeof(uint32_t));
disk = getDisk(primary);
if (disks[disk])
disks[disk]->write(offset, byte, cmdBlk, data);
} else {
switch (offset) {
// Bus master IDE command register
case BMIC1:
case BMIC0:
if (req->size != sizeof(uint8_t))
panic("Invalid BMIC write size: %x\n", req->size);
// select the current disk based on DEV bit
disk = getDisk(primary);
oldVal = bmi_regs[offset];
newVal = *data;
// if a DMA transfer is in progress, R/W control cannot change
if (oldVal & SSBM) {
// stopping DMA transfer
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
// clear the BMIDEA bit
regs[offset + 0x2] &= ~BMIDEA;
if (disks[disk] == NULL)
panic("DMA stop for disk %d which does not exist\n", disk);
// inform the disk of the DMA transfer abort
disks[disk]->dmaStop();
} else {
// starting DMA transfer
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
// set the BMIDEA bit
regs[offset + 0x2] |= BMIDEA;
if (disks[disk] == NULL)
panic("DMA start for disk %d which does not exist\n",
disk);
// inform the disk of the DMA transfer start
disks[disk]->dmaStart();
if ((oldVal & RWCON) ^ (newVal & RWCON)) {
(oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
}
}
// see if the start/stop bit is being changed
if ((oldVal & SSBM) ^ (newVal & SSBM)) {
if (oldVal & SSBM) {
// stopping DMA transfer
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
// clear the BMIDEA bit
bmi_regs[offset + 0x2] &= ~BMIDEA;
if (disks[disk] == NULL)
panic("DMA stop for disk %d which does not exist\n",
disk);
// inform the disk of the DMA transfer abort
disks[disk]->abortDma();
} else {
// starting DMA transfer
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
// set the BMIDEA bit
bmi_regs[offset + 0x2] |= BMIDEA;
if (disks[disk] == NULL)
panic("DMA start for disk %d which does not exist\n",
disk);
// inform the disk of the DMA transfer start
if (primary)
disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP0]);
else
disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP1]);
}
}
// update the register value
bmi_regs[offset] = newVal;
break;
// Bus master IDE status register
case BMIS0:
case BMIS1:
if (req->size != sizeof(uint8_t))
panic("Invalid BMIS write size: %x\n", req->size);
oldVal = bmi_regs[offset];
newVal = *data;
// the BMIDEA bit is RO
newVal |= (oldVal & BMIDEA);
// to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
if ((oldVal & IDEINTS) && (newVal & IDEINTS))
newVal &= ~IDEINTS; // clear the interrupt?
else
(oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
newVal &= ~IDEDMAE;
else
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
bmi_regs[offset] = newVal;
break;
// Bus master IDE descriptor table pointer register
case BMIDTP0:
case BMIDTP1:
if (req->size != sizeof(uint32_t))
panic("Invalid BMIDTP write size: %x\n", req->size);
*(uint32_t *)&bmi_regs[offset] = *(uint32_t *)data & ~0x3;
break;
default:
if (req->size != sizeof(uint8_t) &&
req->size != sizeof(uint16_t) &&
req->size != sizeof(uint32_t))
panic("IDE controller write of invalid write size: %x\n",
req->size);
// do a default copy of data into the registers
memcpy((void *)&bmi_regs[offset], data, req->size);
}
// update the register value
regs[offset] = newVal;
break;
// Bus master IDE status register
case (BMI + BMIS0):
case (BMI + BMIS1):
if (req->size != sizeof(uint8_t))
panic("Invalid BMIS write size: %x\n", req->size);
oldVal = regs[offset];
newVal = *data;
// the BMIDEA bit is RO
newVal |= (oldVal & BMIDEA);
// to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
if ((oldVal & IDEINTS) && (newVal & IDEINTS))
newVal &= ~IDEINTS; // clear the interrupt?
else
(oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
newVal &= ~IDEDMAE;
else
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
regs[offset] = newVal;
break;
// Bus master IDE descriptor table pointer register
case (BMI + BMIDTP0):
case (BMI + BMIDTP1):
if (req->size != sizeof(uint32_t))
panic("Invalid BMIDTP write size: %x\n", req->size);
*(uint32_t *)&regs[offset] = *(uint32_t *)data & ~0x3;
break;
// Write the data word in the command register block
case (CMD1 + IDE_DATA_OFFSET):
case (CMD0 + IDE_DATA_OFFSET):
if (req->size != sizeof(uint16_t))
panic("Invalid command block data write size: %x\n", req->size);
break;
// Write the command byte in command register block
case (CMD1 + IDE_COMMAND_OFFSET):
case (CMD0 + IDE_COMMAND_OFFSET):
if (req->size != sizeof(uint8_t))
panic("Invalid command block command write size: %x\n", req->size);
// select the disk based on the DEV bit
disk = getDisk(offset);
if (cmd_in_progress[disk])
panic("Command on disk %d already in progress!\n", disk);
if (disks[disk] == NULL)
panic("Specified disk %d does not exist!\n", disk);
cmd_in_progress[disk] = true;
// write to both the command/status and alternate status
regs[offset] = *data;
regs[offset + 3] = *data;
// issue the command to the disk
if (disk < 2)
disks[disk]->startIO(&regs[CMD0], &regs[BMI + BMIDTP0]);
else
disks[disk]->startIO(&regs[CMD1], &regs[BMI + BMIDTP1]);
break;
default:
if (req->size != sizeof(uint8_t) && req->size != sizeof(uint16_t) &&
req->size != sizeof(uint32_t))
panic("IDE controller write of invalid write size: %x\n",
req->size);
DPRINTF(IdeCtrl, "IDE default write offset: %#x size: %#x data: %#x\n",
offset, req->size, *(uint32_t *)data);
// do a default copy of data into the registers
memcpy((void *)&regs[offset], data, req->size);
}
return No_Fault;

View file

@ -37,12 +37,6 @@
#include "dev/pcireg.h"
#include "dev/io_device.hh"
#define CMD0 0x00 // Channel 0 command block offset
#define CTRL0 0x08 // Channel 0 control block offset
#define CMD1 0x0c // Channel 1 command block offset
#define CTRL1 0x14 // Channel 1 control block offset
#define BMI 0x18 // Bus master IDE offset
#define BMIC0 0x0 // Bus master IDE command register
#define BMIS0 0x2 // Bus master IDE status register
#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register
@ -62,17 +56,8 @@
#define BMIDEA 0x01 // Bus master IDE active
// IDE Command byte fields
// Taken from include/linux/ide.h
#define IDE_DATA_OFFSET (0)
#define IDE_ERROR_OFFSET (1)
#define IDE_NSECTOR_OFFSET (2)
#define IDE_SECTOR_OFFSET (3)
#define IDE_LCYL_OFFSET (4)
#define IDE_HCYL_OFFSET (5)
#define IDE_SELECT_OFFSET (6)
#define IDE_STATUS_OFFSET (7)
#define IDE_CONTROL_OFFSET (8)
#define IDE_IRQ_OFFSET (9)
#define IDE_SELECT_DEV_BIT 0x10
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
@ -92,8 +77,14 @@
#define BME 0x04 // Bus master function enable
#define IOSE 0x01 // I/O space enable
class IntrControl;
typedef enum RegType {
COMMAND_BLOCK = 0,
CONTROL_BLOCK,
BMI_BLOCK
} RegType_t;
class IdeDisk;
class IntrControl;
class PciConfigAll;
class Tsunami;
class PhysicalMemory;
@ -125,8 +116,10 @@ class IdeController : public PciDev
Addr bmi_size;
private:
/** Registers used for programmed I/O and bus master interface */
uint8_t regs[40];
/** Registers used for bus master interface */
uint8_t bmi_regs[16];
/** Shadows of the device select bit */
uint8_t dev[2];
/** Registers used in PCI configuration */
uint8_t pci_regs[8];
@ -135,60 +128,77 @@ class IdeController : public PciDev
bool bm_enabled;
bool cmd_in_progress[4];
private:
public:
/** Pointer to the chipset */
Tsunami *tsunami;
private:
/** IDE disks connected to controller */
IdeDisk *disks[4];
private:
/** Get offset into register file from access address */
Addr getOffset(const Addr &addr) {
Addr offset = addr;
/** Parse the access address to pass on to device */
void 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;
offset += CMD0;
type = COMMAND_BLOCK;
primary = true;
} else if (addr >= pri_ctrl_addr &&
addr < (pri_ctrl_addr + pri_ctrl_size)) {
offset -= pri_ctrl_addr;
offset += CTRL0;
type = CONTROL_BLOCK;
primary = true;
} else if (addr >= sec_cmd_addr &&
addr < (sec_cmd_addr + sec_cmd_size)) {
offset -= sec_cmd_addr;
offset += CMD1;
type = COMMAND_BLOCK;
primary = false;
} else if (addr >= sec_ctrl_addr &&
addr < (sec_ctrl_addr + sec_ctrl_size)) {
offset -= sec_ctrl_addr;
offset += CTRL1;
type = CONTROL_BLOCK;
primary = false;
} else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
offset -= bmi_addr;
offset += BMI;
type = BMI_BLOCK;
primary = (offset < BMIC1) ? true : false;
} else {
panic("IDE controller access to invalid address: %#x\n", addr);
}
return offset;
};
/** Select the disk based on the register offset */
int getDisk(const Addr &offset) {
/** Select the disk based on the channel and device bit */
int getDisk(bool primary)
{
int disk = 0;
uint8_t *devBit = &dev[0];
// If the offset is in the channel 1 range, disks are 2 or 3
if (offset >= CMD1 && offset < BMI && offset >= (BMI + BMIC1))
if (!primary) {
disk += 2;
if (disk < 2) {
if (regs[CMD0 + IDE_STATUS_OFFSET] & 0x10)
disk += 1;
} else {
if (regs[CMD1 + IDE_STATUS_OFFSET] & 0x10)
disk += 1;
devBit = &dev[1];
}
disk += *devBit;
assert(*devBit == 0 || *devBit == 1);
return disk;
};
/** Select the disk based on a pointer */
int getDisk(IdeDisk *diskPtr)
{
for (int i = 0; i < 4; i++) {
if ((long)diskPtr == (long)disks[i])
return i;
}
return -1;
}
public:
/**
* Constructs and initializes this controller.
@ -204,7 +214,7 @@ class IdeController : public PciDev
* @param hier The hierarchy parameters
*/
IdeController(const std::string &name, IntrControl *ic,
const vector<IdeDisk *> &new_disks,
const std::vector<IdeDisk *> &new_disks,
MemoryController *mmu, PciConfigAll *cf,
PciConfigData *cd, Tsunami *t,
uint32_t bus_num, uint32_t dev_num, uint32_t func_num,
@ -218,6 +228,11 @@ class IdeController : public PciDev
virtual void WriteConfig(int offset, int size, uint32_t data);
virtual void ReadConfig(int offset, int size, uint8_t *data);
void intrPost();
void intrClear();
void setDmaComplete(IdeDisk *disk);
/**
* Read a done field for a given target.
* @param req Contains the address of the field to read.

View file

@ -39,20 +39,795 @@
#include "base/trace.hh"
#include "dev/disk_image.hh"
#include "dev/ide_disk.hh"
#include "dev/ide_ctrl.hh"
#include "dev/tsunami.hh"
#include "dev/tsunami_pchip.hh"
#include "mem/functional_mem/physical_memory.hh"
#include "mem/bus/bus.hh"
#include "mem/bus/dma_interface.hh"
#include "mem/bus/pio_interface.hh"
#include "mem/bus/pio_interface_impl.hh"
#include "sim/builder.hh"
#include "sim/sim_object.hh"
#include "sim/universe.hh"
using namespace std;
IdeDisk::IdeDisk(const string &name, DiskImage *img, int delay)
: SimObject(name), ctrl(NULL), image(img)
IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
int id, int delay)
: SimObject(name), ctrl(NULL), image(img), physmem(phys), dmaTransferEvent(this),
dmaReadWaitEvent(this), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
dmaReadEvent(this), dmaWriteEvent(this)
{
diskDelay = delay * ticksPerSecond / 1000;
diskDelay = (delay * ticksPerSecond / 1000) / image->size();
// initialize the data buffer and shadow registers
dataBuffer = new uint8_t[MAX_DMA_SIZE];
memset(dataBuffer, 0, MAX_DMA_SIZE);
memset(&cmdReg, 0, sizeof(CommandReg_t));
memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
curPrdAddr = 0;
curSector = 0;
curCommand = 0;
cmdBytesLeft = 0;
drqBytesLeft = 0;
dmaRead = false;
intrPending = false;
// fill out the drive ID structure
memset(&driveID, 0, sizeof(struct hd_driveid));
// Calculate LBA and C/H/S values
uint16_t cylinders;
uint8_t heads;
uint8_t sectors;
uint32_t lba_size = image->size();
if (lba_size >= 16383*16*63) {
cylinders = 16383;
heads = 16;
sectors = 63;
} else {
if (lba_size >= 63)
sectors = 63;
else
sectors = lba_size;
if ((lba_size / sectors) >= 16)
heads = 16;
else
heads = (lba_size / sectors);
cylinders = lba_size / (heads * sectors);
}
// Setup the model name
sprintf((char *)driveID.model, "5MI EDD si k");
// Set the maximum multisector transfer size
driveID.max_multsect = MAX_MULTSECT;
// IORDY supported, IORDY disabled, LBA enabled, DMA enabled
driveID.capability = 0x7;
// UDMA support, EIDE support
driveID.field_valid = 0x6;
// Setup default C/H/S settings
driveID.cyls = cylinders;
driveID.sectors = sectors;
driveID.heads = heads;
// Setup the current multisector transfer size
driveID.multsect = MAX_MULTSECT;
driveID.multsect_valid = 0x1;
// Number of sectors on disk
driveID.lba_capacity = lba_size;
// Multiword DMA mode 2 and below supported
driveID.dma_mword = 0x400;
// Set PIO mode 4 and 3 supported
driveID.eide_pio_modes = 0x3;
// Set DMA mode 4 and below supported
driveID.dma_ultra = 0x10;
// Statically set hardware config word
driveID.hw_config = 0x4001;
// set the device state to idle
dmaState = Dma_Idle;
if (id == DEV0) {
devState = Device_Idle_S;
devID = DEV0;
} else if (id == DEV1) {
devState = Device_Idle_NS;
devID = DEV1;
} else {
panic("Invalid device ID: %#x\n", id);
}
// set the device ready bit
cmdReg.status |= STATUS_DRDY_BIT;
}
IdeDisk::~IdeDisk()
{
// destroy the data buffer
delete [] dataBuffer;
}
////
// Device registers read/write
////
void
IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data)
{
DevAction_t action = ACT_NONE;
if (cmdBlk) {
if (offset < 0 || offset > sizeof(CommandReg_t))
panic("Invalid disk command register offset: %#x\n", offset);
if (!byte && offset != DATA_OFFSET)
panic("Invalid 16-bit read, only allowed on data reg\n");
if (!byte)
*(uint16_t *)data = *(uint16_t *)&cmdReg.data0;
else
*data = ((uint8_t *)&cmdReg)[offset];
// determine if an action needs to be taken on the state machine
if (offset == STATUS_OFFSET) {
action = ACT_STAT_READ;
} else if (offset == DATA_OFFSET) {
if (byte)
action = ACT_DATA_READ_BYTE;
else
action = ACT_DATA_READ_SHORT;
}
} else {
if (offset != ALTSTAT_OFFSET)
panic("Invalid disk control register offset: %#x\n", offset);
if (!byte)
panic("Invalid 16-bit read from control block\n");
*data = ((uint8_t *)&cmdReg)[STATUS_OFFSET];
}
if (action != ACT_NONE)
updateState(action);
}
void
IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data)
{
DevAction_t action = ACT_NONE;
if (cmdBlk) {
if (offset < 0 || offset > sizeof(CommandReg_t))
panic("Invalid disk command register offset: %#x\n", offset);
if (!byte && offset != DATA_OFFSET)
panic("Invalid 16-bit write, only allowed on data reg\n");
if (!byte)
*((uint16_t *)&cmdReg.data0) = *(uint16_t *)data;
else
((uint8_t *)&cmdReg)[offset] = *data;
// determine if an action needs to be taken on the state machine
if (offset == COMMAND_OFFSET) {
action = ACT_CMD_WRITE;
} else if (offset == DATA_OFFSET) {
if (byte)
action = ACT_DATA_WRITE_BYTE;
else
action = ACT_DATA_WRITE_SHORT;
}
} else {
if (offset != CONTROL_OFFSET)
panic("Invalid disk control register offset: %#x\n", offset);
if (!byte)
panic("Invalid 16-bit write to control block\n");
if (*data & CONTROL_RST_BIT)
panic("Software reset not supported!\n");
nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
}
if (action != ACT_NONE)
updateState(action);
}
////
// Perform DMA transactions
////
void
IdeDisk::doDmaTransfer()
{
if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
dmaState, devState);
// first read the current PRD
if (dmaInterface) {
if (dmaInterface->busy()) {
// reschedule after waiting period
dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return;
}
dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick,
&dmaPrdReadEvent);
} else {
dmaPrdReadDone();
}
}
void
IdeDisk::dmaPrdReadDone()
{
// actually copy the PRD from physical memory
memcpy((void *)&curPrd.entry,
physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
sizeof(PrdEntry_t));
curPrdAddr += sizeof(PrdEntry_t);
if (dmaRead)
doDmaRead();
else
doDmaWrite();
}
void
IdeDisk::doDmaRead()
{
Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
if (dmaInterface) {
if (dmaInterface->busy()) {
// reschedule after waiting period
dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return;
}
Addr dmaAddr =
ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(),
curTick + totalDiskDelay, &dmaReadEvent);
} else {
// schedule dmaReadEvent with sectorDelay (dmaReadDone)
dmaReadEvent.schedule(curTick + totalDiskDelay);
}
}
void
IdeDisk::dmaReadDone()
{
// actually copy the data from memory to data buffer
Addr dmaAddr =
ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
memcpy((void *)dataBuffer,
physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
curPrd.getByteCount());
uint32_t bytesWritten = 0;
while (bytesWritten < curPrd.getByteCount()) {
if (cmdBytesLeft <= 0)
panic("DMA data is larger than # sectors specified\n");
writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
bytesWritten += SectorSize;
cmdBytesLeft -= SectorSize;
}
// check for the EOT
if (curPrd.getEOT()){
assert(cmdBytesLeft == 0);
dmaState = Dma_Idle;
updateState(ACT_DMA_DONE);
} else {
doDmaTransfer();
}
}
void
IdeDisk::doDmaWrite()
{
Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
if (dmaInterface) {
if (dmaInterface->busy()) {
// reschedule after waiting period
dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return;
}
Addr dmaAddr =
ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
curPrd.getByteCount(), curTick + totalDiskDelay,
&dmaWriteEvent);
} else {
// schedule event with disk delay (dmaWriteDone)
dmaWriteEvent.schedule(curTick + totalDiskDelay);
}
}
void
IdeDisk::dmaWriteDone()
{
uint32_t bytesRead = 0;
// clear out the data buffer
memset(dataBuffer, 0, MAX_DMA_SIZE);
while (bytesRead < curPrd.getByteCount()) {
if (cmdBytesLeft <= 0)
panic("DMA requested data is larger than # sectors specified\n");
readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
bytesRead += SectorSize;
cmdBytesLeft -= SectorSize;
}
// copy the data to memory
Addr dmaAddr =
ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
(void *)dataBuffer, curPrd.getByteCount());
// check for the EOT
if (curPrd.getEOT()) {
assert(cmdBytesLeft == 0);
dmaState = Dma_Idle;
updateState(ACT_DMA_DONE);
} else {
doDmaTransfer();
}
}
////
// Disk utility routines
///
void
IdeDisk::readDisk(uint32_t sector, uint8_t *data)
{
uint32_t bytesRead = image->read(data, sector);
if (bytesRead != SectorSize)
panic("Can't read from %s. Only %d of %d read. errno=%d\n",
name(), bytesRead, SectorSize, errno);
}
void
IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
{
uint32_t bytesWritten = image->write(data, sector);
if (bytesWritten != SectorSize)
panic("Can't write to %s. Only %d of %d written. errno=%d\n",
name(), bytesWritten, SectorSize, errno);
}
////
// Setup and handle commands
////
void
IdeDisk::startDma(const uint32_t &prdTableBase)
{
if (dmaState != Dma_Start)
panic("Inconsistent DMA state, should be in Dma_Start!\n");
if (devState != Transfer_Data_Dma)
panic("Inconsistent device state for DMA start!\n");
curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase);
dmaState = Dma_Transfer;
// schedule dma transfer (doDmaTransfer)
dmaTransferEvent.schedule(curTick + 1);
}
void
IdeDisk::abortDma()
{
if (dmaState == Dma_Idle)
panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n");
if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
panic("Inconsistent device state, should be in Transfer or Prepare!\n");
updateState(ACT_CMD_ERROR);
}
void
IdeDisk::startCommand()
{
DevAction_t action = ACT_NONE;
uint32_t size = 0;
dmaRead = false;
// copy the command to the shadow
curCommand = cmdReg.command;
// Decode commands
switch (cmdReg.command) {
// Supported non-data commands
case WIN_READ_NATIVE_MAX:
size = image->size() - 1;
cmdReg.sec_num = (size & 0xff);
cmdReg.cyl_low = ((size & 0xff00) >> 8);
cmdReg.cyl_high = ((size & 0xff0000) >> 16);
cmdReg.head = ((size & 0xf000000) >> 24);
devState = Command_Execution;
action = ACT_CMD_COMPLETE;
break;
case WIN_RECAL:
case WIN_SPECIFY:
case WIN_FLUSH_CACHE:
case WIN_VERIFY:
case WIN_SEEK:
case WIN_SETFEATURES:
case WIN_SETMULT:
devState = Command_Execution;
action = ACT_CMD_COMPLETE;
break;
// Supported PIO data-in commands
case WIN_IDENTIFY:
cmdBytesLeft = drqBytesLeft = sizeof(struct hd_driveid);
devState = Prepare_Data_In;
action = ACT_DATA_READY;
break;
case WIN_MULTREAD:
case WIN_READ:
if (!(cmdReg.drive & DRIVE_LBA_BIT))
panic("Attempt to perform CHS access, only supports LBA\n");
if (cmdReg.sec_count == 0)
cmdBytesLeft = (256 * SectorSize);
else
cmdBytesLeft = (cmdReg.sec_count * SectorSize);
drqBytesLeft = SectorSize;
curSector = getLBABase();
devState = Prepare_Data_In;
action = ACT_DATA_READY;
break;
// Supported PIO data-out commands
case WIN_MULTWRITE:
case WIN_WRITE:
if (!(cmdReg.drive & DRIVE_LBA_BIT))
panic("Attempt to perform CHS access, only supports LBA\n");
if (cmdReg.sec_count == 0)
cmdBytesLeft = (256 * SectorSize);
else
cmdBytesLeft = (cmdReg.sec_count * SectorSize);
drqBytesLeft = SectorSize;
curSector = getLBABase();
devState = Prepare_Data_Out;
action = ACT_DATA_READY;
break;
// Supported DMA commands
case WIN_WRITEDMA:
dmaRead = true; // a write to the disk is a DMA read from memory
case WIN_READDMA:
if (!(cmdReg.drive & DRIVE_LBA_BIT))
panic("Attempt to perform CHS access, only supports LBA\n");
if (cmdReg.sec_count == 0)
cmdBytesLeft = (256 * SectorSize);
else
cmdBytesLeft = (cmdReg.sec_count * SectorSize);
drqBytesLeft = SectorSize;
curSector = getLBABase();
devState = Prepare_Data_Dma;
action = ACT_DMA_READY;
break;
default:
panic("Unsupported ATA command: %#x\n", cmdReg.command);
}
if (action != ACT_NONE) {
// set the BSY bit
cmdReg.status |= STATUS_BSY_BIT;
// clear the DRQ bit
cmdReg.status &= ~STATUS_DRQ_BIT;
updateState(action);
}
}
////
// Handle setting and clearing interrupts
////
void
IdeDisk::intrPost()
{
if (intrPending)
panic("Attempt to post an interrupt with one pending\n");
intrPending = true;
// talk to controller to set interrupt
if (ctrl)
ctrl->intrPost();
}
void
IdeDisk::intrClear()
{
if (!intrPending)
panic("Attempt to clear a non-pending interrupt\n");
intrPending = false;
// talk to controller to clear interrupt
if (ctrl)
ctrl->intrClear();
}
////
// Manage the device internal state machine
////
void
IdeDisk::updateState(DevAction_t action)
{
switch (devState) {
case Device_Idle_S:
if (!isDEVSelect())
devState = Device_Idle_NS;
else if (action == ACT_CMD_WRITE)
startCommand();
break;
case Device_Idle_SI:
if (!isDEVSelect()) {
devState = Device_Idle_NS;
intrClear();
} else if (action == ACT_STAT_READ || isIENSet()) {
devState = Device_Idle_S;
intrClear();
} else if (action == ACT_CMD_WRITE) {
intrClear();
startCommand();
}
break;
case Device_Idle_NS:
if (isDEVSelect()) {
if (!isIENSet() && intrPending) {
devState = Device_Idle_SI;
intrPost();
}
if (isIENSet() || !intrPending) {
devState = Device_Idle_S;
}
}
break;
case Command_Execution:
if (action == ACT_CMD_COMPLETE) {
// clear the BSY bit
setComplete();
if (!isIENSet()) {
devState = Device_Idle_SI;
intrPost();
} else {
devState = Device_Idle_S;
}
}
break;
case Prepare_Data_In:
if (action == ACT_CMD_ERROR) {
// clear the BSY bit
setComplete();
if (!isIENSet()) {
devState = Device_Idle_SI;
intrPost();
} else {
devState = Device_Idle_S;
}
} else if (action == ACT_DATA_READY) {
// clear the BSY bit
cmdReg.status &= ~STATUS_BSY_BIT;
// set the DRQ bit
cmdReg.status |= STATUS_DRQ_BIT;
// put the first two bytes into the data register
memcpy((void *)&cmdReg.data0, (void *)dataBuffer, sizeof(uint16_t));
// copy the data into the data buffer
if (curCommand == WIN_IDENTIFY)
memcpy((void *)dataBuffer, (void *)&driveID,
sizeof(struct hd_driveid));
else
readDisk(curSector++, dataBuffer);
if (!isIENSet()) {
devState = Data_Ready_INTRQ_In;
intrPost();
} else {
devState = Transfer_Data_In;
}
}
break;
case Data_Ready_INTRQ_In:
if (action == ACT_STAT_READ) {
devState = Transfer_Data_In;
intrClear();
}
break;
case Transfer_Data_In:
if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
if (action == ACT_DATA_READ_BYTE) {
panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
} else {
drqBytesLeft -= 2;
cmdBytesLeft -= 2;
// copy next short into data registers
memcpy((void *)&cmdReg.data0,
(void *)&dataBuffer[SectorSize - drqBytesLeft],
sizeof(uint16_t));
}
if (drqBytesLeft == 0) {
if (cmdBytesLeft == 0) {
// Clear the BSY bit
setComplete();
devState = Device_Idle_S;
} else {
devState = Prepare_Data_In;
cmdReg.status |= STATUS_BSY_BIT;
}
}
}
break;
case Prepare_Data_Out:
if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
// clear the BSY bit
setComplete();
if (!isIENSet()) {
devState = Device_Idle_SI;
intrPost();
} else {
devState = Device_Idle_S;
}
} else if (cmdBytesLeft != 0) {
// clear the BSY bit
cmdReg.status &= ~STATUS_BSY_BIT;
// set the DRQ bit
cmdReg.status |= STATUS_DRQ_BIT;
// clear the data buffer to get it ready for writes
memset(dataBuffer, 0, MAX_DMA_SIZE);
if (!isIENSet()) {
devState = Data_Ready_INTRQ_Out;
intrPost();
} else {
devState = Transfer_Data_Out;
}
}
break;
case Data_Ready_INTRQ_Out:
if (action == ACT_STAT_READ) {
devState = Transfer_Data_Out;
intrClear();
}
break;
case Transfer_Data_Out:
if (action == ACT_DATA_WRITE_BYTE || action == ACT_DATA_WRITE_SHORT) {
if (action == ACT_DATA_READ_BYTE) {
panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
} else {
// copy the latest short into the data buffer
memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
(void *)&cmdReg.data0,
sizeof(uint16_t));
drqBytesLeft -= 2;
cmdBytesLeft -= 2;
}
if (drqBytesLeft == 0) {
// copy the block to the disk
writeDisk(curSector++, dataBuffer);
// set the BSY bit
cmdReg.status |= STATUS_BSY_BIT;
// clear the DRQ bit
cmdReg.status &= ~STATUS_DRQ_BIT;
devState = Prepare_Data_Out;
}
}
break;
case Prepare_Data_Dma:
if (action == ACT_CMD_ERROR) {
// clear the BSY bit
setComplete();
if (!isIENSet()) {
devState = Device_Idle_SI;
intrPost();
} else {
devState = Device_Idle_S;
}
} else if (action == ACT_DMA_READY) {
// clear the BSY bit
cmdReg.status &= ~STATUS_BSY_BIT;
// set the DRQ bit
cmdReg.status |= STATUS_DRQ_BIT;
devState = Transfer_Data_Dma;
if (dmaState != Dma_Idle)
panic("Inconsistent DMA state, should be Dma_Idle\n");
dmaState = Dma_Start;
// wait for the write to the DMA start bit
}
break;
case Transfer_Data_Dma:
if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
// clear the BSY bit
setComplete();
// set the seek bit
cmdReg.status |= 0x10;
// clear the controller state for DMA transfer
ctrl->setDmaComplete(this);
if (!isIENSet()) {
devState = Device_Idle_SI;
intrPost();
} else {
devState = Device_Idle_S;
}
}
break;
default:
panic("Unknown IDE device state: %#x\n", devState);
}
}
void
@ -70,6 +845,8 @@ IdeDisk::unserialize(Checkpoint *cp, const string &section)
BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
SimObjectParam<DiskImage *> image;
SimObjectParam<PhysicalMemory *> physmem;
Param<int> driveID;
Param<int> disk_delay;
END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
@ -77,6 +854,8 @@ END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
INIT_PARAM(image, "Disk image"),
INIT_PARAM(physmem, "Physical memory"),
INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0)
END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
@ -84,7 +863,7 @@ END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
CREATE_SIM_OBJECT(IdeDisk)
{
return new IdeDisk(getInstanceName(), image, disk_delay);
return new IdeDisk(getInstanceName(), image, physmem, driveID, disk_delay);
}
REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)

View file

@ -33,34 +33,203 @@
#ifndef __IDE_DISK_HH__
#define __IDE_DISK_HH__
#include "dev/ide.hh"
#include "dev/disk_image.hh"
#include "dev/io_device.hh"
#include "sim/eventq.hh"
class DiskImage;
#define DMA_BACKOFF_PERIOD 200
#define MAX_DMA_SIZE (16384)
#define MAX_MULTSECT (32)
#define PRD_BASE_MASK 0xfffffffe
#define PRD_COUNT_MASK 0xfffe
#define PRD_EOT_MASK 0x8000
typedef struct PrdEntry {
uint32_t baseAddr;
uint16_t byteCount;
uint16_t endOfTable;
} PrdEntry_t;
class PrdTableEntry {
public:
PrdEntry_t entry;
uint32_t getBaseAddr()
{
return (entry.baseAddr & PRD_BASE_MASK);
}
uint16_t getByteCount()
{
return ((entry.byteCount == 0) ? MAX_DMA_SIZE :
(entry.byteCount & PRD_COUNT_MASK));
}
uint16_t getEOT()
{
return (entry.endOfTable & PRD_EOT_MASK);
}
};
#define DATA_OFFSET (0)
#define ERROR_OFFSET (1)
#define FEATURES_OFFSET (1)
#define NSECTOR_OFFSET (2)
#define SECTOR_OFFSET (3)
#define LCYL_OFFSET (4)
#define HCYL_OFFSET (5)
#define SELECT_OFFSET (6)
#define STATUS_OFFSET (7)
#define COMMAND_OFFSET (7)
#define CONTROL_OFFSET (2)
#define ALTSTAT_OFFSET (2)
#define SELECT_DEV_BIT 0x10
#define CONTROL_RST_BIT 0x04
#define CONTROL_IEN_BIT 0x02
#define STATUS_BSY_BIT 0x80
#define STATUS_DRDY_BIT 0x40
#define STATUS_DRQ_BIT 0x08
#define DRIVE_LBA_BIT 0x40
#define DEV0 (0)
#define DEV1 (1)
typedef struct CommandReg {
uint8_t data0;
union {
uint8_t data1;
uint8_t error;
uint8_t features;
};
uint8_t sec_count;
uint8_t sec_num;
uint8_t cyl_low;
uint8_t cyl_high;
union {
uint8_t drive;
uint8_t head;
};
union {
uint8_t status;
uint8_t command;
};
} CommandReg_t;
typedef enum DevAction {
ACT_NONE = 0,
ACT_CMD_WRITE,
ACT_CMD_COMPLETE,
ACT_CMD_ERROR,
ACT_STAT_READ,
ACT_DATA_READY,
ACT_DATA_READ_BYTE,
ACT_DATA_READ_SHORT,
ACT_DATA_WRITE_BYTE,
ACT_DATA_WRITE_SHORT,
ACT_DMA_READY,
ACT_DMA_DONE
} DevAction_t;
typedef enum DevState {
// Device idle
Device_Idle_S = 0,
Device_Idle_SI,
Device_Idle_NS,
// Non-data commands
Command_Execution,
// PIO data-in (data to host)
Prepare_Data_In,
Data_Ready_INTRQ_In,
Transfer_Data_In,
// PIO data-out (data from host)
Prepare_Data_Out,
Data_Ready_INTRQ_Out,
Transfer_Data_Out,
// DMA protocol
Prepare_Data_Dma,
Transfer_Data_Dma
} DevState_t;
typedef enum DmaState {
Dma_Idle = 0,
Dma_Start,
Dma_Transfer
} DmaState_t;
class PhysicalMemory;
class IdeController;
/**
* SCSI Disk device model
* IDE Disk device model
*/
class IdeDisk : public SimObject
{
protected:
/** The IDE controller for this disk. */
IdeController *ctrl;
/** The DMA interface to use for transfers */
DMAInterface<Bus> *dmaInterface;
/** The image that contains the data of this disk. */
DiskImage *image;
/** Pointer to physical memory for DMA transfers */
PhysicalMemory *physmem;
protected:
/** The disk delay in milliseconds. */
int diskDelay;
private:
/** Drive identification structure for this disk */
struct hd_driveid driveID;
/** Data buffer for transfers */
uint8_t *dataBuffer;
/** Number of bytes left in command data transfer */
uint32_t cmdBytesLeft;
/** Number of bytes left in DRQ block */
uint32_t drqBytesLeft;
/** Current sector in access */
uint32_t curSector;
/** Command block registers */
CommandReg_t cmdReg;
/** Shadow of the current command code */
uint8_t curCommand;
/** Interrupt enable bit */
bool nIENBit;
/** Device state */
DevState_t devState;
/** Dma state */
DmaState_t dmaState;
/** Dma transaction is a read */
bool dmaRead;
/** PRD table base address */
uint32_t curPrdAddr;
/** PRD entry */
PrdTableEntry curPrd;
/** Device ID (master=0/slave=1) */
int devID;
/** Interrupt pending */
bool intrPending;
public:
/**
* Create and initialize this Disk.
* @param name The name of this disk.
* @param img The disk image of this disk.
* @param phys Pointer to physical memory
* @param id The disk ID (master=0/slave=1)
* @param disk_delay The disk delay in milliseconds
*/
IdeDisk(const std::string &name, DiskImage *img, int disk_delay);
IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys,
int id, int disk_delay);
/**
* Delete the data buffer.
@ -71,15 +240,78 @@ class IdeDisk : public SimObject
* Set the controller for this device
* @param c The IDE controller
*/
void setController(IdeController *c) {
void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) {
if (ctrl) panic("Cannot change the controller once set!\n");
ctrl = c;
dmaInterface = dmaIntr;
}
void startIO(uint8_t *cmdBlk, uint8_t *prdPtr) {};
// Device register read/write
void read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data);
void write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data);
void dmaStart() {};
void dmaStop() {};
// Start/abort functions
void startDma(const uint32_t &prdTableBase);
void abortDma();
private:
void startCommand();
// Interrupt management
void intrPost();
void intrClear();
// DMA stuff
void doDmaTransfer();
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
void doDmaRead();
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
void doDmaWrite();
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
void dmaPrdReadDone();
friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
void dmaReadDone();
friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
void dmaWriteDone();
friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
// Disk image read/write
void readDisk(uint32_t sector, uint8_t *data);
void writeDisk(uint32_t sector, uint8_t *data);
// State machine management
void updateState(DevAction_t action);
// Utility functions
bool isBSYSet() { return (cmdReg.status & STATUS_BSY_BIT); }
bool isIENSet() { return nIENBit; }
bool isDEVSelect() { return ((cmdReg.drive & SELECT_DEV_BIT) == devID); }
void setComplete()
{
// clear out the status byte
cmdReg.status = 0;
// set the DRDY bit
cmdReg.status |= STATUS_DRDY_BIT;
}
uint32_t getLBABase()
{
return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
(cmdReg.cyl_low << 8) | (cmdReg.sec_num));
}
/**
* Serialize this object to the given output stream.

View file

@ -39,23 +39,18 @@
#include "dev/scsi_ctrl.hh"
#include "dev/pciconfigall.hh"
#include "dev/pcidev.hh"
#include "dev/tsunamireg.h"
#include "dev/tsunami.hh"
#include "mem/functional_mem/memory_control.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
using namespace std;
PciConfigAll::PciConfigAll(const string &name, Tsunami *t, Addr a,
PciConfigAll::PciConfigAll(const string &name, Addr a,
MemoryController *mmu)
: FunctionalMemory(name), addr(a), tsunami(t)
: FunctionalMemory(name), addr(a)
{
mmu->add_child(this, Range<Addr>(addr, addr + size));
// Put back pointer in tsunami
tsunami->pciconfig = this;
// Make all the pointers to devices null
for(int x=0; x < MAX_PCI_DEV; x++)
for(int y=0; y < MAX_PCI_FUNC; y++)
@ -103,7 +98,7 @@ PciConfigAll::read(MemReqPtr &req, uint8_t *data)
}
}
DPRINTFN("Tsunami PCI Configspace ERROR: read daddr=%#x size=%d\n",
DPRINTFN("PCI Configspace ERROR: read daddr=%#x size=%d\n",
daddr, req->size);
return No_Fault;
@ -166,7 +161,6 @@ PciConfigAll::unserialize(Checkpoint *cp, const std::string &section)
BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
SimObjectParam<Tsunami *> tsunami;
SimObjectParam<MemoryController *> mmu;
Param<Addr> addr;
Param<Addr> mask;
@ -175,7 +169,6 @@ END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
INIT_PARAM(tsunami, "Tsunami"),
INIT_PARAM(mmu, "Memory Controller"),
INIT_PARAM(addr, "Device Address"),
INIT_PARAM(mask, "Address Mask")
@ -184,7 +177,7 @@ END_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
CREATE_SIM_OBJECT(PciConfigAll)
{
return new PciConfigAll(getInstanceName(), tsunami, addr, mmu);
return new PciConfigAll(getInstanceName(), addr, mmu);
}
REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll)

View file

@ -27,10 +27,6 @@
*/
/*
* @todo
* Should derive Tsunami from common platform class so PCI will work with
* multiple platforms
*
* @file
* PCI Config space implementation.
*/
@ -39,7 +35,6 @@
#define __PCICONFIGALL_HH__
#include "mem/functional_mem/functional_memory.hh"
#include "dev/tsunami.hh"
#include "dev/pcireg.h"
#define MAX_PCI_DEV 32
@ -60,15 +55,6 @@ class PciConfigAll : public FunctionalMemory
Addr addr;
static const Addr size = 0xffffff;
protected:
/**
* Pointer to the Tsunmi Object so we can communicate
* to other Tsunami devices in need be.
* @todo Make this more generic for multiple platforms
*/
Tsunami *tsunami;
public:
/**
* Pointers to all the devices that are registered with this
@ -79,8 +65,7 @@ class PciConfigAll : public FunctionalMemory
/**
* The default constructor.
*/
PciConfigAll(const std::string &name, Tsunami *t, Addr a,
MemoryController *mmu);
PciConfigAll(const std::string &name, Addr a, MemoryController *mmu);
virtual Fault read(MemReqPtr &req, uint8_t *data);
virtual Fault write(MemReqPtr &req, const uint8_t *data);

View file

@ -36,6 +36,7 @@
#include "sim/sim_object.hh"
class PciConfigAll;
class IntrControl;
class SimConsole;
@ -46,13 +47,15 @@ class Platform : public SimObject
IntrControl *intrctrl;
/** Pointer to the simulation console */
SimConsole *cons;
/** Pointer to the PCI configuration space */
PciConfigAll *pciconfig;
int interrupt_frequency;
public:
Platform(const std::string &name, SimConsole *con, IntrControl *intctrl,
int intrFreq)
: SimObject(name), intrctrl(intctrl), cons(con),
PciConfigAll *pci, int intrFreq)
: SimObject(name), intrctrl(intctrl), cons(con), pciconfig(pci),
interrupt_frequency(intrFreq) {}
};

View file

@ -38,14 +38,15 @@
#include "dev/tsunami_cchip.hh"
#include "dev/tsunami_pchip.hh"
#include "dev/tsunami.hh"
#include "dev/pciconfigall.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
using namespace std;
Tsunami::Tsunami(const string &name, System *s, SimConsole *con,
IntrControl *ic, int intr_freq)
: Platform(name, con, ic, intr_freq), system(s)
IntrControl *ic, PciConfigAll *pci, int intr_freq)
: Platform(name, con, ic, pci, intr_freq), system(s)
{
// set the back pointer from the system to myself
system->platform = this;
@ -71,6 +72,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami)
SimObjectParam<System *> system;
SimObjectParam<SimConsole *> cons;
SimObjectParam<IntrControl *> intrctrl;
SimObjectParam<PciConfigAll *> pciconfig;
Param<int> interrupt_frequency;
END_DECLARE_SIM_OBJECT_PARAMS(Tsunami)
@ -80,13 +82,14 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami)
INIT_PARAM(system, "system"),
INIT_PARAM(cons, "system console"),
INIT_PARAM(intrctrl, "interrupt controller"),
INIT_PARAM(pciconfig, "PCI configuration"),
INIT_PARAM_DFLT(interrupt_frequency, "frequency of interrupts", 1024)
END_INIT_SIM_OBJECT_PARAMS(Tsunami)
CREATE_SIM_OBJECT(Tsunami)
{
return new Tsunami(getInstanceName(), system, cons, intrctrl,
return new Tsunami(getInstanceName(), system, cons, intrctrl, pciconfig,
interrupt_frequency);
}

View file

@ -81,12 +81,6 @@ class Tsunami : public Platform
*/
TsunamiPChip *pchip;
/** Pointer to the PCI Config Space
* The config space in Tsunami all needs to return
* -1 if a device is not there.
*/
PciConfigAll *pciconfig;
int intr_sum_type[Tsunami::Max_CPUs];
int ipi_pending[Tsunami::Max_CPUs];
@ -99,7 +93,8 @@ class Tsunami : public Platform
* @param intrFreq frequency that interrupts happen
*/
Tsunami(const std::string &name, System *s, SimConsole *con,
IntrControl *intctrl, int intrFreq);
IntrControl *intctrl, PciConfigAll *pci,
int intrFreq);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);