#include "lib9.h"
#include "isa.h"
#include "interp.h"

void	decgen(int);

/*
 * Force intermediate dereference of $o(o(reg)) modes to ensure intermediate
 * pointer is valid. This is required if you want secure memory.
 */
#define	SOFTMMU		0

void
main(void)
{
	int i;

	print("/* Machine generated by decgen.c */\n\n");

	print("#include \"lib9.h\"\n");
	print("#include \"isa.h\"\n");
	print("#include \"interp.h\"\n\n");

	print("#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)\n");

	for(i = 0; i < 256; i++)
		decgen(i);

	print("\nvoid	(*dec[])(void) =\n{\n");
	for(i = 0; i < 256; i++)
		print("\tD%.2uX%c\n", i, i != 255 ? ',' : ' ');
	print("};\n");
}

void
decgen(int addr)
{
	int nodst;

	print("static void\nD%.2uX(void)\n{\n", addr);

	switch(USRC(addr)) {
	case AMP:
		print("\tR.s = R.MP+R.PC->s.ind;\n");
		break;
	case AFP:
		print("\tR.s = R.FP+R.PC->s.ind;\n");
		break;
	case AIMM:
		print("\tR.s = (uchar*)&R.PC->s.imm;\n");
		break;
	case AMP|AIND:
		if(SOFTMMU) {
			print("R.s = R.MP+R.PC->s.i.f\n");
			print("R.s = *(WORD**)R.s\n");
			print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
		}
		else
			print("\tR.s = DIND(MP, s);\n");
		break;
	case AFP|AIND:
		if(SOFTMMU) {
			print("R.s = R.FP+R.PC->s.i.f\n");
			print("R.s = *(WORD**)R.s\n");
			print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
		}
		else
			print("\tR.s = DIND(FP, s);\n");
		break;
	}
	nodst = 0;
	switch(UDST(addr)) {
	default:
		nodst = 1;
		break;
	case AMP:
		print("\tR.d = R.MP+R.PC->d.ind;\n");
		break;
	case AFP:
		print("\tR.d = R.FP+R.PC->d.ind;\n");
		break;
	case AIMM:
		print("\tR.d = (uchar*)&R.PC->d.imm;\n");
		break;
	case AMP|AIND:
		if(SOFTMMU) {
			print("R.d = R.MP+R.PC->d.i.f\n");
			print("R.d = *(WORD**)R.d\n");
			print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
		}
		else
			print("\tR.d = DIND(MP, d);\n");
		break;
	case AFP|AIND:
		if(SOFTMMU) {
			print("R.d = R.FP+R.PC->d.i.f\n");
			print("R.d = *(WORD**)R.d\n");
			print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
		}
		else
			print("\tR.d = DIND(FP, d);\n");
		break;
	}

	if(nodst == 0)
	switch(addr&ARM) {
	case AXNON:
		print("\tR.m = R.d;\n");
		break;
	case AXIMM:
		print("\tR.t = (short)R.PC->reg;\n");
		print("\tR.m = &R.t;\n");
		break;
	case AXINF:
		print("\tR.m = R.FP+R.PC->reg;\n");
		break;
	case AXINM:
		print("\tR.m = R.MP+R.PC->reg;\n");
		break;
	}
	print("}\n");
}
