#! /usr/bin/awk -f
#
#	create IOCS call interface from iocs.h
#
#	written by ITOH Yasufumi
#	public domain
#
#	$NetBSD: makeiocscalls.awk,v 1.3 2011/02/21 02:31:59 itohy Exp $

BEGIN {
	argsiz["l"] = 4; argsiz["w"] = 2
	argsiz["lb31"] = 4; argsiz["wb8"] = 2

	for (i = 0; i < 16; i++) {
		reg = substr("d0d1d2d3d4d5d6d7a0a1a2a3a4a5a6a7", i*2+1, 2)
		regno[reg] = i
	}
	print "#include <machine/asm.h>"
}

$1 == "/*" && ($2 ~ /^[0-9a-f][0-9a-f]$/ || $2 == "(none)") {
	funcnam=""
	iocsno=$2
	ptrval=0
	narg=0
	retd2=0
	err_d0=0
	noret=0
	c_md=0
	b_super=0
	sp_regst=0
	b_curmod = 0
	b_curpat = 0
	b_scroll = 0
	iocs_trap15=0
	for (i = 3; i <= NF && $i != "*/" && $i != ";"; i++) {
		arg[narg] = $i
		narg++
	}
	if ($i == ";") {
		# process opts
		for (i++; i <= NF && $i != "*/"; i++) {
			if ($i == "retd2")
				retd2 = 1
			else if ($i == "err_d0")
				err_d0 = 1
			else if ($i == "noret")
				noret = 1
			else if ($i == "c_md")
				c_md = 1
			else if ($i == "b_super")
				b_super = 1
			else if ($i == "sp_regst")
				sp_regst = 1
			else if ($i == "b_curmod")
				b_curmod = 1
			else if ($i == "b_curpat")
				b_curpat = 1
			else if ($i == "b_scroll")
				b_scroll = 1
			else if ($i == "trap15")
				iocs_trap15 = 1
			else {
				print FILENAME ":" NR ": unknown opt", $i
				exit(1)
			}
		}
	}
	if ($i != "*/") {
		print FILENAME ":" NR ": malformed input line:" $0
		exit(1)
	}

	# find out func name
	printf "|"
	for (i++; i <= NF; i++) {
		printf " %s", $i
		if ($i ~ /^\**IOCS_[A-Z0-9_]*$/) {
			funcnam = $i
			while (funcnam ~ /^\*/) {
				funcnam = substr(funcnam, 2, length(funcnam) -1)
				ptrval = 1
			}
		}
	}
	print ""
	if (!funcnam) {
		print FILENAME ":" NR ": can't find function name"
		exit(1)
	}

	# output assembly code
	print "ENTRY_NOPROFILE(" funcnam ")"

	# SAVE REGISTERS
	for (i = 0; i < 16; i++) {
		savereg[i] = 0
	}
	for (i = 0; i < narg; i++) {
		r = arg[i]
		if (r ~ /^o[ad][0-7]$/)
			r = substr(r, 2, 2)
		else if (r ~ /^d[0-7]=/)
			r = substr(r, 1, 2)
		if (r != "d0" && !regno[r]) {
			print FILENAME ":" NR ": unknown arg type:", arg[i]
			exit(1)
		}
		if (r !~ /^[da][01]$/)		# may not be saved
			savereg[regno[r]] = r
	}
	# count reg to save
	nsave = 0
	for (i = 0; i < 16; i++) {
		if (savereg[i])
			nsave++
	}

	if (iocs_trap15) {
		print "\tmoveml\t%d2-%d7/%a2-%a6,%sp@-"
		nsave = 11
	} else if (nsave == 1 || nsave == 2){
		# use movel
		for (i = 0; i < 16; i++) {
			if (savereg[i])
				print "\tmovel\t%" savereg[i] ",%sp@-"
		}
	} else if (nsave > 2) {
		# use moveml
		saveregs = ""
		for (i = 0; i < 16; i++) {
			if (savereg[i])
				saveregs = saveregs "/%" savereg[i]
		}
		saveregs = substr(saveregs, 2, length(saveregs) - 1)
		print "\tmoveml\t" saveregs ",%sp@-"
	}

	# LOAD ARGS
	# XXX this should be more intelligent
	argoff = nsave * 4 + 4
	# input arguments for IOCS call
	iarg = ""
	iargreglist = ""
	niarg = 0
	iarg_incorder = 1
	immarg = ""
	nimmarg = 0
	for (i = 0; i < narg && arg[i] ~ /^[ad]/; i++) {
		a = arg[i]
		if (a ~ /^d[1-7]=[0-9][0-9]*$/) {
			immarg = immarg " " a
			nimmarg++
		} else {
			if (iarg) {
				if (regno[a1] >= regno[a])
					iarg_incorder = 0
			}
			a1 = a
			iarg = iarg "/" a
			iargreglist = iargreglist "/%" a
			niarg++
		}
	}
	oarg = ""
	noarg = 0
	for ( ; i < narg; i++) {
		if (arg[i] ~ /^[o]d[0-7]/) {
			oarg = oarg " " arg[i]
			noarg++
		} else {
			print "unknown arg:", arg[i]
			exit(1)
		}
	}
	# remove leading char
	iarg = substr(iarg, 2, length(iarg) - 1);
	iargreglist = substr(iargreglist, 2, length(iargreglist) - 1);
	immarg = substr(immarg, 2, length(immarg) - 1);
	oarg = substr(oarg, 2, length(oarg) - 1);
	# load input args
	if (niarg == 0)
		;
	else if (niarg == 1 && iarg !~ /\=/) {
		print "\tmovel\t%sp@(" argoff "),%" iarg	"\t| 1arg"
	} else if (iarg_incorder && iarg !~ /\=/) {
		print "\tmoveml\t%sp@(" argoff ")," iargreglist	"\t| inc order"
	} else if (iarg == "a1/d1") {
		print "\tmoveal\t%sp@(" argoff "),%a1"
		print "\tmovel\t%sp@(" argoff + 4 "),%d1"
	} else if (iarg == "d1/a1/d2") {
		print "\tmoveml\t%sp@(" argoff "),%d1-%d2/%a1"
		print "\texg\t%d2,%a1"
	} else if (iarg == "a1/a2/d1") {
		print "\tmoveml\t%sp@(" argoff "),%a1/%a2"
		print "\tmovel\t%sp@(" argoff + 8 "),%d1"
	} else if (iarg == "a1/a2/d1/d2") {
		print "\tmoveml\t%sp@(" argoff "),%d1-%d2/%a1-%a2"
		print "\texg\t%d1,%a1"
		print "\texg\t%d2,%a2"
	} else if (iarg == "a1/d1/d2") {
		print "\tmoveml\t%sp@(" argoff "),%d0-%d2"
		print "\tmovel\t%d0,%a1"
	} else if (iarg == "d1=bb") {
		print "\tmoveq\t#0,%d1"
		print "\tmoveb\t%sp@(" argoff + 3 "),%d1"
		print "\tlslw\t#8,%d1"
		print "\tmoveb\t%sp@(" argoff + 7 "),%d1"
		niarg = 2
	} else if (iarg == "d1=ww") {
		print "\tmovew\t%sp@(" argoff + 2 "),%d1"
		print "\tswap\t%d1"
		print "\tmovew\t%sp@(" argoff + 6 "),%d1"
		niarg = 2
	} else if (iarg == "d1=hsv") {
		print "\tmoveb\t%sp@(" argoff + 3 "),%d1"
		print "\tswap\t%d1"
		print "\tmoveb\t%sp@(" argoff + 7 "),%d1"
		print "\tlslw\t#8,%d1"
		print "\tmoveb\t%sp@(" argoff + 11 "),%d1"
		print "\tandl\t#0x00ff1f1f,%d1"
		niarg = 3
	} else if (iarg == "a1/d1=bb") {
		print "\tmoveal\t%sp@(" argoff "),%a1"
		print "\tmoveq\t#0,%d1"
		print "\tmoveb\t%sp@(" argoff + 7 "),%d1"
		print "\tlslw\t#8,%d1"
		print "\tmoveb	%sp@(" argoff + 11 "),%d1"
		niarg = 3
	} else if (iarg == "d1/d2=ww") {
		print "\tmovel\t%sp@(" argoff "),%d1"
		print "\tmovew\t%sp@(" argoff + 6 "),%d2"
		print "\tswap\t%d2"
		print "\tmovew\t%sp@(" argoff + 10 "),%d2"
		niarg = 3
	} else if (iarg == "d1=ww/a1") {
		print "\tmoveml\t%sp@(" argoff "),%d0-%d1/%a1"
		print "\tswap\t%d1"
		print "\tmovew\t%d0,%d1"
		print "\tswap\t%d1"
		niarg = 3
	} else if (iarg == "d1=ww/d2=ww") {
		print "\tmoveml\t%sp@(" argoff "),%d1-%d2"
		print "\tswap\t%d1"
		print "\tmovew\t%d2,%d1"
		print "\tmovew\t%sp@(" argoff + 10 "),%d2"
		print "\tswap\t%d2"
		print "\tmovew\t%sp@(" argoff + 14 "),%d2"
		niarg = 4
	} else {
		print "unsupported iarg:", iarg
		exit(1)
	}
	argoff += niarg * 4

	if (sp_regst) {
		print "\tandl\t#0x80000000,%d1"
		print "\tmoveb\t%d0,%d1"
	}

	if (b_curmod) {
		print "\tmoveq\t#1,%d0"
		print "\tcmpl\t%d1,%d0"
#		print "\tbcss\tLerr"
		print "\tbcss\t6f"
	}

	if (b_curpat) {
		print "\ttstw\t%d2"
#		print "\tbeqs\tLerr"
		print "\tbeqs\t6f"
	}

	if (b_super) {
		print "\tmoval\t%sp@+,%a0"
		print "\tmoval\t%sp@,%a1"
	}

	# load imm args
	if (nimmarg) {
		for (i = 0; i < narg && arg[i] ~ /^[ad]/; i++) {
			a = arg[i]
			if (a ~ /^d[1-7]=[0-9][0-9]*$/) {
				r = substr(a, 1, 2)
				v = substr(a, 4, length(a)-3)
				print "\tmoveq\t#" v ",%" r
			}
		}
	}

	if (c_md) {
		# -1: flush(3), -2: set default(2), other: set by the value(4)
		print "\tmovel\t%d2,%d0"
		print "\taddql\t#1,%d0"
		print "\tbeqs\tLcachemd"
		print "\tmoveq\t#2,%d1"
		print "\taddql\t#1,%d0"
		print "\tbnes\tLcachemd"
		print "\tmoveq\t#4,%d1"
		print "Lcachemd:"
	}

	if (b_scroll) {
		# d1 has 16
		print "\tcmpl\t%d1,%d2"
		print "\tbcss\tLscriocs"
		print "\tmovel\t%d2,%d1"
		print "Lscriocs:"
	}

	if (iocs_trap15) {
		print "\tmoveal\t%sp@(" argoff "),%a0	| inregs"
		print "\tmoveml\t%a0@,%d0-%d7/%a1-%a6"
		argoff += 4
	}

	if (iocsno != "(none)") {
		if (iocsno ~ /^[89abcdef]./)
			iocsno = "ffffff" iocsno
		print "\tmoveq\t#0x" iocsno ",%d0"
	}
	print "\ttrap\t#15"

	if (iocs_trap15) {
		print "\tmoveal\t%sp@(" argoff "),%a0	| outregs"
		print "\tmoveml\t%d0-%d7/%a1-%a6,%a0@"
	}

	if (err_d0 && noarg) {
		print "\ttstl\t%d0"
#		print "\tbnes\tLerr"
		print "\tbnes\t6f"
	}

	# SAVERESULTS
	# XXX this should be more intelligent
	if (noarg == 0)
		;
	else if (oarg == "od2") {
		print "\tmoveal\t%sp@(" argoff "),%a0"
		argoff += 4
		print "\tmovel\t%d2,%a0@"
	} else if (oarg == "od1 od2 od0") {
		print "\tmoveml\t%sp@(" argoff "),%a0/%a1"
		argoff += 8
		print "\tmovel\t%d1,%a0@"
		print "\tmovel\t%d2,%a1@"
		print "\tmoveal\t%sp@(" argoff "),%a0"
		argoff += 4
		print "\tmovel\t%d0,%a0@"
	} else if (oarg == "od2 od3") {
		print "\tmoveml\t%sp@(" argoff "),%a0/%a1"
		argoff += 8
		print "\tmovel\t%d2,%a0@"
		print "\tmovel\t%d3,%a1@"
	} else if (oarg == "od2 od3 od4 od5") {
		print "\tmoveml\t%sp@(" argoff "),%a0/%a1"
		argoff += 8
		print "\tmovel\t%d2,%a0@"
		print "\tmovel\t%d3,%a1@"
		print "\tmoveml\t%sp@(" argoff "),%a0/%a1"
		argoff += 8
		print "\tmovel\t%d4,%a0@"
		print "\tmovel\t%d5,%a1@"
	} else {
		print "unsupported oarg:", oarg
		exit(1)
	}

	if ((err_d0 && noarg) || b_curmod || b_curpat)
#		print "Lerr:"
		print "6:"

	# return value
	if (retd2)
		print "\tmovel\t%d2,%d0"

	# RESTORE REGISTERS
	if (iocs_trap15) {
		print "\tmoveml\t%sp@+,%d2-%d7/%a2-%a6"
	} else if (nsave == 1 || nsave == 2){
		# use movel
		for (i = 16 - 1; i >= 0; i--) {
			if (savereg[i])
				print "\tmovel\t%sp@+,%" savereg[i]
		}
	} else if (nsave > 2) {
		# use moveml
		print "\tmoveml\t%sp@+," saveregs
	}


	if (b_super)
		print "\tjmp\t%a0@"
	else if (!noret) {
		if (ptrval)
			print "#ifdef __SVR4_ABI__\n\tmoveal\t%d0,%a0\n#endif"
		print "\trts"
	}
}
