📄 params.c
字号:
/***************************************************************** * ParamAccess * ----------- * When reading a per-machine param, this function is called just * before reading from the dummy param. We copy the correct value * int the dummy and let the copy proceed. * When writing to a per-machine param, this function is called * just after the dummy param is written to. We copy this value * out to all the machines that are currently active. *****************************************************************/char *ParamAccess(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags){ char buf[64]; Tcl_HashEntry *entryPtr; ParamStruct *oneParam; int count; sprintf(buf, "%s(%s)", name1, name2); if (!(entryPtr = Tcl_FindHashEntry(&entries, buf))) { return "unknown parameter accessed"; } oneParam = (ParamStruct *)Tcl_GetHashValue(entryPtr); /* If we are reading the values */ if (flags & TCL_TRACE_READS) { /* We don't want anyone changing variables after they have been read, so we make them read-only after the first read. Note that this only protects you in Tcl, not when referencing and changing the linked variables in C. */ /* A per-machine parameter */ if (oneParam->bitField) { int totalActive = 0, firstActive = MAX_MACHINES+1; char *paramPtr; for (count = 0; count < MAX_MACHINES; count++) { if (machineParamVec[count]) { totalActive++; if (firstActive > count) firstActive = count; } } /* If more than one machine is the read source, only allow if we've never modified this param inside a machine block */ if (totalActive != 1) { if (oneParam->modifiedPerMachine) { CPUWarning("PARAM: Must specify machine num when reading %s (since previously set per-machine).\nPARAM: Use '[machine_val machine_num param_name]' to specify.\n", oneParam->name); return "PARAM: ambiguous variable read"; } else firstActive = 0; } if (!IS_INITIALIZED(*oneParam, firstActive)) { CPUWarning("PARAM: Trying to read uninitialized variable %s (machine %d).\n", oneParam->name, firstActive); return "PARAM: uninitialized variable"; } /* Set the value of the dummy */ if (oneParam->type == PARAM_INT) { paramPtr = tcl_itoa(*(int*)oneParam->accessFunc(firstActive, buf)); } else if (oneParam->type == PARAM_STRING) { paramPtr = SaveString(*((char **)oneParam->accessFunc(firstActive, buf))); } else { /* Type not currently handled here */ ASSERT (0); paramPtr = 0; /* compiler happy */ } Tcl_SetVar2(interp, name1, name2, paramPtr, TCL_GLOBAL_ONLY); SET_READONLY(*oneParam, firstActive); } else { if (machineScope == MACHINE_VAL) { CPUWarning("PARAM: Can't use machine_val to read an all-machines param\n"); return "PARAM: incorrect variable read"; } if (!oneParam->initialized) { CPUWarning("PARAM: Trying to read uninitialized variable %s.\n", oneParam->name); return "PARAM: uninitialized variable"; } oneParam->readOnly = TRUE; } } else {#ifndef SIM_ALPHA ASSERT(TclIniting);#endif /* A per-machine parameter */ if (oneParam->bitField) { char *paramVal = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY); for (count = 0; count < MAX_MACHINES; count++) { if (machineParamVec[count]) { if (IS_READONLY(*oneParam, count)) { CPUWarning("PARAM: Trying to write to %s (machine %d) after it has been read... ABORTING\n", oneParam->name, count); return "PARAM: writing to accessed var"; } else { SET_INITIALIZED(*oneParam, count); } /* Copy the value to this machine's param */ if (oneParam->type == PARAM_INT) { Tcl_GetInt(interp, paramVal, (int*)oneParam->accessFunc(count, buf)); } else if (oneParam->type == PARAM_STRING) { *((char **)oneParam->accessFunc(count, buf)) = SaveString(paramVal); } else { /* Type not currently handled here */ ASSERT (0); } } } /* If we modified this in a machine block, set modifiedPerMachine */ if (machineScope != MACHINE_TOP) { oneParam->modifiedPerMachine = TRUE; } } else { if (machineScope != MACHINE_TOP) { CPUWarning("PARAM: Trying to modify an all-machines param %s per machine... ABORTING\n", oneParam->name); return "PARAM: illegal modification"; } if (oneParam->readOnly) { CPUWarning("PARAM: Trying to write to %s after it has been read... ABORTING\n", oneParam->name); return "PARAM: illegal modification"; } else { oneParam->initialized = TRUE; if (!strcmp(name2, "CPU.Model")) { return AccessCPUModel(interp); } } } } return NULL;}/* * Calling this function for per-machine params would be a bad idea, * since only the last accessed value would be returned. However, it * is never used on these params, so there is no problem. */intParamLookup(void *valptr, char *name, int type) { char *ptr; char *val = Tcl_GetVar2(TCLInterp, "PARAM", name, TCL_GLOBAL_ONLY); if (val == NULL) { return FALSE; } switch (type) { case PARAM_STRING: *((char **)valptr) = val; return TRUE; case PARAM_INT: return (Tcl_GetInt(TCLInterp, val, (int *)valptr) == TCL_OK); case PARAM_BOOLEAN: return (Tcl_GetBoolean(TCLInterp, val, (int *)valptr) == TCL_OK); case PARAM_DOUBLE: return (Tcl_GetDouble(TCLInterp, val, (double *)valptr) == TCL_OK); case PARAM_LL:#if defined(__alpha) || defined(i386) *((int64 *)valptr) = strtol(val, &ptr, 0);#else *((int64 *)valptr) = strtoll(val, &ptr, 0);#endif return (ptr != val); default: break; } return FALSE;}/***************************************************************** * ParamGrabbed * * Almost all parameters return FALSE for this, so will require * initialization by the init.simos and follow-on scripts. * *****************************************************************/static intParamGrabbed(char* varName){ int i; for (i=0; i<numgrabbed; i++) { if (!strcmp(varName, grabbedParams[i])) return TRUE; } return FALSE;}/***************************************************************** * ParamGrabbedAtStartup * * Called by simcpt.c to record its dirty deed. Note that * this is called *before* tclinit so we can't rely on anything * from the tcl library. * NOTE: This specifies that the param has been grabbed for _all_ * machines, since when restoring from checkpoint, values must * have been set for all machines. *****************************************************************/voidParamGrabbedAtStartup(char* varName){ ASSERT(numgrabbed < MAXGRABBED); grabbedParams[numgrabbed++] = varName;}/***************************************************************** * MachineSettingsComplete * * This procedure has two purposes: * Ensure that all variables have had a default value assigned * to them * Compute the derived fields from the "specified" values *****************************************************************/voidMachineSettingsComplete(void){ int i, machNo, cpuCount, memoryCount; int consoleCount, etherCount, clockCount; bool badParamExists = FALSE; Tcl_HashEntry *entryPtr; ParamStruct *oneParam; /* * Find the value of PARAM(MACHINE.Count) so that we know how many machines * to check for completion on. */ if (!(entryPtr = Tcl_FindHashEntry(&entries, "PARAM(MACHINE.Count)"))) { /* It should exist, so if not we will assert fail */ ASSERT(0); } oneParam = (ParamStruct *)Tcl_GetHashValue(entryPtr); ASSERT(oneParam); if (!oneParam->initialized) { CPUWarning("PARAM: PARAM(MACHINE.Count) has not been initialized. Assuming 1 machine.\n"); oneParam->initialized = TRUE; NUM_MACHINES = 1; } if (NUM_MACHINES < 1 || NUM_MACHINES > MAX_MACHINES) { CPUWarning("Number of machines (%d) is out of legal range of %d to %d.\n", NUM_MACHINES, 1, MAX_MACHINES); ASSERT(0); }#ifndef SOLO /* * Ensure that if we have more than one machine, that each machine is just * one cell. i.e If we have multiple machines, then each is just one cell, * and if we have multiple cells, then we only have one machine. */ inCellMode = 0; if (NUM_MACHINES > 1) { for (machNo = 0; machNo < NUM_MACHINES; machNo++) { if (machines.machine[machNo].NumCells > 1) { CPUWarning("Can't have a machine with more than one cell when using multiple machines"); ASSERT(0); } } } else { if (machines.machine[0].NumCells > 1) { inCellMode = 1; ASSERT(NUM_CONSOLES(0) == NUM_CELLS(0)); ASSERT(NUM_ETHER_CONTROLLERS(0) == NUM_CELLS(0)); ASSERT(NUM_CLOCKS(0) == NUM_CELLS(0)); } }#endif /* * Check for any uninitialized parameters. I could also do this * within the Tcl access functions, but then I would miss the case * where C was accessing an uninitialized variable. */ for (i=0; i< paramCount; i++) { if (param[i].bitField) { for (machNo = 0; machNo < NUM_MACHINES; machNo++) { if (!IS_INITIALIZED(param[i], machNo)) { CPUWarning("PARAM: %s (machine %d) has not been initialized\n", param[i].name, machNo); badParamExists = TRUE; } } } else { if (!param[i].initialized) { CPUWarning("PARAM %s has not been initialized\n", param[i].name); badParamExists = TRUE; } } } if (badParamExists) { ASSERT(0); } /* * Compute all of the derived parameter fields */ MAX_CPUS_PER_MACHINE = 0; MAX_CONSOLES_PER_MACHINE = 0; MAX_ETHER_CONTROLLERS_PER_MACHINE = 0; MAX_CLOCKS_PER_MACHINE = 0; /* Find the total number of CPUS for allocating mapping vector */ for (machNo = 0, cpuCount = 0; machNo < NUM_MACHINES; machNo++) { cpuCount += NUM_CPUS(machNo); } /* Allocate memory for cpu to machine mapping array */ MachineFromCPU = (int*) calloc(SIM_MAXCPUS /* XXX cpuCount XXX */, sizeof(int)); for (machNo = 0, cpuCount = 0, memoryCount = 0, consoleCount = 0, etherCount = 0, clockCount = 0 ; machNo < NUM_MACHINES; machNo++) { machines.machine[machNo].MemSize = machines.machine[machNo].MemSizeSpecified*1024*1024; FIRST_CPU(machNo) = cpuCount; for (i = 0; i < NUM_CPUS(machNo); cpuCount++, i++) { MachineFromCPU[cpuCount] = machNo; } LAST_CPU(machNo) = cpuCount-1; if (NUM_CPUS(machNo) > MAX_CPUS_PER_MACHINE) MAX_CPUS_PER_MACHINE = NUM_CPUS(machNo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -