📄 asm.c
字号:
register char *p; /* Current character in string. */ char *errMsg; char *opStart; int length; char msg[100]; int isReg[3]; /* Tells whether each operand in the * instruction is a register. */ int operands[3]; /* Value of each operand (reg #, * immediate, shift amount, etc.). */ char *argStart[3]; /* First chars. of arguments (for * error reporting). */ int numOps; /* Number of operands in the * instruction. */ int done; int requireF, requireD; /* set if the current operand must be * float or double */ /* * Parse off the instruction name, and look it up in the table. */ for (p = string; (*p == ' ') || (*p == '\t'); p++) { /* Empty loop body. */ } opStart = p; for ( ; isalnum(*p); p++) { /* Empty loop body. */ } length = p-opStart; if (length > 0) { for (insPtr = opcodes; insPtr->name != NULL; insPtr++) { if ((insPtr->name[0] == opStart[0]) && (strncmp(insPtr->name, opStart, length) == 0) && (insPtr->name[length] == 0)) { codePtr[0] = insPtr->op; goto gotIns; } } } errMsg= "unknown opcode"; p = opStart; goto error; /* * Parse up to three operand fields in the instruction, storing * information in isReg[], operands[], and numOps. */ gotIns: isReg[0] = isReg[1] = isReg[2] = 0; operands[0] = operands[1] = operands[2] = 0; for (numOps = 0; numOps < 3; numOps++) { char *end, savedChar; int result; /* * Find the starting character for this operand specifier. */ while ((*p == ' ') || (*p == '\t')) { p++; } argStart[numOps] = p; /* * The code below is a special case to handle the second * specifier for instructions in the load-store class. Accept * an optional expression followed by an optional register * name in parentheses. */ if (((numOps == 0) && ((insPtr->class == STORE) || (insPtr->class == FSTORE))) || ((numOps == 1) && ((insPtr->class == LOAD) || (insPtr->class == FLOAD)))) { if (*p == '(') { operands[numOps] = 0; } else { if (Sym_EvalExpr(machPtr, fileName, p, sizeOnly, &operands[numOps], &end) != TCL_OK) { errMsg = machPtr->interp->result; goto error; } p = end; } while ((*p == ' ') || (*p == '\t')) { p++; } argStart[++numOps] = p; isReg[numOps] = 1; operands[numOps] = 0; if (*p == '(') { for (p++; *p != ')'; p++) { if ((*p == 0) || (*p == ';')) { p = argStart[numOps]; errMsg = "missing ) after base register"; goto error; } } savedChar = *p; *p = 0; result = Sym_GetSym(machPtr, fileName, argStart[numOps]+1, SYM_REGS_OK, (unsigned int *) &operands[numOps]); *p = savedChar; if (result != SYM_REGISTER) { p = argStart[numOps]+1; errMsg = (result == SYM_FREG_FOUND) ? "floating register invalid here" : "bad base register name"; goto error; } p++; } /* read till we find a separator */ for (done = 0; !done; ) { switch (*p) { case ',' : case '#' : case ';' : case '\n' : case '\0' : done = 1; break; case ' ' : case '\t' : break; default : errMsg = "unknown garbage in expression"; goto error; } if (!done) p++; } end = p; goto about_to_continue; } /* * Back to the normal case. Find the end of the current * operand specifier. */ while ((*p != ',') && (*p != ';') && (*p != 0) && (*p != '\n')) { p++; } end = p; if (p == argStart[numOps]) { if (numOps == 0) { break; } errMsg = "empty operand specifier"; goto error; } for (p--; (*p == ' ') || (*p == '\t'); p--) { /* Null loop body; just backspace over space */ } p++; /* * Figure out what kind of operand this is. */ savedChar = *p; *p = 0; /* determine if we need a floating/double register now */ requireF = ((numOps == 0) && (insPtr->flags & FIRST_F)) || ((numOps == 1) && (insPtr->flags & SECOND_F)) || ((numOps == 2) && (insPtr->flags & THIRD_F)); requireD = ((numOps == 0) && (insPtr->flags & FIRST_D)) || ((numOps == 1) && (insPtr->flags & SECOND_D)) || ((numOps == 2) && (insPtr->flags & THIRD_D)); if (requireF || requireD) { result = Sym_GetSym(machPtr, fileName, argStart[numOps], SYM_FREGS_OK, (unsigned int *) &operands[numOps]); if (result != SYM_REGISTER) { *p = savedChar; p = argStart[numOps]; errMsg = "floating pointer register required"; goto error; } isReg[numOps] = 1; if (requireD && (operands[numOps] & 1)) { *p = savedChar; p = argStart[numOps]; errMsg = "double floating point register required"; goto error; } } else { result = Sym_GetSym(machPtr, fileName, argStart[numOps], SYM_REGS_OK, (unsigned int *) &operands[numOps]); if (result == SYM_REGISTER) { isReg[numOps] = 1; } else if (result == SYM_FREG_FOUND) { *p = savedChar; p = argStart[numOps]; errMsg = "floating register invalid here"; goto error; } else if (result != SYM_FOUND) { char *term; if (Sym_EvalExpr(machPtr, (char *) NULL, argStart[numOps], sizeOnly, (int *) &operands[numOps], &term) != TCL_OK) { *p = savedChar; p = argStart[numOps]; errMsg = "unrecognizable operand specifier"; goto error; } if (*term != 0) { *p = savedChar; p = term; errMsg = "unknown garbage in expression"; goto error; } } } *p = savedChar; /* * See if this is the last argument. If not, skip over the * separating comma. */about_to_continue: p = end; if (*p != ',') { numOps++; break; } if (numOps == 2) { errMsg = "more than three operands"; goto error; } p++; } /* * Check argument count for propriety. */ if ((numOps < minArgs[insPtr->class]) || (numOps > maxArgs[insPtr->class])) { if (minArgs[insPtr->class] == maxArgs[insPtr->class]) { sprintf(msg, "wrong # operands (must be %d)", minArgs[insPtr->class]); } else { sprintf(msg, "wrong # operands (must be %d or %d)", minArgs[insPtr->class], maxArgs[insPtr->class]); } p = argStart[0]; errMsg = msg; goto error; } /* * Check immediate arguments for proper range. */ if (insPtr->flags & (CHECK_LAST | CHECK_NEXT_TO_LAST | CHECK_FIRST)) { int i; if (insPtr->flags & CHECK_LAST) { i = numOps-1; } else if (insPtr->flags & CHECK_FIRST) { i = 0; } else { i = numOps-2; } if (i >= 0) { if (isReg[i]) { if (insPtr->flags & IMMEDIATE_REQ) { p = argStart[i]; regIllegal: errMsg = "register operand not allowed"; goto error; } } else { int j; j = operands[i] & insPtr->rangeMask; if (j != 0) { if (!(insPtr->flags & SIGN_EXTENDED) || (j != insPtr->rangeMask)) { p = argStart[i]; sprintf(msg, "immediate operand 0x%x out of range", operands[i]); errMsg = msg; goto error; } } } } } /* * Dispatch based on the class of instruction, and handle everything * else in a class-specific fashion. */ *sizePtr = 1; switch (insPtr->class) { case NO_ARGS: codePtr[0] = insPtr->op; break; case LOAD: case FLOAD: codePtr[0] = insPtr->op | (operands[0] << 16) | (operands[1] & 0xffff) | (operands[2] << 21); break; case STORE: case FSTORE: codePtr[0] = insPtr->op | (operands[0] & 0xffff) | (operands[1] << 21) | (operands[2] << 16); break; case LUI: codePtr[0] = insPtr->op | (operands[0] << 16) | (operands[1] & 0xffff); break; /* * The main class of arithmetic instructions can get assembled * in many different ways. Most instructions can end using either * the normal register-to-register opcode, or an immediate opcode, * which is stored in insPtr->other. If the instruction MUST use * only the immediate form, a special value of insPtr->other * indicates this fact. */ case ARITH: case FARITH: case MULDIV: case SHIFT: if (!isReg[0]) { p = argStart[0]; regRequired: errMsg = "operand must be a register"; goto error; } else if (!isReg[1]) { p = argStart[1]; goto regRequired; } if (insPtr->class == ARITH) { if (isReg[2]) { codePtr[0] = insPtr->op | (operands[0] << 11) | (operands[1] << 21) | (operands[2] << 16); } else if (insPtr->flags & IMMEDIATE_REQ) { codePtr[0] = insPtr->op | (operands[0] << 16) | (operands[1] << 21) | (operands[2] & 0xffff); } else { codePtr[0] = insPtr->other | (operands[0] << 16) | (operands[1] << 21) | (operands[2] & 0xffff); } } else if (insPtr->class == SHIFT) { if (isReg[2]) { codePtr[0] = insPtr->op | (operands[0] << 11) | (operands[1] << 21) | (operands[2] << 16); } else if (insPtr->flags & IMMEDIATE_REQ) { codePtr[0] = insPtr->op | (operands[0] << 11) | (operands[1] << 16) | (operands[2] << 6); } else { codePtr[0] = insPtr->other | (operands[0] << 11) | (operands[1] << 16) | (operands[2] << 6); } } else if ((insPtr->class == MULDIV) || (insPtr->class == FARITH)) { if (!isReg[2]) { p = argStart[2]; goto regRequired; } codePtr[0] = insPtr->op | (operands[0] << 11) | (operands[1] << 21) | (operands[2] << 16); } break; /* * Branches: generate (and check) the branch displacement, which * is done the same for all branch instructions. Then handle * different sub-classes differently. */ case JUMP: if (isReg[0]) /* treat it like SRC1 */ codePtr[0] = insPtr->other | (operands[0] << 21); /* I know this falls through, this is just here to allow for * the user to use j instead of jr for instance */ case BRANCH_0_OP: case BRANCH_1_OP: case LABEL: { int disp, mask; if (isReg[numOps-1]) { p = argStart[numOps-1]; goto regIllegal; } disp = operands[numOps-1]; if (disp & 0x3) { p = argStart[numOps-1]; errMsg = "branch target not word-aligned"; goto error; } disp = disp - (dot+4); if ((insPtr->class == JUMP) || (insPtr->class == LABEL)) mask = 0xfe000000; else mask = 0xffff8000; if ((disp & mask) && ((disp & mask) != mask)) { p = argStart[numOps-1]; sprintf(msg, "branch target too far away (offset 0x%x)", disp); errMsg = msg; goto error; } if (insPtr->class == BRANCH_1_OP) { codePtr[0] = insPtr->op | (disp & 0xffff) | (operands[0] << 21); } else if (insPtr->class == BRANCH_0_OP) { codePtr[0] = insPtr->op | (disp & 0xffff); } else { /* JUMP or LABEL */ codePtr[0] = insPtr->op | (disp & 0x3ffffff); } break; } case TRAP: if (isReg[0]) { p = argStart[0]; goto regIllegal; } codePtr[0] = insPtr->op | (operands[0] & 0x3ffffff); break; case SRC1: if (!isReg[0]) { p = argStart[0]; goto regRequired; } codePtr[0] = insPtr->op | (operands[0] << 21); break; case MOVE: /* these are all R-type instructions */ if (!isReg[0]) { p = argStart[0]; goto regRequired; } if (!isReg[1]) { p = argStart[1]; goto regRequired; } codePtr[0] = insPtr->op | (operands[0] << 11) | (operands[1] << 21); break; case FCOMPARE: /* these are all R-type instructions */ if (!isReg[0]) { p = argStart[0]; goto regRequired; } if (!isReg[1]) { p = argStart[1]; goto regRequired; } codePtr[0] = insPtr->op | (operands[0] << 21) | (operands[1] << 16); break; default: errMsg = "internal error: unknown class for instruction"; goto error; } /* * Make sure that there's no garbage left on the line after the * instruction. */ while (isspace(*p)) { p++; } if ((*p != 0) && (*p != ';')) { errMsg = "extra junk at end of line"; goto error; } return TCL_OK; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -