/* $Id$ */
/* Copyright (c) 2011-2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Devel Asm */
/* This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. */



/* generic */
/* registers */
#define OP_RD		AO_REGISTER(0, 32, 0)

/* conditional branching */
/* opcodes */
#define bn		0x0
#define be		0x1
#define bz		be
#define ble		0x2
#define bl		0x3
#define bleu		0x4
#define blu		0x5
#define bneg		0x6
#define ba		0x8
#define bne		0x9
#define bnz		bne
#define bg		0xa
#define bge		0xb
#define bgu		0xc
#define bgeu		0xd
#define bcc		bgeu
/* flags */
#define OPCBF		(32 << AOD_SIZE)
/* helpers */
#define OPCB(opcode)	(opcode << 25 | 0x2 << 22)
#define OPCB_U22	AO_IMMEDIATE(0, 21, 0)

/* integer arithmetic */
/* opcodes */
#define add		0x0
#define and		0x1
#define or		0x2
#define xor		0x3
#define sub		0x4
#define andn		0x5
#define orn		0x6
#define xnor		0x7
#define umul		0xa
#define smul		0xb
#define udiv		0xe
#define sdiv		0xf
#define addcc		(0x10 | add)
#define andcc		(0x10 | and)
#define orcc		(0x10 | or)
#define xorcc		(0x10 | xor)
#define subcc		(0x10 | sub)
#define andncc		(0x10 | andn)
#define orncc		(0x10 | orn)
#define xnorcc		(0x10 | xnor)
#define umulcc		(0x10 | umul)
#define smulcc		(0x10 | smul)
#define udivcc		(0x10 | udiv)
#define sdivcc		(0x10 | sdiv)
/* flags */
#define OPIA1F		(32 << AOD_SIZE)
#define OPIA2F		(32 << AOD_SIZE)
/* registers */
#define OPIA_RS1	AO_REGISTER(0, 32, 0)
#define OPIA_RS2	AO_REGISTER(0, 32, 0)
/* helpers */
#define OPIA1(opcode)	(0x80000000 | opcode << 19)
#define OPIA2(opcode)	(0x80000000 | opcode << 19 | 0x1 << 13)
#define OPIA_S12	AO_IMMEDIATE(AOF_SIGNED, 12, 0)
#define OPIA_U12	AO_IMMEDIATE(AOF_SIGNED, 12, 0)

/* load store */
/* opcodes */
#define ld		0x0
#define ldub		0x1
#define lduh		0x2
#define ldd		0x3
#define st		0x4
#define stb		0x5
#define sth		0x6
#define std		0x7
#define ldsb		0x9
#define ldsh		0xa
/* flags */
#define OPLS1F		(32 << AOD_SIZE)
#define OPLS2F		(32 << AOD_SIZE)
/* registers */
#define OPLS_RS1	AO_DREGISTER(0, 12, 32, 0)
#define OPLS_RS1D	AO_DREGISTER(0, 0, 32, 0)
#define OPLS_RS12	AO_DREGISTER2(0, 32, 32, 0)
/* helpers */
#define OPLS1(opcode)	(0xc0000000 | (opcode << 19))
#define OPLS2(opcode)	(0xc0000000 | (opcode << 19) | (0x1 << 13))

/* sethi */
/* opcodes */
#define sethi		0x4
/* flags */
#define OPSHF		(32 << AOD_SIZE)
/* helpers */
#define OPSH(opcode)	(opcode << 22)
#define OPSH_U21	AO_IMMEDIATE(0, 32, 0)


/* instructions */
{ "add",	OPIA1(add),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "add",	OPIA2(add),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "addcc",	OPIA1(addcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "addcc",	OPIA2(addcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "and",	OPIA1(and),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "and",	OPIA2(and),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "andcc",	OPIA1(andcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "andcc",	OPIA2(andcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "andn",	OPIA1(andn),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "andn",	OPIA2(andn),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "andncc",	OPIA1(andncc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "andncc",	OPIA2(andncc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "ba",		OPCB(ba),	OPCBF,	AO_1(OPCB_U22)			},
{ "be",		OPCB(be),	OPCBF,	AO_1(OPCB_U22)			},
{ "bg",		OPCB(bg),	OPCBF,	AO_1(OPCB_U22)			},
{ "bge",	OPCB(bge),	OPCBF,	AO_1(OPCB_U22)			},
{ "bgeu",	OPCB(bgeu),	OPCBF,	AO_1(OPCB_U22)			},
{ "bl",		OPCB(bl),	OPCBF,	AO_1(OPCB_U22)			},
{ "ble",	OPCB(ble),	OPCBF,	AO_1(OPCB_U22)			},
{ "blu",	OPCB(blu),	OPCBF,	AO_1(OPCB_U22)			},
{ "bn",		OPCB(bn),	OPCBF,	AO_1(OPCB_U22)			},
{ "bne",	OPCB(bne),	OPCBF,	AO_1(OPCB_U22)			},
{ "bneg",	OPCB(bneg),	OPCBF,	AO_1(OPCB_U22)			},
{ "bnz",	OPCB(bnz),	OPCBF,	AO_1(OPCB_U22)			},
{ "bz",		OPCB(bz),	OPCBF,	AO_1(OPCB_U22)			},
{ "ld",		OPLS1(ld),	OPLS1F,	AO_2(OPLS_RS1, OP_RD)		},
{ "ld",		OPLS1(ld),	OPLS1F,	AO_2(OPLS_RS12, OP_RD)		},
{ "ldd",	OPLS1(ldd),	OPLS1F,	AO_2(OPLS_RS1, OP_RD)		},
{ "ldd",	OPLS1(ldd),	OPLS1F,	AO_2(OPLS_RS12, OP_RD)		},
{ "ldsb",	OPLS1(ldsb),	OPLS1F,	AO_2(OPLS_RS1, OP_RD)		},
{ "ldsb",	OPLS1(ldsb),	OPLS1F,	AO_2(OPLS_RS12, OP_RD)		},
{ "ldsh",	OPLS1(ldsh),	OPLS1F,	AO_2(OPLS_RS1, OP_RD)		},
{ "ldsh",	OPLS1(ldsh),	OPLS1F,	AO_2(OPLS_RS12, OP_RD)		},
{ "ldub",	OPLS1(ldub),	OPLS1F,	AO_2(OPLS_RS1D, OP_RD)		},
{ "ldub",	OPLS1(ldub),	OPLS1F,	AO_2(OPLS_RS12, OP_RD)		},
{ "lduh",	OPLS1(lduh),	OPLS1F,	AO_2(OPLS_RS1,OP_RD)		},
{ "lduh",	OPLS1(lduh),	OPLS1F,	AO_2(OPLS_RS12, OP_RD)		},
{ "nop",	OPSH(sethi),	OPSHF,	AO_0()				},
{ "or",		OPIA1(or),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "or",		OPIA2(or),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "orcc",	OPIA1(orcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "orcc",	OPIA2(orcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "orn",	OPIA1(orn),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "orn",	OPIA2(orn),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "orncc",	OPIA1(orncc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "orncc",	OPIA2(orncc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "sdiv",	OPIA1(sdiv),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "sdiv",	OPIA2(sdiv),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "sdivcc",	OPIA1(sdivcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "sdivcc",	OPIA2(sdivcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "sethi",	OPSH(sethi),	OPSHF,	AO_2(OPSH_U21, OP_RD)		},
{ "smul",	OPIA1(smul),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "smul",	OPIA2(smul),	OPIA2F, AO_3(OPIA_RS1, OPIA_S12, OP_RD)	},
{ "smulcc",	OPIA1(smulcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "smulcc",	OPIA2(smulcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_S12, OP_RD)	},
{ "st",		OPLS1(st),	OPLS1F,	AO_2(OP_RD, OPLS_RS1)		},
{ "st",		OPLS1(st),	OPLS1F,	AO_2(OP_RD, OPLS_RS12)		},
{ "stb",	OPLS1(stb),	OPLS1F,	AO_2(OP_RD, OPLS_RS1)		},
{ "stb",	OPLS1(stb),	OPLS1F,	AO_2(OP_RD, OPLS_RS12)		},
{ "std",	OPLS1(std),	OPLS1F,	AO_2(OP_RD, OPLS_RS1)		},
{ "std",	OPLS1(std),	OPLS1F,	AO_2(OP_RD, OPLS_RS12)		},
{ "sth",	OPLS1(sth),	OPLS1F,	AO_2(OP_RD, OPLS_RS1)		},
{ "sth",	OPLS1(sth),	OPLS1F,	AO_2(OP_RD, OPLS_RS12)		},
{ "sub",	OPIA1(sub),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "subcc",	OPIA1(subcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "udiv",	OPIA1(udiv),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "udiv",	OPIA2(udiv),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "udivcc",	OPIA1(udivcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "udivcc",	OPIA2(udivcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "umul",	OPIA1(umul),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "umul",	OPIA2(umul),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "umulcc",	OPIA1(umulcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "umulcc",	OPIA2(umulcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "xnor",	OPIA1(xnor),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "xnor",	OPIA2(xnor),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "xnorcc",	OPIA1(xnorcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "xnorcc",	OPIA2(xnorcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "xor",	OPIA1(xor),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "xor",	OPIA2(xor),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
{ "xorcc",	OPIA1(xorcc),	OPIA1F, AO_3(OPIA_RS1, OPIA_RS2, OP_RD)	},
{ "xorcc",	OPIA2(xorcc),	OPIA2F, AO_3(OPIA_RS1, OPIA_U12, OP_RD)	},
