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:
commit
8538ffdb36
9 changed files with 1294 additions and 236 deletions
195
dev/ide_ctrl.cc
195
dev/ide_ctrl.cc
|
@ -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 *)®s[BMI + BMIS0] = 0x60;
|
||||
*(uint8_t *)®s[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 *)®s[offset]);
|
||||
if (type != BMI_BLOCK) {
|
||||
assert(req->size != sizeof(uint32_t));
|
||||
|
||||
// copy the data from the control registers
|
||||
memcpy((void *)data, ®s[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,28 +373,52 @@ 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 (BMI + BMIC1):
|
||||
case (BMI + BMIC0):
|
||||
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(offset);
|
||||
disk = getDisk(primary);
|
||||
|
||||
oldVal = regs[offset];
|
||||
oldVal = bmi_regs[offset];
|
||||
newVal = *data;
|
||||
|
||||
// if a DMA transfer is in progress, R/W control cannot change
|
||||
|
@ -349,40 +435,44 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
|||
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
|
||||
|
||||
// clear the BMIDEA bit
|
||||
regs[offset + 0x2] &= ~BMIDEA;
|
||||
bmi_regs[offset + 0x2] &= ~BMIDEA;
|
||||
|
||||
if (disks[disk] == NULL)
|
||||
panic("DMA stop for disk %d which does not exist\n", disk);
|
||||
panic("DMA stop for disk %d which does not exist\n",
|
||||
disk);
|
||||
|
||||
// inform the disk of the DMA transfer abort
|
||||
disks[disk]->dmaStop();
|
||||
disks[disk]->abortDma();
|
||||
} else {
|
||||
// starting DMA transfer
|
||||
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
|
||||
|
||||
// set the BMIDEA bit
|
||||
regs[offset + 0x2] |= BMIDEA;
|
||||
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
|
||||
disks[disk]->dmaStart();
|
||||
if (primary)
|
||||
disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP0]);
|
||||
else
|
||||
disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP1]);
|
||||
}
|
||||
}
|
||||
|
||||
// update the register value
|
||||
regs[offset] = newVal;
|
||||
bmi_regs[offset] = newVal;
|
||||
break;
|
||||
|
||||
// Bus master IDE status register
|
||||
case (BMI + BMIS0):
|
||||
case (BMI + BMIS1):
|
||||
case BMIS0:
|
||||
case BMIS1:
|
||||
if (req->size != sizeof(uint8_t))
|
||||
panic("Invalid BMIS write size: %x\n", req->size);
|
||||
|
||||
oldVal = regs[offset];
|
||||
oldVal = bmi_regs[offset];
|
||||
newVal = *data;
|
||||
|
||||
// the BMIDEA bit is RO
|
||||
|
@ -399,65 +489,28 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
|||
else
|
||||
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
|
||||
|
||||
regs[offset] = newVal;
|
||||
bmi_regs[offset] = newVal;
|
||||
break;
|
||||
|
||||
// Bus master IDE descriptor table pointer register
|
||||
case (BMI + BMIDTP0):
|
||||
case (BMI + BMIDTP1):
|
||||
case BMIDTP0:
|
||||
case BMIDTP1:
|
||||
if (req->size != sizeof(uint32_t))
|
||||
panic("Invalid BMIDTP write size: %x\n", req->size);
|
||||
|
||||
*(uint32_t *)®s[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(®s[CMD0], ®s[BMI + BMIDTP0]);
|
||||
else
|
||||
disks[disk]->startIO(®s[CMD1], ®s[BMI + BMIDTP1]);
|
||||
|
||||
*(uint32_t *)&bmi_regs[offset] = *(uint32_t *)data & ~0x3;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (req->size != sizeof(uint8_t) && req->size != sizeof(uint16_t) &&
|
||||
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 *)®s[offset], data, req->size);
|
||||
memcpy((void *)&bmi_regs[offset], data, req->size);
|
||||
}
|
||||
}
|
||||
|
||||
return No_Fault;
|
||||
|
|
|
@ -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.
|
||||
|
|
787
dev/ide_disk.cc
787
dev/ide_disk.cc
|
@ -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 §ion)
|
|||
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)
|
||||
|
|
246
dev/ide_disk.hh
246
dev/ide_disk.hh
|
@ -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.
|
||||
|
|
|
@ -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 §ion)
|
|||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 §ion);
|
||||
|
|
Loading…
Reference in a new issue