make ide disk work for newmem
SConscript: compile ide devices base/chunk_generator.hh: add another parameter to the chuck generator called complete() which returns the number of bytes transfered so far. Very useful for adding to a pointer. configs/test/fs.py: Add ide disk to fs test configuration dev/ide_ctrl.cc: dev/ide_ctrl.hh: dev/ide_disk.cc: dev/ide_disk.hh: dev/io_device.cc: dev/io_device.hh: dev/pciconfigall.cc: dev/pciconfigall.hh: dev/pcidev.cc: dev/pcidev.hh: update for new memory system mem/bus.cc: support devices that return multiple ranges remove old ranges before using new info mem/packet.hh: make senderstate void* per steve's request that we use every construct possible in C++ mem/physical.cc: have memory stamp the packet with the time. mem/physical.hh: actually set the memory latency variable python/m5/objects/Device.py: Add DmaDevice python/m5/objects/Ide.py: Ide disk no longer has a physmem pointer python/m5/objects/Pci.py: update pci device for newmem python/m5/objects/PhysicalMemory.py: add latency parameter for physical memory sim/byteswap.hh: use fast architecture dependent byteswap calls if they exist --HG-- extra : convert_revision : e3cf2e8f61064ad302d94bc22010a00c59f3f793
This commit is contained in:
parent
9a41591693
commit
6dc3b2fa39
22 changed files with 742 additions and 794 deletions
|
@ -186,9 +186,12 @@ full_system_sources = Split('''
|
|||
dev/alpha_console.cc
|
||||
dev/baddev.cc
|
||||
dev/disk_image.cc
|
||||
dev/ide_ctrl.cc
|
||||
dev/ide_disk.cc
|
||||
dev/io_device.cc
|
||||
dev/isa_fake.cc
|
||||
dev/pciconfigall.cc
|
||||
dev/pcidev.cc
|
||||
dev/platform.cc
|
||||
dev/simconsole.cc
|
||||
dev/simple_disk.cc
|
||||
|
@ -219,10 +222,7 @@ full_system_sources = Split('''
|
|||
# dev/etherlink.cc
|
||||
# dev/etherpkt.cc
|
||||
# dev/ethertap.cc
|
||||
# dev/ide_ctrl.cc
|
||||
# dev/ide_disk.cc
|
||||
# dev/ns_gige.cc
|
||||
# dev/pcidev.cc
|
||||
# dev/pcifake.cc
|
||||
# dev/pktfifo.cc
|
||||
# dev/sinic.cc
|
||||
|
|
|
@ -62,6 +62,8 @@ class ChunkGenerator
|
|||
int curSize;
|
||||
/** The number of bytes remaining in the region after the current chunk. */
|
||||
int sizeLeft;
|
||||
/** The start address so we can calculate offset in writing block. */
|
||||
const Addr startAddr;
|
||||
/** The maximum chunk size, e.g., the cache block size or page size. */
|
||||
const int chunkSize;
|
||||
|
||||
|
@ -73,8 +75,8 @@ class ChunkGenerator
|
|||
* @param _chunkSize The size/alignment of chunks into which
|
||||
* the region should be decomposed.
|
||||
*/
|
||||
ChunkGenerator(Addr startAddr, int totalSize, int _chunkSize)
|
||||
: chunkSize(_chunkSize)
|
||||
ChunkGenerator(Addr _startAddr, int totalSize, int _chunkSize)
|
||||
: startAddr(_startAddr), chunkSize(_chunkSize)
|
||||
{
|
||||
// chunkSize must be a power of two
|
||||
assert(chunkSize == 0 || isPowerOf2(chunkSize));
|
||||
|
@ -107,6 +109,8 @@ class ChunkGenerator
|
|||
/** Return size in bytes of current chunk. */
|
||||
int size() { return curSize; }
|
||||
|
||||
/** Number of bytes we have already chunked up. */
|
||||
int complete() { return curAddr - startAddr; }
|
||||
/**
|
||||
* Are we done? That is, did the last call to next() advance
|
||||
* past the end of the region?
|
||||
|
|
|
@ -1,9 +1,50 @@
|
|||
from m5 import *
|
||||
import os
|
||||
from SysPaths import *
|
||||
|
||||
# Base for tests is directory containing this file.
|
||||
test_base = os.path.dirname(__file__)
|
||||
|
||||
linux_image = env.get('LINUX_IMAGE', disk('linux-latest.img'))
|
||||
|
||||
class IdeControllerPciData(PciConfigData):
|
||||
VendorID = 0x8086
|
||||
DeviceID = 0x7111
|
||||
Command = 0x0
|
||||
Status = 0x280
|
||||
Revision = 0x0
|
||||
ClassCode = 0x01
|
||||
SubClassCode = 0x01
|
||||
ProgIF = 0x85
|
||||
BAR0 = 0x00000001
|
||||
BAR1 = 0x00000001
|
||||
BAR2 = 0x00000001
|
||||
BAR3 = 0x00000001
|
||||
BAR4 = 0x00000001
|
||||
BAR5 = 0x00000001
|
||||
InterruptLine = 0x1f
|
||||
InterruptPin = 0x01
|
||||
BAR0Size = '8B'
|
||||
BAR1Size = '4B'
|
||||
BAR2Size = '8B'
|
||||
BAR3Size = '4B'
|
||||
BAR4Size = '16B'
|
||||
|
||||
|
||||
class LinuxRootDisk(IdeDisk):
|
||||
raw_image = RawDiskImage(image_file=linux_image, read_only=True)
|
||||
image = CowDiskImage(child=Parent.raw_image, read_only=False)
|
||||
|
||||
class LinuxSwapDisk(IdeDisk):
|
||||
raw_image = RawDiskImage(image_file = disk('linux-bigswap2.img'),
|
||||
read_only=True)
|
||||
image = CowDiskImage(child = Parent.raw_image, read_only=False)
|
||||
|
||||
class SpecwebFilesetDisk(IdeDisk):
|
||||
raw_image = RawDiskImage(image_file = disk('specweb-fileset.img'),
|
||||
read_only=True)
|
||||
image = CowDiskImage(child = Parent.raw_image, read_only=False)
|
||||
|
||||
class BaseTsunami(Tsunami):
|
||||
cchip = TsunamiCChip(pio_addr=0x801a0000000)
|
||||
pchip = TsunamiPChip(pio_addr=0x80180000000)
|
||||
|
@ -48,17 +89,19 @@ class BaseTsunami(Tsunami):
|
|||
# configdata=IdeControllerPciData(),
|
||||
# pci_func=0, pci_dev=0, pci_bus=0)
|
||||
|
||||
#class LinuxTsunami(BaseTsunami):
|
||||
# disk0 = LinuxRootDisk(delay='0us', driveID='master')
|
||||
# ide = IdeController(disks=[Parent.disk0],
|
||||
# configdata=IdeControllerPciData(),
|
||||
# pci_func=0, pci_dev=0, pci_bus=0)
|
||||
class LinuxTsunami(BaseTsunami):
|
||||
disk0 = LinuxRootDisk(driveID='master')
|
||||
disk1 = SpecwebFilesetDisk(driveID='slave')
|
||||
disk2 = LinuxSwapDisk(driveID='master')
|
||||
ide = IdeController(disks=[Parent.disk0, Parent.disk1, Parent.disk2],
|
||||
configdata=IdeControllerPciData(),
|
||||
pci_func=0, pci_dev=0, pci_bus=0)
|
||||
|
||||
class LinuxAlphaSystem(LinuxAlphaSystem):
|
||||
magicbus = Bus()
|
||||
physmem = PhysicalMemory(range = AddrRange('128MB'))
|
||||
c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus)
|
||||
tsunami = BaseTsunami()
|
||||
tsunami = LinuxTsunami()
|
||||
c2 = Connector(side_a=Parent.tsunami.cchip, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c3 = Connector(side_a=Parent.tsunami.pchip, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c4 = Connector(side_a=Parent.tsunami.pciconfig, side_a_name='pio', side_b=Parent.magicbus)
|
||||
|
@ -67,6 +110,8 @@ class LinuxAlphaSystem(LinuxAlphaSystem):
|
|||
c8 = Connector(side_a=Parent.tsunami.fake_uart2, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c9 = Connector(side_a=Parent.tsunami.fake_uart3, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c10 = Connector(side_a=Parent.tsunami.fake_uart4, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c11 = Connector(side_a=Parent.tsunami.ide, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c13 = Connector(side_a=Parent.tsunami.ide, side_a_name='dma', side_b=Parent.magicbus)
|
||||
c12 = Connector(side_a=Parent.tsunami.fake_ppc, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c14 = Connector(side_a=Parent.tsunami.fake_OROM, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c16 = Connector(side_a=Parent.tsunami.fake_pnp_addr, side_a_name='pio', side_b=Parent.magicbus)
|
||||
|
@ -85,7 +130,7 @@ class LinuxAlphaSystem(LinuxAlphaSystem):
|
|||
c31 = Connector(side_a=Parent.tsunami.io, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c32 = Connector(side_a=Parent.tsunami.uart, side_a_name='pio', side_b=Parent.magicbus)
|
||||
c33 = Connector(side_a=Parent.tsunami.console, side_a_name='pio', side_b=Parent.magicbus)
|
||||
raw_image = RawDiskImage(image_file=disk('linux.img'),
|
||||
raw_image = RawDiskImage(image_file=disk('linux-latest.img'),
|
||||
read_only=True)
|
||||
simple_disk = SimpleDisk(disk=Parent.raw_image)
|
||||
intrctrl = IntrControl()
|
||||
|
|
455
dev/ide_ctrl.cc
455
dev/ide_ctrl.cc
|
@ -31,7 +31,6 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "arch/alpha/ev5.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "cpu/intr_control.hh"
|
||||
#include "dev/ide_ctrl.hh"
|
||||
|
@ -39,17 +38,12 @@
|
|||
#include "dev/pciconfigall.hh"
|
||||
#include "dev/pcireg.h"
|
||||
#include "dev/platform.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 "mem/functional/memory_control.hh"
|
||||
#include "mem/functional/physical.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
////
|
||||
// Initialization and destruction
|
||||
|
@ -92,22 +86,6 @@ IdeController::IdeController(Params *p)
|
|||
bm_enabled = false;
|
||||
memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
|
||||
|
||||
pioInterface = NULL;
|
||||
dmaInterface = NULL;
|
||||
// create the PIO and DMA interfaces
|
||||
if (params()->pio_bus) {
|
||||
pioInterface = newPioInterface(name() + ".pio", params()->hier,
|
||||
params()->pio_bus, this,
|
||||
&IdeController::cacheAccess);
|
||||
pioLatency = params()->pio_latency * params()->pio_bus->clockRate;
|
||||
}
|
||||
|
||||
if (params()->dma_bus) {
|
||||
dmaInterface = new DMAInterface<Bus>(name() + ".dma",
|
||||
params()->dma_bus,
|
||||
params()->dma_bus, 1, true);
|
||||
}
|
||||
|
||||
// setup the disks attached to controller
|
||||
memset(disks, 0, sizeof(disks));
|
||||
dev[0] = 0;
|
||||
|
@ -118,7 +96,7 @@ IdeController::IdeController(Params *p)
|
|||
|
||||
for (int i = 0; i < params()->disks.size(); i++) {
|
||||
disks[i] = params()->disks[i];
|
||||
disks[i]->setController(this, dmaInterface);
|
||||
disks[i]->setController(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,91 +218,158 @@ IdeController::setDmaComplete(IdeDisk *disk)
|
|||
}
|
||||
}
|
||||
|
||||
////
|
||||
// Bus timing and bus access functions
|
||||
////
|
||||
|
||||
Tick
|
||||
IdeController::cacheAccess(MemReqPtr &req)
|
||||
{
|
||||
// @todo Add more accurate timing to cache access
|
||||
return curTick + pioLatency;
|
||||
}
|
||||
|
||||
////
|
||||
// Read and write handling
|
||||
////
|
||||
|
||||
void
|
||||
IdeController::readConfig(int offset, int size, uint8_t *data)
|
||||
IdeController::readConfig(int offset, uint8_t *data)
|
||||
{
|
||||
int config_offset;
|
||||
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::readConfig(offset, size, data);
|
||||
PciDev::readConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + size) <= IDE_CTRL_CONF_END) {
|
||||
(offset + 1) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
config_offset = offset - IDE_CTRL_CONF_START;
|
||||
|
||||
switch (size) {
|
||||
case sizeof(uint8_t):
|
||||
*data = config_regs.data[config_offset];
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_DEV_TIMING:
|
||||
*data = config_regs.sidetim;
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
*(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset];
|
||||
case IDE_CTRL_CONF_UDMA_CNTRL:
|
||||
*data = config_regs.udmactl;
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
*(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset];
|
||||
case IDE_CTRL_CONF_PRIM_TIMING+1:
|
||||
*data = htole(config_regs.idetim0) >> 8;
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING+1:
|
||||
*data = htole(config_regs.idetim1) >> 8;
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
*data = htole(config_regs.ideconfig) & 0xFF;
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG+1:
|
||||
*data = htole(config_regs.ideconfig) >> 8;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration read size!\n");
|
||||
panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n",
|
||||
offset, size, *(uint32_t*)data);
|
||||
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n",
|
||||
offset, (uint32_t)*data);
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::writeConfig(int offset, int size, const uint8_t *data)
|
||||
IdeController::readConfig(int offset, uint16_t *data)
|
||||
{
|
||||
int config_offset;
|
||||
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, size, data);
|
||||
PciDev::readConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + size) <= IDE_CTRL_CONF_END) {
|
||||
(offset + 2) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
config_offset = offset - IDE_CTRL_CONF_START;
|
||||
|
||||
switch(size) {
|
||||
case sizeof(uint8_t):
|
||||
config_regs.data[config_offset] = *data;
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_PRIM_TIMING:
|
||||
*data = config_regs.idetim0;
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
*(uint16_t*)&config_regs.data[config_offset] = *(uint16_t*)data;
|
||||
case IDE_CTRL_CONF_SEC_TIMING:
|
||||
*data = config_regs.idetim1;
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
*(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data;
|
||||
case IDE_CTRL_CONF_UDMA_TIMING:
|
||||
*data = config_regs.udmatim;
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
*data = config_regs.ideconfig;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write size!\n");
|
||||
panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data);
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::readConfig(int offset, uint32_t *data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::readConfig(offset, data);
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data);
|
||||
}
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint8_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + 1) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_DEV_TIMING:
|
||||
config_regs.sidetim = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_CNTRL:
|
||||
config_regs.udmactl = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG+1:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
|
||||
offset, (uint32_t)data);
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint16_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + 2) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_PRIM_TIMING:
|
||||
config_regs.idetim0 = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING:
|
||||
config_regs.idetim1 = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_TIMING:
|
||||
config_regs.udmatim = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = data;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Write of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
|
||||
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: %#x data: %#x\n",
|
||||
offset, size, data);
|
||||
|
||||
// Catch the writes to specific PCI registers that have side affects
|
||||
// (like updating the PIO ranges)
|
||||
switch (offset) {
|
||||
case PCI_COMMAND:
|
||||
/* Trap command register writes and enable IO/BM as appropriate. */
|
||||
if (offset == PCI_COMMAND) {
|
||||
if (letoh(config.command) & PCI_CMD_IOSE)
|
||||
io_enabled = true;
|
||||
else
|
||||
|
@ -334,91 +379,111 @@ IdeController::writeConfig(int offset, int size, const uint8_t *data)
|
|||
bm_enabled = true;
|
||||
else
|
||||
bm_enabled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint32_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
|
||||
|
||||
switch(offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
if (BARAddrs[0] != 0) {
|
||||
if (BARAddrs[0] != 0)
|
||||
pri_cmd_addr = BARAddrs[0];
|
||||
if (pioInterface)
|
||||
pioInterface->addAddrRange(RangeSize(pri_cmd_addr,
|
||||
pri_cmd_size));
|
||||
|
||||
pri_cmd_addr &= EV5::PAddrUncachedMask;
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_BASE_ADDR1:
|
||||
if (BARAddrs[1] != 0) {
|
||||
if (BARAddrs[1] != 0)
|
||||
pri_ctrl_addr = BARAddrs[1];
|
||||
if (pioInterface)
|
||||
pioInterface->addAddrRange(RangeSize(pri_ctrl_addr,
|
||||
pri_ctrl_size));
|
||||
|
||||
pri_ctrl_addr &= EV5::PAddrUncachedMask;
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_BASE_ADDR2:
|
||||
if (BARAddrs[2] != 0) {
|
||||
if (BARAddrs[2] != 0)
|
||||
sec_cmd_addr = BARAddrs[2];
|
||||
if (pioInterface)
|
||||
pioInterface->addAddrRange(RangeSize(sec_cmd_addr,
|
||||
sec_cmd_size));
|
||||
|
||||
sec_cmd_addr &= EV5::PAddrUncachedMask;
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_BASE_ADDR3:
|
||||
if (BARAddrs[3] != 0) {
|
||||
if (BARAddrs[3] != 0)
|
||||
sec_ctrl_addr = BARAddrs[3];
|
||||
if (pioInterface)
|
||||
pioInterface->addAddrRange(RangeSize(sec_ctrl_addr,
|
||||
sec_ctrl_size));
|
||||
|
||||
sec_ctrl_addr &= EV5::PAddrUncachedMask;
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_BASE_ADDR4:
|
||||
if (BARAddrs[4] != 0) {
|
||||
if (BARAddrs[4] != 0)
|
||||
bmi_addr = BARAddrs[4];
|
||||
if (pioInterface)
|
||||
pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size));
|
||||
|
||||
bmi_addr &= EV5::PAddrUncachedMask;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Fault
|
||||
IdeController::read(MemReqPtr &req, uint8_t *data)
|
||||
Tick
|
||||
IdeController::read(Packet &pkt)
|
||||
{
|
||||
Addr offset;
|
||||
IdeChannel channel;
|
||||
IdeRegType reg_type;
|
||||
int disk;
|
||||
|
||||
parseAddr(req->paddr, offset, channel, reg_type);
|
||||
uint8_t *data8 = 0 ;
|
||||
uint16_t *data16 = 0;
|
||||
uint32_t *data32 = 0;
|
||||
|
||||
if (!io_enabled)
|
||||
return NoFault;
|
||||
switch(pkt.size) {
|
||||
case sizeof(uint8_t):
|
||||
if (!pkt.data) {
|
||||
data8 = new uint8_t;
|
||||
pkt.data = data8;
|
||||
} else
|
||||
data8 = pkt.data;
|
||||
*data8 = 0;
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
if (!pkt.data) {
|
||||
data16 = new uint16_t;
|
||||
pkt.data = (uint8_t*)data16;
|
||||
} else
|
||||
data16 = (uint16_t*)pkt.data;
|
||||
*data16 = 0;
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
if (!pkt.data) {
|
||||
data32 = new uint32_t;
|
||||
pkt.data = (uint8_t*)data32;
|
||||
} else
|
||||
data32 = (uint32_t*)pkt.data;
|
||||
*data32 = 0;
|
||||
break;
|
||||
default:
|
||||
panic("Bad IDE read size: %d\n", pkt.size);
|
||||
}
|
||||
|
||||
parseAddr(pkt.addr, offset, channel, reg_type);
|
||||
|
||||
if (!io_enabled) {
|
||||
pkt.result = Success;
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
switch (reg_type) {
|
||||
case BMI_BLOCK:
|
||||
switch (req->size) {
|
||||
switch (pkt.size) {
|
||||
case sizeof(uint8_t):
|
||||
*data = bmi_regs.data[offset];
|
||||
*data8 = bmi_regs.data[offset];
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
*(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset];
|
||||
*data16 = *(uint16_t*)&bmi_regs.data[offset];
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
*(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset];
|
||||
*data32 = *(uint32_t*)&bmi_regs.data[offset];
|
||||
break;
|
||||
default:
|
||||
panic("IDE read of BMI reg invalid size: %#x\n", req->size);
|
||||
panic("IDE read of BMI reg invalid size: %#x\n", pkt.size);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -431,68 +496,82 @@ IdeController::read(MemReqPtr &req, uint8_t *data)
|
|||
|
||||
switch (offset) {
|
||||
case DATA_OFFSET:
|
||||
switch (req->size) {
|
||||
switch (pkt.size) {
|
||||
case sizeof(uint16_t):
|
||||
disks[disk]->read(offset, reg_type, data);
|
||||
disks[disk]->read(offset, reg_type, (uint8_t*)data16);
|
||||
break;
|
||||
|
||||
case sizeof(uint32_t):
|
||||
disks[disk]->read(offset, reg_type, data);
|
||||
disks[disk]->read(offset, reg_type, &data[2]);
|
||||
disks[disk]->read(offset, reg_type, (uint8_t*)data16);
|
||||
disks[disk]->read(offset, reg_type, (uint8_t*)(data16 + sizeof(uint16_t)));
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("IDE read of data reg invalid size: %#x\n", req->size);
|
||||
panic("IDE read of data reg invalid size: %#x\n", pkt.size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (req->size == sizeof(uint8_t)) {
|
||||
disks[disk]->read(offset, reg_type, data);
|
||||
if (pkt.size == sizeof(uint8_t)) {
|
||||
disks[disk]->read(offset, reg_type, data8);
|
||||
} else
|
||||
panic("IDE read of command reg of invalid size: %#x\n", req->size);
|
||||
panic("IDE read of command reg of invalid size: %#x\n", pkt.size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
panic("IDE controller read of unknown register block type!\n");
|
||||
}
|
||||
|
||||
if (pkt.size == 1)
|
||||
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
|
||||
offset, req->size, *(uint32_t*)data);
|
||||
offset, pkt.size, (uint32_t)*data8);
|
||||
else if (pkt.size == 2)
|
||||
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
|
||||
offset, pkt.size, *data16);
|
||||
else
|
||||
DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
|
||||
offset, pkt.size, *data32);
|
||||
|
||||
return NoFault;
|
||||
pkt.result = Success;
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
Fault
|
||||
IdeController::write(MemReqPtr &req, const uint8_t *data)
|
||||
Tick
|
||||
IdeController::write(Packet &pkt)
|
||||
{
|
||||
Addr offset;
|
||||
IdeChannel channel;
|
||||
IdeRegType reg_type;
|
||||
int disk;
|
||||
uint8_t oldVal, newVal;
|
||||
uint8_t data8 = *(uint8_t*)pkt.data;
|
||||
uint32_t data32 = *(uint32_t*)pkt.data;
|
||||
|
||||
parseAddr(req->paddr, offset, channel, reg_type);
|
||||
|
||||
if (!io_enabled)
|
||||
return NoFault;
|
||||
parseAddr(pkt.addr, offset, channel, reg_type);
|
||||
|
||||
if (!io_enabled) {
|
||||
pkt.result = Success;
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
switch (reg_type) {
|
||||
case BMI_BLOCK:
|
||||
if (!bm_enabled)
|
||||
return NoFault;
|
||||
if (!bm_enabled) {
|
||||
pkt.result = Success;
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
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);
|
||||
if (pkt.size != sizeof(uint8_t))
|
||||
panic("Invalid BMIC write size: %x\n", pkt.size);
|
||||
|
||||
// select the current disk based on DEV bit
|
||||
disk = getDisk(channel);
|
||||
|
||||
oldVal = bmi_regs.chan[channel].bmic;
|
||||
newVal = *data;
|
||||
newVal = data8;
|
||||
|
||||
// if a DMA transfer is in progress, R/W control cannot change
|
||||
if (oldVal & SSBM) {
|
||||
|
@ -541,11 +620,11 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
|||
// Bus master IDE status register
|
||||
case BMIS0:
|
||||
case BMIS1:
|
||||
if (req->size != sizeof(uint8_t))
|
||||
panic("Invalid BMIS write size: %x\n", req->size);
|
||||
if (pkt.size != sizeof(uint8_t))
|
||||
panic("Invalid BMIS write size: %x\n", pkt.size);
|
||||
|
||||
oldVal = bmi_regs.chan[channel].bmis;
|
||||
newVal = *data;
|
||||
newVal = data8;
|
||||
|
||||
// the BMIDEA bit is RO
|
||||
newVal |= (oldVal & BMIDEA);
|
||||
|
@ -568,30 +647,28 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
|||
case BMIDTP0:
|
||||
case BMIDTP1:
|
||||
{
|
||||
if (req->size != sizeof(uint32_t))
|
||||
panic("Invalid BMIDTP write size: %x\n", req->size);
|
||||
if (pkt.size != sizeof(uint32_t))
|
||||
panic("Invalid BMIDTP write size: %x\n", pkt.size);
|
||||
|
||||
uint32_t host_data = letoh(*(uint32_t*)data);
|
||||
host_data &= ~0x3;
|
||||
bmi_regs.chan[channel].bmidtp = htole(host_data);
|
||||
bmi_regs.chan[channel].bmidtp = htole(data32 & ~0x3);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (req->size != sizeof(uint8_t) &&
|
||||
req->size != sizeof(uint16_t) &&
|
||||
req->size != sizeof(uint32_t))
|
||||
if (pkt.size != sizeof(uint8_t) &&
|
||||
pkt.size != sizeof(uint16_t) &&
|
||||
pkt.size != sizeof(uint32_t))
|
||||
panic("IDE controller write of invalid write size: %x\n",
|
||||
req->size);
|
||||
pkt.size);
|
||||
|
||||
// do a default copy of data into the registers
|
||||
memcpy(&bmi_regs.data[offset], data, req->size);
|
||||
memcpy(&bmi_regs.data[offset], pkt.data, pkt.size);
|
||||
}
|
||||
break;
|
||||
case COMMAND_BLOCK:
|
||||
if (offset == IDE_SELECT_OFFSET) {
|
||||
uint8_t *devBit = &dev[channel];
|
||||
*devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0;
|
||||
*devBit = (letoh(data8) & IDE_SELECT_DEV_BIT) ? 1 : 0;
|
||||
}
|
||||
// fall-through ok!
|
||||
case CONTROL_BLOCK:
|
||||
|
@ -602,34 +679,44 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
|
|||
|
||||
switch (offset) {
|
||||
case DATA_OFFSET:
|
||||
switch (req->size) {
|
||||
switch (pkt.size) {
|
||||
case sizeof(uint16_t):
|
||||
disks[disk]->write(offset, reg_type, data);
|
||||
disks[disk]->write(offset, reg_type, pkt.data);
|
||||
break;
|
||||
|
||||
case sizeof(uint32_t):
|
||||
disks[disk]->write(offset, reg_type, data);
|
||||
disks[disk]->write(offset, reg_type, &data[2]);
|
||||
disks[disk]->write(offset, reg_type, pkt.data);
|
||||
disks[disk]->write(offset, reg_type, pkt.data +
|
||||
sizeof(uint16_t));
|
||||
break;
|
||||
default:
|
||||
panic("IDE write of data reg invalid size: %#x\n", req->size);
|
||||
panic("IDE write of data reg invalid size: %#x\n", pkt.size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (req->size == sizeof(uint8_t)) {
|
||||
disks[disk]->write(offset, reg_type, data);
|
||||
if (pkt.size == sizeof(uint8_t)) {
|
||||
disks[disk]->write(offset, reg_type, pkt.data);
|
||||
} else
|
||||
panic("IDE write of command reg of invalid size: %#x\n", req->size);
|
||||
panic("IDE write of command reg of invalid size: %#x\n", pkt.size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
panic("IDE controller write of unknown register block type!\n");
|
||||
}
|
||||
|
||||
if (pkt.size == 1)
|
||||
DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
|
||||
offset, req->size, *(uint32_t*)data);
|
||||
offset, pkt.size, (uint32_t)data8);
|
||||
else if (pkt.size == 2)
|
||||
DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
|
||||
offset, pkt.size, *(uint16_t*)pkt.data);
|
||||
else
|
||||
DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
|
||||
offset, pkt.size, data32);
|
||||
|
||||
return NoFault;
|
||||
|
||||
pkt.result = Success;
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
////
|
||||
|
@ -698,51 +785,35 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion)
|
|||
UNSERIALIZE_SCALAR(bm_enabled);
|
||||
UNSERIALIZE_ARRAY(cmd_in_progress,
|
||||
sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
|
||||
|
||||
if (pioInterface) {
|
||||
pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size));
|
||||
pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size));
|
||||
pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size));
|
||||
pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size));
|
||||
pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
|
||||
|
||||
Param<Addr> addr;
|
||||
SimObjectVectorParam<IdeDisk *> disks;
|
||||
SimObjectParam<MemoryController *> mmu;
|
||||
SimObjectParam<System *> system;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<PciConfigAll *> configspace;
|
||||
SimObjectParam<PciConfigData *> configdata;
|
||||
SimObjectParam<Platform *> platform;
|
||||
Param<uint32_t> pci_bus;
|
||||
Param<uint32_t> pci_dev;
|
||||
Param<uint32_t> pci_func;
|
||||
SimObjectParam<Bus *> pio_bus;
|
||||
SimObjectParam<Bus *> dma_bus;
|
||||
Param<Tick> pio_latency;
|
||||
SimObjectParam<HierParams *> hier;
|
||||
SimObjectVectorParam<IdeDisk *> disks;
|
||||
|
||||
END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
|
||||
|
||||
BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
|
||||
|
||||
INIT_PARAM(addr, "Device Address"),
|
||||
INIT_PARAM(disks, "IDE disks attached to this controller"),
|
||||
INIT_PARAM(mmu, "Memory controller"),
|
||||
INIT_PARAM(system, "System pointer"),
|
||||
INIT_PARAM(platform, "Platform pointer"),
|
||||
INIT_PARAM(configspace, "PCI Configspace"),
|
||||
INIT_PARAM(configdata, "PCI Config data"),
|
||||
INIT_PARAM(platform, "Platform pointer"),
|
||||
INIT_PARAM(pci_bus, "PCI bus ID"),
|
||||
INIT_PARAM(pci_dev, "PCI device number"),
|
||||
INIT_PARAM(pci_func, "PCI function code"),
|
||||
INIT_PARAM(pio_bus, ""),
|
||||
INIT_PARAM(dma_bus, ""),
|
||||
INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
|
||||
INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
|
||||
INIT_PARAM(disks, "IDE disks attached to this controller")
|
||||
|
||||
END_INIT_SIM_OBJECT_PARAMS(IdeController)
|
||||
|
||||
|
@ -750,19 +821,15 @@ CREATE_SIM_OBJECT(IdeController)
|
|||
{
|
||||
IdeController::Params *params = new IdeController::Params;
|
||||
params->name = getInstanceName();
|
||||
params->mmu = mmu;
|
||||
params->platform = platform;
|
||||
params->system = system;
|
||||
params->configSpace = configspace;
|
||||
params->configData = configdata;
|
||||
params->plat = platform;
|
||||
params->busNum = pci_bus;
|
||||
params->deviceNum = pci_dev;
|
||||
params->functionNum = pci_func;
|
||||
|
||||
params->pio_delay = pio_latency;
|
||||
params->disks = disks;
|
||||
params->pio_bus = pio_bus;
|
||||
params->dma_bus = dma_bus;
|
||||
params->pio_latency = pio_latency;
|
||||
params->hier = hier;
|
||||
return new IdeController(params);
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,13 @@
|
|||
#define IDE_CTRL_CONF_START 0x40
|
||||
#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs))
|
||||
|
||||
#define IDE_CTRL_CONF_PRIM_TIMING 0x40
|
||||
#define IDE_CTRL_CONF_SEC_TIMING 0x42
|
||||
#define IDE_CTRL_CONF_DEV_TIMING 0x44
|
||||
#define IDE_CTRL_CONF_UDMA_CNTRL 0x48
|
||||
#define IDE_CTRL_CONF_UDMA_TIMING 0x4A
|
||||
#define IDE_CTRL_CONF_IDE_CONFIG 0x54
|
||||
|
||||
|
||||
enum IdeRegType {
|
||||
COMMAND_BLOCK,
|
||||
|
@ -77,13 +84,9 @@ enum IdeRegType {
|
|||
BMI_BLOCK
|
||||
};
|
||||
|
||||
class BaseInterface;
|
||||
class Bus;
|
||||
class HierParams;
|
||||
class IdeDisk;
|
||||
class IntrControl;
|
||||
class PciConfigAll;
|
||||
class PhysicalMemory;
|
||||
class Platform;
|
||||
|
||||
/**
|
||||
|
@ -191,10 +194,6 @@ class IdeController : public PciDev
|
|||
{
|
||||
/** Array of disk objects */
|
||||
std::vector<IdeDisk *> disks;
|
||||
Bus *pio_bus;
|
||||
Bus *dma_bus;
|
||||
Tick pio_latency;
|
||||
HierParams *hier;
|
||||
};
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
|
@ -202,26 +201,28 @@ class IdeController : public PciDev
|
|||
IdeController(Params *p);
|
||||
~IdeController();
|
||||
|
||||
virtual void writeConfig(int offset, int size, const uint8_t *data);
|
||||
virtual void readConfig(int offset, int size, uint8_t *data);
|
||||
virtual void writeConfig(int offset, const uint8_t data);
|
||||
virtual void writeConfig(int offset, const uint16_t data);
|
||||
virtual void writeConfig(int offset, const uint32_t data);
|
||||
virtual void readConfig(int offset, uint8_t *data);
|
||||
virtual void readConfig(int offset, uint16_t *data);
|
||||
virtual void readConfig(int offset, uint32_t *data);
|
||||
|
||||
void setDmaComplete(IdeDisk *disk);
|
||||
|
||||
/**
|
||||
* Read a done field for a given target.
|
||||
* @param req Contains the address of the field to read.
|
||||
* @param data Return the field read.
|
||||
* @return The fault condition of the access.
|
||||
* @param pkt Packet describing what is to be read
|
||||
* @return The amount of time to complete this request
|
||||
*/
|
||||
virtual Fault read(MemReqPtr &req, uint8_t *data);
|
||||
virtual Tick read(Packet &pkt);
|
||||
|
||||
/**
|
||||
* Write to the mmapped I/O control registers.
|
||||
* @param req Contains the address to write to.
|
||||
* @param data The data to write.
|
||||
* @return The fault condition of the access.
|
||||
* Write a done field for a given target.
|
||||
* @param pkt Packet describing what is to be written
|
||||
* @return The amount of time to complete this request
|
||||
*/
|
||||
virtual Fault write(MemReqPtr &req, const uint8_t *data);
|
||||
virtual Tick write(Packet &pkt);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
|
@ -236,11 +237,5 @@ class IdeController : public PciDev
|
|||
*/
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
/**
|
||||
* Return how long this access will take.
|
||||
* @param req the memory request to calcuate
|
||||
* @return Tick when the request is done
|
||||
*/
|
||||
Tick cacheAccess(MemReqPtr &req);
|
||||
};
|
||||
#endif // __IDE_CTRL_HH_
|
||||
|
|
287
dev/ide_disk.cc
287
dev/ide_disk.cc
|
@ -35,6 +35,7 @@
|
|||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
#include "base/chunk_generator.hh"
|
||||
#include "base/cprintf.hh" // csprintf
|
||||
#include "base/trace.hh"
|
||||
#include "dev/disk_image.hh"
|
||||
|
@ -42,11 +43,7 @@
|
|||
#include "dev/ide_ctrl.hh"
|
||||
#include "dev/tsunami.hh"
|
||||
#include "dev/tsunami_pchip.hh"
|
||||
#include "mem/functional/physical.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 "mem/packet.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/root.hh"
|
||||
|
@ -55,11 +52,11 @@
|
|||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
|
||||
IdeDisk::IdeDisk(const string &name, DiskImage *img,
|
||||
int id, Tick delay)
|
||||
: SimObject(name), ctrl(NULL), image(img), physmem(phys), diskDelay(delay),
|
||||
dmaTransferEvent(this), dmaReadWaitEvent(this),
|
||||
dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
|
||||
: SimObject(name), ctrl(NULL), image(img), diskDelay(delay),
|
||||
dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
|
||||
dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
|
||||
dmaReadEvent(this), dmaWriteEvent(this)
|
||||
{
|
||||
// Reset the device state
|
||||
|
@ -139,7 +136,6 @@ IdeDisk::reset(int id)
|
|||
memset(&cmdReg, 0, sizeof(CommandReg_t));
|
||||
memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
|
||||
|
||||
dmaInterfaceBytes = 0;
|
||||
curPrdAddr = 0;
|
||||
curSector = 0;
|
||||
cmdBytes = 0;
|
||||
|
@ -188,29 +184,6 @@ IdeDisk::pciToDma(Addr pciAddr)
|
|||
panic("Access to unset controller!\n");
|
||||
}
|
||||
|
||||
uint32_t
|
||||
IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
|
||||
{
|
||||
uint32_t bytesInPage = 0;
|
||||
|
||||
// First calculate how many bytes could be in the page
|
||||
if (bytesLeft > TheISA::PageBytes)
|
||||
bytesInPage = TheISA::PageBytes;
|
||||
else
|
||||
bytesInPage = bytesLeft;
|
||||
|
||||
// Next, see if we have crossed a page boundary, and adjust
|
||||
Addr upperBound = curAddr + bytesInPage;
|
||||
Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes;
|
||||
|
||||
assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
|
||||
|
||||
if (upperBound >= pageBound)
|
||||
bytesInPage = pageBound - curAddr;
|
||||
|
||||
return bytesInPage;
|
||||
}
|
||||
|
||||
////
|
||||
// Device registers read/write
|
||||
////
|
||||
|
@ -339,29 +312,17 @@ IdeDisk::doDmaTransfer()
|
|||
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();
|
||||
}
|
||||
if (ctrl->dmaPending()) {
|
||||
dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
} else
|
||||
ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
|
||||
(uint8_t*)&curPrd.entry);
|
||||
}
|
||||
|
||||
void
|
||||
IdeDisk::dmaPrdReadDone()
|
||||
{
|
||||
// actually copy the PRD from physical memory
|
||||
memcpy((void *)&curPrd.entry,
|
||||
physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
|
||||
sizeof(PrdEntry_t));
|
||||
|
||||
DPRINTF(IdeDisk,
|
||||
"PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
|
||||
curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
|
||||
|
@ -372,38 +333,49 @@ IdeDisk::dmaPrdReadDone()
|
|||
curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
|
||||
|
||||
if (dmaRead)
|
||||
doDmaRead();
|
||||
doDmaDataRead();
|
||||
else
|
||||
doDmaWrite();
|
||||
doDmaDataWrite();
|
||||
}
|
||||
|
||||
void
|
||||
IdeDisk::doDmaRead()
|
||||
IdeDisk::doDmaDataRead()
|
||||
{
|
||||
/** @todo we need to figure out what the delay actually will be */
|
||||
Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
|
||||
|
||||
DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
|
||||
diskDelay, totalDiskDelay);
|
||||
if (dmaInterface) {
|
||||
if (dmaInterface->busy()) {
|
||||
// reschedule after waiting period
|
||||
dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
}
|
||||
|
||||
Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
|
||||
dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
|
||||
}
|
||||
|
||||
uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
|
||||
(uint32_t)curPrd.getByteCount());
|
||||
|
||||
dmaInterfaceBytes = bytesInPage;
|
||||
void
|
||||
IdeDisk::doDmaRead()
|
||||
{
|
||||
|
||||
dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
|
||||
curTick + totalDiskDelay, &dmaReadEvent);
|
||||
if (!dmaReadCG) {
|
||||
// clear out the data buffer
|
||||
memset(dataBuffer, 0, MAX_DMA_SIZE);
|
||||
dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
|
||||
curPrd.getByteCount(), TheISA::PageBytes);
|
||||
|
||||
}
|
||||
if (ctrl->dmaPending()) {
|
||||
panic("shouldn't be reentant??");
|
||||
dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
} else if (!dmaReadCG->done()) {
|
||||
assert(dmaReadCG->complete() < MAX_DMA_SIZE);
|
||||
ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
|
||||
&dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
|
||||
dmaReadCG->next();
|
||||
} else {
|
||||
// schedule dmaReadEvent with sectorDelay (dmaReadDone)
|
||||
dmaReadEvent.schedule(curTick + totalDiskDelay);
|
||||
assert(dmaReadCG->done());
|
||||
delete dmaReadCG;
|
||||
dmaReadCG = NULL;
|
||||
dmaReadDone();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,63 +383,14 @@ void
|
|||
IdeDisk::dmaReadDone()
|
||||
{
|
||||
|
||||
Addr curAddr = 0, dmaAddr = 0;
|
||||
uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
|
||||
uint32_t bytesWritten = 0;
|
||||
|
||||
// continue to use the DMA interface until all pages are read
|
||||
if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
|
||||
// see if the interface is busy
|
||||
if (dmaInterface->busy()) {
|
||||
// reschedule after waiting period
|
||||
dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
|
||||
curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
|
||||
dmaAddr = pciToDma(curAddr);
|
||||
|
||||
bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
|
||||
dmaInterfaceBytes += bytesInPage;
|
||||
|
||||
dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
|
||||
curTick, &dmaReadEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// set initial address
|
||||
curAddr = curPrd.getBaseAddr();
|
||||
|
||||
// clear out the data buffer
|
||||
memset(dataBuffer, 0, MAX_DMA_SIZE);
|
||||
|
||||
// read the data from memory via DMA into a data buffer
|
||||
while (bytesWritten < curPrd.getByteCount()) {
|
||||
if (cmdBytesLeft <= 0)
|
||||
panic("DMA data is larger than # of sectors specified\n");
|
||||
|
||||
dmaAddr = pciToDma(curAddr);
|
||||
|
||||
// calculate how many bytes are in the current page
|
||||
bytesLeft = curPrd.getByteCount() - bytesWritten;
|
||||
bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
|
||||
|
||||
// copy the data from memory into the data buffer
|
||||
memcpy((void *)(dataBuffer + bytesWritten),
|
||||
physmem->dma_addr(dmaAddr, bytesInPage),
|
||||
bytesInPage);
|
||||
|
||||
curAddr += bytesInPage;
|
||||
bytesWritten += bytesInPage;
|
||||
cmdBytesLeft -= bytesInPage;
|
||||
}
|
||||
|
||||
// write the data to the disk image
|
||||
for (bytesWritten = 0;
|
||||
bytesWritten < curPrd.getByteCount();
|
||||
for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
|
||||
bytesWritten += SectorSize) {
|
||||
|
||||
cmdBytesLeft -= SectorSize;
|
||||
writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
|
||||
}
|
||||
|
||||
|
@ -482,107 +405,55 @@ IdeDisk::dmaReadDone()
|
|||
}
|
||||
|
||||
void
|
||||
IdeDisk::doDmaWrite()
|
||||
IdeDisk::doDmaDataWrite()
|
||||
{
|
||||
/** @todo we need to figure out what the delay actually will be */
|
||||
Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
|
||||
uint32_t bytesRead = 0;
|
||||
|
||||
DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
|
||||
diskDelay, totalDiskDelay);
|
||||
|
||||
if (dmaInterface) {
|
||||
if (dmaInterface->busy()) {
|
||||
// reschedule after waiting period
|
||||
dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
}
|
||||
memset(dataBuffer, 0, MAX_DMA_SIZE);
|
||||
assert(cmdBytesLeft <= MAX_DMA_SIZE);
|
||||
while (bytesRead < curPrd.getByteCount()) {
|
||||
readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
|
||||
bytesRead += SectorSize;
|
||||
cmdBytesLeft -= SectorSize;
|
||||
}
|
||||
|
||||
Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
|
||||
dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
|
||||
}
|
||||
|
||||
uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
|
||||
(uint32_t)curPrd.getByteCount());
|
||||
void
|
||||
IdeDisk::doDmaWrite()
|
||||
{
|
||||
|
||||
dmaInterfaceBytes = bytesInPage;
|
||||
|
||||
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
|
||||
bytesInPage, curTick + totalDiskDelay,
|
||||
&dmaWriteEvent);
|
||||
if (!dmaWriteCG) {
|
||||
// clear out the data buffer
|
||||
dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
|
||||
curPrd.getByteCount(), TheISA::PageBytes);
|
||||
}
|
||||
if (ctrl->dmaPending()) {
|
||||
panic("shouldn't be reentant??");
|
||||
dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
} else if (!dmaWriteCG->done()) {
|
||||
assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
|
||||
ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
|
||||
&dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
|
||||
dmaWriteCG->next();
|
||||
} else {
|
||||
// schedule event with disk delay (dmaWriteDone)
|
||||
dmaWriteEvent.schedule(curTick + totalDiskDelay);
|
||||
assert(dmaWriteCG->done());
|
||||
delete dmaWriteCG;
|
||||
dmaWriteCG = NULL;
|
||||
dmaWriteDone();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IdeDisk::dmaWriteDone()
|
||||
{
|
||||
Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
|
||||
uint32_t bytesRead = 0, bytesInPage = 0;
|
||||
|
||||
// continue to use the DMA interface until all pages are read
|
||||
if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
|
||||
// see if the interface is busy
|
||||
if (dmaInterface->busy()) {
|
||||
// reschedule after waiting period
|
||||
dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
|
||||
curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
|
||||
dmaAddr = pciToDma(curAddr);
|
||||
|
||||
bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
|
||||
dmaInterfaceBytes += bytesInPage;
|
||||
|
||||
dmaInterface->doDMA(WriteInvalidate, dmaAddr,
|
||||
bytesInPage, curTick,
|
||||
&dmaWriteEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// setup the initial page and DMA address
|
||||
curAddr = curPrd.getBaseAddr();
|
||||
pageAddr = TheISA::TruncPage(curAddr);
|
||||
dmaAddr = pciToDma(curAddr);
|
||||
|
||||
// clear out the data buffer
|
||||
memset(dataBuffer, 0, MAX_DMA_SIZE);
|
||||
|
||||
while (bytesRead < curPrd.getByteCount()) {
|
||||
// see if we have crossed into a new page
|
||||
if (pageAddr != TheISA::TruncPage(curAddr)) {
|
||||
// write the data to memory
|
||||
memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
|
||||
(void *)(dataBuffer + (bytesRead - bytesInPage)),
|
||||
bytesInPage);
|
||||
|
||||
// update the DMA address and page address
|
||||
pageAddr = TheISA::TruncPage(curAddr);
|
||||
dmaAddr = pciToDma(curAddr);
|
||||
|
||||
bytesInPage = 0;
|
||||
}
|
||||
|
||||
if (cmdBytesLeft <= 0)
|
||||
panic("DMA requested data is larger than # sectors specified\n");
|
||||
|
||||
readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
|
||||
|
||||
curAddr += SectorSize;
|
||||
bytesRead += SectorSize;
|
||||
bytesInPage += SectorSize;
|
||||
cmdBytesLeft -= SectorSize;
|
||||
}
|
||||
|
||||
// write the last page worth read to memory
|
||||
if (bytesInPage != 0) {
|
||||
memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
|
||||
(void *)(dataBuffer + (bytesRead - bytesInPage)),
|
||||
bytesInPage);
|
||||
}
|
||||
|
||||
// check for the EOT
|
||||
if (curPrd.getEOT()) {
|
||||
assert(cmdBytesLeft == 0);
|
||||
|
@ -1138,13 +1009,13 @@ IdeDisk::serialize(ostream &os)
|
|||
SERIALIZE_SCALAR(curPrd.entry.endOfTable);
|
||||
SERIALIZE_SCALAR(curPrdAddr);
|
||||
|
||||
/** @todo need to serialized chunk generator stuff!! */
|
||||
// Serialize current transfer related information
|
||||
SERIALIZE_SCALAR(cmdBytesLeft);
|
||||
SERIALIZE_SCALAR(cmdBytes);
|
||||
SERIALIZE_SCALAR(drqBytesLeft);
|
||||
SERIALIZE_SCALAR(curSector);
|
||||
SERIALIZE_SCALAR(dmaRead);
|
||||
SERIALIZE_SCALAR(dmaInterfaceBytes);
|
||||
SERIALIZE_SCALAR(intrPending);
|
||||
SERIALIZE_ENUM(devState);
|
||||
SERIALIZE_ENUM(dmaState);
|
||||
|
@ -1190,13 +1061,13 @@ IdeDisk::unserialize(Checkpoint *cp, const string §ion)
|
|||
UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
|
||||
UNSERIALIZE_SCALAR(curPrdAddr);
|
||||
|
||||
/** @todo need to serialized chunk generator stuff!! */
|
||||
// Unserialize current transfer related information
|
||||
UNSERIALIZE_SCALAR(cmdBytes);
|
||||
UNSERIALIZE_SCALAR(cmdBytesLeft);
|
||||
UNSERIALIZE_SCALAR(drqBytesLeft);
|
||||
UNSERIALIZE_SCALAR(curSector);
|
||||
UNSERIALIZE_SCALAR(dmaRead);
|
||||
UNSERIALIZE_SCALAR(dmaInterfaceBytes);
|
||||
UNSERIALIZE_SCALAR(intrPending);
|
||||
UNSERIALIZE_ENUM(devState);
|
||||
UNSERIALIZE_ENUM(dmaState);
|
||||
|
@ -1210,7 +1081,6 @@ static const char *DriveID_strings[] = { "master", "slave" };
|
|||
BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
|
||||
|
||||
SimObjectParam<DiskImage *> image;
|
||||
SimObjectParam<PhysicalMemory *> physmem;
|
||||
SimpleEnumParam<DriveID> driveID;
|
||||
Param<int> delay;
|
||||
|
||||
|
@ -1219,7 +1089,6 @@ END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
|
|||
BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
|
||||
|
||||
INIT_PARAM(image, "Disk image"),
|
||||
INIT_PARAM(physmem, "Physical memory"),
|
||||
INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings),
|
||||
INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1)
|
||||
|
||||
|
@ -1228,7 +1097,7 @@ END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
|
|||
|
||||
CREATE_SIM_OBJECT(IdeDisk)
|
||||
{
|
||||
return new IdeDisk(getInstanceName(), image, physmem, driveID, delay);
|
||||
return new IdeDisk(getInstanceName(), image, driveID, delay);
|
||||
}
|
||||
|
||||
REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
#define DMA_BACKOFF_PERIOD 200
|
||||
|
||||
#define MAX_DMA_SIZE (65536) // 64K
|
||||
#define MAX_DMA_SIZE (131072) // 128K
|
||||
#define MAX_MULTSECT (128)
|
||||
|
||||
#define PRD_BASE_MASK 0xfffffffe
|
||||
|
@ -190,12 +190,8 @@ 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 microseconds. */
|
||||
|
@ -230,8 +226,6 @@ class IdeDisk : public SimObject
|
|||
uint32_t curPrdAddr;
|
||||
/** PRD entry */
|
||||
PrdTableEntry curPrd;
|
||||
/** Number of bytes transfered by DMA interface for current transfer */
|
||||
uint32_t dmaInterfaceBytes;
|
||||
/** Device ID (master=0/slave=1) */
|
||||
int devID;
|
||||
/** Interrupt pending */
|
||||
|
@ -242,12 +236,10 @@ class IdeDisk : public SimObject
|
|||
* 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, PhysicalMemory *phys,
|
||||
int id, Tick disk_delay);
|
||||
IdeDisk(const std::string &name, DiskImage *img, int id, Tick disk_delay);
|
||||
|
||||
/**
|
||||
* Delete the data buffer.
|
||||
|
@ -263,10 +255,9 @@ class IdeDisk : public SimObject
|
|||
* Set the controller for this device
|
||||
* @param c The IDE controller
|
||||
*/
|
||||
void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) {
|
||||
void setController(IdeController *c) {
|
||||
if (ctrl) panic("Cannot change the controller once set!\n");
|
||||
ctrl = c;
|
||||
dmaInterface = dmaIntr;
|
||||
}
|
||||
|
||||
// Device register read/write
|
||||
|
@ -289,11 +280,17 @@ class IdeDisk : public SimObject
|
|||
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
|
||||
EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
|
||||
|
||||
void doDmaDataRead();
|
||||
|
||||
void doDmaRead();
|
||||
ChunkGenerator *dmaReadCG;
|
||||
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
|
||||
EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
|
||||
|
||||
void doDmaDataWrite();
|
||||
|
||||
void doDmaWrite();
|
||||
ChunkGenerator *dmaWriteCG;
|
||||
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
|
||||
EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
|
||||
|
||||
|
@ -339,8 +336,6 @@ class IdeDisk : public SimObject
|
|||
|
||||
inline Addr pciToDma(Addr pciAddr);
|
||||
|
||||
uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
* @param os The stream to serialize to.
|
||||
|
|
|
@ -105,23 +105,24 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list)
|
|||
}
|
||||
|
||||
|
||||
DmaPort::DmaPort(DmaDevice *dev)
|
||||
: device(dev)
|
||||
DmaPort::DmaPort(DmaDevice *dev, Platform *p)
|
||||
: device(dev), platform(p), pendingCount(0)
|
||||
{ }
|
||||
|
||||
bool
|
||||
DmaPort::recvTiming(Packet &pkt)
|
||||
{
|
||||
completionEvent->schedule(curTick+1);
|
||||
completionEvent = NULL;
|
||||
if (pkt.senderState) {
|
||||
DmaReqState *state;
|
||||
state = (DmaReqState*)pkt.senderState;
|
||||
state->completionEvent->schedule(pkt.time - pkt.req->getTime());
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
DmaDevice::DmaDevice(Params *p)
|
||||
: PioDevice(p)
|
||||
{
|
||||
dmaPort = new DmaPort(this);
|
||||
}
|
||||
: PioDevice(p), dmaPort(NULL)
|
||||
{ }
|
||||
|
||||
void
|
||||
DmaPort::SendEvent::process()
|
||||
|
@ -140,8 +141,8 @@ DmaPort::recvRetry()
|
|||
return pkt;
|
||||
}
|
||||
void
|
||||
DmaPort::dmaAction(Command cmd, DmaPort port, Addr addr, int size,
|
||||
Event *event, uint8_t *data)
|
||||
DmaPort::dmaAction(Command cmd, Addr addr, int size, Event *event,
|
||||
uint8_t *data)
|
||||
{
|
||||
|
||||
assert(event);
|
||||
|
@ -161,8 +162,6 @@ DmaPort::dmaAction(Command cmd, DmaPort port, Addr addr, int size,
|
|||
// baseReq.nicReq = true;
|
||||
baseReq.setTime(curTick);
|
||||
|
||||
completionEvent = event;
|
||||
|
||||
for (ChunkGenerator gen(addr, size, peerBlockSize());
|
||||
!gen.done(); gen.next()) {
|
||||
Packet *pkt = new Packet(basePkt);
|
||||
|
@ -175,7 +174,15 @@ DmaPort::dmaAction(Command cmd, DmaPort port, Addr addr, int size,
|
|||
// Increment the data pointer on a write
|
||||
pkt->data = data ? data + prevSize : NULL ;
|
||||
prevSize += pkt->size;
|
||||
// Set the last bit of the dma as the final packet for this dma
|
||||
// and set it's completion event.
|
||||
if (prevSize == size) {
|
||||
DmaReqState *state = new DmaReqState(event, true);
|
||||
|
||||
pkt->senderState = (void*)state;
|
||||
}
|
||||
assert(pendingCount >= 0);
|
||||
pendingCount++;
|
||||
sendDma(*pkt);
|
||||
}
|
||||
}
|
||||
|
@ -194,8 +201,12 @@ DmaPort::sendDma(Packet &pkt)
|
|||
transmitList.push_back(&packet);
|
||||
} else if (state == Atomic) {*/
|
||||
sendAtomic(pkt);
|
||||
completionEvent->schedule(pkt.time - pkt.req->getTime());
|
||||
completionEvent = NULL;
|
||||
if (pkt.senderState) {
|
||||
DmaReqState *state = (DmaReqState*)pkt.senderState;
|
||||
state->completionEvent->schedule(curTick + (pkt.time - pkt.req->getTime()) +1);
|
||||
}
|
||||
pendingCount--;
|
||||
assert(pendingCount >= 0);
|
||||
/* } else if (state == Functional) {
|
||||
sendFunctional(pkt);
|
||||
// Is this correct???
|
||||
|
|
|
@ -113,13 +113,28 @@ class PioPort : public Port
|
|||
friend class PioPort::SendEvent;
|
||||
};
|
||||
|
||||
|
||||
struct DmaReqState
|
||||
{
|
||||
Event *completionEvent;
|
||||
bool final;
|
||||
DmaReqState(Event *ce, bool f)
|
||||
: completionEvent(ce), final(f)
|
||||
{}
|
||||
};
|
||||
|
||||
class DmaPort : public Port
|
||||
{
|
||||
protected:
|
||||
PioDevice *device;
|
||||
DmaDevice *device;
|
||||
std::list<Packet*> transmitList;
|
||||
Event *completionEvent;
|
||||
|
||||
/** The platform that device/port are in. This is used to select which mode
|
||||
* we are currently operating in. */
|
||||
Platform *platform;
|
||||
|
||||
/** Number of outstanding packets the dma port has. */
|
||||
int pendingCount;
|
||||
|
||||
virtual bool recvTiming(Packet &pkt);
|
||||
virtual Tick recvAtomic(Packet &pkt)
|
||||
|
@ -152,13 +167,15 @@ class DmaPort : public Port
|
|||
friend class DmaPort;
|
||||
};
|
||||
|
||||
void dmaAction(Command cmd, DmaPort port, Addr addr, int size,
|
||||
Event *event, uint8_t *data = NULL);
|
||||
|
||||
void sendDma(Packet &pkt);
|
||||
|
||||
public:
|
||||
DmaPort(DmaDevice *dev);
|
||||
DmaPort(DmaDevice *dev, Platform *p);
|
||||
|
||||
void dmaAction(Command cmd, Addr addr, int size, Event *event,
|
||||
uint8_t *data = NULL);
|
||||
|
||||
bool dmaPending() { return pendingCount > 0; }
|
||||
|
||||
friend class DmaPort::SendEvent;
|
||||
|
||||
|
@ -286,13 +303,27 @@ class DmaDevice : public PioDevice
|
|||
DmaDevice(Params *p);
|
||||
virtual ~DmaDevice();
|
||||
|
||||
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data)
|
||||
{ dmaPort->dmaAction(Write, addr, size, event, data) ; }
|
||||
|
||||
void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL)
|
||||
{ dmaPort->dmaAction(Read, addr, size, event, data); }
|
||||
|
||||
bool dmaPending() { return dmaPort->dmaPending(); }
|
||||
|
||||
virtual Port *getPort(const std::string &if_name)
|
||||
{
|
||||
if (if_name == "pio")
|
||||
if (if_name == "pio") {
|
||||
if (pioPort != NULL)
|
||||
panic("pio port already connected to.");
|
||||
pioPort = new PioPort(this, params()->platform);
|
||||
return pioPort;
|
||||
else if (if_name == "dma")
|
||||
} else if (if_name == "dma") {
|
||||
if (dmaPort != NULL)
|
||||
panic("dma port already connected to.");
|
||||
dmaPort = new DmaPort(this, params()->platform);
|
||||
return dmaPort;
|
||||
else
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#include "base/trace.hh"
|
||||
#include "dev/pciconfigall.hh"
|
||||
//#include "dev/pcidev.hh"
|
||||
#include "dev/pcidev.hh"
|
||||
#include "dev/pcireg.h"
|
||||
#include "dev/platform.hh"
|
||||
#include "mem/packet.hh"
|
||||
|
@ -68,7 +68,7 @@ PciConfigAll::PciConfigAll(Params *p)
|
|||
void
|
||||
PciConfigAll::startup()
|
||||
{
|
||||
/* bitset<256> intLines;
|
||||
bitset<256> intLines;
|
||||
PciDev *tempDev;
|
||||
uint8_t intline;
|
||||
|
||||
|
@ -85,7 +85,7 @@ PciConfigAll::startup()
|
|||
} // devices != NULL
|
||||
} // PCI_FUNC
|
||||
} // PCI_DEV
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
Tick
|
||||
|
@ -97,7 +97,7 @@ PciConfigAll::read(Packet &pkt)
|
|||
Addr daddr = pkt.addr - pioAddr;
|
||||
int device = (daddr >> 11) & 0x1F;
|
||||
int func = (daddr >> 8) & 0x7;
|
||||
//int reg = daddr & 0xFF;
|
||||
int reg = daddr & 0xFF;
|
||||
|
||||
pkt.time = curTick + pioDelay;
|
||||
|
||||
|
@ -131,7 +131,7 @@ PciConfigAll::read(Packet &pkt)
|
|||
if (devices[device][func] == NULL)
|
||||
*data32 = 0xFFFFFFFF;
|
||||
else
|
||||
;//devices[device][func]->readConfig(reg, req.size, data32);
|
||||
devices[device][func]->readConfig(reg, data32);
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
if (!pkt.data) {
|
||||
|
@ -143,7 +143,7 @@ PciConfigAll::read(Packet &pkt)
|
|||
if (devices[device][func] == NULL)
|
||||
*data16 = 0xFFFF;
|
||||
else
|
||||
;//devices[device][func]->readConfig(reg, req.size, data16);
|
||||
devices[device][func]->readConfig(reg, data16);
|
||||
break;
|
||||
case sizeof(uint8_t):
|
||||
if (!pkt.data) {
|
||||
|
@ -155,7 +155,7 @@ PciConfigAll::read(Packet &pkt)
|
|||
if (devices[device][func] == NULL)
|
||||
*data8 = 0xFF;
|
||||
else
|
||||
;//devices[device][func]->readConfig(reg, req.size, data8);
|
||||
devices[device][func]->readConfig(reg, data8);
|
||||
break;
|
||||
default:
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
|
@ -177,7 +177,7 @@ PciConfigAll::write(Packet &pkt)
|
|||
|
||||
int device = (daddr >> 11) & 0x1F;
|
||||
int func = (daddr >> 8) & 0x7;
|
||||
// int reg = daddr & 0xFF;
|
||||
int reg = daddr & 0xFF;
|
||||
|
||||
if (devices[device][func] == NULL)
|
||||
panic("Attempting to write to config space on non-existant device\n");
|
||||
|
@ -185,8 +185,19 @@ PciConfigAll::write(Packet &pkt)
|
|||
DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
|
||||
pkt.addr, pkt.size, *(uint32_t*)pkt.data);
|
||||
|
||||
// devices[device][func]->writeConfig(reg, req->size, data);
|
||||
|
||||
switch (pkt.size) {
|
||||
case sizeof(uint8_t):
|
||||
devices[device][func]->writeConfig(reg, *pkt.data);
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
devices[device][func]->writeConfig(reg, *(uint16_t*)pkt.data);
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
devices[device][func]->writeConfig(reg, *(uint32_t*)pkt.data);
|
||||
break;
|
||||
default:
|
||||
panic("invalid pci config write size\n");
|
||||
}
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,8 +54,6 @@ class PciDev;
|
|||
class PciConfigAll : public BasicPioDevice
|
||||
{
|
||||
private:
|
||||
static const Addr size = 0xffffff;
|
||||
|
||||
/**
|
||||
* Pointers to all the devices that are registered with this
|
||||
* particular config space.
|
||||
|
|
332
dev/pcidev.cc
332
dev/pcidev.cc
|
@ -39,20 +39,20 @@
|
|||
#include "base/misc.hh"
|
||||
#include "base/str.hh" // for to_number
|
||||
#include "base/trace.hh"
|
||||
#include "dev/pcidev.hh"
|
||||
#include "dev/pciconfigall.hh"
|
||||
#include "mem/bus/bus.hh"
|
||||
#include "mem/functional/memory_control.hh"
|
||||
#include "dev/pcidev.hh"
|
||||
#include "dev/tsunamireg.h"
|
||||
#include "mem/packet.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/byteswap.hh"
|
||||
#include "sim/param.hh"
|
||||
#include "sim/root.hh"
|
||||
#include "dev/tsunamireg.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
PciDev::PciDev(Params *p)
|
||||
: DmaDevice(p->name, p->plat), _params(p), plat(p->plat),
|
||||
configData(p->configData)
|
||||
: DmaDevice(p), plat(p->platform), configData(p->configData),
|
||||
pioDelay(p->pio_delay)
|
||||
{
|
||||
// copy the config data from the PciConfigData object
|
||||
if (configData) {
|
||||
|
@ -70,214 +70,180 @@ PciDev::PciDev(Params *p)
|
|||
p->configSpace->registerDevice(p->deviceNum, p->functionNum, this);
|
||||
}
|
||||
|
||||
Fault
|
||||
PciDev::read(MemReqPtr &req, uint8_t *data)
|
||||
{ return NoFault; }
|
||||
|
||||
Fault
|
||||
PciDev::write(MemReqPtr &req, const uint8_t *data)
|
||||
{ return NoFault; }
|
||||
|
||||
Fault
|
||||
PciDev::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::readBar1(MemReqPtr &req, Addr daddr, uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::readBar2(MemReqPtr &req, Addr daddr, uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::readBar3(MemReqPtr &req, Addr daddr, uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::readBar4(MemReqPtr &req, Addr daddr, uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::readBar5(MemReqPtr &req, Addr daddr, uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
Fault
|
||||
PciDev::writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data)
|
||||
{ panic("not implemented"); }
|
||||
|
||||
void
|
||||
PciDev::readConfig(int offset, int size, uint8_t *data)
|
||||
PciDev::readConfig(int offset, uint8_t *data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
switch(size) {
|
||||
case sizeof(uint8_t):
|
||||
*data = config.data[offset];
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
*(uint16_t*)data = *(uint16_t*)&config.data[offset];
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
*(uint32_t*)data = *(uint32_t*)&config.data[offset];
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration read size!\n");
|
||||
}
|
||||
*data = config.data[offset];
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, size,
|
||||
*(uint32_t*)data);
|
||||
"read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, *data);
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::writeConfig(int offset, int size, const uint8_t *data)
|
||||
PciDev::addressRanges(AddrRangeList &range_list)
|
||||
{
|
||||
int x = 0;
|
||||
range_list.clear();
|
||||
for (x = 0; x < 6; x++)
|
||||
if (BARAddrs[x] != 0)
|
||||
range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::readConfig(int offset, uint16_t *data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
uint8_t &data8 = *(uint8_t*)data;
|
||||
uint16_t &data16 = *(uint16_t*)data;
|
||||
uint32_t &data32 = *(uint32_t*)data;
|
||||
*data = *(uint16_t*)&config.data[offset];
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: %d data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, size, data32);
|
||||
"read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, *data);
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case sizeof(uint8_t): // 1-byte access
|
||||
switch (offset) {
|
||||
case PCI0_INTERRUPT_LINE:
|
||||
config.interruptLine = data8;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data8;
|
||||
case PCI_LATENCY_TIMER:
|
||||
config.latencyTimer = data8;
|
||||
break;
|
||||
/* Do nothing for these read-only registers */
|
||||
case PCI0_INTERRUPT_PIN:
|
||||
case PCI0_MINIMUM_GRANT:
|
||||
case PCI0_MAXIMUM_LATENCY:
|
||||
case PCI_CLASS_CODE:
|
||||
case PCI_REVISION_ID:
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
void
|
||||
PciDev::readConfig(int offset, uint32_t *data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
*data = *(uint32_t*)&config.data[offset];
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, *data);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PciDev::writeConfig(int offset, const uint8_t data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: 1 data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCI0_INTERRUPT_LINE:
|
||||
config.interruptLine = data;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data;
|
||||
case PCI_LATENCY_TIMER:
|
||||
config.latencyTimer = data;
|
||||
break;
|
||||
|
||||
case sizeof(uint16_t): // 2-byte access
|
||||
switch (offset) {
|
||||
case PCI_COMMAND:
|
||||
config.command = data16;
|
||||
case PCI_STATUS:
|
||||
config.status = data16;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data16;
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
/* Do nothing for these read-only registers */
|
||||
case PCI0_INTERRUPT_PIN:
|
||||
case PCI0_MINIMUM_GRANT:
|
||||
case PCI0_MAXIMUM_LATENCY:
|
||||
case PCI_CLASS_CODE:
|
||||
case PCI_REVISION_ID:
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
}
|
||||
|
||||
case sizeof(uint32_t): // 4-byte access
|
||||
switch (offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
case PCI0_BASE_ADDR1:
|
||||
case PCI0_BASE_ADDR2:
|
||||
case PCI0_BASE_ADDR3:
|
||||
case PCI0_BASE_ADDR4:
|
||||
case PCI0_BASE_ADDR5:
|
||||
void
|
||||
PciDev::writeConfig(int offset, const uint16_t data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
uint32_t barnum, bar_mask;
|
||||
Addr base_addr, base_size, space_base;
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: 2 data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, data);
|
||||
|
||||
barnum = BAR_NUMBER(offset);
|
||||
switch (offset) {
|
||||
case PCI_COMMAND:
|
||||
config.command = data;
|
||||
case PCI_STATUS:
|
||||
config.status = data;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data;
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
}
|
||||
|
||||
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
|
||||
bar_mask = BAR_IO_MASK;
|
||||
space_base = TSUNAMI_PCI0_IO;
|
||||
} else {
|
||||
bar_mask = BAR_MEM_MASK;
|
||||
space_base = TSUNAMI_PCI0_MEMORY;
|
||||
}
|
||||
|
||||
// Writing 0xffffffff to a BAR tells the card to set the
|
||||
// value of the bar to size of memory it needs
|
||||
if (letoh(data32) == 0xffffffff) {
|
||||
// This is I/O Space, bottom two bits are read only
|
||||
void
|
||||
PciDev::writeConfig(int offset, const uint32_t data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(~(BARSize[barnum] - 1) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
} else {
|
||||
MemoryController *mmu = params()->mmu;
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: 4 data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, data);
|
||||
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(letoh(data32) & ~bar_mask) |
|
||||
switch (offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
case PCI0_BASE_ADDR1:
|
||||
case PCI0_BASE_ADDR2:
|
||||
case PCI0_BASE_ADDR3:
|
||||
case PCI0_BASE_ADDR4:
|
||||
case PCI0_BASE_ADDR5:
|
||||
|
||||
uint32_t barnum, bar_mask;
|
||||
Addr base_addr, base_size, space_base;
|
||||
|
||||
barnum = BAR_NUMBER(offset);
|
||||
|
||||
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
|
||||
bar_mask = BAR_IO_MASK;
|
||||
space_base = TSUNAMI_PCI0_IO;
|
||||
} else {
|
||||
bar_mask = BAR_MEM_MASK;
|
||||
space_base = TSUNAMI_PCI0_MEMORY;
|
||||
}
|
||||
|
||||
// Writing 0xffffffff to a BAR tells the card to set the
|
||||
// value of the bar to size of memory it needs
|
||||
if (letoh(data) == 0xffffffff) {
|
||||
// This is I/O Space, bottom two bits are read only
|
||||
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(~(BARSize[barnum] - 1) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
} else {
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(letoh(data) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
|
||||
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
|
||||
base_addr = (letoh(data32) & ~bar_mask) + space_base;
|
||||
base_size = BARSize[barnum];
|
||||
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
|
||||
base_addr = (letoh(data) & ~bar_mask) + space_base;
|
||||
base_size = BARSize[barnum];
|
||||
BARAddrs[barnum] = base_addr;
|
||||
|
||||
// It's never been set
|
||||
if (BARAddrs[barnum] == 0)
|
||||
mmu->add_child((FunctionalMemory *)this,
|
||||
RangeSize(base_addr, base_size));
|
||||
else
|
||||
mmu->update_child((FunctionalMemory *)this,
|
||||
RangeSize(BARAddrs[barnum], base_size),
|
||||
RangeSize(base_addr, base_size));
|
||||
|
||||
BARAddrs[barnum] = base_addr;
|
||||
}
|
||||
pioPort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_ROM_BASE_ADDR:
|
||||
if (letoh(data32) == 0xfffffffe)
|
||||
config.expansionROM = htole((uint32_t)0xffffffff);
|
||||
else
|
||||
config.expansionROM = data32;
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
// This could also clear some of the error bits in the Status
|
||||
// register. However they should never get set, so lets ignore
|
||||
// it for now
|
||||
config.command = data16;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(PCIDEV, "Writing to a read only register");
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_ROM_BASE_ADDR:
|
||||
if (letoh(data) == 0xfffffffe)
|
||||
config.expansionROM = htole((uint32_t)0xffffffff);
|
||||
else
|
||||
config.expansionROM = data;
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
// This could also clear some of the error bits in the Status
|
||||
// register. However they should never get set, so lets ignore
|
||||
// it for now
|
||||
config.command = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("invalid access size");
|
||||
DPRINTF(PCIDEV, "Writing to a read only register");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,12 +262,6 @@ PciDev::unserialize(Checkpoint *cp, const std::string §ion)
|
|||
UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
|
||||
UNSERIALIZE_ARRAY(config.data,
|
||||
sizeof(config.data) / sizeof(config.data[0]));
|
||||
|
||||
// Add the MMU mappings for the BARs
|
||||
for (int i=0; i < 6; i++) {
|
||||
if (BARAddrs[i] != 0)
|
||||
params()->mmu->add_child(this, RangeSize(BARAddrs[i], BARSize[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
|
102
dev/pcidev.hh
102
dev/pcidev.hh
|
@ -44,7 +44,6 @@
|
|||
#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
|
||||
|
||||
class PciConfigAll;
|
||||
class MemoryController;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -85,12 +84,8 @@ class PciConfigData : public SimObject
|
|||
class PciDev : public DmaDevice
|
||||
{
|
||||
public:
|
||||
struct Params
|
||||
struct Params : public ::PioDevice::Params
|
||||
{
|
||||
std::string name;
|
||||
Platform *plat;
|
||||
MemoryController *mmu;
|
||||
|
||||
/**
|
||||
* A pointer to the configspace all object that calls us when
|
||||
* a read comes to this particular device/function.
|
||||
|
@ -111,13 +106,13 @@ class PciDev : public DmaDevice
|
|||
|
||||
/** The function number */
|
||||
uint32_t functionNum;
|
||||
|
||||
/** The latency for pio accesses. */
|
||||
Tick pio_delay;
|
||||
};
|
||||
|
||||
protected:
|
||||
Params *_params;
|
||||
|
||||
public:
|
||||
const Params *params() const { return _params; }
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
protected:
|
||||
/** The current config space. Unlike the PciConfigData this is
|
||||
|
@ -164,6 +159,7 @@ class PciDev : public DmaDevice
|
|||
protected:
|
||||
Platform *plat;
|
||||
PciConfigData *configData;
|
||||
Tick pioDelay;
|
||||
|
||||
public:
|
||||
Addr pciToDma(Addr pciAddr) const
|
||||
|
@ -181,7 +177,11 @@ class PciDev : public DmaDevice
|
|||
interruptLine()
|
||||
{ return configData->config.interruptLine; }
|
||||
|
||||
public:
|
||||
/** return the address ranges that this device responds to.
|
||||
* @params range_list range list to populate with ranges
|
||||
*/
|
||||
void addressRanges(AddrRangeList &range_list);
|
||||
|
||||
/**
|
||||
* Constructor for PCI Dev. This function copies data from the
|
||||
* config file object PCIConfigData and registers the device with
|
||||
|
@ -189,39 +189,6 @@ class PciDev : public DmaDevice
|
|||
*/
|
||||
PciDev(Params *params);
|
||||
|
||||
virtual Fault read(MemReqPtr &req, uint8_t *data);
|
||||
virtual Fault write(MemReqPtr &req, const uint8_t *data);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Implement the read/write as BAR accesses
|
||||
*/
|
||||
Fault readBar(MemReqPtr &req, uint8_t *data);
|
||||
Fault writeBar(MemReqPtr &req, const uint8_t *data);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Read from a specific BAR
|
||||
*/
|
||||
virtual Fault readBar0(MemReqPtr &req, Addr daddr, uint8_t *data);
|
||||
virtual Fault readBar1(MemReqPtr &req, Addr daddr, uint8_t *data);
|
||||
virtual Fault readBar2(MemReqPtr &req, Addr daddr, uint8_t *data);
|
||||
virtual Fault readBar3(MemReqPtr &req, Addr daddr, uint8_t *data);
|
||||
virtual Fault readBar4(MemReqPtr &req, Addr daddr, uint8_t *data);
|
||||
virtual Fault readBar5(MemReqPtr &req, Addr daddr, uint8_t *data);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Write to a specific BAR
|
||||
*/
|
||||
virtual Fault writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data);
|
||||
virtual Fault writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data);
|
||||
virtual Fault writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data);
|
||||
virtual Fault writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data);
|
||||
virtual Fault writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data);
|
||||
virtual Fault writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Write to the PCI config space data that is stored locally. This may be
|
||||
* overridden by the device but at some point it will eventually call this
|
||||
|
@ -230,7 +197,9 @@ class PciDev : public DmaDevice
|
|||
* @param size the size of the write
|
||||
* @param data the data to write
|
||||
*/
|
||||
virtual void writeConfig(int offset, int size, const uint8_t* data);
|
||||
virtual void writeConfig(int offset, const uint8_t data);
|
||||
virtual void writeConfig(int offset, const uint16_t data);
|
||||
virtual void writeConfig(int offset, const uint32_t data);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -241,7 +210,9 @@ class PciDev : public DmaDevice
|
|||
* @param size the size of the read
|
||||
* @param data pointer to the location where the read value should be stored
|
||||
*/
|
||||
virtual void readConfig(int offset, int size, uint8_t *data);
|
||||
virtual void readConfig(int offset, uint8_t *data);
|
||||
virtual void readConfig(int offset, uint16_t *data);
|
||||
virtual void readConfig(int offset, uint32_t *data);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
|
@ -256,43 +227,4 @@ class PciDev : public DmaDevice
|
|||
*/
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
};
|
||||
|
||||
inline Fault
|
||||
PciDev::readBar(MemReqPtr &req, uint8_t *data)
|
||||
{
|
||||
using namespace TheISA;
|
||||
if (isBAR(req->paddr, 0))
|
||||
return readBar0(req, req->paddr - BARAddrs[0], data);
|
||||
if (isBAR(req->paddr, 1))
|
||||
return readBar1(req, req->paddr - BARAddrs[1], data);
|
||||
if (isBAR(req->paddr, 2))
|
||||
return readBar2(req, req->paddr - BARAddrs[2], data);
|
||||
if (isBAR(req->paddr, 3))
|
||||
return readBar3(req, req->paddr - BARAddrs[3], data);
|
||||
if (isBAR(req->paddr, 4))
|
||||
return readBar4(req, req->paddr - BARAddrs[4], data);
|
||||
if (isBAR(req->paddr, 5))
|
||||
return readBar5(req, req->paddr - BARAddrs[5], data);
|
||||
return genMachineCheckFault();
|
||||
}
|
||||
|
||||
inline Fault
|
||||
PciDev::writeBar(MemReqPtr &req, const uint8_t *data)
|
||||
{
|
||||
using namespace TheISA;
|
||||
if (isBAR(req->paddr, 0))
|
||||
return writeBar0(req, req->paddr - BARAddrs[0], data);
|
||||
if (isBAR(req->paddr, 1))
|
||||
return writeBar1(req, req->paddr - BARAddrs[1], data);
|
||||
if (isBAR(req->paddr, 2))
|
||||
return writeBar2(req, req->paddr - BARAddrs[2], data);
|
||||
if (isBAR(req->paddr, 3))
|
||||
return writeBar3(req, req->paddr - BARAddrs[3], data);
|
||||
if (isBAR(req->paddr, 4))
|
||||
return writeBar4(req, req->paddr - BARAddrs[4], data);
|
||||
if (isBAR(req->paddr, 5))
|
||||
return writeBar5(req, req->paddr - BARAddrs[5], data);
|
||||
return genMachineCheckFault();
|
||||
}
|
||||
|
||||
#endif // __DEV_PCIDEV_HH__
|
||||
|
|
27
mem/bus.cc
27
mem/bus.cc
|
@ -97,21 +97,30 @@ Bus::recvStatusChange(Port::Status status, int id)
|
|||
Port *port = interfaces[id];
|
||||
AddrRangeList ranges;
|
||||
AddrRangeList snoops;
|
||||
AddrRangeIter iter;
|
||||
std::vector<DevMap>::iterator portIter;
|
||||
|
||||
// Clean out any previously existent ids
|
||||
for (portIter = portList.begin(); portIter != portList.end(); ) {
|
||||
if (portIter->portId == id)
|
||||
portIter = portList.erase(portIter);
|
||||
else
|
||||
portIter++;
|
||||
}
|
||||
|
||||
port->getPeerAddressRanges(ranges, snoops);
|
||||
|
||||
// not dealing with snooping yet either
|
||||
assert(snoops.size() == 0);
|
||||
// or multiple ranges
|
||||
assert(ranges.size() == 1);
|
||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||
DevMap dm;
|
||||
dm.portId = id;
|
||||
dm.range = *iter;
|
||||
|
||||
DevMap dm;
|
||||
dm.portId = id;
|
||||
dm.range = ranges.front();
|
||||
|
||||
DPRINTF(MMU, "Adding range %llx - %llx for id %d\n", dm.range.start,
|
||||
dm.range.end, id);
|
||||
portList.push_back(dm);
|
||||
DPRINTF(MMU, "Adding range %llx - %llx for id %d\n", dm.range.start,
|
||||
dm.range.end, id);
|
||||
portList.push_back(dm);
|
||||
}
|
||||
DPRINTF(MMU, "port list has %d entries\n", portList.size());
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ struct Packet
|
|||
// assert(dynamic_cast<Foo>) etc.
|
||||
|
||||
/** A virtual base opaque structure used to hold the senders state. */
|
||||
SenderState *senderState; // virtual base opaque,
|
||||
void *senderState; // virtual base opaque,
|
||||
// assert(dynamic_cast<Foo>) etc.
|
||||
|
||||
/** A pointer to the data being transfered. It can be differnt sizes
|
||||
|
|
|
@ -69,8 +69,8 @@ PhysicalMemory::MemResponseEvent::description()
|
|||
return "Physical Memory Timing Access respnse event";
|
||||
}
|
||||
|
||||
PhysicalMemory::PhysicalMemory(const string &n)
|
||||
: MemObject(n), base_addr(0), pmem_addr(NULL), port(NULL)
|
||||
PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
|
||||
: MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
|
||||
{
|
||||
// Hardcoded to 128 MB for now.
|
||||
pmem_size = 1 << 27;
|
||||
|
@ -137,6 +137,7 @@ Tick
|
|||
PhysicalMemory::doAtomicAccess(Packet &pkt)
|
||||
{
|
||||
doFunctionalAccess(pkt);
|
||||
pkt.time = curTick + lat;
|
||||
return curTick + lat;
|
||||
}
|
||||
|
||||
|
@ -344,20 +345,22 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
|
|||
|
||||
Param<string> file;
|
||||
Param<Range<Addr> > range;
|
||||
Param<Tick> latency;
|
||||
|
||||
END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
|
||||
|
||||
BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
|
||||
|
||||
INIT_PARAM_DFLT(file, "memory mapped file", ""),
|
||||
INIT_PARAM(range, "Device Address Range")
|
||||
INIT_PARAM(range, "Device Address Range"),
|
||||
INIT_PARAM(latency, "Memory access latency")
|
||||
|
||||
END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
|
||||
|
||||
CREATE_SIM_OBJECT(PhysicalMemory)
|
||||
{
|
||||
|
||||
return new PhysicalMemory(getInstanceName());
|
||||
return new PhysicalMemory(getInstanceName(), latency);
|
||||
}
|
||||
|
||||
REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
|
||||
|
|
|
@ -71,7 +71,6 @@ class PhysicalMemory : public MemObject
|
|||
|
||||
int numPorts;
|
||||
|
||||
int lat;
|
||||
|
||||
struct MemResponseEvent : public Event
|
||||
{
|
||||
|
@ -94,13 +93,14 @@ class PhysicalMemory : public MemObject
|
|||
uint8_t *pmem_addr;
|
||||
MemoryPort *port;
|
||||
int page_ptr;
|
||||
Tick lat;
|
||||
|
||||
public:
|
||||
Addr new_page();
|
||||
uint64_t size() { return pmem_size; }
|
||||
|
||||
public:
|
||||
PhysicalMemory(const std::string &n);
|
||||
PhysicalMemory(const std::string &n, Tick latency);
|
||||
virtual ~PhysicalMemory();
|
||||
|
||||
public:
|
||||
|
|
|
@ -12,3 +12,7 @@ class BasicPioDevice(PioDevice):
|
|||
abstract = True
|
||||
pio_addr = Param.Addr("Device Address")
|
||||
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
|
||||
|
||||
class DmaDevice(PioDevice):
|
||||
type = 'DmaDevice'
|
||||
abstract = True
|
||||
|
|
|
@ -8,7 +8,6 @@ class IdeDisk(SimObject):
|
|||
delay = Param.Latency('1us', "Fixed disk delay in microseconds")
|
||||
driveID = Param.IdeID('master', "Drive ID")
|
||||
image = Param.DiskImage("Disk image")
|
||||
physmem = Param.PhysicalMemory(Parent.any, "Physical memory")
|
||||
|
||||
class IdeController(PciDevice):
|
||||
type = 'IdeController'
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from m5 import *
|
||||
from Device import BasicPioDevice
|
||||
#, DmaDevice
|
||||
from Device import BasicPioDevice, DmaDevice
|
||||
|
||||
class PciConfigData(SimObject):
|
||||
type = 'PciConfigData'
|
||||
|
@ -42,15 +41,15 @@ class PciConfigData(SimObject):
|
|||
class PciConfigAll(BasicPioDevice):
|
||||
type = 'PciConfigAll'
|
||||
|
||||
#class PciDevice(DmaDevice):
|
||||
# type = 'PciDevice'
|
||||
# abstract = True
|
||||
# addr = 0xffffffffL
|
||||
# pci_bus = Param.Int("PCI bus")
|
||||
# pci_dev = Param.Int("PCI device number")
|
||||
# pci_func = Param.Int("PCI function code")
|
||||
# configdata = Param.PciConfigData(Parent.any, "PCI Config data")
|
||||
# configspace = Param.PciConfigAll(Parent.any, "PCI Configspace")
|
||||
#
|
||||
#class PciFake(PciDevice):
|
||||
# type = 'PciFake'
|
||||
class PciDevice(DmaDevice):
|
||||
type = 'PciDevice'
|
||||
abstract = True
|
||||
pci_bus = Param.Int("PCI bus")
|
||||
pci_dev = Param.Int("PCI device number")
|
||||
pci_func = Param.Int("PCI function code")
|
||||
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
|
||||
configdata = Param.PciConfigData(Parent.any, "PCI Config data")
|
||||
configspace = Param.PciConfigAll(Parent.any, "PCI Configspace")
|
||||
|
||||
class PciFake(PciDevice):
|
||||
type = 'PciFake'
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from m5 import *
|
||||
from Memory import Memory
|
||||
from MemObject import *
|
||||
|
||||
class PhysicalMemory(Memory):
|
||||
class PhysicalMemory(MemObject):
|
||||
type = 'PhysicalMemory'
|
||||
range = Param.AddrRange("Device Address")
|
||||
file = Param.String('', "memory mapped file")
|
||||
latency = Param.Latency('10ns', "latency of an access")
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
// This lets us figure out what the byte order of the host system is
|
||||
#if defined(linux)
|
||||
#include <endian.h>
|
||||
// If this is a linux system, lets used the optimized definitions if they exist.
|
||||
// If one doesn't exist, we pretty much get what is listed below, so it all
|
||||
// works out
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
|
@ -47,6 +51,9 @@
|
|||
static inline uint64_t
|
||||
swap_byte64(uint64_t x)
|
||||
{
|
||||
#if defined(linux)
|
||||
return bswap_64(x);
|
||||
#else
|
||||
return (uint64_t)((((uint64_t)(x) & 0xff) << 56) |
|
||||
((uint64_t)(x) & 0xff00ULL) << 40 |
|
||||
((uint64_t)(x) & 0xff0000ULL) << 24 |
|
||||
|
@ -55,22 +62,30 @@ swap_byte64(uint64_t x)
|
|||
((uint64_t)(x) & 0xff0000000000ULL) >> 24 |
|
||||
((uint64_t)(x) & 0xff000000000000ULL) >> 40 |
|
||||
((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
swap_byte32(uint32_t x)
|
||||
{
|
||||
#if defined(linux)
|
||||
return bswap_32(x);
|
||||
#else
|
||||
return (uint32_t)(((uint32_t)(x) & 0xff) << 24 |
|
||||
((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 |
|
||||
((uint32_t)(x) & 0xff000000) >> 24);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
swap_byte16(uint16_t x)
|
||||
{
|
||||
#if defined(linux)
|
||||
return bswap_16(x);
|
||||
#else
|
||||
return (uint16_t)(((uint16_t)(x) & 0xff) << 8 |
|
||||
((uint16_t)(x) & 0xff00) >> 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
//This lets the compiler figure out how to call the swap_byte functions above
|
||||
|
|
Loading…
Reference in a new issue