[UNTESTED] complete initial disassembler structure for ARM
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
		@@ -14,14 +14,14 @@ class Cpu {
 | 
				
			|||||||
    void step();
 | 
					    void step();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
    static constexpr size_t GPR_COUNT = 16;
 | 
					    static constexpr uint8_t GPR_COUNT = 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static constexpr size_t GPR_FIQ_FIRST     = 8;
 | 
					    static constexpr uint8_t GPR_FIQ_FIRST     = 8;
 | 
				
			||||||
    static constexpr size_t GPR_SVC_FIRST     = 13;
 | 
					    static constexpr uint8_t GPR_SVC_FIRST     = 13;
 | 
				
			||||||
    static constexpr size_t GPR_ABT_FIRST     = 13;
 | 
					    static constexpr uint8_t GPR_ABT_FIRST     = 13;
 | 
				
			||||||
    static constexpr size_t GPR_IRQ_FIRST     = 13;
 | 
					    static constexpr uint8_t GPR_IRQ_FIRST     = 13;
 | 
				
			||||||
    static constexpr size_t GPR_UND_FIRST     = 13;
 | 
					    static constexpr uint8_t GPR_UND_FIRST     = 13;
 | 
				
			||||||
    static constexpr size_t GPR_SYS_USR_FIRST = 8;
 | 
					    static constexpr uint8_t GPR_SYS_USR_FIRST = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<Bus> bus;
 | 
					    std::shared_ptr<Bus> bus;
 | 
				
			||||||
    std::array<uint32_t, GPR_COUNT> gpr; // general purpose registers
 | 
					    std::array<uint32_t, GPR_COUNT> gpr; // general purpose registers
 | 
				
			||||||
@@ -29,7 +29,13 @@ class Cpu {
 | 
				
			|||||||
    Psr cpsr; // current program status register
 | 
					    Psr cpsr; // current program status register
 | 
				
			||||||
    Psr spsr; // status program status register
 | 
					    Psr spsr; // status program status register
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t& pc = gpr[15];
 | 
					    static constexpr uint8_t PC_INDEX = 15;
 | 
				
			||||||
 | 
					    uint32_t& pc                      = gpr[PC_INDEX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool is_flushed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void chg_mode(const Mode to);
 | 
				
			||||||
 | 
					    void exec_arm(const ArmInstruction instruction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct {
 | 
					    struct {
 | 
				
			||||||
        std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
 | 
					        std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
 | 
				
			||||||
@@ -49,7 +55,4 @@ class Cpu {
 | 
				
			|||||||
        Psr irq;
 | 
					        Psr irq;
 | 
				
			||||||
        Psr und;
 | 
					        Psr und;
 | 
				
			||||||
    } spsr_banked; // banked saved program status registers
 | 
					    } spsr_banked; // banked saved program status registers
 | 
				
			||||||
 | 
					 | 
				
			||||||
    void chg_mode(const Mode to);
 | 
					 | 
				
			||||||
    void exec_arm(const ArmInstruction instruction);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,6 +79,38 @@ class ArmInstruction {
 | 
				
			|||||||
        bool pre;
 | 
					        bool pre;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct BlockDataTransfer {
 | 
				
			||||||
 | 
					        uint16_t regs;
 | 
				
			||||||
 | 
					        uint8_t rn;
 | 
				
			||||||
 | 
					        bool load;
 | 
				
			||||||
 | 
					        bool write;
 | 
				
			||||||
 | 
					        bool s;
 | 
				
			||||||
 | 
					        bool up;
 | 
				
			||||||
 | 
					        bool pre;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct DataProcessing {
 | 
				
			||||||
 | 
					        std::variant<Shift, uint32_t> operand;
 | 
				
			||||||
 | 
					        uint8_t rd;
 | 
				
			||||||
 | 
					        uint8_t rn;
 | 
				
			||||||
 | 
					        bool set;
 | 
				
			||||||
 | 
					        OpCode opcode;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct PsrTransfer {
 | 
				
			||||||
 | 
					        enum class Type {
 | 
				
			||||||
 | 
					            Mrs,
 | 
				
			||||||
 | 
					            Msr,
 | 
				
			||||||
 | 
					            Msr_flg
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint32_t operand;
 | 
				
			||||||
 | 
					        bool spsr;
 | 
				
			||||||
 | 
					        Type type;
 | 
				
			||||||
 | 
					        // ignored outside MSR_flg
 | 
				
			||||||
 | 
					        bool imm;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct CoprocessorDataTransfer {
 | 
					    struct CoprocessorDataTransfer {
 | 
				
			||||||
        uint8_t offset;
 | 
					        uint8_t offset;
 | 
				
			||||||
        uint8_t cpn;
 | 
					        uint8_t cpn;
 | 
				
			||||||
@@ -120,6 +152,9 @@ class ArmInstruction {
 | 
				
			|||||||
                                         SingleDataSwap,
 | 
					                                         SingleDataSwap,
 | 
				
			||||||
                                         SingleDataTransfer,
 | 
					                                         SingleDataTransfer,
 | 
				
			||||||
                                         HalfwordTransfer,
 | 
					                                         HalfwordTransfer,
 | 
				
			||||||
 | 
					                                         BlockDataTransfer,
 | 
				
			||||||
 | 
					                                         DataProcessing,
 | 
				
			||||||
 | 
					                                         PsrTransfer,
 | 
				
			||||||
                                         CoprocessorDataTransfer,
 | 
					                                         CoprocessorDataTransfer,
 | 
				
			||||||
                                         CoprocessorDataOperation,
 | 
					                                         CoprocessorDataOperation,
 | 
				
			||||||
                                         CoprocessorRegisterTransfer,
 | 
					                                         CoprocessorRegisterTransfer,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ class Psr {
 | 
				
			|||||||
    // clear the reserved bits i.e, [8:27]
 | 
					    // clear the reserved bits i.e, [8:27]
 | 
				
			||||||
    Psr(uint32_t raw);
 | 
					    Psr(uint32_t raw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t raw() const;
 | 
				
			||||||
 | 
					    void set_all(uint32_t raw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Mode : [4:0]
 | 
					    // Mode : [4:0]
 | 
				
			||||||
    Mode mode() const;
 | 
					    Mode mode() const;
 | 
				
			||||||
    void set_mode(Mode mode);
 | 
					    void set_mode(Mode mode);
 | 
				
			||||||
@@ -45,8 +48,8 @@ class Psr {
 | 
				
			|||||||
    bool condition(Condition cond) const;
 | 
					    bool condition(Condition cond) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
    static constexpr uint32_t PSR_CLEAR_RESERVED = 0xf00000ff;
 | 
					    static constexpr uint32_t PSR_CLEAR_RESERVED = 0xF00000FF;
 | 
				
			||||||
    static constexpr uint32_t PSR_CLEAR_MODE     = 0x0b00000;
 | 
					    static constexpr uint32_t PSR_CLEAR_MODE     = 0xFFFFFFE0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t psr;
 | 
					    uint32_t psr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,6 +65,12 @@ enum class OpCode {
 | 
				
			|||||||
    MVN = 0b1111
 | 
					    MVN = 0b1111
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://fmt.dev/dev/api.html#std-ostream-support
 | 
				
			||||||
 | 
					std::ostream&
 | 
				
			||||||
 | 
					operator<<(std::ostream& os, const OpCode cond);
 | 
				
			||||||
 | 
					template<>
 | 
				
			||||||
 | 
					struct fmt::formatter<OpCode> : ostream_formatter {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class ShiftType {
 | 
					enum class ShiftType {
 | 
				
			||||||
    LSL = 0b00,
 | 
					    LSL = 0b00,
 | 
				
			||||||
    LSR = 0b01,
 | 
					    LSR = 0b01,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										393
									
								
								src/cpu/cpu.cc
									
									
									
									
									
								
							
							
						
						
									
										393
									
								
								src/cpu/cpu.cc
									
									
									
									
									
								
							@@ -1,4 +1,5 @@
 | 
				
			|||||||
#include "cpu/cpu.hh"
 | 
					#include "cpu/cpu.hh"
 | 
				
			||||||
 | 
					#include "cpu/utility.hh"
 | 
				
			||||||
#include "util/bits.hh"
 | 
					#include "util/bits.hh"
 | 
				
			||||||
#include "util/log.hh"
 | 
					#include "util/log.hh"
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
@@ -11,15 +12,17 @@ Cpu::Cpu(Bus& bus)
 | 
				
			|||||||
  , gpr({ 0 })
 | 
					  , gpr({ 0 })
 | 
				
			||||||
  , cpsr(0)
 | 
					  , cpsr(0)
 | 
				
			||||||
  , spsr(0)
 | 
					  , spsr(0)
 | 
				
			||||||
 | 
					  , is_flushed(false)
 | 
				
			||||||
  , gpr_banked({ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 } })
 | 
					  , gpr_banked({ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 } })
 | 
				
			||||||
  , spsr_banked({ 0, 0, 0, 0, 0 }) {
 | 
					  , spsr_banked({ 0, 0, 0, 0, 0 }) {
 | 
				
			||||||
    cpsr.set_mode(Mode::System);
 | 
					    cpsr.set_mode(Mode::Supervisor);
 | 
				
			||||||
    cpsr.set_irq_disabled(true);
 | 
					    cpsr.set_irq_disabled(true);
 | 
				
			||||||
    cpsr.set_fiq_disabled(true);
 | 
					    cpsr.set_fiq_disabled(true);
 | 
				
			||||||
    cpsr.set_state(State::Arm);
 | 
					    cpsr.set_state(State::Arm);
 | 
				
			||||||
    log_info("CPU successfully initialised");
 | 
					    log_info("CPU successfully initialised");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // PC is always two instructions ahead in the pipeline
 | 
					    // PC always points to two instructions ahead
 | 
				
			||||||
 | 
					    // PC - 2 is the instruction being executed
 | 
				
			||||||
    pc += 2 * ARM_INSTRUCTION_SIZE;
 | 
					    pc += 2 * ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +38,7 @@ Cpu::chg_mode(const Mode to) {
 | 
				
			|||||||
 * concatenate views */
 | 
					 * concatenate views */
 | 
				
			||||||
#define STORE_BANKED(mode, MODE)                                               \
 | 
					#define STORE_BANKED(mode, MODE)                                               \
 | 
				
			||||||
    std::copy(gpr.begin() + GPR_##MODE##_FIRST,                                \
 | 
					    std::copy(gpr.begin() + GPR_##MODE##_FIRST,                                \
 | 
				
			||||||
              gpr.begin() + GPR_COUNT - 1,                                     \
 | 
					              gpr.begin() + gpr.size() - 1,                                    \
 | 
				
			||||||
              gpr_banked.mode.begin())
 | 
					              gpr_banked.mode.begin())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (from) {
 | 
					    switch (from) {
 | 
				
			||||||
@@ -145,23 +148,25 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
            pc = gpr[data.rn];
 | 
					            pc = gpr[data.rn];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // ignore [1:0] bits for arm and 0 bit for thumb
 | 
					            // ignore [1:0] bits for arm and 0 bit for thumb
 | 
				
			||||||
            rst_nth_bit(pc, 0);
 | 
					            rst_bit(pc, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (state == State::Arm)
 | 
					            if (state == State::Arm)
 | 
				
			||||||
                rst_nth_bit(pc, 1);
 | 
					                rst_bit(pc, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // pc is affected so flush the pipeline
 | 
				
			||||||
 | 
					            is_flushed = true;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        [this](ArmInstruction::Branch& data) {
 | 
					        [this](ArmInstruction::Branch& data) {
 | 
				
			||||||
            auto offset = data.offset;
 | 
					 | 
				
			||||||
            // lsh 2 and sign extend the 26 bit offset to 32 bits
 | 
					 | 
				
			||||||
            offset <<= 2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (get_nth_bit(offset, 25))
 | 
					 | 
				
			||||||
                offset |= 0xFC000000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (data.link)
 | 
					            if (data.link)
 | 
				
			||||||
                gpr[14] = pc - ARM_INSTRUCTION_SIZE;
 | 
					                gpr[14] = pc - ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pc += offset - ARM_INSTRUCTION_SIZE;
 | 
					            // data.offset accounts for two instructions ahead when
 | 
				
			||||||
 | 
					            // disassembling, so need to adjust
 | 
				
			||||||
 | 
					            pc =
 | 
				
			||||||
 | 
					              static_cast<int32_t>(pc) - 2 * ARM_INSTRUCTION_SIZE + data.offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // pc is affected so flush the pipeline
 | 
				
			||||||
 | 
					            is_flushed = true;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        [this, pc_error](ArmInstruction::Multiply& data) {
 | 
					        [this, pc_error](ArmInstruction::Multiply& data) {
 | 
				
			||||||
            if (data.rd == data.rm)
 | 
					            if (data.rd == data.rm)
 | 
				
			||||||
@@ -176,8 +181,8 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
              gpr[data.rm] * gpr[data.rs] + (data.acc ? gpr[data.rn] : 0);
 | 
					              gpr[data.rm] * gpr[data.rs] + (data.acc ? gpr[data.rn] : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (data.set) {
 | 
					            if (data.set) {
 | 
				
			||||||
                cpsr.set_z(!static_cast<bool>(gpr[data.rd]));
 | 
					                cpsr.set_z(gpr[data.rd] == 0);
 | 
				
			||||||
                cpsr.set_n(get_nth_bit(gpr[data.rd], 31));
 | 
					                cpsr.set_n(get_bit(gpr[data.rd], 31));
 | 
				
			||||||
                cpsr.set_c(0);
 | 
					                cpsr.set_c(0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -199,8 +204,8 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                                static_cast<uint64_t>(gpr[data.rdlo])
 | 
					                                static_cast<uint64_t>(gpr[data.rdlo])
 | 
				
			||||||
                            : 0);
 | 
					                            : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                gpr[data.rdlo] = get_bit_range(eval, 0, 31);
 | 
					                gpr[data.rdlo] = bit_range(eval, 0, 31);
 | 
				
			||||||
                gpr[data.rdhi] = get_bit_range(eval, 32, 63);
 | 
					                gpr[data.rdhi] = bit_range(eval, 32, 63);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                int64_t eval =
 | 
					                int64_t eval =
 | 
				
			||||||
@@ -210,23 +215,22 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                                static_cast<int64_t>(gpr[data.rdlo])
 | 
					                                static_cast<int64_t>(gpr[data.rdlo])
 | 
				
			||||||
                            : 0);
 | 
					                            : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                gpr[data.rdlo] = get_bit_range(eval, 0, 31);
 | 
					                gpr[data.rdlo] = bit_range(eval, 0, 31);
 | 
				
			||||||
                gpr[data.rdhi] = get_bit_range(eval, 32, 63);
 | 
					                gpr[data.rdhi] = bit_range(eval, 32, 63);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (data.set) {
 | 
					            if (data.set) {
 | 
				
			||||||
                cpsr.set_z(!(static_cast<bool>(gpr[data.rdhi]) ||
 | 
					                cpsr.set_z(gpr[data.rdhi] == 0 && gpr[data.rdlo] == 0);
 | 
				
			||||||
                             static_cast<bool>(gpr[data.rdlo])));
 | 
					                cpsr.set_n(get_bit(gpr[data.rdhi], 31));
 | 
				
			||||||
                cpsr.set_n(get_nth_bit(gpr[data.rdhi], 31));
 | 
					 | 
				
			||||||
                cpsr.set_c(0);
 | 
					                cpsr.set_c(0);
 | 
				
			||||||
                cpsr.set_v(0);
 | 
					                cpsr.set_v(0);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        [](ArmInstruction::Undefined) { log_warn("Undefined instruction"); },
 | 
					        [](ArmInstruction::Undefined) { log_warn("Undefined instruction"); },
 | 
				
			||||||
        [this, pc_warn](ArmInstruction::SingleDataSwap& data) {
 | 
					        [this, pc_error](ArmInstruction::SingleDataSwap& data) {
 | 
				
			||||||
            pc_warn(data.rm);
 | 
					            pc_error(data.rm);
 | 
				
			||||||
            pc_warn(data.rn);
 | 
					            pc_error(data.rn);
 | 
				
			||||||
            pc_warn(data.rd);
 | 
					            pc_error(data.rd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (data.byte) {
 | 
					            if (data.byte) {
 | 
				
			||||||
                gpr[data.rd] = bus->read_byte(gpr[data.rn]);
 | 
					                gpr[data.rd] = bus->read_byte(gpr[data.rn]);
 | 
				
			||||||
@@ -244,6 +248,10 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                log_warn("Write-back enabled with post-indexing in {}",
 | 
					                log_warn("Write-back enabled with post-indexing in {}",
 | 
				
			||||||
                         typeid(data).name());
 | 
					                         typeid(data).name());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.rn == PC_INDEX && data.write)
 | 
				
			||||||
 | 
					                log_warn("Write-back enabled with base register as PC {}",
 | 
				
			||||||
 | 
					                         typeid(data).name());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (data.write)
 | 
					            if (data.write)
 | 
				
			||||||
                pc_warn(data.rn);
 | 
					                pc_warn(data.rn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -262,18 +270,21 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                    pc_error(shift->data.operand);
 | 
					                    pc_error(shift->data.operand);
 | 
				
			||||||
                pc_error(shift->rm);
 | 
					                pc_error(shift->rm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                offset =
 | 
				
			||||||
                  eval_shift(shift->data.type, gpr[shift->rm], amount, carry);
 | 
					                  eval_shift(shift->data.type, gpr[shift->rm], amount, carry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                cpsr.set_c(carry);
 | 
					                cpsr.set_c(carry);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // PC is always two instructions ahead
 | 
					            // PC is always two instructions ahead
 | 
				
			||||||
            if (data.rn == 15)
 | 
					            if (data.rn == PC_INDEX)
 | 
				
			||||||
                address -= 2 * ARM_INSTRUCTION_SIZE;
 | 
					                address -= 2 * ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (data.pre)
 | 
					            if (data.pre)
 | 
				
			||||||
                address += (data.up ? offset : -offset);
 | 
					                address += (data.up ? offset : -offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            debug(address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // load
 | 
					            // load
 | 
				
			||||||
            if (data.load) {
 | 
					            if (data.load) {
 | 
				
			||||||
                // byte
 | 
					                // byte
 | 
				
			||||||
@@ -285,7 +296,7 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                // store
 | 
					                // store
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // take PC into consideration
 | 
					                // take PC into consideration
 | 
				
			||||||
                if (data.rd == 15)
 | 
					                if (data.rd == PC_INDEX)
 | 
				
			||||||
                    address += ARM_INSTRUCTION_SIZE;
 | 
					                    address += ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // byte
 | 
					                // byte
 | 
				
			||||||
@@ -301,6 +312,9 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (!data.pre || data.write)
 | 
					            if (!data.pre || data.write)
 | 
				
			||||||
                gpr[data.rn] = address;
 | 
					                gpr[data.rn] = address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.rd == PC_INDEX && data.load)
 | 
				
			||||||
 | 
					                is_flushed = true;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        [this, pc_warn, pc_error](ArmInstruction::HalfwordTransfer& data) {
 | 
					        [this, pc_warn, pc_error](ArmInstruction::HalfwordTransfer& data) {
 | 
				
			||||||
            uint32_t address = gpr[data.rn];
 | 
					            uint32_t address = gpr[data.rn];
 | 
				
			||||||
@@ -331,14 +345,14 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                        gpr[data.rd] = bus->read_halfword(address);
 | 
					                        gpr[data.rd] = bus->read_halfword(address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        // sign extend the halfword
 | 
					                        // sign extend the halfword
 | 
				
			||||||
                        if (get_nth_bit(gpr[data.rd], 15))
 | 
					                        if (get_bit(gpr[data.rd], PC_INDEX))
 | 
				
			||||||
                            gpr[data.rd] |= 0xFFFF0000;
 | 
					                            gpr[data.rd] |= 0xFFFF0000;
 | 
				
			||||||
                        // byte
 | 
					                        // byte
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        gpr[data.rd] = bus->read_byte(address);
 | 
					                        gpr[data.rd] = bus->read_byte(address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        // sign extend the byte
 | 
					                        // sign extend the byte
 | 
				
			||||||
                        if (get_nth_bit(gpr[data.rd], 7))
 | 
					                        if (get_bit(gpr[data.rd], 7))
 | 
				
			||||||
                            gpr[data.rd] |= 0xFFFFFF00;
 | 
					                            gpr[data.rd] |= 0xFFFFFF00;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // unsigned halfword
 | 
					                    // unsigned halfword
 | 
				
			||||||
@@ -348,7 +362,7 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
                // store
 | 
					                // store
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // take PC into consideration
 | 
					                // take PC into consideration
 | 
				
			||||||
                if (data.rd == 15)
 | 
					                if (data.rd == PC_INDEX)
 | 
				
			||||||
                    address += ARM_INSTRUCTION_SIZE;
 | 
					                    address += ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // halfword
 | 
					                // halfword
 | 
				
			||||||
@@ -361,28 +375,337 @@ Cpu::exec_arm(const ArmInstruction instruction) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (!data.pre || data.write)
 | 
					            if (!data.pre || data.write)
 | 
				
			||||||
                gpr[data.rn] = address;
 | 
					                gpr[data.rn] = address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.rd == PC_INDEX && data.load)
 | 
				
			||||||
 | 
					                is_flushed = true;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        [this, pc_error](ArmInstruction::BlockDataTransfer& data) {
 | 
				
			||||||
 | 
					            uint32_t address  = gpr[data.rn];
 | 
				
			||||||
 | 
					            Mode mode         = cpsr.mode();
 | 
				
			||||||
 | 
					            uint8_t alignment = 4; // word
 | 
				
			||||||
 | 
					            uint8_t i         = 0;
 | 
				
			||||||
 | 
					            uint8_t n_regs    = std::popcount(data.regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pc_error(data.rn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (cpsr.mode() == Mode::User && data.s) {
 | 
				
			||||||
 | 
					                log_error("Bit S is set outside priviliged modes in {}",
 | 
				
			||||||
 | 
					                          typeid(data).name());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // we just change modes to load user registers
 | 
				
			||||||
 | 
					            if ((!get_bit(data.regs, PC_INDEX) && data.s) ||
 | 
				
			||||||
 | 
					                (!data.load && data.s)) {
 | 
				
			||||||
 | 
					                chg_mode(Mode::User);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (data.write) {
 | 
				
			||||||
 | 
					                    log_error("Write-back enable for user bank registers in {}",
 | 
				
			||||||
 | 
					                              typeid(data).name());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // account for decrement
 | 
				
			||||||
 | 
					            if (!data.up)
 | 
				
			||||||
 | 
					                address -= (n_regs - 1) * alignment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.pre)
 | 
				
			||||||
 | 
					                address += (data.up ? alignment : -alignment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.load) {
 | 
				
			||||||
 | 
					                if (get_bit(data.regs, PC_INDEX) && data.s && data.load) {
 | 
				
			||||||
 | 
					                    // current mode's spsr is already loaded when it was
 | 
				
			||||||
 | 
					                    // switched
 | 
				
			||||||
 | 
					                    spsr = cpsr;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (i = 0; i < GPR_COUNT; i++) {
 | 
				
			||||||
 | 
					                    if (get_bit(data.regs, i)) {
 | 
				
			||||||
 | 
					                        gpr[i] = bus->read_word(address);
 | 
				
			||||||
 | 
					                        address += alignment;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                for (i = 0; i < GPR_COUNT; i++) {
 | 
				
			||||||
 | 
					                    if (get_bit(data.regs, i)) {
 | 
				
			||||||
 | 
					                        bus->write_word(address, gpr[i]);
 | 
				
			||||||
 | 
					                        address += alignment;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!data.pre)
 | 
				
			||||||
 | 
					                address += (data.up ? alignment : -alignment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // reset back to original address + offset if incremented earlier
 | 
				
			||||||
 | 
					            if (data.up)
 | 
				
			||||||
 | 
					                address -= n_regs * alignment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!data.pre || data.write)
 | 
				
			||||||
 | 
					                gpr[data.rn] = address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.load && get_bit(data.regs, PC_INDEX))
 | 
				
			||||||
 | 
					                is_flushed = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // load back the original mode registers
 | 
				
			||||||
 | 
					            chg_mode(mode);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        [this, pc_error](ArmInstruction::PsrTransfer& data) {
 | 
				
			||||||
 | 
					            if (data.spsr && cpsr.mode() == Mode::User) {
 | 
				
			||||||
 | 
					                log_error("Accessing SPSR in User mode in {}",
 | 
				
			||||||
 | 
					                          typeid(data).name());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Psr& psr = data.spsr ? spsr : cpsr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (data.type) {
 | 
				
			||||||
 | 
					                case ArmInstruction::PsrTransfer::Type::Mrs:
 | 
				
			||||||
 | 
					                    pc_error(data.operand);
 | 
				
			||||||
 | 
					                    gpr[data.operand] = psr.raw();
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ArmInstruction::PsrTransfer::Type::Msr:
 | 
				
			||||||
 | 
					                    pc_error(data.operand);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (cpsr.mode() != Mode::User) {
 | 
				
			||||||
 | 
					                        psr.set_all(gpr[data.operand]);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                case ArmInstruction::PsrTransfer::Type::Msr_flg:
 | 
				
			||||||
 | 
					                    psr.set_n(get_bit(data.operand, 31));
 | 
				
			||||||
 | 
					                    psr.set_z(get_bit(data.operand, 30));
 | 
				
			||||||
 | 
					                    psr.set_c(get_bit(data.operand, 29));
 | 
				
			||||||
 | 
					                    psr.set_v(get_bit(data.operand, 28));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        [this, pc_error](ArmInstruction::DataProcessing& data) {
 | 
				
			||||||
 | 
					            uint32_t op_1 = gpr[data.rn];
 | 
				
			||||||
 | 
					            uint32_t op_2 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint32_t result = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bool overflow = cpsr.v();
 | 
				
			||||||
 | 
					            bool carry    = cpsr.c();
 | 
				
			||||||
 | 
					            bool negative = cpsr.n();
 | 
				
			||||||
 | 
					            bool zero     = cpsr.z();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (const uint32_t* immediate =
 | 
				
			||||||
 | 
					                  std::get_if<uint32_t>(&data.operand)) {
 | 
				
			||||||
 | 
					                op_2 = *immediate;
 | 
				
			||||||
 | 
					            } else if (const Shift* shift = std::get_if<Shift>(&data.operand)) {
 | 
				
			||||||
 | 
					                uint8_t amount =
 | 
				
			||||||
 | 
					                  (shift->data.immediate ? shift->data.operand
 | 
				
			||||||
 | 
					                                         : gpr[shift->data.operand] & 0xFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                bool carry = cpsr.c();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!shift->data.immediate)
 | 
				
			||||||
 | 
					                    pc_error(shift->data.operand);
 | 
				
			||||||
 | 
					                pc_error(shift->rm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                op_2 =
 | 
				
			||||||
 | 
					                  eval_shift(shift->data.type, gpr[shift->rm], amount, carry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cpsr.set_c(carry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // PC is 12 bytes ahead when shifting
 | 
				
			||||||
 | 
					                if (data.rn == PC_INDEX)
 | 
				
			||||||
 | 
					                    op_1 += ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (data.opcode) {
 | 
				
			||||||
 | 
					                case OpCode::AND: {
 | 
				
			||||||
 | 
					                    result = op_1 & op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::EOR: {
 | 
				
			||||||
 | 
					                    result = op_1 ^ op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::SUB: {
 | 
				
			||||||
 | 
					                    bool s1  = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2  = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					                    result   = op_1 - op_2;
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = op_1 < op_2;
 | 
				
			||||||
 | 
					                    overflow = s1 != s2 && s2 == negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::RSB: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					                    result  = op_2 - op_1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = op_2 < op_1;
 | 
				
			||||||
 | 
					                    overflow = s1 != s2 && s1 == negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::ADD: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // result_ is 33 bits
 | 
				
			||||||
 | 
					                    uint64_t result_ = op_2 + op_1;
 | 
				
			||||||
 | 
					                    result           = result_ & 0xFFFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = get_bit(result_, 32);
 | 
				
			||||||
 | 
					                    overflow = s1 == s2 && s1 != negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::ADC: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    uint64_t result_ = op_2 + op_1 + carry;
 | 
				
			||||||
 | 
					                    result           = result_ & 0xFFFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = get_bit(result_, 32);
 | 
				
			||||||
 | 
					                    overflow = s1 == s2 && s1 != negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::SBC: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    uint64_t result_ = op_1 - op_2 + carry - 1;
 | 
				
			||||||
 | 
					                    result           = result_ & 0xFFFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = get_bit(result_, 32);
 | 
				
			||||||
 | 
					                    overflow = s1 != s2 && s2 == negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::RSC: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    uint64_t result_ = op_1 - op_2 + carry - 1;
 | 
				
			||||||
 | 
					                    result           = result_ & 0xFFFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = get_bit(result_, 32);
 | 
				
			||||||
 | 
					                    overflow = s1 != s2 && s1 == negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::TST: {
 | 
				
			||||||
 | 
					                    result = op_1 & op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::TEQ: {
 | 
				
			||||||
 | 
					                    result = op_1 ^ op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::CMP: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    result = op_1 - op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = op_1 < op_2;
 | 
				
			||||||
 | 
					                    overflow = s1 != s2 && s2 == negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::CMN: {
 | 
				
			||||||
 | 
					                    bool s1 = get_bit(op_1, 31);
 | 
				
			||||||
 | 
					                    bool s2 = get_bit(op_2, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    uint64_t result_ = op_2 + op_1;
 | 
				
			||||||
 | 
					                    result           = result_ & 0xFFFFFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                    carry    = get_bit(result_, 32);
 | 
				
			||||||
 | 
					                    overflow = s1 == s2 && s1 != negative;
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::ORR: {
 | 
				
			||||||
 | 
					                    result = op_1 | op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::MOV: {
 | 
				
			||||||
 | 
					                    result = op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::BIC: {
 | 
				
			||||||
 | 
					                    result = op_1 & ~op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					                case OpCode::MVN: {
 | 
				
			||||||
 | 
					                    result = ~op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    negative = get_bit(result, 31);
 | 
				
			||||||
 | 
					                } break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            zero = result == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            debug(carry);
 | 
				
			||||||
 | 
					            debug(overflow);
 | 
				
			||||||
 | 
					            debug(zero);
 | 
				
			||||||
 | 
					            debug(negative);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto set_conditions = [=]() {
 | 
				
			||||||
 | 
					                cpsr.set_c(carry);
 | 
				
			||||||
 | 
					                cpsr.set_v(overflow);
 | 
				
			||||||
 | 
					                cpsr.set_n(negative);
 | 
				
			||||||
 | 
					                cpsr.set_z(zero);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.set) {
 | 
				
			||||||
 | 
					                if (data.rd == 15) {
 | 
				
			||||||
 | 
					                    if (cpsr.mode() == Mode::User)
 | 
				
			||||||
 | 
					                        log_error("Running {} in User mode",
 | 
				
			||||||
 | 
					                                  typeid(data).name());
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    set_conditions();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data.opcode == OpCode::TST || data.opcode == OpCode::TEQ ||
 | 
				
			||||||
 | 
					                data.opcode == OpCode::CMP || data.opcode == OpCode::CMN) {
 | 
				
			||||||
 | 
					                set_conditions();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                gpr[data.rd] = result;
 | 
				
			||||||
 | 
					                if (data.rd == 15 || data.opcode == OpCode::MVN)
 | 
				
			||||||
 | 
					                    is_flushed = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        [this](ArmInstruction::SoftwareInterrupt) {
 | 
					        [this](ArmInstruction::SoftwareInterrupt) {
 | 
				
			||||||
            chg_mode(Mode::Supervisor);
 | 
					            chg_mode(Mode::Supervisor);
 | 
				
			||||||
            pc   = 0x08;
 | 
					            pc   = 0x08;
 | 
				
			||||||
            spsr = cpsr;
 | 
					            spsr = cpsr;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        [](auto& data) { log_error("{} instruction", typeid(data).name()); } },
 | 
					        [](auto& data) {
 | 
				
			||||||
 | 
					            log_error("Unimplemented {} instruction", typeid(data).name());
 | 
				
			||||||
 | 
					        } },
 | 
				
			||||||
      data);
 | 
					      data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
Cpu::step() {
 | 
					Cpu::step() {
 | 
				
			||||||
 | 
					    // Current instruction is two instructions behind PC
 | 
				
			||||||
    uint32_t cur_pc = pc - 2 * ARM_INSTRUCTION_SIZE;
 | 
					    uint32_t cur_pc = pc - 2 * ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (cpsr.state() == State::Arm) {
 | 
					    if (cpsr.state() == State::Arm) {
 | 
				
			||||||
        ArmInstruction instruction(bus->read_word(cur_pc));
 | 
					        debug(cur_pc);
 | 
				
			||||||
        log_info("{:#034b}", bus->read_word(cur_pc));
 | 
					        uint32_t x = bus->read_word(cur_pc);
 | 
				
			||||||
 | 
					        ArmInstruction instruction(x);
 | 
				
			||||||
 | 
					        log_info("{:#034b}", x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        exec_arm(instruction);
 | 
					        exec_arm(instruction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log_info("{:#010X} : {}", cur_pc, instruction.disassemble());
 | 
					        log_info("0x{:08X} : {}", cur_pc, instruction.disassemble());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (is_flushed) {
 | 
				
			||||||
 | 
					            // if flushed, do not increment the PC, instead set it to two
 | 
				
			||||||
 | 
					            // instructions ahead to account for flushed "fetch" and "decode"
 | 
				
			||||||
 | 
					            // instructions
 | 
				
			||||||
 | 
					            pc += 2 * ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					            is_flushed = false;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // if not flushed continue like normal
 | 
				
			||||||
            pc += ARM_INSTRUCTION_SIZE;
 | 
					            pc += ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
#include "cpu/instruction.hh"
 | 
					#include "cpu/instruction.hh"
 | 
				
			||||||
 | 
					#include "cpu/utility.hh"
 | 
				
			||||||
#include "util/bits.hh"
 | 
					#include "util/bits.hh"
 | 
				
			||||||
 | 
					#include <iterator>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ArmInstruction::ArmInstruction(uint32_t insn)
 | 
					ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			||||||
  : condition(static_cast<Condition>(get_bit_range(insn, 28, 31))) {
 | 
					  : condition(static_cast<Condition>(bit_range(insn, 28, 31))) {
 | 
				
			||||||
    // Branch and exhcange
 | 
					    // Branch and exhcange
 | 
				
			||||||
    if ((insn & 0x0FFFFFF0) == 0x012FFF10) {
 | 
					    if ((insn & 0x0FFFFFF0) == 0x012FFF10) {
 | 
				
			||||||
        uint8_t rn = insn & 0b1111;
 | 
					        uint8_t rn = insn & 0b1111;
 | 
				
			||||||
@@ -11,19 +13,27 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Branch
 | 
					        // Branch
 | 
				
			||||||
    } else if ((insn & 0x0E000000) == 0x0A000000) {
 | 
					    } else if ((insn & 0x0E000000) == 0x0A000000) {
 | 
				
			||||||
        bool link       = get_nth_bit(insn, 24);
 | 
					        bool link       = get_bit(insn, 24);
 | 
				
			||||||
        uint32_t offset = get_bit_range(insn, 0, 23);
 | 
					        uint32_t offset = bit_range(insn, 0, 23);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // lsh 2 and sign extend the 26 bit offset to 32 bits
 | 
				
			||||||
 | 
					        offset <<= 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (get_bit(offset, 25))
 | 
				
			||||||
 | 
					            offset |= 0xFC000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        offset += 2 * ARM_INSTRUCTION_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = Branch{ .link = link, .offset = offset };
 | 
					        data = Branch{ .link = link, .offset = offset };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Multiply
 | 
					        // Multiply
 | 
				
			||||||
    } else if ((insn & 0x0FC000F0) == 0x00000090) {
 | 
					    } else if ((insn & 0x0FC000F0) == 0x00000090) {
 | 
				
			||||||
        uint8_t rm = get_bit_range(insn, 0, 3);
 | 
					        uint8_t rm = bit_range(insn, 0, 3);
 | 
				
			||||||
        uint8_t rs = get_bit_range(insn, 8, 11);
 | 
					        uint8_t rs = bit_range(insn, 8, 11);
 | 
				
			||||||
        uint8_t rn = get_bit_range(insn, 12, 15);
 | 
					        uint8_t rn = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t rd = get_bit_range(insn, 16, 19);
 | 
					        uint8_t rd = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool set   = get_nth_bit(insn, 20);
 | 
					        bool set   = get_bit(insn, 20);
 | 
				
			||||||
        bool acc   = get_nth_bit(insn, 21);
 | 
					        bool acc   = get_bit(insn, 21);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = Multiply{
 | 
					        data = Multiply{
 | 
				
			||||||
            .rm = rm, .rs = rs, .rn = rn, .rd = rd, .set = set, .acc = acc
 | 
					            .rm = rm, .rs = rs, .rn = rn, .rd = rd, .set = set, .acc = acc
 | 
				
			||||||
@@ -31,13 +41,13 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Multiply long
 | 
					        // Multiply long
 | 
				
			||||||
    } else if ((insn & 0x0F8000F0) == 0x00800090) {
 | 
					    } else if ((insn & 0x0F8000F0) == 0x00800090) {
 | 
				
			||||||
        uint8_t rm   = get_bit_range(insn, 0, 3);
 | 
					        uint8_t rm   = bit_range(insn, 0, 3);
 | 
				
			||||||
        uint8_t rs   = get_bit_range(insn, 8, 11);
 | 
					        uint8_t rs   = bit_range(insn, 8, 11);
 | 
				
			||||||
        uint8_t rdlo = get_bit_range(insn, 12, 15);
 | 
					        uint8_t rdlo = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t rdhi = get_bit_range(insn, 16, 19);
 | 
					        uint8_t rdhi = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool set     = get_nth_bit(insn, 20);
 | 
					        bool set     = get_bit(insn, 20);
 | 
				
			||||||
        bool acc     = get_nth_bit(insn, 21);
 | 
					        bool acc     = get_bit(insn, 21);
 | 
				
			||||||
        bool uns     = get_nth_bit(insn, 22);
 | 
					        bool uns     = get_bit(insn, 22);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = MultiplyLong{ .rm   = rm,
 | 
					        data = MultiplyLong{ .rm   = rm,
 | 
				
			||||||
                             .rs   = rs,
 | 
					                             .rs   = rs,
 | 
				
			||||||
@@ -53,10 +63,10 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Single data swap
 | 
					        // Single data swap
 | 
				
			||||||
    } else if ((insn & 0x0FB00FF0) == 0x01000090) {
 | 
					    } else if ((insn & 0x0FB00FF0) == 0x01000090) {
 | 
				
			||||||
        uint8_t rm = get_bit_range(insn, 0, 3);
 | 
					        uint8_t rm = bit_range(insn, 0, 3);
 | 
				
			||||||
        uint8_t rd = get_bit_range(insn, 12, 15);
 | 
					        uint8_t rd = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t rn = get_bit_range(insn, 16, 19);
 | 
					        uint8_t rn = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool byte  = get_nth_bit(insn, 22);
 | 
					        bool byte  = get_bit(insn, 22);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = SingleDataSwap{ .rm = rm, .rd = rd, .rn = rn, .byte = byte };
 | 
					        data = SingleDataSwap{ .rm = rm, .rd = rd, .rn = rn, .byte = byte };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,28 +74,28 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
    } else if ((insn & 0x0C000000) == 0x04000000) {
 | 
					    } else if ((insn & 0x0C000000) == 0x04000000) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::variant<uint16_t, Shift> offset;
 | 
					        std::variant<uint16_t, Shift> offset;
 | 
				
			||||||
        uint8_t rd = get_bit_range(insn, 12, 15);
 | 
					        uint8_t rd = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t rn = get_bit_range(insn, 16, 19);
 | 
					        uint8_t rn = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool load  = get_nth_bit(insn, 20);
 | 
					        bool load  = get_bit(insn, 20);
 | 
				
			||||||
        bool write = get_nth_bit(insn, 21);
 | 
					        bool write = get_bit(insn, 21);
 | 
				
			||||||
        bool byte  = get_nth_bit(insn, 22);
 | 
					        bool byte  = get_bit(insn, 22);
 | 
				
			||||||
        bool up    = get_nth_bit(insn, 23);
 | 
					        bool up    = get_bit(insn, 23);
 | 
				
			||||||
        bool pre   = get_nth_bit(insn, 24);
 | 
					        bool pre   = get_bit(insn, 24);
 | 
				
			||||||
        bool imm   = get_nth_bit(insn, 25);
 | 
					        bool imm   = get_bit(insn, 25);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (imm) {
 | 
					        if (imm) {
 | 
				
			||||||
            uint8_t rm = get_bit_range(insn, 0, 3);
 | 
					            uint8_t rm = bit_range(insn, 0, 3);
 | 
				
			||||||
            bool reg   = get_nth_bit(insn, 4);
 | 
					            bool reg   = get_bit(insn, 4);
 | 
				
			||||||
            ShiftType shift_type =
 | 
					            ShiftType shift_type =
 | 
				
			||||||
              static_cast<ShiftType>(get_bit_range(insn, 5, 6));
 | 
					              static_cast<ShiftType>(bit_range(insn, 5, 6));
 | 
				
			||||||
            uint8_t operand = get_bit_range(insn, (reg ? 8 : 7), 11);
 | 
					            uint8_t operand = bit_range(insn, (reg ? 8 : 7), 11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            offset = Shift{ .rm   = rm,
 | 
					            offset = Shift{ .rm   = rm,
 | 
				
			||||||
                            .data = ShiftData{ .type      = shift_type,
 | 
					                            .data = ShiftData{ .type      = shift_type,
 | 
				
			||||||
                                               .immediate = !reg,
 | 
					                                               .immediate = !reg,
 | 
				
			||||||
                                               .operand   = operand } };
 | 
					                                               .operand   = operand } };
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            offset = static_cast<uint16_t>(get_bit_range(insn, 0, 11));
 | 
					            offset = static_cast<uint16_t>(bit_range(insn, 0, 11));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = SingleDataTransfer{ .offset = offset,
 | 
					        data = SingleDataTransfer{ .offset = offset,
 | 
				
			||||||
@@ -99,18 +109,18 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Halfword transfer
 | 
					        // Halfword transfer
 | 
				
			||||||
    } else if ((insn & 0x0E000090) == 0x00000090) {
 | 
					    } else if ((insn & 0x0E000090) == 0x00000090) {
 | 
				
			||||||
        uint8_t offset = get_bit_range(insn, 0, 3);
 | 
					        uint8_t offset = bit_range(insn, 0, 3);
 | 
				
			||||||
        bool half      = get_nth_bit(insn, 5);
 | 
					        bool half      = get_bit(insn, 5);
 | 
				
			||||||
        bool sign      = get_nth_bit(insn, 6);
 | 
					        bool sign      = get_bit(insn, 6);
 | 
				
			||||||
        uint8_t rd     = get_bit_range(insn, 12, 15);
 | 
					        uint8_t rd     = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t rn     = get_bit_range(insn, 16, 19);
 | 
					        uint8_t rn     = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool load      = get_nth_bit(insn, 20);
 | 
					        bool load      = get_bit(insn, 20);
 | 
				
			||||||
        bool write     = get_nth_bit(insn, 21);
 | 
					        bool write     = get_bit(insn, 21);
 | 
				
			||||||
        bool imm       = get_nth_bit(insn, 22);
 | 
					        bool imm       = get_bit(insn, 22);
 | 
				
			||||||
        bool up        = get_nth_bit(insn, 23);
 | 
					        bool up        = get_bit(insn, 23);
 | 
				
			||||||
        bool pre       = get_nth_bit(insn, 24);
 | 
					        bool pre       = get_bit(insn, 24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        offset |= (imm ? get_bit_range(insn, 8, 11) << 2 : 0);
 | 
					        offset |= (imm ? bit_range(insn, 8, 11) << 2 : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = HalfwordTransfer{ .offset = offset,
 | 
					        data = HalfwordTransfer{ .offset = offset,
 | 
				
			||||||
                                 .half   = half,
 | 
					                                 .half   = half,
 | 
				
			||||||
@@ -125,44 +135,99 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Block data transfer
 | 
					        // Block data transfer
 | 
				
			||||||
    } else if ((insn & 0x0E000000) == 0x08000000) {
 | 
					    } else if ((insn & 0x0E000000) == 0x08000000) {
 | 
				
			||||||
        /*static constexpr array<stringv, 2> syn = { "STM", "LDM" };
 | 
					        uint16_t regs = bit_range(insn, 0, 15);
 | 
				
			||||||
 | 
					        uint8_t rn    = bit_range(insn, 16, 19);
 | 
				
			||||||
 | 
					        bool load     = get_bit(insn, 20);
 | 
				
			||||||
 | 
					        bool write    = get_bit(insn, 21);
 | 
				
			||||||
 | 
					        bool s        = get_bit(insn, 22);
 | 
				
			||||||
 | 
					        bool up       = get_bit(insn, 23);
 | 
				
			||||||
 | 
					        bool pre      = get_bit(insn, 24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint16_t regs = get_bit_range(insn, 0, 15);
 | 
					        data = BlockDataTransfer{ .regs  = regs,
 | 
				
			||||||
        uint8_t rn    = get_bit_range(insn, 16, 19);
 | 
					                                  .rn    = rn,
 | 
				
			||||||
        bool load     = get_nth_bit(insn, 20);
 | 
					                                  .load  = load,
 | 
				
			||||||
        bool write    = get_nth_bit(insn, 21);
 | 
					                                  .write = write,
 | 
				
			||||||
        bool s        = get_nth_bit(insn, 22);
 | 
					                                  .s     = s,
 | 
				
			||||||
        bool up       = get_nth_bit(insn, 23);
 | 
					                                  .up    = up,
 | 
				
			||||||
        bool pre      = get_nth_bit(insn, 24);
 | 
					                                  .pre   = pre };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // disassembly
 | 
					        // Data Processing
 | 
				
			||||||
        {
 | 
					    } else if ((insn & 0x0C000000) == 0x00000000) {
 | 
				
			||||||
            uint8_t lpu = load << 2 | pre << 1 | up;
 | 
					        uint8_t rd    = bit_range(insn, 12, 15);
 | 
				
			||||||
            std::string addr_mode;
 | 
					        uint8_t rn    = bit_range(insn, 16, 19);
 | 
				
			||||||
 | 
					        bool set      = get_bit(insn, 20);
 | 
				
			||||||
 | 
					        OpCode opcode = static_cast<OpCode>(bit_range(insn, 21, 24));
 | 
				
			||||||
 | 
					        bool imm      = get_bit(insn, 25);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            switch(lpu) {
 | 
					        if ((opcode == OpCode::TST || opcode == OpCode::CMP) && !set) {
 | 
				
			||||||
 | 
					            data = PsrTransfer{ .operand = rd,
 | 
				
			||||||
 | 
					                                .spsr    = get_bit(insn, 22),
 | 
				
			||||||
 | 
					                                .type    = PsrTransfer::Type::Mrs,
 | 
				
			||||||
 | 
					                                .imm     = 0 };
 | 
				
			||||||
 | 
					        } else if ((opcode == OpCode::TEQ || opcode == OpCode::CMN) && !set) {
 | 
				
			||||||
 | 
					            bool imm         = get_bit(insn, 25);
 | 
				
			||||||
 | 
					            uint32_t operand = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (imm) {
 | 
				
			||||||
 | 
					                operand = bit_range(insn, 0, 3);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                uint32_t immediate = bit_range(insn, 0, 7);
 | 
				
			||||||
 | 
					                uint8_t rotate     = bit_range(insn, 8, 11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                operand = std::rotr(immediate, rotate * 2);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }*/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = Undefined{};
 | 
					            data = PsrTransfer{ .operand = operand,
 | 
				
			||||||
 | 
					                                .spsr    = get_bit(insn, 22),
 | 
				
			||||||
 | 
					                                .type    = (get_bit(insn, 16)
 | 
				
			||||||
 | 
					                                              ? PsrTransfer::Type::Msr
 | 
				
			||||||
 | 
					                                              : PsrTransfer::Type::Msr_flg),
 | 
				
			||||||
 | 
					                                .imm     = imm };
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            std::variant<Shift, uint32_t> operand;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Software Interrupt
 | 
					            if (imm) {
 | 
				
			||||||
        // What to do here?
 | 
					                uint32_t immediate = bit_range(insn, 0, 7);
 | 
				
			||||||
 | 
					                uint8_t rotate     = bit_range(insn, 8, 11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                operand = std::rotr(immediate, rotate * 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                uint8_t rm = bit_range(insn, 0, 3);
 | 
				
			||||||
 | 
					                bool reg   = get_bit(insn, 4);
 | 
				
			||||||
 | 
					                ShiftType shift_type =
 | 
				
			||||||
 | 
					                  static_cast<ShiftType>(bit_range(insn, 5, 6));
 | 
				
			||||||
 | 
					                uint8_t sh_operand = bit_range(insn, (reg ? 8 : 7), 11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                operand = Shift{ .rm   = rm,
 | 
				
			||||||
 | 
					                                 .data = ShiftData{ .type      = shift_type,
 | 
				
			||||||
 | 
					                                                    .immediate = !reg,
 | 
				
			||||||
 | 
					                                                    .operand   = sh_operand } };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            data = DataProcessing{ .operand = operand,
 | 
				
			||||||
 | 
					                                   .rd      = rd,
 | 
				
			||||||
 | 
					                                   .rn      = rn,
 | 
				
			||||||
 | 
					                                   .set     = set,
 | 
				
			||||||
 | 
					                                   .opcode  = opcode };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Software interrupt
 | 
				
			||||||
    } else if ((insn & 0x0F000000) == 0x0F000000) {
 | 
					    } else if ((insn & 0x0F000000) == 0x0F000000) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = SoftwareInterrupt{};
 | 
					        data = SoftwareInterrupt{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Coprocessor data transfer
 | 
					        // Coprocessor data transfer
 | 
				
			||||||
    } else if ((insn & 0x0E000000) == 0x0C000000) {
 | 
					    } else if ((insn & 0x0E000000) == 0x0C000000) {
 | 
				
			||||||
        uint8_t offset = get_bit_range(insn, 0, 7);
 | 
					        uint8_t offset = bit_range(insn, 0, 7);
 | 
				
			||||||
        uint8_t cpn    = get_bit_range(insn, 8, 11);
 | 
					        uint8_t cpn    = bit_range(insn, 8, 11);
 | 
				
			||||||
        uint8_t crd    = get_bit_range(insn, 12, 15);
 | 
					        uint8_t crd    = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t rn     = get_bit_range(insn, 16, 19);
 | 
					        uint8_t rn     = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool load      = get_nth_bit(insn, 20);
 | 
					        bool load      = get_bit(insn, 20);
 | 
				
			||||||
        bool write     = get_nth_bit(insn, 21);
 | 
					        bool write     = get_bit(insn, 21);
 | 
				
			||||||
        bool len       = get_nth_bit(insn, 22);
 | 
					        bool len       = get_bit(insn, 22);
 | 
				
			||||||
        bool up        = get_nth_bit(insn, 23);
 | 
					        bool up        = get_bit(insn, 23);
 | 
				
			||||||
        bool pre       = get_nth_bit(insn, 24);
 | 
					        bool pre       = get_bit(insn, 24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = CoprocessorDataTransfer{ .offset = offset,
 | 
					        data = CoprocessorDataTransfer{ .offset = offset,
 | 
				
			||||||
                                        .cpn    = cpn,
 | 
					                                        .cpn    = cpn,
 | 
				
			||||||
@@ -176,12 +241,12 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Coprocessor data operation
 | 
					        // Coprocessor data operation
 | 
				
			||||||
    } else if ((insn & 0x0F000010) == 0x0E000000) {
 | 
					    } else if ((insn & 0x0F000010) == 0x0E000000) {
 | 
				
			||||||
        uint8_t crm    = get_bit_range(insn, 0, 4);
 | 
					        uint8_t crm    = bit_range(insn, 0, 4);
 | 
				
			||||||
        uint8_t cp     = get_bit_range(insn, 5, 7);
 | 
					        uint8_t cp     = bit_range(insn, 5, 7);
 | 
				
			||||||
        uint8_t cpn    = get_bit_range(insn, 8, 11);
 | 
					        uint8_t cpn    = bit_range(insn, 8, 11);
 | 
				
			||||||
        uint8_t crd    = get_bit_range(insn, 12, 15);
 | 
					        uint8_t crd    = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t crn    = get_bit_range(insn, 16, 19);
 | 
					        uint8_t crn    = bit_range(insn, 16, 19);
 | 
				
			||||||
        uint8_t cp_opc = get_bit_range(insn, 20, 23);
 | 
					        uint8_t cp_opc = bit_range(insn, 20, 23);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = CoprocessorDataOperation{ .crm    = crm,
 | 
					        data = CoprocessorDataOperation{ .crm    = crm,
 | 
				
			||||||
                                         .cp     = cp,
 | 
					                                         .cp     = cp,
 | 
				
			||||||
@@ -192,13 +257,13 @@ ArmInstruction::ArmInstruction(uint32_t insn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Coprocessor register transfer
 | 
					        // Coprocessor register transfer
 | 
				
			||||||
    } else if ((insn & 0x0F000010) == 0x0E000010) {
 | 
					    } else if ((insn & 0x0F000010) == 0x0E000010) {
 | 
				
			||||||
        uint8_t crm    = get_bit_range(insn, 0, 4);
 | 
					        uint8_t crm    = bit_range(insn, 0, 4);
 | 
				
			||||||
        uint8_t cp     = get_bit_range(insn, 5, 7);
 | 
					        uint8_t cp     = bit_range(insn, 5, 7);
 | 
				
			||||||
        uint8_t cpn    = get_bit_range(insn, 8, 11);
 | 
					        uint8_t cpn    = bit_range(insn, 8, 11);
 | 
				
			||||||
        uint8_t rd     = get_bit_range(insn, 12, 15);
 | 
					        uint8_t rd     = bit_range(insn, 12, 15);
 | 
				
			||||||
        uint8_t crn    = get_bit_range(insn, 16, 19);
 | 
					        uint8_t crn    = bit_range(insn, 16, 19);
 | 
				
			||||||
        bool load      = get_nth_bit(insn, 20);
 | 
					        bool load      = get_bit(insn, 20);
 | 
				
			||||||
        uint8_t cp_opc = get_bit_range(insn, 21, 23);
 | 
					        uint8_t cp_opc = bit_range(insn, 21, 23);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = CoprocessorRegisterTransfer{ .crm    = crm,
 | 
					        data = CoprocessorRegisterTransfer{ .crm    = crm,
 | 
				
			||||||
                                            .cp     = cp,
 | 
					                                            .cp     = cp,
 | 
				
			||||||
@@ -319,6 +384,81 @@ ArmInstruction::disassemble() {
 | 
				
			|||||||
              (data.pre ? expression : ""),
 | 
					              (data.pre ? expression : ""),
 | 
				
			||||||
              (data.pre ? (data.write ? "!" : "") : expression));
 | 
					              (data.pre ? (data.write ? "!" : "") : expression));
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        [this](BlockDataTransfer& data) {
 | 
				
			||||||
 | 
					            std::string regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (uint8_t i = 0; i < 16; i++) {
 | 
				
			||||||
 | 
					                if (get_bit(data.regs, i))
 | 
				
			||||||
 | 
					                    fmt::format_to(std::back_inserter(regs), "R{:d},", i);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            regs.pop_back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return fmt::format("{}{}{}{} R{:d}{},{{{}}}{}",
 | 
				
			||||||
 | 
					                               (data.load ? "LDM" : "STM"),
 | 
				
			||||||
 | 
					                               condition,
 | 
				
			||||||
 | 
					                               (data.up ? 'I' : 'D'),
 | 
				
			||||||
 | 
					                               (data.pre ? 'B' : 'A'),
 | 
				
			||||||
 | 
					                               data.rn,
 | 
				
			||||||
 | 
					                               (data.write ? "!" : ""),
 | 
				
			||||||
 | 
					                               regs,
 | 
				
			||||||
 | 
					                               (data.s ? "^" : ""));
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        [this](PsrTransfer& data) {
 | 
				
			||||||
 | 
					            if (data.type == PsrTransfer::Type::Mrs) {
 | 
				
			||||||
 | 
					                return fmt::format("MRS{} R{:d},{}",
 | 
				
			||||||
 | 
					                                   condition,
 | 
				
			||||||
 | 
					                                   data.operand,
 | 
				
			||||||
 | 
					                                   (data.spsr ? "SPSR_all" : "CPSR_all"));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return fmt::format(
 | 
				
			||||||
 | 
					                  "MSR{} {}_{},{}{}",
 | 
				
			||||||
 | 
					                  condition,
 | 
				
			||||||
 | 
					                  (data.spsr ? "SPSR" : "CPSR"),
 | 
				
			||||||
 | 
					                  (data.type == PsrTransfer::Type::Msr_flg ? "flg" : "all"),
 | 
				
			||||||
 | 
					                  (data.imm ? '#' : 'R'),
 | 
				
			||||||
 | 
					                  data.operand);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        [this](DataProcessing& data) {
 | 
				
			||||||
 | 
					            std::string op_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (const uint32_t* operand =
 | 
				
			||||||
 | 
					                  std::get_if<uint32_t>(&data.operand)) {
 | 
				
			||||||
 | 
					                op_2 = fmt::format("#{:d}", *operand);
 | 
				
			||||||
 | 
					            } else if (const Shift* shift = std::get_if<Shift>(&data.operand)) {
 | 
				
			||||||
 | 
					                op_2 = fmt::format("R{:d},{} {}{:d}",
 | 
				
			||||||
 | 
					                                   shift->rm,
 | 
				
			||||||
 | 
					                                   shift->data.type,
 | 
				
			||||||
 | 
					                                   (shift->data.immediate ? '#' : 'R'),
 | 
				
			||||||
 | 
					                                   shift->data.operand);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (data.opcode) {
 | 
				
			||||||
 | 
					                case OpCode::MOV:
 | 
				
			||||||
 | 
					                case OpCode::MVN:
 | 
				
			||||||
 | 
					                    return fmt::format("{}{}{} R{:d},{}",
 | 
				
			||||||
 | 
					                                       data.opcode,
 | 
				
			||||||
 | 
					                                       condition,
 | 
				
			||||||
 | 
					                                       (data.set ? "S" : ""),
 | 
				
			||||||
 | 
					                                       data.rd,
 | 
				
			||||||
 | 
					                                       op_2);
 | 
				
			||||||
 | 
					                case OpCode::TST:
 | 
				
			||||||
 | 
					                case OpCode::TEQ:
 | 
				
			||||||
 | 
					                case OpCode::CMP:
 | 
				
			||||||
 | 
					                case OpCode::CMN:
 | 
				
			||||||
 | 
					                    return fmt::format(
 | 
				
			||||||
 | 
					                      "{}{} R{:d},{}", data.opcode, condition, data.rn, op_2);
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    return fmt::format("{}{}{} R{:d},R{:d},{}",
 | 
				
			||||||
 | 
					                                       data.opcode,
 | 
				
			||||||
 | 
					                                       condition,
 | 
				
			||||||
 | 
					                                       (data.set ? "S" : ""),
 | 
				
			||||||
 | 
					                                       data.rd,
 | 
				
			||||||
 | 
					                                       data.rn,
 | 
				
			||||||
 | 
					                                       op_2);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        [this](SoftwareInterrupt) { return fmt::format("SWI{}", condition); },
 | 
					        [this](SoftwareInterrupt) { return fmt::format("SWI{}", condition); },
 | 
				
			||||||
        [this](CoprocessorDataTransfer& data) {
 | 
					        [this](CoprocessorDataTransfer& data) {
 | 
				
			||||||
            std::string expression = fmt::format(",#{:d}", data.offset);
 | 
					            std::string expression = fmt::format(",#{:d}", data.offset);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,16 @@
 | 
				
			|||||||
Psr::Psr(uint32_t raw)
 | 
					Psr::Psr(uint32_t raw)
 | 
				
			||||||
  : psr(raw & PSR_CLEAR_RESERVED) {}
 | 
					  : psr(raw & PSR_CLEAR_RESERVED) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t
 | 
				
			||||||
 | 
					Psr::raw() const {
 | 
				
			||||||
 | 
					    return psr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					Psr::set_all(uint32_t raw) {
 | 
				
			||||||
 | 
					    psr = raw & ~PSR_CLEAR_RESERVED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Mode
 | 
					Mode
 | 
				
			||||||
Psr::mode() const {
 | 
					Psr::mode() const {
 | 
				
			||||||
    return static_cast<Mode>(psr & ~PSR_CLEAR_MODE);
 | 
					    return static_cast<Mode>(psr & ~PSR_CLEAR_MODE);
 | 
				
			||||||
@@ -18,20 +28,20 @@ Psr::set_mode(Mode mode) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
State
 | 
					State
 | 
				
			||||||
Psr::state() const {
 | 
					Psr::state() const {
 | 
				
			||||||
    return static_cast<State>(get_nth_bit(psr, 5));
 | 
					    return static_cast<State>(get_bit(psr, 5));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
Psr::set_state(State state) {
 | 
					Psr::set_state(State state) {
 | 
				
			||||||
    chg_nth_bit(psr, 5, static_cast<bool>(state));
 | 
					    chg_bit(psr, 5, static_cast<bool>(state));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GET_SET_NTH_BIT_FUNCTIONS(name, n)                                     \
 | 
					#define GET_SET_NTH_BIT_FUNCTIONS(name, n)                                     \
 | 
				
			||||||
    bool Psr::name() const {                                                   \
 | 
					    bool Psr::name() const {                                                   \
 | 
				
			||||||
        return get_nth_bit(psr, n);                                            \
 | 
					        return get_bit(psr, n);                                                \
 | 
				
			||||||
    }                                                                          \
 | 
					    }                                                                          \
 | 
				
			||||||
    void Psr::set_##name(bool val) {                                           \
 | 
					    void Psr::set_##name(bool val) {                                           \
 | 
				
			||||||
        chg_nth_bit(psr, n, val);                                              \
 | 
					        chg_bit(psr, n, val);                                                  \
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GET_SET_NTH_BIT_FUNCTIONS(fiq_disabled, 6)
 | 
					GET_SET_NTH_BIT_FUNCTIONS(fiq_disabled, 6)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,13 +35,45 @@ operator<<(std::ostream& os, const Condition cond) {
 | 
				
			|||||||
    return os;
 | 
					    return os;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::ostream&
 | 
				
			||||||
 | 
					operator<<(std::ostream& os, const OpCode opcode) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CASE(opcode)                                                           \
 | 
				
			||||||
 | 
					    case OpCode::opcode:                                                       \
 | 
				
			||||||
 | 
					        os << #opcode;                                                         \
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (opcode) {
 | 
				
			||||||
 | 
					        CASE(AND)
 | 
				
			||||||
 | 
					        CASE(EOR)
 | 
				
			||||||
 | 
					        CASE(SUB)
 | 
				
			||||||
 | 
					        CASE(RSB)
 | 
				
			||||||
 | 
					        CASE(ADD)
 | 
				
			||||||
 | 
					        CASE(ADC)
 | 
				
			||||||
 | 
					        CASE(SBC)
 | 
				
			||||||
 | 
					        CASE(RSC)
 | 
				
			||||||
 | 
					        CASE(TST)
 | 
				
			||||||
 | 
					        CASE(TEQ)
 | 
				
			||||||
 | 
					        CASE(CMP)
 | 
				
			||||||
 | 
					        CASE(CMN)
 | 
				
			||||||
 | 
					        CASE(ORR)
 | 
				
			||||||
 | 
					        CASE(MOV)
 | 
				
			||||||
 | 
					        CASE(BIC)
 | 
				
			||||||
 | 
					        CASE(MVN)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef CASE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return os;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t
 | 
					uint32_t
 | 
				
			||||||
eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry) {
 | 
					eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry) {
 | 
				
			||||||
    switch (shift_type) {
 | 
					    switch (shift_type) {
 | 
				
			||||||
        case ShiftType::LSL:
 | 
					        case ShiftType::LSL:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (amount > 0 && amount <= 32)
 | 
					            if (amount > 0 && amount <= 32)
 | 
				
			||||||
                carry = get_nth_bit(value, 32 - amount);
 | 
					                carry = get_bit(value, 32 - amount);
 | 
				
			||||||
            else if (amount > 32)
 | 
					            else if (amount > 32)
 | 
				
			||||||
                carry = 0;
 | 
					                carry = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,28 +81,28 @@ eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry) {
 | 
				
			|||||||
        case ShiftType::LSR:
 | 
					        case ShiftType::LSR:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (amount > 0 && amount <= 32)
 | 
					            if (amount > 0 && amount <= 32)
 | 
				
			||||||
                carry = get_nth_bit(value, amount - 1);
 | 
					                carry = get_bit(value, amount - 1);
 | 
				
			||||||
            else if (amount > 32)
 | 
					            else if (amount > 32)
 | 
				
			||||||
                carry = 0;
 | 
					                carry = 0;
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                carry = get_nth_bit(value, 31);
 | 
					                carry = get_bit(value, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return value >> amount;
 | 
					            return value >> amount;
 | 
				
			||||||
        case ShiftType::ASR:
 | 
					        case ShiftType::ASR:
 | 
				
			||||||
            if (amount > 0 && amount <= 32)
 | 
					            if (amount > 0 && amount <= 32)
 | 
				
			||||||
                carry = get_nth_bit(value, amount - 1);
 | 
					                carry = get_bit(value, amount - 1);
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                carry = get_nth_bit(value, 31);
 | 
					                carry = get_bit(value, 31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return static_cast<int32_t>(value) >> amount;
 | 
					            return static_cast<int32_t>(value) >> amount;
 | 
				
			||||||
        case ShiftType::ROR:
 | 
					        case ShiftType::ROR:
 | 
				
			||||||
            if (amount == 0) {
 | 
					            if (amount == 0) {
 | 
				
			||||||
                bool old_carry = carry;
 | 
					                bool old_carry = carry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                carry = get_nth_bit(value, 0);
 | 
					                carry = get_bit(value, 0);
 | 
				
			||||||
                return (value >> 1) | (old_carry << 31);
 | 
					                return (value >> 1) | (old_carry << 31);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                carry = get_nth_bit(value, (amount % 32 + 31) % 32);
 | 
					                carry = get_bit(value, (amount % 32 + 31) % 32);
 | 
				
			||||||
                return std::rotr(value, amount);
 | 
					                return std::rotr(value, amount);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,32 +7,32 @@ using std::size_t;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<std::integral Int>
 | 
					template<std::integral Int>
 | 
				
			||||||
inline bool
 | 
					inline bool
 | 
				
			||||||
get_nth_bit(Int num, size_t n) {
 | 
					get_bit(Int num, size_t n) {
 | 
				
			||||||
    return (num >> n) & 1;
 | 
					    return (num >> n) & 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<std::integral Int>
 | 
					template<std::integral Int>
 | 
				
			||||||
inline void
 | 
					inline void
 | 
				
			||||||
set_nth_bit(Int& num, size_t n) {
 | 
					set_bit(Int& num, size_t n) {
 | 
				
			||||||
    num |= (1 << n);
 | 
					    num |= (1 << n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<std::integral Int>
 | 
					template<std::integral Int>
 | 
				
			||||||
inline void
 | 
					inline void
 | 
				
			||||||
rst_nth_bit(Int& num, size_t n) {
 | 
					rst_bit(Int& num, size_t n) {
 | 
				
			||||||
    num &= ~(1 << n);
 | 
					    num &= ~(1 << n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<std::integral Int>
 | 
					template<std::integral Int>
 | 
				
			||||||
inline void
 | 
					inline void
 | 
				
			||||||
chg_nth_bit(Int& num, size_t n, bool x) {
 | 
					chg_bit(Int& num, size_t n, bool x) {
 | 
				
			||||||
    num = (num & ~(1 << n)) | (x << n);
 | 
					    num = (num & ~(1 << n)) | (x << n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// read range of bits from start to end inclusive
 | 
					/// read range of bits from start to end inclusive
 | 
				
			||||||
template<std::integral Int>
 | 
					template<std::integral Int>
 | 
				
			||||||
inline Int
 | 
					inline Int
 | 
				
			||||||
get_bit_range(Int num, size_t start, size_t end) {
 | 
					bit_range(Int num, size_t start, size_t end) {
 | 
				
			||||||
    // NOTE: we do not require -1 if it is a signed integral
 | 
					    // NOTE: we do not require -1 if it is a signed integral
 | 
				
			||||||
    Int left =
 | 
					    Int left =
 | 
				
			||||||
      std::numeric_limits<Int>::digits - (std::is_unsigned<Int>::value) - end;
 | 
					      std::numeric_limits<Int>::digits - (std::is_unsigned<Int>::value) - end;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user