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

📄 asm.c

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