@@ -1,7 +1,6 @@
 | 
			
		||||
#include "cpu.hh"
 | 
			
		||||
#include "cpu/cpu.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include "util/log.hh"
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,55 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "bus.hh"
 | 
			
		||||
#include "instruction.hh"
 | 
			
		||||
#include "psr.hh"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
using std::size_t;
 | 
			
		||||
 | 
			
		||||
class Cpu {
 | 
			
		||||
  public:
 | 
			
		||||
    Cpu(Bus& bus);
 | 
			
		||||
    void step();
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    static constexpr size_t GPR_COUNT = 16;
 | 
			
		||||
 | 
			
		||||
    static constexpr size_t GPR_FIQ_FIRST     = 8;
 | 
			
		||||
    static constexpr size_t GPR_SVC_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_ABT_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_IRQ_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_UND_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_SYS_USR_FIRST = 8;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Bus> bus;
 | 
			
		||||
    std::array<uint32_t, GPR_COUNT> gpr; // general purpose registers
 | 
			
		||||
 | 
			
		||||
    Psr cpsr; // current program status register
 | 
			
		||||
    Psr spsr; // status program status register
 | 
			
		||||
 | 
			
		||||
    uint32_t& pc = gpr[15];
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_SVC_FIRST - 1> svc;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_ABT_FIRST - 1> abt;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_IRQ_FIRST - 1> irq;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_UND_FIRST - 1> und;
 | 
			
		||||
 | 
			
		||||
        // visible registers before the mode switch
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_SYS_USR_FIRST> old;
 | 
			
		||||
    } gpr_banked; // banked general purpose registers
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        Psr fiq;
 | 
			
		||||
        Psr svc;
 | 
			
		||||
        Psr abt;
 | 
			
		||||
        Psr irq;
 | 
			
		||||
        Psr und;
 | 
			
		||||
    } spsr_banked; // banked saved program status registers
 | 
			
		||||
 | 
			
		||||
    void chg_mode(const Mode to);
 | 
			
		||||
    void exec_arm(const ArmInstruction instruction);
 | 
			
		||||
};
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
#include "instruction.hh"
 | 
			
		||||
#include "cpu/instruction.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
 | 
			
		||||
ArmInstruction::ArmInstruction(uint32_t insn)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,132 +0,0 @@
 | 
			
		||||
#include "cpu/utility.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
template<class... Ts>
 | 
			
		||||
struct overloaded : Ts... {
 | 
			
		||||
    using Ts::operator()...;
 | 
			
		||||
};
 | 
			
		||||
template<class... Ts>
 | 
			
		||||
overloaded(Ts...) -> overloaded<Ts...>;
 | 
			
		||||
 | 
			
		||||
class ArmInstruction {
 | 
			
		||||
  public:
 | 
			
		||||
    ArmInstruction() = delete;
 | 
			
		||||
    ArmInstruction(uint32_t insn);
 | 
			
		||||
 | 
			
		||||
    auto get_condition() const { return condition; }
 | 
			
		||||
    auto get_data() const { return data; }
 | 
			
		||||
 | 
			
		||||
    std::string disassemble();
 | 
			
		||||
 | 
			
		||||
    struct BranchAndExchange {
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Branch {
 | 
			
		||||
        bool link;
 | 
			
		||||
        uint32_t offset;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Multiply {
 | 
			
		||||
        uint8_t rm;
 | 
			
		||||
        uint8_t rs;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        bool set;
 | 
			
		||||
        bool acc;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct MultiplyLong {
 | 
			
		||||
        uint8_t rm;
 | 
			
		||||
        uint8_t rs;
 | 
			
		||||
        uint8_t rdlo;
 | 
			
		||||
        uint8_t rdhi;
 | 
			
		||||
        bool set;
 | 
			
		||||
        bool acc;
 | 
			
		||||
        bool uns;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct SingleDataSwap {
 | 
			
		||||
        uint8_t rm;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool byte;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct SingleDataTransfer {
 | 
			
		||||
        std::variant<uint16_t, Shift> offset;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        bool write;
 | 
			
		||||
        bool byte;
 | 
			
		||||
        bool up;
 | 
			
		||||
        bool pre;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct HalfwordTransfer {
 | 
			
		||||
        uint8_t offset;
 | 
			
		||||
        bool half;
 | 
			
		||||
        bool sign;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        bool write;
 | 
			
		||||
        bool byte;
 | 
			
		||||
        bool imm;
 | 
			
		||||
        bool up;
 | 
			
		||||
        bool pre;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CoprocessorDataTransfer {
 | 
			
		||||
        uint8_t offset;
 | 
			
		||||
        uint8_t cpn;
 | 
			
		||||
        uint8_t crd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        bool write;
 | 
			
		||||
        bool len;
 | 
			
		||||
        bool up;
 | 
			
		||||
        bool pre;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CoprocessorDataOperation {
 | 
			
		||||
        uint8_t crm;
 | 
			
		||||
        uint8_t cp;
 | 
			
		||||
        uint8_t cpn;
 | 
			
		||||
        uint8_t crd;
 | 
			
		||||
        uint8_t crn;
 | 
			
		||||
        uint8_t cp_opc;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CoprocessorRegisterTransfer {
 | 
			
		||||
        uint8_t crm;
 | 
			
		||||
        uint8_t cp;
 | 
			
		||||
        uint8_t cpn;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t crn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        uint8_t cp_opc;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Undefined {};
 | 
			
		||||
    struct SoftwareInterrupt {};
 | 
			
		||||
 | 
			
		||||
    using InstructionData = std::variant<BranchAndExchange,
 | 
			
		||||
                                         Branch,
 | 
			
		||||
                                         Multiply,
 | 
			
		||||
                                         MultiplyLong,
 | 
			
		||||
                                         SingleDataSwap,
 | 
			
		||||
                                         SingleDataTransfer,
 | 
			
		||||
                                         HalfwordTransfer,
 | 
			
		||||
                                         CoprocessorDataTransfer,
 | 
			
		||||
                                         CoprocessorDataOperation,
 | 
			
		||||
                                         CoprocessorRegisterTransfer,
 | 
			
		||||
                                         Undefined,
 | 
			
		||||
                                         SoftwareInterrupt>;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    Condition condition;
 | 
			
		||||
    InstructionData data;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
#include "psr.hh"
 | 
			
		||||
#include "cpu/psr.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include "util/log.hh"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
class Psr {
 | 
			
		||||
  public:
 | 
			
		||||
    // clear the reserved bits i.e, [8:27]
 | 
			
		||||
    Psr(uint32_t raw);
 | 
			
		||||
 | 
			
		||||
    // Mode : [4:0]
 | 
			
		||||
    Mode mode() const;
 | 
			
		||||
    void set_mode(Mode mode);
 | 
			
		||||
 | 
			
		||||
    // State : [5]
 | 
			
		||||
    State state() const;
 | 
			
		||||
    void set_state(State state);
 | 
			
		||||
 | 
			
		||||
#define GET_SET_NTH_BIT_FUNCTIONS(name)                                        \
 | 
			
		||||
    bool name() const;                                                         \
 | 
			
		||||
    void set_##name(bool val);
 | 
			
		||||
 | 
			
		||||
    // FIQ disable : [6]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(fiq_disabled)
 | 
			
		||||
 | 
			
		||||
    // IRQ disable : [7]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(irq_disabled)
 | 
			
		||||
 | 
			
		||||
    // Reserved bits : [27:8]
 | 
			
		||||
 | 
			
		||||
    // Overflow flag : [28]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(v)
 | 
			
		||||
 | 
			
		||||
    // Carry flag : [29]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(c)
 | 
			
		||||
 | 
			
		||||
    // Zero flag : [30]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(z)
 | 
			
		||||
 | 
			
		||||
    // Negative flag : [30]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(n)
 | 
			
		||||
 | 
			
		||||
#undef GET_SET_NTH_BIT_FUNCTIONS
 | 
			
		||||
 | 
			
		||||
    bool condition(Condition cond) const;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    static constexpr uint32_t PSR_CLEAR_RESERVED = 0xf00000ff;
 | 
			
		||||
    static constexpr uint32_t PSR_CLEAR_MODE     = 0x0b00000;
 | 
			
		||||
 | 
			
		||||
    uint32_t psr;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
#include "cpu/utility.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include <bit>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <fmt/ostream.h>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
 | 
			
		||||
static constexpr size_t ARM_INSTRUCTION_SIZE   = 4;
 | 
			
		||||
static constexpr size_t THUMB_INSTRUCTION_SIZE = 2;
 | 
			
		||||
 | 
			
		||||
enum class Mode {
 | 
			
		||||
    /* M[4:0] in PSR */
 | 
			
		||||
    User       = 0b10000,
 | 
			
		||||
    Fiq        = 0b10001,
 | 
			
		||||
    Irq        = 0b10010,
 | 
			
		||||
    Supervisor = 0b10011,
 | 
			
		||||
    Abort      = 0b10111,
 | 
			
		||||
    Undefined  = 0b11011,
 | 
			
		||||
    System     = 0b11111,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class State {
 | 
			
		||||
    Arm   = 0,
 | 
			
		||||
    Thumb = 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Condition {
 | 
			
		||||
    EQ = 0b0000,
 | 
			
		||||
    NE = 0b0001,
 | 
			
		||||
    CS = 0b0010,
 | 
			
		||||
    CC = 0b0011,
 | 
			
		||||
    MI = 0b0100,
 | 
			
		||||
    PL = 0b0101,
 | 
			
		||||
    VS = 0b0110,
 | 
			
		||||
    VC = 0b0111,
 | 
			
		||||
    HI = 0b1000,
 | 
			
		||||
    LS = 0b1001,
 | 
			
		||||
    GE = 0b1010,
 | 
			
		||||
    LT = 0b1011,
 | 
			
		||||
    GT = 0b1100,
 | 
			
		||||
    LE = 0b1101,
 | 
			
		||||
    AL = 0b1110
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// https://fmt.dev/dev/api.html#std-ostream-support
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const Condition cond);
 | 
			
		||||
template<>
 | 
			
		||||
struct fmt::formatter<Condition> : ostream_formatter {};
 | 
			
		||||
 | 
			
		||||
enum class OpCode {
 | 
			
		||||
    AND = 0b0000,
 | 
			
		||||
    EOR = 0b0001,
 | 
			
		||||
    SUB = 0b0010,
 | 
			
		||||
    RSB = 0b0011,
 | 
			
		||||
    ADD = 0b0100,
 | 
			
		||||
    ADC = 0b0101,
 | 
			
		||||
    SBC = 0b0110,
 | 
			
		||||
    RSC = 0b0111,
 | 
			
		||||
    TST = 0b1000,
 | 
			
		||||
    TEQ = 0b1001,
 | 
			
		||||
    CMP = 0b1010,
 | 
			
		||||
    CMN = 0b1011,
 | 
			
		||||
    ORR = 0b1100,
 | 
			
		||||
    MOV = 0b1101,
 | 
			
		||||
    BIC = 0b1110,
 | 
			
		||||
    MVN = 0b1111
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ShiftType {
 | 
			
		||||
    LSL = 0b00,
 | 
			
		||||
    LSR = 0b01,
 | 
			
		||||
    ASR = 0b10,
 | 
			
		||||
    ROR = 0b11
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ShiftData {
 | 
			
		||||
    ShiftType type;
 | 
			
		||||
    bool immediate;
 | 
			
		||||
    uint8_t operand;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Shift {
 | 
			
		||||
    uint8_t rm;
 | 
			
		||||
    ShiftData data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry);
 | 
			
		||||
 | 
			
		||||
// https://fmt.dev/dev/api.html#std-ostream-support
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const ShiftType cond);
 | 
			
		||||
template<>
 | 
			
		||||
struct fmt::formatter<ShiftType> : ostream_formatter {};
 | 
			
		||||
		Reference in New Issue
	
	Block a user