#! /usr/local/gnu/bin/gawk -f

#
#	pasm.awk
#
#	Oct-22-1994	nisimura@aa.cs.keio.ac.jp
#

BEGIN {
	STDERR	= "/dev/stderr";
	ERROR	= -1;

	TYPE_J	= 1;
	TYPE_I1	= 2;
	TYPE_I2	= 3;
	TYPE_R1	= 4;
	TYPE_R2	= 5;
	TYPE_D	= 6;

	OP["J"]    = ston("0x0000");	TYPE["J"]    = TYPE_J;
	OP["JAL"]  = ston("0x1000");	TYPE["JAL"]  = TYPE_J;
	OP["BEQZ"] = ston("0x2000");	TYPE["BEQZ"] = TYPE_J;
	OP["BNEZ"] = ston("0x3000");	TYPE["BNEZ"] = TYPE_J;
	OP["JR"]   = ston("0x4000");	TYPE["JR"]   = TYPE_R1;
	OP["JALR"] = ston("0x5000");	TYPE["JALR"] = TYPE_R1;
	OP["LDL"]  = ston("0x6000");	TYPE["LDL"]  = TYPE_I1;
	OP["LDH"]  = ston("0x7000");	TYPE["LDH"]  = TYPE_I1;
	OP["ANDI"] = ston("0x8000");	TYPE["ANDI"] = TYPE_I1;
	OP["ORI"]  = ston("0x9000");	TYPE["ORI"]  = TYPE_I1;
	OP["XORI"] = ston("0xA000");	TYPE["XORI"] = TYPE_I1;
	OP["ADDI"] = ston("0xC000");	TYPE["ADDI"] = TYPE_I1;
	OP["SUBI"] = ston("0xD000");	TYPE["SUBI"] = TYPE_I1;

	OP["SRLI"] = ston("0xE000");	TYPE["SRLI"] = TYPE_I2;
	OP["SLLI"] = ston("0xE010");	TYPE["SLLI"] = TYPE_I2;
	OP["SRAI"] = ston("0xE020");	TYPE["SRAI"] = TYPE_I2;
	OP["RORI"] = ston("0xE040");	TYPE["RORI"] = TYPE_I2;
	OP["ROLI"] = ston("0xE050");	TYPE["ROLI"] = TYPE_I2;
	OP["SRL"]  = ston("0xE080");	TYPE["SRL"]  = TYPE_R2;
	OP["SLL"]  = ston("0xE090");	TYPE["SLL"]  = TYPE_R2;
	OP["SRA"]  = ston("0xE0A0");	TYPE["SRA"]  = TYPE_R2;
	OP["ROR"]  = ston("0xE0C0");	TYPE["ROR"]  = TYPE_R2;
	OP["ROL"]  = ston("0xE0D0");	TYPE["ROL"]  = TYPE_R2;

	OP["SGT"]  = ston("0xF000");	TYPE["SGT"]  = TYPE_R2;
	OP["SLT"]  = ston("0xF010");	TYPE["SLT"]  = TYPE_R2;
	OP["SEQ"]  = ston("0xF020");	TYPE["SEQ"]  = TYPE_R2;
	OP["LD"]   = ston("0xF030");	TYPE["LD"]   = TYPE_R2;
	OP["SLE"]  = ston("0xF040");	TYPE["SLE"]  = TYPE_R2;
	OP["SGE"]  = ston("0xF050");	TYPE["SGE"]  = TYPE_R2;
	OP["SNE"]  = ston("0xF060");	TYPE["SNE"]  = TYPE_R2;
	OP["ST"]   = ston("0xF070");	TYPE["ST"]   = TYPE_R2;
	OP["AND"]  = ston("0xF080");	TYPE["AND"]  = TYPE_R2;
	OP["OR"]   = ston("0xF090");	TYPE["OR"]   = TYPE_R2;
	OP["XOR"]  = ston("0xF0A0");	TYPE["XOR"]  = TYPE_R2;
	OP["MOV"]  = ston("0xF0B0");	TYPE["MOV"]  = TYPE_R2;
	OP["ADD"]  = ston("0xF0C0");	TYPE["ADD"]  = TYPE_R2;
	OP["SUB"]  = ston("0xF0D0");	TYPE["SUB"]  = TYPE_R2;

	OP["DATA"] = ston("0x0000");	TYPE["DATA"] = TYPE_D;

	RD["R0"]  = ston("0x0000");	RS["R0"]  = ston("0x0000");
	RD["R1"]  = ston("0x0100");	RS["R1"]  = ston("0x0001");
	RD["R2"]  = ston("0x0200");	RS["R2"]  = ston("0x0002");
	RD["R3"]  = ston("0x0300");	RS["R3"]  = ston("0x0003");
	RD["R4"]  = ston("0x0400");	RS["R4"]  = ston("0x0004");
	RD["R5"]  = ston("0x0500");	RS["R5"]  = ston("0x0005");
	RD["R6"]  = ston("0x0600");	RS["R6"]  = ston("0x0006");
	RD["R7"]  = ston("0x0700");	RS["R7"]  = ston("0x0007");
	RD["R8"]  = ston("0x0800");	RS["R8"]  = ston("0x0008");
	RD["R9"]  = ston("0x0900");	RS["R9"]  = ston("0x0009");
	RD["R10"] = ston("0x0A00");	RS["R10"] = ston("0x000A");
	RD["R11"] = ston("0x0B00");	RS["R11"] = ston("0x000B");
	RD["R12"] = ston("0x0C00");	RS["R12"] = ston("0x000C");
	RD["R13"] = ston("0x0D00");	RS["R13"] = ston("0x000D");
	RD["R14"] = ston("0x0E00");	RS["R14"] = ston("0x000E");
	RD["R15"] = ston("0x0F00");	RS["R15"] = ston("0x000F");
}

{
	Buffer[FNR] = $0;

	sub(/[#|;].*/, "");
	if ($1 ~ /:$/) {
		label[$1] = pc - ERROR;
	}
	sub(/.*:$/, "", $1);
	$0 = $0;
	if (NF != 0) {
		pc = pc + 2;
	}
}

END {
	pc = 0;
	for (Line = 1; Line <= FNR; Line++) {
		$0 = Buffer[Line];
		gsub(/[,()]/, " ");
		sub(/[#|;].*/, "");
		sub(/.*:$/, "", $1);
		$0 = $0;
		if (NF == 0) {
			continue;
		}

		pc += 2;

		sub(/NOP/, "J 0");
		sub(/HA?LT/, "J -2");
		sub(/JEZ/, "BEQZ");
		sub(/JNZ/, "BNEZ");
#		sub(/SHR/, "SRL");
#		sub(/SHL/, "SLL");
#		sub(/SLR/, "SRL");
#		sub(/SLL/, "SLL");
#		sub(/SAR/, "SRA");
#		sub(/SAL/, "SLA");
		sub(/SLA/, "SLL");
		op = toupper($1);

		if (TYPE[op] == TYPE_J) {		
			if (NF != 2) {
				error("Syntax error.");
			}
			if ($2 ~ /^[A-Za-z_]/) {
				code = limit(imm($2) - pc, 4096);
			} else {
				code = limit(imm($2), 4096);
			}
		} else if (TYPE[op] == TYPE_I1) {
			if (NF == 3) {
				code = rd($2) + limit(imm($3), 256);
			} else if ($3 ~ /(HIGH)|(high)/) {
				code = rd($2) + high(limit(imm($4), 65536));
			} else if ($3 ~ /(LOW)|(low)/) {
				code = rd($2) + low(limit(imm($4), 65536));
			} else {
				error("Syntax error.");
			}
		} else if (TYPE[op] == TYPE_I2) {
			if (NF != 3) {
				error("Syntax error.");
			}
			code = rd($2) + limit(ston($3), 16);
		} else if (TYPE[op] == TYPE_R1) {
			if (NF != 2) {
				error("Syntax error.");
			}
			code = rd($2);
		} else if (TYPE[op] == TYPE_R2) {
			if (NF != 3) {
				error("Syntax error.");
			}
			code = rd($2) + rs($3);
		} else if (TYPE[op] == TYPE_D) {
			if (NF != 2) {
				error("Syntax error.");
			}
			code = limit(imm($2), 65536);
		} else {
			error("Syntax error.");
		}

		if (pc % 16 == 2) {
			printf("%04X: %04X", pc - 2, OP[op] + code);
		} else if (pc % 16 == 0) {
			printf(" %04X\n", OP[op] + code);
		} else {
			printf(" %04X", OP[op] + code);
		}
	}
	printf("\n");
}

function error(s) {
	printf("! %s\n", s) > STDERR;
	printf("l.%d: %s\n", Line, Buffer[Line]) > STDERR;
	exit ERROR;
}

function imm(s, n) {
	if (s ~ /^[A-Za-z_]/) {
		if ((n = label[s":"] + ERROR) == ERROR) {
			error("Can't find the label.");
		}
	} else if (s ~ /^-/) {
		if ((n = strtol(substr(s, 2), 10)) == ERROR) {
			error("Irregular number.");
		}
		n = (-1) * n;
	} else {
		if ((n = ston(s)) == ERROR) {
			error("Irregular number.");
		}
	}
	return n;
}

function rd(s) {
	s = toupper(s);
	if (s !~ /^R(([0-9])|(1[0-5]))$/) {
		error("Syntax error.");
	}
	return RD[s];
}

function rs(s) {
	s = toupper(s);
	if (s !~ /^R(([0-9])|(1[0-5]))$/) {
		error("Syntax error.");
	}
	return RS[s];
}

function limit(n, max) {
	if (n < 0) {
		n += max;
	}
	if (n < 0 || n >= max) {
		error("Out of range.");
	}
	return n;
}

function high(n) {
	return int(n / 256);
}

function low(n) {
	return n - int(n / 256) * 256;
}

function ston(s, n) {
	if (sub(/^0[Xx]/, "", s)) {
		return strtol(s, 16);
	} else if (sub(/[Hh]$/, "", s)) {
		return strtol(s, 16);
	} else if (sub(/^0[Bb]/, "", s)) {
		return strtol(s, 2);
	} else if (sub(/[Bb]$/, "", s)) {
		return strtol(s, 2);
	} else if (sub(/^0[Oo]/, "", s)) {
		return strtol(s, 8);
	} else if (sub(/[Oo]$/, "", s)) {
		return strtol(s, 8);
	} else if (s ~ /^0/) {
		return strtol(s, 8);
	} else {
		return strtol(s, 10);
	}
}

# int strtol(string s, int base)
function strtol(s, base, n, c, i, j) {
	n = 0;
	for (i = 1; i <= length(s); i++) {
		c = toupper(substr(s, i, 1));
		j = index("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", c);
		if (j == 0 || j > base) {
			return ERROR;
		} else {
			n = n * base + j - 1;
		}
	}
	return n;
}
