⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asm.c

📁 计算机系统结构的讲义,浓缩了一本一千多页的书.真的是好东西.
💻 C
📖 第 1 页 / 共 4 页
字号:
     * 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 + -