📄 myvm.c
字号:
/** Snixos Project version 1.0, 2003.6* (C) Copyright 2003,2004,2005 Jockeyson,KeqiangGao <Snallie@tom.com>* All Rights Reserved.* Distributed under the terms of the GNU General Public License.** This program is a free and open source software and you can redistribute * it and/or modify it under the terms of the GNU General Public License as* published by the Free Software Foundation. As no any liability is assumed * for any incidental or consequential damages in connection with the * information or program fragments contained herein,so any exception arised* is at your own risk. It is ABSOLUTELY WITHOUT ANY WARRANTY.* Bug report please send to Snallie@tom.com .*//* myvm.c : utility in Snixos served as a virtual machine for running myvm assembly language, ported from MYVM Version 0.11a written in C++ in 2003, for more about MYVM mail the author. Author : Snallie@tom.com Time : 2004.6*//* to make in Linux individually: gcc -D_NATIVE myvm.c -o myvm */#ifndef _NATIVE# include "fatfs.h"# include "mem.h"#endif#include "stdio.h"#if __MSDOS__ || MSDOS || WIN32 || __WIN32__# define pathsep '\\'#else# define pathsep '/'#endif#define false 0#define true 1#define boolean int#define bool int#define maxint 2147483647 /* INT_MAX defined in limit.h */#define MAXINSTUCTION 67 /* how many instructions MYVM understands */#define MEMSIZE 256 /* the size of memory for MYVM to store assembled machine code */#define SYMTABLEN 50 /* capacity of symbol table */#define MAXSYMLEN 32 /* the maximum characters a symbol comprised */typedef unsigned char MC_bytes;typedef struct refnodes { MC_bytes refsymaddr; /* the address a address label referenced */ struct refnodes *nextref; /* the next referenced node for the same address */} refnode;typedef struct symtab { char symname[MAXSYMLEN]; /* an address represented in string format */ MC_bytes symaddr; /* the memory address referenced by symname */ struct refnodes *firstref; /* the first reference to symname */} symboltab;/* token type return by lex() *//* ASMCODE:assembly instruction; LABEL:a address defined; *//* REFLABEL:a reference to LABEL; NUM:a numeric string; ID:identifier; *//* CMNT: commentation in source; UNRECOGNIZED: unknown token */typedef enum tktype { ASMCODE, LABEL, REFLABEL, NUMBER, ID, NUM, CMNT, UNRECOGNIZED} tokentype;/* MYVM machine instruction, the order here may not be modified ! */typedef enum MC_opcode { /* 0-7 */ MC_nop, MC_clra, MC_clrc, MC_clrx, MC_cmc, MC_inc, MC_dec, MC_incx, /* 8-f */ MC_decx, MC_tax, MC_ini, MC_inh, MC_inb, MC_ina, MC_oti, MC_otc, /* 10-17 */ MC_oth, MC_otb, MC_ota, MC_push, MC_pop, MC_shl, MC_shr, MC_ret, /* 18-1f */ MC_halt, MC_lda, MC_ldx, MC_ldi, MC_lsp, MC_lspi, MC_sta, MC_stx, /* 20-27 */ MC_add, MC_adx, MC_adi, MC_adc, MC_acx, MC_aci, MC_sub, MC_sbx, /* 28-2f */ MC_sbi, MC_sbc, MC_scx, MC_sci, MC_cmp, MC_cpx, MC_cpi, MC_ana, /* 30-37 */ MC_anx, MC_ani, MC_ora, MC_orx, MC_ori, MC_jmp, MC_bze, MC_bnz, /* 38-3f */ MC_bpz, MC_bng, MC_bcc, MC_bcs, MC_tsp, MC_jsr, MC_lbpi, MC_fbpi, /* 40~ */ MC_tbp, MC_tsb, MC_tabp, MC_bad = 255} MC_opcodes;/* the running state definition for MYVM */typedef enum { running, finished, nodata, baddata, badop } status;FILE *src; /* asm source file FILE * pointer */char srcfile[20]; /* to save source file name ,file name may be less than 20 */symboltab symtabhdr[SYMTABLEN]; /* symbol array */MC_bytes mem[256]; /* memory space for MYVM */char *mnemonics[256]; /* machine code vs mnemonics */int mnxlen[256]; /* table to save each machine code's length */int binlen; /* binary file length */void mksymtab(int *err);MC_bytes lookUpCmds(char *cmd);tokentype ASlex(char *words, MC_opcodes * opcode);int seeklabel(char *lbl, int purpose);int symtablen();void AS(char *sourcename);char *getmns(int i);void MC();MC_bytes MCopcode(char *str);void newsuffix(char *oldstr, char *ext, char *newstr);void ASassemble(bool * errors);int seeklabel(char *lbl, int purpose);int symtablen();void initMC();void releaseSymtab();void runvm();static void logo();/* abs(number), abs(0)=0,abs(-2)=2, abs(2)=2 */int abs(int i){ return i >= 0 ? i : -i;}/* atoi() *//* convert ascii number string to digit value *//* e.g "-983"->983, "983"->983, "+983"->983 ,any string not leading with number returned 0 */int atoi(char *nbrStr){ int i = 0; int tp = 0; if (*(nbrStr + i) && (isdigit(*(nbrStr + i)) || *(nbrStr + i) == '+' || *(nbrStr + i) == '-')) { switch (*(nbrStr + i)) { case '+': tp = atoi(nbrStr + 1); break; case '-': tp = -(atoi(nbrStr + 1)); break; default: while (*(nbrStr + i) && isdigit(*(nbrStr + i))) { tp = tp * 10 + *(nbrStr + i) - 0x30; i++; } } } return tp;}/* ########################################## *//* MYVM Version 0.11a *//* snallie@tom.com 2003.2 *//* 2 pass assembler *//* ########################################## */void AS(char *sourcename){ int i; strcpy(srcfile, sourcename); src = fopen(sourcename, "r"); if (src == NULL) { printf("Could not open input file\n"); return; } /* each element in symbol table initialized as '????????' */ for (i = 0; i < SYMTABLEN; i++) strcpy(symtabhdr[i].symname, "???????");}/* return instruction i's mnemonics */char *getmns(int i){ return mnemonics[i];}/* MYVM initialization: clear memory , instruction table fill up,etc. */void MC(){ int i; /* memory of MYVM totally fill with MC_bad(0xff) */ for (i = 0; i <= 255; i++) mem[i] = MC_bad; /* instrction table filling up */ for (i = 0; i <= 255; i++) mnemonics[i] = "???"; /* opcode string fill in mnemonics[] ,the index implies opcode 0xxx */ mnemonics[MC_nop] = "NOP"; /* 0x0 */ mnemonics[MC_clra] = "CLRA"; /* 0x1 */ mnemonics[MC_clrc] = "CLRC"; /* 0x2 */ mnemonics[MC_clrx] = "CLRX"; /* 0x3 */ mnemonics[MC_cmc] = "CMC"; /* 0x4 */ mnemonics[MC_inc] = "INC"; /* 0x5 */ mnemonics[MC_dec] = "DEC"; /* 0x6 */ mnemonics[MC_incx] = "INCX"; /* 0x7 */ mnemonics[MC_decx] = "DECX"; /* 0x8 */ mnemonics[MC_tax] = "TAX"; /* 0x9 */ mnemonics[MC_ini] = "INI"; /* 0xa */ mnemonics[MC_inh] = "INH"; /* 0xb */ mnemonics[MC_inb] = "INB"; /* 0xc */ mnemonics[MC_ina] = "INA"; /* 0xd */ mnemonics[MC_oti] = "OTI"; /* 0xe */ mnemonics[MC_otc] = "OTC"; /* 0xf */ mnemonics[MC_oth] = "OTH"; /* 0x10 */ mnemonics[MC_otb] = "OTB"; /* 0x11 */ mnemonics[MC_ota] = "OTA"; /* 0x12 */ mnemonics[MC_push] = "PUSH"; /* 0x13 */ mnemonics[MC_pop] = "POP"; /* 0x14 */ mnemonics[MC_shl] = "SHL"; /* 0x15 */ mnemonics[MC_shr] = "SHR"; /* 0x16 */ mnemonics[MC_ret] = "RET"; /* 0x17 */ mnemonics[MC_halt] = "HALT"; /* 0x18 */ mnemonics[MC_lda] = "LDA"; /* 0x19 */ mnemonics[MC_ldx] = "LDX"; /* 0x1a */ mnemonics[MC_ldi] = "LDI"; /* 0x1b */ mnemonics[MC_lsp] = "LSP"; /* 0x1c */ mnemonics[MC_lspi] = "LSPI"; /* 0x1d */ mnemonics[MC_sta] = "STA"; /* 0x1e */ mnemonics[MC_stx] = "STX"; /* 0x1f */ mnemonics[MC_add] = "ADD"; /* 0x20 */ mnemonics[MC_adx] = "ADX"; /* 0x21 */ mnemonics[MC_adi] = "ADI"; /* 0x22 */ mnemonics[MC_adc] = "ADC"; /* 0x23 */ mnemonics[MC_acx] = "ACX"; /* 0x24 */ mnemonics[MC_aci] = "ACI"; /* 0x25 */ mnemonics[MC_sub] = "SUB"; /* 0x26 */ mnemonics[MC_sbx] = "SBX"; /* 0x27 */ mnemonics[MC_sbi] = "SBI"; /* 0x28 */ mnemonics[MC_sbc] = "SBC"; /* 0x29 */ mnemonics[MC_scx] = "SCX"; /* 0x2a */ mnemonics[MC_sci] = "SCI"; /* 0x2b */ mnemonics[MC_cmp] = "CMP"; /* 0x2c */ mnemonics[MC_cpx] = "CPX"; /* 0x2d */ mnemonics[MC_cpi] = "CPI"; /* 0x2e */ mnemonics[MC_ana] = "ANA"; /* 0x2f */ mnemonics[MC_anx] = "ANX"; /* 0x30 */ mnemonics[MC_ani] = "ANI"; /* 0x31 */ mnemonics[MC_ora] = "ORA"; /* 0x32 */ mnemonics[MC_orx] = "ORX"; /* 0x33 */ mnemonics[MC_ori] = "ORI"; /* 0x34 */ mnemonics[MC_jmp] = "JMP"; /* 0x35 */ mnemonics[MC_bze] = "BZE"; /* 0x36 */ mnemonics[MC_bnz] = "BNZ"; /* 0x37 */ mnemonics[MC_bpz] = "BPZ"; /* 0x38 */ mnemonics[MC_bng] = "BNG"; /* 0x39 */ mnemonics[MC_bcc] = "BCC"; /* 0x3a */ mnemonics[MC_bcs] = "BCS"; /* 0x3b */ mnemonics[MC_tsp] = "TSP"; /* 0x3c */ mnemonics[MC_jsr] = "JSR"; /* 0x3d */ mnemonics[MC_lbpi] = "LBPI"; /* 0x3e */ mnemonics[MC_fbpi] = "FBPI"; /* 0x3f */ mnemonics[MC_tbp] = "TBP"; /* 0x40 */ mnemonics[MC_tsb] = "TSB"; /* 0x41 */ mnemonics[MC_tabp] = "TABP"; /* 0x42 */ /* intruction length table initialization */ for (i = 0; i <= 255; i++) mnxlen[i] = 1; mnxlen[MC_lda] = 2; mnxlen[MC_ldx] = 2; mnxlen[MC_ldi] = 2; mnxlen[MC_lsp] = 2; mnxlen[MC_lspi] = 2; mnxlen[MC_sta] = 2; mnxlen[MC_stx] = 2; mnxlen[MC_lbpi] = 2; mnxlen[MC_fbpi] = 2; mnxlen[MC_add] = 2; mnxlen[MC_adi] = 2; mnxlen[MC_adc] = 2; mnxlen[MC_adx] = 2; mnxlen[MC_acx] = 2; mnxlen[MC_aci] = 2; mnxlen[MC_sub] = 2; mnxlen[MC_sbx] = 2; mnxlen[MC_sbi] = 2; mnxlen[MC_sbc] = 2; mnxlen[MC_scx] = 2; mnxlen[MC_sci] = 2; mnxlen[MC_cmp] = 2; mnxlen[MC_cpx] = 2; mnxlen[MC_cpi] = 2; mnxlen[MC_ana] = 2; mnxlen[MC_anx] = 2; mnxlen[MC_ani] = 2; mnxlen[MC_ora] = 2; mnxlen[MC_orx] = 2; mnxlen[MC_ori] = 2; mnxlen[MC_jmp] = 2; mnxlen[MC_bze] = 2; mnxlen[MC_bnz] = 2; mnxlen[MC_bpz] = 2; mnxlen[MC_bng] = 2; mnxlen[MC_bcc] = 2; mnxlen[MC_bcs] = 2; mnxlen[MC_jsr] = 2;}MC_bytes MCopcode(char *str)/* query the opcode for string str *//* return the appopriated opcode if opcode exists, else return MC_bad */{ int i; MC_bytes l; for (i = 0; str[i]; i++) str[i] = toupper(str[i]); l = MC_nop; while (l <= MAXINSTUCTION && strcmp(str, mnemonics[l])) l++; if (l <= MAXINSTUCTION) return l; else return MC_bad;}void newsuffix(char *oldstr, char *ext, char *newstr)/* convert the string oldstr which resemble PRIMARY.xxx to PRIMARY.ext, and save to newstr */{ int i; char old[256]; strcpy(old, oldstr); i = strlen(old); while ((i > 0) && (old[i - 1] != '.') && (old[i - 1] != pathsep)) i--; if ((i > 0) && (old[i - 1] == '.')) old[i - 1] = 0; if (ext[0] != '.') { strcat(old, "."); } strcat(old, ext); strcpy(newstr, old);}/* #define DEBUG *//* assemble 2 pass scan for source file , convert the source to machine code*/void ASassemble(bool * errors){ MC_bytes op; MC_bytes lc = 0; /* address counter for assembling */ int number; char ch; bool okay; tokentype tokencat; /* token's category */ int labelidx; /* indicate the order in symbol table */ char words[10]; char tpwords[15]; MC_opcodes opcode; int i; int errpass1 = 0; FILE *bin; char binfile[256]; logo(); printf("Assembling code ... \n"); mksymtab(&errpass1); /* for the 1st pass scan to make symbol table */ fclose(src); src = NULL; /* close source file ,prepare for the 2nd pass scan */ if (errpass1 > 0) { printf("Pass1: totally %d errors found.\n", errpass1); *errors = errpass1; return; } src = fopen(srcfile, "r"); /* reopen the source file to scan again */ if (src == NULL) { printf("Could not open input file\n"); return; } for (i = 0; i <= MEMSIZE - 1; i++) /* fill memory with MC_bad */ mem[i] = MC_bad; lc = 0; /* clear address counter */ errors = false; /* errors is for save the state of 2nd pass scan */ /* source file scan again , by referencing the symbol table which constructed in the 1st pass scan, it converts the source .asm to machine code and save to mem */ while (!feof(src)) { tokencat = ASlex(words, &opcode); /* read a word, and then identify its cat */ switch (tokencat) { case ASMCODE: /* the word read is an assembly instruction */ op = MCopcode(words); /* to get its opcode */ if (op == MC_bad) { /* no such assembly instruction defined ,raise alarm */ printf("Pass2: %s - Bad mnemonic at %d\n", words, lc); *errors = true; } mem[lc] = op; /* save the legal opcode to memory */ lc = (lc + 1) % MEMSIZE; /* address counter indicates the next position */ break; case REFLABEL: /* the word just read is an reference to a label */ strcpy(tpwords, words); strcat(tpwords, ":"); /* make its tail following a ":" for querying symbol table */ /* seek the label in symbol table to determine its index in symbol table */ labelidx = seeklabel(tpwords, 1); if (labelidx == -1) { printf ("Pass2: ERROR! No such label to be referenced :%s at %d\n", words, lc); *errors = true; return; /* no such label defined , invalid reference */ } else { mem[lc] = symtabhdr[labelidx].symaddr;/* get the label's address and save it to mem */ lc = (lc + 1) % MEMSIZE; /* address counter indicates the next mem */ } break; case NUM: /* a numeric string got, attention: only 1 byte's width of integer */ number = atoi(words); if (number >= 0) /* convert to proper byte value */ mem[lc] = number % 256; else mem[lc] = (256 - abs(number) % 256) % 256; lc = (lc + 1) % 256; /* address counter indicates the next mem */ break; } } binlen = lc; /* how many bytes we've assembled */ printf("Binary assembled: %d bytes.\n", lc); fclose(src); /* dump binary file for reference */ newsuffix(srcfile, "lst", binfile); bin = fopen(binfile, "a"); /* create a new file named binfile */ if (bin == NULL) { printf("Binary file ignored.\n"); } else { char tp[50]; int j = 0; for (i = 0; i < binlen; i++) if (strcmp(getmns(mem[i]), "???") && getmnxlen(mem[i]) == 2) { /* for dealing with 2 bytes instruction */ sprintf(tp, " %02X %02X%02X %-4s %02X\n", i, mem[i], mem[i + 1], getmns(mem[i]), mem[i + 1]); while (*(tp + j)) { fputc(*(tp + j), bin); /* write to disk file */ printf("%c", *(tp + j)); /* put to screen */ j++; } j = 0; i++; } else { /* the instruction only has 1 byte */ sprintf(tp, " %02X %02X %-4s\n", i, mem[i], getmns(mem[i])); while (*(tp + j)) { fputc(*(tp + j), bin); /* write to disk file */ printf("%c", *(tp + j)); /* put to screen */ j++; } j = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -