📄 simmagic.c
字号:
/**************************************************************************** * * SIPS support * ****************************************************************************/struct { /* SIPS state for each MAGIC */ MagicRegister stall; /* shadow of STALLOSPC PPR */ int stalled; /* did an access stall on this OSPC? */ int st_lo; /* stalled on OSPC_LO? */ VA st_va; /* stalled VA (could actually be computed) */} sst[SIM_MAXCPUS];static voidsips_interrupt(int n, int lo, int on){ /* suppress the interrupt if a cache miss is already stalled * on this OSPC. */ if (on && sst[n].stalled && sst[n].st_lo == lo) { /* unstall access that stalled on this OSPC */ CacheCmdUnstall(n, sst[n].st_va);#if (DEBUG_MAGIC == 1) LogEntry("sips_interrupt", n, "lo=%d on=%d SUPPRESSED\n", lo, on);#endif return; } /* XXX DT not true in general! ASSERT(!sst[n].stalled); */#if (DEBUG_MAGIC == 1) LogEntry("sips_interrupt", n, "lo=%d on=%d\n", lo, on);#endif if (on) RaiseIBit(n, lo ? DEV_IEC_OSPC_LO : DEV_IEC_OSPC_HI); else ClearIBit(n, lo ? DEV_IEC_OSPC_LO : DEV_IEC_OSPC_HI);}/* NOTE ON OSPC ACCESSES: * * In the real machine, OSPC accesses are done through a distinct * (cacheable noncoherent) address space. Lacking enough address bits in * the 32bit SimOS version, we have squeezed in the OSPC area in the * second page of KSEG0. The various simulators use different mechanisms for * accessing this area: * * - MIPSY contains a hack in CacheCmdDone. This routine is called * by the memory system when an access completes; in turn, it calls * into sima_magic_OSPC_access below, which may either complete * the access right away (if the data is available), or delay the * access (and call the given continuation later) if we stall on * this OSPC read. * * - EMBRA cannot go through the same mechanism, since having all * Embra memory accesses go through a function would defeat the * efficiency goals of Embra. Hence, Embra special-cases the page * in KSEG0 that maps to OSPC's and treats access to this page like * backdoor accesses, which will go through OSPC_access (registered * in the backdoor). */intsim_magic_OSPC_access(int cpuNum, uint VA, byte *data){ int err; int stall = 0; MagicRegister errval, okval; MagicRegister* dr = (MagicRegister*)data; if (USE_MAGIC()) return 0; /* Flashlite */ /* read the data -- for now, this is only SIPS data */ if (VA >= (__MAGIC_OSPC_BASE + MAGIC_OSPC_LO_OFFS) && VA < (__MAGIC_OSPC_BASE + MAGIC_OSPC_LO_OFFS + MAGIC_OSPC_SIZE)) { errval = MAGIC_OSPC_LO_NONE; okval = MAGIC_OSPC_LO_SIPSREQ; err = sim_sips_get(cpuNum, 1, data); if (sst[cpuNum].stall == (MagicRegister)DEV_IEC_OSPC_LO && err != 0) { stall = 1; } } else if (VA >= (__MAGIC_OSPC_BASE + MAGIC_OSPC_HI_OFFS) && VA < (__MAGIC_OSPC_BASE + MAGIC_OSPC_HI_OFFS + MAGIC_OSPC_SIZE)) { okval = MAGIC_OSPC_HI_SIPSREPLY; errval = MAGIC_OSPC_HI_NONE; err = sim_sips_get(cpuNum, 0, data); if (sst[cpuNum].stall == (MagicRegister)DEV_IEC_OSPC_HI && err != 0) { stall = 1; } } else { /* access to some other location -- ignore */ return 0; } /* SIPS status */ *dr = ( ((*dr) & ~MAGIC_OSPC_OPCODE_MASK) | (((MagicRegister)(err ? errval : okval)) << MAGIC_OSPC_OPCODE_OFFS) );#if (DEBUG_MAGIC == 1) LogEntry("OSPC_access", cpuNum, "delay=%d\n", stall ? (CPU_CLOCK * MAGIC_OSPC_TIMEOUT_US) : 0);#endif return stall ? (CPU_CLOCK * MAGIC_OSPC_TIMEOUT_US) : 0;}voidsim_magic_OSPC_stalled(int cpuNum, VA va, int stalled){#if (DEBUG_MAGIC == 1) LogEntry("sim_magic_OSPC_stalled", cpuNum, "va=0x%llx st=%d\n", (uint64)va, stalled);#endif if (stalled) { /* access has stalled */ ASSERT(!sst[cpuNum].stalled); sst[cpuNum].stalled = 1; sst[cpuNum].st_va = va; sst[cpuNum].st_lo = (va >= (__MAGIC_OSPC_BASE + MAGIC_OSPC_LO_OFFS) && va < (__MAGIC_OSPC_BASE + MAGIC_OSPC_LO_OFFS + MAGIC_OSPC_SIZE)); } else { /* stalled access has timed out. Unstall */ ASSERT(sst[cpuNum].stalled); ASSERT(sst[cpuNum].st_va == va); ASSERT(sst[cpuNum].st_lo == (va >= (__MAGIC_OSPC_BASE+MAGIC_OSPC_LO_OFFS)&& va < (__MAGIC_OSPC_BASE+MAGIC_OSPC_LO_OFFS+ MAGIC_OSPC_SIZE))); sst[cpuNum].stalled = 0; sst[cpuNum].stall = (MagicRegister)0; }}/**************************************************************************** * * PPR emulation * ****************************************************************************/#define MAX_PPR 0x40 /* max. number of PPR's */#define PPR_NODE(va) (((va)>>__MAGIC_NODE_OFFS) & \ ((1 << __MAGIC_NODE_BITS) - 1))#define PPR_REG(va) (((va)>>__MAGIC_REG_OFFS) & \ ((1 << __MAGIC_REG_BITS) - 1))static MagicRegisternode_config(int cell, int realCPU){ unsigned int npc, first, cpu; if (inCellMode) { ASSERT((NUM_CPUS(0)/NUM_CELLS(0))*NUM_CELLS(0) == NUM_CPUS(0)); cpu = realCPU; npc = NUM_CPUS(0)/NUM_CELLS(0); first = cell * npc; } else { ASSERT((cell == 0) && (NUM_CELLS(0) == 1)); cpu = MCPU_FROM_CPU(realCPU); npc = NUM_CPUS(M_FROM_CPU(realCPU)); first = 0; } ASSERT(((((MagicRegister)cpu) << MAGIC_NODECONFIG_THISNODE_OFFS) & ~MAGIC_NODECONFIG_THISNODE_MASK) == 0LL); ASSERT(((((MagicRegister)first) << MAGIC_NODECONFIG_FIRSTNODE_OFFS) & ~MAGIC_NODECONFIG_FIRSTNODE_MASK) == 0LL); ASSERT(((((MagicRegister)npc) << MAGIC_NODECONFIG_NODESINCELL_OFFS) & ~MAGIC_NODECONFIG_NODESINCELL_MASK) == 0LL); ASSERT(((((MagicRegister)cell) << MAGIC_NODECONFIG_THISCELL_OFFS) & ~MAGIC_NODECONFIG_THISCELL_MASK) == 0LL); ASSERT(((((MagicRegister)NUM_CELLS(0)) << MAGIC_NODECONFIG_NCELLS_OFFS) & ~MAGIC_NODECONFIG_NCELLS_MASK) == 0LL); return (((MagicRegister)cpu) << MAGIC_NODECONFIG_THISNODE_OFFS) | (((MagicRegister)first) << MAGIC_NODECONFIG_FIRSTNODE_OFFS) | (((MagicRegister)npc) << MAGIC_NODECONFIG_NODESINCELL_OFFS) | (((MagicRegister)cell) << MAGIC_NODECONFIG_THISCELL_OFFS) | (((MagicRegister)NUM_CELLS(0)) << MAGIC_NODECONFIG_NCELLS_OFFS);}static MagicRegisteraddr_config(int n){ unsigned int machNo = M_FROM_CPU(n); unsigned int pages = MEM_SIZE(machNo) / SIM_PAGE_SIZE / NUM_CPUS(machNo); unsigned int nnb = __MAGIC_NODE_BITS; /* node_number_bits */ unsigned int masb = 0; /* MAGIC address space bits */ ASSERT((MEM_SIZE(machNo)/NUM_CPUS(machNo))*NUM_CPUS(machNo) == MEM_SIZE(machNo)); ASSERT(((((MagicRegister)pages) << MAGIC_ADDRCONFIG_PAGES_OFFS) & ~MAGIC_ADDRCONFIG_PAGES_MASK) == 0LL); ASSERT(((((MagicRegister)nnb) << MAGIC_ADDRCONFIG_NNBITS_OFFS) & ~MAGIC_ADDRCONFIG_NNBITS_MASK) == 0LL); ASSERT(((((MagicRegister)masb) << MAGIC_ADDRCONFIG_MASBITS_OFFS) & ~MAGIC_ADDRCONFIG_MASBITS_MASK) == 0LL); return (((MagicRegister)pages) << MAGIC_ADDRCONFIG_PAGES_OFFS) | (((MagicRegister)nnb) << MAGIC_ADDRCONFIG_NNBITS_OFFS) | (((MagicRegister)masb) << MAGIC_ADDRCONFIG_MASBITS_OFFS);}/* PPR access handler -- handles all accesses to PPR's. * Returns: * - 0: ok access * - 1: this type of access not supported (only dword implemented * for now) * - -1: bus-error this access. */static intPPR_handler(int cpu, /* CPU doing the access */ int n, /* destination node */ int r, /* register number */ int type, /* access type */ void *buff) /* data buffer */{ /* NOTE: for 32 bit Topsy's pleasure, we support word access -- PZ. */#define RDONLY if (type == BDOOR_STORE_DOUBLE || type == BDOOR_STORE_WORD) return -1#define WRONLY if (type == BDOOR_LOAD_DOUBLE || type == BDOOR_LOAD_WORD) return -1#define RDWR#ifdef __alpha MagicRegister* datap = (MagicRegister*) buff;#else int* datap = (int*)buff; /* hack (PZ) */#endif int isrd = (type == BDOOR_LOAD_DOUBLE || type == BDOOR_LOAD_WORD); ASSERT(0 <= cpu && cpu < TOTAL_CPUS); ASSERT(0 <= n && n < TOTAL_CPUS); /* Note: we should never get here if we use Flite! */ ASSERT(!USE_MAGIC());#if (DEBUG_MAGIC == 1) LogEntry("PPR_handler", cpu, "n=%d r=0x%x t=%d\n", n, r, type);#endif /* silly support for word accesses (PZ) */ if (type = BDOOR_STORE_WORD) *datap &= 0xffffffff; /* mask off high bits */ /* we only handle dword accesses and buserror all others */ if (type != BDOOR_LOAD_DOUBLE && type != BDOOR_STORE_DOUBLE && type != BDOOR_LOAD_WORD && type != BDOOR_STORE_WORD) return 1; switch (r) { case MAGIC_PPR_IECHIGH: RDONLY; *datap = mm[n].IEChigh; break; case MAGIC_PPR_ACKINTERNAL: WRONLY; return AckInternalInt(n, (IEC)*datap); case MAGIC_PPR_IECPENDING: RDWR; if (isrd) { *datap = mm[n].iPendingReg; } else { /* clear selected interrupt bits */ mm[n].iTransReg &= ~(*datap); mm[n].iPendingReg &= ~(*datap); /* topsy hack -- PZ */ recompute_intr_bits(n); } break; case MAGIC_PPR_SIPSLOACK: RDONLY; return AckInternalInt(n, (IEC)DEV_IEC_OSPC_LO); case MAGIC_PPR_SIPSHIACK: RDONLY; return AckInternalInt(n, (IEC)DEV_IEC_OSPC_HI); case MAGIC_PPR_IECENABLE: RDWR; if (isrd) { *datap = mm[n].iEnableMask; } else { mm[n].iEnableMask = *datap; recompute_intr_bits(n); } break; case MAGIC_PPR_SENDIPI: WRONLY; { int iec; switch (*datap) { case 0: iec = DEV_IEC_IPI; break; case 1: iec = DEV_IEC_IPI1; break; case 2: iec = DEV_IEC_IPI2; break; default: CPUError("only ipi 0, 1, and 2 supported\n"); } CPUVec.Send_Interrupt(n, iec, IPI_LATENCY); } break; case MAGIC_PPR_OPSPACE: RDWR; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_ASID: RDWR; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_TLBINVAL: WRONLY; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_TLBINUSE: RDONLY; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_MSGTAG: RDWR; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_STALLOSPC: RDWR; if (isrd) *datap = sst[n].stall; else sst[n].stall = *datap; break; case MAGIC_PPR_CYCLECOUNT: RDONLY; /* XXX is this correct? */ *datap = (MagicRegister) CPUVec.CycleCount(n); break; case MAGIC_PPR_PROTVERSION: RDONLY; /* This always returns 2 for now */ *datap = (MagicRegister)2; break; case MAGIC_PPR_HWVERSION: RDONLY; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_REMAPMASK: RDWR; ASSERT( !isrd ); /* w not yet implemented */ memsysVec.MemsysSetRemap(n, (PA)*datap); memsysVec.MemsysControlRemap(n, 1); /* remapenable */ break; case MAGIC_PPR_PROTCONTROL: RDWR; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_RTC: RDONLY; { SimTime currentCycle = CPUVec.CycleCount(n) + startingCycle[n]; *datap = (MagicRegister) CyclesToNanoSecs(currentCycle)/1000; break; } case MAGIC_PPR_INTERVAL: RDWR; if (isrd) *datap = mm[n].timerInterval; else { mm[n].timerInterval = *datap; /* XXX fix this */ InstallTimer(n, *datap, *datap); } break; case MAGIC_PPR_SLOTMAP: RDWR; if (isrd) *datap = ( (MagicRegister)mm[n].ioSlotMap[0] << MAGIC_SLOTMAP_SLOT0_OFFS ) | ( (MagicRegister)mm[n].ioSlotMap[1] << MAGIC_SLOTMAP_SLOT1_OFFS ) | ( (MagicRegister)mm[n].ioSlotMap[2] << MAGIC_SLOTMAP_SLOT2_OFFS ) | ( (MagicRegister)mm[n].ioSlotMap[3] << MAGIC_SLOTMAP_SLOT3_OFFS ); else { int slot; for (slot=0; slot<4; slot++) while (mm[n].ioSlots[slot] > 0) ClearSlot(n, slot); mm[n].ioSlotMap[0] = (*datap & MAGIC_SLOTMAP_SLOT0_MASK) >> MAGIC_SLOTMAP_SLOT0_OFFS; mm[n].ioSlotMap[1] = (*datap & MAGIC_SLOTMAP_SLOT1_MASK) >> MAGIC_SLOTMAP_SLOT1_OFFS; mm[n].ioSlotMap[2] = (*datap & MAGIC_SLOTMAP_SLOT2_MASK) >> MAGIC_SLOTMAP_SLOT2_OFFS; mm[n].ioSlotMap[3] = (*datap & MAGIC_SLOTMAP_SLOT3_MASK) >> MAGIC_SLOTMAP_SLOT3_OFFS; } break; case MAGIC_PPR_FWSHIFT: RDWR; /* obsolete, should be removed */ ASSERT(0); break; case MAGIC_PPR_RECOVERYSYNC: RDONLY; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_REPORT_DIAG_RESULT: RDONLY; ASSERT(0); /* not yet implemented */ break; case MAGIC_PPR_NODECONFIG: RDONLY; { int cell; if (inCellMode) cell = cpu / CPUS_PER_CELL(0); /* this is my node number */ else cell = 0; *datap = node_config(cell, cpu); } break; case MAGIC_PPR_ADDRCONFIG: RDONLY; *datap = addr_config(cpu); break; case MAGIC_PPR_MIG_REP:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -