仮想マシン

仮想マシン(Virtual Machine)
独自に設計した仮想マシンVM)
機械語の命令セットを定義し、そのアセンブラ
flex, bisonで実装。
また仮想マシン自体はC言語で実装。
VMの状態をリアルタイムで観察できるようにXでの表示を行った。

上記のようにベースのVMC言語で実装したが、そのVM上で
動作する仮想マシンを上記のアセンブラ言語で実装した。
仮想マシン上で動作する仮想マシンを設け、プログラムを実行出来るようにした。
更にその上で動作する仮想マシンを動作させ...5世代まで仮想マシンを動作させてみた。

世代を経るに連れ段々と実行が遅くなってくるのが面白かった。
最近は動かしていないが、昔のPC上でXでVM内部の状態表示させながらだとかなり遅かった。



仮想マシン(C言語版)関連

仮想マシン機械語を定義する。簡単に実装するために
スタック型のCPUとした。基本命令数は15個。
ファイルのロードや標準入出力など面倒なので高水準命令を
追加で5つ定義している。


instructions.h

/*
 *	instructions.h
 */


#define	CODE_NOP	0
#define	CODE_PUSH	1
#define	CODE_POP	2
#define	CODE_PUSHI	3
#define	CODE_POPI	4
#define	CODE_REMOVE	5
#define	CODE_ADD	6
#define	CODE_SUB	7
#define	CODE_SFTR	8
#define	CODE_SFTL	9
#define	CODE_JUMP	10
#define	CODE_JLT	11
#define	CODE_JEQ	12
#define	CODE_JGT	13
#define	CODE_HALT	14

/* HIGH LEVEL INSTRUCTIONS */

#define	CODE_LOAD	15

/* DEBUGGING INSTRUCTIONS */

#define	CODE_OUT	16
#define	CODE_DUMP	17
#define	CODE_PRINT	18
#define	CODE_BRK	19





/*

--------------------------------------------------------

code data type definition

        +-----------------------------------+
        | opcode |        |     operand     |
        +-----------------------------------+

--------------------------------------------------------
load file data format

        +---------------+ -
        |               | |
        | codes         | |
        |               | | data
        |               | |
        |               | |
        +---------------+ -



--------------------------------------------------------
Description of each instructions

[NOP]	no operation. just increment PC

	NOP


[PUSH]	push data

	PUSH	data

	SP++
	MEM[SP] = data


[POP]	pop data

	POP	data

	data = MEM[SP]
	SP--;

[PUSHI]	push data with index

	PUSHI

	MEM[SP] = data[MEM[SP]]

[POPI]	pop data with index

	POPI

	data[MEM[SP-1]] = MEM[SP]
	SP--
	SP--

[REMOVE] remove stack

	REMOVE

	SP--

[ADD]	add two data in stack

	ADD

	MEM[SP-1] = MEM[SP-1] + MEM[SP]
	SP--;


[SUB]	sub two data in stack

	SUB

	MEM[SP-1] = MEM[SP-1] - MEM[SP]
	SP--;

[SFTR]	shift right

	SFTR	offset

	MEM[SP] = MEM[SP] >> offset

[SFTL]	shift left

	SFTL	offset

	MEM[SP] = MEM[SP] << offset

[JUMP]	change PC

	JUMP	location

	PC = location

[JLT]	jump if less than

	JLT	location

	if(MEM[SP-1] < MEM[SP])
		PC location
	SP = SP-2;

[JEQ]	jump if equal

	JEQ	location

	if(MEM[SP-1] == MEM[SP])
		PC location
	SP = SP-2;

[JGT]	jump if greater than

	JGT	location

	if(MEM[SP-1] > MEM[SP])
		PC location
	SP = SP-2;


[HALT]	halt VM

	HALT

[LOAD]	load file

	LOAD

	load file


[OUT]	print top stack value

	OUT

	print(MEM[SP])


[DUMP]	print memory

	DUMP	data

	for(i=0;i<8;i++)
		print(data[i])

[PRINT] print string

	PRINT

[BRK]	break

	BRK

	break the execution

*/

VMの共通定義のヘッダ
vm.h

/*
 *	vm.h
 */


#define MEM_LENGTH	4096

C言語によるVMの本体
vm.c

/*
 *	vm.c
 */

#include <stdio.h>
#include "vm.h"
#include "instructions.h"	/* instruction set definition */
#include "vminspect.h"		/* inspector with X */ 


int swap(int src);
static void strExtract(int offset, char *str);
static char opCode(int pc);
static short opRand(int pc);
static void out(int data);
static void initEnv(void);
static void load(char *file_name, int offset);
static void vm(void);
static void memorydump(void);


/*
 * Trace flag
 */
int d_trace_on = 0;
int d_step_on = 1;
int d_step_interval = 10000; /* 10msec. */

int d_instruction_count = 0;

/*
 * register in CPU
 */
int	pc;
int	fp;
int	sp;

/*
 * memory
 */
int *mem;
int memory[MEM_LENGTH];


#define	CHECK_AREA(a)	if((a < 0) || (MEM_LENGTH < a)){ printf("OUT OF RANGE %d\n", a); return; }


/*
 * string buffer
 */
char string[128];


/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
char *load_file;

	load_file = *(++argv);

	initEnv();

	load(load_file, 0);

	vm();
#if 0
	printf("Total instruction number is %d\n", d_instruction_count);
#endif
}

/*----------------------------------------------------------*/
void initEnv(void)
{
int i;

	mem = memory;
	for(i=0;i<MEM_LENGTH;i++) mem[i] = 0;

	pc = 0;
	fp = 0;
	sp = MEM_LENGTH;

	initVmInspect();
}


/*----------------------------------------------------------*/
void vm(void)
{
short offset;
char c;

	for(;;){

		d_instruction_count++;

		getEvent();

		CHECK_AREA(pc)

		c = opCode(pc);
		switch(c){
		case CODE_NOP:
			if(d_trace_on) printf("%4d: NOP\n", pc);
			pc++;
			break;

		case CODE_PUSH:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: PUSH %d\n", pc, offset);
			CHECK_AREA(sp-1)
			CHECK_AREA(fp+offset)

			sp--;
			mem[sp] = mem[fp+offset];
			pc++;
			break;

		case CODE_POP:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: POP %d\n", pc, offset);
			CHECK_AREA(sp)
			CHECK_AREA(fp+offset)

			mem[fp+offset] = mem[sp];
			sp++;
			pc++;
			break;

		case CODE_PUSHI:
			if(d_trace_on) printf("%4d: PUSHI\n", pc);
			CHECK_AREA(sp)
			CHECK_AREA(fp+swap(mem[sp]))

			mem[sp] = mem[fp+swap(mem[sp])];
			pc++;
			break;

		case CODE_POPI:
			if(d_trace_on) printf("%4d: POPI\n", pc);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)
			CHECK_AREA(fp+swap(mem[sp+1]))

			mem[fp+swap(mem[sp+1])] = mem[sp];
			sp++;
			sp++;
			pc++;
			break;

		case CODE_REMOVE:
			if(d_trace_on) printf("%4d: REMOVE\n", pc);

			sp++;
			pc++;
			break;

		case CODE_ADD:
			if(d_trace_on) printf("%4d: ADD\n", pc);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)

			mem[sp+1] = swap(swap(mem[sp+1]) + swap(mem[sp]));
			sp++;
			pc++;
			break;

		case CODE_SUB:
			if(d_trace_on) printf("%4d: SUB\n", pc);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)

			mem[sp+1] = swap(swap(mem[sp+1]) - swap(mem[sp]));
			sp++;
			pc++;
			break;

		case CODE_SFTR:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: SFTR %d\n", pc, offset);
			CHECK_AREA(sp)
			CHECK_AREA(fp+offset)

			mem[sp] = swap(swap(mem[sp]) >> swap(mem[fp+offset]));
			pc++;
			break;

		case CODE_SFTL:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: SFTR %d\n", pc, offset);
			CHECK_AREA(sp)
			CHECK_AREA(fp+offset)

			mem[sp] = swap(swap(mem[sp]) << swap(mem[fp+offset]));
			pc++;
			break;

		case CODE_JUMP:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: JUMP %d\n", pc, offset);

			pc = fp + offset;
			break;

		case CODE_JLT:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: JLT %d\n", pc, offset);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)

			if(swap(mem[sp+1]) < swap(mem[sp]))	pc = fp + offset;
			else					pc++;
			sp += 2;
			break;

		case CODE_JEQ:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: JEQ %d\n", pc, offset);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)

			if(swap(mem[sp+1]) == swap(mem[sp]))	pc = fp + offset;
			else					pc++;
			sp += 2;
			break;

		case CODE_JGT:
			offset = opRand(pc);
			if(d_trace_on) printf("%4d: JGT %d\n", pc,  offset);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)

			if(swap(mem[sp+1]) > swap(mem[sp]))	pc = fp + offset;
			else					pc++;
			sp += 2;
			break;

		case CODE_HALT:
			if(d_trace_on) printf("%4d: HALT\n", pc);
			return;


/* HIGH LEVEL INSTRUCTIONS */

		case CODE_LOAD:
			if(d_trace_on) printf("%4d: LOAD %d\n", pc,  offset);
			CHECK_AREA(sp)
			CHECK_AREA(sp+1)

			strExtract(fp+swap(mem[sp]), string);

			load(string, fp+swap(mem[sp+1]));
			sp++;
			sp++;
			pc++;
			break;


/* DEBUGGING INSTRUCTIONS */

		case CODE_OUT:
			CHECK_AREA(sp)

			out(mem[sp]);
			pc++;
			break;

		case CODE_DUMP:
			memorydump();
			pc++;
			break;

		case CODE_PRINT:
			CHECK_AREA(sp)

			strExtract(fp+swap(mem[sp]), string);
			printf("%s\n", string);
			sp++;
			pc++;
			break;

		case CODE_BRK:
			d_step_on = 1;
			pc++;
			break;

		default:
			printf("Undefined instruction\n");
			break;
		}
	}
}





/*----------------------------------------------------------*/
int swap(int src)
{
int dst;

	((char *)(&dst))[0]	= ((char *)(&src))[3];
	((char *)(&dst))[1]	= ((char *)(&src))[2];
	((char *)(&dst))[2]	= ((char *)(&src))[1];
	((char *)(&dst))[3]	= ((char *)(&src))[0];
	return dst;
}

/*----------------------------------------------------------*/
char opCode(int pc)
{
char c;

	c = ((char *)(&(mem[pc])))[0];
	return c;
}

/*----------------------------------------------------------*/
short opRand(int pc)
{
short d;

	((char *)(&d))[1] = ((char *)(&(mem[pc])))[2];
	((char *)(&d))[0] = ((char *)(&(mem[pc])))[3];
	return d;
}


/*----------------------------------------------------------*/
void load(char *file_name, int offset)
{
FILE	*file;
int	d;
int	i;
char	data[4];

	file = fopen(file_name, "r");
	if(file == NULL){
		fprintf(stderr, "Source file cannot be opened\n");
		exit(-1);
	}

	for(i=0;;i++){
		d = getc(file); if(EOF == d)	break;	data[0] = (char)d;
		d = getc(file); if(EOF == d)	break;	data[1] = (char)d;
		d = getc(file); if(EOF == d)	break;	data[2] = (char)d;
		d = getc(file); if(EOF == d)	break;	data[3] = (char)d;

		CHECK_AREA(offset+i)
		mem[offset+i] = *((int *)data);
	}

	printf("load %s at %d - %d\n", file_name, offset, offset+i);

	fclose(file);
}


/*----------------------------------------------------------*/
static void strExtract(int offset, char *str)
{
int	i;

	for(i=0; i<32; i++){
		CHECK_AREA(offset+i)
		if(swap(mem[offset+i]) == 0) break; 
		str[i] = (char)swap(mem[offset+i]);
	}
	str[i] = '\0';
}


/*----------------------------------------------------------*/
void out(int data)
{
	printf("OUT : %d\n", swap(data));
}


/*----------------------------------------------------------*/
static void memorydump(void)
{
int	address = 0;
int	d;
char	data[17];
int	i, ptr;

	data[16] = 0; /* for string terminator */

	ptr = 0;
	for(;;){

		printf("%05X :", address); /* offset display */

		for(i=0;i<16;i++){

			data[i] = ((char *)mem)[ptr];

			if(i % 4 == 0){
				printf(" ");
			}
			printf("%02X", (unsigned char)data[i]);

			/* eliminate undisplayable character */
			if((data[i] < 0x20) || (0x7E < data[i])){
				data[i] = '.';
			}
			ptr++;
			if(ptr >= MEM_LENGTH*4) break;
		}

		printf(" :  %s", data);

		printf("\n");

		address += 16;
		if(ptr >= MEM_LENGTH*4) break;
	}

}

X表示部分のヘッダ
vminspect.h

/*
 *	vminspect.h
 */


void initVmInspect(void);
int getEvent(void);


enum{
	EVT_QUIT,
	EVT_NOP
};

X表示処理部
vminspect.c

/*
 *	vminspect.c
 */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <stdio.h>
#include "vm.h"
#include "vminspect.h"

#define	VMINSPECT	0

Display	*display;
int	screen;
Window	window;
GC	gc;

XEvent	event;

extern int pc;
extern int fp;
extern int sp;
extern int mem[];
extern int swap(int src);

extern int d_step_on;
extern int d_trace_on;
extern int d_step_interval;

#define	CANVAS_WIDTH	240
#define	CANVAS_HEIGHT	260


#define	FIELD_WIDTH	60
#define	FIELD_HEIGHT	20

#define X_REG		50
#define Y_REG		120

#define	FIELD_MARGIN	5

#define	X_STACK		150
#define	Y_STACK		40

#define	X_PC_STRING	25
#define	Y_PC_STRING	55

#define	STRING_MARGIN	25

#define	X_SOFFSET	5
#define	Y_SOFFSET	15

#define	STACK_NUM	8

int	r_loc[3][4]	= {
				{ X_REG, Y_REG+(FIELD_HEIGHT+FIELD_MARGIN)*0, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_REG, Y_REG+(FIELD_HEIGHT+FIELD_MARGIN)*1, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_REG, Y_REG+(FIELD_HEIGHT+FIELD_MARGIN)*2, FIELD_WIDTH, FIELD_HEIGHT}
			  };

int	s_loc[STACK_NUM+1][4]	= {
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*0, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*1, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*2, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*3, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*4, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*5, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*6, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*7, FIELD_WIDTH, FIELD_HEIGHT},
				{ X_STACK, Y_STACK+(FIELD_HEIGHT+FIELD_MARGIN)*8, FIELD_WIDTH, FIELD_HEIGHT}
			  };



static void drawFrame(void);
static void drawPC(int value);
static void drawFP(int value);
static void drawSP(int value);
static void drawStack(int point, int value);
static void drawValue(int rect[], int value);
static void drawStackPoint(int point);


void initVmInspect(void)
{
#if VMINSPECT

char *display_name = ":0";

	display = XOpenDisplay(display_name);
	screen = DefaultScreen(display);
	window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
					2, BlackPixel(display, screen), WhitePixel(display, screen));
	XSelectInput(display, window, ExposureMask | KeyPressMask);
	XStoreName(display, window, "vm");
	XMapRaised(display, window);
	gc = XCreateGC(display, window, 0, NULL);
	XSetForeground(display, gc, BlackPixel(display, screen));

	XNextEvent(display, &event);

	drawFrame();

	while(1){
		char buf[10];

		XNextEvent(display, &event);
		switch(event.type){
		case KeyPress:
			if(XLookupString(&event.xkey, buf, sizeof(buf), NULL, NULL)){
				switch(buf[0]){
				case 's':
					d_step_on = 1;
					return;
				case 'g':
					d_step_on = 0;
					return;
				case 'q':
					exit(0);
				}
			}
		}
	}
#endif
}


static void drawFrame(void)
{
int i;

	for(i=0;i<3;i++)
		XDrawRectangle(display, window, gc, r_loc[i][0], r_loc[i][1], r_loc[i][2], r_loc[i][3]); 

	for(i=0;i<8;i++)
		XDrawRectangle(display, window, gc, s_loc[i][0], s_loc[i][1], s_loc[i][2], s_loc[i][3]); 

	XDrawString(display, window, gc, r_loc[0][0]-25, r_loc[0][1]+15, "pc", 2);
	XDrawString(display, window, gc, r_loc[1][0]-25, r_loc[1][1]+15, "fp", 2);
	XDrawString(display, window, gc, r_loc[2][0]-25, r_loc[2][1]+15, "sp", 2);

	XDrawString(display, window, gc, s_loc[0][0], s_loc[0][1]-5, "stack", 5);

	for(i=0;i<STACK_NUM;i++){
		char buf[8];
		int len;

		sprintf(buf, "%d", MEM_LENGTH - STACK_NUM + i);
		len = strlen(buf);

		XDrawString(display, window, gc, s_loc[i][0]-28, s_loc[i][1]+15, buf, len);
	}
}


static void drawValue(int rect[], int value)
{
char buf[8];
int len;

	XSetForeground(display, gc, WhitePixel(display, screen));
	XFillRectangle(display, window, gc,  rect[0]+1, rect[1]+1, rect[2]-2, rect[3]-2);
	XFlush(display);

#if 0
	sprintf(buf, "%d", value);
#else
	sprintf(buf, "%08x", value);
#endif
	len = strlen(buf);
	XSetForeground(display, gc, BlackPixel(display, screen));

	XDrawString(display, window, gc, rect[0]+X_SOFFSET, rect[1]+Y_SOFFSET, buf, len);

	XFlush(display);
}


static void drawPC(int value) { drawValue(r_loc[0], value); }
static void drawFP(int value) { drawValue(r_loc[1], value); }
static void drawSP(int value) { drawValue(r_loc[2], value); }

static void drawStack(int point, int value)
{
int i;

	i = point - (MEM_LENGTH - STACK_NUM);
	drawValue(s_loc[i], value);
}

static void drawStackPoint(int point)
{
static int prevSP = MEM_LENGTH;
int i;
int x, y;


	i = prevSP - (MEM_LENGTH - STACK_NUM);
	XSetForeground(display, gc, WhitePixel(display, screen));
	XFillRectangle(display, window, gc, s_loc[i][0] + s_loc[i][2] + 10, s_loc[i][1] + 10, 5, 5);
	XFlush(display);

	if((point < (MEM_LENGTH - STACK_NUM)) || (point > MEM_LENGTH)){
		return;
	}

	i = point - (MEM_LENGTH - STACK_NUM);

	XSetForeground(display, gc, BlackPixel(display, screen));
	XFillRectangle(display, window, gc, s_loc[i][0] + s_loc[i][2] + 10, s_loc[i][1] + 10, 5, 5);
	XFlush(display);

	prevSP = point;
}

int getEvent(void)
{
#if VMINSPECT

char buf[10];
int ret;
int i;

	drawPC(pc);
	drawFP(fp);
	drawSP(sp);

	for(i=MEM_LENGTH - STACK_NUM;i<MEM_LENGTH;i++){
		drawStack(i, swap(mem[i]));
	}
	drawStackPoint(sp);

	while(1){
		if(d_step_on == 1){
			XNextEvent(display, &event);
		}
		else {
#if 0
			usleep(d_step_interval);
#endif
			XCheckTypedEvent(display, KeyPress, &event);
		}
	
		switch(event.type){
		case KeyPress:
			if(XLookupString(&event.xkey, buf, sizeof(buf), NULL, NULL)){
				switch(buf[0]){
				case 'q':
					ret = EVT_QUIT;
					exit(0);
				case 's':
					d_step_on = 1;
					return;
				case 'g':
					d_step_on = 0;
					return;
				case 't':
					d_trace_on = (d_trace_on == 0) ? 1 : 0;
					break;
				}
			}
		}
	}
#endif
}

makefile
Xを利用するためImakefileとする。

Imakefile

#
# $ xmkmf
#

OBJS=vm.o vminspect.o
SYS_LIBRARIES=$(XLIB)
ComplexProgramTarget(vm)




仮想マシンアセンブラ関連
このアセンブラを生成するとasmというアセンブラ実行ファイルが出来る。
後述のマシン語のプログラム(ex. test.m)をアセンブルするには
$ asm test.m
と打つ。すると、test.oという仮想マシン上の実行ファイルが出来る。


仮想マシンアセンブラ用のlex定義ファイル

asm.l

/*
 *	asm.l
 */

%{

#include "y.tab.h"
#include "asmutil.h"

char *StrScan(void);
int SkipComment(void);

%}

%option noyywrap

ws		[ \t]
symbol		[-:\n]
digit		[0-9]
letter		[a-zA-Z_]
id		{letter}({letter}|{digit})*
string		\"([^\"\\\n]|\\.)*\"
other		.

%%

{ws}+
{symbol}	{ return yytext[0]; }

"NOP"		{ return NOP; }
"PUSH"		{ return PUSH; }		 
"POP"		{ return POP; }		 
"PUSHI"		{ return PUSHI; }		 
"POPI"		{ return POPI; }		 
"REMOVE"	{ return REMOVE; }		 
"ADD"		{ return ADD; }		 
"SUB"		{ return SUB; }		 
"SFTR"		{ return SFTR; }		 
"SFTL"		{ return SFTL; }		 
"JUMP"		{ return JUMP; }		 
"JLT"		{ return JLT; }		 
"JEQ"		{ return JEQ; }		 
"JGT"		{ return JGT; }		 
"HALT"		{ return HALT; }		 

"LOAD"		{ return LOAD; }
"OUT"		{ return OUT; }		 
"DUMP"		{ return DUMP; }		 
"PRINT"		{ return PRINT; }
"BRK"		{ return BRK; }		 

"DW"		{ return DW; }		 
"DA"		{ return DA; }		 
"DS"		{ return DS; }

{digit}+	{ sscanf(yytext, "%d", &yylval.Int); return NUM; }
{id}		{ yylval.Char = IDentry(yytext, yyleng); return ID; }
{string}	{ yylval.Char = StrScan(); return STR; }
";"		{ if(SkipComment() == EOF) return EOF; }
{other}		{ fprintf(stderr, "Illegal char '%c' ignoredat line %d\n", yytext[0], yylineno); }

%%

/*
 * string scan
 */
char *StrScan(void)
{
char *p, *q;

	if(yytext[yyleng-1] != '\"')
		yyerror("Unterminated string literal");
	for(p = yytext+1, q = yytext; p < yytext+(yyleng-1); *(q++) = *(p++)){
		if(*p == '\\'){
			if(*(++p) == 'n')	*p = '\n';
			else if(*(++p) == 't')	*p = '\t';
		}
	}
	*q = '\0';
	yyleng = q - yytext;
	return yytext;
}


/*
 * skip comment
 */
int SkipComment(void)
{
int c;

	while(1){
		c = input();

		if(c == '\n'){
			unput(c);
			return 1;
		}
		if(c == EOF){
			unput(c);
			return EOF;
		}
	}
}

仮想マシンアセンブラ用のyacc定義ファイル

asm.y

/*
 * asm.y
 */

%{

#include <stdio.h>
#include "asmutil.h"

#define	YYDEBUG	0


/*
 * source/destination file name
 */
extern	char	srcFile[];
extern	char	dstFile[];

void setData(int pc_address, int setdata);
void setCode(int pc_address, char opcode, short oprand);
void getCode(int pc_address, char *opcode, short *oprand);

/*
 * Input & Output Stream
 */
extern FILE *yyin;
extern FILE *yyout;

#include "instructions.h"

#define NUM_OBJ	10240
static unsigned long *obj;

int pc;

%}

%union {
	int	Int;
	char	*Char;
}

%token	NOP
%token	PUSH
%token	POP
%token	PUSHI
%token	POPI
%token	REMOVE
%token	ADD
%token	SUB
%token	SFTR
%token	SFTL
%token	JUMP
%token	JLT
%token	JEQ
%token	JGT
%token	HALT

%token	LOAD

%token	OUT
%token	DUMP
%token	PRINT
%token	BRK

%token	DW
%token	DA
%token	DS

%token	<Int> NUM
%token	<Char> ID STR

%right	NEG

%type	<Int> num

%%

program		: codes
		;

codes		:
		| codes label code '\n'
		;

code		:
		| NOP			{ setCode(pc, CODE_NOP, 0);  pc++; }
		| PUSH ID		{ registerReference(CODE_PUSH, $2); pc++; }
		| POP ID		{ registerReference(CODE_POP, $2); pc++; }
		| PUSHI			{ setCode(pc, CODE_PUSHI, 0);  pc++; }
		| POPI			{ setCode(pc, CODE_POPI, 0);  pc++; }
		| REMOVE		{ setCode(pc, CODE_REMOVE, 0);  pc++; }
		| ADD			{ setCode(pc, CODE_ADD, 0);  pc++; }
		| SUB			{ setCode(pc, CODE_SUB, 0);  pc++; }
		| SFTR ID		{ registerReference(CODE_SFTR, $2);  pc++; }
		| SFTL ID		{ registerReference(CODE_SFTL, $2);  pc++; }
		| JUMP ID		{ registerReference(CODE_JUMP, $2); pc++; }
		| JLT ID		{ registerReference(CODE_JLT, $2); pc++; }
		| JEQ ID		{ registerReference(CODE_JEQ, $2); pc++; }
		| JGT ID		{ registerReference(CODE_JGT, $2); pc++; }
		| HALT			{ setCode(pc, CODE_HALT, 0); pc++; }
		| LOAD			{ setCode(pc, CODE_LOAD, 0);  pc++; }
		| OUT			{ setCode(pc, CODE_OUT, 0); pc++; }
		| DUMP			{ setCode(pc, CODE_DUMP, 0); pc++; }
		| PRINT			{ setCode(pc, CODE_PRINT, 0);  pc++; }
		| BRK			{ setCode(pc, CODE_BRK, 0); pc++; }
		| DW num		{ setData(pc, $2); pc++;  }
		| DW ID			{ registerReference(0, $2); pc++; }
		| DA num		{ int i; for(i=0;i<$2;i++){ setData(pc, 0); pc++; } }
		| DS STR		{ char *p;

						for(p=$2; *p != '\0'; p++){
							setData(pc, (int)(*p));
							pc++;
						}
						setData(pc, 0);
						pc++;
					}
		;

num		: NUM			{ $$ = $1; }
		| '-' NUM %prec NEG	{ $$ = -$2; }
		;

label		:
		| ID ':'		{ registerSymbol($1); }
		;

%%



/************************************************************
 * Output File Utility
 ************************************************************/


/*----------------------------------------------------------*/
void setData(int pc_address, int setdata)
{
unsigned long	data;

	((char *)(&data))[0]	= ((char *)(&setdata))[3];
	((char *)(&data))[1]	= ((char *)(&setdata))[2];
	((char *)(&data))[2]	= ((char *)(&setdata))[1];
	((char *)(&data))[3]	= ((char *)(&setdata))[0];

	obj[pc_address] = data;
}

/*----------------------------------------------------------*/
void setCode(int pc_address, char opcode, short oprand)
{
unsigned long	data;

	((char *)(&data))[0]	= opcode;
	((char *)(&data))[1]	= (char)0;
	((char *)(&data))[2]	= ((char *)(&oprand))[1];
	((char *)(&data))[3]	= ((char *)(&oprand))[0];

	obj[pc_address] = data;
}

/*----------------------------------------------------------*/
void getCode(int pc_address, char *opcode, short *oprand)
{
unsigned long	data;
char		code;
short		rand;

	data = obj[pc_address];
	code = ((char *)(&data))[0];
	((char *)(&rand))[1] = ((char *)(&data))[2];
	((char *)(&rand))[0] = ((char *)(&data))[3];

	*opcode = code;
	*oprand = rand;
}


/*----------------------------------------------------------*/
void initObj(void)
{
int i;

	obj = (unsigned long *)malloc(NUM_OBJ*4);

	for(i=0;i<NUM_OBJ;i++){
		obj[i] = 0;
	}

	pc = 0;
}

/*----------------------------------------------------------*/
void endObj(void)
{
int i;
char *a;

	a = (char *)obj;
	for(i=0;i<pc;i++){
		putc(*a++, yyout); 
		putc(*a++, yyout); 
		putc(*a++, yyout); 
		putc(*a++, yyout); 
	}

	free(obj);
}




/************************************************************
 * Basic functions
 ************************************************************/

static char srcFile[256];
static char dstFile[256];




/*----------------------------------------------------------*/
yyerror(char *s)
{
extern int	yylineno;

	printf(" ERROR %s : ", srcFile);
	printf("%s at line %d\n", s, yylineno);
}

/*----------------------------------------------------------*/
main(int argc, char *argv[])
{
char *s;
int i;

#if YYDEBUG
	yydebug	= 1;
#endif

	for(i=0;i<256;i++){
		srcFile[i]	= 0;
		dstFile[0]	= 0;
	}

	/* parse command line arguments */
	if(--argc > 0 && (char)(*++argv)[0] == '-'){
		for(s = (char *)*argv+1; *s != '\0'; s++){
			switch(tolower(*s)){
			case 'c': break;
			case 'd': break;
			}
		}
		argc--;
		argv++;
	}

	if(argc > 0){
		strcpy(srcFile, (char *)*argv);
	}

	/* open source file */
	yyin = fopen(srcFile, "r");
	if(yyin == NULL){
		fprintf(stderr, "Source file cannot be opened.");
		exit(-1);
	}

	/* open destination file */
	for(i=0;srcFile[i]!=0;i++){
		if(srcFile[i] == '.') break;
		dstFile[i] = srcFile[i];
	}
	strcpy(&dstFile[i], ".o");

	yyout = fopen(dstFile, "wb");
	if(yyout == NULL){
		fprintf(stderr, "Destination file cannot be opened.");
		fclose(yyin);
		exit(-1);
	}

	initObj();
	initSymList();
	
	/* parse input file */
	yyparse();

	endObj();

	/* close source file */
	fclose(yyin);
	/* close output file */
	fclose(yyout);


	printf("### %s ###\n", dstFile);
}

仮想マシンアセンブラ用のlex, yaccで生成されるコードから利用するユーティリティ関数のヘッダ

asmutil.h

/*
 * asmutil.h
 */

void initSymList(void);
char *IDentry(char *Name, int Len);
void registerSymbol(char *name);
int registerOffset(char *name);

仮想マシンアセンブラ用のlex, yaccで生成されるコードから利用するユーティリティ関数本体

asmutil.c

/*
 * asmutil.c
 */


#include <stdio.h>
#include "asmutil.h"

extern int pc;

typedef struct SymElem {
	char	*data;
	short	symaddr;
	short	reflist;
} SymElem;

#define	NUM_SYMELEM	128
static SymElem symlist[NUM_SYMELEM];
static int freeindex;

static int findSymbol(char *name);

void initSymList(void)
{
int i;

	for(i=0;i<NUM_SYMELEM;i++){
		symlist[i].data = NULL;
		symlist[i].symaddr = -1;
		symlist[i].reflist = -1;
	}
	freeindex = 0;
}


/*
 * local function
 * find the symbol in symlist
 * if the symbol is found, return the index.
 * otherwise return -1
 */
static int findSymbol(char *name)
{
int i;

	for(i=0;i<freeindex;i++){
		if(strcmp(symlist[i].data, name) == 0)	return i;
	}
	return -1;
}

/*
 * register syumbol
 * search symbol table
 * if sama name is found, return registered pointer
 * if samae name is not found, register the name
 * this function is just finding name
 */
char *IDentry(char *Name, int Len)
{
int i;

	i = findSymbol(Name);
	if(i != -1)	return symlist[i].data;

	if(freeindex >= NUM_SYMELEM){
		yyerror("Symbol Table Overflow");
	}

	i = freeindex;
	freeindex++;
	symlist[i].data = (char *)malloc((size_t)Len);
	strcpy(symlist[i].data, Name);
	return symlist[i].data;
}


/*
 * Register symbol
 * this function is called when label definition detected 
 * search symbol table. the same name should be detected.
 * because lexical analyzer has already registered the symbol.
 * if offset is already defined, it's error
 * set PC value to offset
 * if reflist is already defined, fill offset 
 */
void registerSymbol(char *name)
{
int i;
char code;
short off;
int pc_address;

	i = findSymbol(name);

	if(symlist[i].symaddr != -1){
		yyerror("Duplicate definition the Symbol");
		return;
	}
	symlist[i].symaddr = pc;

	if(symlist[i].reflist == -1)	return;

	pc_address = symlist[i].reflist;

	while(1){
		getCode(pc_address, &code, &off);
		setCode(pc_address, code, pc);
		if(off == 0) break;
		pc_address = pc_address + off;
	}

	symlist[i].reflist = -1;
}

/*
 * find the same symbol from symlist
 * list symbol chain
 * if the symbol has already been registered label, resolve offset chain
 */
void registerReference(int code, char *name)
{
int i;

	i = findSymbol(name);

	if(symlist[i].symaddr != -1){
		setCode(pc, code, symlist[i].symaddr);
		return;
	}

	if(symlist[i].reflist == -1){
		setCode(pc, code, 0);
		symlist[i].reflist = pc;
	}
	else{
		setCode(pc, code, symlist[i].reflist - pc);
		symlist[i].reflist = pc;
	}

}

仮想マシン上のプログラム

VM1がVM2を自身の上にロードし、実行すると
VM2がVM3を自身の上にロードし、実行すると
VM3がVM4を自身の上にロードし、実行すると
VM4がVM5を自身の上にロードし、実行すると
VM5がtestを自身の上にロードし、実行する。

これらのVMの違いはロードするファイルが違うだけ。
上手くやればVMを世代によらず共通化できたと思うが
ベタでファイル名の部分だけ変えている。


仮想マシン上の仮想マシンその1

vm1.m

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vm1.m				    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; initialize 
	PUSH	zero
	POP	i
initloop:
	PUSH	i
	PUSH	memp
	ADD
	PUSH	zero
	POPI

	PUSH	i
	PUSH	one
	ADD
	POP	i

	PUSH	i
	PUSH	maxmem
	JLT	initloop

; load file
	PUSH	memp
	PUSH	filep
	LOAD

; execute

exeloop:

; get byte code
; opcode -> c
; oprand -> d

	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTR	c24

	POP	c
	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTL	c16
	SFTR	c16
	POP	d

; decode opcode
	PUSH	c
	PUSH	nop
	JEQ	c_nop

	PUSH	c
	PUSH	push
	JEQ	c_push

	PUSH	c
	PUSH	pop
	JEQ	c_pop

	PUSH	c
	PUSH	pushi
	JEQ	c_pushi

	PUSH	c
	PUSH	popi
	JEQ	c_popi

	PUSH	c
	PUSH	remove
	JEQ	c_remove

	PUSH	c
	PUSH	add
	JEQ	c_add

	PUSH	c
	PUSH	sub
	JEQ	c_sub

	PUSH	c
	PUSH	sftr
	JEQ	c_sftr

	PUSH	c
	PUSH	sftl
	JEQ	c_sftl

	PUSH	c
	PUSH	jump
	JEQ	c_jump

	PUSH	c
	PUSH	jlt
	JEQ	c_jlt

	PUSH	c
	PUSH	jeq
	JEQ	c_jeq

	PUSH	c
	PUSH	jgt
	JEQ	c_jgt

	PUSH	c
	PUSH	halt
	JEQ	c_halt

; high level instructions
	PUSH	c
	PUSH	load
	JEQ	c_load

; debugging instructions

	PUSH	c
	PUSH	out
	JEQ	c_out

	PUSH	c
	PUSH	dump
	JEQ	c_dump

	PUSH	c
	PUSH	print
	JEQ	c_print

	PUSH	c
	PUSH	brk
	JEQ	c_brk

; undefined instruction
	PUSH	undefp
	PRINT
	PUSH	c
	OUT
	REMOVE
	JUMP	finish

; execute each code
c_nop:
	JUMP	done

c_push:
	PUSH	sp
	PUSH	one
	SUB
	POP	sp

	PUSH	sp
	PUSH	memp
	ADD
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_pop:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_pushi:
	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_popi:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JUMP	done

c_remove:
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_add:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	ADD

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sub:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	SUB

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sftr:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTR	d

	POPI

	JUMP	done

c_sftl:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTL	d

	POPI

	JUMP	done


c_jump:
	PUSH	d
	POP	pc
	JUMP	exeloop

c_jlt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jlt1

	JUMP	done
jlt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jeq:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JEQ	jeq1
	JUMP	done
jeq1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jgt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jgt1
	JUMP	done
jgt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_halt:
	BRK
	JUMP	finish

c_load:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	two
	ADD
	POP	sp
	
	LOAD

	JUMP	done
c_out:
	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	OUT
	REMOVE

	JUMP	done

c_dump:
	DUMP
	JUMP	done

c_print:

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	PRINT

	JUMP	done

c_brk:
	BRK

; increment pc
done:
	PUSH	pc
	PUSH	one
	ADD
	POP	pc

	JUMP	exeloop

finish:
	HALT

; data area

 ; constant values
zero:	DW	0
one:	DW	1
two:	DW	2
c16:	DW	16
c24:	DW	24

nop:	DW	0
push:	DW	1
pop:	DW	2
pushi:	DW	3
popi:	DW	4
remove:	DW	5
add:	DW	6
sub:	DW	7
sftr:	DW	8
sftl:	DW	9
jump:	DW	10
jlt:	DW	11
jeq:	DW	12
jgt:	DW	13
halt:	DW	14

load:	DW	15

out:	DW	16
dump:	DW	17
print:	DW	18
brk:	DW	19

 ; temporary variables
c:	DW	0
d:	DW	0
i:	DW	0

 ; global values
undefp:	DW	undef
undef:	DS	"Undefined Instruction"
filep:	DW	file
file:	DS	"vm2.o"
pc:	DW	0
fp:	DW	0
sp:	DW	2500
maxmem:	DW	2500
memp:	DW	mem
memsrt:	DS	"MEMSTART"
mem:	DA	2500
memend:	DS	"MEMEND"


仮想マシン上の仮想マシンその2

vm2.m

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vm2.m				    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; initialize 
	PUSH	zero
	POP	i
initloop:
	PUSH	i
	PUSH	memp
	ADD
	PUSH	zero
	POPI

	PUSH	i
	PUSH	one
	ADD
	POP	i

	PUSH	i
	PUSH	maxmem
	JLT	initloop

; load file
	PUSH	memp
	PUSH	filep
	LOAD

; execute

exeloop:

; get byte code
; opcode -> c
; oprand -> d

	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTR	c24

	POP	c
	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTL	c16
	SFTR	c16
	POP	d

; decode opcode
	PUSH	c
	PUSH	nop
	JEQ	c_nop

	PUSH	c
	PUSH	push
	JEQ	c_push

	PUSH	c
	PUSH	pop
	JEQ	c_pop

	PUSH	c
	PUSH	pushi
	JEQ	c_pushi

	PUSH	c
	PUSH	popi
	JEQ	c_popi

	PUSH	c
	PUSH	remove
	JEQ	c_remove

	PUSH	c
	PUSH	add
	JEQ	c_add

	PUSH	c
	PUSH	sub
	JEQ	c_sub

	PUSH	c
	PUSH	sftr
	JEQ	c_sftr

	PUSH	c
	PUSH	sftl
	JEQ	c_sftl

	PUSH	c
	PUSH	jump
	JEQ	c_jump

	PUSH	c
	PUSH	jlt
	JEQ	c_jlt

	PUSH	c
	PUSH	jeq
	JEQ	c_jeq

	PUSH	c
	PUSH	jgt
	JEQ	c_jgt

	PUSH	c
	PUSH	halt
	JEQ	c_halt

; high level instructions
	PUSH	c
	PUSH	load
	JEQ	c_load

; debugging instructions

	PUSH	c
	PUSH	out
	JEQ	c_out

	PUSH	c
	PUSH	dump
	JEQ	c_dump

	PUSH	c
	PUSH	print
	JEQ	c_print

	PUSH	c
	PUSH	brk
	JEQ	c_brk

; undefined instruction
	PUSH	undefp
	PRINT
	PUSH	c
	OUT
	REMOVE
	JUMP	finish

; execute each code
c_nop:
	JUMP	done

c_push:
	PUSH	sp
	PUSH	one
	SUB
	POP	sp

	PUSH	sp
	PUSH	memp
	ADD
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_pop:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_pushi:
	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_popi:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JUMP	done

c_remove:
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_add:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	ADD

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sub:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	SUB

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sftr:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTR	d

	POPI

	JUMP	done

c_sftl:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTL	d

	POPI

	JUMP	done


c_jump:
	PUSH	d
	POP	pc
	JUMP	exeloop

c_jlt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jlt1

	JUMP	done
jlt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jeq:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JEQ	jeq1
	JUMP	done
jeq1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jgt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jgt1
	JUMP	done
jgt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_halt:
	BRK
	JUMP	finish

c_load:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	two
	ADD
	POP	sp
	
	LOAD

	JUMP	done
c_out:
	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	OUT
	REMOVE

	JUMP	done

c_dump:
	DUMP
	JUMP	done

c_print:

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	PRINT

	JUMP	done

c_brk:
	BRK

; increment pc
done:
	PUSH	pc
	PUSH	one
	ADD
	POP	pc

	JUMP	exeloop

finish:
	HALT

; data area

 ; constant values
zero:	DW	0
one:	DW	1
two:	DW	2
c16:	DW	16
c24:	DW	24

nop:	DW	0
push:	DW	1
pop:	DW	2
pushi:	DW	3
popi:	DW	4
remove:	DW	5
add:	DW	6
sub:	DW	7
sftr:	DW	8
sftl:	DW	9
jump:	DW	10
jlt:	DW	11
jeq:	DW	12
jgt:	DW	13
halt:	DW	14

load:	DW	15

out:	DW	16
dump:	DW	17
print:	DW	18
brk:	DW	19

 ; temporary variables
c:	DW	0
d:	DW	0
i:	DW	0

 ; global values
undefp:	DW	undef
undef:	DS	"Undefined Instruction"
filep:	DW	file
file:	DS	"vm3.o"
pc:	DW	0
fp:	DW	0
sp:	DW	1900
maxmem:	DW	1900
memp:	DW	mem
memsrt:	DS	"MEMSTART"
mem:	DA	1900
memend:	DS	"MEMEND"


仮想マシン上の仮想マシンその3

vm3.m

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vm3.m				    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; initialize 
	PUSH	zero
	POP	i
initloop:
	PUSH	i
	PUSH	memp
	ADD
	PUSH	zero
	POPI

	PUSH	i
	PUSH	one
	ADD
	POP	i

	PUSH	i
	PUSH	maxmem
	JLT	initloop

; load file
	PUSH	memp
	PUSH	filep
	LOAD

; execute

exeloop:

; get byte code
; opcode -> c
; oprand -> d

	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTR	c24

	POP	c
	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTL	c16
	SFTR	c16
	POP	d

; decode opcode
	PUSH	c
	PUSH	nop
	JEQ	c_nop

	PUSH	c
	PUSH	push
	JEQ	c_push

	PUSH	c
	PUSH	pop
	JEQ	c_pop

	PUSH	c
	PUSH	pushi
	JEQ	c_pushi

	PUSH	c
	PUSH	popi
	JEQ	c_popi

	PUSH	c
	PUSH	remove
	JEQ	c_remove

	PUSH	c
	PUSH	add
	JEQ	c_add

	PUSH	c
	PUSH	sub
	JEQ	c_sub

	PUSH	c
	PUSH	sftr
	JEQ	c_sftr

	PUSH	c
	PUSH	sftl
	JEQ	c_sftl

	PUSH	c
	PUSH	jump
	JEQ	c_jump

	PUSH	c
	PUSH	jlt
	JEQ	c_jlt

	PUSH	c
	PUSH	jeq
	JEQ	c_jeq

	PUSH	c
	PUSH	jgt
	JEQ	c_jgt

	PUSH	c
	PUSH	halt
	JEQ	c_halt

; high level instructions
	PUSH	c
	PUSH	load
	JEQ	c_load

; debugging instructions

	PUSH	c
	PUSH	out
	JEQ	c_out

	PUSH	c
	PUSH	dump
	JEQ	c_dump

	PUSH	c
	PUSH	print
	JEQ	c_print

	PUSH	c
	PUSH	brk
	JEQ	c_brk

; undefined instruction
	PUSH	undefp
	PRINT
	PUSH	c
	OUT
	REMOVE
	JUMP	finish

; execute each code
c_nop:
	JUMP	done

c_push:
	PUSH	sp
	PUSH	one
	SUB
	POP	sp

	PUSH	sp
	PUSH	memp
	ADD
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_pop:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_pushi:
	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_popi:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JUMP	done

c_remove:
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_add:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	ADD

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sub:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	SUB

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sftr:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTR	d

	POPI

	JUMP	done

c_sftl:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTL	d

	POPI

	JUMP	done


c_jump:
	PUSH	d
	POP	pc
	JUMP	exeloop

c_jlt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jlt1

	JUMP	done
jlt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jeq:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JEQ	jeq1
	JUMP	done
jeq1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jgt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jgt1
	JUMP	done
jgt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_halt:
	BRK
	JUMP	finish

c_load:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	two
	ADD
	POP	sp
	
	LOAD

	JUMP	done
c_out:
	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	OUT
	REMOVE

	JUMP	done

c_dump:
	DUMP
	JUMP	done

c_print:

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	PRINT

	JUMP	done

c_brk:
	BRK

; increment pc
done:
	PUSH	pc
	PUSH	one
	ADD
	POP	pc

	JUMP	exeloop

finish:
	HALT

; data area

 ; constant values
zero:	DW	0
one:	DW	1
two:	DW	2
c16:	DW	16
c24:	DW	24

nop:	DW	0
push:	DW	1
pop:	DW	2
pushi:	DW	3
popi:	DW	4
remove:	DW	5
add:	DW	6
sub:	DW	7
sftr:	DW	8
sftl:	DW	9
jump:	DW	10
jlt:	DW	11
jeq:	DW	12
jgt:	DW	13
halt:	DW	14

load:	DW	15

out:	DW	16
dump:	DW	17
print:	DW	18
brk:	DW	19

 ; temporary variables
c:	DW	0
d:	DW	0
i:	DW	0

 ; global values
undefp:	DW	undef
undef:	DS	"Undefined Instruction"
filep:	DW	file
file:	DS	"vm4.o"
pc:	DW	0
fp:	DW	0
sp:	DW	1300
maxmem:	DW	1300
memp:	DW	mem
memsrt:	DS	"MEMSTART"
mem:	DA	1300
memend:	DS	"MEMEND"


仮想マシン上の仮想マシンその4

vm4.m

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vm4.m				    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; initialize 
	PUSH	zero
	POP	i
initloop:
	PUSH	i
	PUSH	memp
	ADD
	PUSH	zero
	POPI

	PUSH	i
	PUSH	one
	ADD
	POP	i

	PUSH	i
	PUSH	maxmem
	JLT	initloop

; load file
	PUSH	memp
	PUSH	filep
	LOAD

; execute

exeloop:

; get byte code
; opcode -> c
; oprand -> d

	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTR	c24

	POP	c
	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTL	c16
	SFTR	c16
	POP	d

; decode opcode
	PUSH	c
	PUSH	nop
	JEQ	c_nop

	PUSH	c
	PUSH	push
	JEQ	c_push

	PUSH	c
	PUSH	pop
	JEQ	c_pop

	PUSH	c
	PUSH	pushi
	JEQ	c_pushi

	PUSH	c
	PUSH	popi
	JEQ	c_popi

	PUSH	c
	PUSH	remove
	JEQ	c_remove

	PUSH	c
	PUSH	add
	JEQ	c_add

	PUSH	c
	PUSH	sub
	JEQ	c_sub

	PUSH	c
	PUSH	sftr
	JEQ	c_sftr

	PUSH	c
	PUSH	sftl
	JEQ	c_sftl

	PUSH	c
	PUSH	jump
	JEQ	c_jump

	PUSH	c
	PUSH	jlt
	JEQ	c_jlt

	PUSH	c
	PUSH	jeq
	JEQ	c_jeq

	PUSH	c
	PUSH	jgt
	JEQ	c_jgt

	PUSH	c
	PUSH	halt
	JEQ	c_halt

; high level instructions
	PUSH	c
	PUSH	load
	JEQ	c_load

; debugging instructions

	PUSH	c
	PUSH	out
	JEQ	c_out

	PUSH	c
	PUSH	dump
	JEQ	c_dump

	PUSH	c
	PUSH	print
	JEQ	c_print

	PUSH	c
	PUSH	brk
	JEQ	c_brk

; undefined instruction
	PUSH	undefp
	PRINT
	PUSH	c
	OUT
	REMOVE
	JUMP	finish

; execute each code
c_nop:
	JUMP	done

c_push:
	PUSH	sp
	PUSH	one
	SUB
	POP	sp

	PUSH	sp
	PUSH	memp
	ADD
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_pop:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_pushi:
	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_popi:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JUMP	done

c_remove:
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_add:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	ADD

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sub:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	SUB

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sftr:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTR	d

	POPI

	JUMP	done

c_sftl:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTL	d

	POPI

	JUMP	done


c_jump:
	PUSH	d
	POP	pc
	JUMP	exeloop

c_jlt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jlt1

	JUMP	done
jlt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jeq:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JEQ	jeq1
	JUMP	done
jeq1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jgt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jgt1
	JUMP	done
jgt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_halt:
	BRK
	JUMP	finish

c_load:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	two
	ADD
	POP	sp
	
	LOAD

	JUMP	done
c_out:
	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	OUT
	REMOVE

	JUMP	done

c_dump:
	DUMP
	JUMP	done

c_print:

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	PRINT

	JUMP	done

c_brk:
	BRK

; increment pc
done:
	PUSH	pc
	PUSH	one
	ADD
	POP	pc

	JUMP	exeloop

finish:
	HALT

; data area

 ; constant values
zero:	DW	0
one:	DW	1
two:	DW	2
c16:	DW	16
c24:	DW	24

nop:	DW	0
push:	DW	1
pop:	DW	2
pushi:	DW	3
popi:	DW	4
remove:	DW	5
add:	DW	6
sub:	DW	7
sftr:	DW	8
sftl:	DW	9
jump:	DW	10
jlt:	DW	11
jeq:	DW	12
jgt:	DW	13
halt:	DW	14

load:	DW	15

out:	DW	16
dump:	DW	17
print:	DW	18
brk:	DW	19

 ; temporary variables
c:	DW	0
d:	DW	0
i:	DW	0

 ; global values
undefp:	DW	undef
undef:	DS	"Undefined Instruction"
filep:	DW	file
file:	DS	"vm5.o"
pc:	DW	0
fp:	DW	0
sp:	DW	700
maxmem:	DW	700
memp:	DW	mem
memsrt:	DS	"MEMSTART"
mem:	DA	700
memend:	DS	"MEMEND"


仮想マシン上の仮想マシンその5

vm5.m

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; vm5.m				    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; initialize 
	PUSH	zero
	POP	i
initloop:
	PUSH	i
	PUSH	memp
	ADD
	PUSH	zero
	POPI

	PUSH	i
	PUSH	one
	ADD
	POP	i

	PUSH	i
	PUSH	maxmem
	JLT	initloop

; load file
	PUSH	memp
	PUSH	filep
	LOAD

; execute

exeloop:

; get byte code
; opcode -> c
; oprand -> d

	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTR	c24

	POP	c
	PUSH	pc
	PUSH	memp
	ADD
	PUSHI
	SFTL	c16
	SFTR	c16
	POP	d

; decode opcode
	PUSH	c
	PUSH	nop
	JEQ	c_nop

	PUSH	c
	PUSH	push
	JEQ	c_push

	PUSH	c
	PUSH	pop
	JEQ	c_pop

	PUSH	c
	PUSH	pushi
	JEQ	c_pushi

	PUSH	c
	PUSH	popi
	JEQ	c_popi

	PUSH	c
	PUSH	remove
	JEQ	c_remove

	PUSH	c
	PUSH	add
	JEQ	c_add

	PUSH	c
	PUSH	sub
	JEQ	c_sub

	PUSH	c
	PUSH	sftr
	JEQ	c_sftr

	PUSH	c
	PUSH	sftl
	JEQ	c_sftl

	PUSH	c
	PUSH	jump
	JEQ	c_jump

	PUSH	c
	PUSH	jlt
	JEQ	c_jlt

	PUSH	c
	PUSH	jeq
	JEQ	c_jeq

	PUSH	c
	PUSH	jgt
	JEQ	c_jgt

	PUSH	c
	PUSH	halt
	JEQ	c_halt

; high level instructions
	PUSH	c
	PUSH	load
	JEQ	c_load

; debugging instructions

	PUSH	c
	PUSH	out
	JEQ	c_out

	PUSH	c
	PUSH	dump
	JEQ	c_dump

	PUSH	c
	PUSH	print
	JEQ	c_print

	PUSH	c
	PUSH	brk
	JEQ	c_brk

; undefined instruction
	PUSH	undefp
	PRINT
	PUSH	c
	OUT
	REMOVE
	JUMP	finish

; execute each code
c_nop:
	JUMP	done

c_push:
	PUSH	sp
	PUSH	one
	SUB
	POP	sp

	PUSH	sp
	PUSH	memp
	ADD
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_pop:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_pushi:
	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSHI

	POPI

	JUMP	done

c_popi:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	POPI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JUMP	done

c_remove:
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_add:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	ADD

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sub:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	SUB

	POPI

	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	JUMP	done

c_sftr:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTR	d

	POPI

	JUMP	done

c_sftl:
	PUSH	fp
	PUSH	d
	ADD
	PUSH	memp
	ADD
	PUSHI
	POP	d

	PUSH	sp
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	SFTL	d

	POPI

	JUMP	done


c_jump:
	PUSH	d
	POP	pc
	JUMP	exeloop

c_jlt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jlt1

	JUMP	done
jlt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jeq:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JEQ	jeq1
	JUMP	done
jeq1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_jgt:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI

	PUSH	sp
	PUSH	two
	ADD
	POP	sp

	JLT	jgt1
	JUMP	done
jgt1:
	PUSH	fp
	PUSH	d
	ADD
	POP	pc

	JUMP	exeloop

c_halt:
	BRK
	JUMP	finish

c_load:
	PUSH	sp
	PUSH	one
	ADD
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD

	PUSH	sp
	PUSH	two
	ADD
	POP	sp
	
	LOAD

	JUMP	done
c_out:
	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	OUT
	REMOVE

	JUMP	done

c_dump:
	DUMP
	JUMP	done

c_print:

	PUSH	sp
	PUSH	memp
	ADD
	PUSHI
	PUSH	fp
	ADD
	PUSH	memp
	ADD
	PUSH	sp
	PUSH	one
	ADD
	POP	sp

	PRINT

	JUMP	done

c_brk:
	BRK

; increment pc
done:
	PUSH	pc
	PUSH	one
	ADD
	POP	pc

	JUMP	exeloop

finish:
	HALT

; data area

 ; constant values
zero:	DW	0
one:	DW	1
two:	DW	2
c16:	DW	16
c24:	DW	24

nop:	DW	0
push:	DW	1
pop:	DW	2
pushi:	DW	3
popi:	DW	4
remove:	DW	5
add:	DW	6
sub:	DW	7
sftr:	DW	8
sftl:	DW	9
jump:	DW	10
jlt:	DW	11
jeq:	DW	12
jgt:	DW	13
halt:	DW	14

load:	DW	15

out:	DW	16
dump:	DW	17
print:	DW	18
brk:	DW	19

 ; temporary variables
c:	DW	0
d:	DW	0
i:	DW	0

 ; global values
undefp:	DW	undef
undef:	DS	"Undefined Instruction"
filep:	DW	file
file:	DS	"test.o"
pc:	DW	0
fp:	DW	0
sp:	DW	100
maxmem:	DW	100
memp:	DW	mem
memsrt:	DS	"MEMSTART"
mem:	DA	100
memend:	DS	"MEMEND"


仮想マシン上のテストプログラム

test.m

;;;;;;;;;;;;;;;;;;;;;;;;;
; test.m		;
; SAMPLE PROGRAM	;
;;;;;;;;;;;;;;;;;;;;;;;;;

	PUSH	index
	PUSH	ap
	ADD
	PUSH	data
	POPI

	PUSH	index
	PUSH	ap
	ADD
	PUSHI

	OUT

	REMOVE

loop:
	PUSH	count
	PUSH	one
	ADD
	OUT
	POP	count
	PUSH	count
	PUSH	max
	JLT	loop

	PUSH	strp
	PRINT

	HALT

count:	DW	0
one:	DW	1
max:	DW	10
strp:	DW	str
str:	DS	"Hello World"
ap:	DW	array
array:	DA	10
index:	DW	3
data:	DW	7