📄 simmagic.c
字号:
* Writes to this register have no effect. */ if (BDOOR_IS_LOAD(type)) *datap = (DevRegister)0; } else if (doff >= offsetof(DevDiskRegisters, k0Addr[0]) && doff <= offsetof(DevDiskRegisters, k0Addr[DEV_DISK_MAX_DMA_LENGTH-1])) { int ix = (doff-offsetof(DevDiskRegisters, k0Addr[0])) / sizeof(DevRegister); if (BDOOR_IS_LOAD(type)) { *datap = DISK_SHADOW(node,ctrl,unit).k0Addr[ix]; } else { DISK_SHADOW(node,ctrl,unit).k0Addr[ix] = *datap; } } else if (doff == offsetof(DevDiskRegisters, offset)) { if (BDOOR_IS_LOAD(type)) { *datap = DISK_SHADOW(node,ctrl,unit).offset; } else { DISK_SHADOW(node,ctrl,unit).offset = *datap; } } else if (doff >= offsetof(DevDiskRegisters, command[0]) && doff <= offsetof(DevDiskRegisters, command[DEV_DISK_CMD_SIZE-1])) { int ix = (doff-offsetof(DevDiskRegisters, command[0])) / sizeof(DevRegister); if (BDOOR_IS_LOAD(type)) { *datap = DISK_SHADOW(node,ctrl,unit).command[ix]; } else { DISK_SHADOW(node,ctrl,unit).command[ix] = *datap; } } else if (doff == offsetof(DevDiskRegisters, startIO)) { unsigned char cmd[SIM_DISK_CMD_SIZE]; PA pages[SIM_DISK_MAX_DMA_LENGTH]; int i; if (BDOOR_IS_LOAD(type)) goto illegal; /* note: bogus mapping (n,nd) -> SimOS disk #. To be improved */ ASSERT(DEV_DISK_MAX_DMA_LENGTH <= SIM_DISK_MAX_DMA_LENGTH); ASSERT(DEV_DISK_CMD_SIZE <= SIM_DISK_CMD_SIZE); for (i = 0; i < SIM_DISK_CMD_SIZE; i++) cmd[i] = (unsigned char)DISK_SHADOW(node,ctrl,unit).command[i]; for (i = 0; i < SIM_DISK_MAX_DMA_LENGTH; i++) pages[i] = DISK_SHADOW(node,ctrl,unit).k0Addr[i]; sim_disk_startio(node, ctrl, unit, cmd, pages, (int)DISK_SHADOW(node,ctrl,unit).offset); } else if (doff == offsetof(DevDiskRegisters, doneIO)) { if (BDOOR_IS_LOAD(type)) goto illegal; /* write is (almost) a no-op */ DISK_SHADOW(node,ctrl,unit).doneIO = (DevRegister)0; } else { /* bad disk offset */ ASSERT(0); return 0; } return 0; illegal: /* illegal access type */ ASSERT(0); return 1;}static voiddisk_interrupt(int node, int ctrl, int unit, int on){ int cpu; /* cpu to which interrupt is directed */ if (inCellMode) { /* in cell mode (1 machine), node is absolute CPU number. * Must send interrupt to first CPU of that cell. */ cpu = (node / CPUS_PER_CELL(0)) * CPUS_PER_CELL(0); /* CPU 0 in cell */ } else { /* otherwise, node encodes both a machine number and a node. * Must send interrupt to first CPU in that machine. */ cpu = FIRST_CPU(M_FROM_CPU(node)); }#if (DEBUG_MAGIC == 1) LogEntry("disk_interrupt", CPUVec.CurrentCpuNum(), "node=%d ctrl=%d unit=%d cpu=%d on=%d\n", node, ctrl, unit, cpu, on);#endif if (on) RaiseSlot(cpu, DEV_PCI_DISK_SLOT); else ClearSlot(cpu, DEV_PCI_DISK_SLOT);}/* CONSOLE device. * */static intconsole_handler(int cpuNum, int n, int offs, int type, void* buff){ DevRegister* datap = (DevRegister*)buff; int console; if (inCellMode) { console = n / CPUS_PER_CELL(0); /* XXX one console / cell */ } else { console = FIRST_CONSOLE(M_FROM_CPU(cpuNum)) + n; }#ifdef TORNADO ASSERT(n == cpuNum);#endif#if (DEBUG_MAGIC == 2) /* consoles are logged only if DEBUG_MAGIC is 2 -- PZ */ LogEntry("console_handler", cpuNum, "console=%d offs=0x%x t=%d data=0x%08x\n", console, offs, type, *datap);#endif /* we only handle DevRegister accesses and buserror all others */ ASSERT (BDOOR_SIZE(type) == sizeof(DevRegister)); switch (offs) { case offsetof(DevConsoleRegisters, intr_status): if (BDOOR_IS_LOAD(type)) { *datap = (DevRegister) sim_console_int_status(console); } else { sim_console_int_set(console, (int)*datap); } break; case offsetof(DevConsoleRegisters, data): if (BDOOR_IS_LOAD(type)) { *datap = (DevRegister) sim_console_in(console); } else { sim_console_out(console, (char)*datap); } break; default: ASSERT(0); } return 0;}static voidconsole_interrupt(int n, int on){ int cpu; if (inCellMode) { /* always interrupts first CPU in cell */ cpu = n * CPUS_PER_CELL(0); } else { cpu = FIRST_CPU(M_FROM_CONSOLE(n)); }#ifdef TORNADO /* Give to cpu n */ cpu = n;#endif if (on) RaiseSlot(cpu, DEV_PCI_CONSOLE_SLOT); else ClearSlot(cpu, DEV_PCI_CONSOLE_SLOT);}/* ETHERNET device. * */intether_handler(int cpuNum, int n, int offs, int type, void* buff){ DevRegister* datap = (DevRegister*)buff; int ctrl; if (inCellMode) { ctrl = n / CPUS_PER_CELL(0); /* XXX one console / cell */ } else { ctrl = FIRST_ETHER_CONTROLLER(M_FROM_CPU(cpuNum)) + n; }#if (DEBUG_MAGIC == 1) LogEntry("ether_handler", cpuNum, "ctrl=%d offs=0x%x t=%d data=0x%08x\n", ctrl, offs, type, *datap);#endif /* we only handle dword accesses and buserror all others */ ASSERT (BDOOR_SIZE(type) == sizeof(DevRegister)); /* NOTE: it so "happens" that the SimetherRegisters structure is * isomorphic to DevEtherRegisters. This helps us simplify the * mapping from the simulated registers to the ether simulator. */ if (BDOOR_IS_LOAD(type)) { *datap = (DevRegister)SimetherIO(ctrl, offs, 0, (DevRegister)0); } else { (void)SimetherIO(ctrl, offs, 1, (DevRegister)*datap); } return 0;}static voidether_interrupt(int n, int on){ /* always interrupt first cpu in cell */ int cpu; if (inCellMode) { cpu = n * CPUS_PER_CELL(0); } else { cpu = FIRST_CPU(M_FROM_ETHER_CONTROLLER(n)); } if (on) RaiseSlot(cpu, DEV_PCI_ETHER_SLOT); else ClearSlot(cpu, DEV_PCI_ETHER_SLOT);}/* A fundamental assumption of simether.c is that the DevEtherRegisters * (machine_defs.h) and the SimetherRegisters structures are isomorphic. * We'd better check for this. */static voidcheck_ether_offs(void){ ASSERT(offsetof(DevEtherRegisters, etheraddr[0]) == offsetof(SimetherRegisters, etheraddr[0])); ASSERT(offsetof(DevEtherRegisters, numRcvEntries) == offsetof(SimetherRegisters, numRcvEntries)); ASSERT(offsetof(DevEtherRegisters, numSndEntries) == offsetof(SimetherRegisters, numSndEntries)); ASSERT(offsetof(DevEtherRegisters, numSndChunks) == offsetof(SimetherRegisters, numSndChunks)); ASSERT(offsetof(DevEtherRegisters, rcvEntries[0].pAddr) == offsetof(SimetherRegisters, rcvEntries[0].pAddr)); ASSERT(offsetof(DevEtherRegisters, rcvEntries[0].maxLen) == offsetof(SimetherRegisters, rcvEntries[0].maxLen)); ASSERT(offsetof(DevEtherRegisters, rcvEntries[0].len) == offsetof(SimetherRegisters, rcvEntries[0].len)); ASSERT(offsetof(DevEtherRegisters, rcvEntries[0].flag) == offsetof(SimetherRegisters, rcvEntries[0].flag)); ASSERT(offsetof(DevEtherRegisters, sndEntries[0].firstChunk) == offsetof(SimetherRegisters, sndEntries[0].firstChunk)); ASSERT(offsetof(DevEtherRegisters, sndEntries[0].lastChunk) == offsetof(SimetherRegisters, sndEntries[0].lastChunk)); ASSERT(offsetof(DevEtherRegisters, sndEntries[0].flag) == offsetof(SimetherRegisters, sndEntries[0].flag)); ASSERT(offsetof(DevEtherRegisters, sndChunks[0].pAddr) == offsetof(SimetherRegisters, sndChunks[0].pAddr)); ASSERT(offsetof(DevEtherRegisters, sndChunks[0].len) == offsetof(SimetherRegisters, sndChunks[0].len));}/* CMOS RT clock device. * */static intclock_handler(int cpuNum, int n, int offs, int type, void* buff){ DevRegister* datap = (DevRegister*)buff; ASSERT (BDOOR_SIZE(type) == sizeof(DevRegister)); if (BDOOR_IS_LOAD(type)) { int secsSinceStart = CyclesToNanoSecs(CPUVec.CycleCount(cpuNum))/1000000000; *datap = (DevRegister)(machines.InitialTime + secsSinceStart); } else { ASSERT(0); /* for debugging */ return 1; /* clock register not writable */ } return 0;}/**************************************************************************** * * MAGIC initialization / registry code * ****************************************************************************/#define VA_NODE(va) (((va) >> __MAGIC_NODE_OFFS) & \ ((1<<__MAGIC_NODE_BITS)-1))#define VA_ZONE(va) (((va) >> __MAGIC_ZONE_OFFS) & \ ((1<<__MAGIC_ZONE_BITS)-1))#define VA_REG(va) (((va) >> __MAGIC_REG_OFFS) & \ ((1<<__MAGIC_REG_BITS)-1))#define VA_GRP(va) (((va) >> __MAGIC_PPC_GRP_OFFS) & \ ((1<<__MAGIC_PPC_GRP_BITS)-1))#define VA_OPC(va) (((va) >> __MAGIC_PPC_OPC_OFFS) & \ ((1<<__MAGIC_PPC_OPC_BITS)-1))#define VA_SEQ(va) (((va) >> __MAGIC_PPC_SEQ_OFFS) & \ ((1<<__MAGIC_PPC_SEQ_BITS)-1))#define VA_OFFS(va) ((va) & ((1<<__MAGIC_ZONE_OFFS)-1))static intFPROM_access(int cpuNum, uint VA, int type, uint* buff){ /* boot prom must be initialized, else this is a bus error */ /* ASSERT(sim_misc.fprom != NULL); */ if (sim_misc.fprom[cpuNum] == NULL) { return BUSERROR; } ASSERT(!USE_MAGIC() || !FPromUseFL); ASSERT(VA_ZONE(VA) == MAGIC_ZONE_FPROM_ALIAS); ASSERT(type == BDOOR_LOAD_WORD); ASSERT(VA_OFFS(VA) < FPROM_SIZE); *(uint *)buff = *(uint *)(VA_OFFS(VA)+sim_misc.fprom[cpuNum]); return 0;}static intFRAM_access(int cpuNum, uint VA, int type, uint* buff){ /* boot prom must be initialized */ ASSERT(sim_misc.fprom[cpuNum] != NULL); ASSERT(!USE_MAGIC() || !FPromUseFL); ASSERT(VA_ZONE(VA) == MAGIC_ZONE_FRAM_ALIAS);#ifdef LARGE_SIMULATION if (VA_NODE(VA) == 127) { /* this is really a fprom access from VA 0xbfc0.... */ return FPROM_access(cpuNum, VA, type, buff); }#endif ASSERT(VA_OFFS(VA) < FRAM_SIZE); switch (type) { case BDOOR_LOAD_BYTE: ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(byte *)buff = *(byte *)(VA_OFFS(VA)+sim_misc.fram[cpuNum]); break; case BDOOR_LOAD_HALF: ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(unsigned short *)buff = *(unsigned short *)(VA_OFFS(VA)+sim_misc.fram[cpuNum]); break; case BDOOR_LOAD_WORD: ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(uint *)buff = *(uint *)(VA_OFFS(VA)+sim_misc.fram[cpuNum]); break; case BDOOR_LOAD_DOUBLE: ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(uint64*)buff = *(uint64*)(VA_OFFS(VA)+sim_misc.fram[cpuNum]); break; case BDOOR_STORE_BYTE: /* also need to check if the fram is writeable during recovery, but for now this will do... */ ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(byte *)(VA_OFFS(VA)+sim_misc.fram[cpuNum]) = *(byte *)buff; break; case BDOOR_STORE_HALF: /* also need to check if the fram is writeable during recovery, but for now this will do... */ ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(unsigned short *)(VA_OFFS(VA)+sim_misc.fram[cpuNum]) = *(unsigned short *)buff; break; case BDOOR_STORE_WORD: /* also need to check if the fram is writeable during recovery, but for now this will do... */ ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(uint *)(VA_OFFS(VA)+sim_misc.fram[cpuNum]) = *(uint *)buff; break; case BDOOR_STORE_DOUBLE: /* also need to check if the fram is writeable during recovery, but for now this will do... */ ASSERT(VA_OFFS(VA) < FRAM_SIZE); *(uint64*)(VA_OFFS(VA)+sim_misc.fram[cpuNum]) = *(uint64*)buff; break; default: CPUError("FRAM access is not supported by type %d", type); } return 0;}#ifdef SUPPORT_LINUXstatic int MILO_access(int cpuNum, uint VA, int type, void *buff){ ASSERT(VA_ZONE(VA) == MAGIC_ZONE_MILO_ALIAS); switch (type) { case BDOOR_LOAD_WORD: if (!VA_OFFS(VA)) { *(uint*)buff = sizeof(tagPairs); } else { *(uint *)buff = *(uint*)(VA_OFFS(VA)+(uint)&tagPairs-4); } CPUWarning("MILO: %x val=%x \n", VA_OFFS(VA), *(uint *)buff ); break; default: ASSERT(0); } return 0; }#endifstatic intPPRALIAS_access(int cpuNum, uint VA, int type, void* buff){ /* PPR alias: always accesses local node PPR */ ASSERT(!USE_MAGIC()); ASSERT(VA_ZONE(VA) == MAGIC_ZONE_PPR_ALIAS); return PPR_handler(cpuNum, cpuNum, VA_REG(VA), type, buff);}static intPPCALIAS_access(int cpuNum, uint VA, int type, void* buff){ /* PPC alias: always accesses local node PPC *//* some PPC are not implemented in flashlite, so need to run them through simmagic even with USE_MAGIC set.. ASSERT(!USE_MAGIC()); */ ASSERT(VA_ZONE(VA) == MAGIC_ZONE_PPC_ALIAS); return PPC_handler(cpuNum, cpuNum, VA_GRP(VA), VA_OPC(VA), VA_SEQ(VA), type, buff);}static intFIREWALL_access(int cpuNum, uint VA, int type, void* buff){ MagicRegister* datap = (MagicRegister*)buff; int node = FIRST_CPU(M_FROM_CPU(cpuNum)) + VA_NODE(VA); int pg = VA_OFFS(VA)/sizeof(MagicRegister); ASSERT(!USE_MAGIC());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -