?? moon.c
字號:
/* Moon Simulator. * * Author: Peter Grogono * Last modified: 30 January 1995 * * This source file was created using a tab width of 4 characters. */#include <stdio.h>#include <ctype.h>#include <string.h>#include <math.h>#include <stdlib.h>/* Notes on definitions. * The memory occupies about 6 * MEMSIZE bytes. Enlarging it may create * problems for architectures with memory restrictions, such as the PC. * * The simulator is not completely independent of the underlying * processor. Known variations include: * - trace output depends on whether the host is big- or little endian. * - the MOON `sr' op uses the C `>>' operator. */#define MEMSIZE 8191 /* Memory size in 4-byte words. */#define MAXREG 16 /* Number of registers. */#define MAXINFILES 20 /* Restricts # input files. */#define MAXNAMELEN 60 /* Restricts path/file name length. */#define BUFLEN 255 /* Scanner input buffer. */#define TOKLEN 255 /* Scanner token buffer. */#define RANGE 20 /* Determines size of memory dump. */#define FALSE 0#define TRUE 1#define BYTE unsigned char/* The following function reports syntax errors. It is declared here so * that it can be used by memory functions; its definition appears in the * loader section. */void syntaxerror (char *message);/* The following function reports run-time errors. It is declared here so * that it can be used by memory functions; its definition appears in the * execution section. */void runtimeerror (char *message);/************************ MEMORY ********************************************//* A word of memory contains an instruction (A or B format), four bytes, * or a 32-bit signed integer. The simulated memory also contains two * flags, to tell whether the word contains an instruction and whether * it is a breakpoint. * * The simulated memory is an array of four-byte words. Simulated * addresses are byte addresses. Consequently, all addresses are * shifted right 2 bits before being used. Only the memory module * should know about this. Conventionally, <addr> is a byte address * and <wordaddr> is a word address. */typedef union { struct { unsigned op:6; unsigned ri:4; unsigned rj:4; unsigned rk:4; unsigned :14; } fmta; struct { unsigned op:6; unsigned ri:4; unsigned rj:4; unsigned :2; int k:16; /* Unsigned is not portable! */ } fmtb; BYTE byts [4]; long data; } wordtype;/* Each component of the memory array contains: * - word: The contents of simulated memory. * - cont: `a' => format A instruction * `b' => format B instruction * 'd' => data * `u' => undefined * - breakpoint: True if this is a breakpoint. */struct { wordtype word; char cont; short breakpoint; } mem [MEMSIZE];long ic; /* Instruction counter: contains address of instruction that will be executed next. */wordtype ir; /* Instruction register: contains the instruction that will be executed next. */long mar; /* Memory address register; stores word address of last access. */wordtype mdr; /* Memory data register; stores result of last access. */long entrypoint = -1; /* Address of first instruction */long cycles = 0; /* Counts memory cycles. *//* Initialize the memory: value=zero, kind=undef, no breakpoint. * Set "hardware" addresses to an illegal value. */void initmem () { long wordaddr; for (wordaddr = 0; wordaddr < MEMSIZE; wordaddr++) { mem[wordaddr].word.data = 0; mem[wordaddr].cont = 'u'; mem[wordaddr].breakpoint = FALSE; ic = -1; mar = -1; } }/* Report a run-time error if an illegal address is used. */short outofrange (long addr) { if (addr < 0 || (addr >> 2) > MEMSIZE) { runtimeerror("address error"); return 1; } return 0; }/* Report a run-time error if a memory word access is not on a * four-byte boundary. */short misaligned (long addr) { if (addr & 3) { runtimeerror("alignment error"); return 1; } return 0; }/* Fetch the instruction at <ic>, store it in <ir>, and increment <ic>. */short fetch () { short cont; if (outofrange(ic)) { ir.data = 0; return 0; } cont = mem[ic >> 2].cont; if (!(cont == 'a' || cont == 'b')) { runtimeerror("illegal instruction"); ir.data = 0; return 0; } ir = mem[ic >> 2].word; ic += 4; cycles += 10; return cont; }/* Fetch a data word from memory and return it. */long getmemword (long addr) { long wordaddr; if (outofrange(addr) || misaligned(addr)) return 0; wordaddr = addr >> 2; if (wordaddr == mar) cycles += 1; else { mar = wordaddr; mdr = mem[wordaddr].word; cycles += 10; } return mdr.data; }/* Store a word in memory. */void putmemword (long addr, long data) { long wordaddr; if (outofrange(addr) || misaligned(addr)) return; wordaddr = addr >> 2; if (mem[wordaddr].cont == 'a' || mem[wordaddr].cont == 'b') { runtimeerror("overwriting instructions"); return; } mdr.data = data; mar = wordaddr; mem[mar].word = mdr; mem[mar].cont = 'd'; cycles += 10; return; }/* Fetch a byte from memory. */BYTE getmembyte (long addr) { long wordaddr = addr >> 2; short offset = addr & 3; if (outofrange(addr)) return 0; if (wordaddr == mar) cycles += 1; else { mar = wordaddr; cycles += 10; } mdr = mem[mar].word; return mdr.byts[offset]; }/* Store a byte in memory. */void putmembyte (long addr, BYTE byt) { long wordaddr = addr >> 2; short offset = addr & 3; if (outofrange(addr)) return; if (mem[wordaddr].cont == 'a' || mem[wordaddr].cont == 'b') { runtimeerror("overwriting instructions"); return; } mem[wordaddr].word.byts[offset] = byt & 255; mem[wordaddr].cont = 'd'; return; }/* Store an instruction in memory. Used only by loader. */void putmeminstr (long addr, wordtype word, char cont) { if (addr & 3) syntaxerror("alignment error"); else { long wordaddr = addr >> 2; mem[wordaddr].word = word; mem[wordaddr].cont = cont; } }/* Store a character in memory. Used only by loader. */void putmemchar (long addr, short byte, char cont) { long wordaddr = addr >> 2; mem[wordaddr].word.byts[addr & 3] = byte; mem[wordaddr].cont = cont; }/********************** REGISTERS *******************************************//* There are sixteen registers, numbered 0 through 15. Each register * is a 32-bit word. Functions check the register address although an * error would indicate a fault in the loader rather than the simulator. * Register 0 is always 0. */long regs [MAXREG];/* Fetch the value of a register. */long fetchreg (unsigned short regnum) { if (regnum > 15) { runtimeerror("simulator error (illegal register code)"); return 0; } return regs[regnum]; }/* Store a value in a register. */void storereg (unsigned short regnum, long data) { if (regnum > 15) runtimeerror("simulator error (illegal register code)"); if (regnum > 0) regs[regnum] = data; }/******************** INSTRUCTION CODES *************************************//* Instruction codes and the corresponding strings; obviously, these two * declarations should correspond. The directives have codes although * they are not stored in the memory. Note that 0 is an illegal * instruction. */enum optype { bad, lw, lb, sw, sb, add, sub, mul, divr, mod, and, or, not, ceq, cne, clt, cle, cgt, cge, addi, subi, muli, divi, modi, andi, ori, ceqi, cnei, clti, clei, cgti, cgei, sl, sr, gtc, ptc, bz, bnz, j, jr, jl, jlr, nop, hlt, entry, align, org, dw, db, res, last };char opnames [last] [6] = { "", "lw", "lb", "sw", "sb", "add", "sub", "mul", "div", "mod", "and", "or", "not", "ceq", "cne", "clt", "cle", "cgt", "cge", "addi", "subi", "muli", "divi", "modi", "andi", "ori", "ceqi", "cnei", "clti", "clei", "cgti", "cgei", "sl", "sr", "getc", "putc", "bz", "bnz", "j", "jr", "jl", "jlr", "nop", "hlt", "entry", "align", "org", "dw", "db", "res" };void showfmta (long addr, wordtype word) { char *opcode = opnames[word.fmta.op]; switch (word.fmta.op) { /* Operands Ri, Rj, Rk */ case add: case sub: case mul: case divr: case mod: case and: case or: case ceq: case cne: case clt: case cle: case cgt: case cge: printf("%5ld %-6s r%d, r%d, r%d", addr, opcode, word.fmta.ri, word.fmta.rj, word.fmta.rk); break; /* Operands Ri, Rj */ case not: case jlr: printf("%5ld %-6s r%d, r%d", addr, opcode, word.fmta.ri, word.fmta.rj); break; /* No operands */ case nop: case hlt: printf("%5ld %-6s", addr, opcode); break; } }void showfmtb (long addr, wordtype word) { char *opcode = opnames[word.fmtb.op]; switch (word.fmtb.op) { /* Operands Ri, K(Rj) */ case lw: case lb: printf("%5ld %-6s r%d, %d(r%d)", addr, opcode, word.fmtb.ri, word.fmtb.k, word.fmtb.rj); break; /* Operands K(Rj), Ri */ case sw: case sb: printf("%5ld %-6s %d(r%d), r%d", addr, opcode, word.fmtb.k, word.fmtb.rj, word.fmtb.ri); break; /* Operands Ri, Rj, K */ case addi: case subi: case muli: case divi: case modi: case andi: case ori: case ceqi: case cnei: case clti: case clei: case cgti: case cgei: printf("%5ld %-6s r%d, r%d, %d", addr, opcode, word.fmtb.ri, word.fmtb.rj, word.fmtb.k); break; /* Operands Ri, K */ case sl: case sr: case bz: case bnz: case jl: printf("%5ld %-6s r%d, %d", addr, opcode, word.fmtb.ri, word.fmtb.k); break; /* Operands Ri */ case gtc: case ptc: case jr: printf("%5ld %-6s r%d", addr, opcode, word.fmtb.ri); break; /* Operands K */ case j: printf("%5ld %-6s %d", addr, opcode, word.fmtb.k); break; } }/* Convert a word to a string of 4 characters. Non-graphics to ".". * Exact output depends on whether the host is big-endian or * little-endian. */char *wordtochars (char *buf, wordtype word) { int i; for (i = 0; i < 4; i++) { char c = word.byts[i]; if (32 <= c && c <= 126) buf[i] = c; else buf[i] = '.'; } buf[4] = '\0'; return buf; }/* Display one word of memory. */void showword (long addr) { char charbuf [5]; long wordaddr = addr >> 2; wordtype word = mem[wordaddr].word; if (addr & 3) { printf("Internal error: bad address!\n"); exit(1); } switch (mem[wordaddr].cont) { case 'a': showfmta(addr, word); break; case 'b': showfmtb(addr, word); break; case 'd': printf("%5ld %08lX %s %4ld", addr, word.data, wordtochars(charbuf, word), word.data); break; case 'u': printf("%5ld ??", addr); break; } }/****************************** SYMBOLS *************************************//* There is one <symnode> for each symbol. It records the name and value * of the symbol and how often it has been defined (once is correct). * The <symnode> also contains a pointer to a list of <usenodes>'s, each * of which contains an address where the value of the symbol is used. */struct symnode { char *name; long val; short defs; struct usenode *uses; struct symnode *next; };struct usenode { long addr; struct usenode *next; };/* The base of the symbol table. */struct symnode *symbols = NULL;/* Return a pointer to a symbol entry. This always succeeds, because * it creates a new entry if it can't find a matching entry. */struct symnode *findsymbol (char *name) { struct symnode *p = symbols; while (p) { if (!strcmp(name, p->name)) return p; p = p->next; } /* No entry exists, so make one. */ p = (struct symnode *) malloc (sizeof(struct symnode)); if (p == NULL) { printf("No more memory!\n"); exit(1); } p->name = (char *) malloc(strlen(name) + 1); strcpy(p->name, name); p->val = 0; p->defs = 0; p->uses = NULL; p->next = symbols; symbols = p; return p; }/* Define a symbol. That is, associate the value <val> with * the symbol <name>. */void defsymbol (char *name, long val) { struct symnode *p = findsymbol(name); p->val = val; p->defs++; }/* Use a symbol. That is, record the fact that the symbol <name> * must be stored at <addr>. */void usesymbol (char *name, long addr) { struct symnode *p = findsymbol(name); struct usenode *u = (struct usenode *) malloc (sizeof (struct usenode)); if (u == NULL) { printf("No more memory!\n"); exit(1); } u->addr = addr; u->next = p->uses; p->uses = u; }/* Return the value of a symbol, or -1 if it doesn't exist. */long getsymbolval (char *name) { struct symnode *p = symbols; while (p) { if (!strcmp(name, p->name)) return (p->val); p = p->next; } return -1; }/* Display all symbols and their uses. */void showsymbols () { short count = 0; struct symnode *p = symbols; while (p) { struct usenode *u = p->uses; printf("%-8s = %4ld Used at: ", p->name, p->val); while (u) { printf("%ld ", u->addr); u = u->next; } printf("\n"); p = p->next; if (++count > 20) { printf("Press enter to continue"); getchar(); count = 0; } } }/* Check symbol list for errors and return error count. */int checksymbols () { int errors = 0; struct symnode *p = symbols; while (p) { if (p->defs == 0) { printf("Undefined symbol: %s.\n", p->name); errors++; } else if (p->defs > 1) { printf("Redefined symbol: %s.\n", p->name); errors++; } p = p->next; } return errors; }/* Store symbols at their respective locations. */void storesymbols () { struct symnode *p = symbols; while (p) { struct usenode *u = p->uses; while (u) { long wordaddr = (u -> addr) >> 2; switch (mem[wordaddr].cont) { case 'b': mem[wordaddr].word.fmtb.k = (int) p->val; break; case 'd': mem[wordaddr].word.data = p->val; break; default: printf("Symbol storage error!\n"); break; } u = u->next; } p = p->next; } }/***************************** EXECUTION ************************************/short newreg; /* Address of a register that has changed */long newmem; /* Address of a memory location that has changed */short running; /* True if the processor is running, false after errors */long numsteps; /* Number of instructions executed in trace mode. *//* Report a run-time error and stop the program. */void runtimeerror (char *message) { printf("\n%5ld Run-time error: %s.\n", ic, message); running = FALSE; }/* Execute the instruction at address <ic>. */void execinstr (short tracing) { long w1, w2, k, rk; short cont = fetch(); /* Move next instruction to `ir'. */ int ch; if (!running) return; newreg = -1; newmem = -1; switch (cont) { /* Format A instructions with register operands. */ case 'a': switch (ir.fmta.op) { /* add Ri, Rj, Rk */ case add: storereg(ir.fmta.ri, fetchreg(ir.fmta.rj) + fetchreg(ir.fmta.rk)); newreg = ir.fmta.ri; break; /* sub Ri, Rj, Rk */ case sub: storereg(ir.fmta.ri, fetchreg(ir.fmta.rj) - fetchreg(ir.fmta.rk)); newreg = ir.fmta.ri; break; /* mul Ri, Rj, Rk */ case mul: storereg(ir.fmta.ri, fetchreg(ir.fmta.rj) * fetchreg(ir.fmta.rk)); newreg = ir.fmta.ri; break; /* divr Ri, Rj, Rk */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -