📄 simmagic.c
字号:
ASSERT(VA_ZONE(VA) == MAGIC_ZONE_FIREWALL); /* actually, we should return a bus error for accesses which fall * outside the valid range. For now, we have an assertion since this * makes things easier to debug. */ ASSERT(pg < (MEM_SIZE(M_FROM_CPU(cpuNum)) / NUM_CPUS(M_FROM_CPU(cpuNum)))); if (type == BDOOR_LOAD_DOUBLE) { /* anyone can read the firewall status */ *datap = (MagicRegister)sim_firewall_page_prot(node, pg); } else if (type == BDOOR_STORE_DOUBLE) { /* only nodes in the same cell and cells which have firewall write * access to this page can write the firewall. */ return sim_firewall_set_page_prot(cpuNum, node, pg, (uint64)*datap); } else return 1; /* can only handle dword accesses */ return 0;}/* * Routine called when the MIG_REP zone is accessed * for reading or setting cache-miss or write counters. */static intMIG_REP_access(int cpuNum, uint VA, int type, void* buff){ MagicRegister* datap = (MagicRegister*)buff; int node = FIRST_CPU(M_FROM_CPU(cpuNum)) + VA_NODE(VA); unsigned long pg = VA_OFFS(VA); ASSERT(!USE_MAGIC()); ASSERT(VA_ZONE(VA) == MAGIC_ZONE_MIG_REP); if (IS_NUMA()) { unsigned long typeMask = (1<<(__MAGIC_ZONE_OFFS-1)); unsigned long countType = pg & typeMask; unsigned long countAddr = (pg & (~typeMask))/sizeof(uint64); if (type == BDOOR_LOAD_DOUBLE) { *datap = (MagicRegister) MigRepGetInfo(pg, node, countType, countAddr); } else if (type == BDOOR_STORE_DOUBLE) { MigRepSetInfo(pg, node, *datap, countType, countAddr); } else { return 1; /* can only handle dword accesses */ } } else { /* * For now we just return 0 for reads and do nothing for writes */ if (type == BDOOR_LOAD_DOUBLE) { *datap = (MagicRegister) 0; } else if (type == BDOOR_STORE_DOUBLE) { } else { return 1; /* can only handle dword accesses */ } } return 0;}static intPPR_access(int cpuNum, uint VA, int type, void* buff){ /* PPR access to specified node */ int n = FIRST_CPU(M_FROM_CPU(cpuNum)) + VA_NODE(VA); ASSERT(!USE_MAGIC()); ASSERT(VA_ZONE(VA) == MAGIC_ZONE_PPR); return PPR_handler(cpuNum, n, VA_REG(VA), type, buff);}static intPPC_access(int cpuNum, uint VA, int type, void* buff){ /* PPC access to specified node */ int n = FIRST_CPU(M_FROM_CPU(cpuNum)) + VA_NODE(VA); ASSERT(!USE_MAGIC()); ASSERT(VA_ZONE(VA) == MAGIC_ZONE_PPC); return PPC_handler(cpuNum, n, VA_GRP(VA), VA_OPC(VA), VA_SEQ(VA), type, buff);}static intBDOOR_disk_access(int cpuNum, uint VA, int type, void* buff){ int node = VA_NODE(VA); /* relative to current machine */ int offs = VA_OFFS(VA) - __MAGIC_BDOOR_DISKS_OFFS; int nd = offs / sizeof(DevDiskRegisters); /* unit # */ int doff = offs % sizeof(DevDiskRegisters); /* offset in unit regs */ ASSERT(VA_ZONE(VA) == MAGIC_ZONE_BDOOR_DEV); /* XXX * Uncomment the following assert when not using more disk * controllers than nodes any longer. Currently, I think this * is only used for DISCO. DT. * XXX */ /* ASSERT(0 <= node && node < NUM_CPUS(M_FROM_CPU(cpuNum))); */ /* Note for multiple machines: * must translate this access to an absolute node number. */ return disk_handler(node + FIRST_CPU(M_FROM_CPU(cpuNum)), nd, doff, type, buff);}static intBDOOR_console_access(int cpuNum, uint VA, int type, void* buff){ int n = VA_NODE(VA); int offs = VA_OFFS(VA) - __MAGIC_BDOOR_CNSLE_OFFS; ASSERT(VA_ZONE(VA) == MAGIC_ZONE_BDOOR_DEV); ASSERT(!inCellMode || (n % CPUS_PER_CELL(0) == 0)); ASSERT(0 <= offs && offs < sizeof(DevConsoleRegisters)); return console_handler(cpuNum, n, offs, type, buff);}static intBDOOR_ether_access(int cpuNum, uint VA, int type, void* buff){ int n = VA_NODE(VA); int offs = VA_OFFS(VA) - __MAGIC_BDOOR_ETHER_OFFS; ASSERT(VA_ZONE(VA) == MAGIC_ZONE_BDOOR_DEV); ASSERT(!inCellMode || (n % CPUS_PER_CELL(0) == 0)); ASSERT(0 <= offs && offs < sizeof(DevEtherRegisters)); return ether_handler(cpuNum, n, offs, type, buff);}static intBDOOR_clock_access(int cpuNum, uint VA, int type, void* buff){ int n = VA_NODE(VA); int offs = VA_OFFS(VA) - __MAGIC_BDOOR_CLOCK_OFFS; ASSERT(VA_ZONE(VA) == MAGIC_ZONE_BDOOR_DEV); ASSERT(!inCellMode || (n % CPUS_PER_CELL(0) == 0)); ASSERT(0 <= offs && offs < sizeof(DevClockRegisters)); return clock_handler(cpuNum, n, offs, type, buff);}#ifdef TORNADOstatic intBDOOR_gizmo_access(int cpuNum, uint VA, int type, void* buff){ int n = VA_NODE(VA); int offs = VA_OFFS(VA) - __MAGIC_BDOOR_GIZMO_OFFS; ASSERT(VA_ZONE(VA) == MAGIC_ZONE_BDOOR_DEV); ASSERT(0 <= offs && offs < sizeof(DevGizmoRegisters)); return gizmo_handler(cpuNum, n, offs, type, buff);}#endif /* TORNADO */static intOSPC_access(int cpuNum, uint VA, int type, void* buff){ int offs = VA & (MAGIC_OSPC_SIZE-1); int err; byte ospc_buff[MAGIC_OSPC_SIZE]; ASSERT(!USE_MAGIC()); ASSERT(VA >= __MAGIC_OSPC_BASE && VA < __MAGIC_OSPC_END); if (type != BDOOR_LOAD_BYTE && type != BDOOR_LOAD_HALF && type != BDOOR_LOAD_WORD && type != BDOOR_LOAD_DOUBLE) { ASSERT(0); /* for debugging */ return 1; } err = sim_magic_OSPC_access(cpuNum, VA, ospc_buff); ASSERT(err >= 0); switch (type) { case BDOOR_LOAD_BYTE: *(unsigned char*)buff = ((unsigned char*)ospc_buff)[offs];#if (DEBUG_MAGIC == 1) LogEntry("OSPC_access", cpuNum, "VA 0x%08x BYTE data 0x%02x\n", VA, *(unsigned char*)buff);#endif break; case BDOOR_LOAD_HALF: *(unsigned short*)buff = ((unsigned short*)ospc_buff)[offs/sizeof(unsigned short)];#if (DEBUG_MAGIC == 1) LogEntry("OSPC_access", cpuNum, "VA 0x%08x HALF data 0x%04x\n", VA, *(unsigned short*)buff);#endif break; case BDOOR_LOAD_WORD: ASSERT(offs % sizeof(uint) == 0); *(uint*)buff = ((uint*)ospc_buff)[offs/sizeof(uint)];#if (DEBUG_MAGIC == 1) LogEntry("OSPC_access", cpuNum, "VA 0x%08x WORD data 0x%08x\n", VA, *(uint*)buff);#endif break; case BDOOR_LOAD_DOUBLE: ASSERT(offs % sizeof(uint64) == 0); *(uint64*)buff = ((uint64*)ospc_buff)[offs/sizeof(uint64)];#if (DEBUG_MAGIC == 1) LogEntry("OSPC_access", cpuNum, "VA 0x%08x DWORD data 0x%016lx\n", VA, *(uint64*)buff);#endif break; } return 0;}/* CAVEAT: we currently DON'T model the latency of getting an OSPC * cacheline when not running under Flashlite. This is not tragic, * but should be fixed at some point. */Result sim_magic_MemsysCmd(int cpunum, int cmd, unsigned int paddr, int transId, unsigned int replacedPaddr, int writeback, byte *data){ int command = cmd & MEMSYS_CMDMASK; int flavor = cmd & (~MEMSYS_CMDMASK); byte *wb_buff = data; Result res; /* Is this an OSPC access we should handle? */ if ( 0 && !USE_MAGIC() && (command == MEMSYS_GET || command == MEMSYS_REPLACEMENT_HINT) && (flavor == 0) && (paddr >= (__MAGIC_OSPC_BASE - K0BASE) && paddr < (__MAGIC_OSPC_BASE - K0BASE + 2*MAGIC_OSPC_SIZE)) ) {CPUWarning("OSPC access...\n"); /* OSPC access -- handle hic et nunc */ if (cmd == MEMSYS_GET) { /* Note: paddr is critical-word-first, which is irrelevant for now */ unsigned int offs = (paddr & ~(MAGIC_OSPC_SIZE-1)) - (__MAGIC_OSPC_BASE - K0BASE); byte ospc_buff[MAGIC_OSPC_SIZE]; static byte wb_save[MAGIC_OSPC_SIZE]; MagicRegister errval, okval; int err; /* read the data -- for now, this is only SIPS data */ switch (offs) { case MAGIC_OSPC_LO_OFFS: errval = MAGIC_OSPC_LO_NONE; okval = MAGIC_OSPC_LO_SIPSREQ; err = sim_sips_get(cpunum, 1, ospc_buff); break; case MAGIC_OSPC_HI_OFFS: okval = MAGIC_OSPC_HI_SIPSREPLY; errval = MAGIC_OSPC_HI_NONE; err = sim_sips_get(cpunum, 0, ospc_buff); break; default: ASSERT(0); } /* SIPS status */ *((MagicRegister*)ospc_buff) = err ? errval : okval; /* Note: at this point, the GET is done, as far as we're concerned. * However, we still might have to do a WB, which might stall. * This is sort of perverse, since we're actually doing the operations * in the reverse order than on the real machine (i.e. we're satisfying * the GET first... * In order to avoid clobbering the unique copy of the wb data, we'll * save it to a private buffer. */ ASSERT(MAGIC_OSPC_SIZE >= SCACHE_LINE_SIZE); bcopy(wb_buff, wb_save, sizeof(wb_save)); wb_buff = wb_save; /* Now tell the processor the GET has completed. If the WB stalls, * then we'll call MipsyStall to stall the processor (!). * THIS IS A HACK!!! */ CacheCmdDone(cpunum, transId, MEMSYS_SHARED, MEMSYS_STATUS_SUCCESS, MEMSYS_RESULT_MEMORY, ospc_buff); } /* else: replacement hint is ignored */ if (writeback) { ASSERT((paddr & ~(MAGIC_OSPC_SIZE-1)) != (replacedPaddr & ~(MAGIC_OSPC_SIZE-1))); /* Need to perform the writeback, too! */ res = memsysVec.MemsysCmd(cpunum, MEMSYS_GET, 0LL, -1, replacedPaddr, writeback, data); if (res == STALL) { /* oops, write buffer filled up. We'll have to stall the * CPU again. This is a total hack. */ CPUWarning("Stalling during OSPC....\n"); } return res; } else { return SUCCESS; } } else /* Main memory access -- pass on unaffected */ return memsysVec.MemsysCmd(cpunum, cmd, paddr, transId, replacedPaddr, writeback, data);}/* * Device polling. Some simulated devices which take asynchronous * input from the "real world" need to have a poll function called * periodically to check for input. */static EventCallbackHdr pollHdr; /* poll devices callback */static void PollDevices(int cpuNum, EventCallbackHdr *hdr, void *arg){#if (DEBUG_MAGIC == 1) LogEntry("PollDevices", 0, "\n");#endif /* 1. Poll all consoles */ sim_console_poll(); /* 2. Poll all ethernet interfaces */#ifndef linux SimetherPoll();#endif#ifdef TORNADO /* 3. Poll gizmo interface */ gizmo_poll();#endif /* TORNADO */ /* register callback for next poll round */ EventDoCallback(0, PollDevices, &pollHdr, NULL, MAGIC_POLL_INTERVAL);}void InstallPoller(void){ static int installed = 0; if (!installed) { installed = 1; EventDoCallback(0, PollDevices, &pollHdr, NULL, MAGIC_POLL_INTERVAL); }}/* *** * *** MAGIC & devices initialization. * *** * *** Initialize all devices, device polling, MAGIC emulation, etc. * *** */static voidInitDevices(int restoreFromChkpt){ /* * CPUVector */ CPUVec.UncachedPIO = SimMagic_DoPIO; /* disks */ { int m, n, uc = NUM_UNITS_PER_CONTROLLER(0); for (m = 0; m < NUM_MACHINES; m++) for (n = 0; n < TOTAL_CPUS; n++) { ASSERT(NUM_UNITS_PER_CONTROLLER(m) * NUM_DISK_CONTROLLERS(m,n) <= DEV_DISK_MAX_UNIT); ASSERT(uc == NUM_UNITS_PER_CONTROLLER(m)); } } sim_disk_init(DISK_NODES, NUM_UNITS_PER_CONTROLLER(0), disk_interrupt, restoreFromChkpt); /* ethernet interfaces */ SimetherInit(restoreFromChkpt, ether_interrupt); /* consoles */ sim_console_init(TOTAL_CONSOLES, console_interrupt); /* NOTE: at this point, we'd also like to initialize polling (for those * devices that need it). Unfortunately, this depends on the CPUVec * being more completely initialized than it is now (before any CPU * simulator has started). So we'll let the CPU simulators call * InstallPoller(). */ /* 3. Misc. initialization */ sim_sips_init(TOTAL_CPUS, sips_interrupt); /* 4. Checkpointing stuff */ Simcpt_Register("magic", SimMagic_CheckpointCB, ALL_CPUS); if (restoreFromChkpt) Simcpt_Restore("magic");}static voidBuildDeviceToMachine(void){ int machNo, count; /* * Build the arrays that map from device number back to machine number */ deviceToMachine.console = (int*)malloc(TOTAL_CONSOLES*sizeof(int)); deviceToMachine.ether = (int*)malloc(TOTAL_ETHER_CONTROLLERS*sizeof(int)); deviceToMachine.clock = (int*)malloc(TOTAL_CLOCKS*sizeof(int)); ASSERT(deviceToMachine.console); ASSERT(deviceToMachine.ether); ASSERT(deviceToMachine.clock); for (machNo = 0; machNo < NUM_MACHINES; machNo++) { for (count = FIRST_CONSOLE(machNo); count <= LAST_CONSOLE(machNo); count++) { deviceToMachine.console[count] = machNo; } for (count = FIRST_ETHER_CONTROLLER(machNo); count <= LAST_ETHER_CONTROLLER(machNo); count++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -