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

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [cpu_arm_plugin/] [arm7tdmi.cpp] - Rev 5

Compare with Previous | Blame | View Log

/*
 *  Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
 
#include "api_utils.h"
#include "arm-isa.h"
#include "cpu_arm7_func.h"
 
namespace debugger {
 
static const uint64_t PREFETCH_OFFSET[InstrModes_Total] = {
    8,
    4
};
 
/** Data processing default behaviour can be re-implemeted: */
int ArmDataProcessingInstruction::exec_checked(Reg64Type *payload) {
    DataProcessingType u;
    u.value = payload->buf32[0];
    uint32_t A = static_cast<uint32_t>(R[u.reg_bits.rn]);
    uint32_t M;
    uint32_t Res;
    if (u.imm_bits.I) {
        M = imm12(u.imm_bits);
    } else {
        M = static_cast<uint32_t>(R[u.reg_bits.rm]);
        M = shift12(u.reg_bits, M, R[u.reg_bits.shift >> 1]);
    }
    if (do_operation(A, M, &Res)) {
        R[u.reg_bits.rd] = Res;
    }
    if (is_flags_changed(u)) {
        set_flags(A, M, Res);
    }
    return 4;
}
 
bool ArmDataProcessingInstruction::is_flags_changed(DataProcessingType u) {
    return u.reg_bits.S && u.reg_bits.rd != Reg_pc;
}
 
void ArmDataProcessingInstruction::set_flags(uint32_t A, uint32_t M,
                                             uint32_t Res) {
    icpu_->setC(0);
    icpu_->setZ(Res == 0);
    icpu_->setN(Res >> 31);
}
 
/** @brief Subtruct specific instruction set
 
 Specific flags computation with subtraction
 */
class ArmSubInstruction : public ArmDataProcessingInstruction {
 public:
    ArmSubInstruction(CpuCortex_Functional *icpu, const char *name,
        const char *bits) : ArmDataProcessingInstruction(icpu, name, bits) {}
 protected:
    virtual bool is_inverted() = 0;
    virtual bool with_carry() = 0;
    virtual EOperationResult op_result() = 0;
 
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        if (!is_inverted()) {
            *pRes = A - M;
        } else {
            *pRes = M - A;
        }
        if (with_carry()) {
            *pRes += (icpu_->getC() - 1);
        }
        return op_result();
    }
 
    virtual void set_flags(uint32_t A, uint32_t M, uint32_t Res) {
        if (is_inverted()) {
            uint32_t t1 = A;
            A = M;
            M = t1;
        }
        uint32_t C = !(((~A & M) | (M & Res) | (Res & ~A)) >> 31);
        uint32_t V = ((A & ~M & ~Res) | (~A & M & Res)) >> 31;
        icpu_->setC(C);
        icpu_->setV(V);
        icpu_->setZ(Res == 0);
        icpu_->setN(Res >> 31);
    }
};
 
/** @brief addictive specific instruction set
 
 Specific flags computation with addition
 */
class ArmAddInstruction : public ArmDataProcessingInstruction {
 public:
    ArmAddInstruction(CpuCortex_Functional *icpu, const char *name,
        const char *bits) : ArmDataProcessingInstruction(icpu, name, bits) {}
 protected:
    virtual EOperationResult op_result() = 0;
    virtual bool with_carry() = 0;
 
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A + M;
        if (with_carry()) {
            *pRes += icpu_->getC();
        }
        return op_result();
    }
 
    virtual void set_flags(uint32_t A, uint32_t M, uint32_t Res) {
        uint32_t C = ((A & M) | (M & ~Res) | (A & ~Res)) >> 31;
        uint32_t V = ((A & M & ~Res) | (~A & ~M & Res)) >> 31;
        icpu_->setC(C);
        icpu_->setV(V);
        icpu_->setZ(Res == 0);
        icpu_->setN(Res >> 31);
    }
};
 
/** Single memory transfer: LDR, STR
*/
class SingleDataTransferInstruction : public ArmInstruction {
 public:
    SingleDataTransferInstruction(CpuCortex_Functional *icpu, const char *name,
        const char *bits) : ArmInstruction(icpu, name, bits) {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SingleDataTransferType u;
        u.value = payload->buf32[0];
        uint32_t opsz[2] = {4, 1};
        uint64_t off = R[u.imm_bits.rn];
 
        if (u.imm_bits.rn == Reg_pc) {
            off += PREFETCH_OFFSET[icpu_->getInstrMode()];
            if (u.imm_bits.rd == Reg_pc && !u.imm_bits.I 
                && (u.imm_bits.imm & 0x1)) {
                // DSB, ISB
                return 4;
            }
        }
 
        if (u.imm_bits.P) {
            off += get_increment(u);
            if (u.imm_bits.W) {
                R[u.imm_bits.rn] = off;
            }
        }
 
        trans_.addr = off;
        trans_.wstrb = 0;
        trans_.xsize = opsz[u.imm_bits.B];
        if (u.imm_bits.L) {
            trans_.action = MemAction_Read;
            trans_.rpayload.b64[0] = 0;
        } else {
            trans_.action = MemAction_Write;
            trans_.wstrb = (1 << trans_.xsize) - 1;
            trans_.wpayload.b64[0] = R[u.imm_bits.rd];
        }
        icpu_->dma_memop(&trans_);
 
        if (!u.imm_bits.P) {
            off += get_increment(u);
            R[u.imm_bits.rn] = off;
            if (u.imm_bits.W) {
            /** In the case of post-indexed addressing, the write back bit is
                redundant and must be set to zero, since the old base value can be
                retained by setting the offset to zero. Therefore post-indexed
                data transfers always write back the modified base. The only use of
                the W bit in a post-indexed data transfer is in privileged mode
                code, where setting the W bit forces non-privileged mode for the
                transfer, allowing the operating system to generate a user address
                in a system where the memory management hardware makes suitable
                use of this hardware.
            */
                RISCV_error("Post-index LDR,STR with W=1", 0);
            }
        }
        if (u.imm_bits.L) {
            R[u.imm_bits.rd] = trans_.rpayload.b32[0];
            if (u.imm_bits.rd == Reg_pc) {
                icpu_->setBranch(R[u.imm_bits.rd]);
            }
        }
        return 4;
    }
 
 protected:
    virtual uint64_t get_increment(SingleDataTransferType u) {
        uint64_t incr;
        if (!u.imm_bits.I) {
            incr = u.imm_bits.imm;
        } else {
            /**
             @warning The register specified shift amounts
                      are not available in this instruction class.
             */
            DataProcessingType u2;
            u2.value = u.value;
            incr = shift12(u2.reg_bits,
                           static_cast<uint32_t>(R[u.reg_bits.rm]),
                           0);  // !! not available
        }
        if (!u.reg_bits.U) {
            incr = (~incr) + 1;
        }
        return incr;
    }
};
 
/** Block memory transfer: LDM, STM
*/
class BlockDataTransferInstruction : public ArmInstruction {
 public:
    BlockDataTransferInstruction(CpuCortex_Functional *icpu, const char *name,
        const char *bits) : ArmInstruction(icpu, name, bits) {}
 
    virtual int exec_checked(Reg64Type *payload) {
        BlockDataTransferType u;
        uint64_t adrincr[2] = {static_cast<uint64_t>(-4), 4};
        u.value = payload->buf32[0];
        uint32_t R15 = (u.bits.reglist >> 15) & 0x1;
        int ridx;
        // @todo Mode switching depending R15 value!!!!
 
        trans_.addr = R[u.bits.rn];
        trans_.xsize = 4;
        trans_.wstrb = 0;
        for (int i = 0; i < 16; i++) {
            if (u.bits.L) {
                ridx = 15 - i;
            } else {
                ridx = i;
            }
            if ((u.bits.reglist & (0x1 << ridx)) == 0) {
                continue;
            }
            if (u.bits.L) {
                trans_.action = MemAction_Read;
                trans_.rpayload.b64[0] = 0;
            } else {
                trans_.action = MemAction_Write;
                trans_.wstrb = (1 << trans_.xsize) - 1;
                trans_.wpayload.b64[0] = R[ridx];
            }
            if (u.bits.P) {
                trans_.addr += adrincr[u.bits.U];
                if (u.bits.W) {
                    R[u.bits.rn] = trans_.addr;
                }
            }
 
            icpu_->dma_memop(&trans_);
 
            if (!u.bits.P) {
                trans_.addr += adrincr[u.bits.U];
                R[u.bits.rn] = trans_.addr;
            }
 
            if (u.bits.L) {
                R[ridx] = trans_.rpayload.b32[0];
                if (ridx == Reg_pc) {
                    icpu_->setBranch(R[ridx]);
                }
            }
        }
 
        if (!u.bits.P) {
            if (u.bits.W) {
                RISCV_error("Post-index LDM,STM with W=1", 0);
            }
        }
        if (u.bits.S) {
            // TODO: force user mode
        }
        return 4;
    }
};
 
 
/** Halfword and Signed Data Transfer: LDRH/STRH/LDRSB/LDRSH
*/
class HWordSignedDataTransferInstruction : public ArmInstruction {
 public:
    HWordSignedDataTransferInstruction(CpuCortex_Functional *icpu,
        const char *name, const char *bits)
        : ArmInstruction(icpu, name, bits) {}
 
    virtual int exec_checked(Reg64Type *payload) {
        HWordSignedDataTransferType u;
        u.value = payload->buf32[0];
        uint32_t opsz[2] = {1, 2};
        uint64_t off = R[u.bits.rn];
        if (u.bits.rn == Reg_pc) {
            off += PREFETCH_OFFSET[icpu_->getInstrMode()];
        }
 
        if (u.bits.P) {
            off += get_increment(u);
        }
 
        trans_.addr = off;
        trans_.xsize = opsz[u.bits.h];
        trans_.wstrb = 0;
        if (u.bits.L) {
            trans_.action = MemAction_Read;
            trans_.rpayload.b64[0] = 0;
        } else {
            trans_.action = MemAction_Write;
            trans_.wstrb = (1 << trans_.xsize) - 1;
            trans_.wpayload.b64[0] = R[u.bits.rd];
        }
        icpu_->dma_memop(&trans_);
 
        if (u.bits.W) {
            if (!u.bits.P) {
                off += get_increment(u);
            }
            R[u.bits.rn] = off;
        }
        if (u.bits.L) {
            if (u.bits.h) {
                R[u.bits.rd] = trans_.rpayload.b16[0];
                if (u.bits.s) {
                    R[u.bits.rd] |= EXT_SIGN_16;
                }
            } else {
                R[u.bits.rd] = trans_.rpayload.b8[0];
                if (u.bits.s) {
                    R[u.bits.rd] |= EXT_SIGN_8;
                }
            }
            if (u.bits.rd == Reg_pc) {
                icpu_->setBranch(R[u.bits.rd]);
            }
        }
        return 4;
    }
 
 protected:
    virtual uint64_t get_increment(HWordSignedDataTransferType u) {
        uint64_t incr;
        if (!u.bits.reg_imm) {
            incr = (u.bits.imm_h << 4) | u.bits.rm;
        } else {
            incr = R[u.bits.rm];
        }
        if (!u.bits.U) {
            incr = (~incr) + 1;
        }
        return incr;
    }
};
 
/** Multiply common */
class MultiplyInstruction : public ArmInstruction {
 public:
    MultiplyInstruction(CpuCortex_Functional *icpu, const char *name,
        const char *bits) : ArmInstruction(icpu, name, bits) {}
 
    virtual int exec_checked(Reg64Type *payload) {
        MulType u;
        u.value = payload->buf32[0];
        uint64_t res = R[u.bits.rm] * R[u.bits.rs];
        if (u.bits.A) {
            res += R[u.bits.rn];
        }
        R[u.bits.rd] = static_cast<uint32_t>(res);
        if (u.bits.S) {
            icpu_->setC(0); // set meaningless value
            icpu_->setZ(R[u.bits.rd] == 0);
            icpu_->setN(static_cast<uint32_t>(R[u.bits.rd]) >> 31);
        }
        return 4;
    }
};
 
/** Multiply Long common. */
class MultiplyLongInstruction : public ArmInstruction {
 public:
    MultiplyLongInstruction(CpuCortex_Functional *icpu, const char *name,
        const char *bits) : ArmInstruction(icpu, name, bits) {}
 
    virtual int exec_checked(Reg64Type *payload) {
        MulLongType u;
        u.value = payload->buf32[0];
        uint64_t res = 0;
        if (u.bits.A) {
            res = static_cast<uint64_t>(R[u.bits.rdhi]) << 32;
            res |= R[u.bits.rdlo];
        }
        if (u.bits.S) {
            int64_t a = static_cast<int32_t>(R[u.bits.rm]);
            int64_t b = static_cast<int32_t>(R[u.bits.rs]);
            res = static_cast<uint64_t>(static_cast<int64_t>(res) + a * b);
        } else {
            uint64_t a = R[u.bits.rm];
            uint64_t b = R[u.bits.rs];
            res = res + a * b;
        }
        R[u.bits.rdlo] = static_cast<uint32_t>(res);
        R[u.bits.rdhi] = static_cast<uint32_t>(res >> 32);
        if (u.bits.S) {
            icpu_->setC(0);     // set to meaningless value
            icpu_->setV(0);     // set to meaningless value
            icpu_->setZ(res == 0);
            icpu_->setN(static_cast<uint32_t>(res >> 63));
        }
        return 4;
    }
};
 
 
/**
 * @brief AND.
 */
static const char *AND_OPCODES[2] = {
    "????0000000?????????????????????",
    "????0010000?????????????????????"
};
 
class AND : public ArmDataProcessingInstruction {
 public:
    AND(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "AND", AND_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A & M;
        return OP_Write;
    }
};
 
/** 
 * @brief EOR.
 */
static const char *EOR_OPCODES[2] = {
    "????0000001?????????????????????",
    "????0010001?????????????????????"
};
 
class EOR : public ArmDataProcessingInstruction {
 public:
    EOR(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "EOR", EOR_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A ^ M;
        return OP_Write;
    }
};
 
/** 
 * @brief Subtruct.
 */
static const char *SUB_OPCODES[2] = {
    "????0000010?????????????????????",
    "????0010010?????????????????????"
};
 
class SUB : public ArmSubInstruction {
 public:
    SUB(CpuCortex_Functional *icpu, int opidx) :
        ArmSubInstruction(icpu, "SUB", SUB_OPCODES[opidx]) {}
 protected:
    virtual bool is_inverted() { return false; }
    virtual bool with_carry() { return false; }
    virtual EOperationResult op_result() { return OP_Write; }
};
 
/** 
 * @brief Subtruct right.
 */
static const char *RSB_OPCODES[2] = {
    "????0000011?????????????????????",
    "????0010011?????????????????????"
};
 
class RSB : public ArmSubInstruction {
 public:
    RSB(CpuCortex_Functional *icpu, int opidx) :
        ArmSubInstruction(icpu, "RSB", RSB_OPCODES[opidx]) {}
 protected:
    virtual bool is_inverted() { return true; }
    virtual bool with_carry() { return false; }
    virtual EOperationResult op_result() { return OP_Write; }
};
 
/** 
 * @brief Addition.
 */
static const char *ADD_OPCODES[2] = {
    "????0000100?????????????????????",
    "????0010100?????????????????????"
};
 
class ADD : public ArmAddInstruction {
 public:
    ADD(CpuCortex_Functional *icpu, int opidx) :
        ArmAddInstruction(icpu, "ADD", ADD_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult op_result() { return OP_Write; }
    virtual bool with_carry() { return false; }
};
 
/** 
 * @brief Addition with carry bit.
 */
static const char *ADC_OPCODES[2] = {
    "????0000101?????????????????????",
    "????0010101?????????????????????"
};
 
class ADC : public ArmAddInstruction {
 public:
    ADC(CpuCortex_Functional *icpu, int opidx) :
        ArmAddInstruction(icpu, "ADC", ADC_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult op_result() { return OP_Write; }
    virtual bool with_carry() { return true; }
};
 
/** 
 * @brief Subtruct with carry bit: Op1 - Op2 + C - 1 !!!!!!.
 */
static const char *SBC_OPCODES[2] = {
    "????0000110?????????????????????",
    "????0010110?????????????????????"
};
 
class SBC : public ArmSubInstruction {
 public:
    SBC(CpuCortex_Functional *icpu, int opidx) :
        ArmSubInstruction(icpu, "SBC", SBC_OPCODES[opidx]) {}
 protected:
    virtual bool is_inverted() { return false; }
    virtual bool with_carry() { return true; }
    virtual EOperationResult op_result() { return OP_Write; }
};
 
/** 
 * @brief Subtruct right with carry bit: Op2 - Op1 + C - 1 !!!!.
 */
static const char *RSC_OPCODES[2] = {
    "????0000111?????????????????????",
    "????0010111?????????????????????"
};
 
class RSC : public ArmSubInstruction {
 public:
    RSC(CpuCortex_Functional *icpu, int opidx) :
        ArmSubInstruction(icpu, "RSC", RSC_OPCODES[opidx]) {}
 protected:
    virtual bool is_inverted() { return true; }
    virtual bool with_carry() { return true; }
    virtual EOperationResult op_result() { return OP_Write; }
};
 
/**
 * @brief Set condition codes on Op1 AND Op2.
 * S-flag must be set otherwise it can be MOVW instruction
 */
 static const char *TST_OPCODES[2] = {
    "????00010001????????????????????",
    "????00110001????????????????????"
};
 
class TST : public ArmDataProcessingInstruction {
 public:
    TST(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "TST", TST_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A & M;
        return OP_Drop;
    }
};
 
/**
 * @brief Set condition codes on Op1 EOR Op2.
 */
static const char *TEQ_OPCODES[2] = {
    "????0001001?????????????????????",
    "????0011001?????????????????????"
};
 
class TEQ : public ArmDataProcessingInstruction {
 public:
    TEQ(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "TEQ", TEQ_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A ^ M;
        return OP_Drop;
    }
};
 
/**
 * @brief Set condition codes on Op1 - Op2.
 */
static const char *CMP_OPCODES[2] = {
    "????0001010?????????????????????",
    "????0011010?????????????????????"
};
 
class CMP : public ArmSubInstruction {
 public:
    CMP(CpuCortex_Functional *icpu, int opidx) :
        ArmSubInstruction(icpu, "CMP", CMP_OPCODES[opidx]) {}
 protected:
    virtual bool is_inverted() { return false; }
    virtual bool with_carry() { return false; }
    virtual EOperationResult op_result() { return OP_Drop; }
};
 
/**
 * @brief Set condition codes on Op1 + Op2.
 */
static const char *CMN_OPCODES[2] = {
    "????0001011?????????????????????",
    "????0011011?????????????????????"
};
 
class CMN : public ArmAddInstruction {
 public:
    CMN(CpuCortex_Functional *icpu, int opidx) :
        ArmAddInstruction(icpu, "CMN", CMN_OPCODES[opidx]) {}
 protected:
    virtual bool with_carry() { return false; }
    virtual EOperationResult op_result() { return OP_Drop; }
};
 
/**
 * @brief OR
 */
static const char *ORR_OPCODES[2] = {
    "????0001100?????????????????????",
    "????0011100?????????????????????"
};
 
class ORR : public ArmDataProcessingInstruction {
 public:
    ORR(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "ORR", ORR_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A | M;
        return OP_Write;
    }
};
 
/**
 * @brief Move data: Rd = Op2
 */
static const char *MOV_OPCODES[2] = {
    "????0001101?????????????????????",
    "????0011101?????????????????????"
};
 
class MOV : public ArmDataProcessingInstruction {
 public:
    MOV(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "MOV", MOV_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = M;
        return OP_Write;
    }
};
 
/** Move Top writes an immediate value to the top halfword of the destination
    register. It does not affect the contents of the bottom halfword. */
class MOVT : public ArmInstruction {
 public:
    MOVT(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "MOVT", "????00110100????????????????????") {}
 protected:
    virtual int exec_checked(Reg64Type *payload) {
        DataProcessingType u;
        u.value = payload->buf32[0];
        uint32_t imm16 = (u.mov_bits.imm4 << 12) | u.mov_bits.imm12;
        R[u.mov_bits.rd] &= ~0xFFFF0000;
        R[u.mov_bits.rd] |= (imm16 << 16);
        return 4;
    }
};
 
/** This new variant of MOV (immediate) writes a 16-bit immediate 
    value to the destination register */
class MOVW : public ArmInstruction {
 public:
    MOVW(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "MOVW", "????00110000????????????????????") {}
 protected:
    virtual int exec_checked(Reg64Type *payload) {
        DataProcessingType u;
        u.value = payload->buf32[0];
        uint32_t imm16 = (u.mov_bits.imm4 << 12) | u.mov_bits.imm12;
        R[u.mov_bits.rd] &= ~0xFFFF;
        R[u.mov_bits.rd] |= imm16;
        return 4;
    }
};
 
/** Rd:=Rm*Rs. */
class MUL : public MultiplyInstruction {
 public:
    MUL(CpuCortex_Functional *icpu) : MultiplyInstruction(icpu,
        "MUL", "????0000000?????????????1001????") {}
};
 
/** Multiply and accumulate:  Rd:=Rm*Rs+Rn */
class MLA : public MultiplyInstruction {
 public:
    MLA(CpuCortex_Functional *icpu) : MultiplyInstruction(icpu,
        "MLA", "????0000001?????????????1001????") {}
};
 
/** Unsigned Multiply Long */
class UMULL : public MultiplyLongInstruction {
 public:
    UMULL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
        "UMULL", "????0000100?????????????1001????") {}
};
 
/** Unsigned Multiply ^ Accumulate Long */
class UMLAL : public MultiplyLongInstruction {
 public:
    UMLAL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
        "UMLAL", "????0000101?????????????1001????") {}
};
 
/** Signed Multiply Long */
class SMULL : public MultiplyLongInstruction {
 public:
    SMULL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
        "SMULL", "????0000110?????????????1001????") {}
};
 
/** Signed Multiply ^ Accumulate Long */
class SMLAL : public MultiplyLongInstruction {
 public:
    SMLAL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
        "SMLAL", "????0000111?????????????1001????") {}
};
 
/**
 * @brief Bit clear: AND NOT
 */
static const char *BIC_OPCODES[2] = {
    "????0001110?????????????????????",
    "????0011110?????????????????????"
};
 
class BIC : public ArmDataProcessingInstruction {
 public:
    BIC(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "BIC", BIC_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = A & ~M;
        return OP_Write;
    }
};
 
/**
 * @brief Move inverted data: Rd = NOT Op2
 */
static const char *MVN_OPCODES[2] = {
    "????0001111?????????????????????",
    "????0011111?????????????????????"
};
 
class MVN : public ArmDataProcessingInstruction {
 public:
    MVN(CpuCortex_Functional *icpu, int opidx) :
        ArmDataProcessingInstruction(icpu, "MVN", MVN_OPCODES[opidx]) {}
 protected:
    virtual EOperationResult do_operation(uint32_t A, uint32_t M,
                                          uint32_t *pRes) {
        *pRes = ~M;
        return OP_Write;
    }
};
 
/** Branch */
class B : public ArmInstruction {
public:
    B(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "B", "????1010????????????????????????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        BranchType u;
        u.value = payload->buf32[0];
        uint32_t off = u.bits.offset;
        if ((u.value >> 23) & 0x1) {
            off |= 0xFF000000;
        }
        off = static_cast<uint32_t>(
            R[Reg_pc] + (off << 2) + PREFETCH_OFFSET[icpu_->getInstrMode()]);
        R[Reg_pc] = off;
        icpu_->setBranch(off);
        return 4;
    }
};
 
/** Branch with Link */
class BL : public ArmInstruction {
public:
    BL(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "BL", "????1011????????????????????????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        BranchType u;
        u.value = payload->buf32[0];
        R[Reg_lr] = R[Reg_pc] + 4;
        uint32_t off = u.bits.offset;
        if ((u.value >> 23) & 0x1) {
            off |= 0xFF000000;
        }
        off = static_cast<uint32_t>(
            R[Reg_pc] + (off << 2) + PREFETCH_OFFSET[icpu_->getInstrMode()]);
        R[Reg_pc] = off;
        icpu_->setBranch(off);
        return 4;
    }
};
 
/** Branch and Exchange */
class BX : public ArmInstruction {
public:
    BX(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "BX", "????000100101111111111110001????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        BranchType u;
        u.value = payload->buf32[0];
        uint32_t off = static_cast<uint32_t>(R[u.bits.offset & 0xf]);
        if (off & 0x1) {
            icpu_->setInstrMode(THUMB_mode);
        } else {
            icpu_->setInstrMode(ARM_mode);
        }
        R[Reg_pc] = off;
        icpu_->setBranch(off);
        return 4;
    }
};
 
/** Load word pre-adding immediate offset to base register */
static const char *LDR_OPCODES[4] = {
    "????0100???1????????????????????", // immedaiate, post incr
    "????0101???1????????????????????", // immedaiate, pre incr
    "????0110???1????????????????????", // shift reg, post incr
    "????0111???1????????????????????", // shift reg, pre incr
};
 
class LDR : public SingleDataTransferInstruction {
public:
    LDR(CpuCortex_Functional *icpu, int opidx) :
        SingleDataTransferInstruction(icpu, "LDR", LDR_OPCODES[opidx]) {}
};
 
/** Load Signed Byte */
static const char *LDRSB_OPCODES[4] = {
    "????0000???1????????????1101????", // post incr
    "????0001???1????????????1101????", // pre incr
};
 
class LDRSB : public HWordSignedDataTransferInstruction {
public:
    LDRSB(CpuCortex_Functional *icpu, int opidx) :
        HWordSignedDataTransferInstruction(icpu, "LDRSB", LDRSB_OPCODES[opidx])
        {}
};
 
/** Load Unsigned Half-Word */
static const char *LDRH_OPCODES[4] = {
    "????0000???1????????????1011????", // post incr
    "????0001???1????????????1011????", // pre incr
};
 
class LDRH : public HWordSignedDataTransferInstruction {
public:
    LDRH(CpuCortex_Functional *icpu, int opidx) :
        HWordSignedDataTransferInstruction(icpu, "LDRH", LDRH_OPCODES[opidx])
        {}
};
 
/** Load Signed Half-word */
static const char *LDRSH_OPCODES[4] = {
    "????0000???1????????????1111????", // post incr
    "????0001???1????????????1111????", // pre incr
};
 
class LDRSH : public HWordSignedDataTransferInstruction {
public:
    LDRSH(CpuCortex_Functional *icpu, int opidx) :
        HWordSignedDataTransferInstruction(icpu, "LDRSH", LDRSB_OPCODES[opidx])
        {}
};
 
/** Load Block data */
static const char *LDM_OPCODES[4] = {
    "????1000???1????????????????????", // post incr
    "????1001???1????????????????????", // pre incr
};
 
class LDM : public BlockDataTransferInstruction {
 public:
    LDM(CpuCortex_Functional *icpu, int opidx) :
        BlockDataTransferInstruction(icpu, "LDM", LDM_OPCODES[opidx]) {}
};
 
 
 
/** Store word */
static const char *STR_OPCODES[4] = {
    "????0100?0?0????????????????????", // immedaiate, post incr
    "????0101?0?0????????????????????", // immedaiate, pre incr
    "????0110?0?0????????????????????", // shift reg, post incr
    "????0111?0?0????????????????????", // shift reg, pre incr
};
 
class STR : public SingleDataTransferInstruction {
public:
    STR(CpuCortex_Functional *icpu, int opidx) :
        SingleDataTransferInstruction(icpu, "STR", STR_OPCODES[opidx]) {}
};
 
/** Store Byte */
static const char *STRB_OPCODES[4] = {
    "????0100?1?0????????????????????", // immedaiate, post incr
    "????0101?1?0????????????????????", // immedaiate, pre incr
    "????0110?1?0????????????????????", // shift reg, post incr
    "????0111?1?0????????????????????", // shift reg, pre incr
};
 
class STRB : public SingleDataTransferInstruction {
public:
    STRB(CpuCortex_Functional *icpu, int opidx) :
        SingleDataTransferInstruction(icpu, "STRB", STRB_OPCODES[opidx]) {}
};
 
/** Store Half-Word */
static const char *STRH_OPCODES[4] = {
    "????0000???0????????????1?11????", // post incr
    "????0001???0????????????1?11????", // pre incr
};
 
class STRH : public HWordSignedDataTransferInstruction {
public:
    STRH(CpuCortex_Functional *icpu, int opidx) :
        HWordSignedDataTransferInstruction(icpu, "STRH", STRH_OPCODES[opidx])
        {}
};
 
/** Store Block data */
static const char *STM_OPCODES[4] = {
    "????1000???0????????????????????", // post incr
    "????1001???0????????????????????", // pre incr
};
 
class STM : public BlockDataTransferInstruction {
 public:
    STM(CpuCortex_Functional *icpu, int opidx) :
        BlockDataTransferInstruction(icpu, "STM", STM_OPCODES[opidx]) {}
};
 
/** Move from coprocessor to ARM7TDMI-S register (L=1) */
class MRC : public ArmInstruction {
 public:
    MRC(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "MRC", "????1110???1???????????????1????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        CoprocessorTransferType u;
        u.value = payload->buf32[0];
        return 4;
    }
};
 
/** Move from ARM7TDMI-S register to coprocessor (L=0) */
class MCR : public ArmInstruction {
 public:
    MCR(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "MRC", "????1110???0???????????????1????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        CoprocessorTransferType u;
        u.value = payload->buf32[0];
        return 4;
    }
};
 
/** 
 * @brief Transfer register to PSR flags.
 */
static const char *MSR_OPCODES[2] = {
    "????00010?10????1111????????????",
    "????00110?10????1111????????????"
};
 
class MSR : public ArmInstruction {
public:
    MSR(CpuCortex_Functional *icpu, int opidx) :
        ArmInstruction(icpu, "MSR", MSR_OPCODES[opidx]) {}
 
    virtual int exec_checked(Reg64Type *payload) {
        PsrTransferType u;
        u.value = payload->buf32[0];
        return 4;
    }
};
 
class MRS : public ArmInstruction {
public:
    MRS(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "MRS", "????00010?001111????000000000000") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        PsrTransferType u;
        u.value = payload->buf32[0];
        return 4;
    }
};
 
class NOP : public ArmInstruction {
public:
    NOP(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "NOP", "????0011001000001111000000000000") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        return 4;
    }
};
 
/** Bytes zero-extending
 UXTB extracts an 8-bit value from a register and zero extends it to 32 bits.
 You can specify a rotation by 0, 8, 16, or 24 bits before extracting 
 the 8-bit value.
 */
class UXTB : public ArmInstruction {
public:
    UXTB(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "UXTB", "????011011101111????????0111????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SignExtendType u;
        u.value = payload->buf32[0];
        uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
        t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
        t1 &= 0xFF;
        R[u.bits.rd] = static_cast<uint32_t>(t1);
        return 4;
    }
};
 
/** */
class UXTAB : public ArmInstruction {
public:
    UXTAB(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "UXTAB", "????01101110????????????0111????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SignExtendType u;
        u.value = payload->buf32[0];
        uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
        t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
        t1 &= 0xFF;
        R[u.bits.rd] = R[u.bits.rn] + static_cast<uint32_t>(t1);
        return 4;
    }
};
 
/** UXTB16 extracts two 8-bit values from a register and zero extends them
  to 16 bits each. You can specify a rotation by 0, 8, 16, or 24 bits before
  extracting the 8-bit values.
 */
class UXTB16 : public ArmInstruction {
public:
    UXTB16(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "UXTB16", "????011011001111????????0111????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SignExtendType u;
        u.value = payload->buf32[0];
        uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
        t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
        t1 &= 0x00FF00FF;
        R[u.bits.rd] = static_cast<uint32_t>(t1);
        return 4;
    }
};
 
/** UXTAB16 extracts two 8-bit values from a register, zero extends them
 to 16 bits each, and adds the results to the two values from another
 register. You can specify a rotation by 0, 8, 16, or 24 bits before
 extracting the 8-bit values.
 */
class UXTAB16 : public ArmInstruction {
public:
    UXTAB16(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "UXTAB16", "????01101100????????????0111????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SignExtendType u;
        u.value = payload->buf32[0];
        uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
        t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
        uint32_t a = (R[u.bits.rd] & 0xFFFF) + (t1 & 0xFF);
        uint32_t b = ((R[u.bits.rd] >> 16) & 0xFFFF) + ((t1 >> 16) & 0xFF);
        R[u.bits.rd] = (b << 16) | a;
        return 4;
    }
};
 
 
/** UXTH extracts a 16-bit value from a register and zero extends it
 to 32 bits. You can specify a rotation by 0, 8, 16, or 24 bits before
 extracting the 16-bit value.
 */
class UXTH : public ArmInstruction {
public:
    UXTH(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "UXTH", "????011011111111????????0111????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SignExtendType u;
        u.value = payload->buf32[0];
        uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
        t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
        t1 &= 0xFFFF;
        R[u.bits.rd] = static_cast<uint32_t>(t1);
        return 4;
    }
};
 
/** UXTAH extracts a 16-bit value from a register, zero extends it to 32 bits,
 and adds the result to a value in another register. You can specify a
 rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value.
 */
class UXTAH : public ArmInstruction {
public:
    UXTAH(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "UXTAH", "????01101111????????????0111????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        SignExtendType u;
        u.value = payload->buf32[0];
        uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
        t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
        t1 &= 0xFFFF;
        R[u.bits.rd] = R[u.bits.rn] + static_cast<uint32_t>(t1);
        return 4;
    }
};
 
 
/**
 * @brief SWI (software breakpoint instruction)
 *
 */
class SWI : public ArmInstruction {
 public:
    SWI(CpuCortex_Functional *icpu) :
        ArmInstruction(icpu, "SWI", "????1110???1???????????????1????") {}
 
    virtual int exec_checked(Reg64Type *payload) {
        icpu_->raiseSoftwareIrq();
        return 4;
    }
};
 
 
 
void CpuCortex_Functional::addArm7tmdiIsa() {
 
    // Arm V6 instructions:
    //      CPS, SRS, RFE
    //      REV, REV16, REVSH
    //      SETEND
    //      LDREX, STREX
    //      SXTB, SXTH, UXTB, UXTH
    addSupportedInstruction(new UXTB(this));    // same opcode as STRB
    addSupportedInstruction(new UXTAB(this));
    addSupportedInstruction(new UXTB16(this));  // rn=1111b
    addSupportedInstruction(new UXTAB16(this));  // rn=????b
    addSupportedInstruction(new UXTH(this));    // rn=1111b
    addSupportedInstruction(new UXTAH(this));   // rn=????
 
    // use the same as opcodes TEQ, TST, CMN and CMP without S-flag
    // and must be registered first.
    addSupportedInstruction(new BX(this));  // use TST,MSR opcode
    addSupportedInstruction(new NOP(this)); // use MSR opcode
    addSupportedInstruction(new MOVT(this));
    addSupportedInstruction(new MOVW(this));
    addSupportedInstruction(new MUL(this));
    addSupportedInstruction(new MLA(this));
    addSupportedInstruction(new UMULL(this));
    addSupportedInstruction(new UMLAL(this));
    addSupportedInstruction(new SMULL(this));
    addSupportedInstruction(new SMLAL(this));
    addSupportedInstruction(new MRS(this));
    addSupportedInstruction(new MSR(this, 0));
    addSupportedInstruction(new MSR(this, 1));
 
    addSupportedInstruction(new AND(this, 0));
    addSupportedInstruction(new AND(this, 1));
    addSupportedInstruction(new EOR(this, 0));
    addSupportedInstruction(new EOR(this, 1));
    addSupportedInstruction(new SUB(this, 0));
    addSupportedInstruction(new SUB(this, 1));
    addSupportedInstruction(new RSB(this, 0));
    addSupportedInstruction(new RSB(this, 1));
    addSupportedInstruction(new ADD(this, 0));
    addSupportedInstruction(new ADD(this, 1));
    addSupportedInstruction(new ADC(this, 0));
    addSupportedInstruction(new ADC(this, 1));
    addSupportedInstruction(new SBC(this, 0));
    addSupportedInstruction(new SBC(this, 1));
    addSupportedInstruction(new RSC(this, 0));
    addSupportedInstruction(new RSC(this, 1));
    addSupportedInstruction(new TST(this, 0));
    addSupportedInstruction(new TST(this, 1));
    addSupportedInstruction(new TEQ(this, 0));
    addSupportedInstruction(new TEQ(this, 1));
    addSupportedInstruction(new CMP(this, 0));
    addSupportedInstruction(new CMP(this, 1));
    addSupportedInstruction(new CMN(this, 0));
    addSupportedInstruction(new CMN(this, 1));
    addSupportedInstruction(new ORR(this, 0));
    addSupportedInstruction(new ORR(this, 1));
    addSupportedInstruction(new MOV(this, 0));
    addSupportedInstruction(new MOV(this, 1));
    addSupportedInstruction(new BIC(this, 0));
    addSupportedInstruction(new BIC(this, 1));
    addSupportedInstruction(new MVN(this, 0));
    addSupportedInstruction(new MVN(this, 1));
    addSupportedInstruction(new B(this));
    addSupportedInstruction(new BL(this));
    addSupportedInstruction(new LDR(this, 0));
    addSupportedInstruction(new LDR(this, 1));
    addSupportedInstruction(new LDR(this, 2));
    addSupportedInstruction(new LDR(this, 3));
    addSupportedInstruction(new LDRSB(this, 0));
    addSupportedInstruction(new LDRSB(this, 1));
    addSupportedInstruction(new LDRH(this, 0));
    addSupportedInstruction(new LDRH(this, 1));
    addSupportedInstruction(new LDRSH(this, 0));
    addSupportedInstruction(new LDRSH(this, 1));
    addSupportedInstruction(new LDM(this, 0));
    addSupportedInstruction(new LDM(this, 1));
    addSupportedInstruction(new STR(this, 0));
    addSupportedInstruction(new STR(this, 1));
    addSupportedInstruction(new STR(this, 2));
    addSupportedInstruction(new STR(this, 3));
    addSupportedInstruction(new STRB(this, 0));
    addSupportedInstruction(new STRB(this, 1));
    addSupportedInstruction(new STRB(this, 2));
    addSupportedInstruction(new STRB(this, 3));
    addSupportedInstruction(new STRH(this, 0));
    addSupportedInstruction(new STRH(this, 1));
    addSupportedInstruction(new STM(this, 0));
    addSupportedInstruction(new STM(this, 1));
    addSupportedInstruction(new MCR(this));
    addSupportedInstruction(new MRC(this));
    addSupportedInstruction(new SWI(this));
}
 
}  // 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.