mips/lib/mips1.c

571 lines
14 KiB
C

#include <mips1.h>
#define RTYPE "rd,rs,rt"
#define ITYPE "rt,rs,immd"
#define JTYPE "target"
#define LOAD "rt,offset(base)"
#define SHIFT "rd,rt,sa"
#define SHIFTV "rd,rt,rs"
#define BRANCH "rs,rt,offset"
#define BRANCHZ "rs,offset"
#define TRAP "rs,rt"
#define TRAPI "rs,immd"
#define INS(name, grammer) {#name, grammer, MIPS1_INS_ ##name, \
/* pseudo stub */ 0, {{0, ""}}}
#define PSEUDO(name, grammer, ...) {name, grammer, __MIPS1_INS_NULL, \
__VA_ARGS__ }
struct mips32_grammer mips1_grammers[__MIPS1_GRAMMER_LEN] = {
// real instructions
INS(ADD, RTYPE),
INS(ADDI, ITYPE),
INS(ADDIU, ITYPE),
INS(ADDU, RTYPE),
INS(AND, RTYPE),
INS(ANDI, ITYPE),
INS(BC1F, "cc,offset"),
INS(BC1T, "cc,offset"),
INS(BEQ, BRANCH),
INS(BGEZ, BRANCHZ),
INS(BGEZAL, BRANCHZ),
INS(BGTZ, BRANCHZ),
INS(BLEZ, BRANCHZ),
INS(BLTZAL, BRANCHZ),
INS(BLTZ, BRANCHZ),
INS(BNE, BRANCHZ),
INS(BREAK, "code"),
INS(CLO, "rd,rs"),
INS(CLZ, "rd,rs"),
INS(DIV, "rs,rt"),
INS(DIVU, "rs,rt"),
INS(ERET, ""),
INS(J, JTYPE),
INS(JAL, JTYPE),
INS(JALR, "rs"),
INS(JR, "rs"),
INS(LB, LOAD),
INS(LBU, LOAD),
INS(LH, LOAD),
INS(LHU, LOAD),
INS(LL, LOAD),
INS(LUI, "rt,immd"),
INS(LW, LOAD),
INS(LWC1, "ft,base(offset)"),
INS(LWL, LOAD),
INS(LWR, LOAD),
INS(MADD, "rs,rt"),
INS(MADDU, "rs,rt"),
INS(MFC0, "rt,rd"),
INS(MFC1, "rt,fs"),
INS(MFHI, "rd"),
INS(MFLO, "rd"),
INS(MOVN, RTYPE),
INS(MOVZ, RTYPE),
INS(MSUB, "rs,rt"),
INS(MSUBU, "rs,rt"),
INS(MTC0, "rd,rt"),
INS(MTC1, "rd,fs"),
INS(MTHI, "rs"),
INS(MTLO, "rs"),
INS(MUL, RTYPE),
INS(MULT, "rs,rt"),
INS(MULTU, "rs,rt"),
INS(NOR, "rs,rt"),
INS(OR, RTYPE),
INS(ORI, ITYPE),
INS(SB, LOAD),
INS(SC, LOAD),
INS(SDC1, "ft,base(offset)"),
INS(SH, LOAD),
INS(SLL, SHIFT),
INS(SLLV, SHIFTV),
INS(SLT, RTYPE),
INS(SLTI, ITYPE),
INS(SLTIU, ITYPE),
INS(SLTU, RTYPE),
INS(SRA, SHIFT),
INS(SRAV, SHIFTV),
INS(SRL, SHIFT),
INS(SRLV, SHIFTV),
INS(SUB, RTYPE),
INS(SUBU, RTYPE),
INS(SW, LOAD),
INS(SWC1, "ft,base(offset)"),
INS(SWL, LOAD),
INS(SWR, LOAD),
INS(SYSCALL, ""),
INS(TEQ, TRAP),
INS(TEQI, TRAPI),
INS(TGE, TRAP),
INS(TGEI, TRAPI),
INS(TGEIU, TRAPI),
INS(TGEU, TRAP),
INS(TLT, TRAP),
INS(TLTI, TRAPI),
INS(TLTIU, TRAPI),
INS(TLTU, TRAP),
INS(TNE, TRAP),
INS(TNEI, TRAPI),
INS(XOR, RTYPE),
INS(XORI, ITYPE),
// pseudo instructions
PSEUDO("abs", "rd,rs", 3, {
{MIPS1_INS_SRA, "rd=$at,rt=rs,sa=31"},
{MIPS1_INS_ADD, "rd,rs,rt=$at"},
{MIPS1_INS_XOR, "rd,rs=rd,rt=$at"},
}),
PSEUDO("div", "rd,rt,rs", 2, {
{MIPS1_INS_DIV, "rt,rs"},
{MIPS1_INS_MFLO, "rd"},
}),
PSEUDO("divu", "rd,rt,rs", 2, {
{MIPS1_INS_DIVU, "rt,rs"},
{MIPS1_INS_MFLO, "rd"},
}),
PSEUDO("mulo", "rd,rt,rs", 2, {
{MIPS1_INS_MULT, "rt,rs"},
{MIPS1_INS_MFLO, "rd"},
}),
PSEUDO("mulou", "rd,rt,rs", 2, {
{MIPS1_INS_MULTU, "rt,rs"},
{MIPS1_INS_MFLO, "rd"},
}),
PSEUDO("neg", "rd,rt", 1, {
{MIPS1_INS_SUB, "rd,rs=$zero,rt"},
}),
PSEUDO("negu", "rd,rt", 1, {
{MIPS1_INS_SUBU, "rd,rs=$zero,rt"},
}),
PSEUDO("not", "rd,rt", 1, {
{MIPS1_INS_NOR, "rd,rs=$zero,rt"},
}),
PSEUDO("rem", "rd,rt,rs", 2, {
{MIPS1_INS_DIV, "rt,rs"},
{MIPS1_INS_MFHI, "rd"},
}),
PSEUDO("remu", "rd,rt,rs", 2, {
{MIPS1_INS_DIVU, "rt,rs"},
{MIPS1_INS_MFHI, "rd"},
}),
// TODO: rol
// TODO: ror
PSEUDO("subi", "rt,rs,immd", 1, {
{MIPS1_INS_ADDI, "rt,rs,-immd"},
}),
PSEUDO("li", "rt,immd", 1, {
{MIPS1_INS_ADDI, "rt,immd"}
}),
PSEUDO("seq", "rd,rs,rt", 3, {
{MIPS1_INS_SLT, "rd,rs,rt"},
{MIPS1_INS_SLT, "rd=$at,rs,rt"},
{MIPS1_INS_NOR, "rd,rs=rd,rt=$at"},
}),
PSEUDO("sgt", "rd,rs,rt", 1, {
{MIPS1_INS_SLT, "rd,rs=rt,rt=rs"},
}),
PSEUDO("sgtu", "rd,rs,rt", 1, {
{MIPS1_INS_SLTU, "rd,rs=rt,rt=rs"},
}),
PSEUDO("sge", "rd,rs,rt", 2, {
{MIPS1_INS_SLT, "rd,rs,rt"},
{MIPS1_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("sgeu", "rd,rs,rt", 2, {
{MIPS1_INS_SLTU, "rd,rs,rt"},
{MIPS1_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("slte", "rd,rs,rt", 2, {
{MIPS1_INS_SLT, "rd,rs=rt,rt=rs"},
{MIPS1_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("slteu", "rd,rs,rt", 2, {
{MIPS1_INS_SLTU, "rd,rs=rt,rt=rs"},
{MIPS1_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("sne", "rd,rs,rt", 3, {
{MIPS1_INS_SLT, "rd,rs,rt"},
{MIPS1_INS_SLT, "rd=$at,rs,rt"},
{MIPS1_INS_OR, "rd,rs=rd,rt=$at"},
}),
PSEUDO("b", "offset", 1, {
{MIPS1_INS_BEQ, "rs=$zero,rt=$zero,offset"},
}),
PSEUDO("beqz", "rs,offset", 1, {
{MIPS1_INS_BEQ, "rs,rt=$zero,offset"},
}),
PSEUDO("bge", "rs,rt,offset", 2, {
{MIPS1_INS_SLT, "rd=$at,rs,rt"},
{MIPS1_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bgeu", "rs,rt,offset", 2, {
{MIPS1_INS_SLTU, "rd=$at,rs,rt"},
{MIPS1_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bge", "rs,rt,offset", 2, {
{MIPS1_INS_SLT, "rd=$at,rs,rt"},
{MIPS1_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bgeu", "rs,rt,offset", 2, {
{MIPS1_INS_SLTU, "rd=$at,rs,rt"},
{MIPS1_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("ble", "rs,rt,offset", 2, {
{MIPS1_INS_SLT, "rd=$at,rs=rt,rt=rs"},
{MIPS1_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bleu", "rs,rt,offset", 2, {
{MIPS1_INS_SLT, "rd=$at,rs=rt,rt=rs"},
{MIPS1_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("blt", "rs,rt,offset", 2, {
{MIPS1_INS_SLT, "rd=$at,rs,rt"},
{MIPS1_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bltu", "rs,rt,offset", 2, {
{MIPS1_INS_SLTU, "rd=$at,rs,rt"},
{MIPS1_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bnez", "rs,offset", 1, {
{MIPS1_INS_BNE, "rs,rt=$zero,offset"},
}),
// TODO: ld
// TODO: load unaligned
// TODO: store unaligned
PSEUDO("la", "rt,target", 2, {
{MIPS1_INS_LUI, "rt=$at,hi"},
{MIPS1_INS_ORI, "rt,rs=$at,lo"},
}),
PSEUDO("move", "rd,rs", 1, {
{MIPS1_INS_OR, "rd,rs"}
}),
PSEUDO("nop", "", 1, {
{MIPS1_INS_SLL, ""},
}),
};
#define MIPS_INS(ins, ...) \
[MIPS1_INS_ ##ins] = { __VA_ARGS__ },
union mips32_instruction mips1_instructions[__MIPS1_INS_LEN] = {
/* ADD - add */
MIPS_INS(ADD, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_ADD)
/* ADDI - add immediate */
MIPS_INS(ADDI, .op = MIPS1_OP_ADDI)
/* ADDIU - add immediate unsigned */
MIPS_INS(ADDIU, .op = MIPS1_OP_ADDIU)
/* ADDU - add unsigned */
MIPS_INS(ADDU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_ADDU)
/* AND - and */
MIPS_INS(AND, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_AND)
/* ANDI - and immediate */
MIPS_INS(ANDI, .op = MIPS1_OP_ANDI)
/* BC1F - branch on coprocessor 1 false */
MIPS_INS(BC1F, .op = MIPS1_OP_COP1, .cfunct = MIPS1_FUNCT_BC, .tf = 0)
/* BC1T - branch on coprocessor 1 true */
MIPS_INS(BC1T, .op = MIPS1_OP_COP1, .cfunct = MIPS1_FUNCT_BC, .tf = 1)
/* BEQ - branch on equal */
MIPS_INS(BEQ, .op = MIPS1_OP_BEQ)
/* BGEZ - branch on greater than or equal to zero */
MIPS_INS(BGEZ, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_BGEZ)
/* BGEZAL - branch on greater than or equal to zero and link */
MIPS_INS(BGEZAL, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_BGEZAL)
/* BGTZ - branch on greater than zero */
MIPS_INS(BGTZ, .op = MIPS1_OP_BGTZ)
/* BLEZ - branch on less than or equal to zero */
MIPS_INS(BLEZ, .op = MIPS1_OP_BLEZ)
/* BLTZAL - branch on less than zero and link */
MIPS_INS(BLTZAL, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_BLTZAL)
/* BLTZ - branch on less than zero */
MIPS_INS(BLTZ, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_BLTZ)
/* BNE - branch on not equal */
MIPS_INS(BNE, .op = MIPS1_OP_BNE)
/* BREAK - break */
MIPS_INS(BREAK, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_BREAK)
/* CLO - count loading zeros */
MIPS_INS(CLO, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_CLO)
/* CLZ - count loading zeros */
MIPS_INS(CLZ, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_CLZ)
/* DIV - divide */
MIPS_INS(DIV, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_DIV)
/* DIVU - divide unsigned */
MIPS_INS(DIVU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_DIVU)
/* ERET - exception return */
MIPS_INS(ERET, .op = MIPS1_OP_COP0, .c0 = 1, .funct = MIPS1_FUNCT_ERET)
/* J - jump */
MIPS_INS(J, .op = MIPS1_OP_J)
/* JAL - jump and link */
MIPS_INS(JAL, .op = MIPS1_OP_JAL)
/* JALR - jump and link register */
MIPS_INS(JALR, .rd = MIPS32_REG_RA, .op = MIPS1_OP_SPECIAL,
.funct = MIPS1_FUNCT_JALR)
/* JR - jump register */
MIPS_INS(JR, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_JR)
/* LB - load byte */
MIPS_INS(LB, .op = MIPS1_OP_LB)
/* LBU - load byte unsigned */
MIPS_INS(LBU, .op = MIPS1_OP_LBU)
/* LH - load half */
MIPS_INS(LH, .op = MIPS1_OP_LH)
/* LHU - load half unsigned */
MIPS_INS(LHU, .op = MIPS1_OP_LHU)
/* LL - load linked */
MIPS_INS(LL, .op = MIPS1_OP_LL)
/* LUI - load upper immediate */
MIPS_INS(LUI, .op = MIPS1_OP_LUI)
/* LW - load word */
MIPS_INS(LW, .op = MIPS1_OP_LW)
/* LWC1 - load word cop1 */
MIPS_INS(LWC1, .op = MIPS1_OP_LWC1)
/* LWL - load word left */
MIPS_INS(LWL, .op = MIPS1_OP_LWL)
/* LWR - load word right */
MIPS_INS(LWR, .op = MIPS1_OP_LWR)
/* MADD - multiply add */
MIPS_INS(MADD, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_MADD)
/* MADDU - multiply add unsigned */
MIPS_INS(MADDU, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_MADDU)
/* MFC0 - move from cop0 */
MIPS_INS(MFC0, .op = MIPS1_OP_COP0, .cfunct = MIPS1_FUNCT_MF)
/* MFC1 - move from cop1 */
MIPS_INS(MFC1, .op = MIPS1_OP_COP1, .cfunct = MIPS1_FUNCT_MF)
/* MFHI - move from hi */
MIPS_INS(MFHI, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MFHI)
/* MFLO - move from low */
MIPS_INS(MFLO, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MFLO)
/* MOVN - move conditional not zero */
MIPS_INS(MOVN, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MOVN)
/* MOVZ - move conditional zero */
MIPS_INS(MOVZ, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MOVZ)
/* MSUB - multiply subtract */
MIPS_INS(MSUB, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_MSUB)
/* MSUBU - multiply subtract unsigned */
MIPS_INS(MSUBU, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_MSUBU)
/* MTC0 - move from cop0 */
MIPS_INS(MTC0, .op = MIPS1_OP_COP0, .cfunct = MIPS1_FUNCT_MT)
/* MTC1 - move from cop1 */
MIPS_INS(MTC1, .op = MIPS1_OP_COP1, .cfunct = MIPS1_FUNCT_MT)
/* MTHI - move to hi */
MIPS_INS(MTHI, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MTHI)
/* MTLO - move to low */
MIPS_INS(MTLO, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MTLO)
/* MUL - multiply */
MIPS_INS(MUL, .op = MIPS1_OP_SPECIAL2, .funct = MIPS1_FUNCT_MUL)
/* MULT - multiply */
MIPS_INS(MULT, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MULT)
/* MULTU - multiply unsinged */
MIPS_INS(MULTU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_MULTU)
/* NOR - not or */
MIPS_INS(NOR, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_NOR)
/* OR - or */
MIPS_INS(OR, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_OR)
/* ORI - or imemdiate */
MIPS_INS(ORI, .op = MIPS1_OP_ORI)
/* SB - store byte */
MIPS_INS(SB, .op = MIPS1_OP_SB)
/* SC - store conditional */
MIPS_INS(SC, .op = MIPS1_OP_SC)
/* SDC1 - store double word cop1 */
MIPS_INS(SDC1, .op = MIPS1_OP_SDC1)
/* SH - store half */
MIPS_INS(SH, .op = MIPS1_OP_SH)
/* SLL - shift left logical */
MIPS_INS(SLL, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SLL)
/* SLLV - shift left logical variable */
MIPS_INS(SLLV, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SLLV)
/* SLT - set less then */
MIPS_INS(SLT, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SLT)
/* SLTI - set less then immediate */
MIPS_INS(SLTI, .op = MIPS1_OP_SLTI)
/* SLTIU - set less then imemdiate unsigned */
MIPS_INS(SLTIU, .op = MIPS1_OP_SLTIU)
/* SLTU - set less than unsigned */
MIPS_INS(SLTU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SLTU)
/* SRA - shift right arithmetic */
MIPS_INS(SRA, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SRA)
/* SRAV - shift right arithmetic variable */
MIPS_INS(SRAV, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SRAV)
/* SRL - shift right logical */
MIPS_INS(SRL, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SRL)
/* SRLV - shift right logical variable */
MIPS_INS(SRLV, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SRLV)
/* SUB - subtract */
MIPS_INS(SUB, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SUB)
/* SUBU - subtract unsigned */
MIPS_INS(SUBU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SUBU)
/* SW - store word */
MIPS_INS(SW, .op = MIPS1_OP_SW)
/* SWC1 - store word cop1 */
MIPS_INS(SWC1, .op = MIPS1_OP_SWC1)
/* SWL - store word left */
MIPS_INS(SWL, .op = MIPS1_OP_SWL)
/* SWR - store word right */
MIPS_INS(SWR, .op = MIPS1_OP_SWR)
/* SYSCALL - syscall */
MIPS_INS(SYSCALL, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_SYSCALL)
/* TEQ - trap if equal */
MIPS_INS(TEQ, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_TEQ)
/* TEQ - trap if equal immediate */
MIPS_INS(TEQI, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_TEQI)
/* TGE - trap if greater or equal to */
MIPS_INS(TGE, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_TGE)
/* TGEI - trap if greater or equal to immediate */
MIPS_INS(TGEI, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_TGEI)
/* TGEIU - trap if greater or equal to immediate unsigned */
MIPS_INS(TGEIU, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_TGEIU)
/* TGEU - trap if greater or equal to unsigned */
MIPS_INS(TGEU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_TGEU)
/* TLT - trap if less or equal to */
MIPS_INS(TLT, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_TLT)
/* TLTI - trap if less or equal to immediate */
MIPS_INS(TLTI, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_TLTI)
/* TLTIU - trap if less or equal to immediate unsigned */
MIPS_INS(TLTIU, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_TLTIU)
/* TLTU - trap if less or equal to unsigned */
MIPS_INS(TLTU, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_TLTU)
/* TNE - trap if not equal */
MIPS_INS(TNE, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_TNE)
/* TNEI - trap if not equal immediate */
MIPS_INS(TNEI, .op = MIPS1_OP_REGIMM, .bfunct = MIPS1_FUNCT_TNEI)
/* XOR - exclusive or */
MIPS_INS(XOR, .op = MIPS1_OP_SPECIAL, .funct = MIPS1_FUNCT_XOR)
/* XORI - exclusive or immediate */
MIPS_INS(XORI, .op = MIPS1_OP_XORI)
};
#undef MIPS_INS