📄 asm.c
字号:
/* * asm.c -- * * The procedures in this file do assembly and dis-assembly of * DLX assembler instructions. * * This file is part of DISC. It was modified by Yinong Zhang * (yinong@ecn.purdue.edu) from the file "asm.c" in the distribution * of "dlxsim" available at: * ftp://max.stanford.edu/pub/hennessy-patterson.software/dlx.tar.Z * * The original source code is copyright as follows: * * Copyright 1989 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * */#include <ctype.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <tcl.h>#include "dlx.h"#include "sym.h"/* * The following structure type encapsulates the state of loading one * or more assembler files, and is used for communication between the * procedures that do assembly. */typedef struct { char *file; /* Name of file currently being assembled * (none means info to assemble comes from * some source other than file). */ int lineNum; /* Line number within file (-1 if info being * assembled doesn't come from file). */ char *line; /* Contents of entire line being assembled * (useful for error messages). */ unsigned int codeAddr; /* Next address to place information in * code area. */ unsigned int dataAddr; /* Next address to place information in * data area. */ unsigned int dot; /* Address at which to place information * (can be either code or data). */ /* * Information used to build up a concatenated version of all the * error strings that occur while reading the files: */ char *message; /* Pointer to current message (calloc-ed). * NULL means no error has occurred so far. */ char *end; /* Address of NULL byte at end of message; * append new messages here. */ int totalBytes; /* # of bytes allocated at message. 0 means * no error has occurred yet. */ int errorCount; /* If too many errors occur, give up. */ int flags; /* Various flags: see below for values. */} LoadInfo;/* * Flags for LoadInfo structures: * * ASM_CODE - 1 means currently assembling into code * area; 0 means currently assembling into * data area. * ASM_SIZE_ONLY - 1 means this is the first pass, where the * only important thing is size (suppress * all error messages). * ASM_ALIGN_0 - 1 means that an "align 0" command is in * effect. */#define ASM_CODE 1#define ASM_SIZE_ONLY 2#define ASM_ALIGN_0 4#define ASM_MAX_ERRORS 20/* * The #defines below specify the different classes of instructions, * as defined on pp. D-4 to D-6 of Kane's book. These classes are used * during assembly, and indicate the different formats that may be taken * by operand specifiers for a particular opcode. * * NO_ARGS - no operands * LOAD - (register, address) * STORE - (address, register) * LUI - (dest, 16-bit expression) * ARITH - (dest, src1, sr2c) OR (dest/src1, src2) * OR (dest, src1, 16-bit immediate) * OR (dest/src1, 16-bit immediate) * MULDIV - same as ARITH (special subset to handle * mult/divide/rem instructions because they * operate on floating point registers) * SHIFT - same as ARITH (special subset to handle * shifting instructions) * BRANCH_0_OP - (label) the source register is implied * BRANCH_1_OP - (src1, label) * JUMP - (label) OR (src1) * SRC1 - (src1) * LABEL - (label) * MOVE - (dest,src1) * FLOAD - like LOAD, for floating/double * FSTORE - like STORE, for floating/double * FARITH - like ARITH, for floating point * FCOMPARE - compare two floating point numbers * TRAP - (trap number) */#define NO_ARGS 0#define LOAD 1#define STORE 2#define LUI 3#define ARITH 4#define MULDIV 5#define SHIFT 6#define BRANCH_0_OP 7#define BRANCH_1_OP 8#define JUMP 9#define SRC1 10#define LABEL 11#define MOVE 12#define FLOAD 13#define FSTORE 14#define FARITH 15#define FCOMPARE 16#define TRAP 17/* * The tables below give the maximum and minimum # of arguments * permissible for each class above. */static int minArgs[] = {0, 3, 3, 2, 3, 3, 3, 1, 2, 1, 1, 1, 2, 3, 3, 3, 2, 1};static int maxArgs[] = {0, 3, 3, 2, 3, 3, 3, 1, 2, 1, 1, 1, 2, 3, 3, 3, 2, 1};/* * Structures of the following type are used during assembly and * disassembly. One such structure exists for each defined op code. */typedef struct { char *name; /* Opcode name, e.g. "add". */ int class; /* Class of instruction (see table above). */ int op; /* Bit pattern corresponding to this * instruction. */ int mask; /* Used for disassembly: if these bits match * op, then use this opcode for disassembly. * 0 means this is a synthesized instruction * that doesn't exist in native form, so * it should be ignored during disassembly. */ int other; /* This field is used when the assembler * is generating multiple instructions for * a single opcode, or when different * instructions may be generated for the * same opcode (e.g. add -> addi). The * meaning of the field depends on class; * see the code in Asm_Assemble. */ int flags; /* OR-ed combination of bits, giving various * information for use during assembly, such * as for range checking. See below for * values. */ int rangeMask; /* Mask for use in range check: for unsigned * check, none of these bits must be set. For * sign-extended check, either all or none * must be set. */} OpcodeInfo;/* * Bits for "flags" field, used for range checking: * * CHECK_FIRST - 1 means check first argument, if it is an immediate * CHECK_LAST - 1 means check last argument, if it is * an immediate. * CHECK_NEXT_TO_LAST - 1 means check next-to-last argument, if it * is an immediate. * IMMEDIATE_REQ - 1 means the argument given above MUST be * an immediate. * SIGN_EXTENDED - 1 means the immediate will be sign-extended. * FIRST_F * SECOND_F * THIRD_F Must the 1st/2nd/3rd be a single or double prec. * floating point register * FIRST_D * SECOND_D * THIRD_D Must the 1st/2nd/3rd be a double prec. register? */#define CHECK_LAST 0x1#define CHECK_NEXT_TO_LAST 0x2#define IMMEDIATE_REQ 0x4#define SIGN_EXTENDED 0x8#define CHECK_FIRST 0x10#define FIRST_INT 0x20#define SECOND_INT 0x40#define THIRD_INT 0x80#define FIRST_F 0x100#define SECOND_F 0x200#define THIRD_F 0x400#define FIRST_D 0x800#define SECOND_D 0x1000#define THIRD_D 0x2000/* * The following value for "other" is used in the SHIFT class to * indicate that this instruction must always take the variable * form. */#define ALWAYS_VAR 0xfffffffe/* * Table of all known instructions: */OpcodeInfo opcodes[] = { {"add", ARITH, 0x20, 0xfc00003f, 0x20000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"addd", FARITH, 0x04000004, 0xfc00003f, 0, FIRST_D|SECOND_D|THIRD_D, 0}, {"addf", FARITH, 0x04000000, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"addi", ARITH, 0x20000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"addu", ARITH, 0x21, 0xfc00003f, 0x24000000, CHECK_LAST, 0xffff0000}, {"addui", ARITH, 0x24000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"and", ARITH, 0x24, 0xfc00003f, 0x30000000, CHECK_LAST, 0xffff0000}, {"andi", ARITH, 0x30000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"beqz", BRANCH_1_OP, 0x10000000, 0xfc000000, 0, 0, 0}, {"bfpf", BRANCH_0_OP, 0x18000000, 0xfc000000, 0, 0, 0}, {"bfpt", BRANCH_0_OP, 0x1c000000, 0xfc000000, 0, 0, 0}, {"bnez", BRANCH_1_OP, 0x14000000, 0xfc000000, 0, 0, 0}, {"cvtd2f", MOVE, 0x0400000a, 0xfc00003f, 0, FIRST_F|SECOND_D, 0}, {"cvtd2i", MOVE, 0x0400000b, 0xfc00003f, 0, FIRST_F|SECOND_D, 0}, {"cvtf2d", MOVE, 0x04000008, 0xfc00003f, 0, FIRST_D|SECOND_F, 0}, {"cvtf2i", MOVE, 0x04000009, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"cvti2d", MOVE, 0x0400000d, 0xfc00003f, 0, FIRST_D|SECOND_F, 0}, {"cvti2f", MOVE, 0x0400000c, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"div", MULDIV, 0x0400000f, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"divd", FARITH, 0x04000007, 0xfc00003f, 0, FIRST_D|SECOND_D|THIRD_D, 0}, {"divf", FARITH, 0x04000003, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"divu", MULDIV, 0x04000017, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"eqd", FCOMPARE, 0x04000018, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"eqf", FCOMPARE, 0x04000010, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"ged", FCOMPARE, 0x0400001d, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"gef", FCOMPARE, 0x04000015, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"gtd", FCOMPARE, 0x0400001b, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"gtf", FCOMPARE, 0x04000013, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"j", JUMP, 0x08000000, 0xfc000000, 0x48000000, 0, 0}, {"jal", JUMP, 0x0c000000, 0xfc000000, 0x4c000000, 0, 0}, {"jalr", SRC1, 0x4c000000, 0xfc000000, 0, 0, 0}, {"jr", SRC1, 0x48000000, 0xfc000000, 0, 0, 0}, {"lb", LOAD, 0x80000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"lbu", LOAD, 0x90000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"ld", FLOAD, 0x9c000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED|FIRST_D, 0xffff8000}, {"led", FCOMPARE, 0x0400001c, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"lef", FCOMPARE, 0x04000014, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"lf", FLOAD, 0x98000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED|FIRST_F, 0xffff8000}, {"lh", LOAD, 0x84000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"lhi", LUI, 0x3c000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"lhu", LOAD, 0x94000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"ltd", FCOMPARE, 0x0400001a, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"ltf", FCOMPARE, 0x04000012, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"lw", LOAD, 0x8c000000, 0xfc000000, 0, CHECK_NEXT_TO_LAST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"movd", MOVE, 0x00000033, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"movf", MOVE, 0x00000032, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"movfp2i", MOVE, 0x00000034, 0xfc00003f, 0, SECOND_F, 0}, {"movi2fp", MOVE, 0x00000035, 0xfc00003f, 0, FIRST_F, 0}, {"movi2s", MOVE, 0x00000030, 0xfc00003f, 0, 0, 0}, {"movs2i", MOVE, 0x00000031, 0xfc00003f, 0, 0, 0}, {"mult", MULDIV, 0x0400000e, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"multd", FARITH, 0x04000006, 0xfc00003f, 0, FIRST_D|SECOND_D|THIRD_D, 0}, {"multf", FARITH, 0x04000002, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"multu", MULDIV, 0x04000016, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"ned", FCOMPARE, 0x04000019, 0xfc00003f, 0, FIRST_D|SECOND_D, 0}, {"nef", FCOMPARE, 0x04000011, 0xfc00003f, 0, FIRST_F|SECOND_F, 0}, {"nop", NO_ARGS, 0x0, 0xffffffff, 0, 0, 0}, {"or", ARITH, 0x25, 0xfc00003f, 0x34000000, CHECK_LAST, 0xffff0000}, {"ori", ARITH, 0x34000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"rfe", LABEL, 0x40000000, 0xfc000000, 0, 0, 0xfe000000}, {"sb", STORE, 0xa0000000, 0xfc000000, 0, CHECK_FIRST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"sd", FSTORE, 0xbc000000, 0xfc000000, 0, CHECK_FIRST|IMMEDIATE_REQ|SIGN_EXTENDED|THIRD_D, 0xffff8000}, {"seq", ARITH, 0x00000028, 0xfc00003f, 0x60000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"seqi", ARITH, 0x60000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"sequ", ARITH, 0x00000010, 0xfc00003f, 0xc0000000, CHECK_LAST, 0xffff0000}, {"sequi", ARITH, 0xc0000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sf", FSTORE, 0xb8000000, 0xfc000000, 0, CHECK_FIRST|IMMEDIATE_REQ|SIGN_EXTENDED|THIRD_F, 0xffff8000}, {"sge", ARITH, 0x0000002d, 0xfc00003f, 0x74000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"sgei", ARITH, 0x74000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"sgeu", ARITH, 0x00000015, 0xfc00003f, 0xd4000000, CHECK_LAST, 0xffff0000}, {"sgeui", ARITH, 0xd4000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sgt", ARITH, 0x0000002b, 0xfc00003f, 0x6c000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"sgti", ARITH, 0x6c000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"sgtu", ARITH, 0x00000013, 0xfc00003f, 0xcc000000, CHECK_LAST, 0xffff0000}, {"sgtui", ARITH, 0xcc000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sh", STORE, 0xa4000000, 0xfc000000, 0, CHECK_FIRST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"sle", ARITH, 0x0000002c, 0xfc00003f, 0x70000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"slei", ARITH, 0x70000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"sleu", ARITH, 0x00000014, 0xfc00003f, 0xd0000000, CHECK_LAST, 0xffff0000}, {"sleui", ARITH, 0xd0000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sll", SHIFT, 0x4, 0xfc00003f, 0x0, CHECK_LAST, 0xffffffe0}, {"slli", SHIFT, 0x0, 0xfc00003f, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffffffe0}, {"slt", ARITH, 0x0000002a, 0xfc00003f, 0x68000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"slti", ARITH, 0x68000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"sltu", ARITH, 0x00000012, 0xfc00003f, 0xc8000000, CHECK_LAST, 0xffff0000}, {"sltui", ARITH, 0xc8000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sne", ARITH, 0x00000029, 0xfc00003f, 0x64000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"snei", ARITH, 0x64000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"sneu", ARITH, 0x00000011, 0xfc00003f, 0xc4000000, CHECK_LAST, 0xffff0000}, {"sneui", ARITH, 0xc4000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sra", SHIFT, 0x7, 0xfc00003f, 0x3, CHECK_LAST, 0xffffffe0}, {"srai", SHIFT, 0x3, 0xfc00003f, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffffffe0}, {"srl", SHIFT, 0x6, 0xfc00003f, 0x2, CHECK_LAST, 0xffffffe0}, {"srli", SHIFT, 0x2, 0xfc00003f, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffffffe0}, {"sub", ARITH, 0x22, 0xfc00003f, 0x28000000, CHECK_LAST|SIGN_EXTENDED, 0xffff8000}, {"subd", FARITH, 0x04000005, 0xfc00003f, 0, FIRST_D|SECOND_D|THIRD_D, 0}, {"subf", FARITH, 0x04000001, 0xfc00003f, 0, FIRST_F|SECOND_F|THIRD_F, 0}, {"subi", ARITH, 0x28000000, 0xfc000000, 0, CHECK_LAST|SIGN_EXTENDED|IMMEDIATE_REQ, 0xffff8000}, {"subu", ARITH, 0x23, 0xfc00003f, 0x2c000000, CHECK_LAST, 0xffff0000}, {"subui", ARITH, 0x2c000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {"sw", STORE, 0xac000000, 0xfc000000, 0, CHECK_FIRST|IMMEDIATE_REQ|SIGN_EXTENDED, 0xffff8000}, {"trap", TRAP, 0x44000000, 0xfc000000, 0, CHECK_FIRST|IMMEDIATE_REQ, 0xfc000000}, {"xor", ARITH, 0x26, 0xfc00003f, 0x38000000, CHECK_LAST, 0xffff0000}, {"xori", ARITH, 0x38000000, 0xfc000000, 0, CHECK_LAST|IMMEDIATE_REQ, 0xffff0000}, {NULL, NO_ARGS, 0, 0, 0, 0, 0}};/* * Opcode values that are used in the code of this module: */#define SUBU_OP 0x23#define ADDI_OP 0x20000000#define ADDIU_OP 0x24000000#define LUI_OP 0x3c000000#define ORI_OP 0x34000000#define BEQ_OP 0x10000000#define BNE_OP 0x14000000#define LOAD_IMM(reg, x) (0x20000000 | ((reg) << 16) | ((x) & 0xffff))#define LOAD_IMM_UNS(reg, x) (0x34000000 | ((reg) << 16) | ((x) & 0xffff))/* * Table mapping from register number to register name. */char *Asm_RegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "hi", "lo", "pc", "npc", /* some of these will be removed later <bly> */ "status", "cause", "epc"};/* * Size of largest instruction we can assemble, in words: */#define ASM_MAX_WORDS 5 /* probably 1 <bly> *//* * Forward declarations for procedures defined in this file: */static void AddErrMsg(Tcl_Interp *, LoadInfo *, int);static void IndicateError(Tcl_Interp *, char *, char *, char *);static void ReadFile(char *, DLX *, LoadInfo *);static int StoreWords(DLX *, unsigned int, int *, int, int);/* *---------------------------------------------------------------------- * * Asm_Assemble -- * * Given a string describing an assembler instruction, return * the binary code corresponding to the instruction. * * Results: * The return value is a standard Tcl result (normally TCL_OK plus * an empty string). If the assembly completed successfully, then * *sizePtr gets filled in with the # of instruction words assembled * (may be more than 1 for special pseudo-instructions), and the * word(s) at *codePtr get filled in with the actual instruction. * * Side effects: * None. * *---------------------------------------------------------------------- */intAsm_Assemble(machPtr, fileName, string, dot, wholeLine, sizeOnly, sizePtr, codePtr) DLX *machPtr; /* Machine for which assembly is done: * used for symbol table and error * reporting. */ char *fileName; /* File name to use for symbol * lookups. See GetSym procedure in * sym.c for more information. */ char *string; /* DLX assembler instruction. */ unsigned int dot; /* Where in memory instruction(s) will * be placed. */ char *wholeLine; /* Entire line containing string; used * when printing error messages. */ int sizeOnly; /* Non-zero means this is the first * pass, so ignore errors and just * compute the size of the instruction. */ int *sizePtr; /* Fill in with # words assembled * for this instruction. */ int *codePtr; /* Pointer to ASM_MAX_WORDS words * storage, which get filled in with * assembled code. */{ register OpcodeInfo *insPtr; /* Info about instruction. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -