fc349e2cf1/vm/fast-console/vm.c
Commiter: Charles Childers
Author: Charles Childers
Revision: fc349e2cf1
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;
} |