#include #include "simul.h" /* --- bus read/write --- */ #define SwapEndian(BE) (((BE)>>24)|(((BE)&0x00FF0000)>>8)|(((BE)&0x0000FF00)<<8)|(((BE)&0x00FF)<<24)) static int bus2longreg(simulBusCallbackStruct * bus, simulWord32 * reg) { switch (bus->width) { case 8: *reg = (*reg & ~(0xff << ((~bus->address & 0x3) << 3))) | (bus->data << ((~bus->address & 0x3) << 3)); break; case 16: if (bus->address & 0x1) return SIMUL_MEMORY_FAIL; *reg = (*reg & ~(0xffff << ((~bus->address & 0x2) << 3))) | (bus->data << ((~bus->address & 0x2) << 3)); break; case 32: if (bus->address & 0x3) return SIMUL_MEMORY_FAIL; *reg = bus->data; break; default: return SIMUL_MEMORY_FAIL; } return SIMUL_MEMORY_OK; } static int longreg2bus(simulBusCallbackStruct * bus, simulWord32 * reg) { switch (bus->width) { case 8: bus->data = (*reg >> ((~bus->address & 0x3) << 3)) & 0xff; break; case 16: if (bus->address & 0x1) return SIMUL_MEMORY_FAIL; bus->data = (*reg >> ((~bus->address & 0x2) << 3)) & 0xffff; break; case 32: if (bus->address & 0x3) return SIMUL_MEMORY_FAIL; bus->data = *reg; break; default: return SIMUL_MEMORY_FAIL; } return SIMUL_MEMORY_OK; } /* --- Regs I/O --- */ typedef struct { enum { MAP_A, MAP_B } nPciMap; simulWord32 nCurrentConfig; unsigned char pPciMapSpace[0x10004]; } PCIData_t; static int SIMULAPI PCI_ConfigWrite(simulProcessor processor, simulCallbackStruct * cbs, simulPtr perContext) { PCIData_t* pciData = (PCIData_t*) perContext; simulWord32 config; cbs->x.bus.clocks = 1; bus2longreg(&cbs->x.bus, &config); pciData->nCurrentConfig = SwapEndian(config) & 0x80FFFFFC; return SIMUL_MEMORY_OK; } static int SIMULAPI PCI_ConfigRead(simulProcessor processor, simulCallbackStruct * cbs, simulPtr perContext) { PCIData_t* pciData = (PCIData_t*) perContext; simulWord32 config = SwapEndian(pciData->nCurrentConfig); cbs->x.bus.clocks = 1; return longreg2bus(&cbs->x.bus, &config); } static int SIMULAPI PCI_DataWrite(simulProcessor processor, simulCallbackStruct * cbs, simulPtr perContext) { PCIData_t* pciData = (PCIData_t*) perContext; cbs->x.bus.clocks = 1; if (pciData->nCurrentConfig & 0x80000000) { simulWord32 configAddr = (pciData->nCurrentConfig & ~0x80000000) + (cbs->x.bus.address & 0x00000003); if (configAddr < 0x10000) { simulWord32 data = cbs->x.bus.data; if (cbs->x.bus.width < 32) data <<= (32 - cbs->x.bus.width); switch (cbs->x.bus.width) { case 32: pciData->pPciMapSpace[configAddr++] = (data >> 24); data <<= 8; pciData->pPciMapSpace[configAddr++] = (data >> 24); data <<= 8; case 16: pciData->pPciMapSpace[configAddr++] = (data >> 24); data <<= 8; case 8: pciData->pPciMapSpace[configAddr++] = (data >> 24); data <<= 8; } } } return SIMUL_MEMORY_OK; } static int SIMULAPI PCI_DataRead(simulProcessor processor, simulCallbackStruct * cbs, simulPtr perContext) { PCIData_t* pciData = (PCIData_t*) perContext; cbs->x.bus.clocks = 1; if (pciData->nCurrentConfig & 0x80000000) { simulWord32 configAddr = (pciData->nCurrentConfig & ~0x80000000) + (cbs->x.bus.address & 0x00000003); if (configAddr < 0x10000) { simulWord32 data = 0; switch (cbs->x.bus.width) { case 32: data = (data << 8) | (pciData->pPciMapSpace[configAddr++]); data = (data << 8) | (pciData->pPciMapSpace[configAddr++]); case 16: data = (data << 8) | (pciData->pPciMapSpace[configAddr++]); case 8: data = (data << 8) | (pciData->pPciMapSpace[configAddr++]); } cbs->x.bus.data = data; } else { cbs->x.bus.data = 0xDEADDEAD; } } return SIMUL_MEMORY_OK; } static void PCI_Init(simulProcessor processor, PCIData_t* pciData, int map_b) { simulWord nConfigAddr, nConfigAddrEnd; simulWord nDataAddr, nDataAddrEnd; memset(pciData, 0, sizeof(PCIData_t)); pciData->nPciMap = map_b ? MAP_B : MAP_A; pciData->pPciMapSpace[0] = 0x57; pciData->pPciMapSpace[1] = 0x10; pciData->pPciMapSpace[2] = 0x03; pciData->pPciMapSpace[3] = 0x00; nConfigAddr = (pciData->nPciMap == MAP_A) ? 0x80000CF8 : 0xFEC00000; nDataAddr = (pciData->nPciMap == MAP_A) ? 0x80000CFC : 0xFEE00000; nConfigAddrEnd = nConfigAddr + 3; nDataAddrEnd = nDataAddr + 3; SIMUL_RegisterBusWriteCallback(processor, PCI_ConfigWrite, (simulPtr) pciData, 0, &nConfigAddr, &nConfigAddrEnd); SIMUL_RegisterBusReadCallback(processor, PCI_ConfigRead, (simulPtr) pciData, 0, &nConfigAddr, &nConfigAddrEnd); SIMUL_RegisterBusWriteCallback(processor, PCI_DataWrite, (simulPtr) pciData, 0, &nDataAddr, &nDataAddrEnd); SIMUL_RegisterBusReadCallback(processor, PCI_DataRead, (simulPtr) pciData, 0, &nDataAddr, &nDataAddrEnd); } int SIMULAPI SIMUL_Init(simulProcessor processor, simulCallbackStruct * cbs) { PCIData_t* pPciDataMapA; PCIData_t* pPciDataMapB; strcpy(cbs->x.init.modelname, __DATE__ "PowerPC PCI MAP A/B Configuration Space"); pPciDataMapA = (PCIData_t*) SIMUL_Alloc(processor, sizeof(PCIData_t)); PCI_Init(processor, pPciDataMapA, 0); pPciDataMapB = (PCIData_t*) SIMUL_Alloc(processor, sizeof(PCIData_t)); PCI_Init(processor, pPciDataMapB, 1); return SIMUL_INIT_OK; }