bmi_size = BARSize[4];
// zero out all of the registers
- memset(bmi_regs, 0, sizeof(bmi_regs));
+ memset(bmi_regs.data, 0, sizeof(bmi_regs));
memset(pci_config_regs.data, 0, sizeof(pci_config_regs.data));
// setup initial values
pci_config_regs.idetim = htoa((uint32_t)0x80008000); // enable both channels
- *(uint8_t *)&bmi_regs[BMIS0] = 0x60;
- *(uint8_t *)&bmi_regs[BMIS1] = 0x60;
+ bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
+ bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
// reset all internal variables
io_enabled = false;
if (diskNum < 2) {
// clear the start/stop bit in the command register
- bmi_regs[BMIC0] &= ~SSBM;
+ bmi_regs.bmic0 &= ~SSBM;
// clear the bus master active bit in the status register
- bmi_regs[BMIS0] &= ~BMIDEA;
+ bmi_regs.bmis0 &= ~BMIDEA;
// set the interrupt bit
- bmi_regs[BMIS0] |= IDEINTS;
+ bmi_regs.bmis0 |= IDEINTS;
} else {
// clear the start/stop bit in the command register
- bmi_regs[BMIC1] &= ~SSBM;
+ bmi_regs.bmic1 &= ~SSBM;
// clear the bus master active bit in the status register
- bmi_regs[BMIS1] &= ~BMIDEA;
+ bmi_regs.bmis1 &= ~BMIDEA;
// set the interrupt bit
- bmi_regs[BMIS1] |= IDEINTS;
+ bmi_regs.bmis1 |= IDEINTS;
}
}
void
IdeController::ReadConfig(int offset, int size, uint8_t *data)
{
- int config_offset;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ };
-#if TRACING_ON
- Addr origOffset = offset;
-#endif
+ int config_offset;
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::ReadConfig(offset, size, data);
- } else if (offset >= IDE_CTRL_CONFIG_START && (offset + size) <= IDE_CTRL_CONFIG_END) {
+ } else if (offset >= IDE_CTRL_CONFIG_START &&
+ (offset + size) <= IDE_CTRL_CONFIG_END) {
config_offset = offset - IDE_CTRL_CONFIG_START;
+ dword = 0;
- switch(size) {
- case sizeof(uint32_t):
- memcpy(data, &pci_config_regs.data[config_offset], sizeof(uint32_t));
- *(uint32_t*)data = htoa(*(uint32_t*)data);
+ switch (size) {
+ case sizeof(uint8_t):
+ memcpy(&byte, &pci_config_regs.data[config_offset], size);
+ *data = byte;
break;
-
case sizeof(uint16_t):
- memcpy(data, &pci_config_regs.data[config_offset], sizeof(uint16_t));
- *(uint16_t*)data = htoa(*(uint16_t*)data);
+ memcpy(&byte, &pci_config_regs.data[config_offset], size);
+ *(uint16_t*)data = htoa(word);
break;
-
- case sizeof(uint8_t):
- memcpy(data, &pci_config_regs.data[config_offset], sizeof(uint8_t));
+ case sizeof(uint32_t):
+ memcpy(&byte, &pci_config_regs.data[config_offset], size);
+ *(uint32_t*)data = htoa(dword);
break;
-
default:
panic("Invalid PCI configuration read size!\n");
}
+
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n",
+ offset, size, htoa(dword));
+
} else {
panic("Read of unimplemented PCI config. register: %x\n", offset);
}
-
- DPRINTF(IdeCtrl, "PCI read offset: %#x (%#x) size: %#x data: %#x\n",
- origOffset, offset, size,
- *(uint32_t *)data & (0xffffffff >> 8 * (4 - size)));
}
void
IdeController::WriteConfig(int offset, int size, uint32_t data)
{
int config_offset;
+ uint32_t write_data;
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::WriteConfig(offset, size, data);
- } else if (offset >= IDE_CTRL_CONFIG_START && (offset + size) <= IDE_CTRL_CONFIG_END) {
+ } else if (offset >= IDE_CTRL_CONFIG_START &&
+ (offset + size) <= IDE_CTRL_CONFIG_END) {
config_offset = offset - IDE_CTRL_CONFIG_START;
+ write_data = htoa(data);
+
switch(size) {
- case sizeof(uint32_t):
- case sizeof(uint16_t):
case sizeof(uint8_t):
- memcpy(&pci_config_regs.data[config_offset], &data, size);
+ case sizeof(uint16_t):
+ case sizeof(uint32_t):
+ memcpy(&pci_config_regs.data[config_offset], &write_data, size);
break;
default:
panic("Invalid PCI configuration write size!\n");
}
-
} else {
panic("Write of unimplemented PCI config. register: %x\n", offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: %#x data: %#x\n",
- offset, size, data & (0xffffffff >> 8 * (4 - size)));
-
+ offset, size, data);
// Catch the writes to specific PCI registers that have side affects
// (like updating the PIO ranges)
RegType_t type;
int disk;
+ /* union
+ * +-- --+-- --+-- --+-- --+
+ * | 0 | 1 | 2 | 3 |
+ * +-- --+-- --+-- --+-- --+
+ * | byte | .. | .. | .. |
+ * +-- --+-- --+-- --+-- --+
+ * | word0 | word1 |
+ * +-- --+-- --+
+ * | dword |
+ * +-- --+
+ */
+ union {
+ uint8_t byte;
+ uint16_t word[2];
+ uint32_t dword;
+ };
+
+ dword = 0;
+
parseAddr(req->paddr, offset, primary, type);
if (!io_enabled)
return No_Fault;
- // sanity check the size (allows byte, word, or dword access)
- switch (req->size) {
- case sizeof(uint8_t):
- case sizeof(uint16_t):
- case sizeof(uint32_t):
+ switch (type) {
+ case BMI_BLOCK:
+ switch (req->size) {
+ case sizeof(uint8_t):
+ memcpy(&byte, &bmi_regs.data[offset], sizeof(uint8_t));
+ *data = byte;
+ break;
+ case sizeof(uint16_t):
+ memcpy(&byte, &bmi_regs.data[offset], sizeof(uint16_t));
+ *(uint16_t*)data = htoa(word[0]);
+ break;
+ case sizeof(uint32_t):
+ memcpy(&byte, &bmi_regs.data[offset], sizeof(uint32_t));
+ *(uint32_t*)data = htoa(dword);
+ break;
+ default:
+ panic("IDE read of BMI reg invalid size: %#x\n", req->size);
+ }
break;
- default:
- panic("IDE controller read of invalid size: %#x\n", req->size);
- }
-
- if (type != BMI_BLOCK) {
+ case COMMAND_BLOCK:
+ case CONTROL_BLOCK:
disk = getDisk(primary);
- if (disks[disk])
- if (req->size == sizeof(uint32_t) && offset == DATA_OFFSET) {
- ((uint16_t*)data)[0] = disks[disk]->read(offset, type);
- ((uint16_t*)data)[1] = disks[disk]->read(offset, type);
- }
- else if (req->size == sizeof(uint8_t) && offset == DATA_OFFSET) {
+
+ if (disks[disk] == NULL)
+ break;
+
+ switch (offset) {
+ case DATA_OFFSET:
+ switch (req->size) {
+ case sizeof(uint16_t):
+ disks[disk]->read(offset, type, (uint8_t*)&word[0]);
+ *(uint16_t*)data = htoa(word[0]);
+ break;
+
+ case sizeof(uint32_t):
+ disks[disk]->read(offset, type, (uint8_t*)&word[0]);
+ disks[disk]->read(offset, type, (uint8_t*)&word[1]);
+ *(uint32_t*)data = htoa(dword);
+ break;
+
+ default:
panic("IDE read of data reg invalid size: %#x\n", req->size);
}
- else {
- *data = disks[disk]->read(offset, type);
- }
- } else {
- memcpy((void *)data, &bmi_regs[offset], req->size);
+ break;
+ default:
+ if (req->size == sizeof(uint8_t)) {
+ disks[disk]->read(offset, type, &byte);
+ *data = byte;
+ } else
+ panic("IDE read of command reg of invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ panic("IDE controller read of unknown register block type!\n");
}
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
- offset, req->size,
- (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - req->size)));
+ offset, req->size, htoa(dword));
return No_Fault;
}
{
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;
+ union {
+ uint8_t byte;
+ uint16_t word[2];
+ uint32_t dword;
+ };
- DPRINTF(IdeCtrl, "write from offset: %#x size: %#x data: %#x\n",
- offset, req->size,
- (*(uint32_t *)data) & (0xffffffff >> 8 * (4 - req->size)));
+ dword = 0;
+
+ parseAddr(req->paddr, offset, primary, type);
uint8_t oldVal, newVal;
if (!io_enabled)
return No_Fault;
- if (type == BMI_BLOCK && !bm_enabled)
- return No_Fault;
+ switch (type) {
+ case BMI_BLOCK:
+ if (!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 BMIC1:
// select the current disk based on DEV bit
disk = getDisk(primary);
- oldVal = bmi_regs[offset];
- newVal = *data;
+ oldVal = bmi_regs.data[offset];
+ byte = *data;
+ newVal = byte;
// if a DMA transfer is in progress, R/W control cannot change
if (oldVal & SSBM) {
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
// clear the BMIDEA bit
- bmi_regs[offset + 0x2] &= ~BMIDEA;
+ bmi_regs.data[offset + 0x2] &= ~BMIDEA;
if (disks[disk] == NULL)
panic("DMA stop for disk %d which does not exist\n",
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
// set the BMIDEA bit
- bmi_regs[offset + 0x2] |= BMIDEA;
+ bmi_regs.data[offset + 0x2] |= BMIDEA;
if (disks[disk] == NULL)
panic("DMA start for disk %d which does not exist\n",
// inform the disk of the DMA transfer start
if (primary)
- disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP0]);
+ disks[disk]->startDma(bmi_regs.bmidtp0);
else
- disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP1]);
+ disks[disk]->startDma(bmi_regs.bmidtp1);
}
}
// update the register value
- bmi_regs[offset] = newVal;
+ bmi_regs.data[offset] = newVal;
break;
// Bus master IDE status register
if (req->size != sizeof(uint8_t))
panic("Invalid BMIS write size: %x\n", req->size);
- oldVal = bmi_regs[offset];
- newVal = *data;
+ oldVal = bmi_regs.data[offset];
+ byte = *data;
+ newVal = byte;
// the BMIDEA bit is RO
newVal |= (oldVal & BMIDEA);
else
(oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
- bmi_regs[offset] = newVal;
+ bmi_regs.data[offset] = newVal;
break;
// Bus master IDE descriptor table pointer register
if (req->size != sizeof(uint32_t))
panic("Invalid BMIDTP write size: %x\n", req->size);
- *(uint32_t *)&bmi_regs[offset] = *(uint32_t *)data & ~0x3;
+ dword = htoa(*(uint32_t *)data & ~0x3);
+ *(uint32_t *)&bmi_regs.data[offset] = dword;
break;
default:
req->size);
// do a default copy of data into the registers
- memcpy((void *)&bmi_regs[offset], data, req->size);
+ memcpy((void *)&bmi_regs.data[offset], data, req->size);
+ }
+ break;
+ case COMMAND_BLOCK:
+ if (offset == IDE_SELECT_OFFSET) {
+ uint8_t *devBit = (primary ? &dev[0] : &dev[1]);
+ *devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0);
}
+ // fall-through ok!
+ case CONTROL_BLOCK:
+ disk = getDisk(primary);
+
+ if (disks[disk] == NULL)
+ break;
+
+ switch (offset) {
+ case DATA_OFFSET:
+ switch (req->size) {
+ case sizeof(uint16_t):
+ word[0] = htoa(*(uint16_t*)data);
+ disks[disk]->write(offset, type, (uint8_t*)&word[0]);
+ break;
+
+ case sizeof(uint32_t):
+ dword = htoa(*(uint32_t*)data);
+ disks[disk]->write(offset, type, (uint8_t*)&word[0]);
+ disks[disk]->write(offset, type, (uint8_t*)&word[1]);
+ break;
+ default:
+ panic("IDE write of data reg invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ if (req->size == sizeof(uint8_t)) {
+ byte = *data;
+ disks[disk]->write(offset, type, &byte);
+ } else
+ panic("IDE write of command reg of invalid size: %#x\n", req->size);
+ }
+ break;
+ default:
+ panic("IDE controller write of unknown register block type!\n");
}
+ DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
+ offset, req->size, dword);
+
return No_Fault;
}
SERIALIZE_SCALAR(bmi_size);
// Serialize registers
- SERIALIZE_ARRAY(bmi_regs, 16);
- SERIALIZE_ARRAY(dev, 2);
- SERIALIZE_ARRAY(pci_config_regs.data, 22);
+ SERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
+ SERIALIZE_ARRAY(dev, sizeof(dev));
+ SERIALIZE_ARRAY(pci_config_regs.data, sizeof(pci_config_regs));
// Serialize internal state
SERIALIZE_SCALAR(io_enabled);
SERIALIZE_SCALAR(bm_enabled);
- SERIALIZE_ARRAY(cmd_in_progress, 4);
+ SERIALIZE_ARRAY(cmd_in_progress, sizeof(cmd_in_progress));
}
void
UNSERIALIZE_SCALAR(bmi_size);
// Unserialize registers
- UNSERIALIZE_ARRAY(bmi_regs, 16);
- UNSERIALIZE_ARRAY(dev, 2);
- UNSERIALIZE_ARRAY(pci_config_regs.data, 22);
+ UNSERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
+ UNSERIALIZE_ARRAY(dev, sizeof(dev));
+ UNSERIALIZE_ARRAY(pci_config_regs.data, sizeof(pci_config_regs));
// Unserialize internal state
UNSERIALIZE_SCALAR(io_enabled);
UNSERIALIZE_SCALAR(bm_enabled);
- UNSERIALIZE_ARRAY(cmd_in_progress, 4);
+ UNSERIALIZE_ARRAY(cmd_in_progress, sizeof(cmd_in_progress));
if (pioInterface) {
pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size));
driveID.atap_udmamode_supp = 0x10;
// Statically set hardware config word
driveID.atap_hwreset_res = 0x4001;
+
+ //arbitrary for now...
+ driveID.atap_ata_major = WDC_VER_ATA7;
}
IdeDisk::~IdeDisk()
memset(&cmdReg, 0, sizeof(CommandReg_t));
memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
- cmdReg.error = 1;
-
dmaInterfaceBytes = 0;
curPrdAddr = 0;
curSector = 0;
// set the device ready bit
status = STATUS_DRDY_BIT;
+
+ cmdReg.error = 0x1;
}
////
// Device registers read/write
////
-uint16_t
-IdeDisk::read(const Addr &offset, RegType_t type)
+void
+IdeDisk::read(const Addr &offset, RegType_t type, uint8_t *data)
{
- uint16_t data = 0;
DevAction_t action = ACT_NONE;
- if (type == COMMAND_BLOCK) {
-
- if (offset == STATUS_OFFSET)
- action = ACT_STAT_READ;
- else if (offset == DATA_OFFSET)
- action = ACT_DATA_READ_SHORT;
-
+ switch (type) {
+ case COMMAND_BLOCK:
switch (offset) {
+ // Data transfers occur two bytes at a time
case DATA_OFFSET:
- data = cmdReg.data;
+ memcpy(data, &cmdReg.data, sizeof(uint16_t));
+ action = ACT_DATA_READ_SHORT;
break;
case ERROR_OFFSET:
- data = cmdReg.error;
+ *data = cmdReg.error;
break;
case NSECTOR_OFFSET:
- data = cmdReg.sec_count;
+ *data = cmdReg.sec_count;
break;
case SECTOR_OFFSET:
- data = cmdReg.sec_num;
+ *data = cmdReg.sec_num;
break;
case LCYL_OFFSET:
- data = cmdReg.cyl_low;
+ *data = cmdReg.cyl_low;
break;
case HCYL_OFFSET:
- data = cmdReg.cyl_high;
+ *data = cmdReg.cyl_high;
break;
- case SELECT_OFFSET:
- data = cmdReg.drive;
+ case DRIVE_OFFSET:
+ *data = cmdReg.drive;
break;
case STATUS_OFFSET:
- data = status;
+ *data = status;
+ action = ACT_STAT_READ;
break;
default:
panic("Invalid IDE command register offset: %#x\n", offset);
}
- }
- else if (type == CONTROL_BLOCK) {
- if (offset != ALTSTAT_OFFSET)
+ break;
+ case CONTROL_BLOCK:
+ if (offset == ALTSTAT_OFFSET)
+ *data = status;
+ else
panic("Invalid IDE control register offset: %#x\n", offset);
-
- data = status;
+ break;
+ default:
+ panic("Unknown register block!\n");
}
if (action != ACT_NONE)
updateState(action);
-
- return data;
}
void
-IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data)
+IdeDisk::write(const Addr &offset, RegType_t type, 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.data) = *(uint16_t *)data;
- else {
- switch (offset) {
- case DATA_OFFSET:
- cmdReg.data = *data;
- break;
- case FEATURES_OFFSET:
- cmdReg.features = *data;
- break;
- case NSECTOR_OFFSET:
- cmdReg.sec_count = *data;
- break;
- case SECTOR_OFFSET:
- cmdReg.sec_num = *data;
- break;
- case LCYL_OFFSET:
- cmdReg.cyl_low = *data;
- break;
- case HCYL_OFFSET:
- cmdReg.cyl_high = *data;
- break;
- case SELECT_OFFSET:
- cmdReg.drive = *data;
- break;
- case COMMAND_OFFSET:
- cmdReg.command = *data;
- break;
- default:
- panic("Invalid IDE command register offset: %#x\n", offset);
- }
- }
-
- // 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 == SELECT_OFFSET) {
+ switch (type) {
+ case COMMAND_BLOCK:
+ switch (offset) {
+ case DATA_OFFSET:
+ memcpy(&cmdReg.data, data, sizeof(uint16_t));
+ action = ACT_DATA_WRITE_SHORT;
+ break;
+ case FEATURES_OFFSET:
+ break;
+ case NSECTOR_OFFSET:
+ cmdReg.sec_count = *data;
+ break;
+ case SECTOR_OFFSET:
+ cmdReg.sec_num = *data;
+ break;
+ case LCYL_OFFSET:
+ cmdReg.cyl_low = *data;
+ break;
+ case HCYL_OFFSET:
+ cmdReg.cyl_high = *data;
+ break;
+ case DRIVE_OFFSET:
+ cmdReg.drive = *data;
action = ACT_SELECT_WRITE;
+ break;
+ case COMMAND_OFFSET:
+ cmdReg.command = *data;
+ action = ACT_CMD_WRITE;
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
-
- } 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) {
- // force the device into the reset state
- devState = Device_Srst;
- action = ACT_SRST_SET;
- } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
- action = ACT_SRST_CLEAR;
+ break;
+ case CONTROL_BLOCK:
+ if (offset == CONTROL_OFFSET) {
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ action = ACT_SRST_SET;
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
+ action = ACT_SRST_CLEAR;
+
+ nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
}
-
- nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
+ else
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ break;
+ default:
+ panic("Unknown register block!\n");
}
if (action != ACT_NONE)
intrPending = true;
// talk to controller to set interrupt
- if (ctrl){
- ctrl->bmi_regs[BMIS0] |= IDEINTS;
+ if (ctrl) {
+ ctrl->bmi_regs.bmis0 |= IDEINTS;
ctrl->intrPost();
}
}