OpenCores
URL https://opencores.org/ocsvn/z3/z3/trunk

Subversion Repositories z3

[/] [z3/] [trunk/] [utils/] [zops.c] - Rev 2

Compare with Previous | Blame | View Log

#include "common.h"
#include "file.h"
#include "mem.h"
#include "random.h"
#include "stack.h"
#include <ctype.h>
#include "SDL.h"
 
#define MAX_TOKEN_LEN 256
#define USE_BIOS 1
 
u16 randomseed=1;
 
enum
{
	SrcImmediate,
	SrcVariable
};
 
enum
{
	Form0OP,
	Form1OP,
	Form2OP,
	FormVAR
};
 
static int zeroOpStoreInstructions[]={};
static int oneOpStoreInstructions[]={0x01,0x02,0x03,0x04,0x08,0x0E,0x0F};
static int twoOpStoreInstructions[]={0x08,0x09,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19};
static int varOpStoreInstructions[]={0x00,0x07,0x0C,0x16,0x17,0x18,0x1E};
 
static int zeroOpBranchInstructions[]={0x05,0x06,0x0D};
static int oneOpBranchInstructions[]={0x00,0x01,0x02};
static int twoOpBranchInstructions[]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x0A};
static int varOpBranchInstructions[]={0x17};
 
static char alphabetLookup[3][27]={
	{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' },
	{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' },
	{ ' ', '\n','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '!', '?', '_', '#', '\'','"', '/', '\\','-', ':', '(', ')' },
};
 
typedef struct ZOperand_s
{
	int value;
	int src;
} ZOperand;
 
typedef struct ZBranch_s
{
	int offset;
	int negate;
} ZBranch;
 
typedef struct ZInstruction_s
{
	int op;
	int form;
	int store;
	int numOps;
	ZBranch branch;
	ZOperand operands[4];
} ZInstruction;
 
typedef struct ZCallStack_s
{
	int returnAddr;
	int returnStore;
	int locals[16];
	int depth;
} ZCallStack;
 
typedef struct ZObject_s
{
	int addr;
	int propTable;
} ZObject;
 
typedef struct ZProperty_s
{
	int addr;
	int size;
	int bDefault;
} ZProperty;
 
typedef struct ZToken_s
{
	char token[MAX_TOKEN_LEN];
	int offset;
} ZToken;
 
typedef struct ZDictEntry_s
{
	int coded[4];
	int current;
} ZDictEntry;
 
typedef char byte;
 
static ZInstruction m_ins;
static int m_pc;
static int m_globalVariables;
static int m_abbrevTable;
static int m_objectTable;
static int m_dictionaryTable;
static int m_memSize;
static int m_memOffset;
static byte *rom;
static byte *memory;
static byte *biosRAM;
static u16 *screen;
static int m_numberstack[1024];
static stack m_stack;
static ZCallStack m_callstackcontents[1024];
static stack m_callStack;
 
int forceDynamic=0;
int curIdx=0;
int curX=0;
int curY=0;
int winXMin=0;
int winXMax=240-1;
int winYMin=0;
int winYMax=320-1;
SDL_Window *window;
SDL_Renderer *ren;
SDL_Texture *tex;
int mouseDown=0;
int mouseX=0;
int mouseY=0;
 
byte ReadMem(int addr)
{
	return memory[addr+m_memOffset];
}
 
void WriteMem(int addr, byte val)
{
	memory[addr+m_memOffset]=val;
}
 
byte ReadMemDyn(int addr)
{
	if (addr>=0x10000 && forceDynamic)
		return biosRAM[addr-0x10000];
	return memory[addr+m_memOffset];
}
 
void displayState();
 
void WriteMemDyn(int addr, byte val)
{
	if (addr>=0x10000)
	{
		if (1)//forceDynamic)
			biosRAM[addr-0x10000]=val;
		else
		{
			printf("Bad write:%x (PC:%x)\n", addr, m_pc);
			displayState();
		}
	}
	else
	{
		memory[addr+m_memOffset]=val;
	}
}
 
int makeS16(int msb, int lsb)
{
	int ret=(msb<<8)+lsb;
	if ((ret&0x8000)!=0)
	{
		ret+=-0x10000;
	}
	return ret;
}
 
int makeU16(int msb, int lsb)
{
	return (msb<<8)+lsb;
}
 
int readBytePC()
{
	return ReadMem(m_pc++)&0xFF;
}
 
int readS16PC()
{
	int msb=readBytePC();
	int lsb=readBytePC();
	return makeS16(msb, lsb);
}
 
int readVariable(int var)
{
	if (var==0)
	{
		return *(int*)stackPop(&m_stack);
	}
	if (var<16)
	{
		return ((ZCallStack*)stackPeek(&m_callStack))->locals[var-1];
	}
	int off=2*(var-16);
	off+=m_globalVariables;
	return makeS16(ReadMem(off)&0xFF, ReadMem(off+1)&0xFF); 
}
 
void setVariable(int var, int value)
{
	value&=0xFFFF;
	if ((value&0x8000)!=0)
	{
		value+=-0x10000;
	}
	if (var==0)
	{
		*(int*)stackPush(&m_stack)=value;
		return;
	}
	if (var<16)
	{
		((ZCallStack*)stackPeek(&m_callStack))->locals[var-1]=value;
		return;
	}
	int off=2*(var-16);
	off+=m_globalVariables;
	WriteMem(off+0,(byte)((value&0xFF00)>>8));
	WriteMem(off+1,(byte)((value&0x00FF)>>0)); 
}
 
void setVariableIndirect(int var, int value)
{
	if (var==0)
	{
		stackPop(&m_stack);
	}
	setVariable(var, value);
}
 
int readVariableIndirect(int var)
{
	int ret=readVariable(var);
	if (var==0)
	{
		setVariable(var, ret);
	}
	return ret;
}
 
ZObject getObject(int id)
{
	ZObject ret;
	ret.addr=m_objectTable+2*31+9*(id-1);
	ret.propTable=makeU16(ReadMem(ret.addr+7)&0xFF, ReadMem(ret.addr+8)&0xFF);
	return ret;
}
 
ZProperty getProperty(ZObject obj, int id)
{
	ZProperty ret;
	int address=obj.propTable;
	int textLen=ReadMem(address++)&0xFF;
	address+=textLen*2;
	while (ReadMem(address)!=0)
	{
		int sizeId=ReadMem(address++)&0xFF;
		int size=1+(sizeId>>5);
		int propId=sizeId&31;
		if (propId==id)
		{
			ret.addr=address;
			ret.size=size;
			ret.bDefault=FALSE;
			return ret;
		}
		address+=size;
	}
	ret.addr=(m_objectTable+(id-1)*2)&0xFFFF;
	ret.size=2;
	ret.bDefault=TRUE;
	return ret;
}
 
void returnRoutine(int value)
{
	ZCallStack *cs=stackPop(&m_callStack);
	while (cs->depth<stackDepth(&m_stack))
	{
		readVariable(0);
	}
	if (cs->returnStore>=0)
	{
		setVariable(cs->returnStore, value);
	}
	m_pc=cs->returnAddr;
	if (cs->returnStore==-2)
	{
		returnRoutine(1);
	}
}
 
void doBranch(int cond, ZBranch branch)
{
	if (branch.negate)
	{
		cond=!cond;
	}
	if (cond)
	{
		if (branch.offset==0)
			returnRoutine(0);
		else if (branch.offset==1)
			returnRoutine(1);
		else
			m_pc+=branch.offset-2;
	}
}
 
void readOperand(int operandType)
{
	if (operandType==3) //omitted
	{
		return;
	}
	ZOperand *operand = &m_ins.operands[m_ins.numOps++];
	switch (operandType)
	{
		case 0: // long constant
			operand->value = readS16PC();
			operand->src = SrcImmediate;
			break;
		case 1: // small constant
			operand->value = readBytePC();
			operand->src = SrcImmediate;
			break;
		case 2: // variable
			operand->value = readVariable(readBytePC());
			operand->src = SrcVariable;
			break;
	}
}
 
void readShortForm(int opcode)
{
	int operand=(opcode>>4)&3;
	int op=opcode&15;
	m_ins.op=op;
	if (operand==3)
		m_ins.form=Form0OP;
	else
		m_ins.form=Form1OP;
	readOperand(operand);
}
 
void readLongForm(int opcode)
{
	int op=opcode&31;
	m_ins.op=op;
	m_ins.form=Form2OP;
	readOperand(((opcode&(1<<6))!=0)?2:1);
	readOperand(((opcode&(1<<5))!=0)?2:1);
}
 
void readVariableForm(int opcode)
{
	int op=opcode&31;
	int operandTypes=readBytePC();
	int i;
	m_ins.op=op;
	if ((opcode&0xF0)>=0xE0)
		m_ins.form=FormVAR;
	else
		m_ins.form=Form2OP;
	for (i=3; i>=0; i--)
	{
		readOperand((operandTypes>>(2*i))&3);
	}
}
 
int readStoreInstruction(int *match, int length, int op)
{
	int i;
	for (i=0; i<length; i++)
	{
		if (op==match[i])
		{
			return readBytePC();
		}
	}
	return -1;
}
 
ZBranch readBranchInstruction(int *match, int length, int op)
{
	ZBranch ret;
	int i;
	for (i=0; i<length; i++)
	{
		if (op==match[i])
		{
			int branch1=readBytePC();
			if ((branch1&(1<<6))==0)
			{
				int branch2=readBytePC();
				int offset=((branch1&63)<<8)+branch2;
				if ((offset&(1<<13))!=0)
				{
					offset+=-(1<<14);
				}
				ret.offset=offset;
				ret.negate=((branch1&0x80)==0);
				return ret;
			}
			else
			{
				ret.offset=branch1&63;
				ret.negate=((branch1&0x80)==0);
				return ret;
			}
		}
	}
	ret.offset=0;
	ret.negate=FALSE;
	return ret;
}
 
void callRoutine(int address, int returnStore, int setOperands)
{
	if (address==0)
	{
		setVariable(returnStore, 0);
	}
	else
	{
		int numLocals=ReadMem(address++)%0xFF;
		int i;
		ZCallStack cs;
		cs.returnAddr=m_pc;
		cs.returnStore=returnStore;
		for (i=0; i<numLocals; i++)
		{
			cs.locals[i]=makeS16(ReadMem(address)&0xFF, ReadMem(address+1)&0xFF);
			address+=2;
		}
		if (setOperands)
		{
			for (i=0; i<m_ins.numOps-1; i++)
			{
				cs.locals[i]=m_ins.operands[i+1].value;
			}
		}
		cs.depth=stackDepth(&m_stack);
		m_pc=address;
		*(ZCallStack*)stackPush(&m_callStack)=cs;
	}
}
 
void callBIOS(int id, int doubleReturn)
{
	int addr=0x1E58B+5*id;
	callRoutine(2*makeU16(ReadMem(addr)&0xFF,ReadMem(addr+1)&0xFF), doubleReturn?-2:-1, TRUE);
}
 
void displayState()
{
	int i;
	printf("Next PC:%x\n", m_pc);
	printf("Form:%d Opcode:%d\n", m_ins.form, m_ins.op);
	printf("Num operands: %d\n", m_ins.numOps);
	for (i=0; i<m_ins.numOps; i++)
	{
		printf("Value:%d Src:%d\n", m_ins.operands[i].value, m_ins.operands[i].src); 
	}
	printf("Store:%d Branch:%d %s\n", m_ins.store, m_ins.branch.offset, (m_ins.branch.negate?" Negated":" Normal"));
}
 
void dumpCurrentInstruction()
{
	int i;
	for (i=0; i<m_ins.numOps; i++)
	{ 
		printf("Arg:%d Value:%d\n", i, (m_ins.operands[i].value&0xFFFF));
	}
}
 
void haltInstruction()
{
	printf("\n\nUnimplemented instruction!\n");
	displayState();
	exit(1);
}
 
void illegalInstruction()
{
	printf("\n\nIllegal instruction!\n");
	displayState();
	exit(1);
}
 
int printText(int address)
{
	int pair1=0, pair2=0;
	int alphabet=0;
	int characters[3];
	int abbrNext=FALSE;
	int longNext=0;
	int longChar=0;
	int abbrChar=0;
	while ((pair1&0x80)==0)
	{
		int i;
		pair1=ReadMem(address++)&0xFF;
		pair2=ReadMem(address++)&0xFF;
		characters[0]=(pair1&0x7C)>>2;
		characters[1]=((pair1&3)<<3) + ((pair2&0xE0)>>5);
		characters[2]=pair2&0x1F;
		for (i=0; i<3; i++)
		{
			if (longNext>0)
			{
				longChar<<=5;
				longChar&=0x3FF;
				longChar|=characters[i];
				longNext--;
				if (longNext==0)
				{
					printf("%c", (char)longChar);
				}
			}
			else if (!abbrNext)
			{
				if (characters[i]==6 && alphabet==2)
				{
					longNext=2;
				}
				else if (characters[i]>=6)
				{
					characters[i]-=6;
					printf("%c", alphabetLookup[alphabet][characters[i]]);
					alphabet=0;
				}
				else if (characters[i]==4)
				{
					alphabet=1;
				}
				else if (characters[i]==5)
				{
					alphabet=2;
				}
				else if (characters[i]==0)
				{
					printf(" ");
				}
				else
				{
					abbrChar=characters[i];
					abbrNext=TRUE;
				}
			}
			else
			{
				int idx=32*(abbrChar-1)+characters[i];
				int abbrevTable=m_abbrevTable+2*idx;
				int abbrevAddress=makeU16(ReadMem(abbrevTable)&0xFF, ReadMem(abbrevTable+1)&0xFF);
				printText(2*abbrevAddress);
				abbrNext=FALSE;
			}
		}
	}
	return address;
}
 
void removeObject(int childId)
{
	ZObject child=getObject(childId);
	int parentId=ReadMem(child.addr+4)&0xFF;
	if (parentId!=0)
	{
		ZObject parent=getObject(parentId);
		if ((ReadMem(parent.addr+6)&0xFF)==childId)
		{
			WriteMem(parent.addr+6,ReadMem(child.addr+5)); // parent.child=child.sibling
		}
		else
		{
			int siblingId=ReadMem(parent.addr+6)&0xFF;
			while (siblingId!=0)
			{
				ZObject sibling=getObject(siblingId);
				int nextSiblingId=ReadMem(sibling.addr+5)&0xFF;
				if (nextSiblingId==childId)
				{
					WriteMem(sibling.addr+5,ReadMem(child.addr+5)); // sibling.sibling=child.sibling
					break;
				}
				siblingId=nextSiblingId;
			}
			if (siblingId==0)
			{
				illegalInstruction();
			}
		}
		WriteMem(child.addr+4,0);
		WriteMem(child.addr+5,0);
	}
}
 
void addChild(int parentId, int childId)
{
	ZObject child=getObject(childId);
	ZObject parent=getObject(parentId);
	WriteMem(child.addr+5,ReadMem(parent.addr+6)); // child.sibling=parent.child
	WriteMem(child.addr+4,(byte)parentId); // child.parent=parent
	WriteMem(parent.addr+6,(byte)childId); // parent.child=child
}
 
void zDictInit(ZDictEntry *entry)
{
	entry->current=0;
	entry->coded[0]=0;
	entry->coded[1]=0;
	entry->coded[2]=0x80;
	entry->coded[3]=0;
}
 
void zDictAddCharacter(ZDictEntry *entry, int code)
{
	code&=31;
	switch (entry->current)
	{
		case 0: entry->coded[0]|=code<<2; break;
		case 1: entry->coded[0]|=code>>3; entry->coded[1]|=(code<<5)&0xFF; break;
		case 2: entry->coded[1]|=code; break;
		case 3: entry->coded[2]|=code<<2; break;
		case 4: entry->coded[2]|=code>>3; entry->coded[3]|=(code<<5)&0xFF; break;
		case 5: entry->coded[3]|=code; break;
	}
	entry->current++;
}
 
ZDictEntry encodeToken(char* token)
{
	ZDictEntry ret;
	int tokenLen=strlen(token);
	int t;
	zDictInit(&ret);
	for (t=0; t<tokenLen; t++)
	{
		char curChar = token[t];
		int alphabet=-1;
		int code=-1;
		int a;
		for (a=0; a<3 && alphabet==-1; a++)
		{
			int i;
			for (i=0; i<27; i++)
			{
				if (curChar == alphabetLookup[a][i])
				{
					alphabet=a;
					code=i;
					break;
				}
			}
		}
		if (alphabet==-1)
		{
			zDictAddCharacter(&ret, 5);
			zDictAddCharacter(&ret, 6);
			zDictAddCharacter(&ret, curChar>>5);
			zDictAddCharacter(&ret, curChar&31);
		}
		else
		{
			if (alphabet>0)
			{
				int shift=alphabet+3;
				zDictAddCharacter(&ret, shift);
			}
			zDictAddCharacter(&ret, code+6);
		}
	}
	for (t=0; t<6; t++) // pad
	{
		zDictAddCharacter(&ret, 5);
	}
	return ret;
}
 
int getDictionaryAddress(char* token, int dictionary)
{
	int entryLength = ReadMem(dictionary++)&0xFF;
	int numEntries = makeU16(ReadMem(dictionary+0)&0xFF, ReadMem(dictionary+1)&0xFF);
	ZDictEntry zde = encodeToken(token);
	int i;
	dictionary+=2;
	for (i=0; i<numEntries; i++)
	{
		if (zde.coded[0]==(ReadMem(dictionary+0)&0xFF) && zde.coded[1]==(ReadMem(dictionary+1)&0xFF)
				&& zde.coded[2]==(ReadMem(dictionary+2)&0xFF) && zde.coded[3]==(ReadMem(dictionary+3)&0xFF))
		{
			return dictionary;
		}
		dictionary+=entryLength;
	}
	return 0;
}
 
int lexicalAnalysis(char* input, int parseBuffer, int maxEntries)
{
	static ZToken tokens[256];
	static char seps[256];
	int numTokens=0;
	int dictionaryAddress=m_dictionaryTable;
	int numSeperators=ReadMem(dictionaryAddress++);
	char *current=input;
	char *end=input+strlen(current);
	int i;
	for (i=0; i<numSeperators; i++)
	{
		seps[i]=(char)ReadMem(dictionaryAddress++);
	}
	while (current!=end)
	{
		char *space=strchr(current, ' ');
		char *min=end;
		int sepFound=FALSE;
		int tokLen;
		if (space==current)
		{
			current++;
			continue;
		}
		else if (space)
		{
			min=space;
		}
		for (i=0; i<numSeperators; i++)
		{
			char *sep=strchr(current, seps[i]);
			if (sep==current)
			{
				tokens[numTokens].offset=current-input;
				tokens[numTokens].token[0]=*current;
				tokens[numTokens].token[1]='\0';
				numTokens++;
				current++;
				sepFound=TRUE;
				break;
			}
			else if (sep && sep<min)
			{
				min=sep;
			}
		}
		if (sepFound)
		{
			continue;
		}
 
		tokens[numTokens].offset=(int)(current-input);
		tokLen=MIN(min-current, MAX_TOKEN_LEN-1);
		strncpy(tokens[numTokens].token, current, tokLen);
		tokens[numTokens].token[tokLen]='\0';
		numTokens++;
		current=min;
	}
 
	for (i=0; i<numTokens && i<maxEntries; i++)
	{
		int outAddress=getDictionaryAddress(tokens[i].token, dictionaryAddress);
		WriteMem(parseBuffer++,(byte)((outAddress>>8)&0xFF));
		WriteMem(parseBuffer++,(byte)((outAddress>>0)&0xFF));
		WriteMem(parseBuffer++,(byte)strlen(tokens[i].token));
		WriteMem(parseBuffer++,(byte)(tokens[i].offset+1));
	}
 
	return MIN(maxEntries, numTokens);
}
 
void restart()
{
	memcpy(memory, rom, m_memSize);
	memset(biosRAM, 0, 0x10000);
	ASSERT(ReadMem(0)==3);
	m_globalVariables=makeU16(ReadMem(0xC)&0xFF, ReadMem(0xD)&0xFF);
	m_abbrevTable=makeU16(ReadMem(0x18)&0xFF, ReadMem(0x19)&0xFF);
	m_objectTable=makeU16(ReadMem(0xA)&0xFF, ReadMem(0xB)&0xFF);
	m_dictionaryTable=makeU16(ReadMem(0x8)&0xFF, ReadMem(0x9)&0xFF);
	m_pc=makeU16(ReadMem(6)&0xFF, ReadMem(7)&0xFF);
	//WriteMem(1,ReadMem(1)|(1<<4)); // status line not available
	//WriteMem(1,ReadMem(1)&~(1<<5)); // screen splitting available
	//WriteMem(1,ReadMem(1)&~(1<<6)); // variable pitch font
	//WriteMem(0x10,ReadMem(0x10)|(1<<0)); // transcripting
	//WriteMem(0x10,ReadMem(0x10)|(1<<1)); // fixed font
	stackInit(&m_stack, m_numberstack, sizeof(m_numberstack[0]), ARRAY_SIZEOF(m_numberstack));
	stackInit(&m_callStack, m_callstackcontents, sizeof(m_callstackcontents[0]), ARRAY_SIZEOF(m_callstackcontents));
#if USE_BIOS
	callBIOS(0,FALSE);
#endif
}
 
void process0OPInstruction()
{
	switch (m_ins.op)
	{
		case 0: //rtrue
			returnRoutine(1);
			break;
		case 1: //rfalse
			returnRoutine(0);
			break;
		case 2: //print
			{
#if !USE_BIOS
				m_pc=printText(m_pc);
#else
				int origAddr=m_pc;
				while (!(ReadMem(m_pc)&0x80))
				{
					m_pc+=2;
				}
				m_pc+=2;
				m_ins.operands[1].value=origAddr&1;
				m_ins.operands[2].value=origAddr>>1;
				m_ins.numOps=3;
				callBIOS(1,FALSE);
#endif
				break;
			}
		case 3: //print_ret
			{
#if !USE_BIOS
				m_pc=printText(m_pc);
				printf("\n");
				returnRoutine(1);
#else
				int origAddr=m_pc;
				while (!(ReadMem(m_pc)&0x80))
				{
					m_pc+=2;
				}
				m_pc+=2;
				m_ins.operands[1].value=(origAddr&1)|2;
				m_ins.operands[2].value=origAddr>>1;
				m_ins.numOps=3;
				callBIOS(1,TRUE);
#endif
				break;
			}
		case 4: //nop
			break;
		case 5: //save
			doBranch(FALSE, m_ins.branch);
			break;
		case 6: //restore
			doBranch(FALSE, m_ins.branch);
			break;
		case 7: //restart
			restart();
			break;
		case 8: //ret_popped
			returnRoutine(*(int*)stackPop(&m_stack));
			break;
		case 9: //pop
			stackPop(&m_stack);
			break;
		case 0xA: //quit
#if !USE_BIOS
			haltInstruction();
#else
			callBIOS(6,FALSE);
#endif
			break;
		case 0xB: //new_line
#if !USE_BIOS
			printf("\n");
#else
			m_ins.operands[1].value='\n';
			m_ins.numOps=2;
			callBIOS(2,FALSE);
#endif
			break;
		case 0xC: //show_status
#if !USE_BIOS
			haltInstruction();
#else
			callBIOS(5,FALSE);
#endif
			break;
		case 0xD: //verify
			doBranch(TRUE, m_ins.branch);
			break;
		case 0xE: //extended
			illegalInstruction();
			break;
		case 0xF: //piracy
//			doBranch(TRUE, m_ins.branch);
			forceDynamic=1;
			break;
	}
}
 
void process1OPInstruction()
{
	switch (m_ins.op)
	{
		case 0: //jz
			doBranch(m_ins.operands[0].value==0, m_ins.branch);
			break;
		case 1: //get_sibling
			{
				ZObject child=getObject(m_ins.operands[0].value);
				int siblingId=ReadMem(child.addr+5)&0xFF;
				setVariable(m_ins.store, siblingId);
				doBranch(siblingId!=0, m_ins.branch);
				break;
			}
		case 2: //get_child
			{
				ZObject child=getObject(m_ins.operands[0].value);
				int childId=ReadMem(child.addr+6)&0xFF;
				setVariable(m_ins.store, childId);
				doBranch(childId!=0, m_ins.branch);
				break;
			}
		case 3: //get_parent_object
			{
				ZObject child=getObject(m_ins.operands[0].value);
				setVariable(m_ins.store, ReadMem(child.addr+4)&0xFF);
				break;
			}
		case 4: //get_prop_len
			{
				int propAddress=(m_ins.operands[0].value&0xFFFF)-1;
				int sizeId=ReadMem(propAddress)&0xFF;
				int size=(sizeId>>5)+1;
				setVariable(m_ins.store, size);
				break;
			}
		case 5: //inc
			{
				int value=readVariable(m_ins.operands[0].value);
				setVariable(m_ins.operands[0].value, value+1);
				break;
			}
		case 6: //dec
			{
				int value=readVariable(m_ins.operands[0].value);
				setVariable(m_ins.operands[0].value, value-1);
				break;
			}	
		case 7: //print_addr
#if !USE_BIOS
			printText(m_ins.operands[0].value);
#else
			m_ins.operands[1].value=m_ins.operands[0].value&1;
			m_ins.operands[2].value=m_ins.operands[0].value>>1;
			m_ins.numOps=3;
			callBIOS(1,FALSE);
#endif
			break;
		case 8: //call_1s
			m_memOffset=(m_ins.operands[0].value&3)*0x20000;
			restart();
			break;
		case 9: //remove_obj
			{
				removeObject(m_ins.operands[0].value);
				break;
			}
		case 0xA: //print_obj
			{
#if !USE_BIOS
				ZObject obj=getObject(m_ins.operands[0].value);
				printText(obj.propTable+1);
#else
				ZObject obj=getObject(m_ins.operands[0].value);
				m_ins.operands[1].value=(obj.propTable+1)&1;
				m_ins.operands[2].value=(obj.propTable+1)>>1;
				m_ins.numOps=3;
				callBIOS(1,FALSE);
#endif
				break;
			}
		case 0xB: //ret
			returnRoutine(m_ins.operands[0].value);
			break;
		case 0xC: //jump
			m_pc+=m_ins.operands[0].value-2;
			break;
		case 0xD: //print_paddr
#if !USE_BIOS
			printText(2*(m_ins.operands[0].value&0xFFFF));
#else
			m_ins.operands[1].value=0;
			m_ins.operands[2].value=m_ins.operands[0].value;
			m_ins.numOps=3;
			callBIOS(1,FALSE);
#endif
			break;
		case 0xE: //load
			setVariable(m_ins.store, readVariableIndirect(m_ins.operands[0].value));
			break;
		case 0xF: //not
			setVariable(m_ins.store, ~m_ins.operands[0].value);
			break;
	}
}
 
void process2OPInstruction()
{
	switch (m_ins.op)
	{
		case 0:
			illegalInstruction();
			break;
		case 1: //je
			{
				int takeBranch=FALSE;
				int test=m_ins.operands[0].value;
				int i;
				for (i=1; i<m_ins.numOps; i++)
				{
					if (test==m_ins.operands[i].value)
					{
						takeBranch=TRUE;
						break;
					}
				}
				doBranch(takeBranch, m_ins.branch);
				break;
			}
		case 2: //jl
			doBranch(m_ins.operands[0].value<m_ins.operands[1].value, m_ins.branch);
			break;
		case 3: //jg
			doBranch(m_ins.operands[0].value>m_ins.operands[1].value, m_ins.branch);
			break;
		case 4: //dec_chk
			{
				int value=readVariable(m_ins.operands[0].value);
				value--;
				setVariable(m_ins.operands[0].value, value);
				doBranch(value<m_ins.operands[1].value, m_ins.branch);
				break;
			}	
		case 5: //inc_chk
			{
				int value=readVariable(m_ins.operands[0].value);
				value++;
				setVariable(m_ins.operands[0].value, value);
				doBranch(value>m_ins.operands[1].value, m_ins.branch);
				break;
			}
		case 6: //jin
			{
				ZObject child=getObject(m_ins.operands[0].value);
				doBranch((ReadMem(child.addr+4)&0xFF)==m_ins.operands[1].value, m_ins.branch);
				break;
			}
		case 7: //test
			{
				int flags=m_ins.operands[1].value;
				doBranch((m_ins.operands[0].value&flags)==flags, m_ins.branch);
				break;
			}
		case 8: //or
			setVariable(m_ins.store, m_ins.operands[0].value|m_ins.operands[1].value);
			break;
		case 9: //and
			setVariable(m_ins.store, m_ins.operands[0].value&m_ins.operands[1].value);
			break;
		case 0xA: //test_attr
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				int attr=m_ins.operands[1].value;
				int offset=attr/8;
				int bit=0x80>>(attr%8);
				doBranch((ReadMem(obj.addr+offset)&bit)==bit, m_ins.branch);
				break;
			}
		case 0xB: //set_attr
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				int attr=m_ins.operands[1].value;
				int offset=attr/8;
				int bit=0x80>>(attr%8);
				WriteMem(obj.addr+offset,ReadMem(obj.addr+offset)|bit);
				break;
			}
		case 0xC: //clear_attr
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				int attr=m_ins.operands[1].value;
				int offset=attr/8;
				int bit=0x80>>(attr%8);
				WriteMem(obj.addr+offset,ReadMem(obj.addr+offset)&~bit);
				break;
			}
		case 0xD: //store
			setVariableIndirect(m_ins.operands[0].value, m_ins.operands[1].value);
			break;
		case 0xE: //insert_obj
			{
				removeObject(m_ins.operands[0].value);
				addChild(m_ins.operands[1].value, m_ins.operands[0].value);
				break;
			}
		case 0xF: //loadw
			{
				int address=((m_ins.operands[0].value&0xFFFF)+2*(m_ins.operands[1].value&0xFFFF));
				setVariable(m_ins.store, makeS16(ReadMemDyn(address)&0xFF, ReadMemDyn(address+1)&0xFF));
				forceDynamic=0;
				break;
			}
		case 0x10: //loadb
			{
				int address=((m_ins.operands[0].value&0xFFFF)+(m_ins.operands[1].value&0xFFFF));
				setVariable(m_ins.store, ReadMemDyn(address)&0xFF);
				forceDynamic=0;
				break;
			}
		case 0x11: //get_prop
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				ZProperty prop=getProperty(obj, m_ins.operands[1].value);
				if (prop.size==1)
				{
					setVariable(m_ins.store, ReadMem(prop.addr)&0xFF);
				}
				else if (prop.size==2)
				{
					setVariable(m_ins.store, makeS16(ReadMem(prop.addr)&0xFF, ReadMem(prop.addr+1)&0xFF));
				}
				else
				{
					illegalInstruction();
				}
				break;
			}
		case 0x12: //get_prop_addr
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				ZProperty prop=getProperty(obj, m_ins.operands[1].value);
				if (prop.bDefault)
					setVariable(m_ins.store, 0);
				else
					setVariable(m_ins.store, prop.addr);
				break;
			}
		case 0x13: //get_next_prop
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				if (m_ins.operands[1].value==0)
				{
					int address=obj.propTable;
					int textLen=ReadMem(address++)&0xFF;
					address+=textLen*2;
					int nextSizeId=ReadMem(address)&0xFF;
					setVariable(m_ins.store, nextSizeId&31);
				}
				else
				{
					ZProperty prop=getProperty(obj, m_ins.operands[1].value);
					if (prop.bDefault)
					{
						illegalInstruction();
					}
					else
					{
						int nextSizeId=ReadMem(prop.addr+prop.size)&0xFF;
						setVariable(m_ins.store, nextSizeId&31);
					}
				}
				break;
			}
		case 0x14: //add
			setVariable(m_ins.store, m_ins.operands[0].value+m_ins.operands[1].value);
			break;
		case 0x15: //sub
			setVariable(m_ins.store, m_ins.operands[0].value-m_ins.operands[1].value);
			break;
		case 0x16: //mul
			setVariable(m_ins.store, m_ins.operands[0].value*m_ins.operands[1].value);
			break;
		case 0x17: //div
			setVariable(m_ins.store, m_ins.operands[0].value/m_ins.operands[1].value);
			break;
		case 0x18: //mod
			setVariable(m_ins.store, m_ins.operands[0].value%m_ins.operands[1].value);
			break;
		case 0x19: //call_2s
			illegalInstruction();
			break;
		case 0x1A: //call_2n
			illegalInstruction();
			break;
		case 0x1B: //set_colour
			illegalInstruction();
			break;
		case 0x1C: //throw
			illegalInstruction();
			break;
		case 0x1D:
			illegalInstruction();
			break;
		case 0x1E:
			//printf("WriteReg: %04x %04x\n", m_ins.operands[0].value&0xFFFF, m_ins.operands[1].value&0xFFFF);
			if (m_ins.operands[0].value==0x22)
			{
				screen[curIdx%(320*240)]=m_ins.operands[1].value;
				curIdx++;
				curX++;
				if (curX>winXMax)
				{
					curX=winXMin;
					curY++;
					if (curY>winYMax)
					{
						curY=winYMin;
					}
					curIdx=curY*240+curX;
				}
			}
			else if (m_ins.operands[0].value==0x20)
			{
				curX=m_ins.operands[1].value;
				curIdx=curY*240+curX;
			}
			else if (m_ins.operands[0].value==0x21)
			{
				curY=m_ins.operands[1].value;
				curIdx=curY*240+curX;
			}
			else if (m_ins.operands[0].value==0x50)
			{
				winXMin=m_ins.operands[1].value;
			}
			else if (m_ins.operands[0].value==0x51)
			{
				winXMax=m_ins.operands[1].value;
			}
			else if (m_ins.operands[0].value==0x52)
			{
				winYMin=m_ins.operands[1].value;
			}
			else if (m_ins.operands[0].value==0x53)
			{
				winYMax=m_ins.operands[1].value;
			}
			else if (m_ins.operands[0].value==7)
			{
				SDL_UpdateTexture(tex, NULL, screen, 240*sizeof(screen[0]));
				SDL_RenderClear(ren);
				SDL_RenderCopy(ren, tex, NULL, NULL);
				SDL_RenderPresent(ren);
				SDL_Delay(1);
			}
			break;
		case 0x1F:
			illegalInstruction();
			break;
	}
}
 
void processVARInstruction()
{
	switch (m_ins.op)
	{
		case 0: // call
			callRoutine(2*(m_ins.operands[0].value&0xFFFF), m_ins.store, TRUE);
			break;
		case 1: //storew
			{
				int address=((m_ins.operands[0].value&0xFFFF)+2*(m_ins.operands[1].value&0xFFFF));
				int value=m_ins.operands[2].value;
				WriteMemDyn(address,(byte)((value>>8)&0xFF));
				WriteMemDyn(address+1,(byte)(value&0xFF));
				forceDynamic=0;
				break;
			}
		case 2: //storeb
			{
				int address=((m_ins.operands[0].value&0xFFFF)+(m_ins.operands[1].value&0xFFFF));
				int value=m_ins.operands[2].value;
				WriteMemDyn(address,(byte)(value&0xFF));
				forceDynamic=0;
				break;
			}
		case 3: //put_prop
			{
				ZObject obj=getObject(m_ins.operands[0].value);
				ZProperty prop=getProperty(obj, m_ins.operands[1].value);
				if (!prop.bDefault)
				{
					if (prop.size==1)
					{
						WriteMem(prop.addr,(byte)(m_ins.operands[2].value&0xFF));
					}
					else if (prop.size==2)
					{
						WriteMem(prop.addr+0,(byte)((m_ins.operands[2].value>>8)&0xFF));
						WriteMem(prop.addr+1,(byte)(m_ins.operands[2].value&0xFF));
					}
				}
				else
				{
					illegalInstruction();
				}
				break;
			}
		case 4: //sread
			{
#if !USE_BIOS
				static char input[4096];
				int bufferAddr=m_ins.operands[0].value;
				int parseAddr=m_ins.operands[1].value;
				int maxLength=ReadMem(bufferAddr++)&0xFF;
				int maxParse=ReadMem(parseAddr++)&0xFF;
				int realInLen=0;
				int inLen;
				int i;
				fgets(input, sizeof(input), stdin);
				inLen=strlen(input);
				for (i=0; i<inLen && i<maxLength; i++)
				{
					if (input[i]!='\r' && input[i]!='\n')
					{
						input[realInLen++]=tolower(input[i]);
						WriteMem(bufferAddr++,(byte)input[i]);
					}
				}
				input[realInLen]='\0';
				WriteMem(bufferAddr++,0);
				WriteMem(parseAddr,(byte)lexicalAnalysis(input, parseAddr+1, maxParse));
#else
				m_ins.operands[2].value=m_ins.operands[0].value;
				m_ins.numOps=3;
				callBIOS(4,FALSE);
#endif
				break;
			}
		case 5: //print_char
#if !USE_BIOS
			printf("%c", (char)m_ins.operands[0].value);
#else
			m_ins.operands[1].value=m_ins.operands[0].value;
			m_ins.numOps=2;
			callBIOS(2,FALSE);
#endif
			break;
		case 6: //print_num
#if !USE_BIOS
			printf("%d", m_ins.operands[0].value);
#else
			m_ins.operands[1].value=m_ins.operands[0].value;
			m_ins.numOps=2;
			callBIOS(3,FALSE);
#endif
			break;
		case 7: //random
			{
				int maxValue=m_ins.operands[0].value;
				int ret=0;
				if (maxValue>0)
				{
					randomseed=randomseed^(randomseed<<13);
					randomseed=randomseed^(randomseed>>9);
					randomseed=randomseed^(randomseed<<7);
					ret=((randomseed&0x7FFF)%(maxValue))+1;
				}
				else if (maxValue<0)
				{
					randomseed=maxValue;
				}
				setVariable(m_ins.store, ret);
				break;
			}
		case 8: //push
			setVariable(0, m_ins.operands[0].value);
			break;
		case 9: //pull
			setVariableIndirect(m_ins.operands[0].value, readVariable(0));
			break;
		case 0xA: //split_window
			haltInstruction();
			break;
		case 0xB: //set_window
			haltInstruction();
			break;
		case 0xC: //call_vs2
			illegalInstruction();
			break;
		case 0xD: //erase_window
			illegalInstruction();
			break;
		case 0xE: //erase_line
			illegalInstruction();
			break;
		case 0xF: //set_cursor
			illegalInstruction();
			break;
		case 0x10: //get_cursor
			illegalInstruction();
			break;
		case 0x11: //set_text_style
			illegalInstruction();
			break;
		case 0x12: //buffer_mode
			illegalInstruction();
			break;
		case 0x13: //output_stream
			haltInstruction();
			break;
		case 0x14: //input_stream
			haltInstruction();
			break;
		case 0x15: //sound_effect
			haltInstruction();
			break;
		case 0x16: //read_char
			illegalInstruction();
			break;
		case 0x17: //scan_table
			illegalInstruction();
			break;
		case 0x18: //not
			illegalInstruction();
			break;
		case 0x19: //call_vn
			illegalInstruction();
			break;
		case 0x1A: //call_vn2
			illegalInstruction();
			break;
		case 0x1B: //tokenise
			illegalInstruction();
			break;
		case 0x1C: //encode_text
			illegalInstruction();
			break;
		case 0x1D: //copy_table
			illegalInstruction();
			break;
		case 0x1E: //print_table
			{
				//			printf("GetTouch: %04x\n", m_ins.operands[0].value);
				SDL_Event e;
				while (SDL_PollEvent(&e))
				{
					if (e.type == SDL_QUIT)
						exit(1);
					else if (e.type == SDL_MOUSEBUTTONDOWN)
						mouseDown=1;
					else if (e.type == SDL_MOUSEBUTTONUP)
						mouseDown=0;
					else if (e.type == SDL_MOUSEMOTION)
					{
						SDL_MouseMotionEvent *mm=(SDL_MouseMotionEvent*)&e;
						mouseX=mm->x;
						mouseY=mm->y;
					}
				}
				if (m_ins.operands[0].value==0x93) // touching?
					setVariable(m_ins.store, mouseDown?0:1024);
				else if (m_ins.operands[0].value==0x95) // X
				{
					float m=(840.0f-170.0f)/(216.0f-23.0f);
					float c=840.0f-216.0f*m;
					float v=mouseX*m+c;
					setVariable(m_ins.store, (int)MIN(MAX(v,0),1023));
				}
				else if (m_ins.operands[0].value==0x1A) // Y
				{
					float m=(870.0f-720.0f)/(302.0f-243.0f);
					float c=870.0f-302.0f*m;
					float v=mouseY*m+c;
					setVariable(m_ins.store, (int)MIN(MAX(v,0),1023));
				}
				else
					setVariable(m_ins.store, 0);
				break;
			}
		case 0x1F: //check_arg_count
			{
				int i;
				//printf("Blit: %04x %04x %04x %04x\n", m_ins.operands[0].value&0xFFFF, m_ins.operands[1].value&0xFFFF, m_ins.operands[2].value&0xFFFF, m_ins.operands[3].value&0xFFFF);
				forceDynamic=1;
				for (i=0; i<(m_ins.operands[1].value&0xFFFF); i++)
				{
					byte data=ReadMemDyn(2*(m_ins.operands[0].value&0xFFFF)+i);
					screen[curIdx%(320*240)]=(data&0x80)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;
					screen[curIdx%(320*240)]=(data&0x40)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;
					screen[curIdx%(320*240)]=(data&0x20)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;
					screen[curIdx%(320*240)]=(data&0x10)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;
					screen[curIdx%(320*240)]=(data&0x08)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;                         
					screen[curIdx%(320*240)]=(data&0x04)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;                         
					screen[curIdx%(320*240)]=(data&0x02)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;                         
					screen[curIdx%(320*240)]=(data&0x01)?m_ins.operands[3].value:m_ins.operands[2].value;
					curIdx++;
					curX+=8;
					if (curX>winXMax)
					{
						curX=winXMin;
						curY++;
						if (curY>winYMax)
						{
							curY=winYMin;
						}
						curIdx=curY*240+curX;
					}
				}
				SDL_UpdateTexture(tex, NULL, screen, 240*sizeof(screen[0]));
				SDL_RenderClear(ren);
				SDL_RenderCopy(ren, tex, NULL, NULL);
				SDL_RenderPresent(ren);
				SDL_Delay(1);
				forceDynamic=0;
				break;
			}
	}
}
 
void executeInstruction()
{
	m_ins.numOps=0;
	//printf("\nPC:%05x ", m_pc);
	//System.out.println(String.format("%04x", m_pc));
	int opcode=readBytePC();
	if ((opcode&0xC0)==0xC0)
	{
		readVariableForm(opcode);
	}
	else if ((opcode&0xC0)==0x80)
	{
		readShortForm(opcode);
	}
	else
	{
		readLongForm(opcode);
	}
	switch (m_ins.form)
	{
		case Form0OP:
			//printf("Doing op0:%2d\n", m_ins.op);
			m_ins.store=readStoreInstruction(zeroOpStoreInstructions,ARRAY_SIZEOF(zeroOpStoreInstructions),m_ins.op);
			m_ins.branch=readBranchInstruction(zeroOpBranchInstructions,ARRAY_SIZEOF(zeroOpBranchInstructions),m_ins.op);
			//dumpCurrentInstruction();
			process0OPInstruction();
			break;
		case Form1OP:
			//printf("Doing op1:%2d Operands:%04x\n", m_ins.op, m_ins.operands[0].value&0xFFFF);
			m_ins.store=readStoreInstruction(oneOpStoreInstructions,ARRAY_SIZEOF(oneOpStoreInstructions),m_ins.op);
			m_ins.branch=readBranchInstruction(oneOpBranchInstructions,ARRAY_SIZEOF(oneOpBranchInstructions),m_ins.op);
			//dumpCurrentInstruction();
			process1OPInstruction();
			break;
		case Form2OP:
			//printf("Doing op2:%2d Operands:%04x %04x\n", m_ins.op, m_ins.operands[0].value&0xFFFF, m_ins.operands[1].value&0xFFFF);
			m_ins.store=readStoreInstruction(twoOpStoreInstructions,ARRAY_SIZEOF(twoOpStoreInstructions),m_ins.op);
			m_ins.branch=readBranchInstruction(twoOpBranchInstructions,ARRAY_SIZEOF(twoOpBranchInstructions),m_ins.op);
			//dumpCurrentInstruction();
			process2OPInstruction();
			break;
		case FormVAR:
			//if (m_ins.numOps==4)
			//	printf("Doing opvar:%2d Operands:%04x %04x %04x %04x\n", m_ins.op, m_ins.operands[0].value&0xFFFF, m_ins.operands[1].value&0xFFFF, m_ins.operands[2].value&0xFFFF, m_ins.operands[3].value&0xFFFF);
			//else if (m_ins.numOps==3)
			//	printf("Doing opvar:%2d Operands:%04x %04x %04x\n", m_ins.op, m_ins.operands[0].value&0xFFFF, m_ins.operands[1].value&0xFFFF, m_ins.operands[2].value&0xFFFF);
			//else if (m_ins.numOps==2)
			//	printf("Doing opvar:%2d Operands:%04x %04x\n", m_ins.op, m_ins.operands[0].value&0xFFFF, m_ins.operands[1].value&0xFFFF);
			//else if (m_ins.numOps==1)
			//	printf("Doing opvar:%2d Operands:%04x\n", m_ins.op, m_ins.operands[0].value&0xFFFF);
			//else
			//	printf("Doing opvar:%2d Operands:\n", m_ins.op);
			m_ins.store=readStoreInstruction(varOpStoreInstructions,ARRAY_SIZEOF(varOpStoreInstructions),m_ins.op);
			m_ins.branch=readBranchInstruction(varOpBranchInstructions,ARRAY_SIZEOF(varOpBranchInstructions),m_ins.op);
			//dumpCurrentInstruction();
			processVARInstruction();
			break;
	}
}
 
int main(int argc, char **argv)
{
	TFile fh;
	if (argc!=2)
	{
		printf("Usage: zops game.z3\n");
	}
	else if (fileOpen(&fh, argv[1], TRUE))
	{
		m_memSize=fileSize(&fh);
 
		SDL_Init(SDL_INIT_VIDEO);
		window = SDL_CreateWindow("TFTLCD",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,240,320,SDL_WINDOW_SHOWN);
		if (window == NULL)
		{
			printf("Could not create window: %s\n", SDL_GetError());
			return 1;
		}
		ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
		if (ren == NULL)
		{
			printf("Could not create renderer: %s\n", SDL_GetError());
			return 1;
		}
		tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, 240, 320);
		if (tex == NULL)
		{
			printf("Could not create texture: %s\n", SDL_GetError());
			return 1;
		}
 
		rom=memAlloc(m_memSize);
		memory=memAlloc(m_memSize);
		biosRAM=memAlloc(0x10000);
		screen=memAlloc(320*240*sizeof(u16));
		fileReadData(&fh, rom, m_memSize);
		fileClose(&fh);
		restart();
		while (1)
		{
			executeInstruction();
		}
 
		SDL_DestroyTexture(tex);
		SDL_DestroyRenderer(ren);
		SDL_DestroyWindow(window);
		SDL_Quit();
		return 0;
	}
	return 1;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.