/* $NetBSD: insn.h,v 1.5 2024/02/02 22:00:33 andvar Exp $ */

/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas of 3am Software Foundry.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef _RISCV_INSN_H_
#define _RISCV_INSN_H_

/*
* I have corrected and updated this, but it's the wrong way to do it.
* It's still used by ddb_machdep.c but that code should be fixed to
* use the newer stuff below. - dholland
*/
union riscv_insn {
       uint32_t val;
       /* register ops */
       struct {
               unsigned int r_opcode : 7;
               unsigned int r_rd : 5;
               unsigned int r_funct3 : 3;
               unsigned int r_rs1 : 5;
               unsigned int r_rs2 : 5;
               unsigned int r_funct7 : 7;
       } type_r;
       /* 32-bit shifts */
       struct {
               unsigned int rs32_opcode : 7;
               unsigned int rs32_rd : 5;
               unsigned int rs32_funct3 : 3;
               unsigned int rs32_rs1 : 5;
               unsigned int rs32_shamt : 5;
               unsigned int rs32_funct7 : 7;
       } type_rs32;
       /* 64-bit shifts */
       struct {
               unsigned int rs64_opcode : 7;
               unsigned int rs64_rd : 5;
               unsigned int rs64_funct3 : 3;
               unsigned int rs64_rs1 : 5;
               unsigned int rs64_shamt : 6;
               unsigned int rs64_zero : 1;
               unsigned int rs64_funct5 : 5;
       } type_rs64;
       /* atomics */
       struct {
               unsigned int ra_opcode : 7;
               unsigned int ra_rd : 5;
               unsigned int ra_funct3 : 3;
               unsigned int ra_rs1 : 5;
               unsigned int ra_rs2 : 5;
               unsigned int ra_rl : 1;
               unsigned int ra_aq : 1;
               unsigned int ra_funct5 : 5;
       } type_ra;
       /* certain fpu ops */
       struct {
               unsigned int rf_opcode : 7;
               unsigned int rf_rd : 5;
               unsigned int rf_rm : 3;
               unsigned int rf_rs1 : 5;
               unsigned int rf_rs2 : 5;
               unsigned int rf_size : 2;
               unsigned int rf_funct5 : 5;
       } type_rf;
       /* other fpu ops */
       struct {
               unsigned int rf4_opcode : 7;
               unsigned int rf4_rd : 5;
               unsigned int rf4_rm : 3;
               unsigned int rf4_rs1 : 5;
               unsigned int rf4_rs2 : 5;
               unsigned int rf4_size : 2;
               unsigned int rf4_rs3 : 5;
       } type_rf4;
       /* immediates */
       struct {
               unsigned int i_opcode : 7;
               unsigned int i_rd : 5;
               unsigned int i_funct3 : 3;
               unsigned int i_rs1 : 5;
               signed int i_imm11to0 : 12;
       } type_i;
       /* stores */
       struct {
               unsigned int s_opcode : 7;
               unsigned int s_imm4_to_0 : 5;
               unsigned int s_funct3 : 3;
               unsigned int s_rs1 : 5;
               unsigned int s_rs2 : 5;
               signed int s_imm11_to_5 : 7;
       } type_s;
       /* branches */
       struct {
               unsigned int b_opcode : 7;
               unsigned int b_imm11 : 1;
               unsigned int b_imm4to1 : 4;
               unsigned int b_funct3 : 3;
               unsigned int b_rs1 : 5;
               unsigned int b_rs2 : 5;
               unsigned int b_imm10to5 : 6;
               signed int b_imm12 : 1;
       } type_b;
       /* large immediate constants */
       struct {
               unsigned int u_opcode : 7;
               unsigned int u_rd : 5;
               signed int u_imm31to12 : 20;
       } type_u;
       /* large immediate jumps */
       struct {
               unsigned int j_opcode : 7;
               unsigned int j_rd : 5;
               unsigned int j_imm19to12 : 9;
               unsigned int j_imm11 : 1;
               unsigned int j_imm10to1 : 9;
               signed int j_imm20 : 1;
       } type_j;
};

/*
* old macro still in use with the above
* (XXX, doesn't handle 16-bit instructions)
*/

#define OPCODE_P(i, x)          (((i) & 0b1111111) == ((OPCODE_##x<<2)|0b11))

////////////////////////////////////////////////////////////

/*
* Instruction size
*/

/* cumulative size tests */
#define INSN_SIZE_IS_16(insn) (((insn) & 0b11) != 0b11)
#define INSN_SIZE_IS_32(insn) (((insn) & 0b11100) != 0b11100)
#define INSN_SIZE_IS_48(insn) (((insn) & 0b100000) != 0b100000)
#define INSN_SIZE_IS_64(insn) (((insn) & 0b1000000) != 0b1000000)

/* returns 1-5 for the number of uint16s */
#define INSN_HALFWORDS(insn) \
       (INSN_SIZE_IS_16(insn) ? 1 : \
        INSN_SIZE_IS_32(insn) ? 2 : \
        INSN_SIZE_IS_48(insn) ? 3 : \
        INSN_SIZE_IS_64(insn) ? 4 : \
        5)

#define INSN_SIZE(insn) (INSN_HALFWORDS(insn) * sizeof(uint16_t))

/*
* sign-extend x from the bottom k bits
*/
#define SIGNEXT32(x, k) ( \
               ( ((x) & (1U << ((k)-1))) ? (0xffffffffU << (k)) : 0U) | \
               ((x) & (0xffffffffU >> (32 - (k))))                      \
       )

/*
* Field extractors for 32-bit instructions
*/

#define INSN_OPCODE32(insn)     (((insn) & 0x0000007f) >> 2)
#define INSN_RD(insn)           (((insn) & 0x00000f80) >> 7)
#define INSN_FUNCT3(insn)       (((insn) & 0x00007000) >> 12)
#define INSN_RS1(insn)          (((insn) & 0x000f8000) >> 15)
#define INSN_RS2(insn)          (((insn) & 0x01f00000) >> 20)
#define INSN_FUNCT7(insn)       (((insn) & 0xfe000000) >> 25)

/* U-type immediate, just the top bits of the instruction */
#define INSN_IMM_U(insn)         ((insn) & 0xfffff000)

/* I-type immediate, upper 12 bits sign-extended */
#define INSN_IMM_I(insn)        SIGNEXT32(((insn) & 0xfff00000) >> 20, 12)

/* S-type immediate (stores), pasted from funct7 field and rd field */
#define INSN_IMM_S_raw(insn)    ((INSN_FUNCT7(insn) << 5) | INSN_RD(insn))
#define INSN_IMM_S(insn)        SIGNEXT32(INSN_IMM_S_raw(insn), 12)

/* B-type immediate (branches), pasted messily from funct7 and rd fields */
#define INSN_IMM_B_raw(insn)                    \
       (((insn & 0x80000000) >> (31-12)) |     \
        ((insn & 0x00000080) << (11-7))  |     \
        ((insn & 0x7e000000) >> (25-5))  |     \
        ((insn & 0x00000f00) >> (8-1)))
#define INSN_IMM_B(insn)        SIGNEXT32(INSN_IMM_B_raw(insn), 13)

/* J-type immediate (jumps), rehash of the U immediate field */
#define INSN_IMM_J_raw(insn)                    \
       (((insn & 0x80000000) >> (31-20)) |     \
        ((insn & 0x000ff000) >> (12-12)) |     \
        ((insn & 0x00100000) >> (20-11)) |     \
        ((insn & 0x7fe00000) >> (21-1)))
#define INSN_IMM_J(insn)        SIGNEXT32(INSN_IMM_J_raw(insn), 21)

/*
* Field extractors for 16-bit instructions
*/

#define INSN16_QUADRANT(insn)   ((insn) & 0b11)

/*
* In the manual there's
*    FUNCT3 (bits 13-15)
*    FUNCT4 (bits 12-15)
*    FUNCT6 (bits 10-15)
*    FUNCT2 (bits 5-6)
*
* but this does not reflect the actual usage correctly. So I've got
*    FUNCT3 (bits 13-15)
*    FUNCT2a (bits 10-11)
*    FUNCT1b (bit 12)
*    FUNCT2b (bits 5-6)
*    FUNCT3b (FUNCT1b pasted to FUNCT3b)
*
* Quadrant 0 just uses FUNCT3;
* Quadrant 1 goes FUNCT3 -> FUNCT2a -> FUNCT3b,
* Quadrant 2 goes FUNCT3 -> FUNCT1b.
*/
#define INSN16_FUNCT3(insn)     (((insn) & 0xe000) >> 13)
#define INSN16_FUNCT2a(insn)    (((insn) & 0x0c00) >> 10)
#define INSN16_FUNCT1b(insn)    (((insn) & 0x1000) >> 12)
#define INSN16_FUNCT2b(insn)    (((insn) & 0x0060) >> 5)
#define INSN16_FUNCT3c(insn)    \
       ((INSN16_FUNCT1b(insn) << 2) | INSN16_FUNCT2b(insn))

/* full-size register fields */
#define INSN16_RS1(insn)        (((insn) & 0x0f80) >> 7)  /* bits 7-11 */
#define INSN16_RS2(insn)        (((insn) & 0x007c) >> 2)  /* bits 2-6 */

/* small register fields, for registers 8-15 */
#define INSN16_RS1x(insn)       ((((insn) & 0x0380) >> 7) + 8)  /* bits 7-9 */
#define INSN16_RS2x(insn)       ((((insn) & 0x001c) >> 2) + 8)  /* bits 2-4 */

/* CI format immediates, for word/double/quad offsets, zero-extended */
#define INSN16_IMM_CI_W(insn) \
       ((((insn) & 0b0001000000000000) >> (12-5)) |    \
        (((insn) & 0b0000000001110000) >> (4-2)) |     \
        (((insn) & 0b0000000000001100) << (6-2)))
#define INSN16_IMM_CI_D(insn) \
       ((((insn) & 0b0001000000000000) >> (12-5)) |    \
        (((insn) & 0b0000000001100000) >> (4-2)) |     \
        (((insn) & 0b0000000000011100) << (6-2)))
#define INSN16_IMM_CI_Q(insn) \
       ((((insn) & 0b0001000000000000) >> (12-5)) |    \
        (((insn) & 0b0000000001000000) >> (4-2)) |     \
        (((insn) & 0b0000000000111100) << (6-2)))

/* additional CI format immediates for constants, sign-extended */
#define INSN16_IMM_CI_K_raw(insn) \
       ((((insn) & 0b0001000000000000) >> (12-5)) |    \
        (((insn) & 0b0000000001111100) >> (2-0)))
#define INSN16_IMM_CI_K(insn) SIGNEXT32(INSN16_IMM_CI_K_raw(insn), 6)
#define INSN16_IMM_CI_K12(insn) SIGNEXT32(INSN16_IMM_CI_K_raw(insn) << 12, 18)

/* and another one, sign-extended */
#define INSN16_IMM_CI_K4_raw(insn) \
       ((((insn) & 0b0001000000000000) >> (12-9)) |    \
        (((insn) & 0b0000000001000000) >> (6-4)) |     \
        (((insn) & 0b0000000000100000) << (6-5)) |     \
        (((insn) & 0b0000000000011000) << (7-3)) |     \
        (((insn) & 0b0000000000000100) << (5-2)))
#define INSN16_IMM_CI_K4(insn) SIGNEXT32(INSN16_IMM_CI_K4_raw(insn), 10)


/* CSS format immediates, for word/double/quad offsets, zero-extended */
#define INSN16_IMM_CSS_W(insn) \
       ((((insn) & 0b0001111000000000) >> (9-2)) |     \
        (((insn) & 0b0000000110000000) >> (7-6)))
#define INSN16_IMM_CSS_D(insn) \
       ((((insn) & 0b0001110000000000) >> (9-2)) |     \
        (((insn) & 0b0000001110000000) >> (7-6)))
#define INSN16_IMM_CSS_Q(insn) \
       ((((insn) & 0b0001100000000000) >> (9-2)) |     \
        (((insn) & 0b0000011110000000) >> (7-6)))

/* CL format immediates, for word/double/quad offsets, zero-extended */
#define INSN16_IMM_CL_W(insn) \
       ((((insn) & 0b0001110000000000) >> (10-3)) |    \
        (((insn) & 0b0000000001000000) >> (6-2)) |     \
        (((insn) & 0b0000000000100000) << (6-5)))
#define INSN16_IMM_CL_D(insn) \
       ((((insn) & 0b0001110000000000) >> (10-3)) |    \
        (((insn) & 0b0000000001100000) << (6-5)))
#define INSN16_IMM_CL_Q(insn) \
       ((((insn) & 0b0001100000000000) >> (11-4)) |    \
        (((insn) & 0b0000010000000000) >> (10-8)) |    \
        (((insn) & 0b0000000001100000) << (6-5)))

/* CS format immediates are the same as the CL ones */
#define INSN16_IMM_CS_W(insn) INSN16_IMM_CL_W(insn)
#define INSN16_IMM_CS_D(insn) INSN16_IMM_CL_D(insn)
#define INSN16_IMM_CS_Q(insn) INSN16_IMM_CL_Q(insn)

/* CJ format immediate, sign extended */
#define INSN16_IMM_CJ_raw(insn) \
       ((((insn) & 0b0001000000000000) >> (12-11)) |   \
        (((insn) & 0b0000100000000000) >> (11-4)) |    \
        (((insn) & 0b0000011000000000) >> (9-8)) |     \
        (((insn) & 0b0000000100000000) << (10-8)) |    \
        (((insn) & 0b0000000010000000) >> (7-6)) |     \
        (((insn) & 0b0000000001000000) << (7-6)) |     \
        (((insn) & 0b0000000000111000) >> (3-1)) |     \
        (((insn) & 0b0000000000000100) << (5-2)))
#define INSN16_IMM_CJ(insn) SIGNEXT32(INSN16_IMM_CJ_raw(insn), 12)

/* CB format immediate, sign extended */
#define INSN16_IMM_CB_raw(insn) \
       ((((insn) & 0b0001000000000000) >> (12-8)) |    \
        (((insn) & 0b0000110000000000) >> (10-3)) |    \
        (((insn) & 0b0000000001100000) << (6-5)) |     \
        (((insn) & 0b0000000000011000) >> (3-1)) |     \
        (((insn) & 0b0000000000000100) << (5-2)))
#define INSN16_IMM_CB(insn) SIGNEXT32(INSN16_IMM_CB_raw(insn), 9)

/* also some CB instructions use the CI_K immediate */

/* CIW format immediate, zero-extended */
#define INSN16_IMM_CIW(insn) \
       ((((insn) & 0b0001100000000000) >> (11-4)) |    \
        (((insn) & 0b0000011110000000) >> (7-6)) |     \
        (((insn) & 0b0000000001000000) >> (6-2)) |     \
        (((insn) & 0b0000000000100000) >> (5-3)))

/*
* Values for the primary opcode field (bits 2-6) in 32-bit instructions
*/

#define OPCODE_LOAD             0b00000
#define OPCODE_LOADFP           0b00001
#define OPCODE_CUSTOM0          0b00010
#define OPCODE_MISCMEM          0b00011
#define OPCODE_OPIMM            0b00100
#define OPCODE_AUIPC            0b00101
#define OPCODE_OPIMM32          0b00110
#define OPCODE_X48a             0b00111

#define OPCODE_STORE            0b01000
#define OPCODE_STOREFP          0b01001
#define OPCODE_CUSTOM1          0b01010
#define OPCODE_AMO              0b01011
#define OPCODE_OP               0b01100
#define OPCODE_LUI              0b01101
#define OPCODE_OP32             0b01110
#define OPCODE_X64              0b01111

#define OPCODE_MADD             0b10000         // FMADD.[S,D]
#define OPCODE_MSUB             0b10001         // FMSUB.[S,D]
#define OPCODE_NMSUB            0b10010         // FNMSUB.[S,D]
#define OPCODE_NMADD            0b10011         // FNMADD.[S,D]
#define OPCODE_OPFP             0b10100
#define OPCODE_rsvd21           0b10101
#define OPCODE_CUSTOM2          0b10110
#define OPCODE_X48b             0b10111

#define OPCODE_BRANCH           0b11000
#define OPCODE_JALR             0b11001
#define OPCODE_rsvd26           0b11010
#define OPCODE_JAL              0b11011
#define OPCODE_SYSTEM           0b11100
#define OPCODE_rsvd29           0b11101
#define OPCODE_CUSTOM3          0b11110
#define OPCODE_X80              0b11111

/*
* Values for the secondary/tertiary opcode field funct7 in 32-bit instructions
* for various primary and secondary opcodes.
*
* Note: for many of these the opcodes shown are the top 5 bits and the
* bottom two serve a separate purpose.
*/

// primary is OP (0b01100, 12)
#define OP_ARITH                0b0000000
#define OP_MULDIV               0b0000001
#define OP_NARITH               0b0100000

// primary is OPFP (0b10100, 20), top 5 bits
// bottom 2 bits give the size
#define OPFP_ADD                0b00000
#define OPFP_SUB                0b00001
#define OPFP_MUL                0b00010
#define OPFP_DIV                0b00011
#define OPFP_SGNJ               0b00100
#define OPFP_MINMAX             0b00101
#define OPFP_CVTFF              0b01000
#define OPFP_SQRT               0b01011
#define OPFP_CMP                0b10100
#define OPFP_CVTIF              0b11000
#define OPFP_CVTFI              0b11010
#define OPFP_MVFI_CLASS         0b11100
#define OPFP_MVIF               0b11110

// primary is OPFP (0b10100, 20), bottom two bits (operand size)
// these bits also give the size for FMADD/FMSUB/FNMSUB/FNMADD
// and for FCVTFF they appear at the bottom of the rs2 field as well
#define OPFP_S                  0b00
#define OPFP_D                  0b01
#define OPFP_Q                  0b11

// in some instructions they're an integer operand size instead
#define OPFP_W                  0b00
#define OPFP_WU                 0b01
#define OPFP_L                  0b10
#define OPFP_LU                 0b11

// primary is AMO (0b01011, 11), top 5 bits
// (bottom two bits are ACQUIRE and RELEASE flags respectively)
// funct3 gives the operand size
#define AMO_ADD                 0b00000
#define AMO_SWAP                0b00001
#define AMO_LR                  0b00010
#define AMO_SC                  0b00011
#define AMO_XOR                 0b00100
#define AMO_OR                  0b01000
#define AMO_AND                 0b01100
#define AMO_MIN                 0b10000
#define AMO_MAX                 0b10100
#define AMO_MINU                0b11000
#define AMO_MAXU                0b11100

// primary is SYSTEM (0b11100, 28) and funct3 is PRIV (0)
#define PRIV_USER               0b0000000
#define PRIV_SYSTEM             0b0001000
#define PRIV_SFENCE_VMA         0b0001001
#define PRIV_HFENCE_BVMA        0b0010001
#define PRIV_MACHINE            0b0011000
#define PRIV_HFENCE_GVMA        0b1010001

/*
* Values for the secondary/tertiary opcode field funct3 in 32-bit instructions
* for various primary and secondary opcodes.
*/

// primary is LOAD (0x00000)
#define LOAD_LB                 0b000
#define LOAD_LH                 0b001
#define LOAD_LW                 0b010
#define LOAD_LD                 0b011           // RV64I
#define LOAD_LBU                0b100
#define LOAD_LHU                0b101
#define LOAD_LWU                0b110           // RV64I

// primary is LOADFP (0x00001)
#define LOADFP_FLW              0b010
#define LOADFP_FLD              0b011
#define LOADFP_FLQ              0b100

// primary is MISCMEM (0x00011, 3)
#define MISCMEM_FENCE           0b000
#define MISCMEM_FENCEI          0b001

// primary is STORE (0b01000, 8)
#define STORE_SB                0b000
#define STORE_SH                0b001
#define STORE_SW                0b010
#define STORE_SD                0b011           // RV64I

// primary is STOREFP (0b01001, 9)
#define STOREFP_FSW             0b010
#define STOREFP_FSD             0b011
#define STOREFP_FSQ             0b100

// primary is AMO (0b01011, 11), funct7 gives the operation
#define AMO_W                   0b010
#define AMO_D                   0b011           // RV64I

// primary is
//    OPIMM   (0b00100, 4)
//    OPIMM32 (0b00110, 6)
//    OP      (0b01100, 12) when funct7 is ARITH or NARITH
//    OP32    (0b01110, 14)
//                                               OP     OP      OP32    OP32
// given:                          OPIMM OPIMM32 ARITH  NARITH  ARITH   NARITH
#define OP_ADDSUB       0b000   // addi  addiw   add    sub     addw    subw
#define OP_SLL          0b001   // (1)   (2)     sll    -       sllw    -
#define OP_SLT          0b010   // slti  -       slt    -       -       -
#define OP_SLTU         0b011   // sltiu -       sltu   -       -       -
#define OP_XOR          0b100   // xori  -       xor    -       -       -
#define OP_SRX          0b101   // (3)   (4)     srl    sra     srlw    sraw
#define OP_OR           0b110   // ori   -       or     -       -       -
#define OP_AND          0b111   // andi  -       and    -       -       -
//
// (1) slli when funct7 is ARITH
// (2) slliw when funct7 is ARITH
// (3) srli when funct7 is ARITH, srai when funct7 is NARITH
// (4) srliw when funct7 is ARITH, sraiw when funct7 is NARITH
//
// caution: on RV64, the immediate field of slli/srli/srai bleeds into
// funct7, so you have to actually only test the upper 6 bits of funct7.
// (and if RV128 ever actually happens, the upper 5 bits; conveniently
// that aligns with other uses of those 5 bits)
//

// primary is
//    OP      (0b01100, 12) when funct7 is MULDIV
//    OP32    (0b01110, 14) when funct7 is MULDIV
//
// given:                                  OP      OP32
#define OP_MUL                  0b000   // mul     mulw
#define OP_MULH                 0b001   // mulh    -
#define OP_MULHSU               0b010   // mulhsu  -
#define OP_MULHU                0b011   // mulhu   -
#define OP_DIV                  0b100   // div     divw
#define OP_DIVU                 0b101   // divu    divuw
#define OP_REM                  0b110   // rem     remw
#define OP_REMU                 0b111   // remu    remuw

// primary is
//    MADD    (0b10000, 16)
//    MSUB    (0b10001, 17)
//    NMADD   (0b10010, 18)
//    NMSUB   (0b10011, 19)
//    OPFP    (0b10100, 20) when funct7 is
//                ADD SUB MULDIV SQRT CVTFF CVTIF CVTFI
#define ROUND_RNE               0b000
#define ROUND_RTZ               0b001
#define ROUND_RDN               0b010
#define ROUND_RUP               0b011
#define ROUND_RMM               0b100
#define ROUND_DYN               0b111

// primary is OPFP (0b10100, 20) and funct7 is FSGNJ (0b00100)
#define SGN_SGNJ                0b000
#define SGN_SGNJN               0b001
#define SGN_SGNJX               0b010

// primary is OPFP (0b10100, 20) and funct7 is MINMAX (0b00101)
#define MINMAX_MIN              0b000
#define MINMAX_MAX              0b001

// primary is OPFP (0b10100, 20) and funct7 is CMP (0b10100)
#define CMP_LE                  0b000
#define CMP_LT                  0b001
#define CMP_EQ                  0b010

// primary is OPFP (0b10100, 20) and funct7 is MVFI_CLASS (0b11110)
#define MVFI_CLASS_MVFI         0b000
#define MVFI_CLASS_CLASS        0b001

// primary is BRANCH (0b11000, 24)
#define BRANCH_BEQ              0b000
#define BRANCH_BNE              0b001
#define BRANCH_BLT              0b100
#define BRANCH_BGE              0b101
#define BRANCH_BLTU             0b110
#define BRANCH_BGEU             0b111

// primary is SYSTEM (0b11100, 28)
#define SYSTEM_PRIV             0b000
#define SYSTEM_CSRRW            0b001
#define SYSTEM_CSRRS            0b010
#define SYSTEM_CSRRC            0b011
#define SYSTEM_CSRRWI           0b101
#define SYSTEM_CSRRSI           0b110
#define SYSTEM_CSRRCI           0b111

// the funct3 field is not used for
//    AUIPC   (0b00101, 5)
//    LUI     (0b01101, 13)
//    JALR    (0b11001, 25) (or rather, it's always 0)
//    JAL     (0b11011, 27)

// and for these there are no standard instructions defined anyhow
//    CUSTOM0 (0b00010, 2)
//    CUSTOM1 (0b01010, 10)
//    CUSTOM2 (0b10110, 22)
//    CUSTOM3 (0b11110, 30)
//    rsvd21  (0b10101, 21)
//    rsvd29  (0b11101, 29)
//    X48a    (0b00111, 7)
//    X64     (0b01111, 15)
//    X48b    (0b10111, 23)
//    X80     (0b11111, 31)

/*
* quaternary opcodes in rs2 field of 32-bit instructions
*/

// primary is SYSTEM (0b11100, 28)
// funct3 is PRIV (0)
// funct7 is USER (0)
#define USER_ECALL              0b00000
#define USER_EBREAK             0b00001
#define USER_URET               0b00010

// primary is SYSTEM (0b11100, 28)
// funct3 is PRIV (0)
// funct7 is SYSTEM (0b0001000, 16)
#define SYSTEM_SRET             0b00010
#define SYSTEM_WFI              0b00101

// primary is SYSTEM (0b11100, 28)
// funct3 is PRIV (0)
// funct7 is MACHINE (0b0011000, 48)
#define MACHINE_MRET            0b00010

// primary is OPFP (0b10100, 20)
// funct7 is CVTFI or CVTIF
#define CVT_W                   0b00000
#define CVT_WU                  0b00001
#define CVT_L                   0b00010
#define CVT_LU                  0b00011

/*
* code bits for fence instruction
*/

#define FENCE_INPUT     0b1000
#define FENCE_OUTPUT    0b0100
#define FENCE_READ      0b0010
#define FENCE_WRITE     0b0001

#define FENCE_FM_NORMAL 0b0000
#define FENCE_FM_TSO    0b1000

/*
* AMO aq/rl bits in funct7
*/
#define AMO_AQ          0b0000010
#define AMO_RL          0b0000001

/*
* Opcode values for 16-bit instructions.
*/

#define OPCODE16_Q0     0b00    /* quadrant 0 */
#define OPCODE16_Q1     0b01    /* quadrant 1 */
#define OPCODE16_Q2     0b10    /* quadrant 2 */

/* quadrant 0 */
#define Q0_ADDI4SPN     0b000
#define Q0_FLD_LQ       0b001   /* RV32/RV64 FLD, RV128 LQ */
#define Q0_LW           0b010
#define Q0_FLW_LD       0b011   /* RV32 FLW, RV64/RV128 LD */
#define Q0_RESERVED     0b100
#define Q0_FSD_SQ       0b101   /* RV32/RV64 FSD, RV128 SQ */
#define Q0_SW           0b110
#define Q0_FSW_SD       0b111   /* RV32 FSW, RV64/RV128 SD */

/* quadrant 1 */
#define Q1_NOP_ADDI     0b000   /* NOP when rs1/rd == 0, ADDI otherwise */
#define Q1_JAL_ADDIW    0b001   /* RV32 JAL, RV64/RV128 ADDIW */
#define Q1_LI           0b010
#define Q1_ADDI16SP_LUI 0b011   /* ADDI16SP when rs1/rd == sp, else LUI */
#define Q1_MISC         0b100
#define Q1_J            0b101
#define Q1_BEQZ         0b110
#define Q1_BNEZ         0b111

/* funct2a values for Q1_MISC */
#define Q1MISC_SRLI     0b00
#define Q1MISC_SRAI     0b01
#define Q1MISC_ANDI     0b10
#define Q1MISC_MORE     0b11

/* funct3b values for Q1MISC_MORE */
#define Q1MORE_SUB      0b000
#define Q1MORE_XOR      0b001
#define Q1MORE_OR       0b010
#define Q1MORE_AND      0b011
#define Q1MORE_SUBW     0b100   /* RV64/RV128 */
#define Q1MORE_ADDW     0b101   /* RV64/RV128 */

/* quadrant 2 */
#define Q2_SLLI         0b000
#define Q2_FLDSP_LQSP   0b001   /* RV32/RV64 FLDSP, RV128 LQSP */
#define Q2_LWSP         0b010
#define Q2_FLWSP_LDSP   0b011   /* RV32 FLWSP, RV64/RV128 LDSP */
#define Q2_MISC         0b100
#define Q2_FSDSP_SQSP   0b101   /* RV32/RV64 FSDSP, RV128 SQSP */
#define Q2_SWSP         0b110
#define Q2_FSWSP_SDSP   0b111   /* RV32/RV64 FSWSP, RV128 SDSP */

/* funct1b values for Q2_MISC */
#define Q2MISC_JR_MV    0b0     /* JR when rs2 == 0, MV otherwise */
#define Q2MISC_EBREAK_JALR_ADD  0b1 /* EBREAK rs1==0; JALR rs2==0; else ADD */

/*
* CSR numbers
*/

// fpu
#define CSR_FFLAGS              0x001
#define CSR_FRM                 0x002
#define CSR_FCSR                0x003

// perfcounters
#define CSR_CYCLE               0xc00
#define CSR_TIME                0xc01
#define CSR_INSTRET             0xc02
#define CSR_HPMCOUNTER(n)       (0xc00+(n))     // n in 3..31
#define CSR_CYCLEH              0xc80   // RV32I
#define CSR_TIMEH               0xc81   // RV32I
#define CSR_INSTRETH            0xc82   // RV32I
#define CSR_HPMCOUNTERH(n)      (0xc80+(n))     // n in 3..31

// system
#define CSR_SSTATUS             0x100
//      CSR_SEDELEG             0x102
//      CSR_SIDELEG             0x103
#define CSR_SIE                 0x104
#define CSR_STVEC               0x105
#define CSR_SCOUNTEREN          0x106
#define CSR_SSCRATCH            0x140
#define CSR_SEPC                0x141
#define CSR_SCAUSE              0x142
#define CSR_STVAL               0x143
#define CSR_SIP                 0x144
#define CSR_SATP                0x180

// machine
#define CSR_MVENDORID           0xf11
#define CSR_MARCHID             0xf12
#define CSR_MIMPID              0xf13
#define CSR_MHARTID             0xf14
#define CSR_MSTATUS             0x300
#define CSR_MISA                0x301
#define CSR_MEDELEG             0x302
#define CSR_MIDELEG             0x303
#define CSR_MIE                 0x304
#define CSR_MTVEC               0x305
#define CSR_MCOUNTEREN          0x306
#define CSR_MSCRATCH            0x340
#define CSR_MEPC                0x341
#define CSR_MCAUSE              0x342
#define CSR_MTVAL               0x343
#define CSR_MIP                 0x344
#define CSR_PMPCFG(n)           (0x3a0 + (n))   // n in 0..3
#define CSR_PMPADDR(n)          (0x3b0 + (n))   // n in 0..15
#define CSR_MCYCLE              0xb00
#define CSR_MINSTRET            0xb02
#define CSR_MHPMCOUNTER(n)      (0xb00+(n))     // n in 3..31
#define CSR_MCYCLEH             0xb80   // RV32I
#define CSR_MINSTRETH           0xb82   // RV32I
#define CSR_MHPMCOUNTERH(n)     (0xb80+(n))     // n in 3..31
#define CSR_MCOUNTINHIBIT       0x320
#define CSR_MHPMEVENT(n)        (0x320+(n))     // n in 3..31

// debug
#define CSR_TSELECT             0x7a0
#define CSR_TDATA1              0x7a1
#define CSR_TDATA2              0x7a2
#define CSR_TDATA3              0x7a3
#define CSR_DCSR                0x7b0
#define CSR_DPC                 0x7b1
#define CSR_DSCRATCH0           0x7b2
#define CSR_DSCRATCH1           0x7b3


#endif /* _RISCV_INSN_H_ */