43fd6a76ba/vm/fast-console/vm.c

User picture

Commiter: Charles Childers

Author: Charles Childers

Revision: 43fd6a76ba


File Size: 24 KB

(March 09, 2010 04:05 UTC) About 2 years ago

fix warning in retro-fast build

 

Showing without highlighting since it looks like a big file and may slow your browser - show with highlighting

Show/hide line numbers
/******************************************************
 * Ngaro
 *
 *|F|
 *|F| FILE: vm.c
 *|F|
 *
 * Threading interpreter by Matthias Schirm.
 * Released into the public domain
 ******************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef SOCKETS
/* for sockets */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <netinet/tcp.h>
#include <netdb.h>
#endif

#include "functions.h"
#include "vm.h"

/******************************************************
 * Initialize the VM
 * This will clear the memory and stacks, and set the
 * registers to zero.
 ******************************************************/
void init_vm(VM *vm)
{
   int a;
   vm->ip = 0;
   vm->sp = 0;
   vm->rsp = 0;
   for (a = 0; a < STACK_DEPTH; a++)
      vm->data[a] = 0;
   for (a = 0; a < ADDRESSES; a++)
      vm->address[a] = 0;
   for (a = 0; a < IMAGE_SIZE; a++)
      vm->image[a] = 0;
   for (a = 0; a < 1024; a++)
      vm->ports[a] = 0;
}


/******************************************************
 * Process the entire vm-code image
 ******************************************************/

void vm_process(VM *vm)
{
  /* register cache */

  register int a, b;
  register int acc = 0;

#ifdef SOCKETS
  int sock, port, addrlen, data, c;
  struct sockaddr_in address;
  struct hostent *server;
  char s[65535];
#endif

  /* start interpreter loop */
  NEXT;


    /***************************************************/
    /* NOP    Does Nothing. Used for padding           */
    /* Opcode: 0        Stack:  -       Address: -     */
    /***************************************************/

  fVM_NOP: vm->ip++; NEXT;

    /***************************************************/
    /* LIT    Push the value in the following cell to  */
    /*        the stack                                */
    /* Opcode: 1 n      Stack: -n       Address: -     */
    /***************************************************/

  fVM_LIT: vm->sp++;
           vm->ip++;
           TOS = acc;
           acc = VMOP;
           vm->ip++;
           NEXT;

    /***************************************************/
    /* DUP    Duplicate the value on the top of the    */
    /*        stack                                    */
    /* Opcode: 2        Stack: n-nn     Address: -     */
    /***************************************************/

  fVM_DUP: vm->sp++;
           vm->data[vm->sp] = acc;
           vm->ip++;
           NEXT;

    /***************************************************/
    /* DROP   Drop the value on the top of the stack   */
    /* Opcode: 3        Stack: n-       Address: -     */
    /***************************************************/

  fVM_DROP: acc = vm->data[vm->sp];
            vm->sp--;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* SWAP   Exchange the top two values on the stack */
    /* Opcode: 4        Stack: xy-yx    Address: -     */
    /***************************************************/

  fVM_SWAP: a = TOS;
            TOS = acc;
            acc = a;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* PUSH   Move the top value on the stack to the   */
    /*        address stack. Remove it from the data   */
    /*        stack.                                   */
    /* Opcode: 5        Stack: n-       Address: -n    */
    /***************************************************/

  fVM_PUSH: vm->rsp++;
            TORS = acc;
            acc = vm->data[vm->sp];
            vm->sp--;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* POP    Move the top value from the address      */
    /*        stack to the data stack. Remove it from  */
    /*        the address stack.                       */
    /* Opcode: 6        Stack: -n       Address: n-    */
    /***************************************************/

  fVM_POP: vm->sp++;
           TOS = acc;
           acc = TORS;
           vm->rsp--;
           vm->ip++;
           NEXT;

    /***************************************************/
    /* CALL   Call a subroutine whose address is given */
    /*        in the following cell. Push the address  */
    /*        following this instruction to the address*/
    /*         stack.                                  */
    /* Opcode: 7 a       Stack: -      Address: -a     */
    /***************************************************/

  fVM_CALL: vm->ip++;
            vm->rsp++;
            TORS = (vm->ip);
            vm->ip = vm->image[vm->ip];
            if (vm->ip < 0)
            {
              vm->ip = IMAGE_SIZE;
              return;
            }
            else
            {
              if (vm->image[vm->ip+1] == 0)
                vm->ip++;
              if (vm->image[vm->ip+1] == 0)
                vm->ip++;
            }
            NEXT;

    /***************************************************/
    /* JUMP   Unconditional jump to the address given  */
    /*        in the following cell.                   */
    /* Opcode: 8 a       Stack: -       Address: -     */
    /***************************************************/

  fVM_JUMP: vm->ip++;
            vm->ip = VMOP;
            if (vm->ip < 0)
            {
              vm->ip = IMAGE_SIZE;
              return;
            }
            else
            {
              if (vm->image[vm->ip+1] == 0)
                vm->ip++;
              if (vm->image[vm->ip+1] == 0)
                vm->ip++;
            }
            NEXT;

    /***************************************************/
    /* ;      Return from a subroutine. Control is     */
    /*        passed to the address on the top of the  */
    /*        address stack.                           */
    /* Opcode: 9         Stack: -       Address: a-    */
    /***************************************************/

  fVM_RETURN: vm->ip = (TORS+1);
              vm->rsp--;
              NEXT;

    /***************************************************/
    /* >JUMP  Jump to the address in the following     */
    /*        cell if NOS > TOS.                       */
    /* Opcode: 10 a      Stack: xy-     Address: -     */
    /***************************************************/

  fVM_GT_JUMP: vm->ip++;
               if(TOS > acc)
                 vm->ip = VMOP;
               else vm->ip++;
               vm->sp--;
               acc = vm->data[vm->sp];
               vm->sp--;
               NEXT;

    /***************************************************/
    /* <JUMP  Jump to the address in the following     */
    /*        cell if NOS < TOS.                       */
    /* Opcode: 11 a      Stack: xy-     Address: -     */
    /***************************************************/

   fVM_LT_JUMP: vm->ip++;
                if(TOS < acc)
                  vm->ip = VMOP;
                else vm->ip++;
                vm->sp--;
                acc = vm->data[vm->sp];
                vm->sp--;
                NEXT;

    /***************************************************/
    /* !JUMP  Jump to the address in the following     */
    /*        cell if NOS <> TOS.                      */
    /* Opcode: 12 a      Stack: xy-     Address: -     */
    /***************************************************/

   fVM_NE_JUMP: vm->ip++;
                if(acc != TOS)
                  vm->ip = VMOP;
                else vm->ip++;
                vm->sp--;
                acc = vm->data[vm->sp];
                vm->sp--;
                NEXT;

    /***************************************************/
    /* =JUMP  Jump to the address in the following     */
    /*        cell if NOS = TOS.                       */
    /* Opcode: 13 a      Stack: xy-     Address: -     */
    /***************************************************/

   fVM_EQ_JUMP: vm->ip++;
                if(acc == TOS)
                  vm->ip = VMOP;
                else vm->ip++;
                vm->sp--;
                acc = vm->data[vm->sp];
                vm->sp--;
                NEXT;

    /***************************************************/
    /* @      Fetch a value from a memory location     */
    /* Opcode: 14        Stack: a-n     Address: -     */
    /***************************************************/

   fVM_FETCH: acc = vm->image[acc];
              vm->ip++;
              NEXT;

    /***************************************************/
    /* !      Store a value to a memory location       */
    /* Opcode: 15        Stack: na-     Address: -     */
    /***************************************************/

   fVM_STORE: vm->image[acc] = TOS;
              vm->sp--;
              acc = vm->data[vm->sp];
              vm->sp--;
              vm->ip++;
              NEXT;

    /***************************************************/
    /* +      Add TOS and NOS, leaving the result      */
    /* Opcode: 16        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_ADD: TOS += acc;
            acc = vm->data[vm->sp];
            vm->sp--;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* -      Subtract TOS from NOS, leaving the result*/
    /* Opcode: 17        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_SUB: TOS -= acc;
            acc = vm->data[vm->sp];
            vm->sp--;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* *      Multiply TOS by NOS, leaving the result  */
    /* Opcode: 18        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_MUL: TOS *= acc;
            acc = vm->data[vm->sp];
            vm->sp--;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* /MOD   Divide NOS by TOS, leaving the quotient  */
    /*        and remainder.                           */
    /* Opcode: 19        Stack: xy-qr   Address: -     */
    /***************************************************/

   fVM_DIVMOD: a = acc;
               b = TOS;
               acc = b / a;
               TOS = b % a;
               vm->ip++;
               NEXT;

    /***************************************************/
    /* AND    Perform a bitwise and operation on TOS   */
    /*        and NOS.                                 */
    /* Opcode: 20        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_AND: a = acc;
            b = TOS;
            acc = vm->data[vm->sp];
            vm->sp--;
            acc = a & b;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* OR     Perform a bitwise or operation on TOS    */
    /*        and NOS.                                 */
    /* Opcode: 21        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_OR: a = acc;
           b = TOS;
           acc = vm->data[vm->sp];
           vm->sp--;
           acc = a | b;
           vm->ip++;
           NEXT;

    /***************************************************/
    /* XOR    Perform a bitwise xor operation on TOS   */
    /*        and NOS.                                 */
    /* Opcode: 22        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_XOR: a = acc;
            b = TOS;
            acc = vm->data[vm->sp];
            vm->sp--;
            acc = a ^ b;
            vm->ip++;
            NEXT;


    /***************************************************/
    /* <<    Shift NOS left by TOS bits.               */
    /* Opcode: 23        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_SHL: a = acc;
            b = TOS;
            acc = vm->data[vm->sp];
            vm->sp--;
            acc = b << a;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* >>    Shift NOS right by TOS bits.              */
    /* Opcode: 24        Stack: xy-z    Address: -     */
    /***************************************************/

   fVM_SHR: a = acc;
            b = TOS;
            acc = vm->data[vm->sp];
            vm->sp--;
            acc = b >>= a;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* 0;    Return from a subroutine if TOS = 0.      */
    /*       If TOS = 0, DROP TOS.                     */
    /*       If TOS <> 0, do nothing                   */
    /* Opcode: 25         Stack: n-     Address: a-    */
    /*                    Stack: n-n    Address: -     */
    /***************************************************/

   fVM_ZERO_EXIT: if (acc == 0)
                  {
                    acc = vm->data[vm->sp];
                    vm->sp--;
                    vm->ip = (TORS+1);
                    vm->rsp--;
                  }
                  else vm->ip++;
                  NEXT;

    /***************************************************/
    /* 1+    Increase TOS by 1                         */
    /* Opcode: 26        Stack: x-y     Address: -     */
    /***************************************************/

   fVM_INC: acc += 1;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* 1-    Decrease TOS by 1                         */
    /* Opcode: 27        Stack: x-y     Address: -     */
    /***************************************************/

   fVM_DEC: acc -= 1;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* IN    Read a value from an I/O port             */
    /* Opcode: 28        Stack: p-n     Address: -     */
    /***************************************************/

   fVM_IN: a = acc;
           acc = vm->ports[a];
           vm->ports[a] = 0;
           vm->ip++;
           NEXT;

    /***************************************************/
    /* OUT   Send a value to an I/O port               */
    /* Opcode: 29        Stack: np-     Address: -     */
    /***************************************************/

   fVM_OUT: vm->ports[0] = 0;
            vm->ports[acc] = TOS;
            acc = vm->data[vm->sp];
            vm->sp--;
            acc = vm->data[vm->sp];
            vm->sp--;
            vm->ip++;
            NEXT;

    /***************************************************/
    /* WAIT  Wait for an I/O event to occur.           */
    /* Opcode: 30        Stack: -       Address: -     */
    /***************************************************/

   fVM_WAIT: if (vm->ports[0] == 1)
             {
               vm->ip++;
               NEXT;
             }

             /* Input */
             if (vm->ports[0] == 0 && vm->ports[1] == 1)
             {
               vm->ports[1] = dev_getch();
               vm->ports[0] = 1;
               dev_refresh ();
             }

             /* Output (character generator) */
             if (vm->ports[2] == 1)
             {
               dev_putch(acc);
               acc = vm->data[vm->sp];
               vm->sp--;
               vm->ports[2] = 0;
               vm->ports[0] = 1;
               dev_refresh();
             }

             /* Save Image */
             if (vm->ports[4] == 1)
             {
               vm_save_image(vm, vm->filename);
               vm->ports[4] = 0;
               vm->ports[0] = 1;
             }

             /* Add file to input stack */
             if (vm->ports[4] == 2)
             {
               vm->ports[4] = 0;
               vm->ports[0] = 1;
               char s[1024];
               int name = acc;
               acc = vm->data[vm->sp];
               vm->sp--;
               int i = 0;
               while(vm->image[name] != 0)
               {
                 s[i] = ((char)vm->image[name]);
                 i++; name++;
               }
               s[i] = 0;
               dev_include(s);
             }

          /* Create file handle */
          if (vm->ports[4] == -1) {
            char *modes[] = { "r", "r+", "w", "w+", "a", "a+" };
            int mode = acc; DROP;
            int i, address = acc; DROP;
            char filename[256];
            for (i = 0; i < 256; i++) {
              filename[i] = vm->image[address+i];
              if (! filename[i]) break;
            }
            FILE *handle = fopen(filename, modes[mode]);
            vm->ports[4] = (int)handle;
            vm->ports[0] = 1;
          }

          /* Read a char; response indicates success/failure */
          if (vm->ports[4] == -2) {
            int cell = acc; DROP;
            FILE *handle = (FILE *) acc; DROP;
            int c = fgetc(handle);
            vm->image[cell] = c;
            if   ( c == EOF ) vm->ports[4] =  0;
            else              vm->ports[4] = -1;
            vm->ports[0] = 1;
          }

          /* Write a char; response indicates success/failure */
          if (vm->ports[4] == -3) {
            FILE *handle = (FILE *) acc; DROP;
            int c = acc; DROP;
            int r = fputc(c, handle);
            if   ( r == EOF ) vm->ports[4] =  0;
            else              vm->ports[4] = -1;
            vm->ports[0] = 1;
          }

          /* Close handle */
          if (vm->ports[4] == -4) {
            FILE *handle = (FILE *)acc; DROP;
            fclose(handle);
            vm->ports[4] = 1;
            vm->ports[0] = 1;
          }

          /* Getpos */
          if (vm->ports[4] == -5) {
            FILE *handle = (FILE *)acc; DROP;
            int pos = (int) ftell(handle);
            vm->ports[4] = pos;
            vm->ports[0] = 1;
          }

          /* Seek */
          if (vm->ports[4] == -6) {
            FILE *handle = (FILE *) acc; DROP;
            int pos = acc; DROP;
            int r = fseek(handle, pos, SEEK_SET);
            if   ( r == 0 ) vm->ports[4] = -1;
            else            vm->ports[4] =  0;
            vm->ports[0] = 1;
          }

          /* File size */
          if (vm->ports[4] == -7) {
            FILE *handle = (FILE *) acc; DROP;
            int current = ftell(handle);
            int r = fseek(handle, 0, SEEK_END);
            int size = ftell(handle);
            fseek(handle, current, SEEK_SET);
            if   ( r == 0 ) vm->ports[4] = size;
            else            vm->ports[4] = 0;
            vm->ports[0] = 1;
          }


             /* Capabilities */
             if (vm->ports[5] == -1)
             {
               vm->ports[5] = IMAGE_SIZE;
               vm->ports[0] = 1;
             }

             /* The framebuffer related bits aren't supported, so return 0 for them. */
             if (vm->ports[5] == -2 || vm->ports[5] == -3 || vm->ports[5] == -4)
             {
               vm->ports[5] = 0;
               vm->ports[0] = 1;
             }

             /* Data & Return Stack Depth */
             if (vm->ports[5] == -5)
             {
               vm->ports[5] = vm->sp;
               vm->ports[0] = 1;
             }
             if (vm->ports[5] == -6)
             {
               vm->ports[5] = vm->rsp;
               vm->ports[0] = 1;
             }
             if (vm->ports[5] == -7)
             {
               vm->ports[5] = 0;
               vm->ports[0] = 1;
             }
             if (vm->ports[5] == -8)
             {
               vm->ports[5] = time(NULL);
               vm->ports[0] = 1;
             }
             if (vm->ports[5] == -9)
             {
               vm->ip = IMAGE_SIZE;
               vm->ports[5] = 0;
               vm->ports[0] = 1;
               return;
             }

#ifdef SOCKETS
         if (vm->ports[8] != 0)
         {
           switch (vm->ports[8])
           {
             case -1: sock = socket(AF_INET, SOCK_STREAM, 0);
                      vm->sp++;
                      acc = sock;
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -2: port = acc; DROP;
                      sock = acc;
                      address.sin_family = AF_INET;
                      address.sin_addr.s_addr = INADDR_ANY;
                      address.sin_port = htons(port);
                      acc = bind(sock,(struct sockaddr *)&address,sizeof(address));
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -3: acc = listen(acc, 3);
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -4: sock = acc;
                      addrlen = sizeof(struct sockaddr_in);
                      acc = accept(sock, (struct sockaddr *)&address, (socklen_t *)&addrlen);
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -5: acc = close(acc);
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -6: sock = acc; DROP;
                      data = acc;
                      for (c = 0; c < 65535; c++)
                        s[c] = '\0';
                      for (c = 0; vm->image[data] != 0; c++, data++)
                        s[c] = (char)vm->image[data];
                      acc = send(sock, s, strlen(s), 0);
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -7: sock = acc;
                      s[0] = '\0';
                      recv(sock, s, 1, 0);
                      acc = (int)s[0];
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             case -8: sock = acc; DROP;
                      port = acc; DROP;
                      data = acc;
                      addrlen = sizeof(struct sockaddr_in);
                      for (c = 0; c < 1024; c++)
                        s[c] = '\0';
                      for (c = 0; vm->image[data] != 0; c++, data++)
                        s[c] = (char)vm->image[data];
                      server = gethostbyname(s);
                      bzero((char *) &address, sizeof(address));
                      address.sin_family = AF_INET;
                      bcopy((char *)server->h_addr, (char *)&address.sin_addr.s_addr, server->h_length);
                      address.sin_port = htons(port);
                      acc = connect(sock, (struct sockaddr *)&address, (socklen_t)addrlen);
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
                      break;
             default:
                      vm->ports[8] = 0;
                      vm->ports[0] = 1;
           }
         }
#endif

             vm->ip++;
             NEXT;

    /* IMPLICIT CALL                                   */
    /* If we don't recognize the opcode, treat it as a */
    /* subroutine address and CALL it.                 */
    /* Opcode: * a       Stack: -      Address: -a     */
   fVM_DEFAULT:
            vm->rsp++;
            TORS = (vm->ip);
            vm->ip = vm->image[vm->ip];
            if (vm->ip < 0)
            {
              vm->ip = IMAGE_SIZE;
              return;
            }
            else
            {
              if (vm->image[vm->ip+1] == 0)
                vm->ip++;
              if (vm->image[vm->ip+1] == 0)
                vm->ip++;
            }
            NEXT;
}