summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-10-21 12:27:18 -0400
committerFreya Murphy <freya@freyacat.org>2024-10-21 12:27:18 -0400
commit37a4e740133f8e4d669cafc8468dd13107a4810a (patch)
tree116b001142b5c0aea03ae46ef299f5fc220c4e5e
parentadd mips1 and mips32r2 isa definitions (diff)
downloadmips-37a4e740133f8e4d669cafc8468dd13107a4810a.tar.gz
mips-37a4e740133f8e4d669cafc8468dd13107a4810a.tar.bz2
mips-37a4e740133f8e4d669cafc8468dd13107a4810a.zip
save dev statedev
-rw-r--r--include/mips32r6.h338
-rw-r--r--lib/mips32r6.c673
-rw-r--r--masm/gen.c661
-rw-r--r--masm/gen.h93
-rw-r--r--masm/gen/grammer.c643
-rw-r--r--masm/gen/log.c28
-rw-r--r--masm/gen/section.c156
-rw-r--r--masm/tab/reftab.c (renamed from masm/reftab.c)2
-rw-r--r--masm/tab/symtab.c (renamed from masm/symtab.c)3
9 files changed, 1834 insertions, 763 deletions
diff --git a/include/mips32r6.h b/include/mips32r6.h
index 88eda4d..c6c1d59 100644
--- a/include/mips32r6.h
+++ b/include/mips32r6.h
@@ -7,6 +7,97 @@
#include <stdint.h>
#include <mips.h>
+// TODO:
+// balc
+
+// TODO: [add]
+// align
+// aluipc
+// aui
+// auipc
+// bal real ins
+// balc
+// bc
+// bc1eqz
+// bc1nez
+// bc2eqz
+// bc2nez
+// b{le,ge,gt,lt,eq,ne}ZALC
+// b<cond>c
+// bitswap
+// bovc
+// bnvc
+// crc32{b,h,w}
+// c2c32c{b,h,w}
+// div, mod, divu, modu
+// dvp
+// eretnc
+// evp
+// gnvi
+// ginvt
+// jialc
+// jic
+// jr assembly idiom
+// llwp
+// llwpe
+// lsa
+// lwpc
+// mfhc0
+// mthc0
+// mul muh mulu muhu
+// nal
+// scwp
+// scwpe
+// seleqz selnez
+// sigrie
+
+// TODO: [remove]
+// bc1f
+// bc1fl
+// bc1tl
+// bc1tl
+// bc2f
+// bc2fl
+// bc2t
+// bc2tl
+// all branch likely
+// div
+// divu
+// jr
+// ldxc1
+// lui
+// luxc1
+// lwl
+// lwr
+// lwxc1
+// madd
+// maddu
+// mfhi
+// mflo
+// movf
+// movn
+// movt
+// movz
+// msub
+// msubu
+// mthi
+// mtlo
+// mul
+// mult
+// multu
+// prefx
+// sdxc1
+// suxc1
+// swl
+// swr
+// swxc1
+// teqi
+// tgei
+// tgeiu
+// tlti
+// tltiu
+// tnei
+
/* mips instructions */
enum mips32r6_instruction_type {
MIPS32R6_INS_ADD,
@@ -15,39 +106,110 @@ enum mips32r6_instruction_type {
MIPS32R6_INS_ADDU,
MIPS32R6_INS_AND,
MIPS32R6_INS_ANDI,
- MIPS32R6_INS_BAL,
- MIPS32R6_INS_BALC,
- MIPS32R6_INS_BC,
+ MIPS32R6_INS_BC1F,
+ MIPS32R6_INS_BC1FL,
+ MIPS32R6_INS_BC1T,
+ MIPS32R6_INS_BC1TL,
+ MIPS32R6_INS_BC2F,
+ MIPS32R6_INS_BC2FL,
+ MIPS32R6_INS_BC2T,
+ MIPS32R6_INS_BC2TL,
MIPS32R6_INS_BEQ,
+ MIPS32R6_INS_BEQL,
MIPS32R6_INS_BGEZ,
MIPS32R6_INS_BGEZAL,
+ MIPS32R6_INS_BGEZALL,
+ MIPS32R6_INS_BGEZL,
MIPS32R6_INS_BGTZ,
+ MIPS32R6_INS_BGTZL,
MIPS32R6_INS_BLEZ,
+ MIPS32R6_INS_BLEZL,
MIPS32R6_INS_BLTZ,
MIPS32R6_INS_BLTZAL,
+ MIPS32R6_INS_BLTZALL,
+ MIPS32R6_INS_BLTZL,
MIPS32R6_INS_BNE,
+ MIPS32R6_INS_BNEL,
+ MIPS32R6_INS_BREAK,
+ MIPS32R6_INS_CACHE,
+ MIPS32R6_INS_CFC1,
+ MIPS32R6_INS_CFC2,
+ MIPS32R6_INS_CLO,
+ MIPS32R6_INS_CLZ,
+ MIPS32R6_INS_COP2,
+ MIPS32R6_INS_CTC1,
+ MIPS32R6_INS_CTC2,
+ MIPS32R6_INS_DERET,
+ MIPS32R6_INS_DI,
MIPS32R6_INS_DIV,
- MIPS32R6_INS_MOD,
MIPS32R6_INS_DIVU,
- MIPS32R6_INS_MODU,
+ MIPS32R6_INS_EI,
+ MIPS32R6_INS_ERET,
+ MIPS32R6_INS_EXT,
+ MIPS32R6_INS_INS,
MIPS32R6_INS_J,
MIPS32R6_INS_JAL,
MIPS32R6_INS_JALR,
- MIPS32R6_INS_JALX,
MIPS32R6_INS_JR,
MIPS32R6_INS_LB,
MIPS32R6_INS_LBU,
+ MIPS32R6_INS_LDC1,
+ MIPS32R6_INS_LDC2,
+ MIPS32R6_INS_LDXC1,
MIPS32R6_INS_LH,
MIPS32R6_INS_LHU,
+ MIPS32R6_INS_LL,
MIPS32R6_INS_LUI,
+ MIPS32R6_INS_LUXC1,
MIPS32R6_INS_LW,
+ MIPS32R6_INS_LWC1,
+ MIPS32R6_INS_LWC2,
+ MIPS32R6_INS_LWL,
+ MIPS32R6_INS_LWR,
+ MIPS32R6_INS_LWXC1,
+ MIPS32R6_INS_MADD,
+ MIPS32R6_INS_MADDU,
+ MIPS32R6_INS_MFC0,
+ MIPS32R6_INS_MFC1,
+ MIPS32R6_INS_MFC2,
+ MIPS32R6_INS_MFHC1,
+ MIPS32R6_INS_MFHC2,
+ MIPS32R6_INS_MFHI,
+ MIPS32R6_INS_MFLO,
+ MIPS32R6_INS_MOVF,
+ MIPS32R6_INS_MOVN,
+ MIPS32R6_INS_MOVT,
+ MIPS32R6_INS_MOVZ,
+ MIPS32R6_INS_MSUB,
+ MIPS32R6_INS_MSUBU,
+ MIPS32R6_INS_MTC0,
+ MIPS32R6_INS_MTC1,
+ MIPS32R6_INS_MTC2,
+ MIPS32R6_INS_MTHC1,
+ MIPS32R6_INS_MTHC2,
+ MIPS32R6_INS_MTHI,
+ MIPS32R6_INS_MTLO,
MIPS32R6_INS_MUL,
- MIPS32R6_INS_MUH,
- MIPS32R6_INS_MULU,
- MIPS32R6_INS_MUHU,
+ MIPS32R6_INS_MULT,
+ MIPS32R6_INS_MULTU,
+ MIPS32R6_INS_NOR,
+ MIPS32R6_INS_OR,
+ MIPS32R6_INS_ORI,
+ MIPS32R6_INS_PREF,
+ MIPS32R6_INS_PREFX,
+ MIPS32R6_INS_RDHWR,
+ MIPS32R6_INS_RDPGPR,
+ MIPS32R6_INS_ROTR,
+ MIPS32R6_INS_ROTRV,
MIPS32R6_INS_SB,
+ MIPS32R6_INS_SC,
+ MIPS32R6_INS_SDBBP,
+ MIPS32R6_INS_SDC1,
+ MIPS32R6_INS_SDC2,
+ MIPS32R6_INS_SDXC1,
+ MIPS32R6_INS_SEB,
+ MIPS32R6_INS_SEH,
MIPS32R6_INS_SH,
- MIPS32R6_INS_SW,
MIPS32R6_INS_SLL,
MIPS32R6_INS_SLLV,
MIPS32R6_INS_SLT,
@@ -60,21 +222,54 @@ enum mips32r6_instruction_type {
MIPS32R6_INS_SRLV,
MIPS32R6_INS_SUB,
MIPS32R6_INS_SUBU,
+ MIPS32R6_INS_SUXC1,
+ MIPS32R6_INS_SW,
+ MIPS32R6_INS_SWC1,
+ MIPS32R6_INS_SWC2,
+ MIPS32R6_INS_SWL,
+ MIPS32R6_INS_SWR,
+ MIPS32R6_INS_SWXC1,
+ MIPS32R6_INS_SYNC,
+ MIPS32R6_INS_SYNCI,
MIPS32R6_INS_SYSCALL,
- MIPS32R6_INS_OR,
- MIPS32R6_INS_ORI,
- MIPS32R6_INS_NOR,
+ MIPS32R6_INS_TEQ,
+ MIPS32R6_INS_TEQI,
+ MIPS32R6_INS_TGE,
+ MIPS32R6_INS_TGEI,
+ MIPS32R6_INS_TGEIU,
+ MIPS32R6_INS_TGEU,
+ MIPS32R6_INS_TLBP,
+ MIPS32R6_INS_TLBR,
+ MIPS32R6_INS_TLBWI,
+ MIPS32R6_INS_TLBWR,
+ MIPS32R6_INS_TLT,
+ MIPS32R6_INS_TLTI,
+ MIPS32R6_INS_TLTIU,
+ MIPS32R6_INS_TLTU,
+ MIPS32R6_INS_TNE,
+ MIPS32R6_INS_TNEI,
+ MIPS32R6_INS_WAIT,
+ MIPS32R6_INS_WRPGPR,
+ MIPS32R6_INS_WSBH,
MIPS32R6_INS_XOR,
MIPS32R6_INS_XORI,
__MIPS32R6_INS_NULL,
};
+// op code groups
#define MIPS32R6_OP_SPECIAL 0b000000
+#define MIPS32R6_OP_SPECIAL2 0b011100
+#define MIPS32R6_OP_SPECIAL3 0b011111
+#define MIPS32R6_OP_REGIMM 0b000001
+#define MIPS32R6_OP_COP0 0b010000
+#define MIPS32R6_OP_COP1 0b010001
+#define MIPS32R6_OP_COP2 0b010010
+#define MIPS32R6_OP_COP1X 0b010011
+
+// op codes
#define MIPS32R6_OP_ADDI 0b001000
#define MIPS32R6_OP_ADDIU 0b001001
#define MIPS32R6_OP_ANDI 0b001100
-#define MIPS32R6_OP_REGIMM 0b000001
-#define MIPS32R6_OP_BALC 0b111010
#define MIPS32R6_OP_BC 0b110010
#define MIPS32R6_OP_BEQ 0b000100
#define MIPS32R6_OP_BEQL 0b010100
@@ -84,36 +279,59 @@ enum mips32r6_instruction_type {
#define MIPS32R6_OP_BLEZL 0b010110
#define MIPS32R6_OP_BNE 0b000101
#define MIPS32R6_OP_BNEL 0b010101
+#define MIPS32R6_OP_CACHE 0b101111
#define MIPS32R6_OP_J 0b000010
#define MIPS32R6_OP_JAL 0b000011
#define MIPS32R6_OP_JALX 0b011101
#define MIPS32R6_OP_LB 0b100000
#define MIPS32R6_OP_LBU 0b100100
+#define MIPS32R6_OP_LDC1 0b110101
+#define MIPS32R6_OP_LDC2 0b110110
#define MIPS32R6_OP_LH 0b100001
#define MIPS32R6_OP_LHU 0b100101
+#define MIPS32R6_OP_LL 0b110000
#define MIPS32R6_OP_LUI 0b001111
#define MIPS32R6_OP_LW 0b100011
+#define MIPS32R6_OP_LWC1 0b110001
+#define MIPS32R6_OP_LWC2 0b110010
+#define MIPS32R6_OP_LWL 0b100010
+#define MIPS32R6_OP_LWR 0b100110
+#define MIPS32R6_OP_ORI 0b001101
+#define MIPS32R6_OP_PREF 0b110011
#define MIPS32R6_OP_SB 0b101000
+#define MIPS32R6_OP_SC 0b111000
+#define MIPS32R6_OP_SDC1 0b111101
+#define MIPS32R6_OP_SDC2 0b111110
#define MIPS32R6_OP_SH 0b101001
-#define MIPS32R6_OP_SW 0b101011
#define MIPS32R6_OP_SLTI 0b001010
#define MIPS32R6_OP_SLTIU 0b001011
-#define MIPS32R6_OP_ORI 0b001101
+#define MIPS32R6_OP_SW 0b101011
+#define MIPS32R6_OP_SWC1 0b111001
+#define MIPS32R6_OP_SWC2 0b111010
+#define MIPS32R6_OP_SWL 0b101010
+#define MIPS32R6_OP_SWR 0b101110
#define MIPS32R6_OP_XORI 0b001110
+// op special
#define MIPS32R6_FUNCT_ADD 0b100000
#define MIPS32R6_FUNCT_ADDU 0b100001
#define MIPS32R6_FUNCT_AND 0b100100
-#define MIPS32R6_FUNCT_SOP32 0b011010
-#define MIPS32R6_FUNCT_SOP33 0b011011
+#define MIPS32R6_FUNCT_BREAK 0b001101
+#define MIPS32R6_FUNCT_DIV 0b000011
+#define MIPS32R6_FUNCT_DIVU 0b011011
#define MIPS32R6_FUNCT_JALR 0b001001
#define MIPS32R6_FUNCT_JR 0b001000
#define MIPS32R6_FUNCT_MFHI 0b010000
#define MIPS32R6_FUNCT_MFLO 0b010010
+#define MIPS32R6_FUNCT_MOVCL 0b000001
+#define MIPS32R6_FUNCT_MOVN 0b001011
+#define MIPS32R6_FUNCT_MOVZ 0b001010
#define MIPS32R6_FUNCT_MTHI 0b010001
#define MIPS32R6_FUNCT_MTLO 0b010011
-#define MIPS32R6_FUNCT_SOP30 0b011000
-#define MIPS32R6_FUNCT_SOP31 0b011001
+#define MIPS32R6_FUNCT_MULT 0b011000
+#define MIPS32R6_FUNCT_MULTU 0b011001
+#define MIPS32R6_FUNCT_NOR 0b100111
+#define MIPS32R6_FUNCT_OR 0b100101
#define MIPS32R6_FUNCT_SLL 0b000000
#define MIPS32R6_FUNCT_SLLV 0b000100
#define MIPS32R6_FUNCT_SLT 0b101010
@@ -124,12 +342,38 @@ enum mips32r6_instruction_type {
#define MIPS32R6_FUNCT_SRLV 0b000110
#define MIPS32R6_FUNCT_SUB 0b100010
#define MIPS32R6_FUNCT_SUBU 0b100011
+#define MIPS32R6_FUNCT_SYNC 0b001111
#define MIPS32R6_FUNCT_SYSCALL 0b001100
-#define MIPS32R6_FUNCT_OR 0b100101
-#define MIPS32R6_FUNCT_NOR 0b100111
+#define MIPS32R6_FUNCT_TEQ 0b110100
+#define MIPS32R6_FUNCT_TGE 0b110000
+#define MIPS32R6_FUNCT_TGEU 0b110001
+#define MIPS32R6_FUNCT_TLT 0b110010
+#define MIPS32R6_FUNCT_TLTU 0b110011
+#define MIPS32R6_FUNCT_TNE 0b110110
#define MIPS32R6_FUNCT_XOR 0b100110
-#define MIPS32R6_FUNCT_BAL 0b10001
+// op special2
+#define MIPS32R6_FUNCT_CLO 0b100001
+#define MIPS32R6_FUNCT_CLZ 0b100000
+#define MIPS32R6_FUNCT_MADD 0b000000
+#define MIPS32R6_FUNCT_MADDU 0b000001
+#define MIPS32R6_FUNCT_MSUB 0b000100
+#define MIPS32R6_FUNCT_MSUBU 0b000101
+#define MIPS32R6_FUNCT_MUL 0b000010
+#define MIPS32R6_FUNCT_SDBBP 0b111111
+
+// op special 3
+#define MIPS32R6_FUNCT_EXT 0b000000
+#define MIPS32R6_FUNCT_INS 0b000100
+#define MIPS32R6_FUNCT_RDHWR 0b111011
+#define MIPS32R6_FUNCT_BSHFL 0b100000
+
+// op bshfl
+#define MIPS32R6_FUNCT_SEB 0b10000
+#define MIPS32R6_FUNCT_SEH 0b11000
+#define MIPS32R6_FUNCT_WSBH 0b00010
+
+// op regimm
#define MIPS32R6_FUNCT_BGEZ 0b00001
#define MIPS32R6_FUNCT_BGEZAL 0b10001
#define MIPS32R6_FUNCT_BGEZALL 0b10011
@@ -138,18 +382,46 @@ enum mips32r6_instruction_type {
#define MIPS32R6_FUNCT_BLTZAL 0b10000
#define MIPS32R6_FUNCT_BLTZALL 0b10010
#define MIPS32R6_FUNCT_BLTZL 0b00010
+#define MIPS32R6_FUNCT_SYNCI 0b11111
+#define MIPS32R6_FUNCT_TEQI 0b01100
+#define MIPS32R6_FUNCT_TGEI 0b01000
+#define MIPS32R6_FUNCT_TGEIU 0b01001
+#define MIPS32R6_FUNCT_TLTI 0b01010
+#define MIPS32R6_FUNCT_TLTIU 0b01011
+#define MIPS32R6_FUNCT_TNEI 0b01110
+
+// op cop cfunct
+#define MIPS32R6_FUNCT_BC 0b01000
+#define MIPS32R6_FUNCT_CF 0b00010
+#define MIPS32R6_FUNCT_CT 0b00110
+#define MIPS32R6_FUNCT_MF 0b00000
+#define MIPS32R6_FUNCT_MFH 0b00011
+#define MIPS32R6_FUNCT_MT 0b00100
+#define MIPS32R6_FUNCT_MTH 0b00111
+#define MIPS32R6_FUNCT_MFMC0 0b01011
+#define MIPS32R6_FUNCT_RDPGPR 0b01010
+#define MIPS32R6_FUNCT_WRPGPR 0b01110
+
+// op cop funct
+#define MIPS32R6_FUNCT_DERET 0b011111
+#define MIPS32R6_FUNCT_ERET 0b011000
+#define MIPS32R6_FUNCT_TLBP 0b001000
+#define MIPS32R6_FUNCT_TLBR 0b000001
+#define MIPS32R6_FUNCT_TLBWI 0b000010
+#define MIPS32R6_FUNCT_TLBWR 0b000110
-#define MIPS32R6_SOP30_MUL 0b00010
-#define MIPS32R6_SOP30_MUH 0b00011
-#define MIPS32R6_SOP31_MULU 0b00010
-#define MIPS32R6_SOP31_MUHU 0b00011
-#define MIPS32R6_SOP32_DIV 0b00010
-#define MIPS32R6_SOP32_MOD 0b00011
-#define MIPS32R6_SOP33_DIVU 0b00010
-#define MIPS32R6_SOP33_MODU 0b00011
+// op cop1x
+#define MIPS32R6_FUNCT_LDXC1 0b000001
+#define MIPS32R6_FUNCT_LUXC1 0b000101
+#define MIPS32R6_FUNCT_LWXC1 0b000000
+#define MIPS32R6_FUNCT_PREFX 0b001111
+#define MIPS32R6_FUNCT_SDXC1 0b001001
+#define MIPS32R6_FUNCT_SUXC1 0b001101
+#define MIPS32R6_FUNCT_SWXC1 0b001000
+#define MIPS32R6_FUNCT_WAIT 0b100000
#define __MIPS32R6_INS_LEN (__MIPS32R6_INS_NULL)
-#define __MIPS32R6_PSEUDO_LEN (4)
+#define __MIPS32R6_PSEUDO_LEN (38)
#define __MIPS32R6_GRAMMER_LEN (__MIPS32R6_INS_LEN + __MIPS32R6_PSEUDO_LEN)
extern struct mips32_grammer mips32r6_grammers[__MIPS32R6_GRAMMER_LEN];
diff --git a/lib/mips32r6.c b/lib/mips32r6.c
index 1f1fe61..01b028e 100644
--- a/lib/mips32r6.c
+++ b/lib/mips32r6.c
@@ -24,40 +24,111 @@ struct mips32_grammer mips32r6_grammers[__MIPS32R6_GRAMMER_LEN] = {
INS(ADDIU, ITYPE),
INS(ADDU, RTYPE),
INS(AND, RTYPE),
- INS(ADDI, ITYPE),
INS(ANDI, ITYPE),
- INS(BAL, "offset"),
- INS(BALC, "target"),
- INS(BC, "target"),
+ INS(BC1F, "cc,offset"),
+ INS(BC1FL, "cc,offset"),
+ INS(BC1T, "cc,offset"),
+ INS(BC1TL, "cc,offset"),
+ INS(BC2F, "cc,offset"),
+ INS(BC2FL, "cc,offset"),
+ INS(BC2T, "cc,offset"),
+ INS(BC2TL, "cc,offset"),
INS(BEQ, BRANCH),
+ INS(BEQL, BRANCH),
INS(BGEZ, BRANCHZ),
INS(BGEZAL, BRANCHZ),
+ INS(BGEZALL, BRANCHZ),
+ INS(BGEZL, BRANCHZ),
INS(BGTZ, BRANCHZ),
+ INS(BGTZL, BRANCHZ),
INS(BLEZ, BRANCHZ),
+ INS(BLEZL, BRANCHZ),
INS(BLTZ, BRANCHZ),
INS(BLTZAL, BRANCHZ),
+ INS(BLTZALL, BRANCHZ),
+ INS(BLTZL, BRANCHZ),
INS(BNE, BRANCH),
+ INS(BNEL, BRANCH),
+ INS(BREAK, "code"),
+ INS(CACHE, "op,offset(base)"),
+ INS(CFC1, "rt,fs"),
+ INS(CFC2, "rt,rd"),
+ INS(CLO, "rd,rs"),
+ INS(CLZ, "rd,rs"),
+ INS(COP2, "func"),
+ INS(CTC1, "rt,fs"),
+ INS(CTC2, "rt,rd"),
+ INS(DERET, ""),
+ INS(DI, "rt"),
INS(DIV, RTYPE),
- INS(MOD, RTYPE),
INS(DIVU, RTYPE),
- INS(MODU, RTYPE),
+ INS(EI, "rt"),
+ INS(ERET, ""),
+ INS(EXT, "rt,rs,pos,size"),
+ INS(INS, "rt,rs,pos,size"),
INS(J, JTYPE),
INS(JAL, JTYPE),
INS(JALR, "rs"),
INS(JR, "rs"),
INS(LB, LOAD),
INS(LBU, LOAD),
+ INS(LDC1, "ft,offset(base)"),
+ INS(LDC2, LOAD),
+ INS(LDXC1, "fd,index(base)"),
INS(LH, LOAD),
INS(LHU, LOAD),
+ INS(LL, LOAD),
INS(LUI, "rt,immd"),
+ INS(LUXC1, "fd,index(base)"),
INS(LW, LOAD),
+ INS(LWC1, "ft,offset(base)"),
+ INS(LWC2, LOAD),
+ INS(LWL, LOAD),
+ INS(LWR, LOAD),
+ INS(LWXC1, "fd,index(base)"),
+ INS(MADD, "rs,rt"),
+ INS(MADDU, "rs,rt"),
+ INS(MFC0, "rt,rd"),
+ INS(MFC1, "rt,fs"),
+ INS(MFC2, "rt,rd"),
+ INS(MFHC1, "rt,fs"),
+ INS(MFHC2, "rt,rd"),
+ INS(MFHI, "rd"),
+ INS(MFLO, "rd"),
+ INS(MOVF, "rd,rs,cc"),
+ INS(MOVN, RTYPE),
+ INS(MOVT, "rd,rs,cc"),
+ INS(MOVZ, RTYPE),
+ INS(MSUB, "rs,rt"),
+ INS(MSUBU, "rs,rt"),
+ INS(MTC0, "rt,rd"),
+ INS(MTC1, "rt,fs"),
+ INS(MTC2, "rt,rd"),
+ INS(MTHC1, "rt,fs"),
+ INS(MTHC2, "rt,rd"),
+ INS(MTHI, "rs"),
+ INS(MTLO, "rs"),
INS(MUL, RTYPE),
- INS(MUH, RTYPE),
- INS(MULU, RTYPE),
- INS(MUHU, RTYPE),
+ INS(MULT, "rs,rt"),
+ INS(MULTU, "rs,rt"),
+ INS(NOR, RTYPE),
+ INS(OR, RTYPE),
+ INS(ORI, ITYPE),
+ INS(PREF, "hint,offset(base)"),
+ INS(PREFX, "hint,index(base)"),
+ INS(RDHWR, "rt,rd"),
+ INS(RDPGPR, "rd,rt"),
+ INS(ROTR, SHIFT),
+ INS(ROTRV, SHIFTV),
INS(SB, LOAD),
+ INS(SC, LOAD),
+ INS(SDBBP, "code"),
+ INS(SDC1, "ft,offset(base)"),
+ INS(SDC2, LOAD),
+ INS(SDXC1, "fs,index(base)"),
+ INS(SEB, "rd,rt"),
+ INS(SEH, "rd,rt"),
INS(SH, LOAD),
- INS(SW, LOAD),
INS(SLL, SHIFT),
INS(SLLV, SHIFTV),
INS(SLT, RTYPE),
@@ -70,19 +141,206 @@ struct mips32_grammer mips32r6_grammers[__MIPS32R6_GRAMMER_LEN] = {
INS(SRLV, SHIFT),
INS(SUB, RTYPE),
INS(SUBU, RTYPE),
+ INS(SUXC1, "fs,index(base)"),
+ INS(SW, LOAD),
+ INS(SWC1, "ft,offset(base)"),
+ INS(SWC2, LOAD),
+ INS(SWL, LOAD),
+ INS(SWR, LOAD),
+ INS(SWXC1, "fs,index(base)"),
+ INS(SYNC, ""),
+ INS(SYNCI, "offest(base)"),
INS(SYSCALL, ""),
- INS(OR, RTYPE),
- INS(ORI, ITYPE),
- INS(NOR, RTYPE),
+ INS(TEQ, "rs,rt"),
+ INS(TEQI, "rs,immd"),
+ INS(TGE, "rs,rt"),
+ INS(TGEI, "rs,immd"),
+ INS(TGEIU, "rs,immd"),
+ INS(TGEU, "rs,rt"),
+ INS(TLBP, ""),
+ INS(TLBR, ""),
+ INS(TLBWI, ""),
+ INS(TLBWR, ""),
+ INS(TLT, "rs,rt"),
+ INS(TLTI, "rs,immd"),
+ INS(TLTIU, "rs,immd"),
+ INS(TLTU, "rs,rt"),
+ INS(TNE, "rs,rt"),
+ INS(TNEI, "rs,immd"),
+ INS(WAIT, ""),
+ INS(WRPGPR, "rd,rt"),
INS(XOR, RTYPE),
INS(XORI, ITYPE),
// pseudo instructions
+ PSEUDO("abs", "rd,rs", 3, {
+ {MIPS32R6_INS_SRA, "rd=$at,rt=rs,sa=31"},
+ {MIPS32R6_INS_ADD, "rd,rs,rt=$at"},
+ {MIPS32R6_INS_XOR, "rd,rs=rd,rt=$at"},
+ }),
+
+ PSEUDO("div", "rd,rt,rs", 2, {
+ {MIPS32R6_INS_DIV, "rt,rs"},
+ {MIPS32R6_INS_MFLO, "rd"},
+ }),
+
+ PSEUDO("divu", "rd,rt,rs", 2, {
+ {MIPS32R6_INS_DIVU, "rt,rs"},
+ {MIPS32R6_INS_MFLO, "rd"},
+ }),
+
+ PSEUDO("mulo", "rd,rt,rs", 2, {
+ {MIPS32R6_INS_MULT, "rt,rs"},
+ {MIPS32R6_INS_MFLO, "rd"},
+ }),
+
+ PSEUDO("mulou", "rd,rt,rs", 2, {
+ {MIPS32R6_INS_MULTU, "rt,rs"},
+ {MIPS32R6_INS_MFLO, "rd"},
+ }),
+
+ PSEUDO("neg", "rd,rt", 1, {
+ {MIPS32R6_INS_SUB, "rd,rs=$zero,rt"},
+ }),
+
+ PSEUDO("negu", "rd,rt", 1, {
+ {MIPS32R6_INS_SUBU, "rd,rs=$zero,rt"},
+ }),
+
+ PSEUDO("not", "rd,rt", 1, {
+ {MIPS32R6_INS_NOR, "rd,rs=$zero,rt"},
+ }),
+
+ PSEUDO("rem", "rd,rt,rs", 2, {
+ {MIPS32R6_INS_DIV, "rt,rs"},
+ {MIPS32R6_INS_MFHI, "rd"},
+ }),
+
+ PSEUDO("remu", "rd,rt,rs", 2, {
+ {MIPS32R6_INS_DIVU, "rt,rs"},
+ {MIPS32R6_INS_MFHI, "rd"},
+ }),
+
+ // TODO: rol
+
+ // TODO: ror
+
+ PSEUDO("subi", "rt,rs,immd", 1, {
+ {MIPS32R6_INS_ADDI, "rt,rs,-immd"},
+ }),
+
PSEUDO("li", "rt,immd", 1, {
{MIPS32R6_INS_ADDI, "rt,immd"}
}),
+ PSEUDO("seq", "rd,rs,rt", 3, {
+ {MIPS32R6_INS_SLT, "rd,rs,rt"},
+ {MIPS32R6_INS_SLT, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_NOR, "rd,rs=rd,rt=$at"},
+ }),
+
+ PSEUDO("sgt", "rd,rs,rt", 1, {
+ {MIPS32R6_INS_SLT, "rd,rs=rt,rt=rs"},
+ }),
+
+ PSEUDO("sgtu", "rd,rs,rt", 1, {
+ {MIPS32R6_INS_SLTU, "rd,rs=rt,rt=rs"},
+ }),
+
+ PSEUDO("sge", "rd,rs,rt", 2, {
+ {MIPS32R6_INS_SLT, "rd,rs,rt"},
+ {MIPS32R6_INS_SLTI, "rt=rd,rs=rd,immd=1"},
+ }),
+
+ PSEUDO("sgeu", "rd,rs,rt", 2, {
+ {MIPS32R6_INS_SLTU, "rd,rs,rt"},
+ {MIPS32R6_INS_SLTI, "rt=rd,rs=rd,immd=1"},
+ }),
+
+ PSEUDO("slte", "rd,rs,rt", 2, {
+ {MIPS32R6_INS_SLT, "rd,rs=rt,rt=rs"},
+ {MIPS32R6_INS_SLTI, "rt=rd,rs=rd,immd=1"},
+ }),
+
+ PSEUDO("slteu", "rd,rs,rt", 2, {
+ {MIPS32R6_INS_SLTU, "rd,rs=rt,rt=rs"},
+ {MIPS32R6_INS_SLTI, "rt=rd,rs=rd,immd=1"},
+ }),
+
+ PSEUDO("sne", "rd,rs,rt", 3, {
+ {MIPS32R6_INS_SLT, "rd,rs,rt"},
+ {MIPS32R6_INS_SLT, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_OR, "rd,rs=rd,rt=$at"},
+ }),
+
+ PSEUDO("jalr.hb", "rs", 1, {
+ {MIPS32R6_INS_JALR, "rs,hb=1"}
+ }),
+
+ PSEUDO("jr.hb", "rs", 1, {
+ {MIPS32R6_INS_JR, "rs,hb=1"}
+ }),
+
+
+ PSEUDO("b", "offset", 1, {
+ {MIPS32R6_INS_BEQ, "rs=$zero,rt=$zero,offset"},
+ }),
+
+ PSEUDO("beqz", "rs,offset", 1, {
+ {MIPS32R6_INS_BEQ, "rs,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bge", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLT, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_BNE, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bgeu", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLTU, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_BNE, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bge", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLT, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_BEQ, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bgeu", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLTU, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_BEQ, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("ble", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLT, "rd=$at,rs=rt,rt=rs"},
+ {MIPS32R6_INS_BEQ, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bleu", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLT, "rd=$at,rs=rt,rt=rs"},
+ {MIPS32R6_INS_BEQ, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("blt", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLT, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_BNE, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bltu", "rs,rt,offset", 2, {
+ {MIPS32R6_INS_SLTU, "rd=$at,rs,rt"},
+ {MIPS32R6_INS_BNE, "rs=$at,rt=$zero,offset"},
+ }),
+
+ PSEUDO("bnez", "rs,offset", 1, {
+ {MIPS32R6_INS_BNE, "rs,rt=$zero,offset"},
+ }),
+
+ // TODO: ld
+
+ // TODO: load unaligned
+
+ // TODO: store unaligned
+
PSEUDO("la", "rt,target", 2, {
{MIPS32R6_INS_LUI, "rt=$at,hi"},
{MIPS32R6_INS_ORI, "rt,rs=$at,lo"},
@@ -95,6 +353,14 @@ struct mips32_grammer mips32r6_grammers[__MIPS32R6_GRAMMER_LEN] = {
PSEUDO("nop", "", 1, {
{MIPS32R6_INS_SLL, ""},
}),
+
+ PSEUDO("ssnop", "", 1, {
+ {MIPS32R6_INS_SLL, "sa=1"},
+ }),
+
+ PSEUDO("ehb", "", 1, {
+ {MIPS32R6_INS_SLL, "sa=3"}
+ }),
};
#define MIPS_INS(ins, ...) \
@@ -119,54 +385,138 @@ MIPS_INS(AND, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_AND)
/* ANDI - and immediate */
MIPS_INS(ANDI, .op = MIPS32R6_OP_ANDI)
-/* BAL - branch and link */
-MIPS_INS(BAL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BAL)
+/* BC1F - branch on cop1 false */
+MIPS_INS(BC1F, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 0, .tf = 0)
+
+/* BC1FL - branch on cop1 false likely */
+MIPS_INS(BC1FL, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 1, .tf = 0)
-/* BALC - branch and link, compact */
-MIPS_INS(BALC, .op = MIPS32R6_OP_BALC)
+/* BC1T - branch on cop1 true */
+MIPS_INS(BC1T, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 0, .tf = 1)
-/* BC - branch, compact */
-MIPS_INS(BC, .op = MIPS32R6_OP_BC)
+/* BC1TL - branch on cop1 true likely */
+MIPS_INS(BC1TL, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 1, .tf = 1)
+
+/* BC2F - branch on cop1 false */
+MIPS_INS(BC2F, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 0, .tf = 0)
+
+/* BC2FL - branch on cop1 false likely */
+MIPS_INS(BC2FL, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 1, .tf = 0)
+
+/* BC2T - branch on cop1 true */
+MIPS_INS(BC2T, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 0, .tf = 1)
+
+/* BC2TL - branch on cop1 true likely */
+MIPS_INS(BC2TL, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_BC,
+ .nd = 1, .tf = 1)
/* BEQ - branch on equal */
MIPS_INS(BEQ, .op = MIPS32R6_OP_BEQ)
+/* BEQL - branch on equal likely */
+MIPS_INS(BEQL, .op = MIPS32R6_OP_BEQL)
+
/* BGEZ - branch on greater than or equal to zero */
MIPS_INS(BGEZ, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BGEZ)
/* BGEZAL - branch on greater than or equal to zero and link */
MIPS_INS(BGEZAL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BGEZAL)
+/* BGEZALL - branch on greater than or equal to zero and link likely */
+MIPS_INS(BGEZALL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BGEZALL)
+
+/* BGEZL - branch on greater than or equal to zero likely */
+MIPS_INS(BGEZL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BGEZL)
+
/* BGTZ - branch on greater than zero */
MIPS_INS(BGTZ, .op = MIPS32R6_OP_BGTZ)
+/* BGTZL - branch on greater than zero likely */
+MIPS_INS(BGTZL, .op = MIPS32R6_OP_BGTZL)
+
/* BLEZ - branch on less than or equal to zero */
MIPS_INS(BLEZ, .op = MIPS32R6_OP_BLEZ)
+/* BLEZL - branch on less than or equal to zero likely */
+MIPS_INS(BLEZL, .op = MIPS32R6_OP_BLEZL)
+
/* BLTZ - branch on less than zero */
MIPS_INS(BLTZ, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BLTZ)
/* BLTZAL - branch on less than zero and link */
MIPS_INS(BLTZAL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BLTZAL)
+/* BLTZALL - branch on less than zero and link likely */
+MIPS_INS(BLTZALL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BLTZALL)
+
+/* BLTZL - branch on less than zero likely */
+MIPS_INS(BLTZL, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_BLTZL)
+
/* BNE - branch on not equal */
MIPS_INS(BNE, .op = MIPS32R6_OP_BNE)
-/* DIV - divide */
-MIPS_INS(DIV, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP32_DIV,
- .funct = MIPS32R6_FUNCT_SOP32)
+/* BNEL - branch on not equal likely */
+MIPS_INS(BNEL, .op = MIPS32R6_OP_BNEL)
+
+/* BREAK - breakpoint */
+MIPS_INS(BREAK, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_BREAK)
+
+/* CACHE - perform cache operation */
+MIPS_INS(CACHE, .op = MIPS32R6_OP_CACHE)
+
+/* CFC1 - move control word from floating point */
+MIPS_INS(CFC1, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_CF)
+
+/* CFC2 - move control word from coprocessor 2 */
+MIPS_INS(CFC2, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_CF)
+
+/* CLO - count leading ones */
+MIPS_INS(CLO, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_CLO)
+
+/* CLZ - count leading zeros */
+MIPS_INS(CLZ, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_CLZ)
-/* MOD - modulo */
-MIPS_INS(MOD, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP32_MOD,
- .funct = MIPS32R6_FUNCT_SOP32)
+/* COP2 - coprocessor operation to coprocessor 2 */
+MIPS_INS(COP2, .op = MIPS32R6_OP_COP2, .c0 = 1)
+
+/* CTC1 - move control word to floating point */
+MIPS_INS(CTC1, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_CT)
+
+/* CTC2 - move control word to coprocessor 2 */
+MIPS_INS(CTC2, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_CT)
+
+/* DERET - debug exception return */
+MIPS_INS(DERET, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_DERET)
+
+/* DI - disable interupts */
+MIPS_INS(DI, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MFMC0,
+ .rd = 12, .sc = 0)
+
+/* DIV - divide */
+MIPS_INS(DIV, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_DIV)
/* DIVU - divide unsigned */
-MIPS_INS(DIVU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP33_DIVU,
- .funct = MIPS32R6_FUNCT_SOP33)
+MIPS_INS(DIVU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_DIVU)
+
+/* EI - enable interupts */
+MIPS_INS(EI, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MFMC0,
+ .rd = 12, .sc = 1)
-/* MODU - modulo unsigned */
-MIPS_INS(MODU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP33_MODU,
- .funct = MIPS32R6_FUNCT_SOP33)
+/* ERET - exception return */
+MIPS_INS(ERET, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_ERET)
+
+/* ERT - extract bit field */
+MIPS_INS(EXT, .op = MIPS32R6_OP_SPECIAL3, .funct = MIPS32R6_FUNCT_EXT)
+
+/* INS - insert bit field */
+MIPS_INS(INS, .op = MIPS32R6_OP_SPECIAL3, .funct = MIPS32R6_FUNCT_INS)
/* J - jump */
MIPS_INS(J, .op = MIPS32R6_OP_J)
@@ -178,9 +528,6 @@ MIPS_INS(JAL, .op = MIPS32R6_OP_JAL)
MIPS_INS(JALR, .rd = MIPS32_REG_RA, .op = MIPS32R6_OP_SPECIAL,
.funct = MIPS32R6_FUNCT_JALR)
-/* JALX - jump and link exchange */
-MIPS_INS(JALX, .op = MIPS32R6_OP_JALX)
-
/* JR - jump register */
MIPS_INS(JR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_JR)
@@ -190,43 +537,182 @@ MIPS_INS(LB, .op = MIPS32R6_OP_LB)
/* LBU - load byte unsigned */
MIPS_INS(LBU, .op = MIPS32R6_OP_LBU)
+/* LDC1 - load doubleword floating point */
+MIPS_INS(LDC1, .op = MIPS32R6_OP_LDC1)
+
+/* LDC2 - load doubleword cop2 */
+MIPS_INS(LDC2, .op = MIPS32R6_OP_LDC2)
+
+/* LDXC1 - load doubleword indexed to floating point */
+MIPS_INS(LDXC1, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_LDXC1)
+
/* LH - load half */
MIPS_INS(LH, .op = MIPS32R6_OP_LH)
/* LHU - load half unsigned */
MIPS_INS(LHU, .op = MIPS32R6_OP_LHU)
+/* LK - load linked */
+MIPS_INS(LL, .op = MIPS32R6_OP_LL)
+
/* LUI - load upper immediate */
MIPS_INS(LUI, .op = MIPS32R6_OP_LUI)
+/* LUXC1 - load doubleword indexed unaligned to floating point */
+MIPS_INS(LUXC1, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_LUXC1)
+
/* LW - load word */
MIPS_INS(LW, .op = MIPS32R6_OP_LW)
-/* MUL - multiply low word */
-MIPS_INS(MUL, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP30_MUL,
- .funct = MIPS32R6_FUNCT_SOP30)
+/* LDC1 - load word floating point */
+MIPS_INS(LWC1, .op = MIPS32R6_OP_LWC1)
+
+/* LDC2 - load eword cop2 */
+MIPS_INS(LWC2, .op = MIPS32R6_OP_LWC2)
+
+/* LWL - load word left */
+MIPS_INS(LWL, .op = MIPS32R6_OP_LWL)
+
+/* LWR - load word right */
+MIPS_INS(LWR, .op = MIPS32R6_OP_LWR)
+
+/* LWXC1 - load word indexed to floating point */
+MIPS_INS(LWXC1, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_LWXC1)
+
+/* MADD - multiply and add words to hi,lo */
+MIPS_INS(MADD, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_MADD)
+
+/* MADDU - multiply and add unsigned words to hi,lo */
+MIPS_INS(MADDU, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_MADDU)
+
+/* MFC0 - move from cop0 */
+MIPS_INS(MFC0, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MF)
+
+/* MFC1 - move from floating point */
+MIPS_INS(MFC1, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_MF)
+
+/* MFC2 - move from cop2 */
+MIPS_INS(MFC2, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MF)
+
+/* MFHC1 - move word from high half of floating point register */
+MIPS_INS(MFHC1, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_MFH)
+
+/* MFHC2 - move word from high half of cop2 */
+MIPS_INS(MFHC2, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_MFH)
+
+/* MFHI - move from hi register */
+MIPS_INS(MFHI, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MFHI)
+
+/* MFLO - move from lo register */
+MIPS_INS(MFLO, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MFLO)
+
+/* MOVF - move on floating point false */
+MIPS_INS(MOVF, .op = MIPS32R6_OP_SPECIAL, .tf = 0,
+ .funct = MIPS32R6_FUNCT_MOVCL)
+
+/* MOVN - move conditional on non zero */
+MIPS_INS(MOVN, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MOVN)
+
+/* MOVT - move on floating point true */
+MIPS_INS(MOVT, .op = MIPS32R6_OP_SPECIAL, .tf = 1,
+ .funct = MIPS32R6_FUNCT_MOVCL)
+
+/* MOVZ - move conditional on zero */
+MIPS_INS(MOVZ, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MOVZ)
+
+/* MSUB - multiply and add words to hi,lo */
+MIPS_INS(MSUB, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_MSUB)
+
+/* MSUBU - multiply and add unsigned words to hi,lo */
+MIPS_INS(MSUBU, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_MSUBU)
+
+/* MTC0 - move to cop0 */
+MIPS_INS(MTC0, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MT)
+
+/* MTC1 - move to floating point */
+MIPS_INS(MTC1, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_MT)
+
+/* MTC2 - move to cop2 */
+MIPS_INS(MTC2, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MT)
+
+/* MTHC1 - move word to high half of floating point register */
+MIPS_INS(MTHC1, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_MTH)
+
+/* MTHC2 - move word to high half of cop2 */
+MIPS_INS(MTHC2, .op = MIPS32R6_OP_COP2, .cfunct = MIPS32R6_FUNCT_MTH)
+
+/* MTHI - move to hi register */
+MIPS_INS(MTHI, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MTHI)
+
+/* MTLO - move to lo register */
+MIPS_INS(MTLO, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MTLO)
+
+/* MUL - multiply word to GPR */
+MIPS_INS(MUL, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_MUL)
+
+/* MULT - multiply word */
+MIPS_INS(MULT, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MULT)
+
+/* MULTU - multiply unsigned word */
+MIPS_INS(MULTU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_MULTU)
+
+/* NOR - not or */
+MIPS_INS(NOR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_NOR)
+
+/* OR - or */
+MIPS_INS(OR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_OR)
+
+/* ORI - or imemdiate */
+MIPS_INS(ORI, .op = MIPS32R6_OP_ORI)
+
+/* PREF - prefetch */
+MIPS_INS(PREF, .op = MIPS32R6_OP_PREF)
+
+/* PREFX - prefetch indexed */
+MIPS_INS(PREFX, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_PREFX)
-/* MUH - multiply high word */
-MIPS_INS(MUH, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP30_MUH,
- .funct = MIPS32R6_FUNCT_SOP30)
+/* RDHWR - read hardware register */
+MIPS_INS(RDHWR, .op = MIPS32R6_OP_SPECIAL3, .funct = MIPS32R6_FUNCT_RDHWR)
-/* MULU - multiply low word unsigned */
-MIPS_INS(MULU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP31_MULU,
- .funct = MIPS32R6_FUNCT_SOP31)
+/* RDPGPR - read gpr from previous shadow set */
+MIPS_INS(RDPGPR, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_RDPGPR)
-/* MUHU - multiply high word unsgined */
-MIPS_INS(MUHU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP31_MUHU,
- .funct = MIPS32R6_FUNCT_SOP31)
+/* ROTR - rotate word right */
+MIPS_INS(ROTR, .op = MIPS32R6_OP_SPECIAL, .r = 1, .funct = MIPS32R6_FUNCT_SRL)
+
+/* ROTRV - rotate word right variable */
+MIPS_INS(ROTRV, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SRLV,
+ .rv = 1)
/* SB - store byte */
MIPS_INS(SB, .op = MIPS32R6_OP_SB)
+/* SC - store conditional word */
+MIPS_INS(SC, .op = MIPS32R6_OP_SC)
+
+/* SDBBP - software debug breakpoint */
+MIPS_INS(SDBBP, .op = MIPS32R6_OP_SPECIAL2, .funct = MIPS32R6_FUNCT_SDBBP)
+
+/* SDC1 - store doubleword floating point */
+MIPS_INS(SDC1, .op = MIPS32R6_OP_SDC1)
+
+/* SDC2 - store doubleword cop2 */
+MIPS_INS(SDC2, .op = MIPS32R6_OP_SDC2)
+
+/* SDXC1 - store doubleword indexed from floating point */
+MIPS_INS(SDXC1, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_SDXC1)
+
+/* SEB - sign extend byte */
+MIPS_INS(SEB, .op = MIPS32R6_OP_SPECIAL3, .shamt = MIPS32R6_FUNCT_SEB,
+ .funct = MIPS32R6_FUNCT_BSHFL)
+
+/* SEH - sign extend halfword */
+MIPS_INS(SEH, .op = MIPS32R6_OP_SPECIAL3, .shamt = MIPS32R6_FUNCT_SEH,
+ .funct = MIPS32R6_FUNCT_BSHFL)
+
/* SH - store half */
MIPS_INS(SH, .op = MIPS32R6_OP_SH)
-/* SW - store word */
-MIPS_INS(SW, .op = MIPS32R6_OP_SW)
-
/* SLL - shift left logical */
MIPS_INS(SLL, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SLL)
@@ -263,17 +749,93 @@ MIPS_INS(SUB, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SUB)
/* SUBU - subtract unsigned */
MIPS_INS(SUBU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SUBU)
+/* SUXC1 - store doubleword indexed unaligned from floating point */
+MIPS_INS(SUXC1, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_SUXC1)
+
+/* SW - store word */
+MIPS_INS(SW, .op = MIPS32R6_OP_SW)
+
+/* SWC1 - store word floating point */
+MIPS_INS(SWC1, .op = MIPS32R6_OP_SWC1)
+
+/* SWC2 - store eword cop2 */
+MIPS_INS(SWC2, .op = MIPS32R6_OP_SWC2)
+
+/* SWL - store word left */
+MIPS_INS(SWL, .op = MIPS32R6_OP_SWL)
+
+/* SWR - store word right */
+MIPS_INS(SWR, .op = MIPS32R6_OP_SWR)
+
+/* SWXC1 - store word indexed from floating point */
+MIPS_INS(SWXC1, .op = MIPS32R6_OP_COP1X, .funct = MIPS32R6_FUNCT_SWXC1)
+
+/* SYNC - synchronize shared memory */
+MIPS_INS(SYNC, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SYNC)
+
+/* SYNCI - synchronize caches to make instruction writes effective */
+MIPS_INS(SYNCI, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_SYNCI)
+
/* SYSCALL - syscall */
MIPS_INS(SYSCALL, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_SYSCALL)
-/* OR - or */
-MIPS_INS(OR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_OR)
+/* TEQ - trap if equal */
+MIPS_INS(TEQ, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_TEQ)
-/* ORI - or imemdiate */
-MIPS_INS(ORI, .op = MIPS32R6_OP_ORI)
+/* TEQI - trap if equal immediate */
+MIPS_INS(TEQI, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_TEQI)
-/* NOR - not or */
-MIPS_INS(NOR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_NOR)
+/* TGE - trap if greater or equal */
+MIPS_INS(TGE, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_TGE)
+
+/* TGEI - trap if greater or equal immediate */
+MIPS_INS(TGEI, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_TGEI)
+
+/* TGEIU - trap if greater or equal immediate unsigned */
+MIPS_INS(TGEIU, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_TGEIU)
+
+/* TGEU - trap if greater or equal unsigned */
+MIPS_INS(TGEU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_TGEU)
+
+/* TLBP - probe TLB for matching entry */
+MIPS_INS(TLBP, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_TLBP)
+
+/* TLBR - read indexed TLB entry */
+MIPS_INS(TLBR, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_TLBR)
+
+/* TLBWI - write indexed TLB entry */
+MIPS_INS(TLBWI, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_TLBWI)
+
+/* TLBWR - write random TLB entry */
+MIPS_INS(TLBWR, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_TLBWR)
+
+/* TLT - trap if less then */
+MIPS_INS(TLT, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_TLT)
+
+/* TLTI - trap if less then immediate */
+MIPS_INS(TLTI, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_TLTI)
+
+/* TLTIU - trap if less then immediate unsigned */
+MIPS_INS(TLTIU, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_TLTIU)
+
+/* TLTU - trap if less then unsigned */
+MIPS_INS(TLTU, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_TLTU)
+
+/* TNE - trap if not equal */
+MIPS_INS(TNE, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_TNE)
+
+/* TNEI - trap if not equal immediate */
+MIPS_INS(TNEI, .op = MIPS32R6_OP_REGIMM, .bfunct = MIPS32R6_FUNCT_TNEI)
+
+/* WAIT - enter standby mode */
+MIPS_INS(WAIT, .op = MIPS32R6_OP_COP0, .c0 = 1, .funct = MIPS32R6_FUNCT_WAIT)
+
+/* WRPGRP - write to GPR in previous shadow set */
+MIPS_INS(WRPGPR, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_WRPGPR)
+
+/* WSBH - word swap bytes within halfwords */
+MIPS_INS(WSBH, .op = MIPS32R6_OP_SPECIAL3, .funct = MIPS32R6_FUNCT_BSHFL,
+ .shamt = MIPS32R6_FUNCT_WSBH)
/* XOR - exclusive or */
MIPS_INS(XOR, .op = MIPS32R6_OP_SPECIAL, .funct = MIPS32R6_FUNCT_XOR)
@@ -284,3 +846,6 @@ MIPS_INS(XORI, .op = MIPS32R6_OP_XORI)
#undef MIPS_INS
+
+
+
diff --git a/masm/gen.c b/masm/gen.c
index c4a15a0..74d30d2 100644
--- a/masm/gen.c
+++ b/masm/gen.c
@@ -11,178 +11,9 @@
#include "parse.h"
///
-/// section table
-///
-
-static void section_get_default_perm(struct section *sec, const char *name)
-{
- #define __LEN 7
- static const struct perms {
- char *name;
- bool read;
- bool write;
- bool execute;
- int alignment;
- } defaults[__LEN] = {
- {".text", true, false, true, 4},
- {".code", true, false, true, 4},
- {".data", true, true, false, 1},
- {".stack", true, true, false, 1},
- {".rodata", true, false, false, 1},
- {".bss", true, true, false, 1},
- {".robss", true, false, false, 1},
- };
-
- for (int i = 0; i < __LEN; i++) {
- const struct perms *p = &defaults[i];
- if (strcasecmp(name, p->name) != 0)
- continue;
- sec->read = p->read;
- sec->write = p->write;
- sec->execute = p->execute;
- sec->align = p->alignment;
- break;
- }
-
-}
-
-static int section_get(struct generator *gen, struct section **res,
- const struct string *const name)
-{
- /// find the section if it exists
- for (size_t i = 0; i < gen->sections_len; i++) {
- struct section *sec = &gen->sections[i];
- if (sec->name.len != name->len)
- continue;
- if (strcmp(sec->name.str, name->str) != 0)
- continue;
- *res = sec;
- return M_SUCCESS;
- }
-
- /// allocate a new one if it doesnt
- size_t size = gen->sections_size ? gen->sections_size * 2 : 8;
- void *new = realloc(gen->sections, size * sizeof(struct section));
- if (new == NULL) {
- PERROR("cannot realloc");
- return M_ERROR;
- }
-
- gen->sections_size = size;
- gen->sections = new;
-
- struct section *sec = &gen->sections[gen->sections_len++];
-
- // alloc reftab
- if (reftab_init(&sec->reftab))
- return M_ERROR;
-
- // copy name
- if (string_clone(&sec->name, name))
- return M_ERROR;
-
- // set defaults
- sec->len = 0;
- sec->size = 0;
- sec->align = 1;
- sec->data = NULL;
- sec->read = true;
- sec->write = true;
- sec->execute = false;
- section_get_default_perm(sec, name->str);
-
- *res = sec;
- return M_SUCCESS;
-}
-
-static int section_extend(struct section *section, size_t space)
-{
- size_t newlen = section->len + space;
- if (newlen < section->size)
- return M_SUCCESS;
-
- size_t size = section->size ? section->size * 2 + newlen : newlen * 2;
- void *new = realloc(section->data, size);
- if (new == NULL) {
- PERROR("cannot realloc");
- return M_ERROR;
- }
- section->size = size;
- section->data = new;
-
- return M_SUCCESS;
-}
-
-static int section_push(struct section *section, void *data, size_t len)
-{
- size_t newlen = section->len + len;
- size_t zeros = newlen % section->align;
- if (zeros)
- zeros = section->align - zeros;
-
- if (section_extend(section, len + zeros))
- return M_ERROR;
-
- memset(section->data + section->len, 0, zeros);
- memcpy(section->data + section->len + zeros, data, len);
- section->len += len + zeros;
-
- return M_SUCCESS;
-}
-
-static int section_zero(struct section *section, size_t len)
-{
- size_t zeros = section->len % section->align;
- if (zeros)
- zeros = section->align - zeros;
-
- if (section_extend(section, len + zeros))
- return M_ERROR;
-
- memset(section->data + section->len, 0, len + zeros);
- section->len += len + zeros;
-
- return M_SUCCESS;
-}
-
-void section_free(struct section *section)
-{
- reftab_free(&section->reftab);
- string_free(&section->name);
- free(section->data);
-}
-
-///
/// generation functions
///
-static void print_curr_line(struct generator *gen,
- const struct expr *const expr)
-{
- int line = expr->line_no,
- len = expr->byte_end - expr->byte_start,
- nl = true,
- c = EOF;
- FILE *file = gen->parser.lexer.file;
-
- fseek(file, expr->byte_start, SEEK_SET);
-
- while (len--) {
- c = getc(file);
- if (c == EOF || c == '\0')
- break;
- if (nl) {
- fprintf(stderr, "\t%d | ", line);
- line++;
- nl = false;
- }
- if (c == '\n')
- nl = true;
- putc(c, stderr);
- }
-
-}
-
static int gen_directive_whb(struct generator *gen, const void *data,
uint32_t count, uint32_t len)
{
@@ -265,488 +96,6 @@ static int gen_constant(struct generator *gen, struct expr_const *const expr)
return M_ERROR;
}
-static int parse_register(enum mips32_register *reg, struct string *name)
-{
- int len = name->len;
- int c0 = len > 0 ? name->str[0] : '\0',
- c1 = len > 1 ? name->str[1] : '\0',
- c2 = len > 2 ? name->str[2] : '\0',
- c3 = len > 3 ? name->str[3] : '\0';
-
- // $zero
- if (c0 == 'z') {
- if (c1 == 'e' && c2 == 'r' && c3 == 'o') {
- *reg = MIPS32_REG_ZERO;
- return M_SUCCESS;
- }
- }
-
- // $a0-a3 $at
- else if (c0 == 'a') {
- if (c1 == 't') {
- *reg = MIPS32_REG_AT;
- return M_SUCCESS;
- }
- if (c1 >= '0' && c1 <= '3') {
- *reg = MIPS32_REG_A0;
- *reg += c1 - '0';
- return M_SUCCESS;
- }
- }
-
- // $v0-v1
- else if (c0 == 'v') {
- if (c1 >= '0' && c1 <= '1') {
- *reg = MIPS32_REG_V0;
- *reg += c1 - '0';
- return M_SUCCESS;
- }
- }
-
- // $t0-t9
- else if (c0 == 't') {
- if (c1 >= '0' && c1 <= '7') {
- *reg = MIPS32_REG_T0;
- *reg += c1 - '0';
- return M_SUCCESS;
- }
- // reg T8-T9 are not in order with T0-T7
- if (c1 >= '8' && c1 <= '9') {
- *reg = MIPS32_REG_T8;
- *reg += c1 - '8';
- return M_SUCCESS;
- }
- }
-
- // $s0-s7 $sp
- else if (c0 == 's') {
- if (c1 >= '0' && c1 <= '7') {
- *reg = MIPS32_REG_S0;
- *reg += c1 - '0';
- return M_SUCCESS;
- }
- if (c1 == 'p') {
- *reg = MIPS32_REG_SP;
- return M_SUCCESS;
- }
- }
-
- // $k0-k1
- else if (c0 == 'k') {
- if (c1 >= '0' && c1 <= '1') {
- *reg = MIPS32_REG_K0;
- *reg += c1 - '0';
- return M_SUCCESS;
- }
- }
-
- // $gp
- else if (c0 == 'g') {
- if (c1 == 'p') {
- *reg = MIPS32_REG_GP;
- return M_SUCCESS;
- }
- }
-
- // $fp
- else if (c0 == 'f') {
- if (c1 == 'p') {
- *reg = MIPS32_REG_FP;
- return M_SUCCESS;
- }
- }
-
- // $rp
- else if (c0 == 'r') {
- if (c1 == 'a') {
- *reg = MIPS32_REG_RA;
- return M_SUCCESS;
- }
- }
-
- // $0-31 (non aliased register names)
- else if (c0 >= '0' && c0 <= '9') {
- int i = c0 - '0';
- if (c1 >= '0' && c1 <= '9') {
- i *= 10;
- i += c1 - '0';
- }
- if (i <= 31) {
- *reg = i;
- return M_SUCCESS;
- }
- }
-
- ERROR("unknown register $%.*s", name->len, name->str);
- return M_ERROR;
-}
-
-static int parse_fp_register(enum mips32_fp_register *reg, struct string *name)
-{
- int len = name->len;
- int c0 = len > 0 ? name->str[0] : '\0',
- c1 = len > 1 ? name->str[1] : '\0',
- c2 = len > 2 ? name->str[2] : '\0';
-
- *reg = 0;
-
- if (c0 != 'f')
- goto error;
-
- if (c1 < '0' || c1 > '9')
- goto error;
-
- *reg += c1 - '0';
-
- if (c1 == '\0')
- return M_SUCCESS;
-
- if (c2 < '0' || c2 > '9')
- goto error;
-
- *reg *= 10;
- *reg += c2 - '0';
-
- return M_SUCCESS;
-
-error:
- ERROR("unknown fp register $%.*s", name->len, name->str);
- return M_ERROR;
-
-}
-
-static enum grammer_type get_gmr_type(const char *name, size_t *len)
-{
- #define CHK(part, str) { \
- if (strncasecmp(str, name, strlen(str)) == 0) { \
- *len = strlen(str); \
- return GMR_ ##part; \
- }} \
-
- CHK(RD, "rd")
- CHK(RS, "rs")
- CHK(RT, "rt")
- CHK(FS, "fs")
- CHK(FT, "ft")
- CHK(FD, "fd")
- CHK(IMMD, "immd")
- CHK(CC, "cc")
- CHK(CODE, "code")
- CHK(POS, "pos")
- CHK(SIZE, "size")
- CHK(HB, "hb")
- CHK(HINT, "hint")
- CHK(OFFSET_BASE, "offset(base)")
- CHK(INDEX_BASE, "index(base)")
- CHK(OFFSET, "offset")
- CHK(TARGET, "target")
- CHK(HI, "hi")
- CHK(LO, "lo")
-
- #undef CHK
-
- BUG("invalid grammer key: %s", name);
- exit(1);
-}
-
-static int get_gmr_hc(struct gen_ins_state *state,
- struct gen_ins_override *over,
- char *value)
-{
- int vlen = 0;
- int res = M_SUCCESS;
-
- /* get length of value */
- for (const char *ptr = value;
- *ptr != '\0' && *ptr != ',';
- ptr++, vlen++);
-
- /* must be at least of length 1 */
- if (vlen < 1)
- return M_ERROR;
-
- #define VAL(v) if (strncmp(v, value, vlen) == 0)
- /* register to register mapping */
- VAL("rd")
- over->reg = state->rd;
- else VAL("rs")
- over->reg = state->rs;
- else VAL("rt")
- {
- over->reg = state->rt;
- }
- else VAL("fs")
- over->fpreg = state->fs;
- else VAL("ft")
- over->fpreg = state->ft;
- else VAL("fd")
- over->fpreg = state->fd;
- else VAL("immd")
- over->immd = state->immd;
- else VAL("-immd")
- over->immd = -state->immd;
- /* hardcoded register */
- else if (*value == '$') {
- // register
- if (vlen < 2)
- return M_ERROR;
- struct string name;
- name.str = value + 1;
- name.len = vlen - 1;
- if (*name.str == 'f')
- res = parse_fp_register(&over->fpreg, &name);
- else
- res = parse_register(&over->reg, &name);
- /* hardcoded immediate */
- } else {
- // immediate
- char c;
- int immd = 0;
- while (c = *(value++), c != ',' && c != '\0') {
- if (c < '0' || c > '9')
- return M_ERROR;
- immd *= 10;
- immd += c - '0';
- }
- over->immd = immd;
- }
-
- #undef KEY
-
- return res;
-}
-
-static int gen_ins_read_state(struct generator *gen,
- struct expr *const expr,
- struct gen_ins_state *state,
- struct mips32_grammer *grammer)
-{
- char *ptr = grammer->grammer;
- uint32_t argi = 0;
-
- // read values into state
- while (*ptr != '\0') {
-
- if (argi >= expr->instruction.args_len) {
- ERROR("not enough arguments passed");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- struct expr_ins_arg *arg = &expr->instruction.args[argi++];
-
- size_t skip;
- switch (get_gmr_type(ptr, &skip)) {
- case GMR_RD:
- // rd
- if (arg->type != EXPR_INS_ARG_REGISTER) {
- ERROR("expected a register");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- if (parse_register(&state->rd, &arg->reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_RS:
- // rs
- if (arg->type != EXPR_INS_ARG_REGISTER) {
- ERROR("expected a register");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- if (parse_register(&state->rs, &arg->reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_RT:
- // rt
- if (arg->type != EXPR_INS_ARG_REGISTER) {
- ERROR("expected a register");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- if (parse_register(&state->rt, &arg->reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_FS:
- // fs
- if (arg->type != EXPR_INS_ARG_REGISTER) {
- ERROR("expected a register");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- if (parse_fp_register(&state->fs, &arg->reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_FT:
- // ft
- if (arg->type != EXPR_INS_ARG_REGISTER) {
- ERROR("expected a register");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- if (parse_fp_register(&state->ft, &arg->reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_FD:
- // fd
- if (arg->type != EXPR_INS_ARG_REGISTER) {
- ERROR("expected a register");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- if (parse_fp_register(&state->fd, &arg->reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_IMMD:
- // immd
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->immd = arg->immd;
- break;
- case GMR_CC:
- // cc
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->cc = arg->immd;
- break;
- case GMR_CODE:
- // code
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->code = arg->immd;
- break;
- case GMR_POS:
- // pos
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->pos = arg->immd;
- break;
- case GMR_SIZE:
- // size
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- // TODO: check valid size
- state->size = arg->immd;
- break;
- case GMR_HB:
- // hb
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->hb = !!(arg->immd);
- break;
- case GMR_HINT:
- // hint
- if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
- ERROR("expected an immediate");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->hint = arg-> immd;
- break;
- case GMR_OFFSET:
- // offset
- state->offset = 0;
- if (arg->type == EXPR_INS_ARG_IMMEDIATE)
- state->offset = arg->immd;
- else if (arg->type == EXPR_INS_ARG_LABEL)
- state->label = &arg->label;
- else {
- ERROR("invalid instruction");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_OFFSET_BASE:
- // offset(base)
- if (arg->type != EXPR_INS_ARG_OFFSET) {
- ERROR("expected an offset($base)");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->offset = arg->offset.immd;
- if (parse_register(&state->base, &arg->offset.reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_INDEX_BASE:
- // index(base)
- if (arg->type != EXPR_INS_ARG_OFFSET) {
- ERROR("expected an index($base)");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- state->index = arg->offset.immd;
- if (parse_register(&state->base, &arg->offset.reg)) {
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- case GMR_TARGET:
- // target
- state->target = 0;
- if (arg->type == EXPR_INS_ARG_IMMEDIATE)
- state->target = arg->immd;
- else if (arg->type == EXPR_INS_ARG_LABEL)
- state->label = &arg->label;
- else {
- ERROR("invalid instruction");
- print_curr_line(gen, expr);
- return M_ERROR;
- }
- break;
- default:
- break;
- }
-
- // skip entry
- ptr += skip;
-
- // skip comma
- if (*ptr == ',') {
- ptr++;
- continue;
- } else if (*ptr == '\0') {
- break;
- } else {
- BUG("invalid grammer '%s'", grammer);
- exit(1);
- }
-
- }
-
- return M_SUCCESS;
-}
-
static int gen_ins_write_state(
struct generator *gen,
union mips32_instruction ins, // the instruction to modify
@@ -1037,6 +386,12 @@ static int generate(struct generator *gen)
return M_SUCCESS;
}
+//
+// the following functions set default generator
+// state values for different versions of the mips
+// isa
+//
+
/* run codegen with the mips32r6 specification */
int generate_mips32r6(struct generator *gen)
{
@@ -1067,6 +422,10 @@ int generate_mips1(struct generator *gen)
return generate(gen);
}
+//
+// constructors and deconstructors
+//
+
int generator_init(const char *file, struct generator *gen)
{
if (parser_init(file, &gen->parser))
diff --git a/masm/gen.h b/masm/gen.h
index 42fbf50..ed35750 100644
--- a/masm/gen.h
+++ b/masm/gen.h
@@ -37,8 +37,26 @@ struct section {
struct reference_table reftab;
};
+/* get a section from the generator by name, and return it into res. if the
+ * section does not exist, one will be created. */
+int gen_get_section(struct generator *gen, struct section **res,
+ struct string *name);
+
+/* initalize a section */
+int section_init(struct section *section, struct string *name);
+
+/* free a section */
void section_free(struct section *section);
+/* extend a section by space bytes plus alignment */
+int section_extend(struct section *section, size_t space);
+
+/* push data into a section */
+int section_push(struct section *section, void *data, size_t len);
+
+/* push zeros (empty space) to a section */
+int section_zero(struct section *section, size_t len);
+
///
/// instruction generation state
///
@@ -55,36 +73,35 @@ struct gen_ins_state {
enum mips32_fp_register fd;
// immd
- uint16_t immd; // 16 bit
+ uint16_t immd;
// cc
- uint16_t cc; // 3 bit
+ uint16_t cc;
// code
- uint32_t code; // 5 bit
+ uint32_t code;
// pos
- uint32_t pos; // 5 bit
+ uint32_t pos;
// size
- uint32_t size; // 5 bit - 1
-
- // hb
- bool hb; // 1 bit - 1
-
- // index
- uint32_t index;
+ uint32_t size;
// hint
uint32_t hint;
- // offset(base)
- uint16_t offset; // 16 bit
- enum mips32_register base;
+ // hazard barrier
+ bool hb; // 1 bit - 1
// target
uint32_t target;
+ // index(base)
+ // offset(base)
+ uint32_t index;
+ uint16_t offset;
+ enum mips32_register base;
+
// current referencd label
struct string *label;
};
@@ -95,16 +112,11 @@ struct gen_ins_override {
uint32_t immd;
};
-///
-/// grammer type
-///
-
enum grammer_type {
// registers
GMR_RD,
GMR_RS,
GMR_RT,
- GMR_INDEX_BASE,
// fp registers
GMR_FS,
GMR_FT,
@@ -118,13 +130,47 @@ enum grammer_type {
GMR_HB,
GMR_HINT,
// addresses
- GMR_OFFSET,
- GMR_OFFSET_BASE,
- GMR_TARGET,
GMR_HI,
GMR_LO,
+ GMR_TARGET,
+ GMR_OFFSET,
+ GMR_INDEX_BASE,
+ GMR_OFFSET_BASE,
+ // len
+ __GMR_LEN
};
+/* Parses the input string and matches it to a grammer type. Returns
+ * the number of characters consumed, or -1 on error.
+ */
+int gen_parse_grammer_type(const char *name, enum grammer_type *res);
+
+/* Parses a register name, returing 0 on success, 1 on error*/
+int gen_parse_register(enum mips32_register *reg, struct string *name);
+
+/* Parses a floating point register name, returing 0 on success, 1 on error*/
+int gen_parse_fp_register(enum mips32_fp_register *reg, struct string *name);
+
+/* Parses the overide expression (after the =) in the dsl for the grammer.
+ * returns the number of characters consumed, or -1 on error. */
+int gen_parse_grammer_overide(struct gen_ins_state *state,
+ struct gen_ins_override *over, char *value);
+
+/* Given a grammer for an instruction, read all args as values into the
+ * instruction generator state. */
+int gen_read_grammer_state(struct generator *gen,
+ struct expr *const expr,
+ struct gen_ins_state *state,
+ struct mips32_grammer *grammer);
+
+/* Given a grammer for an instruction, and a read state, output multiple
+ * instructions into the current section in the generator. note:
+ * this write_grammer is different from the read grammer such that
+ * it supports paramater reassignment and overides. */
+int gen_write_grammer_state(struct generator *gen,
+ struct gen_ins_state *state,
+ char *write_grammer);
+
///
/// generates assembley
/// from a parser stream
@@ -152,6 +198,9 @@ struct generator {
struct symbol_table symtab;
};
+/* output the source code lines for a provided expression */
+void gen_output_expr(struct generator *gen, struct expr *expr);
+
/* generate the input as mips32r6 */
int generate_mips32r6(struct generator *gen);
/* run codegen with the mips32r2 specification */
diff --git a/masm/gen/grammer.c b/masm/gen/grammer.c
new file mode 100644
index 0000000..d7327da
--- /dev/null
+++ b/masm/gen/grammer.c
@@ -0,0 +1,643 @@
+#include <strings.h>
+#include <string.h>
+#include <merror.h>
+
+#include "../gen.h"
+#include "mips.h"
+
+struct grammer_mapping {
+ char *name;
+ int name_len;
+ enum grammer_type type;
+};
+
+#define MAPPING(name, enum) {name, sizeof(name), GMR_ ##enum}
+
+static const struct grammer_mapping grammer_mappings[__GMR_LEN] = {
+ // registers
+ MAPPING("rd", RD),
+ MAPPING("rs", RS),
+ MAPPING("rt", RT),
+ // fp registers
+ MAPPING("fs", FS),
+ MAPPING("ft", FT),
+ MAPPING("fd", FD),
+ // numberic fileds
+ MAPPING("immd", IMMD),
+ MAPPING("cc", CC),
+ MAPPING("code", CODE),
+ MAPPING("pos", POS),
+ MAPPING("size", SIZE),
+ MAPPING("hb", HB),
+ MAPPING("hint", HINT),
+ // addresses
+ MAPPING("hi", HI),
+ MAPPING("lo", LO),
+ MAPPING("target", TARGET),
+ MAPPING("offset", OFFSET),
+ MAPPING("offset(base)", OFFSET_BASE),
+ MAPPING("index(base)", INDEX_BASE)
+};
+
+/* Parses the input string and matches it to a grammer type. Returns
+ * the number of characters consumed, or -1 on error.
+ */
+int gen_parse_grammer_type(const char *name, enum grammer_type *res)
+{
+ for (int i = 0; i < __GMR_LEN; i++) {
+ const struct grammer_mapping *mapping = &grammer_mappings[i];
+ if (strncasecmp(name, mapping->name, mapping->name_len) != 0)
+ continue;
+ if (res != NULL)
+ *res = mapping->type;
+ return mapping->name_len;
+ }
+
+ return -1;
+}
+
+/* Parses a register name, returing 0 on success, 1 on error*/
+int gen_parse_register(enum mips32_register *reg, struct string *name)
+{
+ int len = name->len;
+ int c0 = len > 0 ? name->str[0] : '\0',
+ c1 = len > 1 ? name->str[1] : '\0',
+ c2 = len > 2 ? name->str[2] : '\0',
+ c3 = len > 3 ? name->str[3] : '\0';
+
+ // $zero
+ if (c0 == 'z') {
+ if (c1 == 'e' && c2 == 'r' && c3 == 'o') {
+ *reg = MIPS32_REG_ZERO;
+ return M_SUCCESS;
+ }
+ }
+
+ // $a0-a3 $at
+ else if (c0 == 'a') {
+ if (c1 == 't') {
+ *reg = MIPS32_REG_AT;
+ return M_SUCCESS;
+ }
+ if (c1 >= '0' && c1 <= '3') {
+ *reg = MIPS32_REG_A0;
+ *reg += c1 - '0';
+ return M_SUCCESS;
+ }
+ }
+
+ // $v0-v1
+ else if (c0 == 'v') {
+ if (c1 >= '0' && c1 <= '1') {
+ *reg = MIPS32_REG_V0;
+ *reg += c1 - '0';
+ return M_SUCCESS;
+ }
+ }
+
+ // $t0-t9
+ else if (c0 == 't') {
+ if (c1 >= '0' && c1 <= '7') {
+ *reg = MIPS32_REG_T0;
+ *reg += c1 - '0';
+ return M_SUCCESS;
+ }
+ // reg T8-T9 are not in order with T0-T7
+ if (c1 >= '8' && c1 <= '9') {
+ *reg = MIPS32_REG_T8;
+ *reg += c1 - '8';
+ return M_SUCCESS;
+ }
+ }
+
+ // $s0-s7 $sp
+ else if (c0 == 's') {
+ if (c1 >= '0' && c1 <= '7') {
+ *reg = MIPS32_REG_S0;
+ *reg += c1 - '0';
+ return M_SUCCESS;
+ }
+ if (c1 == 'p') {
+ *reg = MIPS32_REG_SP;
+ return M_SUCCESS;
+ }
+ }
+
+ // $k0-k1
+ else if (c0 == 'k') {
+ if (c1 >= '0' && c1 <= '1') {
+ *reg = MIPS32_REG_K0;
+ *reg += c1 - '0';
+ return M_SUCCESS;
+ }
+ }
+
+ // $gp
+ else if (c0 == 'g') {
+ if (c1 == 'p') {
+ *reg = MIPS32_REG_GP;
+ return M_SUCCESS;
+ }
+ }
+
+ // $fp
+ else if (c0 == 'f') {
+ if (c1 == 'p') {
+ *reg = MIPS32_REG_FP;
+ return M_SUCCESS;
+ }
+ }
+
+ // $rp
+ else if (c0 == 'r') {
+ if (c1 == 'a') {
+ *reg = MIPS32_REG_RA;
+ return M_SUCCESS;
+ }
+ }
+
+ // $0-31 (non aliased register names)
+ else if (c0 >= '0' && c0 <= '9') {
+ int i = c0 - '0';
+ if (c1 >= '0' && c1 <= '9') {
+ i *= 10;
+ i += c1 - '0';
+ }
+ if (i <= 31) {
+ *reg = i;
+ return M_SUCCESS;
+ }
+ }
+
+ ERROR("unknown register $%.*s", name->len, name->str);
+ return 1;
+}
+
+/* Parses a floating point register name, returing 0 on success, 1 on error*/
+int gen_parse_fp_register(enum mips32_fp_register *reg, struct string *name)
+{
+ int len = name->len;
+ int c0 = len > 0 ? name->str[0] : '\0',
+ c1 = len > 1 ? name->str[1] : '\0',
+ c2 = len > 2 ? name->str[2] : '\0';
+
+ *reg = 0;
+
+ if (c0 != 'f')
+ goto error;
+
+ if (c1 < '0' || c1 > '9')
+ goto error;
+
+ *reg += c1 - '0';
+
+ if (c1 == '\0')
+ return M_SUCCESS;
+
+ if (c2 < '0' || c2 > '9')
+ goto error;
+
+ *reg *= 10;
+ *reg += c2 - '0';
+
+ return M_SUCCESS;
+
+error:
+ ERROR("unknown fp register $%.*s", name->len, name->str);
+ return 1;
+
+}
+
+/* convert string to number with int len max length */
+static int antoi(char *str, int len)
+{
+ char c;
+ int num = 0;
+
+ while (c = *str++, len--) {
+ if (c < '0' || c > '9')
+ break;
+ num *= 10;
+ num += c - '0';
+ }
+
+ return num;
+}
+
+/* Parses the override expression (after the =) in the dsl for the grammer.
+ * returns the number of characters consumed, or -1 on error. */
+int gen_parse_grammer_override(struct gen_ins_state *state,
+ struct gen_ins_override *over, char *value)
+{
+ int value_len = 0;
+
+ /* get length of value */
+ for (const char *ptr = value;
+ *ptr != '\0' && *ptr != ',';
+ ptr++, value_len++);
+
+ // rd
+ if (strncmp("rd", value, value_len))
+ over->reg = state->rd;
+ // rs
+ else if (strncmp("rs", value, value_len))
+ over->reg = state->rs;
+ // rt
+ else if (strncmp("rt", value, value_len))
+ over->reg = state->rt;
+
+ // fd
+ else if (strncmp("fd", value, value_len))
+ over->fpreg = state->fd;
+ // fs
+ else if (strncmp("fs", value, value_len))
+ over->fpreg = state->fs;
+ // ft
+ else if (strncmp("ft", value, value_len))
+ over->fpreg = state->ft;
+
+ // immd
+ else if (strncmp("immd", value, value_len))
+ over->immd = state->immd;
+ // -immd
+ else if (strncmp("-immd", value, value_len))
+ over->immd = -state->immd;
+
+ // floating point register
+ else if (value_len > 2 && value[0] == '$' && value[1] == 'f') {
+ struct string temp = {
+ .str = value + 1,
+ .len = value_len - 1
+ };
+ if (gen_parse_fp_register(&over->fpreg, &temp))
+ return -1;
+ }
+
+ // register
+ else if (value_len > 1 && value[0] == '$') {
+ struct string temp = {
+ .str = value + 1,
+ .len = value_len - 1
+ };
+ if (gen_parse_register(&over->reg, &temp))
+ return -1;
+ }
+
+ // number
+ else
+ over->immd = antoi(value, value_len);
+
+ return value_len;
+}
+
+static int read_next_state(struct expr_ins_arg *arg,
+ struct gen_ins_state *state,
+ enum grammer_type type)
+{
+ switch (type) {
+ case GMR_RD:
+ // rd
+ if (arg->type != EXPR_INS_ARG_REGISTER) {
+ ERROR("expected a register");
+ return 1;
+ }
+ if (gen_parse_register(&state->rd, &arg->reg))
+ return 1;
+ break;
+ case GMR_RS:
+ // rs
+ if (arg->type != EXPR_INS_ARG_REGISTER) {
+ ERROR("expected a register");
+ return 1;
+ }
+ if (gen_parse_register(&state->rs, &arg->reg))
+ return 1;
+ break;
+ case GMR_RT:
+ // rt
+ if (arg->type != EXPR_INS_ARG_REGISTER) {
+ ERROR("expected a register");
+ return 1;
+ }
+ if (gen_parse_register(&state->rt, &arg->reg))
+ return 1;
+ break;
+ case GMR_FS:
+ // fs
+ if (arg->type != EXPR_INS_ARG_REGISTER) {
+ ERROR("expected a register");
+ return 1;
+ }
+ if (gen_parse_fp_register(&state->fs, &arg->reg))
+ return 1;
+ break;
+ case GMR_FT:
+ // ft
+ if (arg->type != EXPR_INS_ARG_REGISTER) {
+ ERROR("expected a register");
+ return 1;
+ }
+ if (gen_parse_fp_register(&state->ft, &arg->reg))
+ return 1;
+ break;
+ case GMR_FD:
+ // fd
+ if (arg->type != EXPR_INS_ARG_REGISTER) {
+ ERROR("expected a register");
+ return 1;
+ }
+ if (gen_parse_fp_register(&state->fd, &arg->reg))
+ return 1;
+ break;
+ case GMR_IMMD:
+ // immd
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ state->immd = arg->immd;
+ break;
+ case GMR_CC:
+ // cc
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ state->cc = arg->immd;
+ break;
+ case GMR_CODE:
+ // code
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ state->code = arg->immd;
+ break;
+ case GMR_POS:
+ // pos
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ state->pos = arg->immd;
+ break;
+ case GMR_SIZE:
+ // size
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ // TODO: check valid size
+ state->size = arg->immd;
+ break;
+ case GMR_HB:
+ // hb
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ state->hb = !!(arg->immd);
+ break;
+ case GMR_HINT:
+ // hint
+ if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
+ ERROR("expected an immediate");
+ return 1;
+ }
+ state->hint = arg-> immd;
+ break;
+ case GMR_OFFSET:
+ // offset
+ state->offset = 0;
+ if (arg->type == EXPR_INS_ARG_IMMEDIATE)
+ state->offset = arg->immd;
+ else if (arg->type == EXPR_INS_ARG_LABEL)
+ state->label = &arg->label;
+ else {
+ ERROR("invalid instruction");
+ return 1;
+ }
+ break;
+ case GMR_OFFSET_BASE:
+ // offset(base)
+ if (arg->type != EXPR_INS_ARG_OFFSET) {
+ ERROR("expected an offset($base)");
+ return 1;
+ }
+ state->offset = arg->offset.immd;
+ if (gen_parse_register(&state->base, &arg->offset.reg))
+ return 1;
+ break;
+ case GMR_INDEX_BASE:
+ // index(base)
+ if (arg->type != EXPR_INS_ARG_OFFSET) {
+ ERROR("expected an index($base)");
+ return 1;
+ }
+ state->index = arg->offset.immd;
+ if (gen_parse_register(&state->base, &arg->offset.reg))
+ return 1;
+ break;
+ case GMR_TARGET:
+ // target
+ state->target = 0;
+ if (arg->type == EXPR_INS_ARG_IMMEDIATE)
+ state->target = arg->immd;
+ else if (arg->type == EXPR_INS_ARG_LABEL)
+ state->label = &arg->label;
+ else {
+ ERROR("invalid instruction");
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int gen_read_grammer_state(struct generator *gen,
+ struct expr *const expr,
+ struct gen_ins_state *state,
+ struct mips32_grammer *grammer)
+{
+
+ char *ptr = grammer->grammer;
+ uint32_t argi = 0;
+
+ // read values into state
+ while (*ptr != '\0') {
+ struct expr_ins_arg *arg;
+ enum grammer_type type;
+ size_t consumed;
+
+ if (argi >= expr->instruction.args_len) {
+ ERROR("not enough arguments passed");
+ gen_output_expr(gen, expr);
+ return 1;
+ }
+
+ arg = &expr->instruction.args[argi++];
+ consumed = gen_parse_grammer_type(ptr, &type);
+
+ if (consumed < 0) {
+ BUG("invalid grammer: %s", grammer);
+ return 1;
+ }
+
+ if (read_next_state(arg, state, type)) {
+ gen_output_expr(gen, expr);
+ return 1;
+ }
+
+ ptr += consumed;
+
+ if (*ptr == ',') {
+ ptr++;
+ continue;
+ }
+
+ if (*ptr != '\0') {
+ BUG("invalid grammer: %s", grammer);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int write_next_state(struct gen_ins_state *state,
+ struct gen_ins_override *over,
+ union mips32_instruction *ins,
+ enum reference_type *reftype,
+ char *ptr)
+{
+ enum grammer_type type;
+ size_t consumed;
+ bool hc = false;
+
+ consumed = gen_parse_grammer_type(ptr, &type);
+
+ if (consumed < 0) {
+ BUG("invalid grammer: %s", ptr);
+ return -1;
+ }
+
+ if (*(ptr + consumed) == '=') {
+ hc = true;
+ consumed += gen_parse_grammer_override(state, over, ptr);
+
+ if (consumed < 0) {
+ BUG("invalid grammer: %s", ptr);
+ return -1;
+ }
+ }
+
+ switch (type) {
+ case GMR_RD:
+ ins->rd = hc ? over->reg : state->rd;
+ break;
+ case GMR_RS:
+ ins->rs = hc ? over->reg : state->rs;
+ break;
+ case GMR_RT:
+ ins->rt = hc ? over->reg : state->rt;
+ break;
+ case GMR_FS:
+ ins->fs = hc ? over->fpreg : state->fs;
+ break;
+ case GMR_FT:
+ ins->ft = hc ? over->fpreg : state->ft;
+ break;
+ case GMR_FD:
+ ins->fd = hc ? over->fpreg : state->fd;
+ break;
+ case GMR_IMMD:
+ ins->immd = hc ? over->immd : state->immd;
+ break;
+ case GMR_CC:
+ ins->cc = state->cc;
+ break;
+ case GMR_CODE:
+ ins->code = state->code;
+ break;
+ case GMR_POS:
+ ins->shamt = state->pos;
+ break;
+ case GMR_SIZE:
+ ins->rd = state->size ? state->size - 1 : 0;
+ break;
+ case GMR_HB:
+ ins->hb = hc ? over->immd : state->hb;
+ break;
+ case GMR_HINT:
+ ins->rt = state->hint;
+ break;
+ case GMR_OFFSET:
+ ins->offset = state->offset;
+ *reftype = REF_MIPS_PC16;
+ break;
+ case GMR_OFFSET_BASE:
+ ins->offset = state->offset;
+ ins->rs = state->base;
+ *reftype = REF_MIPS_16;
+ break;
+ case GMR_INDEX_BASE:
+ ins->rt = state->index;
+ ins->rs = state->base;
+ break;
+ case GMR_TARGET:
+ ins->target = state->target;
+ *reftype = REF_MIPS_26;
+ break;
+ case GMR_HI:
+ ins->immd = state->target >> 16;
+ *reftype = REF_MIPS_HI16;
+ break;
+ case GMR_LO:
+ ins->immd = state->target & 0x0000FFFF;
+ *reftype = REF_MIPS_LO16;
+ break;
+ default:
+ break;
+ }
+
+ return consumed;
+}
+
+
+int gen_write_grammer_state(struct generator *gen,
+ struct gen_ins_state *state,
+ char *grammer)
+{
+ enum reference_type reftype = REF_NONE;
+ struct gen_ins_override over;
+ char *ptr = grammer;
+
+ union mips32_instruction ins;
+
+ while (*ptr != '\0') {
+ int consumed;
+
+ consumed = write_next_state(state, &over,
+ &ins, &reftype, ptr);
+
+ if (consumed < 0)
+ return 1;
+
+ ptr += consumed;
+
+ if (*ptr == ',') {
+ ptr++;
+ continue;
+ }
+
+ if (*ptr != '\0') {
+ BUG("invalid grammer: %s", grammer);
+ return 1;
+ }
+ }
+
+
+}
diff --git a/masm/gen/log.c b/masm/gen/log.c
new file mode 100644
index 0000000..2df455b
--- /dev/null
+++ b/masm/gen/log.c
@@ -0,0 +1,28 @@
+#include "../gen.h"
+
+void gen_output_expr(struct generator *gen, struct expr *expr)
+{
+ int line = expr->line_no,
+ len = expr->byte_end - expr->byte_start,
+ nl = true,
+ c = EOF;
+ FILE *file = gen->parser.lexer.file;
+
+ fseek(file, expr->byte_start, SEEK_SET);
+
+ while (len--) {
+ c = getc(file);
+ if (c == EOF || c == '\0')
+ break;
+ if (nl) {
+ fprintf(stderr, "\t%d | ", line);
+ line++;
+ nl = false;
+ }
+ if (c == '\n')
+ nl = true;
+ putc(c, stderr);
+ }
+
+}
+
diff --git a/masm/gen/section.c b/masm/gen/section.c
new file mode 100644
index 0000000..44f83f8
--- /dev/null
+++ b/masm/gen/section.c
@@ -0,0 +1,156 @@
+#include "../gen.h"
+
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+#include <merror.h>
+
+struct section_default {
+ char *name;
+ int name_len;
+
+ bool read;
+ bool write;
+ bool execute;
+ int alignment;
+};
+
+#define SECTION_DEFAULTS_LEN 7
+#define MAPPING(name, ...) {name, sizeof(name), __VA_ARGS__}
+static const struct section_default section_defaults[SECTION_DEFAULTS_LEN] = {
+ MAPPING(".text", true, false, true, 4),
+ MAPPING(".code", true, false, true, 4),
+ MAPPING(".data", true, true, false, 1),
+ MAPPING(".stack", true, true, false, 1),
+ MAPPING(".rodata", true, false, false, 1),
+ MAPPING(".bss", true, true, false, 1),
+ MAPPING(".robss", true, false, false, 1),
+};
+
+static void section_get_default_perm(struct section *sec, const char *name)
+{
+ for (int i = 0; i < SECTION_DEFAULTS_LEN; i++) {
+ const struct section_default *defaults = &section_defaults[i];
+ if (strncasecmp(name, defaults->name, defaults->name_len))
+ continue;
+ sec->read = defaults->read;
+ sec->write = defaults->write;
+ sec->execute = defaults->execute;
+ sec->align = defaults->alignment;
+ break;
+ }
+}
+
+int gen_get_section(struct generator *gen, struct section **res,
+ struct string *name)
+{
+ /// find the section if it exists
+ for (size_t i = 0; i < gen->sections_len; i++) {
+ struct section *sec = &gen->sections[i];
+ if (sec->name.len != name->len)
+ continue;
+ if (strcmp(sec->name.str, name->str) != 0)
+ continue;
+ *res = sec;
+ return 0;
+ }
+
+ /// allocate a new one if it doesnt
+ size_t size = gen->sections_size ? gen->sections_size * 2 : 8;
+ void *new = realloc(gen->sections, size * sizeof(struct section));
+ if (new == NULL) {
+ PERROR("cannot realloc");
+ return 1;
+ }
+
+ gen->sections_size = size;
+ gen->sections = new;
+
+ struct section *sec = &gen->sections[gen->sections_len++];
+ if (section_init(sec, name))
+ return 1;
+
+ *res = sec;
+ return 0;
+}
+
+int section_init(struct section *sec, struct string *name)
+{
+ sec->len = 0;
+ sec->size = 0;
+ sec->align = 1;
+ sec->data = NULL;
+ sec->read = true;
+ sec->write = true;
+ sec->execute = false;
+
+ // set defaults
+ section_get_default_perm(sec, name->str);
+
+ // alloc reftab
+ if (reftab_init(&sec->reftab))
+ return 1;
+
+ // copy name
+ if (string_clone(&sec->name, name))
+ return 1;
+
+ return 0;
+}
+
+int section_extend(struct section *section, size_t space)
+{
+ size_t newlen = section->len + space;
+ if (newlen < section->size)
+ return M_SUCCESS;
+
+ size_t size = section->size ? section->size * 2 + newlen : newlen * 2;
+ void *new = realloc(section->data, size);
+ if (new == NULL) {
+ PERROR("cannot realloc");
+ return M_ERROR;
+ }
+ section->size = size;
+ section->data = new;
+
+ return M_SUCCESS;
+}
+
+int section_push(struct section *section, void *data, size_t len)
+{
+ size_t newlen = section->len + len;
+ size_t zeros = newlen % section->align;
+ if (zeros)
+ zeros = section->align - zeros;
+
+ if (section_extend(section, len + zeros))
+ return M_ERROR;
+
+ memset(section->data + section->len, 0, zeros);
+ memcpy(section->data + section->len + zeros, data, len);
+ section->len += len + zeros;
+
+ return M_SUCCESS;
+}
+
+int section_zero(struct section *section, size_t len)
+{
+ size_t zeros = section->len % section->align;
+ if (zeros)
+ zeros = section->align - zeros;
+
+ if (section_extend(section, len + zeros))
+ return M_ERROR;
+
+ memset(section->data + section->len, 0, len + zeros);
+ section->len += len + zeros;
+
+ return M_SUCCESS;
+}
+
+void section_free(struct section *section)
+{
+ reftab_free(&section->reftab);
+ string_free(&section->name);
+ free(section->data);
+}
diff --git a/masm/reftab.c b/masm/tab/reftab.c
index f8793e1..3eddc50 100644
--- a/masm/reftab.c
+++ b/masm/tab/reftab.c
@@ -1,7 +1,7 @@
#include <stdlib.h>
#include <merror.h>
-#include "tab.h"
+#include "../tab.h"
#define REFTAB_INIT_LEN 8
diff --git a/masm/symtab.c b/masm/tab/symtab.c
index 990be46..a2aa1ea 100644
--- a/masm/symtab.c
+++ b/masm/tab/symtab.c
@@ -5,8 +5,7 @@
#include <stdlib.h>
#include <string.h>
-#include "lex.h"
-#include "tab.h"
+#include "../tab.h"
#define SYMTBL_INIT_LEN 24