OpenCores
URL https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [cpu_fnc_plugin/] [riscv-ext-c.cpp] - Rev 5

Compare with Previous | Blame | View Log

/**
 * @file
 * @copyright  Copyright 2017 GNSS Sensor Ltd. All right reserved.
 * @author     Sergey Khabarov - sergeykhbr@gmail.com
 * @brief      RISC-V extension-C (Comporessed Instructions).
 */
 
#include "api_utils.h"
#include "riscv-isa.h"
#include "cpu_riscv_func.h"
 
namespace debugger {
 
/** 
 * @brief Add register to register
 *
 * C.ADD adds the values in registers rd and rs2 and writes the result to
 * register rd. C.ADD expands into add rd, rd, rs2.
 */
class C_ADD : public RiscvInstruction16 {
public:
    C_ADD(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ADD", "????????????????1001??????????10") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload)
                && u.bits.rdrs1 && u.bits.rs2;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CR_type u;
        u.value = payload->buf16[0];
        if (u.bits.rdrs1) {
            R[u.bits.rdrs1] += R[u.bits.rs2];
        }
        return 2;
    }
};
 
/** 
 * @brief Add immediate
 *
 * C.ADDI adds the non-zero sign-extended 6-bit immediate to the value in
 * register rd then writes the result to rd. C.ADDI expands into
 * addi rd, rd, nzimm[5:0].
 */
class C_ADDI : public RiscvInstruction16 {
public:
    C_ADDI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ADDI", "????????????????000???????????01") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CI_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = u.bits.imm;
        if (u.bits.imm6) {
            imm |= EXT_SIGN_6;
        }
        R[u.bits.rdrs] = R[u.bits.rdrs] + imm;
        return 2;
    }
};
 
/** 
 * @brief Stack-relative Add immediate
 *
 * C.ADDI16SP shares the opcode with C.LUI, but has a destination field of x2.
 * C.ADDI16SP adds the non-zero sign-extended 6-bit immediate to the value in
 * the stack pointer (sp=x2), where the immediate is scaled to represent
 * multiples of 16 in the range (-512,496). C.ADDI16SP is used to adjust the
 * stack pointer in procedure prologues and epilogues. It expands into
 * addi x2, x2, nzimm[9:4].
 */
class C_ADDI16SP : public RiscvInstruction16 {
public:
    C_ADDI16SP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ADDI16SP", "????????????????011?00010?????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CI_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = (u.spbits.imm8_7 << 3) | (u.spbits.imm6 << 2)
                    | (u.spbits.imm5 << 1) | u.spbits.imm4;
        if (u.spbits.imm9) {
            imm |= EXT_SIGN_6;
        }
        imm <<= 4;
        R[Reg_sp] = R[Reg_sp] + imm;
        return 2;
    }
};
 
/** 
 * @brief Stack-relative Add wide immediate
 *
 * C.ADDI4SPN is a CIW-format RV32C/RV64C-only instruction that adds a
 * zero-extended non-zero immediate, scaled by 4, to the stack pointer, x2,
 * and writes the result to rd0. This instruction is used to generate
 * pointers to stack-allocated variables, and expands to
 * addi rd0, x2, zimm[9:2].
 */
class C_ADDI4SPN : public RiscvInstruction16 {
public:
    C_ADDI4SPN(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ADDI4SPN", "????????????????000???????????00") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CIW_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = (u.bits.imm9_6 << 4) | (u.bits.imm5_4 << 2)
                    | (u.bits.imm3 << 1) | u.bits.imm2;
        imm <<= 2;
        R[8 + u.bits.rd] = R[Reg_sp] + imm;
        return 2;
    }
};
 
/** 
 * @brief Add immediate with sign extending
 *
 * C.ADDIW is an RV64C/RV128C-only instruction that performs the same
 * computation but produces a 32-bit result, then sign-extends result
 * to 64 bits. C.ADDIW expands into addiw rd, rd, imm[5:0]. The immediate
 * can be zero for C.ADDIW, where this corresponds to sext.w rd.
 */
class C_ADDIW : public RiscvInstruction16 {
public:
    C_ADDIW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ADDIW", "????????????????001???????????01") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CI_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = u.bits.imm;
        if (u.bits.imm6) {
            imm |= EXT_SIGN_6;
        }
        R[u.bits.rdrs] = (R[u.bits.rdrs] + imm) & 0xFFFFFFFFLL;
        if (R[u.bits.rdrs] & (1LL << 31)) {
            R[u.bits.rdrs] |= EXT_SIGN_32;
        }
        return 2;
    }
};
 
/**
 * @brief C_ADDW
 *
 * C.ADDW is an RV64C/RV128C-only instruction that adds the values in registers
 * rd' and rs2', then sign-extends the lower 32 bits of the sum before writing
 * the result to register rd'. C.ADDW expands into addw rd', rd', rs2'.
 */
class C_ADDW : public RiscvInstruction16 {
public:
    C_ADDW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ADDW", "????????????????100111???01???01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CS_type u;
        u.value = payload->buf16[0];
        R[8 + u.bits.rs1] += R[8 + u.bits.rs2];
        R[8 + u.bits.rs1] &= 0xFFFFFFFFLL;
 
        if (R[8 + u.bits.rs1] & (1LL << 31)) {
            R[8 + u.bits.rs1] |= EXT_SIGN_32;
        }
        return 2;
    }
};
 
 
/**
 * @brief C_AND
 *
 * C.AND computes the bitwise AND of the values in registers rd' and rs2', then
 * writes the result to register rd'. C.AND expands into and rd', rd', rs2'.
 */
class C_AND : public RiscvInstruction16 {
public:
    C_AND(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_AND", "????????????????100011???11???01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CS_type u;
        u.value = payload->buf16[0];
        R[8 + u.bits.rs1] &= R[8 + u.bits.rs2];
        return 2;
    }
};
 
/** 
 * @brief AND with sign-extended immediate
 *
 * C.ANDI is a CB-format instruction that computes the bitwise AND of the
 * value in register rd' and the sign-extended 6-bit immediate, then writes
 * the result to rd'. C.ANDI expands to andi rd', rd', imm[5:0].
 */
class C_ANDI : public RiscvInstruction16 {
public:
    C_ANDI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_ANDI", "????????????????100?10????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CB_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = (u.bits.off7_6 << 3) | (u.bits.off2_1 << 1)  | u.bits.off5;
        if (u.bits.off8) {
            imm |= EXT_SIGN_5;
        }
        R[8 + u.bits.rs1] &= imm;
        return 2;
    }
};
 
/**
 * @brief Branch if registers zero
 *
 * C.BEQZ performs conditional control transfers. The offset is sign-extended
 * and added to the pc to form the branch target address. It can therefore
 * target a 256B range. C.BEQZ takes the branch if the value in register rs1'
 *  is zero. It expands to beq rs1', x0, offset[8:1].
 */
class C_BEQZ : public RiscvInstruction16 {
public:
    C_BEQZ(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_BEQZ", "????????????????110???????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CB_type u;
        u.value = payload->buf32[0];
 
        if (R[8 + u.bits.rs1] == 0) {
            uint64_t imm = (u.bits.off7_6 << 5) | (u.bits.off5 << 4)
                    | (u.bits.off4_3 << 2) | u.bits.off2_1;
            imm <<= 1;
            if (u.bits.off8) {
                imm |= EXT_SIGN_9;
            }
            icpu_->setBranch(icpu_->getPC() + imm);
        }
        return 2;
    }
};
 
 
/**
 * @brief Branch if registers not zero
 *
 * C.BNEZ is defined analogously, but it takes the branch if rs1' contains a 
 * nonzero value. It expands to bne rs1', x0, offset[8:1].
 */
class C_BNEZ : public RiscvInstruction16 {
public:
    C_BNEZ(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_BNEZ", "????????????????111???????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CB_type u;
        u.value = payload->buf32[0];
 
        if (R[8 + u.bits.rs1]) {
            uint64_t imm = (u.bits.off7_6 << 5) | (u.bits.off5 << 4)
                    | (u.bits.off4_3 << 2) | u.bits.off2_1;
            imm <<= 1;
            if (u.bits.off8) {
                imm |= EXT_SIGN_9;
            }
            icpu_->setBranch(icpu_->getPC() + imm);
        }
        return 2;
    }
};
 
/**
 * @brief C.EBREAK (breakpoint instruction)
 *
 * The C.EBREAK instruction is used by debuggers to cause control to be
 * transferred back to a debug-ging environment.
 */
class C_EBREAK : public RiscvInstruction16 {
public:
    C_EBREAK(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_EBREAK", "????????????????1001000000000010") {}
 
    virtual int exec(Reg64Type *payload) {
        icpu_->raiseSignal(EXCEPTION_Breakpoint);
        return 2;
    }
};
 
 
/**
 * @brief Unconditional jump
 *
 * C.J performs an unconditional control transfer. The offset is sign-extended
 *  and added to the pc to form the jump target address. C.J can therefore
 * target a 2 KiB range. C.J expands to jal x0, offset[11:1].
 */
class C_J : public RiscvInstruction16 {
public:
    C_J(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_J", "????????????????101???????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CJ_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.bits.off10 << 9) | (u.bits.off9_8 << 7)
                     | (u.bits.off7 << 6) | (u.bits.off6 << 5)
                     | (u.bits.off5 << 4) | (u.bits.off4 << 3)
                     | u.bits.off3_1;
        off <<= 1;
        if (u.bits.off11) {
            off |= EXT_SIGN_11;
        }
        icpu_->setBranch(icpu_->getPC() + off);
        return 2;
    }
};
 
#ifdef RV32C_ONLY  // conflict with C_ADDIW
/**
 * @brief Unconditional jump with write to ra
 *
 * C.JAL is an RV32C-only instruction that performs the same operation as C.J,
 * but additionally writes the address of the instruction following the jump
 * (pc+2) to the link register, x1. C.JAL expands to jal x1, offset[11:1].
 */
class C_JAL : public RiscvInstruction16 {
public:
    C_JAL(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_JAL", "????????????????001???????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CJ_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.bits.off10 << 9) | (u.bits.off9_8 << 7)
                     | (u.bits.off7 << 6) | (u.bits.off6 << 5)
                     | (u.bits.off5 << 4) | (u.bits.off4 << 3)
                     | u.bits.off3_1;
        off <<= 1;
        if (u.bits.off11) {
            off |= EXT_SIGN_11;
        }
        R[Reg_ra] = icpu_->getPC() + 2;
        icpu_->setBranch(icpu_->getPC() + off);
        icpu_->pushStackTrace();
        return 2;
    }
};
#endif
 
/**
 * @brief Unconditional jump with write to ra
 *
 * C.JALR (jump and link register) performs the same operation as C.JR, but
 * additionally writes the address of the instruction following the jump (pc+2)
 * to the link register, x1. C.JALR expands to jalr x1, rs1, 0.
 */
class C_JALR : public RiscvInstruction16 {
public:
    C_JALR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_JALR", "????????????????1001?????0000010") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CR_type u;
        u.value = payload->buf16[0];
        R[Reg_ra] = icpu_->getPC() + 2;
        icpu_->setBranch(R[u.bits.rdrs1]);
        icpu_->pushStackTrace();
        return 2;
    }
};
 
/**
 * @brief Unconditional jump
 *
 * C.JR (jump register) performs an unconditional control transfer to the
 * address in register rs1. C.JR expands to jalr x0, rs1, 0.
 */
class C_JR : public RiscvInstruction16 {
public:
    C_JR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_JR", "????????????????1000?????0000010") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CR_type u;
        u.value = payload->buf16[0];
        icpu_->setBranch(R[u.bits.rdrs1]);
        if (u.bits.rdrs1 == Reg_ra) {
            icpu_->popStackTrace();
        }
        return 2;
    }
};
 
/**
 * @brief LOAD instructions with sign extending.
 *
 * C.LD is an RV64C/RV128C-only instruction that loads a 64-bit value from
 * memory into register rd0. It computes an eective address by adding the
 * zero-extended oset, scaled by 8, to the base address in register rs10.
 * It expands to ld rd0, offset[7:3](rs10).
 */ 
class C_LD : public RiscvInstruction16 {
public:
    C_LD(CpuRiver_Functional *icpu) :
        RiscvInstruction16(icpu, "C_LD", "????????????????011???????????00") {}
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CL_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.bits.imm27 << 4) | (u.bits.imm6 << 3)
                     | u.bits.imm5_3;
        off <<= 3;
        trans.action = MemAction_Read;
        trans.addr = R[8 + u.bits.rs1] + off;
        trans.xsize = 8;
        if (trans.addr & 0x7) {
            trans.rpayload.b64[0] = 0;
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        R[8 + u.bits.rd] = trans.rpayload.b64[0];
        return 2;
    }
};
 
/**
 * @brief LOAD stack-relative dword.
 *
 * C.LDSP is an RV64C/RV128C-only instruction that loads a 64-bit value from
 * memory into register rd. It computes its eective address by adding the
 * zero-extended oset, scaled by 8, to the stack pointer, x2.
 * It expands to ld rd, offset[8:3](x2).
 */ 
class C_LDSP : public RiscvInstruction16 {
public:
    C_LDSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_LDSP", "????????????????011???????????10") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CI_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.ldspbits.off8_6 << 3) | (u.ldspbits.off5 << 2)
                     | u.ldspbits.off4_3;
        off <<= 3;
        trans.action = MemAction_Read;
        trans.addr = R[Reg_sp] + off;
        trans.xsize = 8;
        if (trans.addr & 0x7) {
            trans.rpayload.b64[0] = 0;
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        R[u.ldspbits.rd] = trans.rpayload.b64[0];
        return 2;
    }
};
 
/** 
 * @brief Constant generation
 *
 * C.LI loads the sign-extended 6-bit immediate, imm, into register rd. C.LI is
 * only valid when rd /= x0. C.LI expands into addi rd, x0, imm[5:0].
 */
class C_LI : public RiscvInstruction16 {
public:
    C_LI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_LI", "????????????????010???????????01") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CI_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = u.bits.imm;
        if (u.bits.imm6) {
            imm |= EXT_SIGN_6;
        }
        R[u.bits.rdrs] = imm;
        return 2;
    }
};
 
/**
 * @brief LOAD instructions with sign extending.
 *
 * C.LW loads a 32-bit value from memory into register rd0. It computes an
 * effective address by adding the zero-extended offset, scaled by 4, to the
 * base address in register rs10. It expands to lw rd0, offset[6:2](rs10).
 */ 
class C_LW : public RiscvInstruction16 {
public:
    C_LW(CpuRiver_Functional *icpu) :
        RiscvInstruction16(icpu, "C_LW", "????????????????010???????????00") {}
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CL_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.bits.imm6 << 4) | (u.bits.imm5_3 << 1) | u.bits.imm27;
        off <<= 2;
        trans.action = MemAction_Read;
        trans.addr = R[8 + u.bits.rs1] + off;
        trans.xsize = 4;
        trans.rpayload.b64[0] = 0;
        if (trans.addr & 0x3) {
            trans.rpayload.b64[0] = 0;
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        R[8 + u.bits.rd] = trans.rpayload.b32[0];
        if (R[8 + u.bits.rd] & (1LL << 31)) {
            R[8 + u.bits.rd] |= EXT_SIGN_32;
        }
        return 2;
    }
};
 
/**
 * @brief LOAD stack-relative word.
 *
 * C.LWSP loads a 32-bit value from memory into register rd. It computes
 * an eective address by adding the zero-extended oset, scaled by 4, to the
 * stack pointer, x2. It expands to lw rd, offset[7:2](x2).
 */ 
class C_LWSP : public RiscvInstruction16 {
public:
    C_LWSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_LWSP", "????????????????010???????????10") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CI_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.lwspbits.off7_6 << 4) | (u.lwspbits.off5 << 3)
                     | u.lwspbits.off4_2;
        off <<= 2;
        trans.action = MemAction_Read;
        trans.addr = R[Reg_sp] + off;
        trans.xsize = 4;
        if (trans.addr & 0x3) {
            trans.rpayload.b64[0] = 0;
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        R[u.lwspbits.rd] = trans.rpayload.b32[0];
        if (R[u.lwspbits.rd] & (1LL << 31)) {
            R[u.lwspbits.rd] |= EXT_SIGN_32;
        }
        return 2;
    }
};
 
/** 
 * @brief Constant generation
 *
 * C.LUI loads the non-zero 6-bit immediate eld into bits 17-12 of the
 * destination register, clears the bottom 12 bits, and sign-extends
 * bit 17 into all higher bits of the destination. C.LUI is only
 * valid when rd /= {x0; x2}, and when the immediate is not equal to zero.
 * C.LUI expands into lui rd, nzuimm[17:12].
 */
class C_LUI : public RiscvInstruction16 {
public:
    C_LUI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_LUI", "????????????????011???????????01") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1
            && u.bits.rdrs1 != Reg_sp;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CI_type u;
        u.value = payload->buf16[0];
 
        uint64_t imm = u.bits.imm;
        if (u.bits.imm6) {
            imm |= EXT_SIGN_6;
        }
        imm <<= 12;
        R[u.bits.rdrs] = imm;
        return 2;
    }
};
 
/**
 * @brief Move register to register
 *
 * C.MV copies the value in register rs2 into register rd. C.MV expands
 * into add rd, x0, rs2.
 */
class C_MV : public RiscvInstruction16 {
public:
    C_MV(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_MV", "????????????????1000??????????10") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload)
            && u.bits.rs2 && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CR_type u;
        u.value = payload->buf16[0];
        R[u.bits.rdrs1] = R[u.bits.rs2];
        return 2;
    }
};
 
/** 
 * @brief empty cycle
 */
class C_NOP : public RiscvInstruction16 {
public:
    C_NOP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_NOP", "????????????????0000000000000001") {}
 
    virtual bool parse(uint32_t *payload) {
        return RiscvInstruction::parse(payload);
    }
 
    virtual int exec(Reg64Type *payload) {
        return 2;
    }
};
 
 
/**
 * @brief C_OR
 *
 * C.OR computes the bitwise OR of the values in registers rd' and rs2', then
 * writes the result to register rd'. C.OR expands into or rd', rd', rs2'.
 */
class C_OR : public RiscvInstruction16 {
public:
    C_OR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_OR", "????????????????100011???10???01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CS_type u;
        u.value = payload->buf16[0];
        R[8 + u.bits.rs1] |= R[8 + u.bits.rs2];
        return 2;
    }
};
 
/** 
 * @brief Store 64-bits data
 *
 * C.SD is an RV64C/RV128C-only instruction that stores a 64-bit value in
 * register rs20 to memory. It computes an eective address by adding the
 * zero-extended oset, scaled by 8, to the base address in register rs10. It
 * expands to sd rs20, offset[7:3](rs10).
 */
class C_SD : public RiscvInstruction16 {
public:
    C_SD(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SD", "????????????????111???????????00") {}
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CS_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.bits.imm27 << 4) | (u.bits.imm6 << 3) | u.bits.imm5_3;
        off <<= 3;
        trans.action = MemAction_Write;
        trans.xsize = 8;
        trans.wstrb = (1 << trans.xsize) - 1;
        trans.addr = R[8 + u.bits.rs1] + off;
        trans.wpayload.b64[0] = R[8 + u.bits.rs2];
        if (trans.addr & 0x7) {
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        return 2;
    }
};
 
/** 
 * @brief Stack-relative Store 64-bits data
 *
 * C.SDSP is an RV64C/RV128C-only instruction that stores a 64-bit value
 * in register rs2 to memory. It computes an eective address by adding the
 * zero-extended oset, scaled by 8, to the stack pointer, x2. It expands
 * to sd rs2, offset[8:3](x2).
 */
class C_SDSP : public RiscvInstruction16 {
public:
    C_SDSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SDSP", "????????????????111???????????10") {}
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CSS_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.dbits.imm8_6 << 3) | u.dbits.imm5_3;
        off <<= 3;
        trans.action = MemAction_Write;
        trans.xsize = 8;
        trans.wstrb = (1 << trans.xsize) - 1;
        trans.addr = R[Reg_sp] + off;
        trans.wpayload.b64[0] = R[u.dbits.rs2];
        if (trans.addr & 0x7) {
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        return 2;
    }
};
 
/**
 * @brief Logical shift left
 *
 * C.SLLI is a CI-format instruction that performs a logical left shift
 * of the value in register rd then writes the result to rd. The shift amount
 * is encoded in the shamt eld, where shamt[5] must be zero for RV32C.
 * For RV32C and RV64C, the shift amount must be non-zero. For RV128C, a shift
 * amount of zero is used to encode a shift of 64. C.SLLI expands into 
 * slli rd, rd, shamt[5:0], except for RV128C with shamt=0, which expands
 * to slli rd, rd, 64.
 */
class C_SLLI : public RiscvInstruction16 {
public:
    C_SLLI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SLLI", "????????????????000???????????10") {}
 
    virtual bool parse(uint32_t *payload) {
        ISA_CR_type u;
        u.value = static_cast<uint16_t>(payload[0]);
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
    }
 
    virtual int exec(Reg64Type *payload) {
        ISA_CB_type u;
        u.value = payload->buf16[0];
        uint32_t shamt = (u.shbits.shamt5 << 5) | u.shbits.shamt;
        uint32_t idx = (u.shbits.funct2 << 3) | u.shbits.rd;
        R[idx] = R[idx] << shamt;
        return 2;
    }
};
 
/** 
 * @brief Arith shift right
 *
 * C.SRAI is defined analogously to C.SRLI, but instead performs an arithmetic
 * right shift. C.SRAI expands to srai rd', rd', shamt[5:0].
 */
class C_SRAI : public RiscvInstruction16 {
public:
    C_SRAI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SRAI", "????????????????100?01????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CB_type u;
        u.value = payload->buf16[0];
        uint32_t shamt = (u.shbits.shamt5 << 5) | u.shbits.shamt;
        R[8 + u.shbits.rd] = static_cast<int64_t>(R[8 + u.shbits.rd]) >> shamt;
        return 2;
    }
};
 
/**
 * @brief Logical shift right
 *
 * C.SRLI is a CB-format instruction that performs a logical right shift of
 * the value in register rd' then writes the result to rd'. The shift amount
 * is encoded in the shamt field, where shamt[5] must be zero for RV32C.
 * For RV32C and RV64C, the shift amount must be non-zero. For RV128C, a shift
 * amount of zero is used to encode a shift of 64. Furthermore, the shift
 * amount is sign-extended for RV128C, and so the legal shift amounts are
 * 1-31, 64, and 96-127. C.SRLI expands into srli rd0, rd0, shamt[5:0],
 * except for RV128C with shamt=0, which expands to srli rd0, rd0, 64.
 */
class C_SRLI : public RiscvInstruction16 {
public:
    C_SRLI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SRLI", "????????????????100?00????????01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CB_type u;
        u.value = payload->buf16[0];
        uint32_t shamt = (u.shbits.shamt5 << 5) | u.shbits.shamt;
        R[8 + u.shbits.rd] = R[8 + u.shbits.rd] >> shamt;
        return 2;
    }
};
 
/**
 * @brief C_SUB
 *
 * C.SUB subtracts the value in register rs2' from the value in register rd',
 * then writes the result to register rd'. C.SUB expands into
 * sub rd', rd', rs2'.
 */
class C_SUB : public RiscvInstruction16 {
public:
    C_SUB(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SUB", "????????????????100011???00???01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CS_type u;
        u.value = payload->buf16[0];
        R[8 + u.bits.rs1] -= R[8 + u.bits.rs2];
        return 2;
    }
};
 
/**
 * @brief C_SUBW
 *
 * C.SUBW is an RV64C/RV128C-only instruction that subtracts the value in
 * register rs2' from the value in register rd', then sign-extends the lower
 * 32 bits of the difference before writing the result to register rd'.
 * C.SUBW expands into subw rd', rd', rs2'.
 */
class C_SUBW : public RiscvInstruction16 {
public:
    C_SUBW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SUBW", "????????????????100111???00???01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CS_type u;
        u.value = payload->buf16[0];
        R[8 + u.bits.rs1] -= R[8 + u.bits.rs2];
        R[8 + u.bits.rs1] &= 0xFFFFFFFFLL;
 
        if (R[8 + u.bits.rs1] & (1LL << 31)) {
            R[8 + u.bits.rs1] |= EXT_SIGN_32;
        }
        return 2;
    }
};
 
/** 
 * @brief Store word
 *
 * C.SW stores a 32-bit value in register rs20 to memory. It computes an
 * effective address by adding the zero-extended oset, scaled by 4, to the
 * base address in register rs10. It expands to sw rs20, offset[6:2](rs10).
 */
class C_SW : public RiscvInstruction16 {
public:
    C_SW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SW", "????????????????110???????????00") {}
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CS_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.bits.imm6 << 4) | (u.bits.imm5_3 << 1) | u.bits.imm27;
        off <<= 2;
        trans.action = MemAction_Write;
        trans.xsize = 4;
        trans.wstrb = (1 << trans.xsize) - 1;
        trans.addr = R[8 + u.bits.rs1] + off;
        trans.wpayload.b64[0] = R[8 + u.bits.rs2];
        if (trans.addr & 0x3) {
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        return 2;
    }
};
 
/** 
 * @brief Stack-relative Store word
 *
 * C.SWSP stores a 32-bit value in register rs2 to memory. It computes an
 * effective address by adding the zero-extended oset, scaled by 4, to the
 * stack pointer, x2. It expands to sw rs2, offset[7:2](x2).
 */
class C_SWSP : public RiscvInstruction16 {
public:
    C_SWSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_SWSP", "????????????????110???????????10") {}
 
    virtual int exec(Reg64Type *payload) {
        Axi4TransactionType trans;
        ISA_CSS_type u;
        u.value = payload->buf16[0];
        uint64_t off = (u.wbits.imm7_6 << 4) | u.wbits.imm5_2;
        off <<= 2;
        trans.action = MemAction_Write;
        trans.xsize = 4;
        trans.wstrb = (1 << trans.xsize) - 1;
        trans.addr = R[Reg_sp] + off;
        trans.wpayload.b64[0] = R[u.wbits.rs2];
        if (trans.addr & 0x3) {
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
        } else {
            icpu_->dma_memop(&trans);
        }
        return 2;
    }
};
 
/**
 * @brief C_XOR
 *
 * C.XOR computes the bitwise XOR of the values in registers rd' and rs2', then
 * writes the result to register rd'. C.XOR expands into xor rd', rd', rs2'.
 */
class C_XOR : public RiscvInstruction16 {
public:
    C_XOR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
        "C_XOR", "????????????????100011???01???01") {}
 
    virtual int exec(Reg64Type *payload) {
        ISA_CS_type u;
        u.value = payload->buf16[0];
        R[8 + u.bits.rs1] ^= R[8 + u.bits.rs2];
        return 2;
    }
};
 
 
void CpuRiver_Functional::addIsaExtensionC() {
    addSupportedInstruction(new C_ADD(this));
    addSupportedInstruction(new C_ADDI(this));
    addSupportedInstruction(new C_ADDI16SP(this));
    addSupportedInstruction(new C_ADDI4SPN(this));
    addSupportedInstruction(new C_ADDIW(this));
    addSupportedInstruction(new C_ADDW(this));
    addSupportedInstruction(new C_AND(this));
    addSupportedInstruction(new C_ANDI(this));
    addSupportedInstruction(new C_BEQZ(this));
    addSupportedInstruction(new C_BNEZ(this));
    addSupportedInstruction(new C_EBREAK(this));
    addSupportedInstruction(new C_J(this));
#ifdef RV32C_ONLY
    addSupportedInstruction(new C_JAL(this));
#endif
    addSupportedInstruction(new C_JALR(this));
    addSupportedInstruction(new C_JR(this));
    addSupportedInstruction(new C_LD(this));
    addSupportedInstruction(new C_LDSP(this));
    addSupportedInstruction(new C_LWSP(this));
    addSupportedInstruction(new C_LI(this));
    addSupportedInstruction(new C_LUI(this));
    addSupportedInstruction(new C_LW(this));
    addSupportedInstruction(new C_MV(this));
    addSupportedInstruction(new C_NOP(this));
    addSupportedInstruction(new C_OR(this));
    addSupportedInstruction(new C_SD(this));
    addSupportedInstruction(new C_SDSP(this));
    addSupportedInstruction(new C_SLLI(this));
    addSupportedInstruction(new C_SRAI(this));
    addSupportedInstruction(new C_SRLI(this));
    addSupportedInstruction(new C_SUB(this));
    addSupportedInstruction(new C_SUBW(this));
    addSupportedInstruction(new C_SW(this));
    addSupportedInstruction(new C_SWSP(this));
    addSupportedInstruction(new C_XOR(this));
 
    uint64_t isa = portCSR_.read(CSR_misa).val;
    portCSR_.write(CSR_misa, isa | (1LL << ('C' - 'C')));
}
 
}  // namespace debugger
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.