免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: converse
打印 上一主题 下一主题

虚拟机源码分析 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2005-01-17 17:56 |只看该作者

虚拟机源码分析

主程序myvm.cpp


  1. //////////////////////////////////////
  2. // 汇编语言虚拟机  MYVM Version 0.11a
  3. // snallie@163.net  2003.2
  4. //
  5. // myvm.cpp
  6. // 虚拟机的总控程序
  7. //////////////////////////////////////
  8. #include "misc.h"
  9. #include "as.h"
  10. #include "mc.h"

  11. int main(int argc, char *argv[])
  12. {
  13.     bool errors;
  14.     int c;
  15.     int i = 1;
  16.     int trace = 0;                // 跟踪标志
  17.     char datafile[20] = { 0 };        // 输入数据文件名
  18.     char outfile[20] = { 0 };        // 输出结果文件名
  19.     int entry = 0;                // 程序执行入口点
  20.     logo();
  21.     if (argc == 1) {
  22.                 printf
  23.                         ("Usage: %s [-Trace] [-datafile] [-Outputfile] [-exx] sourcefile\n",
  24.                          *argv);
  25.                 exit(1);
  26.     }
  27.     // 分析命令行参数
  28.     while (*(argv + i) && strlen(*(argv + i)) >; 1) {
  29.                 c = (*(argv[i] + 1)) | 0x20;
  30.                 switch (c) {
  31.                 case 't':                //处理跟踪标志
  32.                         trace = 1;
  33.                         break;
  34.                 case 'd':                //处理输入数据文件名
  35.                         strcpy(datafile, (argv[i] + 2));
  36.                         break;
  37.                 case 'o':                //处理输出结果文件名
  38.                         strcpy(outfile, (argv[i] + 2));
  39.                         break;
  40.                 case 'e':                //处理程序执行入口点
  41.                         entry = atoi(argv[i] + 2);
  42.                         break;
  43.                 }
  44.                 i++;
  45.     }

  46.     if (i < argc) {
  47.                 printf("Illegal argument: %s\n", *(argv + i));
  48.                 printf
  49.                         ("Usage: %s [-Trace] [-datafile] [-Outputfile] [-e23] sourcefile\n",
  50.                          *argv);
  51.                 exit(1);
  52.     }

  53.     MC *Machine = new MC();        //产生一个虚拟机对象实例,Machine指向该实例
  54.     //生成一个汇编器对象实例
  55.     AS *Assembler = new AS(argv[argc - 1], Machine);

  56.     //汇编器对源程序代码进行汇编处理,结果存入Machine的内存mem中,
  57.     //将汇编过程所出现的错误状态返回给主调函数
  58.     Assembler->;assemble(errors);
  59.     delete Assembler;
  60.     if (errors) {                //汇编过程有错误则输出提示信息,退出。
  61.                 printf("Unable to execute binary\n");
  62.     } else {                        //汇编过程没有错误则执行Machine的内存mem中机器指令。
  63.                 printf("About to execute binary...\n");
  64.                 Machine->;interpret(argc, trace, datafile, outfile, entry);
  65.                 //dump memory to src.map
  66.                 Machine->;listcode(argv[argc - 1]);

  67.     }
  68.     delete Machine;

  69.         return 0;
  70. }

复制代码

论坛徽章:
0
22 [报告]
发表于 2005-01-17 17:57 |只看该作者

虚拟机源码分析

mc虚拟机类的头文件:mc.h


  1. //////////////////////////////////////
  2. // 汇编语言虚拟机  MYVM Version 0.11a
  3. // snallie@163.net  2003.2
  4. //
  5. // mc.h
  6. // 虚拟机定义的头文件
  7. //////////////////////////////////////
  8. #ifndef MC_H
  9. #define MC_H

  10. #include "misc.h"

  11. // 虚拟机机器指令表
  12. enum MC_opcodes {
  13.          MC_nop, MC_clra, MC_clrc, MC_clrx, MC_cmc, MC_inc, MC_dec, MC_incx, MC_decx,
  14.          MC_tax, MC_ini, MC_inh, MC_inb, MC_ina, MC_oti, MC_otc, MC_oth, MC_otb,
  15.          MC_ota, MC_push, MC_pop, MC_shl, MC_shr, MC_ret, MC_halt, MC_lda, MC_ldx,
  16.          MC_ldi, MC_lsp, MC_lspi, MC_sta, MC_stx, MC_add, MC_adx, MC_adi, MC_adc,
  17.          MC_acx, MC_aci, MC_sub, MC_sbx, MC_sbi, MC_sbc, MC_scx, MC_sci, MC_cmp,
  18.          MC_cpx, MC_cpi, MC_ana, MC_anx, MC_ani, MC_ora, MC_orx, MC_ori, MC_jmp,
  19.          MC_bze, MC_bnz, MC_bpz, MC_bng, MC_bcc, MC_bcs, MC_tsp, MC_jsr, MC_lbpi,
  20.          MC_fbpi, MC_tbp, MC_tsb, MC_tabp, MC_bad = 255
  21. };

  22. //虚拟机的运行状态枚举定义
  23. typedef enum { running, finished, nodata, baddata, badop } status;
  24. typedef unsigned char MC_bytes;

  25. class MC {
  26. public:
  27.          MC_bytes mem[256];                // 虚拟机的内存空间

  28.          //将mem中的数据据输出到srcname所指的文件中
  29.          void listcode(char *srcname = "");
  30.    
  31.          //对虚拟机执行汇编后的机器指令程序的主体函数
  32.          //各参数取自interpret()传递过来的值,意义与interpret()相同。
  33.          void execute(MC_bytes initpc, FILE * data, FILE * results,
  34.                                   bool tracing);
  35.    
  36.          //对虚拟机执行汇编后的机器指令程序进行执行执行前的准备工作:
  37.          //argc:用户在命令行上提供的参数个数,据此判断是否以交互方式提示用户输入如下的参数:
  38.          //trace:设定跟踪标志;datafile:程序的输入数据文件, outfile:程序的输出文件
  39.          //entrance:机器指令程序的入口点
  40.          void interpret(int argc, int trace, char *datafile, char *outfile,
  41.                                         int entrance);

  42.          // 取得str所对应的机器指令
  43.          MC_bytes opcode(char *str);
  44.    

  45.          // 构造函数对机器进行初始化
  46.      MC();
  47.    
  48.          //取得机器指令i的助记符
  49.          inline char *getmns(int i) {
  50.                   return mnemonics[i];
  51.          }

  52.          //取得机器指令i长度?
  53.          inline int getmnxlen(int i) {
  54.                   return mnxlen[i];
  55.          }

  56. private:
  57.          //虚拟机的处理器的内部结构定义
  58.          struct processor {
  59.                   MC_bytes a;                // 累加器A
  60.                   MC_bytes sp;                // 堆栈指针sp
  61.                   MC_bytes x;                // 变址寄存器 x
  62.                   MC_bytes ir;                // 指令寄存器 ir
  63.                   MC_bytes pc;                // 程序计数器
  64.                   MC_bytes bp;                // 基址指针bp
  65.                   bool z, p, c;                // 标志寄存器
  66.          };
  67.          processor cpu;  //虚拟机的cpu
  68.          status ps;      //保存cpu的运行状态

  69.          char *mnemonics[256];  //机器指令/助记符对照表
  70.          int   mnxlen[256];  //机器指令长度表
  71.          void trace(FILE * results, MC_bytes pcnow);  //程序运行实时跟踪函数
  72.          void runtime_error(FILE * results, MC_bytes pcnow); //输出运行时错误至results文件
  73.          void setflags(MC_bytes MC_register); //设定MC_register的状态
  74.          MC_bytes index(void); //计算变址地址
  75. };

  76. #endif                                /*MC_H */

复制代码

论坛徽章:
0
23 [报告]
发表于 2005-01-17 17:58 |只看该作者

虚拟机源码分析

虚拟机类的实现文件:mc.cpp


  1. //////////////////////////////////////
  2. // 汇编语言虚拟机  MYVM Version 0.11a
  3. // snallie@163.net  2003.2
  4. //
  5. // mc.cpp
  6. // 虚拟机的内部操作的实现
  7. //////////////////////////////////////
  8. #include "misc.h"
  9. #include "mc.h"

  10. const int ESC = 1;

  11. // 将X执行加1操作,并保持其值在0~255范围内,因为CPU字长为8位
  12. inline void increment(MC_bytes & x)
  13. {
  14.     x = (x + 257) % 256;
  15. }

  16. // 将X执行减1操作,并保持其值在0~255范围内,因为CPU字长为8位
  17. inline void decrement(MC_bytes & x)
  18. {
  19.     x = (x + 255) % 256;
  20. }

  21. // 对str所指向的汇编助记符查指令表,
  22. // 对正确的指令形式返回其所对应的机器码,对于错误的指令返回MC_bad(255)
  23. MC_bytes MC::opcode(char *str)
  24. {
  25.     for (int i = 0; str[i]; i++)
  26.                 str[i] = toupper(str[i]);
  27.     MC_bytes l = MC_nop;
  28.     while (l <= MAXINSTUCTION && strcmp(str, mnemonics[l]))
  29.                 l++;
  30.     if (l <= MAXINSTUCTION)
  31.                 return l;
  32.     else
  33.                 return MC_bad;
  34. }

  35. // 以16进制形式输出CPU的256字节内存单元的内容
  36. void MC::listcode(char *srcname)
  37. {
  38.     MC_bytes nextbyte = 0, tnb;
  39.     char filename[256];

  40.     newsuffix(srcname, "map", filename);
  41.     if (*filename == '\0')
  42.                 return;

  43.     FILE *listfile = fopen(filename, "w");
  44.     if (listfile == NULL)
  45.                 listfile = stdout;
  46.     for (int i = 1; i <= 16; i++) {
  47.                 fprintf(listfile, "%02X(%03d)  ", (i - 1) * 16, (i - 1) * 16);
  48.                 tnb = nextbyte;
  49.                 int j;
  50.                 for (j = 1; j <= 16; j++) {
  51.                         fprintf(listfile, "%02X %s", mem[nextbyte],
  52.                                         (j == 8) ? " " : "");
  53.                         increment(nextbyte);
  54.                 }
  55.                 fprintf(listfile, "  ");
  56.                 nextbyte = tnb;
  57.                 for (j = 1; j <= 16; j++) {
  58.                         fprintf(listfile, "%c",
  59.                                         (mem[nextbyte] < 0x20) ? '.' : mem[nextbyte]);
  60.                         increment(nextbyte);
  61.                 }
  62.                 putc('\n', listfile);
  63.     }
  64.     if (listfile != stdout)
  65.                 fclose(listfile);
  66. }

  67. // 运行时CPU内部主要寄存器的状态输出(设定了跟踪参数)
  68. void MC::trace(FILE * results, MC_bytes pcnow)
  69. {
  70.     fprintf(results, "PC=%02X A=%02X ", pcnow, cpu.a);
  71.     fprintf(results, "X=%02X SP=%02X [SP]=%02X BP=%02X ", cpu.x, cpu.sp,
  72.                         mem[cpu.sp], cpu.bp);
  73.     fprintf(results, "Z=%d P=%d C=%d ", cpu.z, cpu.p, cpu.c);
  74.     fprintf(results, "OPCODE=%02X  (%s)\n", cpu.ir, mnemonics[cpu.ir]);
  75. }

  76. // 输出程序运行时错误
  77. void MC::runtime_error(FILE * results, MC_bytes pcnow)
  78. {
  79.     switch (ps) {
  80.     case badop:
  81.                 fprintf(results, "Illegal opcode");
  82.                 break;
  83.     case nodata:
  84.                 fprintf(results, "No more data");
  85.                 break;
  86.     case baddata:
  87.                 fprintf(results, "Invalid data");
  88.                 break;
  89.     }
  90.     fprintf(results, " at %d\n", pcnow);
  91.     trace(results, pcnow);
  92.     printf
  93.                 ("\nRuntime error happend, dumping memory to runtime.err.map ...\n");
  94.     listcode("runtime.err.dump");        //dump runtime error to runtime.err.map file
  95. }

  96. // 根据寄存器的值设定标志器P和Z的状态
  97. inline void MC::setflags(MC_bytes MC_register)
  98. {
  99.     cpu.z = (MC_register == 0);
  100.     cpu.p = (MC_register <= 127);
  101. }

  102. //计算变址地址 X+B
  103. inline MC_bytes MC::index(void)
  104. {
  105.     return ((mem[cpu.pc] + cpu.x) % 256);
  106. }

  107. //从data文件读入一字符,并检测是否为中断字符
  108. void readchar(FILE * data, char &ch, status & ps)
  109. {

  110.     if (feof(data)) {
  111.                 ps = nodata;
  112.                 ch = ' ';
  113.                 return;
  114.     }
  115.     ch = getc(data);
  116.     if (ch == ESC)
  117.                 ps = finished;
  118.     if (ch < ' ' || feof(data))
  119.                 ch = ' ';
  120. }

  121. // 将ch内的16进制数转换为数值
  122. int hexdigit(char ch)
  123. {
  124.     char tpch;
  125.     tpch = ch;

  126.         // 将大于10的字母转换为相应的数字
  127.     if (isalpha(ch) && (tpch | 0x20 >;= 'a' && tpch | 0x20 <= 'f'))
  128.         return (ch + 10 - 'a');
  129.     if (isdigit(ch))
  130.         return (ch - '0');
  131.     else
  132.         return (0);
  133. }

  134. // 以指定的进制从data文件读入一个数字 格式{+|-}?{digit}*
  135. int getnumber(FILE *data, int base, status &ps)
  136. {
  137.     bool negative = false;
  138.     char ch;
  139.     int num = 0;

  140.     do {
  141.                 readchar(data, ch, ps);
  142.     } while (!(ch >; ' ' || feof(data) || ps != running));

  143.     if (ps == running) {
  144.                 if (feof(data))
  145.                         ps = nodata;
  146.                 else {
  147.                         switch (ch) {
  148.                         case '-':
  149.                                 negative = true;
  150.                                 readchar(data, ch, ps);
  151.                                 break;
  152.                         case '+':
  153.                                 negative = false;
  154.                                 readchar(data, ch, ps);
  155.                                 break;
  156.                         }
  157.                         if (!isxdigit(ch))
  158.                                 ps = baddata;
  159.                         else {
  160.                                 while (isxdigit(ch) && ps == running) {
  161.                                         if (hexdigit(ch) < base
  162.                                                 && num <= (maxint - hexdigit(ch)) / base)
  163.                                                 num = base * num + hexdigit(ch);
  164.                                         else
  165.                                                 ps = baddata;
  166.                                         readchar(data, ch, ps);
  167.                                 }
  168.                         }
  169.                 }
  170.                 if (negative)
  171.                         num = -num;
  172.                 if (num >; 0)
  173.                         return num % 256;
  174.                 else
  175.                         return (256 - abs(num) % 256) % 256;        //负数以2的补码的形式表示返回
  176.     }

  177.     return 0;
  178. }

  179. //对虚拟机执行汇编后的机器指令程序的主体函数
  180. void MC::execute(MC_bytes initpc, FILE * data, FILE * results,
  181.                                  bool tracing)
  182. {
  183.     MC_bytes pcnow;                // 程序计数器的先前值
  184.     MC_bytes carry;                // 保存进位位的状态
  185.     MC_bytes number;
  186.     cpu.z = false;
  187.     cpu.p = false;
  188.     cpu.c = false;                // 初始化标志器的状态
  189.     cpu.a = 0;
  190.     cpu.x = 0;
  191.     cpu.sp = 0;                        // 初始化栈指针寄存器
  192.     cpu.bp = 0;                        // 初始化基址指针寄存器
  193.     cpu.pc = initpc;                // 初始化程序计数器
  194.     ps = running;                // 初始化cpu的运行状态

  195.     //如下循环进行实际的取指,分析解释,执行指令过程,直到停机halt或出现运行时错误
  196.     do {
  197.                 cpu.ir = mem[cpu.pc];        // 从内存中取指令送入指令寄存器
  198.                 pcnow = cpu.pc;                // 保存PC的先前值
  199.                 increment(cpu.pc);        // PC指向下一条将要执行的指令地址
  200.                 if (tracing)
  201.                         trace(results, pcnow);        //若调试,输出全部cpu内部寄存器值
  202.                 switch (cpu.ir) {        //根据指令值,转入相应的处理
  203.                 case MC_nop:
  204.                         break;                //空操作,直接返回
  205.                 case MC_clra:                //累加器A清0
  206.                         cpu.a = 0;
  207.                         break;
  208.                 case MC_clrc:                //进位标志器 C 清0
  209.                         cpu.c = false;
  210.                         break;
  211.                 case MC_clrx:                //变址寄存器 x 清0
  212.                         cpu.x = 0;
  213.                         break;
  214.                 case MC_cmc:                //进位标志器 C 取反
  215.                         cpu.c = !cpu.c;
  216.                         break;
  217.                 case MC_inc:                //累加器A自增1,影响标志器
  218.                         increment(cpu.a);
  219.                         setflags(cpu.a);
  220.                         break;
  221.                 case MC_dec:                //累加器A自减1,影响标志器
  222.                         decrement(cpu.a);
  223.                         setflags(cpu.a);
  224.                         break;
  225.                 case MC_incx:                //变址寄存器 x 自增1,影响标志器
  226.                         increment(cpu.x);
  227.                         setflags(cpu.x);
  228.                         break;
  229.                 case MC_decx:                //变址寄存器 x 自减1,影响标志器
  230.                         decrement(cpu.x);
  231.                         setflags(cpu.x);
  232.                         break;
  233.                 case MC_tax:                //累加器A内容送入变址寄存器 x
  234.                         cpu.x = cpu.a;
  235.                         break;
  236.                 case MC_ini:                //从输入读一10进制数送累加器A,影响标志器
  237.                         cpu.a = getnumber(data, 10, ps);
  238.                         setflags(cpu.a);
  239.                         break;
  240.                 case MC_inb:                //从输入读一2进制数送累加器A,影响标志器
  241.                         cpu.a = getnumber(data, 2, ps);
  242.                         setflags(cpu.a);
  243.                         break;
  244.                 case MC_inh:                //从输入读一16进制数送累加器A,影响标志器
  245.                         cpu.a = getnumber(data, 16, ps);
  246.                         setflags(cpu.a);
  247.                         break;
  248.                 case MC_ina:                //从输入读一ascii字符送累加器A,影响标志器
  249.                         char ascii;
  250.                         readchar(data, ascii, ps);
  251.                         if (feof(data))
  252.                                 ps = nodata;
  253.                         else {
  254.                                 cpu.a = ascii;
  255.                                 setflags(cpu.a);
  256.                         }
  257.                         break;
  258.                 case MC_oti:                //以10进形式输出累加器A的内容
  259.                         if (cpu.a < 128)
  260.                                 fprintf(results, "%d ", cpu.a);
  261.                         else
  262.                                 fprintf(results, "%d ", cpu.a - 256);
  263.                         if (tracing)
  264.                                 putc('\n', results);
  265.                         break;
  266.                 case MC_oth:                //以16进形式输出累加器A的内容
  267.                         fprintf(results, "%02X ", cpu.a);
  268.                         if (tracing)
  269.                                 putc('\n', results);
  270.                         break;
  271.                 case MC_otc:                //以无符号10进数形式输出累加器A的内容
  272.                         fprintf(results, "%d ", cpu.a);
  273.                         if (tracing)
  274.                                 putc('\n', results);
  275.                         break;
  276.                 case MC_otb:                //以无符号2进制形式输出累加器A的内容
  277.                         int bits[8];
  278.                         number = cpu.a;
  279.                         int loop;
  280.                         for (loop = 0; loop <= 7; loop++) {
  281.                                 bits[loop] = number % 2;
  282.                                 number /= 2;
  283.                         }
  284.                         for (loop = 7; loop >;= 0; loop--)
  285.                                 fprintf(results, "%d", bits[loop]);
  286.                         putc(' ', results);
  287.                         if (tracing)
  288.                                 putc('\n', results);
  289.                         break;
  290.                 case MC_ota:                //以ascii字符形式输出累加器A的内容
  291.                         putc(cpu.a, results);
  292.                         if (tracing)
  293.                                 putc('\n', results);
  294.                         break;
  295.                 case MC_push:                //压栈操作:堆栈指针SP减1,累加器A的内容压入栈顶。
  296.                         decrement(cpu.sp);
  297.                         mem[cpu.sp] = cpu.a;
  298.                         break;
  299.                 case MC_pop:                //出栈操作:栈顶的内容送入A,堆栈指针SP增1,影响标志器
  300.                         cpu.a = mem[cpu.sp];
  301.                         increment(cpu.sp);
  302.                         setflags(cpu.a);
  303.                         break;
  304.                 case MC_shl:                //累加器A的各位顺次左移1位,最高位移入进位标志C,影响标志器
  305.                         cpu.c = (cpu.a * 2 >; 255);
  306.                         cpu.a = cpu.a * 2 % 256;
  307.                         setflags(cpu.a);
  308.                         break;
  309.                 case MC_shr:                //累加器A的各位顺次右移1位,最低位移入进位标志C,影响标志器
  310.                         cpu.c = cpu.a & 1;
  311.                         cpu.a /= 2;
  312.                         setflags(cpu.a);
  313.                         break;
  314.                 case MC_ret:                //子程序调用返回,将栈顶保存的返回地址送PC,退栈
  315.                         cpu.pc = mem[cpu.sp];
  316.                         increment(cpu.sp);
  317.                         break;
  318.                 case MC_halt:                //停机
  319.                         ps = finished;
  320.                         break;
  321.                 case MC_lda:
  322.                         //双字节指令,格式:LDA B,其第二字节为一个内存地址,
  323.                         //将位于B地址单元中的内容送入A累加器.
  324.                         //实现时以当前PC所指内存中的数值为地址偏移,将其所指的内存中的内容送入A
  325.                         cpu.a = mem[mem[cpu.pc]];
  326.                         increment(cpu.pc);
  327.                         setflags(cpu.a);
  328.                         break;
  329.                 case MC_ldx:
  330.                         //将X+B所指的内存单元的内容送入A,即:A=[X+B]
  331.                         cpu.a = mem[index()];
  332.                         increment(cpu.pc);
  333.                         setflags(cpu.a);
  334.                         break;
  335.                 case MC_ldi:                //A=ImmB
  336.                         cpu.a = mem[cpu.pc];
  337.                         increment(cpu.pc);
  338.                         setflags(cpu.a);
  339.                         break;
  340.                 case MC_lsp:                //SP=[ImmB]
  341.                         cpu.sp = mem[mem[cpu.pc]];
  342.                         increment(cpu.pc);
  343.                         break;
  344.                 case MC_lspi:                //SP=ImmB
  345.                         cpu.sp = mem[cpu.pc];
  346.                         increment(cpu.pc);
  347.                         break;
  348.                 case MC_sta:                //[ImmB]=A
  349.                         mem[mem[cpu.pc]] = cpu.a;
  350.                         increment(cpu.pc);
  351.                         break;
  352.                 case MC_stx:                //[X+B]=A
  353.                         mem[index()] = cpu.a;
  354.                         increment(cpu.pc);
  355.                         break;
  356.                 case MC_add:                //A=A+[ImmB]
  357.                         cpu.c = (cpu.a + mem[mem[cpu.pc]] >; 255);
  358.                         cpu.a = (cpu.a + mem[mem[cpu.pc]]) % 256;        //限定数值的大小为8bit
  359.                         increment(cpu.pc);
  360.                         setflags(cpu.a);
  361.                         break;
  362.                 case MC_adx:                //A=A+[X+ImmB]
  363.                         cpu.c = (cpu.a + mem[index()] >; 255);
  364.                         cpu.a = (cpu.a + mem[index()]) % 256;
  365.                         increment(cpu.pc);
  366.                         setflags(cpu.a);
  367.                         break;
  368.                 case MC_adi:                //A=A+ImmB
  369.                         cpu.c = (cpu.a + mem[cpu.pc] >; 255);
  370.                         cpu.a = (cpu.a + mem[cpu.pc]) % 256;
  371.                         increment(cpu.pc);
  372.                         setflags(cpu.a);
  373.                         break;
  374.                 case MC_adc:                //A=A+C+[ImmB]
  375.                         carry = cpu.c;
  376.                         cpu.c = (cpu.a + mem[mem[cpu.pc]] + carry >; 255);
  377.                         cpu.a = (cpu.a + mem[mem[cpu.pc]] + carry) % 256;
  378.                         increment(cpu.pc);
  379.                         setflags(cpu.a);
  380.                         break;
  381.                 case MC_acx:                //A=A+C+[X+ImmB]
  382.                         carry = cpu.c;
  383.                         cpu.c = (cpu.a + mem[index()] + carry >; 255);
  384.                         cpu.a = (cpu.a + mem[index()] + carry) % 256;
  385.                         increment(cpu.pc);
  386.                         setflags(cpu.a);
  387.                         break;
  388.                 case MC_aci:                //A=A+C+ImmB
  389.                         carry = cpu.c;
  390.                         cpu.c = (cpu.a + mem[cpu.pc] + carry >; 255);
  391.                         cpu.a = (cpu.a + mem[cpu.pc] + carry) % 256;
  392.                         increment(cpu.pc);
  393.                         setflags(cpu.a);
  394.                         break;
  395.                 case MC_sub:                //A=A-[ImmB]
  396.                         cpu.c = (cpu.a < mem[mem[cpu.pc]]);
  397.                         cpu.a = (cpu.a - mem[mem[cpu.pc]] + 256) % 256;
  398.                         increment(cpu.pc);
  399.                         setflags(cpu.a);
  400.                         break;
  401.                 case MC_sbx:                //A=A-[X+ImmB]
  402.                         cpu.c = (cpu.a < mem[index()]);
  403.                         cpu.a = (cpu.a - mem[index()] + 256) % 256;
  404.                         increment(cpu.pc);
  405.                         setflags(cpu.a);
  406.                         break;
  407.                 case MC_sbi:                //A=A-ImmB
  408.                         cpu.c = (cpu.a < mem[cpu.pc]);
  409.                         cpu.a = (cpu.a - mem[cpu.pc] + 256) % 256;
  410.                         increment(cpu.pc);
  411.                         setflags(cpu.a);
  412.                         break;
  413.                 case MC_sbc:                //A=A-C-[ImmB]
  414.                         carry = cpu.c;
  415.                         cpu.c = (cpu.a < mem[mem[cpu.pc]] + carry);
  416.                         cpu.a = (cpu.a - mem[mem[cpu.pc]] - carry + 256) % 256;
  417.                         increment(cpu.pc);
  418.                         setflags(cpu.a);
  419.                         break;
  420.                 case MC_scx:                //A=A-C-[X+ImmB]
  421.                         carry = cpu.c;
  422.                         cpu.c = (cpu.a < mem[index()] + carry);
  423.                         cpu.a = (cpu.a - mem[index()] - carry + 256) % 256;
  424.                         increment(cpu.pc);
  425.                         setflags(cpu.a);
  426.                         break;
  427.                 case MC_sci:                //A=A-C-ImmB
  428.                         carry = cpu.c;
  429.                         cpu.c = (cpu.a < mem[cpu.pc] + carry);
  430.                         cpu.a = (cpu.a - mem[cpu.pc] - carry + 256) % 256;
  431.                         increment(cpu.pc);
  432.                         setflags(cpu.a);
  433.                         break;
  434.                 case MC_cmp:                //A与B所指单元的内容进行比较,影响标志位
  435.                         cpu.c = (cpu.a < mem[mem[cpu.pc]]);
  436.                         setflags((cpu.a - mem[mem[cpu.pc]] + 256) % 256);
  437.                         increment(cpu.pc);
  438.                         break;
  439.                 case MC_cpx:                //A与 X+ImmB 所指单元的内容进行比较,影响标志位
  440.                         cpu.c = (cpu.a < mem[index()]);
  441.                         setflags((cpu.a - mem[index()] + 256) % 256);
  442.                         increment(cpu.pc);
  443.                         break;
  444.                 case MC_cpi:                //A与ImmB进行比较,影响标志位
  445.                         cpu.c = (cpu.a < mem[cpu.pc]);
  446.                         setflags((cpu.a - mem[cpu.pc] + 256) % 256);
  447.                         increment(cpu.pc);
  448.                         break;
  449.                 case MC_ana:                //A与[ImmB]进行位与,影响标志位
  450.                         cpu.a &= mem[mem[cpu.pc]];
  451.                         increment(cpu.pc);
  452.                         setflags(cpu.a);
  453.                         cpu.c = false;
  454.                         break;
  455.                 case MC_anx:                //A与[X+ImmB]进行位与,影响标志位
  456.                         cpu.a &= mem[index()];
  457.                         increment(cpu.pc);
  458.                         setflags(cpu.a);
  459.                         cpu.c = false;
  460.                         break;
  461.                 case MC_ani:                //A与ImmB进行位与,影响标志位
  462.                         cpu.a &= mem[cpu.pc];
  463.                         increment(cpu.pc);
  464.                         setflags(cpu.a);
  465.                         cpu.c = false;
  466.                         break;
  467.                 case MC_ora:                //A与[ImmB]进行位或,影响标志位
  468.                         cpu.a |= mem[mem[cpu.pc]];
  469.                         increment(cpu.pc);
  470.                         setflags(cpu.a);
  471.                         cpu.c = false;
  472.                         break;
  473.                 case MC_orx:                //A与[X+ImmB]进行位或,影响标志位
  474.                         cpu.a |= mem[index()];
  475.                         increment(cpu.pc);
  476.                         setflags(cpu.a);
  477.                         cpu.c = false;
  478.                         break;
  479.                 case MC_ori:                //A与ImmB进行位或,影响标志位
  480.                         cpu.a |= mem[cpu.pc];
  481.                         increment(cpu.pc);
  482.                         setflags(cpu.a);
  483.                         cpu.c = false;
  484.                         break;
  485.                 case MC_jmp:                //绝对跳转到B地址
  486.                         cpu.pc = mem[cpu.pc];
  487.                         break;
  488.                 case MC_bze:                //如Z标志为1 则跳转到B 单元去执行,否则顺序执行
  489.                         if (cpu.z)
  490.                                 cpu.pc = mem[cpu.pc];
  491.                         else
  492.                                 increment(cpu.pc);
  493.                         break;
  494.                 case MC_bnz:                //如Z标志为0 则跳转到B 单元去执行,否则顺序执行
  495.                         if (!cpu.z)
  496.                                 cpu.pc = mem[cpu.pc];
  497.                         else
  498.                                 increment(cpu.pc);
  499.                         break;
  500.                 case MC_bpz:                //如P标志为1(正) 则跳转到B 单元去执行,否则顺序执行
  501.                         if (cpu.p)
  502.                                 cpu.pc = mem[cpu.pc];
  503.                         else
  504.                                 increment(cpu.pc);
  505.                         break;
  506.                 case MC_bng:                //如P标志为0(负) 则跳转到B 单元去执行,否则顺序执行
  507.                         if (!cpu.p)
  508.                                 cpu.pc = mem[cpu.pc];
  509.                         else
  510.                                 increment(cpu.pc);
  511.                         break;
  512.                 case MC_bcs:                //如C标志为1 则跳转到B 单元去执行,否则顺序执行
  513.                         if (cpu.c)
  514.                                 cpu.pc = mem[cpu.pc];
  515.                         else
  516.                                 increment(cpu.pc);
  517.                         break;
  518.                 case MC_bcc:                //如C标志为0 则跳转到B 单元去执行,否则顺序执行
  519.                         if (!cpu.c)
  520.                                 cpu.pc = mem[cpu.pc];
  521.                         else
  522.                                 increment(cpu.pc);
  523.                         break;
  524.                 case MC_jsr:                //调用子程序,返回地址入栈,操作数(JSR的后一字节)B->;PC
  525.                         decrement(cpu.sp);
  526.                         mem[cpu.sp] = (cpu.pc + 1) % 256;        // push return address
  527.                         cpu.pc = mem[cpu.pc];
  528.                         break;
  529.                 case MC_tsp:                //单字节指令,将栈指针寄存器SP的内容送入A累加器
  530.                         cpu.a = cpu.sp;
  531.                         setflags(cpu.a);
  532.                         break;
  533.                 case MC_lbpi:                //双字节指令,格式:LBPI B,将由基址指针寄存器BP指示的内存单元起的偏移量为B字节的内存单元的内容送入A
  534.                                         //累加器
  535.                         cpu.a = mem[cpu.bp + mem[cpu.pc]];
  536.                         increment(cpu.pc);
  537.                         setflags(cpu.a);
  538.                         break;
  539.                 case MC_fbpi:                //双字节指令,格式:FBPI B,将立即数B送入基址指针寄存器BP
  540.                         cpu.bp = mem[cpu.pc];
  541.                         increment(cpu.pc);
  542.                         break;
  543.                 case MC_tbp:                //单字节指令,将基址指针寄存器BP的内容送入A累加器
  544.                         cpu.a = cpu.bp;
  545.                         setflags(cpu.a);
  546.                         break;
  547.                 case MC_tsb:                //单字节指令,将栈指针寄存器SP的内容送入址指针寄存器BP
  548.                         cpu.bp = cpu.sp;
  549.                         break;
  550.                 case MC_tabp:                //单字节指令,将A累加器的内容送入到栈指针寄存器BP中
  551.                         cpu.bp = cpu.a;
  552.                         break;
  553.                 default:
  554.                         ps = badop;
  555.                         break;
  556.                 }
  557.     } while (ps == running);
  558.     if (ps != finished)
  559.                 runtime_error(results, pcnow);
  560. }

  561. /*
  562.   对虚拟机执行汇编后的机器指令程序进行执行执行前的准备工作:
  563.   argc:用户在命令行上提供的参数个数,据此判断是否以交互方式提示用户输入如下的参数:
  564.   trace:设定跟踪标志;datafile:程序的输入数据文件, outfile:程序的输出文件
  565.   entrance:机器指令程序的入口点
  566. */
  567. void MC::interpret(int argc, int trace, char *datafile, char *outfile,
  568.                                    int entrance)
  569. {
  570.     char filename[256] = { 0 };
  571.     FILE *data, *results;
  572.     bool tracing;
  573.     int entry;

  574.     if (argc == 2) {
  575.                 //用户没有提供任何的任选参数,交互式提示用户输入
  576.                 printf("\nTrace execution (y/N/q)? ");
  577.                 char reply = getchar();
  578.                 scanf("%*[^\n]");
  579.                 getchar();
  580.                 if (toupper(reply) != 'Q') {
  581.                         tracing = toupper(reply) == 'Y';

  582.                         printf("\nData file [STDIN] ? ");
  583.                         fgets(filename, sizeof(filename), stdin);
  584.                         filename[strlen(filename) - 1] = 0;        //replace trailing '\n' with 0
  585.                         (!filename[0]) ? data = NULL : data = fopen(filename, "r");
  586.                         if (data == NULL) {
  587.                                 printf("taking data from stdin\n");
  588.                                 data = stdin;
  589.                         }

  590.                         printf("\nResults file [STDOUT] ? ");
  591.                         fgets(filename, sizeof(filename), stdin);
  592.                         filename[strlen(filename) - 1] = 0;        //replace trailing '\n' with 0
  593.                         !filename[0] ? results = NULL : results = fopen(filename, "w");
  594.                         if (results == NULL) {
  595.                                 printf("sending results to stdout\n");
  596.                                 results = stdout;
  597.                         }

  598.                         printf("Entry point? ");
  599.                         if (scanf("%d%*[^\n]", &entry) != 1)
  600.                                 entry = 0;
  601.                         getchar();
  602.                 } else {
  603.                         exit(0);
  604.                 }
  605.     }
  606.     //用户在命令行上提供了任选参数,根据参数值打开相关文件,设定程序入口地址
  607.     if (argc >; 2) {
  608.                 tracing = trace;
  609.                 entry = entrance;

  610.                 (!datafile[0]) ? data = NULL : data = fopen(datafile, "r");
  611.                 if (data == NULL) {
  612.                         printf("taking data from stdin\n");
  613.                         data = stdin;
  614.                 }

  615.                 (!outfile[0]) ? results = NULL : results = fopen(outfile, "w");
  616.                 if (results == NULL) {
  617.                         printf("sending results to stdout\n");
  618.                         results = stdout;
  619.                 }
  620.     }
  621.     //执行机器指令程序
  622.     execute(entry % 256, data, results, tracing);        // do it!
  623.     if (results != stdout)
  624.                 fclose(results);
  625.     if (data != stdin)
  626.                 fclose(data);
  627. }

  628. //虚拟机初始化,清空内存,初始机器指令表
  629. MC::MC()
  630. {
  631.     int i;
  632.     //清空内存
  633.     for (i = 0; i <= 255; i++)
  634.                 mem[i] = MC_bad;
  635.     // 初始机器指令表
  636.     for (i = 0; i <= 255; i++)
  637.                 mnemonics[i] = "???";
  638.     //机器指令表填入对应的汇编助记符  0xxx为机器指令值
  639.     mnemonics[MC_nop] = "NOP";        //ox0
  640.     mnemonics[MC_clra] = "CLRA";        //ox1
  641.     mnemonics[MC_clrc] = "CLRC";        //ox2
  642.     mnemonics[MC_clrx] = "CLRX";        //ox3
  643.     mnemonics[MC_cmc] = "CMC";        //ox4
  644.     mnemonics[MC_inc] = "INC";        //ox5
  645.     mnemonics[MC_dec] = "DEC";        //ox6
  646.     mnemonics[MC_incx] = "INCX";        //ox7
  647.     mnemonics[MC_decx] = "DECX";        //ox8
  648.     mnemonics[MC_tax] = "TAX";        //ox9
  649.     mnemonics[MC_ini] = "INI";        //oxa
  650.     mnemonics[MC_inh] = "INH";        //oxb
  651.     mnemonics[MC_inb] = "INB";        //oxc
  652.     mnemonics[MC_ina] = "INA";        //oxd
  653.     mnemonics[MC_oti] = "OTI";        //oxe
  654.     mnemonics[MC_otc] = "OTC";        //oxf
  655.     mnemonics[MC_oth] = "OTH";        //ox10
  656.     mnemonics[MC_otb] = "OTB";        //ox11
  657.     mnemonics[MC_ota] = "OTA";        //ox12
  658.     mnemonics[MC_push] = "PUSH";        //ox13
  659.     mnemonics[MC_pop] = "POP";        //ox14
  660.     mnemonics[MC_shl] = "SHL";        //ox15
  661.     mnemonics[MC_shr] = "SHR";        //ox16
  662.     mnemonics[MC_ret] = "RET";        //ox17
  663.     mnemonics[MC_halt] = "HALT";        //ox18
  664.     mnemonics[MC_lda] = "LDA";        //ox19
  665.     mnemonics[MC_ldx] = "LDX";        //ox1a
  666.     mnemonics[MC_ldi] = "LDI";        //ox1b
  667.     mnemonics[MC_lsp] = "LSP";        //ox1c
  668.     mnemonics[MC_lspi] = "LSPI";        //ox1d
  669.     mnemonics[MC_sta] = "STA";        //ox1e
  670.     mnemonics[MC_stx] = "STX";        //ox1f
  671.     mnemonics[MC_add] = "ADD";        //ox20
  672.     mnemonics[MC_adx] = "ADX";        //ox21
  673.     mnemonics[MC_adi] = "ADI";        //ox22
  674.     mnemonics[MC_adc] = "ADC";        //ox23
  675.     mnemonics[MC_acx] = "ACX";        //ox24
  676.     mnemonics[MC_aci] = "ACI";        //ox25
  677.     mnemonics[MC_sub] = "SUB";        //ox26
  678.     mnemonics[MC_sbx] = "SBX";        //ox27
  679.     mnemonics[MC_sbi] = "SBI";        //ox28
  680.     mnemonics[MC_sbc] = "SBC";        //ox29
  681.     mnemonics[MC_scx] = "SCX";        //ox2a
  682.     mnemonics[MC_sci] = "SCI";        //ox2b
  683.     mnemonics[MC_cmp] = "CMP";        //ox2c
  684.     mnemonics[MC_cpx] = "CPX";        //ox2d
  685.     mnemonics[MC_cpi] = "CPI";        //ox2e
  686.     mnemonics[MC_ana] = "ANA";        //ox2f
  687.     mnemonics[MC_anx] = "ANX";        //ox30
  688.     mnemonics[MC_ani] = "ANI";        //ox31
  689.     mnemonics[MC_ora] = "ORA";        //ox32
  690.     mnemonics[MC_orx] = "ORX";        //ox33
  691.     mnemonics[MC_ori] = "ORI";        //ox34
  692.     mnemonics[MC_jmp] = "JMP";        //ox35
  693.     mnemonics[MC_bze] = "BZE";        //ox36
  694.     mnemonics[MC_bnz] = "BNZ";        //ox37
  695.     mnemonics[MC_bpz] = "BPZ";        //ox38
  696.     mnemonics[MC_bng] = "BNG";        //ox39
  697.     mnemonics[MC_bcc] = "BCC";        //ox3a
  698.     mnemonics[MC_bcs] = "BCS";        //ox3b
  699.     mnemonics[MC_tsp] = "TSP";        //ox3c
  700.     mnemonics[MC_jsr] = "JSR";        //ox3d
  701.     mnemonics[MC_lbpi] = "LBPI";        //ox3e
  702.     mnemonics[MC_fbpi] = "FBPI";        //ox3f
  703.     mnemonics[MC_tbp] = "TBP";        //ox40
  704.     mnemonics[MC_tsb] = "TSB";        //ox41
  705.     mnemonics[MC_tabp] = "TABP";        //ox42  

  706.     // 初始机器指令长度表
  707.     for (i = 0; i <= 255; i++)
  708.                 mnxlen[i] = 1;
  709.     mnxlen[MC_lda] = 2;
  710.     mnxlen[MC_ldx] = 2;
  711.     mnxlen[MC_ldi] = 2;
  712.     mnxlen[MC_lsp] = 2;
  713.     mnxlen[MC_lspi] = 2;
  714.     mnxlen[MC_sta] = 2;
  715.     mnxlen[MC_stx] = 2;
  716.     mnxlen[MC_lbpi] = 2;
  717.     mnxlen[MC_fbpi] = 2;
  718.     mnxlen[MC_add] = 2;
  719.     mnxlen[MC_adi] = 2;
  720.     mnxlen[MC_adc] = 2;
  721.     mnxlen[MC_adx] = 2;
  722.     mnxlen[MC_acx] = 2;
  723.     mnxlen[MC_aci] = 2;
  724.     mnxlen[MC_sub] = 2;
  725.     mnxlen[MC_sbx] = 2;
  726.     mnxlen[MC_sbi] = 2;
  727.     mnxlen[MC_sbc] = 2;
  728.     mnxlen[MC_scx] = 2;
  729.     mnxlen[MC_sci] = 2;
  730.     mnxlen[MC_cmp] = 2;
  731.     mnxlen[MC_cpx] = 2;
  732.     mnxlen[MC_cpi] = 2;
  733.     mnxlen[MC_ana] = 2;
  734.     mnxlen[MC_anx] = 2;
  735.     mnxlen[MC_ani] = 2;
  736.     mnxlen[MC_ora] = 2;
  737.     mnxlen[MC_orx] = 2;
  738.     mnxlen[MC_ori] = 2;
  739.     mnxlen[MC_jmp] = 2;
  740.     mnxlen[MC_bze] = 2;
  741.     mnxlen[MC_bnz] = 2;
  742.     mnxlen[MC_bpz] = 2;
  743.     mnxlen[MC_bng] = 2;
  744.     mnxlen[MC_bcc] = 2;
  745.     mnxlen[MC_bcs] = 2;
  746.     mnxlen[MC_jsr] = 2;
  747. }

复制代码

论坛徽章:
0
24 [报告]
发表于 2005-01-17 17:59 |只看该作者

虚拟机源码分析

汇编器类的头文件:as.h


  1. //////////////////////////////////////
  2. // 汇编语言虚拟机  MYVM Version 0.11a
  3. // snallie@163.net  2003.2
  4. //
  5. // as.h
  6. // 汇编器的头文件
  7. //////////////////////////////////////
  8. #ifndef AS_H
  9. #define AS_H

  10. #include "misc.h"
  11. #include "mc.h"

  12. typedef struct refnodes {
  13.          MC_bytes refsymaddr;        //引用地址标号产生的内存地址
  14.          struct refnodes *nextref;        //指向向后引用地址标号的下一结点的链表指针
  15. } refnode;

  16. typedef struct symtab {
  17.          char symname[MAXSYMLEN];        //符号地址定义名
  18.          MC_bytes symaddr;                //符号地址定义名所代表的内存地址
  19.          struct refnodes *firstref;        //引用该符号地址的首次出现,用以实现链表
  20. } symboltab;

  21. //由lex词法分析器给调用者返回的记号种类的枚举类型定义
  22. //ASMCODE:汇编指令;LABEL:定义地址标号;REFLABEL:引用地址标号;NUM:数字标识;
  23. //ID:标识符;       CMNT:注释语名标识; UNKNOWN:不可识别的标号
  24. typedef enum tktype {
  25.          ASMCODE, LABEL, REFLABEL,
  26.          NUMBER, ID, NUM, CMNT,UNKNOWN
  27. } tokentype;

  28. class AS {
  29. public:
  30.          //  汇编器的构造函数 打开源文件,初始化符号表
  31.          AS(char *sourcename, MC * M);

  32.          // 析构函数关闭源文件
  33.          ~AS();

  34.          // 将源文件的汇编语言程序汇编成机器指令并将其存入CPU的内存中,若在汇编中存在错误,则将
  35.          // 错误标志返回到errors中
  36.          void assemble(bool & errors);

  37.          //mksymtab:第1遍扫描时构造符号表   
  38.          void mksymtab(int &err);

  39.          /*
  40.        lex:汇编器所要调用的词法分析函数,给主调函数返回当前所读得的词法记号的类型并将单词符号串
  41.        存入words数组中,同时查机器的指令表,将该单词对应的机器指令存入opcode返回主调函数。
  42.      */
  43.          tokentype lex(char *words, MC_opcodes & opcode);


  44.          //lookupcmd: 查询汇编指令表,返回cmd所对应的机器指令
  45.          MC_bytes lookupcmd(char *cmd, MC * mch);

  46.          /*   
  47.                    seeklabel
  48.                    查询符号表,确定符号的存在收
  49.                    purpose=0 是否对于符号进行了重复定义,进行错误提示
  50.                    purpose=1 是否已经有该符号,以便进行引用填充   
  51.      */
  52.          int seeklabel(char *lbl, int purpose);

  53.          //symtablen(): 取得符号表的长度
  54.          int symtablen();
  55.          int binlen;                        //binary code length

  56. private:
  57.          MC * Machine;                // 指向MC对象实例的指针
  58.          FILE *src;                        // 源文件指针
  59.          char srcfile[20];                // 保存源文件名
  60.          symboltab symtabhdr[SYMTABLEN];        //符号表结构数组
  61. };

  62. #endif                                /*AS_H */

复制代码

论坛徽章:
0
25 [报告]
发表于 2005-01-17 18:01 |只看该作者

虚拟机源码分析

汇编器的实现文件:as.cpp


  1. ////////////////////////////////////
  2. // 汇编语言虚拟机  MYVM Version 0.11a
  3. // snallie@163.net  2003.2
  4. //
  5. // as.cpp
  6. // 2遍扫描的汇编器的实现
  7. /////////////////////////////////////
  8. #include "as.h"

  9. /***************************************************
  10. * 汇编器的构造函数AS: 打开源文件,初始化符号表
  11. ****************************************************/
  12. AS::AS(char *sourcename, MC * M)
  13. {
  14.     Machine = M;
  15.     int i;
  16.     strcpy(srcfile, sourcename);
  17.     src = fopen(sourcename, "r");
  18.     if (src == NULL) {
  19.                 printf("Could not open input file\n");
  20.                 exit(1);
  21.     }
  22.     //符号表内的符号名全部初始为 '????????'
  23.     for (i = 0; i < SYMTABLEN; i++)
  24.                 strcpy(symtabhdr[i].symname, "???????");
  25. }

  26. /****************************************************
  27. * 汇编器的析构函数~AS: 关闭源文件
  28. *****************************************************/
  29. AS::~AS()
  30. {
  31.     if (src) {
  32.                 fclose(src);
  33.     }
  34.     src = NULL;
  35. }

  36. /*****************************************************
  37.   assemble
  38.   汇编函数
  39.   2遍扫描源程序,构造符号表,汇编成机器指令
  40. ****************************************************/
  41. void AS::assemble(bool & errors)
  42. {
  43.     MC_bytes lc = 0;                // 地址计数器
  44.     MC_bytes op;
  45.     int number;
  46.     char ch;
  47.     bool okay;
  48.     tokentype tokencat;                // 记号类别
  49.     int labelidx;                // 标号在符号表内的序号
  50.     char words[10];
  51.     char tpwords[15];
  52.     MC_opcodes opcode;
  53.     int i;
  54.     int errpass1 = 0;

  55.     printf("Assembling code ... \n");
  56.     mksymtab(errpass1);                // 进行第1遍扫描,以建立标号的符号表
  57.     fclose(src);
  58.     src = NULL;                        // 关闭输入流,完成第1遍扫描,准备第2遍扫描
  59.     if (errpass1 >; 0) {
  60.                 printf("Pass1: totally %d errors found.\n", errpass1);
  61.                 exit(3);
  62.     }

  63.     src = fopen(srcfile, "r");        // 重新打开输入流,以进行第2遍扫描
  64.     if (src == NULL) {
  65.                 printf("Could not open input file\n");
  66.                 exit(1);
  67.     }

  68.     for (i = 0; i <= MEMSIZE - 1; i++)        // 将处理机的内存初始为无效代码 MC_bad
  69.                 Machine->;mem[i] = MC_bad;
  70.     lc = 0;                        // 地址计数器清0
  71.     errors = false;                // errors保存在第2遍扫描过程的错误状态

  72.     /*
  73.           开始第2遍扫描,结合第1遍扫描生成的符号表,将输入的汇编源程序汇编成机器指令,
  74.           将其存入到Machine的mem中
  75.         */
  76.     while (!feof(src)) {
  77.                 tokencat = lex(words, opcode);        //读入一个单词,取得单词的类别及相关信息
  78. #ifdef DEBUG
  79.                 printf("(%2d) %d %-8s\n", opcode != MAXINSTUCTION ? opcode : -1,
  80.                            tokencat, words);
  81. #endif
  82.                 switch (tokencat) {
  83.                 case ASMCODE:                //汇编指令处理
  84.             // 为什么在这里还要查询汇编指令。不是已经在lex中的opcode得到了吗?
  85.                         op = Machine->;opcode(words);        // 查询汇编指令代表的机器指令
  86.                         if (op == MC_bad)        // 不识别的汇编指令,设置错误标志
  87.                         {
  88.                                 printf("Pass2: %s - Bad mnemonic at %d\n", words, lc);
  89.                                 errors = true;
  90.                         }
  91.                         Machine->;mem[lc] = op;        // 存储机器指令到机器的内存中
  92.                         lc = (lc + 1) % MEMSIZE;        // 地址计数器增1
  93.                         break;
  94.                 case REFLABEL:                //地址标号的引用处理
  95.                         strcpy(tpwords, words);
  96.                         strcat(tpwords, ":");        //将地址标号转变成其定义的形式
  97.                         //查询符号表,是否已经有该符号,返回在符号表的位置
  98.                         labelidx = seeklabel(tpwords, 1);
  99.                         if (labelidx == -1) {
  100.                                 printf
  101.                                         ("Pass2: ERROR! No such label to be referenced :%s at %d\n",
  102.                                          words, lc);
  103.                                 exit(3);        //未定义该标号,引用错误!
  104.                         } else {
  105. #ifdef DEBUG
  106.                                 //显示标号所代表的内存地址...   
  107.                                 printf("REFLBL %d %d %s\n", lc,
  108.                                            symtabhdr[labelidx].symaddr, words);
  109. #endif
  110.                                 //取得该符号所代表的内存地址,存到机器的内存中
  111.                                 Machine->;mem[lc] = symtabhdr[labelidx].symaddr;
  112.                                 lc = (lc + 1) % MEMSIZE;        // 地址计数器增1
  113.                         }
  114.                         break;
  115.                 case NUM:                //数值处理:仅可为1个字节宽度
  116.                         number = atoi(words);
  117.                         if (number >;= 0)        // convert to proper byte value
  118.                                 Machine->;mem[lc] = number % 256;
  119.                         else
  120.                                 Machine->;mem[lc] = (256 - abs(number) % 256) % 256;
  121.                         lc = (lc + 1) % 256;        // 地址计数器增1
  122.                         break;
  123.                 }
  124.     }

  125.     binlen = lc;                //最终的汇编后的二进制的代码总长度
  126.     printf("Binary assembled: %d bytes.\n", lc);

  127.     // dump binary file for reference
  128.     char binfile[256];
  129.     FILE *bin;
  130.     newsuffix(srcfile, "lst", binfile);

  131.     bin = fopen(binfile, "w");
  132.     if (bin == NULL) {
  133.                 printf("Binary file ignored.\n");
  134.     } else {
  135.                 for (i = 0; i < binlen; i++)
  136.                         if (strcmp(Machine->;getmns(Machine->;mem[i]), "???")
  137.                                 && Machine->;getmnxlen(Machine->;mem[i]) == 2) {
  138.                                 fprintf(bin, " %02X  %02X%02X      %-4s %02X\n", i,
  139.                                                 Machine->;mem[i], Machine->;mem[i + 1],
  140.                                                 Machine->;getmns(Machine->;mem[i]),
  141.                                                 Machine->;mem[i + 1]);
  142.                                 i++;
  143.                         } else
  144.                                 fprintf(bin, " %02X  %02X        %-4s\n", i, Machine->;mem[i],
  145.                                                 Machine->;getmns(Machine->;mem[i]));
  146.     }
  147.     fclose(bin);
  148. }


  149. /*
  150.   mksymtab()
  151.   构造符号表,建立符号地址与内存地址的对应表,
  152.   同时将对符号地址的引用情况以链表的形式表示出来
  153. */
  154. void AS::mksymtab(int &err)
  155. {
  156.     char words[10];
  157.     char tpwords[15];
  158.     int labelidx;
  159.     int tokencnt = 0;                //记号的个数
  160.     int symcnt = 0;
  161.     MC_opcodes opcode;
  162.     refnode *refs, *refsa, *newnode;
  163.     tokentype tokencat;

  164.     while (!feof(src)) {
  165.                 tokencat = lex(words, opcode);        //读入一个单词,取得单词的类别及相关信息
  166.                 if (tokencat != CMNT)        // 注释信息,直接跳过
  167.                         tokencnt++;
  168.                 else
  169.                         continue;

  170.                 switch (tokencat) {
  171.                 case LABEL:                //新定义的标号,将其加入符号表   
  172.                         if (seeklabel(words, 0) == -1) {
  173.                                 strcpy(symtabhdr[symcnt].symname, words);
  174.                                 symtabhdr[symcnt].symaddr = tokencnt - symtablen();
  175.                                 symtabhdr[symcnt].firstref = NULL;
  176.                                 symcnt++;
  177.                         } else if (seeklabel(words, 0) == -2) {
  178.                                 //标号重复定义错误
  179.                                 err++;
  180.                         }
  181.                         break;
  182.                 case REFLABEL:
  183.                         //标号地址的引用处理
  184.                         strcpy(tpwords, words);
  185.                         strcat(tpwords, ":");

  186.                         labelidx = seeklabel(tpwords, 1);
  187.                         if (labelidx == -1) {
  188. #ifdef DEBUG
  189.                                 //向前引用,暂且输出一个警告信息,待进一步向前扫描才确定其是否定义
  190.                                 printf
  191.                                         ("Pass1 warning: label not defined by now: '%s:' , addr:%2d, ignored!\n",
  192.                                          words, tokencnt);
  193. #endif
  194.                                 ;
  195.                         } else {
  196.                                 // 向后引用情况,则将该引用的地址加入单链表
  197.                                 newnode = new refnode;
  198.                                 newnode->;refsymaddr = tokencnt - 1;
  199.                                 newnode->;nextref = NULL;
  200.                                 if (symtabhdr[labelidx].firstref == NULL) {
  201.                                         symtabhdr[labelidx].firstref = newnode;
  202.                                 } else {
  203.                                         refs = symtabhdr[labelidx].firstref;
  204.                                         refsa = refs;
  205.                                         while (refs != NULL) {
  206.                                                 refsa = refs;
  207.                                                 refs = refs->;nextref;
  208.                                         }
  209.                                         refsa->;nextref = newnode;
  210.                                 }
  211.                         }
  212.                         break;
  213.                 case UNKNOWN:                //不可识别的符号,输出错误信息
  214. #ifdef DEBUG

  215.                         printf("Pass1 Warning: Unknown token: %d %s(%d)\n", tokencat,
  216.                                    words, tokencnt);
  217.                         //err++;      
  218. #endif

  219.                         break;
  220.                 }
  221. #ifdef DEBUG
  222.                 printf("(%2d) %d %-8s(%d)\n",
  223.                            opcode != MAXINSTUCTION ? opcode : -1, tokencat, words,
  224.                            tokencnt);
  225. #endif
  226.     }
  227. #ifdef DEBUG

  228.     //输出所建立的符号表
  229.     printf("\n<<<< Symbol table constructed >;>;>;>;\n");
  230.     for (int i = 0; i < symcnt; i++) {
  231.                 printf("%s %d %x ->; ", symtabhdr[i].symname, symtabhdr[i].symaddr,
  232.                            symtabhdr[i].firstref);
  233.                 if (symtabhdr[i].firstref != NULL) {
  234.                         refs = symtabhdr[i].firstref;
  235.                         while (refs != NULL) {
  236.                                 printf("%d %x ->; ", refs->;refsymaddr, refs->;nextref);
  237.                                 refs = refs->;nextref;
  238.                         }
  239.                         printf("\n");
  240.                 }
  241.                 printf("\n");
  242.     }
  243.     printf("<<<< Symbol table above >;>;>;>;\n");
  244.     //符号表建立完成
  245. #endif
  246. }

  247. /*
  248.   seeklabel()
  249.   查询符号表,确定符号存在与否
  250.   purpose=0 是否对于符号进行了重复定义,进行错误提示
  251.   purpose=1 是否已经有该符号,以便进行引用填充
  252. */
  253. int AS::seeklabel(char *lbl, int purpose)
  254. {
  255.     int i = 0;

  256.     for (i = 0; i < SYMTABLEN && strcmp(symtabhdr[i].symname, lbl); i++)
  257.                 ;
  258.     if (i < SYMTABLEN && !purpose) {
  259.                 printf("label '%s' multiple defined ,location:%d\n", lbl,
  260.                            symtabhdr[i].symaddr);
  261.                 return -2;                //标号重复定义
  262.     } else if (i < SYMTABLEN && purpose == 1) {
  263.                 return i;                //返回标号在符号表中的下标
  264.     } else {
  265.                 return -1;                //无此标号
  266.     }
  267. }

  268. /*
  269.   lex:词法分析
  270.   逐字符读取输入流,以空格为分隔标记,将输入流的字符组合成单词,
  271.   给主调函数返回当前所读得的词法记号的类型并将单词符号串存入
  272.   words数组中,同时查机器的指令表,将该单词对应的机器指令存入
  273.   opcode返回主调函数。
  274. */
  275. tokentype AS::lex(char *words, MC_opcodes & opcode)
  276. {
  277.     char cmds[20];
  278.     char ch;
  279.     MC_bytes cds;
  280.     tokentype tks;
  281.     int i = 0;

  282.     cmds[0] = 0;

  283.     ch = toupper(getc(src));

  284.         //凡是ASCII不大于0X20(空格)的字符都规定为空格
  285.     while (ch <= ' ' && !feof(src))        //跳过所有的ASCII值为00~0x20的字符
  286.                 ch = toupper(getc(src));

  287.     if (isalpha(ch)) {                //地址标号/汇编指令:字母开头字母及数字的有限序列
  288.                 do {
  289.                         cmds[i] = ch;
  290.                         i++;
  291.                         ch = toupper(getc(src));
  292.                 } while (ch >; ' ' && (isalpha(ch) || isdigit(ch)) && !feof(src));

  293.                 if (ch == ':') {        // 若尾随有":",则为地址标号的定义,应将其保留
  294.                         cmds[i] = ch;
  295.                         i++;
  296.                 }
  297.                 //查询汇编指令表,以确定是否为汇编指令还是地址标号的定义及引用
  298.                 cmds[i] = 0;
  299.                 strcpy(words, cmds);
  300.                 cds = lookupcmd(cmds, Machine);        //查询汇编指令表
  301.                 opcode = (MC_opcodes) cds;
  302.                 // 如果没有查找到相应地汇编指令并且这个符号后面紧跟着":",那么就是地址标号地定义
  303.                 if (cds == MAXINSTUCTION && words[strlen(words) - 1] == ':')
  304.                         tks = LABEL;        // 确定为地址标号的定义
  305.                 // 如果没有查找到相应地汇编指令并且这个符号后面没有紧跟着":",那么就是地址标号的引用
  306.                 else if (cds == MAXINSTUCTION && words[strlen(words) - 1] != ':')
  307.                         tks = REFLABEL;        //确定为地址标号的引用
  308.                 else
  309.                         tks = ASMCODE;        // 确定为汇编指令
  310.     } else if (isdigit(ch)) {        // 数字的处理:数字开头后跟0~9的有限序列
  311.                 do {
  312.                         cmds[i] = ch;
  313.                         i++;
  314.                         ch = toupper(getc(src));
  315.                 } while (ch >; ' ' && isdigit(ch) && !feof(src));
  316.                 tks = NUM;                //确定为数字
  317.                 cmds[i] = 0;
  318.                 strcpy(words, cmds);
  319.     } else if (ch == ';') {        //单行注释:以';'起始至行尾的任意字符序列
  320.                 do {
  321.                         ch = toupper(getc(src));
  322.                 } while (ch != 0x0a && !feof(src));
  323.                 strcpy(words, "CMNT");
  324.                 opcode = (MC_opcodes) - 99;
  325.                 tks = CMNT;                //识别为注释字符序列
  326.     } else {                        //不可识别的字符的处理
  327.                 cmds[i] = ch;
  328.                 i++;
  329.                 cmds[i] = 0;
  330.                 strcpy(words, cmds);
  331.                 tks = UNKNOWN;                //不可识别的字符
  332.     }

  333.     return tks;                        //返回类别标志
  334. }

  335. /*lookupcmd()
  336.   查询汇编指令表,返回对应的机器指令,机器指令隐含为指令数组的下标
  337. */
  338. MC_bytes AS::lookupcmd(char *cmd, MC * mch)
  339. {
  340.     int i = 0;
  341.     while (i < MAXINSTUCTION && strcmp(mch->;getmns(i), cmd))
  342.                 i++;
  343.     return (MC_bytes) i;
  344. }

  345. /*
  346.   symtablen()
  347.   取得符号表的长度
  348. */
  349. int AS::symtablen()
  350. {
  351.     int i = 0;
  352.     for (i = 0; i < SYMTABLEN && strcmp(symtabhdr[i].symname, "???????"); i++)
  353.                 ;
  354.     return i;
  355. }


复制代码

论坛徽章:
0
26 [报告]
发表于 2005-01-17 18:02 |只看该作者

虚拟机源码分析

公共数据,其它源程序均要包含此文件:misc.h


  1. ////////////////////////////////////////
  2. // 汇编语言虚拟机  MYVM Version 0.11a
  3. // snallie@163.net  2003.2
  4. //
  5. // misc.h
  6. // 公共数据,其它源程序均要包含此文件
  7. ////////////////////////////////////////
  8. #ifndef MISC_H
  9. #define MISC_H

  10. #include <stdio.h>;
  11. #include <stdlib.h>;
  12. #include <string.h>;
  13. #include <stdarg.h>;
  14. #include <ctype.h>;
  15. #include <limits.h>;

  16. #define  boolean  int
  17. #define  bool     int
  18. #define  true     1
  19. #define  false    0
  20. #define  TRUE     1
  21. #define  FALSE    0
  22. #define  maxint   INT_MAX
  23. #define  MAXINSTUCTION  67        //虚拟机支持的最大机器指令数
  24. #define  MEMSIZE  256                //存储器容量
  25. #define  SYMTABLEN 50                //汇编器符号表的最大容量
  26. #define  MAXSYMLEN 32                //符号地址所允许的最大长度
  27. //#define  DEBUG                //for debug purpose

  28. #if __MSDOS__ || MSDOS || WIN32 || __WIN32__
  29. #  define  pathsep '\\'
  30. #else
  31. #  define  pathsep '/'
  32. #endif

  33. static void logo()
  34. {
  35.     printf("\nMYVM Virtual Machine Premiere, Version 0.11a \n");
  36.     printf("\tCopyright under GPL 2002,2003, Snallie@163.net\n\n");
  37. }

  38. static void newsuffix(char *oldstr, char *ext, char *newstr)
  39. // 将oldstr所指源文件名PRIMARY.xxx 更改为PRIMARY.ext存放在newstr

  40. {
  41.     int i;
  42.     char old[256];
  43.     strcpy(old, oldstr);
  44.     i = strlen(old);
  45.     while ((i >; 0) && (old[i - 1] != '.') && (old[i - 1] != pathsep))
  46.         i--;
  47.     if ((i >; 0) && (old[i - 1] == '.'))
  48.         old[i - 1] = 0;
  49.     if (ext[0] == '.')
  50.         sprintf(newstr, "%s%s", old, ext);
  51.     else
  52.         sprintf(newstr, "%s.%s", old, ext);
  53. }

  54. #endif                                /* MISC_H */

复制代码

论坛徽章:
0
27 [报告]
发表于 2005-01-17 18:09 |只看该作者

虚拟机源码分析

相应的makefile文件:

  1. myvm:as.cpp as.h mc.cpp mc.h myvm.cpp misc.h
  2.         g++ as.cpp mc.cpp myvm.cpp -o myvm
复制代码

论坛徽章:
0
28 [报告]
发表于 2005-01-18 08:45 |只看该作者

虚拟机源码分析

道兄牛人也!
我也喜欢学习研究底层的实现原理,感觉好的设计会非常简练、精巧。

论坛徽章:
0
29 [报告]
发表于 2005-01-18 09:46 |只看该作者

虚拟机源码分析

终于放假了,临走之前用自己的机器再播一次号,终于让我看见converse您给我的光明了,哈哈,寒假好好去学习去。。谢谢

论坛徽章:
0
30 [报告]
发表于 2005-01-18 10:29 |只看该作者

虚拟机源码分析

现在谈谈以后如何在虚拟机上进行功能的扩展。由于两个虚拟机的机制大体都是一致的,所以以第二个虚拟机为准来讲述。

   1)扩展虚拟机的指令集
   前面已经看出,虚拟机的指令集是存放在一个enum类型的,相应的enum值作为下标来得到相应的指令助记符和指令的长度,而且指令集也是有长度的,目前是67,但是作者为了今后的扩展之用设置了指令集的最大长度是256,因为在enum类型中设置了MC_bad=256。现在来看看如何加入自己的指令:
   首先,改变misc.h中的宏MAXINSTUCTION为68,原来是67。
   其次,在enum MC_opcodes中在MC_bad = 256之前加入自己新加的指令,假设是MC_myop.
   然后,在MC类的构造函数中循环初始化指令表中加入指令的助记符:mnemonics[MC_myop] = "MYOP",还要在mnxien中指定指令的长度。
   最后,在MC::execute函数中加入处理新指令的case语句:case MC_myop:
   这样,就加入了一个新的指令。

   2)未来可能的扩展
   还可以考虑给这个虚拟机设计一门高级语言的编译机,也就是说把这个虚拟机作为目标机器,设计一个编译器把高级语言
   翻译成为这个虚拟机可以识别的汇编语言,在<<编译原理与实践>;>;一书中作者就是这么做的。

   到此,这份文档就结束了,虚拟机之旅也暂告一个段落,如果我的讲解还有不够明白的地方,大家给点意见,我再进行修改。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP