Compare commits

..

6 commits

26 changed files with 4407 additions and 731 deletions

View file

@ -6,6 +6,7 @@
#include <elf.h>
#include <arpa/inet.h>
/// mips is a big endian system
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define B32(n) (__bswap_constant_32(n))
#define B16(n) (__bswap_constant_16(n))
@ -32,7 +33,7 @@ static const Elf32_Ehdr MIPS_ELF_EHDR =
.e_machine = B16(EM_MIPS),
.e_version = B32(EV_CURRENT),
.e_entry = 0x00,
.e_flags = B32(EF_MIPS_ARCH_32R6 | EF_MIPS_NAN2008 | EF_MIPS_ABI_O32),
.e_flags = 0x00,
.e_ehsize = B16(sizeof(Elf32_Ehdr)),
.e_phentsize = B16(sizeof(Elf32_Phdr)),
.e_shentsize = B16(sizeof(Elf32_Shdr)),

View file

@ -14,6 +14,7 @@
#define __DEBUG 1
#define __WARNING 2
#define __ERROR 3
#define __BUG 4
__attribute__((format(printf, 4, 5)))
void __log_impl_pos(int line, int column, int type, const char *format, ...);
@ -25,6 +26,9 @@ void __log_impl(int type, const char *format, ...);
#define WARNING(format, ...) \
__log_impl(__WARNING, format, ##__VA_ARGS__)
#define BUG(format, ...) \
__log_impl(__BUG, format, ##__VA_ARGS__)
#define ERROR(format, ...) \
__log_impl(__ERROR, format, ##__VA_ARGS__)

View file

@ -43,6 +43,42 @@ enum mips32_register {
MIPS32_REG_RA = 31,
};
/* all mips fp registers $f0-$f31 */
enum mips32_fp_register {
MIPS32_REG_F0 = 0,
MIPS32_REG_F1 = 1,
MIPS32_REG_F2 = 2,
MIPS32_REG_F3 = 3,
MIPS32_REG_F4 = 4,
MIPS32_REG_F5 = 5,
MIPS32_REG_F6 = 6,
MIPS32_REG_F7 = 7,
MIPS32_REG_F8 = 8,
MIPS32_REG_F9 = 9,
MIPS32_REG_F10 = 10,
MIPS32_REG_F11 = 11,
MIPS32_REG_F12 = 12,
MIPS32_REG_F13 = 13,
MIPS32_REG_F14 = 14,
MIPS32_REG_F15 = 15,
MIPS32_REG_F16 = 16,
MIPS32_REG_F17 = 17,
MIPS32_REG_F18 = 18,
MIPS32_REG_F19 = 19,
MIPS32_REG_F20 = 20,
MIPS32_REG_F21 = 21,
MIPS32_REG_F22 = 22,
MIPS32_REG_F23 = 23,
MIPS32_REG_F24 = 24,
MIPS32_REG_F25 = 25,
MIPS32_REG_F26 = 26,
MIPS32_REG_F27 = 27,
MIPS32_REG_F28 = 28,
MIPS32_REG_F29 = 29,
MIPS32_REG_F30 = 30,
MIPS32_REG_F31 = 31,
};
/* mips instruction */
union mips32_instruction {
/* raw ins */
@ -77,6 +113,48 @@ union mips32_instruction {
uint32_t bfunct : 5;
uint32_t : 11;
};
/* coprocessor */
struct {
uint32_t : 21;
uint32_t cfunct : 5;
uint32_t : 6;
};
/* flags */
struct {
// 6 bit
uint32_t : 5;
uint32_t sc : 1; // interrupt
// 5 bit
uint32_t rv : 1; // rotate variable
uint32_t : 3;
uint32_t hb : 1; // hazard barrier
// 5 bit
uint32_t : 5;
// 5 bit
uint32_t tf : 1; // true false
uint32_t nd : 1; //
uint32_t cc : 3; // code
// 5 bit
uint32_t r : 1; // rotate
uint32_t : 3;
uint32_t c0 : 1; // cop0
// 6 bit
uint32_t : 6;
};
/* break code */
struct {
uint32_t : 6;
uint32_t code : 20;
uint32_t : 6;
};
/* floating point */
struct {
uint32_t : 6;
uint32_t fd : 5;
uint32_t fs : 5;
uint32_t ft : 5;
uint32_t : 11;
};
} __attribute__((packed));
/// grammer syntax:

227
include/mips1.h Normal file
View file

@ -0,0 +1,227 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __MIPS1_H__
#define __MIPS1_H__
#include <mlimits.h>
#include <stdint.h>
#include <mips.h>
// TODO:
// CFC1
// CTC1
// COP0-3
// LWC1-3
// SWC1-3
/* mips instructions */
enum mips1_instruction_type {
MIPS1_INS_ADD,
MIPS1_INS_ADDI,
MIPS1_INS_ADDIU,
MIPS1_INS_ADDU,
MIPS1_INS_AND,
MIPS1_INS_ANDI,
MIPS1_INS_BC1F,
MIPS1_INS_BC1T,
MIPS1_INS_BEQ,
MIPS1_INS_BGEZ,
MIPS1_INS_BGEZAL,
MIPS1_INS_BGTZ,
MIPS1_INS_BLEZ,
MIPS1_INS_BLTZAL,
MIPS1_INS_BLTZ,
MIPS1_INS_BNE,
MIPS1_INS_BREAK,
MIPS1_INS_CLO,
MIPS1_INS_CLZ,
MIPS1_INS_DIV,
MIPS1_INS_DIVU,
MIPS1_INS_ERET,
MIPS1_INS_J,
MIPS1_INS_JAL,
MIPS1_INS_JALR,
MIPS1_INS_JR,
MIPS1_INS_LB,
MIPS1_INS_LBU,
MIPS1_INS_LH,
MIPS1_INS_LHU,
MIPS1_INS_LL,
MIPS1_INS_LUI,
MIPS1_INS_LW,
MIPS1_INS_LWC1,
MIPS1_INS_LWL,
MIPS1_INS_LWR,
MIPS1_INS_MADD,
MIPS1_INS_MADDU,
MIPS1_INS_MFC0,
MIPS1_INS_MFC1,
MIPS1_INS_MFHI,
MIPS1_INS_MFLO,
MIPS1_INS_MOVN,
MIPS1_INS_MOVZ,
MIPS1_INS_MSUB,
MIPS1_INS_MSUBU,
MIPS1_INS_MTC0,
MIPS1_INS_MTC1,
MIPS1_INS_MTHI,
MIPS1_INS_MTLO,
MIPS1_INS_MUL,
MIPS1_INS_MULT,
MIPS1_INS_MULTU,
MIPS1_INS_NOR,
MIPS1_INS_OR,
MIPS1_INS_ORI,
MIPS1_INS_SB,
MIPS1_INS_SC,
MIPS1_INS_SDC1,
MIPS1_INS_SH,
MIPS1_INS_SLL,
MIPS1_INS_SLLV,
MIPS1_INS_SLT,
MIPS1_INS_SLTI,
MIPS1_INS_SLTIU,
MIPS1_INS_SLTU,
MIPS1_INS_SRA,
MIPS1_INS_SRAV,
MIPS1_INS_SRL,
MIPS1_INS_SRLV,
MIPS1_INS_SUB,
MIPS1_INS_SUBU,
MIPS1_INS_SW,
MIPS1_INS_SWC1,
MIPS1_INS_SWL,
MIPS1_INS_SWR,
MIPS1_INS_SYSCALL,
MIPS1_INS_TEQ,
MIPS1_INS_TEQI,
MIPS1_INS_TGE,
MIPS1_INS_TGEI,
MIPS1_INS_TGEIU,
MIPS1_INS_TGEU,
MIPS1_INS_TLT,
MIPS1_INS_TLTI,
MIPS1_INS_TLTIU,
MIPS1_INS_TLTU,
MIPS1_INS_TNE,
MIPS1_INS_TNEI,
MIPS1_INS_XOR,
MIPS1_INS_XORI,
__MIPS1_INS_NULL,
};
// op code groups
#define MIPS1_OP_SPECIAL 0b000000
#define MIPS1_OP_SPECIAL2 0b011100
#define MIPS1_OP_REGIMM 0b000001
#define MIPS1_OP_COP0 0b010000
#define MIPS1_OP_COP1 0b010001
// op codes
#define MIPS1_OP_ADDI 0b001000
#define MIPS1_OP_ADDIU 0b001001
#define MIPS1_OP_ANDI 0b001100
#define MIPS1_OP_BEQ 0b000100
#define MIPS1_OP_BGTZ 0b000111
#define MIPS1_OP_BLEZ 0b000110
#define MIPS1_OP_BNE 0b000101
#define MIPS1_OP_J 0b000010
#define MIPS1_OP_JAL 0b000011
#define MIPS1_OP_LB 0b100000
#define MIPS1_OP_LBU 0b100100
#define MIPS1_OP_LH 0b100001
#define MIPS1_OP_LHU 0b100101
#define MIPS1_OP_LL 0b110000
#define MIPS1_OP_LUI 0b001111
#define MIPS1_OP_LW 0b100011
#define MIPS1_OP_LWC1 0b110001
#define MIPS1_OP_LWL 0b100010
#define MIPS1_OP_LWR 0b100110
#define MIPS1_OP_ORI 0b001101
#define MIPS1_OP_SB 0b101000
#define MIPS1_OP_SC 0b111000
#define MIPS1_OP_SDC1 0b111101
#define MIPS1_OP_SH 0b101001
#define MIPS1_OP_SLTI 0b001010
#define MIPS1_OP_SLTIU 0b001011
#define MIPS1_OP_SW 0b101011
#define MIPS1_OP_SWC1 0b111001
#define MIPS1_OP_SWL 0b101010
#define MIPS1_OP_SWR 0b101110
#define MIPS1_OP_XORI 0b001110
// op special
#define MIPS1_FUNCT_ADD 0b100000
#define MIPS1_FUNCT_ADDU 0b100001
#define MIPS1_FUNCT_AND 0b100100
#define MIPS1_FUNCT_BREAK 0b001101
#define MIPS1_FUNCT_DIV 0b011010
#define MIPS1_FUNCT_DIVU 0b011011
#define MIPS1_FUNCT_JALR 0b001001
#define MIPS1_FUNCT_JR 0b001000
#define MIPS1_FUNCT_MFHI 0b010000
#define MIPS1_FUNCT_MFLO 0b010010
#define MIPS1_FUNCT_MOVN 0b001011
#define MIPS1_FUNCT_MOVZ 0b001010
#define MIPS1_FUNCT_MTHI 0b010001
#define MIPS1_FUNCT_MTLO 0b010011
#define MIPS1_FUNCT_MULT 0b011000
#define MIPS1_FUNCT_MULTU 0b011001
#define MIPS1_FUNCT_NOR 0b100111
#define MIPS1_FUNCT_OR 0b100101
#define MIPS1_FUNCT_SLL 0b000000
#define MIPS1_FUNCT_SLLV 0b000100
#define MIPS1_FUNCT_SLT 0b101010
#define MIPS1_FUNCT_SLTU 0b101011
#define MIPS1_FUNCT_SRA 0b000011
#define MIPS1_FUNCT_SRAV 0b000111
#define MIPS1_FUNCT_SRL 0b000010
#define MIPS1_FUNCT_SRLV 0b000110
#define MIPS1_FUNCT_SUB 0b100010
#define MIPS1_FUNCT_SUBU 0b100011
#define MIPS1_FUNCT_SYSCALL 0b001100
#define MIPS1_FUNCT_TEQ 0b110100
#define MIPS1_FUNCT_TGE 0b110000
#define MIPS1_FUNCT_TGEU 0b110001
#define MIPS1_FUNCT_TLT 0b110010
#define MIPS1_FUNCT_TLTU 0b110011
#define MIPS1_FUNCT_TNE 0b110110
#define MIPS1_FUNCT_XOR 0b100110
// op special 2
#define MIPS1_FUNCT_CLO 0b100001
#define MIPS1_FUNCT_CLZ 0b100000
#define MIPS1_FUNCT_MADD 0b000000
#define MIPS1_FUNCT_MADDU 0b000001
#define MIPS1_FUNCT_MSUB 0b000100
#define MIPS1_FUNCT_MSUBU 0b000101
#define MIPS1_FUNCT_MUL 0b100000
// op regimm
#define MIPS1_FUNCT_BGEZ 0b00001
#define MIPS1_FUNCT_BGEZAL 0b10001
#define MIPS1_FUNCT_BLTZ 0b00001
#define MIPS1_FUNCT_BLTZAL 0b10000
#define MIPS1_FUNCT_TEQI 0b01100
#define MIPS1_FUNCT_TGEI 0b01000
#define MIPS1_FUNCT_TGEIU 0b01001
#define MIPS1_FUNCT_TLTI 0b01010
#define MIPS1_FUNCT_TLTIU 0b01011
#define MIPS1_FUNCT_TNEI 0b01110
// op cop
#define MIPS1_FUNCT_BC 0b01000
#define MIPS1_FUNCT_MF 0b00000
#define MIPS1_FUNCT_MT 0b00100
// sub op c0
#define MIPS1_FUNCT_ERET 0b011000
#define __MIPS1_INS_LEN (__MIPS1_INS_NULL)
#define __MIPS1_PSEUDO_LEN (34)
#define __MIPS1_GRAMMER_LEN (__MIPS1_INS_LEN + __MIPS1_PSEUDO_LEN)
extern struct mips32_grammer mips1_grammers[__MIPS1_GRAMMER_LEN];
extern union mips32_instruction mips1_instructions[__MIPS1_INS_LEN];
#endif /* __MIPS1_H__ */

342
include/mips32r2.h Normal file
View file

@ -0,0 +1,342 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __MIPS32R2_H__
#define __MIPS32R2_H__
#include <mlimits.h>
#include <stdint.h>
#include <mips.h>
// TODO:
// balc
/* mips instructions */
enum mips32r2_instruction_type {
MIPS32R2_INS_ADD,
MIPS32R2_INS_ADDI,
MIPS32R2_INS_ADDIU,
MIPS32R2_INS_ADDU,
MIPS32R2_INS_AND,
MIPS32R2_INS_ANDI,
MIPS32R2_INS_BC1F,
MIPS32R2_INS_BC1FL,
MIPS32R2_INS_BC1T,
MIPS32R2_INS_BC1TL,
MIPS32R2_INS_BC2F,
MIPS32R2_INS_BC2FL,
MIPS32R2_INS_BC2T,
MIPS32R2_INS_BC2TL,
MIPS32R2_INS_BEQ,
MIPS32R2_INS_BEQL,
MIPS32R2_INS_BGEZ,
MIPS32R2_INS_BGEZAL,
MIPS32R2_INS_BGEZALL,
MIPS32R2_INS_BGEZL,
MIPS32R2_INS_BGTZ,
MIPS32R2_INS_BGTZL,
MIPS32R2_INS_BLEZ,
MIPS32R2_INS_BLEZL,
MIPS32R2_INS_BLTZ,
MIPS32R2_INS_BLTZAL,
MIPS32R2_INS_BLTZALL,
MIPS32R2_INS_BLTZL,
MIPS32R2_INS_BNE,
MIPS32R2_INS_BNEL,
MIPS32R2_INS_BREAK,
MIPS32R2_INS_CACHE,
MIPS32R2_INS_CFC1,
MIPS32R2_INS_CFC2,
MIPS32R2_INS_CLO,
MIPS32R2_INS_CLZ,
MIPS32R2_INS_COP2,
MIPS32R2_INS_CTC1,
MIPS32R2_INS_CTC2,
MIPS32R2_INS_DERET,
MIPS32R2_INS_DI,
MIPS32R2_INS_DIV,
MIPS32R2_INS_DIVU,
MIPS32R2_INS_EI,
MIPS32R2_INS_ERET,
MIPS32R2_INS_EXT,
MIPS32R2_INS_INS,
MIPS32R2_INS_J,
MIPS32R2_INS_JAL,
MIPS32R2_INS_JALR,
MIPS32R2_INS_JR,
MIPS32R2_INS_LB,
MIPS32R2_INS_LBU,
MIPS32R2_INS_LDC1,
MIPS32R2_INS_LDC2,
MIPS32R2_INS_LDXC1,
MIPS32R2_INS_LH,
MIPS32R2_INS_LHU,
MIPS32R2_INS_LL,
MIPS32R2_INS_LUI,
MIPS32R2_INS_LUXC1,
MIPS32R2_INS_LW,
MIPS32R2_INS_LWC1,
MIPS32R2_INS_LWC2,
MIPS32R2_INS_LWL,
MIPS32R2_INS_LWR,
MIPS32R2_INS_LWXC1,
MIPS32R2_INS_MADD,
MIPS32R2_INS_MADDU,
MIPS32R2_INS_MFC0,
MIPS32R2_INS_MFC1,
MIPS32R2_INS_MFC2,
MIPS32R2_INS_MFHC1,
MIPS32R2_INS_MFHC2,
MIPS32R2_INS_MFHI,
MIPS32R2_INS_MFLO,
MIPS32R2_INS_MOVF,
MIPS32R2_INS_MOVN,
MIPS32R2_INS_MOVT,
MIPS32R2_INS_MOVZ,
MIPS32R2_INS_MSUB,
MIPS32R2_INS_MSUBU,
MIPS32R2_INS_MTC0,
MIPS32R2_INS_MTC1,
MIPS32R2_INS_MTC2,
MIPS32R2_INS_MTHC1,
MIPS32R2_INS_MTHC2,
MIPS32R2_INS_MTHI,
MIPS32R2_INS_MTLO,
MIPS32R2_INS_MUL,
MIPS32R2_INS_MULT,
MIPS32R2_INS_MULTU,
MIPS32R2_INS_NOR,
MIPS32R2_INS_OR,
MIPS32R2_INS_ORI,
MIPS32R2_INS_PREF,
MIPS32R2_INS_PREFX,
MIPS32R2_INS_RDHWR,
MIPS32R2_INS_RDPGPR,
MIPS32R2_INS_ROTR,
MIPS32R2_INS_ROTRV,
MIPS32R2_INS_SB,
MIPS32R2_INS_SC,
MIPS32R2_INS_SDBBP,
MIPS32R2_INS_SDC1,
MIPS32R2_INS_SDC2,
MIPS32R2_INS_SDXC1,
MIPS32R2_INS_SEB,
MIPS32R2_INS_SEH,
MIPS32R2_INS_SH,
MIPS32R2_INS_SLL,
MIPS32R2_INS_SLLV,
MIPS32R2_INS_SLT,
MIPS32R2_INS_SLTI,
MIPS32R2_INS_SLTIU,
MIPS32R2_INS_SLTU,
MIPS32R2_INS_SRA,
MIPS32R2_INS_SRAV,
MIPS32R2_INS_SRL,
MIPS32R2_INS_SRLV,
MIPS32R2_INS_SUB,
MIPS32R2_INS_SUBU,
MIPS32R2_INS_SUXC1,
MIPS32R2_INS_SW,
MIPS32R2_INS_SWC1,
MIPS32R2_INS_SWC2,
MIPS32R2_INS_SWL,
MIPS32R2_INS_SWR,
MIPS32R2_INS_SWXC1,
MIPS32R2_INS_SYNC,
MIPS32R2_INS_SYNCI,
MIPS32R2_INS_SYSCALL,
MIPS32R2_INS_TEQ,
MIPS32R2_INS_TEQI,
MIPS32R2_INS_TGE,
MIPS32R2_INS_TGEI,
MIPS32R2_INS_TGEIU,
MIPS32R2_INS_TGEU,
MIPS32R2_INS_TLBP,
MIPS32R2_INS_TLBR,
MIPS32R2_INS_TLBWI,
MIPS32R2_INS_TLBWR,
MIPS32R2_INS_TLT,
MIPS32R2_INS_TLTI,
MIPS32R2_INS_TLTIU,
MIPS32R2_INS_TLTU,
MIPS32R2_INS_TNE,
MIPS32R2_INS_TNEI,
MIPS32R2_INS_WAIT,
MIPS32R2_INS_WRPGPR,
MIPS32R2_INS_WSBH,
MIPS32R2_INS_XOR,
MIPS32R2_INS_XORI,
__MIPS32R2_INS_NULL,
};
// op code groups
#define MIPS32R2_OP_SPECIAL 0b000000
#define MIPS32R2_OP_SPECIAL2 0b011100
#define MIPS32R2_OP_SPECIAL3 0b011111
#define MIPS32R2_OP_REGIMM 0b000001
#define MIPS32R2_OP_COP0 0b010000
#define MIPS32R2_OP_COP1 0b010001
#define MIPS32R2_OP_COP2 0b010010
#define MIPS32R2_OP_COP1X 0b010011
// op codes
#define MIPS32R2_OP_ADDI 0b001000
#define MIPS32R2_OP_ADDIU 0b001001
#define MIPS32R2_OP_ANDI 0b001100
#define MIPS32R2_OP_BC 0b110010
#define MIPS32R2_OP_BEQ 0b000100
#define MIPS32R2_OP_BEQL 0b010100
#define MIPS32R2_OP_BGTZ 0b000111
#define MIPS32R2_OP_BGTZL 0b010111
#define MIPS32R2_OP_BLEZ 0b000110
#define MIPS32R2_OP_BLEZL 0b010110
#define MIPS32R2_OP_BNE 0b000101
#define MIPS32R2_OP_BNEL 0b010101
#define MIPS32R2_OP_CACHE 0b101111
#define MIPS32R2_OP_J 0b000010
#define MIPS32R2_OP_JAL 0b000011
#define MIPS32R2_OP_JALX 0b011101
#define MIPS32R2_OP_LB 0b100000
#define MIPS32R2_OP_LBU 0b100100
#define MIPS32R2_OP_LDC1 0b110101
#define MIPS32R2_OP_LDC2 0b110110
#define MIPS32R2_OP_LH 0b100001
#define MIPS32R2_OP_LHU 0b100101
#define MIPS32R2_OP_LL 0b110000
#define MIPS32R2_OP_LUI 0b001111
#define MIPS32R2_OP_LW 0b100011
#define MIPS32R2_OP_LWC1 0b110001
#define MIPS32R2_OP_LWC2 0b110010
#define MIPS32R2_OP_LWL 0b100010
#define MIPS32R2_OP_LWR 0b100110
#define MIPS32R2_OP_ORI 0b001101
#define MIPS32R2_OP_PREF 0b110011
#define MIPS32R2_OP_SB 0b101000
#define MIPS32R2_OP_SC 0b111000
#define MIPS32R2_OP_SDC1 0b111101
#define MIPS32R2_OP_SDC2 0b111110
#define MIPS32R2_OP_SH 0b101001
#define MIPS32R2_OP_SLTI 0b001010
#define MIPS32R2_OP_SLTIU 0b001011
#define MIPS32R2_OP_SW 0b101011
#define MIPS32R2_OP_SWC1 0b111001
#define MIPS32R2_OP_SWC2 0b111010
#define MIPS32R2_OP_SWL 0b101010
#define MIPS32R2_OP_SWR 0b101110
#define MIPS32R2_OP_XORI 0b001110
// op special
#define MIPS32R2_FUNCT_ADD 0b100000
#define MIPS32R2_FUNCT_ADDU 0b100001
#define MIPS32R2_FUNCT_AND 0b100100
#define MIPS32R2_FUNCT_BREAK 0b001101
#define MIPS32R2_FUNCT_DIV 0b000011
#define MIPS32R2_FUNCT_DIVU 0b011011
#define MIPS32R2_FUNCT_JALR 0b001001
#define MIPS32R2_FUNCT_JR 0b001000
#define MIPS32R2_FUNCT_MFHI 0b010000
#define MIPS32R2_FUNCT_MFLO 0b010010
#define MIPS32R2_FUNCT_MOVCL 0b000001
#define MIPS32R2_FUNCT_MOVN 0b001011
#define MIPS32R2_FUNCT_MOVZ 0b001010
#define MIPS32R2_FUNCT_MTHI 0b010001
#define MIPS32R2_FUNCT_MTLO 0b010011
#define MIPS32R2_FUNCT_MULT 0b011000
#define MIPS32R2_FUNCT_MULTU 0b011001
#define MIPS32R2_FUNCT_NOR 0b100111
#define MIPS32R2_FUNCT_OR 0b100101
#define MIPS32R2_FUNCT_SLL 0b000000
#define MIPS32R2_FUNCT_SLLV 0b000100
#define MIPS32R2_FUNCT_SLT 0b101010
#define MIPS32R2_FUNCT_SLTU 0b101011
#define MIPS32R2_FUNCT_SRA 0b000011
#define MIPS32R2_FUNCT_SRAV 0b000111
#define MIPS32R2_FUNCT_SRL 0b000010
#define MIPS32R2_FUNCT_SRLV 0b000110
#define MIPS32R2_FUNCT_SUB 0b100010
#define MIPS32R2_FUNCT_SUBU 0b100011
#define MIPS32R2_FUNCT_SYNC 0b001111
#define MIPS32R2_FUNCT_SYSCALL 0b001100
#define MIPS32R2_FUNCT_TEQ 0b110100
#define MIPS32R2_FUNCT_TGE 0b110000
#define MIPS32R2_FUNCT_TGEU 0b110001
#define MIPS32R2_FUNCT_TLT 0b110010
#define MIPS32R2_FUNCT_TLTU 0b110011
#define MIPS32R2_FUNCT_TNE 0b110110
#define MIPS32R2_FUNCT_XOR 0b100110
// op special2
#define MIPS32R2_FUNCT_CLO 0b100001
#define MIPS32R2_FUNCT_CLZ 0b100000
#define MIPS32R2_FUNCT_MADD 0b000000
#define MIPS32R2_FUNCT_MADDU 0b000001
#define MIPS32R2_FUNCT_MSUB 0b000100
#define MIPS32R2_FUNCT_MSUBU 0b000101
#define MIPS32R2_FUNCT_MUL 0b000010
#define MIPS32R2_FUNCT_SDBBP 0b111111
// op special 3
#define MIPS32R2_FUNCT_EXT 0b000000
#define MIPS32R2_FUNCT_INS 0b000100
#define MIPS32R2_FUNCT_RDHWR 0b111011
#define MIPS32R2_FUNCT_BSHFL 0b100000
// op bshfl
#define MIPS32R2_FUNCT_SEB 0b10000
#define MIPS32R2_FUNCT_SEH 0b11000
#define MIPS32R2_FUNCT_WSBH 0b00010
// op regimm
#define MIPS32R2_FUNCT_BGEZ 0b00001
#define MIPS32R2_FUNCT_BGEZAL 0b10001
#define MIPS32R2_FUNCT_BGEZALL 0b10011
#define MIPS32R2_FUNCT_BGEZL 0b00011
#define MIPS32R2_FUNCT_BLTZ 0b00000
#define MIPS32R2_FUNCT_BLTZAL 0b10000
#define MIPS32R2_FUNCT_BLTZALL 0b10010
#define MIPS32R2_FUNCT_BLTZL 0b00010
#define MIPS32R2_FUNCT_SYNCI 0b11111
#define MIPS32R2_FUNCT_TEQI 0b01100
#define MIPS32R2_FUNCT_TGEI 0b01000
#define MIPS32R2_FUNCT_TGEIU 0b01001
#define MIPS32R2_FUNCT_TLTI 0b01010
#define MIPS32R2_FUNCT_TLTIU 0b01011
#define MIPS32R2_FUNCT_TNEI 0b01110
// op cop cfunct
#define MIPS32R2_FUNCT_BC 0b01000
#define MIPS32R2_FUNCT_CF 0b00010
#define MIPS32R2_FUNCT_CT 0b00110
#define MIPS32R2_FUNCT_MF 0b00000
#define MIPS32R2_FUNCT_MFH 0b00011
#define MIPS32R2_FUNCT_MT 0b00100
#define MIPS32R2_FUNCT_MTH 0b00111
#define MIPS32R2_FUNCT_MFMC0 0b01011
#define MIPS32R2_FUNCT_RDPGPR 0b01010
#define MIPS32R2_FUNCT_WRPGPR 0b01110
// op cop funct
#define MIPS32R2_FUNCT_DERET 0b011111
#define MIPS32R2_FUNCT_ERET 0b011000
#define MIPS32R2_FUNCT_TLBP 0b001000
#define MIPS32R2_FUNCT_TLBR 0b000001
#define MIPS32R2_FUNCT_TLBWI 0b000010
#define MIPS32R2_FUNCT_TLBWR 0b000110
// op cop1x
#define MIPS32R2_FUNCT_LDXC1 0b000001
#define MIPS32R2_FUNCT_LUXC1 0b000101
#define MIPS32R2_FUNCT_LWXC1 0b000000
#define MIPS32R2_FUNCT_PREFX 0b001111
#define MIPS32R2_FUNCT_SDXC1 0b001001
#define MIPS32R2_FUNCT_SUXC1 0b001101
#define MIPS32R2_FUNCT_SWXC1 0b001000
#define MIPS32R2_FUNCT_WAIT 0b100000
#define __MIPS32R2_INS_LEN (__MIPS32R2_INS_NULL)
#define __MIPS32R2_PSEUDO_LEN (38)
#define __MIPS32R2_GRAMMER_LEN (__MIPS32R2_INS_LEN + __MIPS32R2_PSEUDO_LEN)
extern struct mips32_grammer mips32r2_grammers[__MIPS32R2_GRAMMER_LEN];
extern union mips32_instruction mips32r2_instructions[__MIPS32R2_INS_LEN];
#endif /* __MIPS32R2_H__ */

View file

@ -5,7 +5,98 @@
#include <mlimits.h>
#include <stdint.h>
#include <mips32.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 {
@ -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
#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 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
// 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];

View file

@ -25,6 +25,9 @@ void __log_impl_pos(int line, int column, int type, const char *format, ...)
case __ERROR:
t = "\033[31merror:\033[0m";
break;
case __BUG:
t = "\033[31bug:\033[0m";
break;
}
if (current_file != NULL)
@ -55,6 +58,9 @@ void __log_impl(int type, const char *format, ...)
case __ERROR:
t = "\033[31merror:\033[0m";
break;
case __BUG:
t = "\033[31bug:\033[0m";
break;
}
if (current_file != NULL)

571
lib/mips1.c Normal file
View file

@ -0,0 +1,571 @@
#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

851
lib/mips32r2.c Normal file
View file

@ -0,0 +1,851 @@
#include <mips32r2.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 INS(name, grammer) {#name, grammer, MIPS32R2_INS_ ##name, \
/* pseudo stub */ 0, {{0, ""}}}
#define PSEUDO(name, grammer, ...) {name, grammer, __MIPS32R2_INS_NULL, \
__VA_ARGS__ }
struct mips32_grammer mips32r2_grammers[__MIPS32R2_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(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(DIVU, 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(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(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, 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(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, {
{MIPS32R2_INS_SRA, "rd=$at,rt=rs,sa=31"},
{MIPS32R2_INS_ADD, "rd,rs,rt=$at"},
{MIPS32R2_INS_XOR, "rd,rs=rd,rt=$at"},
}),
PSEUDO("div", "rd,rt,rs", 2, {
{MIPS32R2_INS_DIV, "rt,rs"},
{MIPS32R2_INS_MFLO, "rd"},
}),
PSEUDO("divu", "rd,rt,rs", 2, {
{MIPS32R2_INS_DIVU, "rt,rs"},
{MIPS32R2_INS_MFLO, "rd"},
}),
PSEUDO("mulo", "rd,rt,rs", 2, {
{MIPS32R2_INS_MULT, "rt,rs"},
{MIPS32R2_INS_MFLO, "rd"},
}),
PSEUDO("mulou", "rd,rt,rs", 2, {
{MIPS32R2_INS_MULTU, "rt,rs"},
{MIPS32R2_INS_MFLO, "rd"},
}),
PSEUDO("neg", "rd,rt", 1, {
{MIPS32R2_INS_SUB, "rd,rs=$zero,rt"},
}),
PSEUDO("negu", "rd,rt", 1, {
{MIPS32R2_INS_SUBU, "rd,rs=$zero,rt"},
}),
PSEUDO("not", "rd,rt", 1, {
{MIPS32R2_INS_NOR, "rd,rs=$zero,rt"},
}),
PSEUDO("rem", "rd,rt,rs", 2, {
{MIPS32R2_INS_DIV, "rt,rs"},
{MIPS32R2_INS_MFHI, "rd"},
}),
PSEUDO("remu", "rd,rt,rs", 2, {
{MIPS32R2_INS_DIVU, "rt,rs"},
{MIPS32R2_INS_MFHI, "rd"},
}),
// TODO: rol
// TODO: ror
PSEUDO("subi", "rt,rs,immd", 1, {
{MIPS32R2_INS_ADDI, "rt,rs,-immd"},
}),
PSEUDO("li", "rt,immd", 1, {
{MIPS32R2_INS_ADDI, "rt,immd"}
}),
PSEUDO("seq", "rd,rs,rt", 3, {
{MIPS32R2_INS_SLT, "rd,rs,rt"},
{MIPS32R2_INS_SLT, "rd=$at,rs,rt"},
{MIPS32R2_INS_NOR, "rd,rs=rd,rt=$at"},
}),
PSEUDO("sgt", "rd,rs,rt", 1, {
{MIPS32R2_INS_SLT, "rd,rs=rt,rt=rs"},
}),
PSEUDO("sgtu", "rd,rs,rt", 1, {
{MIPS32R2_INS_SLTU, "rd,rs=rt,rt=rs"},
}),
PSEUDO("sge", "rd,rs,rt", 2, {
{MIPS32R2_INS_SLT, "rd,rs,rt"},
{MIPS32R2_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("sgeu", "rd,rs,rt", 2, {
{MIPS32R2_INS_SLTU, "rd,rs,rt"},
{MIPS32R2_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("slte", "rd,rs,rt", 2, {
{MIPS32R2_INS_SLT, "rd,rs=rt,rt=rs"},
{MIPS32R2_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("slteu", "rd,rs,rt", 2, {
{MIPS32R2_INS_SLTU, "rd,rs=rt,rt=rs"},
{MIPS32R2_INS_SLTI, "rt=rd,rs=rd,immd=1"},
}),
PSEUDO("sne", "rd,rs,rt", 3, {
{MIPS32R2_INS_SLT, "rd,rs,rt"},
{MIPS32R2_INS_SLT, "rd=$at,rs,rt"},
{MIPS32R2_INS_OR, "rd,rs=rd,rt=$at"},
}),
PSEUDO("jalr.hb", "rs", 1, {
{MIPS32R2_INS_JALR, "rs,hb=1"}
}),
PSEUDO("jr.hb", "rs", 1, {
{MIPS32R2_INS_JR, "rs,hb=1"}
}),
PSEUDO("b", "offset", 1, {
{MIPS32R2_INS_BEQ, "rs=$zero,rt=$zero,offset"},
}),
PSEUDO("beqz", "rs,offset", 1, {
{MIPS32R2_INS_BEQ, "rs,rt=$zero,offset"},
}),
PSEUDO("bge", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLT, "rd=$at,rs,rt"},
{MIPS32R2_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bgeu", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLTU, "rd=$at,rs,rt"},
{MIPS32R2_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bge", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLT, "rd=$at,rs,rt"},
{MIPS32R2_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bgeu", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLTU, "rd=$at,rs,rt"},
{MIPS32R2_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("ble", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLT, "rd=$at,rs=rt,rt=rs"},
{MIPS32R2_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bleu", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLT, "rd=$at,rs=rt,rt=rs"},
{MIPS32R2_INS_BEQ, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("blt", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLT, "rd=$at,rs,rt"},
{MIPS32R2_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bltu", "rs,rt,offset", 2, {
{MIPS32R2_INS_SLTU, "rd=$at,rs,rt"},
{MIPS32R2_INS_BNE, "rs=$at,rt=$zero,offset"},
}),
PSEUDO("bnez", "rs,offset", 1, {
{MIPS32R2_INS_BNE, "rs,rt=$zero,offset"},
}),
// TODO: ld
// TODO: load unaligned
// TODO: store unaligned
PSEUDO("la", "rt,target", 2, {
{MIPS32R2_INS_LUI, "rt=$at,hi"},
{MIPS32R2_INS_ORI, "rt,rs=$at,lo"},
}),
PSEUDO("move", "rd,rs", 1, {
{MIPS32R2_INS_OR, "rd,rs"}
}),
PSEUDO("nop", "", 1, {
{MIPS32R2_INS_SLL, ""},
}),
PSEUDO("ssnop", "", 1, {
{MIPS32R2_INS_SLL, "sa=1"},
}),
PSEUDO("ehb", "", 1, {
{MIPS32R2_INS_SLL, "sa=3"}
}),
};
#define MIPS_INS(ins, ...) \
[MIPS32R2_INS_ ##ins] = { __VA_ARGS__ },
union mips32_instruction mips32r2_instructions[__MIPS32R2_INS_LEN] = {
/* ADD - add */
MIPS_INS(ADD, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_ADD)
/* ADDI - add immediate */
MIPS_INS(ADDI, .op = MIPS32R2_OP_ADDI)
/* ADDIU - add immediate unsigned */
MIPS_INS(ADDIU, .op = MIPS32R2_OP_ADDIU)
/* ADDU - add unsigned */
MIPS_INS(ADDU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_ADDU)
/* AND - and */
MIPS_INS(AND, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_AND)
/* ANDI - and immediate */
MIPS_INS(ANDI, .op = MIPS32R2_OP_ANDI)
/* BC1F - branch on cop1 false */
MIPS_INS(BC1F, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 0, .tf = 0)
/* BC1FL - branch on cop1 false likely */
MIPS_INS(BC1FL, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 1, .tf = 0)
/* BC1T - branch on cop1 true */
MIPS_INS(BC1T, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 0, .tf = 1)
/* BC1TL - branch on cop1 true likely */
MIPS_INS(BC1TL, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 1, .tf = 1)
/* BC2F - branch on cop1 false */
MIPS_INS(BC2F, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 0, .tf = 0)
/* BC2FL - branch on cop1 false likely */
MIPS_INS(BC2FL, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 1, .tf = 0)
/* BC2T - branch on cop1 true */
MIPS_INS(BC2T, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 0, .tf = 1)
/* BC2TL - branch on cop1 true likely */
MIPS_INS(BC2TL, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_BC,
.nd = 1, .tf = 1)
/* BEQ - branch on equal */
MIPS_INS(BEQ, .op = MIPS32R2_OP_BEQ)
/* BEQL - branch on equal likely */
MIPS_INS(BEQL, .op = MIPS32R2_OP_BEQL)
/* BGEZ - branch on greater than or equal to zero */
MIPS_INS(BGEZ, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BGEZ)
/* BGEZAL - branch on greater than or equal to zero and link */
MIPS_INS(BGEZAL, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BGEZAL)
/* BGEZALL - branch on greater than or equal to zero and link likely */
MIPS_INS(BGEZALL, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BGEZALL)
/* BGEZL - branch on greater than or equal to zero likely */
MIPS_INS(BGEZL, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BGEZL)
/* BGTZ - branch on greater than zero */
MIPS_INS(BGTZ, .op = MIPS32R2_OP_BGTZ)
/* BGTZL - branch on greater than zero likely */
MIPS_INS(BGTZL, .op = MIPS32R2_OP_BGTZL)
/* BLEZ - branch on less than or equal to zero */
MIPS_INS(BLEZ, .op = MIPS32R2_OP_BLEZ)
/* BLEZL - branch on less than or equal to zero likely */
MIPS_INS(BLEZL, .op = MIPS32R2_OP_BLEZL)
/* BLTZ - branch on less than zero */
MIPS_INS(BLTZ, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BLTZ)
/* BLTZAL - branch on less than zero and link */
MIPS_INS(BLTZAL, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BLTZAL)
/* BLTZALL - branch on less than zero and link likely */
MIPS_INS(BLTZALL, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BLTZALL)
/* BLTZL - branch on less than zero likely */
MIPS_INS(BLTZL, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_BLTZL)
/* BNE - branch on not equal */
MIPS_INS(BNE, .op = MIPS32R2_OP_BNE)
/* BNEL - branch on not equal likely */
MIPS_INS(BNEL, .op = MIPS32R2_OP_BNEL)
/* BREAK - breakpoint */
MIPS_INS(BREAK, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_BREAK)
/* CACHE - perform cache operation */
MIPS_INS(CACHE, .op = MIPS32R2_OP_CACHE)
/* CFC1 - move control word from floating point */
MIPS_INS(CFC1, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_CF)
/* CFC2 - move control word from coprocessor 2 */
MIPS_INS(CFC2, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_CF)
/* CLO - count leading ones */
MIPS_INS(CLO, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_CLO)
/* CLZ - count leading zeros */
MIPS_INS(CLZ, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_CLZ)
/* COP2 - coprocessor operation to coprocessor 2 */
MIPS_INS(COP2, .op = MIPS32R2_OP_COP2, .c0 = 1)
/* CTC1 - move control word to floating point */
MIPS_INS(CTC1, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_CT)
/* CTC2 - move control word to coprocessor 2 */
MIPS_INS(CTC2, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_CT)
/* DERET - debug exception return */
MIPS_INS(DERET, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_DERET)
/* DI - disable interupts */
MIPS_INS(DI, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_MFMC0,
.rd = 12, .sc = 0)
/* DIV - divide */
MIPS_INS(DIV, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_DIV)
/* DIVU - divide unsigned */
MIPS_INS(DIVU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_DIVU)
/* EI - enable interupts */
MIPS_INS(EI, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_MFMC0,
.rd = 12, .sc = 1)
/* ERET - exception return */
MIPS_INS(ERET, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_ERET)
/* ERT - extract bit field */
MIPS_INS(EXT, .op = MIPS32R2_OP_SPECIAL3, .funct = MIPS32R2_FUNCT_EXT)
/* INS - insert bit field */
MIPS_INS(INS, .op = MIPS32R2_OP_SPECIAL3, .funct = MIPS32R2_FUNCT_INS)
/* J - jump */
MIPS_INS(J, .op = MIPS32R2_OP_J)
/* JAL - jump and link */
MIPS_INS(JAL, .op = MIPS32R2_OP_JAL)
/* JALR - jump and link register */
MIPS_INS(JALR, .rd = MIPS32_REG_RA, .op = MIPS32R2_OP_SPECIAL,
.funct = MIPS32R2_FUNCT_JALR)
/* JR - jump register */
MIPS_INS(JR, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_JR)
/* LB - load byte */
MIPS_INS(LB, .op = MIPS32R2_OP_LB)
/* LBU - load byte unsigned */
MIPS_INS(LBU, .op = MIPS32R2_OP_LBU)
/* LDC1 - load doubleword floating point */
MIPS_INS(LDC1, .op = MIPS32R2_OP_LDC1)
/* LDC2 - load doubleword cop2 */
MIPS_INS(LDC2, .op = MIPS32R2_OP_LDC2)
/* LDXC1 - load doubleword indexed to floating point */
MIPS_INS(LDXC1, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_LDXC1)
/* LH - load half */
MIPS_INS(LH, .op = MIPS32R2_OP_LH)
/* LHU - load half unsigned */
MIPS_INS(LHU, .op = MIPS32R2_OP_LHU)
/* LK - load linked */
MIPS_INS(LL, .op = MIPS32R2_OP_LL)
/* LUI - load upper immediate */
MIPS_INS(LUI, .op = MIPS32R2_OP_LUI)
/* LUXC1 - load doubleword indexed unaligned to floating point */
MIPS_INS(LUXC1, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_LUXC1)
/* LW - load word */
MIPS_INS(LW, .op = MIPS32R2_OP_LW)
/* LDC1 - load word floating point */
MIPS_INS(LWC1, .op = MIPS32R2_OP_LWC1)
/* LDC2 - load eword cop2 */
MIPS_INS(LWC2, .op = MIPS32R2_OP_LWC2)
/* LWL - load word left */
MIPS_INS(LWL, .op = MIPS32R2_OP_LWL)
/* LWR - load word right */
MIPS_INS(LWR, .op = MIPS32R2_OP_LWR)
/* LWXC1 - load word indexed to floating point */
MIPS_INS(LWXC1, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_LWXC1)
/* MADD - multiply and add words to hi,lo */
MIPS_INS(MADD, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_MADD)
/* MADDU - multiply and add unsigned words to hi,lo */
MIPS_INS(MADDU, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_MADDU)
/* MFC0 - move from cop0 */
MIPS_INS(MFC0, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_MF)
/* MFC1 - move from floating point */
MIPS_INS(MFC1, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_MF)
/* MFC2 - move from cop2 */
MIPS_INS(MFC2, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_MF)
/* MFHC1 - move word from high half of floating point register */
MIPS_INS(MFHC1, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_MFH)
/* MFHC2 - move word from high half of cop2 */
MIPS_INS(MFHC2, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_MFH)
/* MFHI - move from hi register */
MIPS_INS(MFHI, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MFHI)
/* MFLO - move from lo register */
MIPS_INS(MFLO, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MFLO)
/* MOVF - move on floating point false */
MIPS_INS(MOVF, .op = MIPS32R2_OP_SPECIAL, .tf = 0,
.funct = MIPS32R2_FUNCT_MOVCL)
/* MOVN - move conditional on non zero */
MIPS_INS(MOVN, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MOVN)
/* MOVT - move on floating point true */
MIPS_INS(MOVT, .op = MIPS32R2_OP_SPECIAL, .tf = 1,
.funct = MIPS32R2_FUNCT_MOVCL)
/* MOVZ - move conditional on zero */
MIPS_INS(MOVZ, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MOVZ)
/* MSUB - multiply and add words to hi,lo */
MIPS_INS(MSUB, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_MSUB)
/* MSUBU - multiply and add unsigned words to hi,lo */
MIPS_INS(MSUBU, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_MSUBU)
/* MTC0 - move to cop0 */
MIPS_INS(MTC0, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_MT)
/* MTC1 - move to floating point */
MIPS_INS(MTC1, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_MT)
/* MTC2 - move to cop2 */
MIPS_INS(MTC2, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_MT)
/* MTHC1 - move word to high half of floating point register */
MIPS_INS(MTHC1, .op = MIPS32R2_OP_COP1, .cfunct = MIPS32R2_FUNCT_MTH)
/* MTHC2 - move word to high half of cop2 */
MIPS_INS(MTHC2, .op = MIPS32R2_OP_COP2, .cfunct = MIPS32R2_FUNCT_MTH)
/* MTHI - move to hi register */
MIPS_INS(MTHI, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MTHI)
/* MTLO - move to lo register */
MIPS_INS(MTLO, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MTLO)
/* MUL - multiply word to GPR */
MIPS_INS(MUL, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_MUL)
/* MULT - multiply word */
MIPS_INS(MULT, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MULT)
/* MULTU - multiply unsigned word */
MIPS_INS(MULTU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_MULTU)
/* NOR - not or */
MIPS_INS(NOR, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_NOR)
/* OR - or */
MIPS_INS(OR, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_OR)
/* ORI - or imemdiate */
MIPS_INS(ORI, .op = MIPS32R2_OP_ORI)
/* PREF - prefetch */
MIPS_INS(PREF, .op = MIPS32R2_OP_PREF)
/* PREFX - prefetch indexed */
MIPS_INS(PREFX, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_PREFX)
/* RDHWR - read hardware register */
MIPS_INS(RDHWR, .op = MIPS32R2_OP_SPECIAL3, .funct = MIPS32R2_FUNCT_RDHWR)
/* RDPGPR - read gpr from previous shadow set */
MIPS_INS(RDPGPR, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_RDPGPR)
/* ROTR - rotate word right */
MIPS_INS(ROTR, .op = MIPS32R2_OP_SPECIAL, .r = 1, .funct = MIPS32R2_FUNCT_SRL)
/* ROTRV - rotate word right variable */
MIPS_INS(ROTRV, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SRLV,
.rv = 1)
/* SB - store byte */
MIPS_INS(SB, .op = MIPS32R2_OP_SB)
/* SC - store conditional word */
MIPS_INS(SC, .op = MIPS32R2_OP_SC)
/* SDBBP - software debug breakpoint */
MIPS_INS(SDBBP, .op = MIPS32R2_OP_SPECIAL2, .funct = MIPS32R2_FUNCT_SDBBP)
/* SDC1 - store doubleword floating point */
MIPS_INS(SDC1, .op = MIPS32R2_OP_SDC1)
/* SDC2 - store doubleword cop2 */
MIPS_INS(SDC2, .op = MIPS32R2_OP_SDC2)
/* SDXC1 - store doubleword indexed from floating point */
MIPS_INS(SDXC1, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_SDXC1)
/* SEB - sign extend byte */
MIPS_INS(SEB, .op = MIPS32R2_OP_SPECIAL3, .shamt = MIPS32R2_FUNCT_SEB,
.funct = MIPS32R2_FUNCT_BSHFL)
/* SEH - sign extend halfword */
MIPS_INS(SEH, .op = MIPS32R2_OP_SPECIAL3, .shamt = MIPS32R2_FUNCT_SEH,
.funct = MIPS32R2_FUNCT_BSHFL)
/* SH - store half */
MIPS_INS(SH, .op = MIPS32R2_OP_SH)
/* SLL - shift left logical */
MIPS_INS(SLL, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SLL)
/* SLLV - shift left logical variable */
MIPS_INS(SLLV, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SLLV)
/* SLT - set less then */
MIPS_INS(SLT, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SLT)
/* SLTI - set less then immediate */
MIPS_INS(SLTI, .op = MIPS32R2_OP_SLTI)
/* SLTIU - set less then imemdiate unsigned */
MIPS_INS(SLTIU, .op = MIPS32R2_OP_SLTIU)
/* SLTU - set less than unsigned */
MIPS_INS(SLTU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SLTU)
/* SRA - shift right arithmetic */
MIPS_INS(SRA, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SRA)
/* SRAV - shift right arithmetic variable */
MIPS_INS(SRAV, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SRAV)
/* SRL - shift right logical */
MIPS_INS(SRL, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SRL)
/* SRLV - shift right logical variable */
MIPS_INS(SRLV, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SRLV)
/* SUB - subtract */
MIPS_INS(SUB, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SUB)
/* SUBU - subtract unsigned */
MIPS_INS(SUBU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SUBU)
/* SUXC1 - store doubleword indexed unaligned from floating point */
MIPS_INS(SUXC1, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_SUXC1)
/* SW - store word */
MIPS_INS(SW, .op = MIPS32R2_OP_SW)
/* SWC1 - store word floating point */
MIPS_INS(SWC1, .op = MIPS32R2_OP_SWC1)
/* SWC2 - store eword cop2 */
MIPS_INS(SWC2, .op = MIPS32R2_OP_SWC2)
/* SWL - store word left */
MIPS_INS(SWL, .op = MIPS32R2_OP_SWL)
/* SWR - store word right */
MIPS_INS(SWR, .op = MIPS32R2_OP_SWR)
/* SWXC1 - store word indexed from floating point */
MIPS_INS(SWXC1, .op = MIPS32R2_OP_COP1X, .funct = MIPS32R2_FUNCT_SWXC1)
/* SYNC - synchronize shared memory */
MIPS_INS(SYNC, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SYNC)
/* SYNCI - synchronize caches to make instruction writes effective */
MIPS_INS(SYNCI, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_SYNCI)
/* SYSCALL - syscall */
MIPS_INS(SYSCALL, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_SYSCALL)
/* TEQ - trap if equal */
MIPS_INS(TEQ, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_TEQ)
/* TEQI - trap if equal immediate */
MIPS_INS(TEQI, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_TEQI)
/* TGE - trap if greater or equal */
MIPS_INS(TGE, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_TGE)
/* TGEI - trap if greater or equal immediate */
MIPS_INS(TGEI, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_TGEI)
/* TGEIU - trap if greater or equal immediate unsigned */
MIPS_INS(TGEIU, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_TGEIU)
/* TGEU - trap if greater or equal unsigned */
MIPS_INS(TGEU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_TGEU)
/* TLBP - probe TLB for matching entry */
MIPS_INS(TLBP, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_TLBP)
/* TLBR - read indexed TLB entry */
MIPS_INS(TLBR, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_TLBR)
/* TLBWI - write indexed TLB entry */
MIPS_INS(TLBWI, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_TLBWI)
/* TLBWR - write random TLB entry */
MIPS_INS(TLBWR, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_TLBWR)
/* TLT - trap if less then */
MIPS_INS(TLT, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_TLT)
/* TLTI - trap if less then immediate */
MIPS_INS(TLTI, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_TLTI)
/* TLTIU - trap if less then immediate unsigned */
MIPS_INS(TLTIU, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_TLTIU)
/* TLTU - trap if less then unsigned */
MIPS_INS(TLTU, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_TLTU)
/* TNE - trap if not equal */
MIPS_INS(TNE, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_TNE)
/* TNEI - trap if not equal immediate */
MIPS_INS(TNEI, .op = MIPS32R2_OP_REGIMM, .bfunct = MIPS32R2_FUNCT_TNEI)
/* WAIT - enter standby mode */
MIPS_INS(WAIT, .op = MIPS32R2_OP_COP0, .c0 = 1, .funct = MIPS32R2_FUNCT_WAIT)
/* WRPGRP - write to GPR in previous shadow set */
MIPS_INS(WRPGPR, .op = MIPS32R2_OP_COP0, .cfunct = MIPS32R2_FUNCT_WRPGPR)
/* WSBH - word swap bytes within halfwords */
MIPS_INS(WSBH, .op = MIPS32R2_OP_SPECIAL3, .funct = MIPS32R2_FUNCT_BSHFL,
.shamt = MIPS32R2_FUNCT_WSBH)
/* XOR - exclusive or */
MIPS_INS(XOR, .op = MIPS32R2_OP_SPECIAL, .funct = MIPS32R2_FUNCT_XOR)
/* XORI - exclusive or immediate */
MIPS_INS(XORI, .op = MIPS32R2_OP_XORI)
};
#undef MIPS_INS

View file

@ -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)
/* BALC - branch and link, compact */
MIPS_INS(BALC, .op = MIPS32R6_OP_BALC)
/* BC1FL - branch on cop1 false likely */
MIPS_INS(BC1FL, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_BC,
.nd = 1, .tf = 0)
/* BC - branch, compact */
MIPS_INS(BC, .op = MIPS32R6_OP_BC)
/* BC1T - branch on cop1 true */
MIPS_INS(BC1T, .op = MIPS32R6_OP_COP1, .cfunct = MIPS32R6_FUNCT_BC,
.nd = 0, .tf = 1)
/* 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)
/* MOD - modulo */
MIPS_INS(MOD, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP32_MOD,
.funct = MIPS32R6_FUNCT_SOP32)
/* 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)
/* 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)
/* MODU - modulo unsigned */
MIPS_INS(MODU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP33_MODU,
.funct = MIPS32R6_FUNCT_SOP33)
/* EI - enable interupts */
MIPS_INS(EI, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_MFMC0,
.rd = 12, .sc = 1)
/* 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)
/* MUH - multiply high word */
MIPS_INS(MUH, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP30_MUH,
.funct = MIPS32R6_FUNCT_SOP30)
/* LDC2 - load eword cop2 */
MIPS_INS(LWC2, .op = MIPS32R6_OP_LWC2)
/* MULU - multiply low word unsigned */
MIPS_INS(MULU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP31_MULU,
.funct = MIPS32R6_FUNCT_SOP31)
/* LWL - load word left */
MIPS_INS(LWL, .op = MIPS32R6_OP_LWL)
/* MUHU - multiply high word unsgined */
MIPS_INS(MUHU, .op = MIPS32R6_OP_SPECIAL, .shamt = MIPS32R6_SOP31_MUHU,
.funct = MIPS32R6_FUNCT_SOP31)
/* 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)
/* RDHWR - read hardware register */
MIPS_INS(RDHWR, .op = MIPS32R6_OP_SPECIAL3, .funct = MIPS32R6_FUNCT_RDHWR)
/* RDPGPR - read gpr from previous shadow set */
MIPS_INS(RDPGPR, .op = MIPS32R6_OP_COP0, .cfunct = MIPS32R6_FUNCT_RDPGPR)
/* 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

View file

@ -1,99 +0,0 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __ASM_H__
#define __ASM_H__
#include <elf.h>
#include "gen.h"
///
/// ELF string table
///
struct elf_str_table {
// size of the ptr in bytes
size_t size;
// pointer that contains
// the strings
char *ptr;
};
/* initalize a string table */
int strtab_init(struct elf_str_table *strtab);
/* free a string table */
void strtab_free(struct elf_str_table *strtab);
/* get a string form the string table */
int strtab_get_str(struct elf_str_table *strtab, const char *str, size_t *res);
/* get or append a string into the string table */
int strtab_write_str(struct elf_str_table *strtab, const char *str, size_t *res);
///
/// elf section
///
/* holds a section of the asm file (i.e. .text, .bss, .data) */
struct elf_section {
// section data *weak* pointer
struct section *data;
// index of the section in
// the ELF shdr
size_t shdr_idx;
// relocation table
size_t reltab_shidx;
uint32_t reltab_len;
Elf32_Rel *reltab;
};
///
/// assembler
///
struct assembler {
// the code generator
struct generator gen;
/// symbol table
size_t symtab_shidx;
size_t symtab_len;
Elf32_Sym *symbols;
// sh string table
size_t strtab_shidx;
struct elf_str_table strtab;
// string table
size_t shstrtab_shidx;
struct elf_str_table shstrtab;
/// sections
uint32_t section_len;
struct elf_section *sections;
/// section header
Elf32_Shdr *shdr;
uint32_t shdr_len;
};
/* defines arguments to the assembler */
struct assembler_arguments {
char *in_file;
char *out_file;
};
/* initalize the assembler */
int assembler_init(struct assembler *assembler, const char *path);
/* free the assembler */
void assembler_free(struct assembler *assembler);
/* assemble a file */
int assemble_file(struct assembler_arguments args);
#endif /* __ASM_H__ */

View file

@ -1,15 +1,11 @@
#include <merror.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
#include <string.h>
#include <stddef.h>
#include <melf.h>
#include "asm.h"
#include "gen.h"
#include "tab.h"
#include "../tab.h"
#include "../masm.h"
#include "elf32.h"
extern char *current_file;
@ -83,10 +79,10 @@ static void elf_section_free(struct elf_section *sec)
free(sec->reltab);
}
static int asm_init_sections(struct assembler *assembler)
static int asm_init_sections(struct elf_assembler *assembler)
{
struct section *sections = assembler->gen.sections;
uint32_t len = assembler->gen.sections_len;
struct section *sections = assembler->gen->sections;
uint32_t len = assembler->gen->sections_len;
struct elf_section *elftab = malloc(sizeof(struct elf_section) * len);
if (elftab == NULL) {
@ -121,8 +117,8 @@ static int elf_sym_bind(enum symbol_type ty) {
return STB_GLOBAL;
}
static int asm_init_symtab(struct assembler *assembler) {
struct symbol_table *symtab = &assembler->gen.symtab;
static int asm_init_symtab(struct elf_assembler *assembler) {
struct symbol_table *symtab = &assembler->gen->symtab;
size_t len = symtab->len + 1;
Elf32_Sym *elftab = malloc(sizeof(Elf32_Sym) * len);
if (elftab == NULL) {
@ -146,6 +142,17 @@ static int asm_init_symtab(struct assembler *assembler) {
return M_ERROR;
}
// check if symbol is undefined
if (sym->secidx == SYM_SEC_STUB) {
if (sym->type == SYM_LOCAL &&
assembler->args->extern_undefined == false) {
ERROR("undefined symbol %s", sym->name.str);
return M_ERROR;
}
sym->secidx = 0;
bind = STB_GLOBAL;
}
elftab[i+1] = (Elf32_Sym) {
.st_name = B32(str_off),
.st_info = ELF32_ST_INFO(bind, type),
@ -162,18 +169,7 @@ static int asm_init_symtab(struct assembler *assembler) {
return M_SUCCESS;
}
static int parse_file(struct assembler *assembler)
{
if (generate_mips32r6(&assembler->gen))
return M_ERROR;
if (asm_init_sections(assembler))
return M_ERROR;
if (asm_init_symtab(assembler))
return M_ERROR;
return M_SUCCESS;
}
static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
static int assemble_shdr(struct elf_assembler *assembler, Elf32_Shdr **res,
uint32_t *res2)
{
uint32_t max_entries = 0;
@ -337,7 +333,7 @@ static int assemble_shdr(struct assembler *assembler, Elf32_Shdr **res,
return M_SUCCESS;
}
static void update_offsets(struct assembler *assembler, Elf32_Ehdr *ehdr)
static void update_offsets(struct elf_assembler *assembler, Elf32_Ehdr *ehdr)
{
Elf32_Shdr *shdr = (Elf32_Shdr *) assembler->shdr;
uint32_t ptr = 0;
@ -402,7 +398,7 @@ static void update_offsets(struct assembler *assembler, Elf32_Ehdr *ehdr)
ehdr->e_shoff = B32(ptr);
}
static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
static int write_file(struct elf_assembler *assembler, Elf32_Ehdr *ehdr,
const char *path)
{
FILE *out = fopen(path, "w");
@ -453,11 +449,11 @@ static int write_file(struct assembler *assembler, Elf32_Ehdr *ehdr,
return M_SUCCESS;
}
static void update_sym_shndx(struct assembler *assembler)
static void update_sym_shndx(struct elf_assembler *assembler)
{
for (uint32_t i = 1; i < assembler->symtab_len; i++) {
Elf32_Sym *esym = &assembler->symbols[i];
struct symbol *sym = &assembler->gen.symtab.symbols[i - 1];
struct symbol *sym = &assembler->gen->symtab.symbols[i - 1];
// get shindx
int shindx = 0;
@ -470,14 +466,42 @@ static void update_sym_shndx(struct assembler *assembler)
}
}
static int assemble_elf(struct assembler *assembler, const char *out)
static int assemble_elf(struct elf_assembler *assembler, const char *out)
{
if (asm_init_sections(assembler))
return M_ERROR;
if (asm_init_symtab(assembler))
return M_ERROR;
if (assemble_shdr(assembler, &assembler->shdr, &assembler->shdr_len))
return M_ERROR;
// get ehdr flags
uint32_t flags = EF_MIPS_NAN2008;
switch (assembler->args->isa) {
case ISA_MIPS1:
flags |= EF_MIPS_ARCH_1;
break;
case ISA_MIPS32R2:
flags |= EF_MIPS_ARCH_32R2;
break;
case ISA_MIPS32R6:
flags |= EF_MIPS_ARCH_32R6;
break;
}
switch (assembler->args->abi) {
case ABI_O32:
flags |= EF_MIPS_ABI_O32;
break;
case ABI_NONE:
break;
}
Elf32_Ehdr ehdr = MIPS_ELF_EHDR;
ehdr.e_shnum = B16(assembler->shdr_len);
ehdr.e_shstrndx = B16(assembler->shstrtab_shidx);
ehdr.e_flags = B32(flags);
update_offsets(assembler, &ehdr);
update_sym_shndx(assembler);
@ -487,41 +511,20 @@ static int assemble_elf(struct assembler *assembler, const char *out)
return M_SUCCESS;
}
int assemble_file(struct assembler_arguments args)
static int assembler_init(struct elf_assembler *assembler,
struct generator *gen,
struct arguments *args)
{
struct assembler assembler;
int res = M_SUCCESS;
assembler->args = args;
assembler->gen = gen;
current_file = args.in_file;
if (assembler_init(&assembler, args.in_file))
return M_ERROR;
if (res == M_SUCCESS)
res = parse_file(&assembler);
if (res == M_SUCCESS)
res = assemble_elf(&assembler, args.out_file);
assembler_free(&assembler);
return res;
}
int assembler_init(struct assembler *assembler, const char *path)
{
assembler->shdr = NULL;
assembler->symbols = NULL;
assembler->sections = NULL;
assembler->strtab.ptr = NULL;
assembler->shstrtab.ptr = NULL;
assembler->gen.sections = NULL;
assembler->gen.symtab.symbols = NULL;
assembler->section_len = 0;
if (generator_init(path, &assembler->gen))
return M_ERROR;
if (strtab_init(&assembler->shstrtab))
return M_ERROR;
@ -531,7 +534,7 @@ int assembler_init(struct assembler *assembler, const char *path)
return M_SUCCESS;
}
void assembler_free(struct assembler *assembler)
static void assembler_free(struct elf_assembler *assembler)
{
if (assembler->shdr)
free(assembler->shdr);
@ -545,5 +548,20 @@ void assembler_free(struct assembler *assembler)
strtab_free(&assembler->strtab);
strtab_free(&assembler->shstrtab);
generator_free(&assembler->gen);
}
int assemble_elf32(struct generator *gen, struct arguments *args)
{
struct elf_assembler assembler;
int res = M_SUCCESS;
current_file = args->in_file;
if (assembler_init(&assembler, gen, args))
return M_ERROR;
res = assemble_elf(&assembler, args->out_file);
assembler_free(&assembler);
return res;
}

90
masm/asm/elf32.h Normal file
View file

@ -0,0 +1,90 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __ELF32_H__
#define __ELF32_H__
#include <elf.h>
#include "../gen.h"
#include "../masm.h"
///
/// ELF string table
///
struct elf_str_table {
// size of the ptr in bytes
size_t size;
// pointer that contains
// the strings
char *ptr;
};
/* initalize a string table */
int strtab_init(struct elf_str_table *strtab);
/* free a string table */
void strtab_free(struct elf_str_table *strtab);
/* get a string form the string table */
int strtab_get_str(struct elf_str_table *strtab, const char *str, size_t *res);
/* get or append a string into the string table */
int strtab_write_str(struct elf_str_table *strtab, const char *str, size_t *res);
///
/// elf section
///
/* holds a section of the asm file (i.e. .text, .bss, .data) */
struct elf_section {
// section data *weak* pointer
struct section *data;
// index of the section in
// the ELF shdr
size_t shdr_idx;
// relocation table
size_t reltab_shidx;
uint32_t reltab_len;
Elf32_Rel *reltab;
};
///
/// assembler
///
struct elf_assembler {
// arguments passed in
struct arguments *args;
// the code generator
struct generator *gen;
/// symbol table
size_t symtab_shidx;
size_t symtab_len;
Elf32_Sym *symbols;
// sh string table
size_t strtab_shidx;
struct elf_str_table strtab;
// string table
size_t shstrtab_shidx;
struct elf_str_table shstrtab;
/// sections
uint32_t section_len;
struct elf_section *sections;
/// section header
Elf32_Shdr *shdr;
uint32_t shdr_len;
};
int assemble_elf32(struct generator *gen, struct arguments *args);
#endif /* __ELF32_H__ */

View file

@ -2,7 +2,7 @@
#include <string.h>
#include <stdlib.h>
#include "asm.h"
#include "elf32.h"
int strtab_get_str(struct elf_str_table *strtab, const char *str, size_t *res)
{

View file

@ -1,186 +1,19 @@
#include <stdlib.h>
#include <merror.h>
#include <melf.h>
#include <mips32.h>
#include <mips.h>
#include <mips1.h>
#include <mips32r2.h>
#include <mips32r6.h>
#include "tab.h"
#include "gen.h"
#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)
{
@ -263,300 +96,37 @@ static int gen_constant(struct generator *gen, struct expr_const *const expr)
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(IMMD, "immd")
CHK(OFFSET_BASE, "offset(base)")
CHK(OFFSET, "offset")
CHK(TARGET, "target")
CHK(HI, "hi")
CHK(LO, "lo")
#undef CHK
ERROR("!!! BUG: this should never hit !!!");
exit(1);
}
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 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_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_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_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 {
ERROR("!! BUG3: invalid splitting char %c !!!", *ptr);
exit(1);
}
}
return M_SUCCESS;
}
static int gen_ins_write_state(
struct generator *gen,
union mips32_instruction ins, // the instruction to modify
struct gen_ins_state *state, // the current read state
char *grammer) // the gramemr to parse
{
// grammer pointer
char *ptr = grammer;
// new reference type if needed
enum reference_type reftype = REF_NONE;
// hardcoded
struct gen_ins_override hstate;
bool hc = false;
// read values into state
while (*ptr != '\0') {
// parse next dsl entry
size_t skip;
enum grammer_type gmr = get_gmr_type(ptr, &skip);
// check for dsl hardcoded register argument
bool hardcoded = false;
enum mips32_register hard_reg;
hc = false;
if (*(ptr + skip) == '=') {
// parse argument
char *rptr = ptr + skip + 2;
hardcoded = true;
struct string regname;
string_bss(&regname, rptr);
if (parse_register(&hard_reg, &regname)) {
ERROR("!!! BUG2: this should never hit !!!");
// get value pointer
char *value = ptr + skip + 1;
hc = true;
// parse value
if (get_gmr_hc(state, &hstate, value)) {
BUG("invalid grammer: %s", grammer);
exit(1);
}
}
@ -568,16 +138,43 @@ static int gen_ins_write_state(
switch (gmr) {
case GMR_RD:
ins.rd = hardcoded ? hard_reg : state->rd;
ins.rd = hc ? hstate.reg : state->rd;
break;
case GMR_RS:
ins.rs = hardcoded ? hard_reg : state->rs;
ins.rs = hc ? hstate.reg : state->rs;
break;
case GMR_RT:
ins.rt = hardcoded ? hard_reg : state->rt;
ins.rt = hc ? hstate.reg : state->rt;
break;
case GMR_FS:
ins.fs = hc ? hstate.fpreg : state->fs;
break;
case GMR_FT:
ins.ft = hc ? hstate.fpreg : state->ft;
break;
case GMR_FD:
ins.fd = hc ? hstate.fpreg : state->fd;
break;
case GMR_IMMD:
ins.immd = state->immd;
ins.immd = hc ? hstate.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 ? hstate.immd : state->hb;
break;
case GMR_HINT:
ins.rt = state->hint;
break;
case GMR_OFFSET:
ins.offset = state->offset;
@ -588,6 +185,10 @@ static int gen_ins_write_state(
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;
@ -600,6 +201,7 @@ static int gen_ins_write_state(
ins.immd = state->target & 0x0000FFFF;
reftype = REF_MIPS_LO16;
break;
break;
}
}
@ -721,8 +323,8 @@ static int gen_label(struct generator *gen, struct string *const label)
return M_SUCCESS;
}
/* run codegen */
static int generate(struct generator *gen)
/* run codegen for next expression */
static int generate_next(struct generator *gen)
{
struct expr expr;
int res = M_SUCCESS;
@ -771,16 +373,10 @@ static int generate(struct generator *gen)
return res;
}
/* run codegen with the mips32r6 specification */
int generate_mips32r6(struct generator *gen)
static int generate(struct generator *gen)
{
gen->instructions_len = __MIPS32R6_INS_LEN;
gen->instructions = mips32r6_instructions;
gen->grammers_len = __MIPS32R6_GRAMMER_LEN;
gen->grammers = mips32r6_grammers;
int res;
while (res = generate(gen), 1) {
while (res = generate_next(gen), 1) {
if (res == M_ERROR)
return M_ERROR;
if (res == M_EOF)
@ -790,6 +386,46 @@ int generate_mips32r6(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)
{
gen->instructions_len = __MIPS32R6_INS_LEN;
gen->instructions = mips32r6_instructions;
gen->grammers_len = __MIPS32R6_GRAMMER_LEN;
gen->grammers = mips32r6_grammers;
return generate(gen);
}
/* run codegen with the mips32r2 specification */
int generate_mips32r2(struct generator *gen)
{
gen->instructions_len = __MIPS32R2_INS_LEN;
gen->instructions = mips32r2_instructions;
gen->grammers_len = __MIPS32R2_GRAMMER_LEN;
gen->grammers = mips32r2_grammers;
return generate(gen);
}
/* run codegen with the mips32r6 specification */
int generate_mips1(struct generator *gen)
{
gen->instructions_len = __MIPS1_INS_LEN;
gen->instructions = mips1_instructions;
gen->grammers_len = __MIPS1_GRAMMER_LEN;
gen->grammers = mips1_grammers;
return generate(gen);
}
//
// constructors and deconstructors
//
int generator_init(const char *file, struct generator *gen)
{
if (parser_init(file, &gen->parser))

View file

@ -4,7 +4,7 @@
#define __GEN_H__
#include <mlimits.h>
#include <mips32.h>
#include <mips.h>
#include <stdint.h>
#include "parse.h"
@ -37,48 +37,140 @@ 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
///
struct gen_ins_state {
// rd,rst,rt
// rd,rs,rt
enum mips32_register rd;
enum mips32_register rs;
enum mips32_register rt;
// fs,ft
enum mips32_fp_register fs;
enum mips32_fp_register ft;
enum mips32_fp_register fd;
// immd
uint16_t immd;
// offset(base)
uint16_t offset;
enum mips32_register base;
// cc
uint16_t cc;
// code
uint32_t code;
// pos
uint32_t pos;
// size
uint32_t size;
// hint
uint32_t hint;
// 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;
};
///
/// grammer type
///
struct gen_ins_override {
enum mips32_register reg;
enum mips32_fp_register fpreg;
uint32_t immd;
};
enum grammer_type {
// registers
GMR_RD,
GMR_RS,
GMR_RT,
// fp registers
GMR_FS,
GMR_FT,
GMR_FD,
// numeric fields
GMR_IMMD,
GMR_OFFSET,
GMR_OFFSET_BASE,
GMR_TARGET,
GMR_CC,
GMR_CODE,
GMR_POS,
GMR_SIZE,
GMR_HB,
GMR_HINT,
// addresses
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
@ -106,8 +198,15 @@ 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 */
int generate_mips32r2(struct generator *gen);
/* run codegen with the mips32r6 specification */
int generate_mips1(struct generator *gen);
/* initalize a generator */
int generator_init(const char *file, struct generator *gen);

643
masm/gen/grammer.c Normal file
View file

@ -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;
}
}
}

28
masm/gen/log.c Normal file
View file

@ -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);
}
}

156
masm/gen/section.c Normal file
View file

@ -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);
}

View file

@ -1,33 +1,151 @@
#include <unistd.h>
#include <merror.h>
#include <string.h>
#include <stdio.h>
#include "asm.h"
#include "gen.h"
#include "masm.h"
#include "asm/elf32.h"
void help(void) {
printf("usage: masm [options] source.asm\n\n");
printf("options:\n");
printf("\t-h\t\tprints this help message\n");
printf("\t-o <output>\tselect a output file destination\n");
printf(
"usage: masm [options] source.asm\n"
"\n"
"options: \n"
" -h print the help message \n"
" -g assume undefined symbols are external\n"
" -o <output> specify the object file output name \n"
" -a <abi> specify mips abi used [none, o32] \n"
" default: o32 \n"
" -i <isa> mips machine isa to assemble for [mips1, mips32r2, mips32r6] \n"
" default: mips32r6\n"
" -f <format> specify the object file format [elf32] \n"
" defualt: elf32\n"
);
}
static int read_isa(enum isa *isa, const char *str)
{
#define __ISA_CHK(name) \
if (strcasecmp(#name, str) == 0) { \
*isa = ISA_ ##name; \
return M_SUCCESS; \
} \
__ISA_CHK(MIPS1);
__ISA_CHK(MIPS32R2);
__ISA_CHK(MIPS32R6);
ERROR("invalid isa '%s'", str);
return M_ERROR;
}
static int read_abi(enum abi *abi, const char *str)
{
#define __ABI_CHK(name) \
if (strcasecmp(#name, str) == 0) { \
*abi = ABI_ ##name; \
return M_SUCCESS; \
} \
__ABI_CHK(O32);
__ABI_CHK(NONE);
ERROR("invalid abi '%s'", str);
return M_ERROR;
}
static int read_format(enum format *format, const char *str)
{
#define __FORMAT_CHK(name) \
if (strcasecmp(#name, str) == 0) { \
*format = FORMAT_ ##name; \
return M_SUCCESS; \
} \
__FORMAT_CHK(ELF32);
ERROR("invalid format '%s'", str);
return M_ERROR;
}
static int generate(struct generator *gen, struct arguments *args)
{
if (generator_init(args->in_file, gen))
return M_ERROR;
switch (args->isa) {
case ISA_MIPS1:
return generate_mips1(gen);
case ISA_MIPS32R2:
return generate_mips32r2(gen);
case ISA_MIPS32R6:
return generate_mips32r6(gen);
}
return M_ERROR;
}
static int assemble(struct arguments *args)
{
struct generator gen;
int res = M_SUCCESS;
if (generate(&gen, args))
return M_ERROR;
switch (args->format) {
case FORMAT_ELF32:
res = assemble_elf32(&gen, args);
break;
default:
res = M_ERROR;
break;
}
generator_free(&gen);
return res;
}
int main(int argc, char **argv) {
struct assembler_arguments args = {
struct arguments args = {
.in_file = NULL,
.out_file = "out.o",
.extern_undefined = false,
.isa = ISA_MIPS32R6,
.abi = ABI_O32,
.format = FORMAT_ELF32
};
int c;
while ((c = getopt(argc, argv, "ho:")) != 1) {
while ((c = getopt(argc, argv, "hgo:a:i:f:")) != 1) {
switch(c) {
case 'h':
help();
return M_SUCCESS;
case 'g':
args.extern_undefined = true;
break;
case 'o':
args.out_file = optarg;
break;
case 'a':
if (read_abi(&args.abi, optarg))
return M_ERROR;
break;
case 'i':
if (read_isa(&args.isa, optarg))
return M_ERROR;
break;
case 'f':
if (read_format(&args.format, optarg))
return M_ERROR;
break;
case '?':
return M_ERROR;
default:
@ -48,5 +166,5 @@ next:
args.in_file = argv[optind];
return assemble_file(args);
return assemble(&args);
}

45
masm/masm.h Normal file
View file

@ -0,0 +1,45 @@
/* Copyright (c) 2024 Freya Murphy */
#ifndef __MASM_H__
#define __MASM_H__
// isa to asemble for
enum isa {
ISA_MIPS1, // a.k.a mipsR2000
ISA_MIPS32R2,
ISA_MIPS32R6,
};
// abi to mark output object
enum abi {
ABI_O32, // mips o32 abi
ABI_NONE, // no flag output
};
// format for the object file
enum format {
FORMAT_ELF32,
};
// defines arguments
struct arguments {
// files to read from and
// write to
char *in_file;
char *out_file;
// if undefined symbols should
// be treated as extern
bool extern_undefined;
// isa to assemble for
enum isa isa;
// abi to mark object
enum abi abi;
// format to output
enum format format;
};
#endif /* __ASM_H__ */

View file

@ -1,7 +1,7 @@
#include <stdlib.h>
#include <merror.h>
#include "tab.h"
#include "../tab.h"
#define REFTAB_INIT_LEN 8

View file

@ -5,8 +5,7 @@
#include <stdlib.h>
#include <string.h>
#include "lex.h"
#include "tab.h"
#include "../tab.h"
#define SYMTBL_INIT_LEN 24

25
test/masm/pseudo.asm Normal file
View file

@ -0,0 +1,25 @@
# Copyright (c) 2024 Freya Murphy
# file: pseudo.asm
# test: test pseudo dsl parser
.text
.align 2
.globl main
main:
li $t0, 0
li $t1, 1
ble $t0, $t1, less
nop
less:
beqz $t0, exit
nop
exit:
# return
slte $a0, $t0, $t1
jr $ra
nop

1
test/out/pesudo.status Normal file
View file

@ -0,0 +1 @@
0

0
test/out/pseudo Normal file
View file