Results 1 to 3 of 3

Thread: Fish VM

  1. #1

    Thread Starter
    Fanatic Member BenJones's Avatar
    Join Date
    Mar 2010
    Location
    Wales UK
    Posts
    629

    Post Fish VM

    hi,
    The last few weeks I been reading about virtual machines and how they work as I always wanted to write my own little language. I have read many books on the subject but never really sat down and tried to do something.

    So I decided the other day and try and make my own little VM one day I hope to build something I can use to make programs, but for now I am just starting off small and see how things process.

    anyway here what I made so far, this VM supports a small instruction set, you can play around with numbers it supports global only variables and that about it. it’s got some examples with this code at the moment they are hardcoded into integer arrays.

    In the next updates I am going to introduce an assembler to convert a more human readable form of language into binary code or also known as byte code Then have the VM execute it.

    anyway I hope you like what I done and hope it will help someone. Comments are more than welcome or if you can think of improvements I can make drop me a line.

    You will need GCC to compile the code, but I think it should also work in Visual Studio since it just basic C code.

    Code:
    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    
    #define MAX_STACK 100
    #define MAX_GLOBAL 1000
    #define MAX_CODE 65536
    
    //Program counter
    int pc = 0;
    //Stack pointer always points to the top of the stack.
    int sp =-1;
    
    int Stack[MAX_STACK] = {0};
    
    int Global[MAX_GLOBAL] = {0};
    
    //Main program vars
    int ProgData[MAX_CODE] = {0};
    int ProgCount = 0;
    
    //Instructions
    enum TOprands{
        NOP = 0,
        IADD = 1,
        ISUB = 2,
        IMUL = 3,
        IDIV = 4,
        IAND = 5,
        IOR = 6,
        IXOR = 7,
        IMOD = 8,
        INC = 9,
        DEC = 10,
        NEG = 11,
        NOT = 12,
        SHL = 13,
        SHR = 14,
        DUP = 15,
        ISGT = 16,
        ISLT = 17,
        ISEQ = 18,
        JMP = 19,
        JT = 20,
        JF = 21,
        ICONST = 22,
        GSTORE = 23,
        GLOAD = 24,
        PRINTI = 25,
        PRINTC = 26,
        HALT = 27
    }Operands;
    
    //Testing programs
    //Add two numbers and show the result
    int testAdd[] = {
        ICONST,20,
        ICONST,5,
        IADD,
        PRINTI,
        HALT
    };
    //Print ABC and make a beep sound
    int testChar[] = {
        ICONST,65,
        PRINTC,
        ICONST,66,
        PRINTC,
        ICONST,67,
        PRINTC,
        ICONST,7,
        PRINTC,
        HALT
    };
    //Test Dup
    int testDup[] = {
        ICONST,50,
        DUP,
        IADD,
        PRINTI,
        HALT
    };
    
    //Test global variables
    int varTest1[] = {
        ICONST,25,
        GSTORE,1,
        ICONST,15,
        GLOAD,1,
        IADD,
        PRINTI,
        HALT
    };
    
    int varTest2[] = {
        //x = 5
        ICONST,20,
        GSTORE,0,
        // y = 0
        ICONST,0,
        GSTORE,1,
        //y = x + 20
        GLOAD,0,
        ICONST,20,
        IADD,
        //y now contains 40
        GSTORE,1,
        GLOAD,1,
        PRINTI,
        HALT
    };
    
    //Jump test
    int jumpTest[] = {
        JMP,6,
        ICONST,10,
        PRINTI,
        HALT,
        ICONST,20,
        //Print newline
        PRINTI,
        ICONST,10,
        PRINTC,
        //Make a beep sound
        ICONST, 7,
        PRINTC,
        JMP,2
    };
    
    int testIfElse[] = {
        //set x to 8
        ICONST,8,
        GSTORE,0,
        //set y to 4
        ICONST,4,
        GSTORE,1,
        //load x and t onto the stack
        GLOAD,0,
        GLOAD,1,
        //test if x > y
        ISGT,
        //jump to label 22 if x > y
        JT,22,
        //Else
        //load y
        GLOAD,1,
        //set z to y
        GSTORE,2,
        //load z onto the stack
        GLOAD,2,
        //print z
        PRINTI,
        HALT,
        //Address 22
        //load x
        GLOAD,0,
        //set z to x
        GSTORE,2,
        //load z onto the stack
        GLOAD,2,
        //print the value of z
        PRINTI,
        HALT
    };
    
    int testINC [] = {
        //Push 10 on the stack
        ICONST,10,
        //Inc stack value by 1
        INC,
        //Print stack value now 11
        PRINTI,
        HALT
    };
    
    int testDEC [] = {
        //Push 10 on the stack
        ICONST,10,
        //Dec stack value by 1
        DEC,
        //Print stack value now 9
        PRINTI,
        HALT
    };
    
    int testNeg [] = {
        ICONST,5,
        NEG,
        DUP,
        PRINTI,
        NEG,
        PRINTI,
        HALT
    };
    
    int testNot [] = {
        ICONST,0,
        NOT,
        PRINTI,
        HALT
    };
    
    int testSHL[] = {
        ICONST,4,
        GSTORE,0,
        GLOAD,0,
        ICONST,4,
        SHL,
        GSTORE,1,
        GLOAD,1,
        PRINTI,
        HALT
    };
    int testSHR[] = {
        //set a = 512
        ICONST,512,
        GSTORE,0,
        //load a
        GLOAD,0,
        //push 8 on the stack
        ICONST,8,
        //Shift right
        SHR,
        //set c = (a >> 8)
        GSTORE,1,
        GLOAD,1,
        PRINTI,
        HALT
    };
    
    int testHello[] = {
        ICONST, 'H',
        PRINTC,
        ICONST, 'e',
        PRINTC,
        ICONST, 'l',
        PRINTC,
        ICONST, 'l',
        PRINTC,
        ICONST, 'o',
        PRINTC,
        HALT
    };
    
    int testSwap[] = {
        //Set a = 100
        ICONST,100,
        GSTORE,0,
        //Set b = 200
        ICONST,200,
        GSTORE,1,
        //swap numbers
        //set t to a
        GLOAD,1,
        GSTORE,2,
        //store a into b
        GLOAD,0,
        GSTORE,1,
        //set a to t
        GLOAD,2,
        GSTORE,0,
        //end swap
        //display value of a
        GLOAD,0,
        PRINTI,
        //This just separates the numbers eg 200:100
        ICONST,':',
        PRINTC,
        //display value of b
        GLOAD,1,
        PRINTI,
        HALT
    };
    
    //End of testing programs
    
    void Push(int v){
        Stack[++sp] = v;
    }
    
    int Pop(){
        return Stack[sp--];
    }
    
    int Peek(){
        return Stack[sp];
    }
    
    void vm_addCode(int code[], int size){
    int x = 0;
        while(x < size){
            ProgData[x] = code[x];
            x++;
        }
        ProgCount = x;
    }
    
    void vm_free(){
        pc = 0;
        sp =-1;
        ProgCount = 0;
        memset(ProgData,0,sizeof ProgData);
        memset(Stack,0,sizeof Stack);
        memset(Global,0,sizeof Global);
    }
    
    int vm_BinaryOp(int op, int a, int b){
        switch(op){
        case IADD:
            return a + b;
        case ISUB:
            return b - a;
        case IMUL:
            return a * b;
        case IDIV:
            return b / a;
        case IAND:
            return a && b;
        case IOR:
            return a || b;
        case IXOR:
            return a ^ b;
        case IMOD:
            return b % a;
        case ISGT:
            return (b > a) ? 1 : 0;
        case ISLT:
            return (b < a) ? 1 : 0;
        case ISEQ:
            return (a == b) ? 1 : 0;
        default:
            return 0;
        }
    }
    
    void vm_execute(){
    int a  = 0;
    int b = 0;
    int addr = 0;
    
        while(pc < ProgCount){
            //Fetch op-codes
            int op = ProgData[pc];
            //Execute the op-codes
            switch(op){
            case JMP:
                //Jump to address
                pc++;
                //Get address from pcode
                addr = ProgData[pc];
                //Set program counter to addr
                pc = addr;
                break;
            case JT:
                //Jump if stack contains 1
                pc++;
                //Get jump address from pcode
                addr = ProgData[pc];
                //Test for true or 1
                if(Pop()){
                    //Jump to the address
                    pc = addr;
                }
                break;
            case JF:
                //Jump if stack contains 0
                pc++;
                //Get jump address from pcode
                addr = ProgData[pc];
                //Test for false or 0
                if(!Pop()){
                    //Jump to the address
                    pc = addr;
                }
                break;
            case ICONST:
                //INC program counter to get next index
                pc++;
                //Push the value on the stack top
                Push(ProgData[pc]);
                break;
            case GSTORE:
                pc++;
                //Get variable address
                addr = ProgData[pc];
                //Store the top of the stack in global[address]
                Global[addr] = Pop();
                break;
            case GLOAD:
                pc++;
                //Get variable address
                addr = ProgData[pc];
                //Push the value from global onto the stack
                Push(Global[addr]);
                break;
            case IADD:
            case ISUB:
            case IMUL:
            case IDIV:
            case IAND:
            case IOR:
            case IXOR:
            case IMOD:
            case ISGT:
            case ISLT:
                //Pop of the two values on top of the stack
                a = Pop();
                b = Pop();
                //Preform the binary op and push back the result on the stack.
                Push(vm_BinaryOp(op,a,b));
                break;
            case INC:
                a = Pop();
                Push(a+1);
                break;
            case DEC:
                a = Pop();
                Push(a-1);
                break;
            case NEG:
                a = Pop();
                Push(-a);
                break;
            case NOT:
                a = Pop();
                Push(!a);
                break;
            case SHL:
                a = Pop();
                b = Pop();
                Push(b << a);
                break;
            case SHR:
                a = Pop();
                b = Pop();
                Push(b >> a);
                break;
            case DUP:
                //Duplicate what is on the stack and push the value on the stack.
                Push(Peek());
                break;
            case PRINTI:
                //Pop of the top of the stack value and display to user.
                printf("%d",Pop());
                break;
            case PRINTC:
                //Same as PRINTI but this converts and prints as a char
                printf("%c",Pop());
                break;
            case HALT:
                //Stop the program
                pc = ProgCount;
                break;
            case NOP:
                //Do nothing
                break;
            default:
                break;
            }
            //INC Program counter
            pc++;
        }
    }
    
    int main()
    {
        //Get the size of the program to execute
        int n = sizeof(testSwap) / sizeof(int);
        //Add test code make sure you also include the size
        vm_addCode(testSwap,n);
    
        vm_execute();
        //Clean up VM
        vm_free();
    
        return 0;
    }
    Last edited by BenJones; Jun 30th, 2020 at 02:24 PM. Reason: Update 30/06/2020

  2. #2

    Thread Starter
    Fanatic Member BenJones's Avatar
    Join Date
    Mar 2010
    Location
    Wales UK
    Posts
    629

    Re: Fish VM

    I have updated my Virtual Machine added some more examples and op-codes you can now do simple logic if's and jumps, I am now currently working on an assembler that I will upload as soon as I have finished it.

  3. #3

    Thread Starter
    Fanatic Member BenJones's Avatar
    Join Date
    Mar 2010
    Location
    Wales UK
    Posts
    629

    Post Re: Fish VM Beta 1.1

    I have updated my Virtual machine to include an assembler I also added a few examples to show how the VM works no more hard coded examples. anyway hope you like the update.

    fish.zip

    To assemble and test the examples use this when in the bin folder

    Code:
    ./build loop.txt loop.fish
    to run the above assembled example on the VM use

    Code:
    ./fish loop.fish
    Next update I will hope to add function calls to the VM and also look at building a compiler frontend so you can compile a more human like high level language.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width