Advertisement
Guest User

VM

a guest
Dec 25th, 2016
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 8.78 KB | None | 0 0
  1. module VM;
  2.  
  3. import std.stdio;
  4. import std.conv;
  5. import core.checkedint;
  6.  
  7. enum OPERANDS { REG = 1, IDATA = 2, ADDR = 4 };
  8. enum INS { HALT, READC, READB, READH, READW, WRITEC, WRITEB, WRITEH, WRITEW, PUSH, POP, MOV, ADD, SUB, MUL, DIV };
  9.          //0     1      2      3      4      5       6       7       8       9     10   11   12   13   14   15
  10. enum STACK_SIZE = 2^^16;
  11. enum NUM_REGS = 16;
  12.  
  13. struct Flags
  14. {
  15.     bool overflow;
  16.     bool zero;
  17.     bool negative;
  18. }
  19.  
  20. class VM
  21. {
  22.     private:
  23.         int[NUM_REGS] regs;
  24.         ushort code_ptr, data_ptr;
  25.         ushort stack_ptr;
  26.         int[] code_seg;
  27.         int[] data_seg;
  28.         int[STACK_SIZE] stack_seg;
  29.         ushort ins, ins_flags;
  30.         ushort code_size, data_size;
  31.         int addr;
  32.         int *op1;
  33.         int *op2;
  34.         int tmp1, tmp2;
  35.         bool op_switch = true;
  36.         Flags flags;
  37.  
  38.     public this()
  39.     {
  40.         op1 = &tmp1;
  41.         op2 = &tmp2;       
  42.     }
  43.  
  44.     /**
  45.      * Load up the code and data section from the file
  46.      * Params: input is the binary file to run
  47.      */
  48.     public void load(File input)
  49.     {
  50.         code_size = input.rawRead(new ushort[1])[0]; //Grab size of the code segment
  51.         data_size = input.rawRead(new ushort[1])[0]; //Grab size of the data segment
  52.         if(code_size) code_seg = input.rawRead(new int[code_size]);
  53.         if(data_size) data_seg = input.rawRead(new int[data_size]);
  54.         debug(load)
  55.         {
  56.             writeln(this.code_size);
  57.             writeln(this.data_size);
  58.             writeln(code_seg.length);
  59.             writeln(data_seg.length);
  60.         }
  61.     }
  62.    
  63.     /**
  64.      * Runs through the code segment and executes each instruction
  65.      **/
  66.     public void run()
  67.     {
  68.         for(; code_ptr < code_size; ++code_ptr)
  69.         {
  70.             exec_ins(code_seg[code_ptr]);
  71.         }
  72.     }
  73.  
  74.     /**
  75.      * Stops the virtual machine
  76.      **/
  77.     private void halt()
  78.     {
  79.         writeln("HALTING");
  80.         import core.runtime: Runtime;
  81.         import core.stdc.stdlib: exit;
  82.         Runtime.terminate();
  83.         exit(0);   
  84.     }
  85.    
  86.     /**
  87.      * Reads length Ts from stdin to dest
  88.      * Params:
  89.      *      dest holds a pointer to the beginning of memory to be read to
  90.      *      length holds the amount of Ts to be read
  91.      **/
  92.     private void read(T)(int *dest, in ulong length)
  93.     {
  94.         foreach(i; 0..length)
  95.         {
  96.             readf("%s", cast(T *) &dest[i]);
  97.         }
  98.     }
  99.  
  100.     /**
  101.      * Writes length Ts from src to stdout
  102.      * Params:
  103.      *      src holds a pointer to the beginning of memory to be read from
  104.      *      length hold the amount of Ts to write
  105.      **/
  106.     private void write(T)(int *src, in uint length)
  107.     {
  108.         foreach(i; 0..length)
  109.         {
  110.             writef("%s", cast(T) src[i]);
  111.         }
  112.     }
  113.  
  114.     /**
  115.      * Pushes a value onto the stack
  116.      * Params:
  117.      *      op1 holds value to be pushed
  118.      **/
  119.     private void push(in int op1)
  120.     {
  121.         if(stack_ptr == STACK_SIZE)
  122.         {
  123.             throw new Error("Hit upper limit of the stack!");
  124.         }
  125.         stack_seg[stack_ptr] = cast(int) op1;
  126.         debug(push)
  127.         {
  128.             writeln("Pushing: ", stack_seg[stack_ptr]);
  129.         }
  130.         ++stack_ptr;
  131.     }
  132.  
  133.     /**
  134.      * Pops a value off the stack
  135.      * Params:
  136.      *      op1 holds the destination address
  137.      **/
  138.     private void pop(int *op1)
  139.     {
  140.         if(stack_ptr == 0)
  141.         {
  142.             throw new Error("The stack is empty!");
  143.         }
  144.         --stack_ptr;
  145.         debug(pop)
  146.         {
  147.             writeln("Popping: ", stack_seg[stack_ptr]);
  148.         }
  149.         *op1 = stack_seg[stack_ptr];
  150.     }
  151.  
  152.     /**
  153.      * Moves the value in op1 to *op2
  154.      * Params:
  155.      *      op1 holds the value to be moved
  156.      *      *op2 holds where the value is being moved
  157.      **/
  158.     private void mov(in int op1, int *op2)
  159.     {
  160.         debug (move) { writeln("Moving"); }
  161.         *op2 = op1;
  162.     }
  163.  
  164.     /**
  165.      * Adds op1 and *op2
  166.      * Can set overflow, negative or zero flag
  167.      * Params:
  168.      *      op1 is the first value
  169.      *      *op2 holds the second value and where the result gets stored
  170.      **/
  171.     private void add(int op1, int *op2)
  172.     {
  173.         debug(add) { writeln("Adding"); }
  174.         *op2 = adds(op1, *op2, flags.overflow);
  175.         flags.negative = *op2 < 0;
  176.         flags.zero = *op2 == 0;
  177.     }
  178.  
  179.     /**
  180.      * Subtracts op1 from *op2
  181.      * Can set overflow, negative or zero flag
  182.      * Params:
  183.      *      op1 is the first value
  184.      *      *op2 holds the second value and where the result gets stored
  185.      **/
  186.     private void sub(int op1, int *op2)
  187.     {
  188.         debug(sub) { writeln("Subtracting"); }
  189.         *op2 = subs(*op2, op1, flags.overflow);
  190.         flags.negative = *op2 < 0;
  191.         flags.zero = *op2 == 0;
  192.     }
  193.  
  194.     /**
  195.      * Multiplies op1 and *op2
  196.      * Can set overflow, negative or zero flag
  197.      * Params:
  198.      *      op1 is the first value
  199.      *      *op2 is the second value and is where the result gets stored
  200.      **/
  201.     private void mul(int op1, int *op2)
  202.     {
  203.         debug(mul) { writeln("Multiplying"); }
  204.         *op2 = muls(op1, *op2, flags.overflow);
  205.         flags.zero = *op2 == 0;
  206.         flags.negative = *op2 < 0;
  207.     }
  208.  
  209.     /**
  210.      * Divides *op2 by op1
  211.      * Can set negative or zero flag
  212.      * Params:
  213.      *      op1 is the first value
  214.      *      *op2 is the second value and is where the result gets stored
  215.      **/
  216.     private void div(int op1, int *op2)
  217.     {
  218.         debug(div) { writeln("Dividing"); }
  219.         if(op1 == 0)
  220.         {
  221.             stdout.flush();
  222.             throw new Error("Division by zero");
  223.         }
  224.         *op2 = *op2 / op1;
  225.         flags.zero = *op2 == 0;
  226.         flags.negative = *op2 < 0;
  227.     }
  228.  
  229.     /**
  230.      * Executes the given instruction
  231.      * Format in binary is op2 flags, op1 flags, then instruction itself
  232.      * Params:
  233.      *      instr holds the value of the next instruction to execute and its flags
  234.      **/
  235.     public void exec_ins(in uint instr)
  236.     {
  237.         ins_flags = cast(ushort) (instr & 0xFFFF);
  238.         ins = cast(ushort) ((instr >> 16) & 0xFFFF);
  239.  
  240.         void get_ops(ref int *op, in ubyte flags)
  241.         in
  242.         {
  243.             assert(ins >= INS.min && ins <= INS.max, "Invalid instruction");
  244.             assert(flags == OPERANDS.REG || flags == OPERANDS.IDATA || flags == OPERANDS.ADDR, "Invalid flags");
  245.         }
  246.         out
  247.         {
  248.             if(data_seg.length)
  249.             {
  250.                 assert((op1 >= &regs[0] && op1 <= &regs[15]) || (op1 >= &data_seg[0] && op1 <= &data_seg[data_size - 1]) || (op1 == &tmp1), "Fail on op1");
  251.                 assert((op2 >= &regs[0] && op2 <= &regs[15]) || (op2 >= &data_seg[0] && op2 <= &data_seg[data_size - 1]) || (op2 == &tmp2), "Fail on op2");
  252.             }
  253.             else
  254.             {
  255.                 assert((op1 >= &regs[0] && op1 <= &regs[15]) || (op1 == &tmp1), "Fail on op1");
  256.                 assert((op2 >= &regs[0] && op2 <= &regs[15]) || (op2 == &tmp2), "Fail on op2");
  257.             }
  258.         }
  259.         body
  260.         {
  261.             ++code_ptr;
  262.             addr = code_seg[code_ptr];
  263.            
  264.             debug (get_op)
  265.             {
  266.                 writeln("Address: ", addr);
  267.                 writeln("Flags: ", flags);
  268.             }
  269.  
  270.             final switch(flags)
  271.             {
  272.                 case OPERANDS.REG:
  273.                     op = &regs[addr];
  274.                     break;
  275.                 case OPERANDS.IDATA:
  276.                     if(op_switch)
  277.                     {
  278.                         op1 = &tmp1;
  279.                     }
  280.                     else
  281.                     {
  282.                         op2 = &tmp2;
  283.                     }
  284.                     *op = addr;
  285.                     break;
  286.                 case OPERANDS.ADDR:
  287.                     op = &data_seg[addr];
  288.                     break;
  289.             }
  290.  
  291.             op_switch = !op_switch;
  292.  
  293.             debug (get_op)
  294.             {
  295.                 writeln("Operand: ", *op);
  296.             }
  297.         }
  298.  
  299.         debug (ins_flag)
  300.         {
  301.             writeln("Instruction: ", ins);
  302.             writeln("Flags: ", ins_flags);
  303.         }
  304.  
  305.         final switch(ins)
  306.         {
  307.             case INS.HALT:
  308.                 halt();
  309.                 break;
  310.             case INS.READC:
  311.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  312.                 get_ops(op2, ins_flags & 0xFF);
  313.                 read!char(cast(int *) op1, *op2);
  314.                 break;
  315.             case INS.READB:
  316.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  317.                 get_ops(op2, ins_flags & 0xFF);
  318.                 read!byte(cast(int *) op1, *op2);
  319.                 break;
  320.             case INS.READH:
  321.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  322.                 get_ops(op2, ins_flags & 0xFF);
  323.                 read!short(cast(int *) op1, *op2);
  324.                 break;
  325.             case INS.READW:
  326.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  327.                 get_ops(op2, ins_flags & 0xFF);
  328.                 read!int(cast(int *) op1, *op2);
  329.                 break;
  330.             case INS.WRITEC:
  331.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  332.                 get_ops(op2, ins_flags & 0xFF);
  333.                 write!char(cast(int *) op1, *op2);
  334.                 break;
  335.             case INS.WRITEB:
  336.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  337.                 get_ops(op2, ins_flags & 0xFF);
  338.                 write!byte(cast(int *) op1, *op2);
  339.                 break;
  340.             case INS.WRITEH:
  341.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  342.                 get_ops(op2, ins_flags & 0xFF);
  343.                 write!short(cast(int *) op1, *op2);
  344.                 break;
  345.             case INS.WRITEW:
  346.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  347.                 get_ops(op2, ins_flags & 0xFF);
  348.                 write!int(cast(int *) op1, *op2);
  349.                 break;
  350.             case INS.PUSH:
  351.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  352.                 push(*op1);
  353.                 break;
  354.             case INS.POP:
  355.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  356.                 pop(op1);
  357.                 break;
  358.             case INS.MOV:
  359.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  360.                 get_ops(op2, ins_flags & 0xFF);
  361.                 mov(*op1, op2);
  362.                 break;
  363.             case INS.ADD:
  364.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  365.                 get_ops(op2, ins_flags & 0xFF);
  366.                 add(*op1, op2);
  367.                 break;
  368.             case INS.SUB:
  369.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  370.                 get_ops(op2, ins_flags & 0xFF);
  371.                 sub(*op1, op2);
  372.                 break;
  373.             case INS.MUL:
  374.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  375.                 get_ops(op2, ins_flags & 0xFF);
  376.                 mul(*op1, op2);
  377.                 break;
  378.             case INS.DIV:
  379.                 get_ops(op1, (ins_flags >> 8) & 0xFF);
  380.                 get_ops(op2, ins_flags & 0xFF);
  381.                 div(*op1, op2);
  382.                 break;
  383.         }
  384.  
  385.         op_switch = true;
  386.     }
  387. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement