Merge zizzer:/bk/linux

into zower.eecs.umich.edu:/.automount/zizzer/z/alschult/DiskModel/linux

--HG--
extra : convert_revision : 8eca0fba9d96bffea7a24bce9b14f0284bd58c83
This commit is contained in:
Andrew Schultz 2004-05-03 11:48:17 -04:00
commit 8538ffdb36
9 changed files with 1294 additions and 236 deletions

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);