📄 asm.c
字号:
* Generate a reasonably-human-understandable error message. */ error: IndicateError(machPtr->interp, errMsg, wholeLine, p); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * Asm_Disassemble -- * * Given an instruction, return a string describing the instruction * in assembler format. * * Results: * The return value is a string, which either describes the * instruction or contains a message saying that the instruction * didn't make sense. The string is statically-allocated, meaning * that it will change on the next call to this procedure. * * Side effects: * None. * *---------------------------------------------------------------------- */char *Asm_Disassemble(machPtr, ins, pc) DLX *machPtr; /* Machine to use for symbol table info. */ int ins; /* The contents of the instruction. */ unsigned int pc; /* Memory address at which instruction is * located. */{ register OpcodeInfo *opPtr; OpcodeInfo *bestPtr; static char string[200]; int field, bestMask; int reg1, reg2; /* * Match this instruction against our instruction table to find * out what instruction it is. Look */ for (bestMask = 0, opPtr = opcodes; opPtr->name != NULL; opPtr++) { if (opPtr->mask == 0) { continue; } if ((ins & opPtr->mask) != (opPtr->op)) { continue; } if ((bestMask & opPtr->mask) != opPtr->mask) { bestMask = opPtr->mask; bestPtr = opPtr; } } if (bestMask == 0) { sprintf(string, "unrecognized instruction (0x%x)", ins); return string; } opPtr = bestPtr; /* * Dispatch on the type of the instruction. */ switch (opPtr->class) { case NO_ARGS: sprintf(string, "%s", opPtr->name); break; case LOAD: field = ins & 0xffff; sprintf(string, "%s %s,%s(%s)", opPtr->name, Asm_RegNames[(ins >> 16) & 0x1f], Sym_GetString(machPtr, (unsigned) field), Asm_RegNames[(ins >> 21) & 0x1f]); break; case FLOAD: field = ins & 0xffff; sprintf(string, "%s %s,%s(%s)", opPtr->name, Asm_RegNames[((ins >> 16) & 0x1f) + 32], Sym_GetString(machPtr, (unsigned) field), Asm_RegNames[(ins >> 21) & 0x1f]); break; case STORE: field = ins & 0xffff; sprintf(string, "%s %s(%s),%s", opPtr->name, Sym_GetString(machPtr, (unsigned) field), Asm_RegNames[(ins >> 21) & 0x1f], Asm_RegNames[(ins >> 16) & 0x1f]); break; case FSTORE: field = ins & 0xffff; sprintf(string, "%s %s(%s),%s", opPtr->name, Sym_GetString(machPtr, (unsigned) field), Asm_RegNames[(ins >> 21) & 0x1f], Asm_RegNames[((ins >> 16) & 0x1f) + 32]); break; case LUI: field = ins & 0xffff; sprintf(string, "%s %s,0x%x", opPtr->name, Asm_RegNames[(ins >> 16) & 0x1f], field); break; case ARITH: if (opPtr->flags & IMMEDIATE_REQ) { field = ins & 0xffff; sprintf(string, "%s %s,%s,0x%x", opPtr->name, Asm_RegNames[(ins >> 16) & 0x1f], Asm_RegNames[(ins >> 21) & 0x1f], field); } else { sprintf(string, "%s %s,%s,%s", opPtr->name, Asm_RegNames[(ins >> 11) & 0x1f], Asm_RegNames[(ins >> 21) & 0x1f], Asm_RegNames[(ins >> 16) & 0x1f]); } break; case FARITH: case MULDIV: sprintf(string, "%s %s,%s,%s", opPtr->name, Asm_RegNames[((ins >> 11) & 0x1f) + 32], Asm_RegNames[((ins >> 21) & 0x1f) + 32], Asm_RegNames[((ins >> 16) & 0x1f) + 32]); break; case SHIFT: if (opPtr->other == ALWAYS_VAR) { sprintf(string, "%s %s,%s,%s", opPtr->name, Asm_RegNames[(ins >> 11) & 0x1f], Asm_RegNames[(ins >> 16) & 0x1f], Asm_RegNames[(ins >> 21) & 0x1f]); } else { field = (ins >> 6) & 0x1f; sprintf(string, "%s %s,%s,%d", opPtr->name, Asm_RegNames[(ins >> 11) & 0x1f], Asm_RegNames[(ins >> 16) & 0x1f], field); } break; case BRANCH_0_OP: field = (ins & 0xffff); if (field & 0x8000) { field |= 0xffff0000; } field += pc + 4; sprintf(string, "%s %s", opPtr->name, Sym_GetString(machPtr, (unsigned) field)); break; case BRANCH_1_OP: field = (ins & 0xffff); if (field & 0x8000) { field |= 0xffff0000; } field += pc + 4; sprintf(string, "%s %s,%s", opPtr->name, Asm_RegNames[(ins >> 21) & 0x1f], Sym_GetString(machPtr, (unsigned) field)); break; case TRAP: field = (ins & 0x3ffffff); sprintf(string, "%s 0x%x", opPtr->name, field); break; case LABEL: case JUMP: field = (ins & 0x3ffffff); if (field & 0x2000000) { field |= 0xfc000000; } field += pc + 4; sprintf(string, "%s %s", opPtr->name, Sym_GetString(machPtr, (unsigned) field)); break; case SRC1: sprintf(string, "%s %s", opPtr->name, Asm_RegNames[(ins >> 21) & 0x1f]); break; case MOVE: case FCOMPARE: /* this is a R-type instruction */ reg1 = (ins >> 11) & 0x1f; reg2 = (ins >> 21) & 0x1f; if ((opPtr->flags & FIRST_F) || (opPtr->flags & FIRST_D)) reg1 += 32; if ((opPtr->flags & SECOND_F) || (opPtr->flags & SECOND_D)) reg2 += 32; sprintf(string, "%s %s,%s", opPtr->name, Asm_RegNames[reg1], Asm_RegNames[reg2]); break; default: sprintf(string, "instruction confused dis-assembler (0x%x)", ins); break; } return string;}/* *---------------------------------------------------------------------- * * Asm_AsmCmd -- * * This procedure is invoked to process the "asm" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- *//* ARGSUSED */intAsm_AsmCmd(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ DLX *machPtr = (DLX *) clientData; int result; unsigned int pc; char *end; int size, code[ASM_MAX_WORDS]; if ((argc != 2) && (argc != 3)) { sprintf(interp->result, "wrong # args: should be \"%.50s\" instruction [pc]", argv[0]); return TCL_ERROR; } if (argc == 3) { pc = strtoul(argv[2], &end, 0); if ((*end != 0) || (end == argv[2])) { sprintf(interp->result, "bad pc \"%.50s\"", argv[2]); return TCL_ERROR; } } else { pc = 0; } result = Asm_Assemble(machPtr, (char *) NULL, argv[1], pc, argv[1], 1, &size, code); if (result != TCL_OK) { return result; } sprintf(interp->result, "0x%x", code[0]); return TCL_OK;}/* *---------------------------------------------------------------------- * * Asm_LoadCmd -- * * This procedure is invoked to process the "load" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl return result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- *//* ARGSUSED */intAsm_LoadCmd(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Count of number of files in argv. */ char **argv; /* Array containing names of files to * assemble. */{ DLX *machPtr = (DLX *) clientData; unsigned int codeStart, dataStart; char *p, *end; LoadInfo info; int i; /* * Figure out the starting addresses for code and data (check for * variables "codeStart" and "dataStart", and use their values if * they're defined; otherwise use defaults). */ codeStart = 0x100; p = Tcl_GetVar(machPtr->interp, "codeStart", TCL_GLOBAL_ONLY); if (p != NULL) { codeStart = strtoul(p, &end, 0); if (*end != 0) { sprintf(machPtr->interp->result, "\"codeStart\" variable doesn't contain an address: \"%.50s\"", p); return TCL_ERROR; } } dataStart = 0x1000; p = Tcl_GetVar(machPtr->interp, "dataStart", TCL_GLOBAL_ONLY); if (p != NULL) { dataStart = strtoul(p, &end, 0); if (*end != 0) { sprintf(machPtr->interp->result, "\"dataStart\" variable doesn't contain an address: \"%.50s\"", p); return TCL_ERROR; } } /* * Pass 1: delete old symbol definitions. */ for (i = 1; i < argc; i++) { Sym_DeleteSymbols(machPtr, argv[i]); } /* * Pass 2: read through all of the files to build the symbol table. */ info.codeAddr = codeStart; info.dataAddr = dataStart; info.message = NULL; info.end = NULL; info.totalBytes = 0; info.errorCount = 0; info.flags = ASM_SIZE_ONLY; for (i = 1; i < argc; i++) { ReadFile(argv[i], machPtr, &info); } /* * Pass 3: read through the files a second time to actually assemble * the code. */ info.codeAddr = codeStart; info.dataAddr = dataStart; info.flags = 0; for (i = 1; i < argc; i++) { ReadFile(argv[i], machPtr, &info); if (info.errorCount > ASM_MAX_ERRORS) { break; } } if (info.message == NULL) { return TCL_OK; } Tcl_Return(machPtr->interp, info.message, TCL_DYNAMIC); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * ReadFile -- * * Read in an assembler file. * * Results: * None. * * Side effects: * Information gets loaded into *machPtr's memory, and *infoPtr * gets modified (to point to an error message, for example). * *---------------------------------------------------------------------- */static voidReadFile(fileName, machPtr, infoPtr) char *fileName; /* Name of assembler file to read. */ DLX *machPtr; /* Machine into whose memory the information * is to be loaded. */ register LoadInfo *infoPtr; /* Information about the state of the * assembly process. */{#define MAX_LINE_SIZE 200#define MAX_NAME_SIZE 10 char line[MAX_LINE_SIZE]; char pseudoOp[MAX_NAME_SIZE+1]; FILE *f; register char *p; int i, nullTerm; char *end, *curToken; char savedChar; char msg[40]; double strtod(); f = fopen(fileName, "r"); if (f == NULL) { if (infoPtr->flags & ASM_SIZE_ONLY) { return; } sprintf(machPtr->interp->result, "couldn't open file \"%.50s\": %.100s", fileName, strerror(errno)); AddErrMsg(machPtr->interp, infoPtr, 0); return; } /* * Process the file one line at a time. */ infoPtr->file = fileName; infoPtr->dot = (infoPtr->codeAddr + 3) & ~3; infoPtr->flags |= ASM_CODE; for (infoPtr->lineNum = 1; ; infoPtr->lineNum++) { infoPtr->line = fgets(line, MAX_LINE_SIZE, f); if (infoPtr->line == NULL) { if (!feof(f)) { sprintf(machPtr->interp->result, "error reading file: %.100s", strerror(errno)); AddErrMsg(machPtr->interp, infoPtr, 1); } break; } /* * Skip leading blanks. */ for (p = line; (*p == ' ') || (*p == '\t'); p++) { /* Null body: just skip spaces. */ } /* * Parse off an optional symbol at the beginning of the line. * Note: force symbol-related error messages to be output * during pass 1, even though most other error messages get * ignored during pass 1. */ if (isalpha(*p) || (*p == '_') || (*p == '$')) { curToken = p; for (p++; isalnum(*p) || (*p == '_') || (*p == '$'); p++) { /* Null body: just skip past symbol. */ } if (*p == ':') { *p = 0; if (infoPtr->flags & ASM_SIZE_ONLY) { Sym_AddSymbol(machPtr, fileName, curToken, infoPtr->dot, 0); if (*machPtr->interp->result != 0) { AddErrMsg(machPtr->interp, infoPtr, 1); } } *p = ':'; p++; } else { p = curToken; } } /* * Skip empty lines.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -