add a basic structure for disassembler + executor
Instructions added Branch and Exchange (BX) Branch and Link (B) Multiply and Accumulate (MUL, MLA) Multiply Long and Accumulate (SMULL, SMLAL, UMULL, UMLAL) Single data swap (SWP) [WIP] Halfword Transfer (STRH, LDRH) Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
		@@ -1,43 +0,0 @@
 | 
			
		||||
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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
};
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
lib_sources += files(
 | 
			
		||||
)
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
#include "cpu.hh"
 | 
			
		||||
#include "cpu/utility.hh"
 | 
			
		||||
#include "util/log.hh"
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
Cpu::Cpu(Bus bus)
 | 
			
		||||
using namespace logger;
 | 
			
		||||
 | 
			
		||||
Cpu::Cpu(std::shared_ptr<Bus> bus)
 | 
			
		||||
  : gpr(0)
 | 
			
		||||
  , cpsr(0)
 | 
			
		||||
  , spsr(0)
 | 
			
		||||
@@ -14,6 +17,7 @@ Cpu::Cpu(Bus bus)
 | 
			
		||||
    cpsr.set_irq_disabled(true);
 | 
			
		||||
    cpsr.set_fiq_disabled(true);
 | 
			
		||||
    cpsr.set_state(State::Arm);
 | 
			
		||||
    log_info("CPU successfully initialised");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* change modes */
 | 
			
		||||
@@ -103,15 +107,13 @@ Cpu::chg_mode(Mode from, Mode to) {
 | 
			
		||||
    cpsr.set_mode(to);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  set register
 | 
			
		||||
inline uint32_t&
 | 
			
		||||
Cpu::operator[](uint8_t idx) {
 | 
			
		||||
    // avoid unneeded complexity like index checks
 | 
			
		||||
    return gpr[idx];
 | 
			
		||||
}
 | 
			
		||||
void
 | 
			
		||||
Cpu::step() {
 | 
			
		||||
    uint32_t insn = 0xffffffff;
 | 
			
		||||
 | 
			
		||||
// get register
 | 
			
		||||
inline const uint32_t&
 | 
			
		||||
Cpu::operator[](uint8_t idx) const {
 | 
			
		||||
    return gpr[idx];
 | 
			
		||||
    if (cpsr.state() == State::Arm) {
 | 
			
		||||
        std::string disassembled = exec_arm(insn);
 | 
			
		||||
        log_info("{:#010X} : {}", gpr[15], disassembled);
 | 
			
		||||
        gpr[15] += ARM_INSTRUCTION_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,8 @@ using std::size_t;
 | 
			
		||||
 | 
			
		||||
class Cpu {
 | 
			
		||||
  public:
 | 
			
		||||
    Cpu(Bus bus);
 | 
			
		||||
    Cpu(std::shared_ptr<Bus> bus);
 | 
			
		||||
    void step();
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    static constexpr size_t GPR_FIQ_BANKED_FIRST = 8;
 | 
			
		||||
@@ -35,7 +36,7 @@ class Cpu {
 | 
			
		||||
    uint32_t gpr[GPR_VISIBLE_COUNT]; // general purpose registers
 | 
			
		||||
    Psr cpsr;                        // current program status register
 | 
			
		||||
    Psr spsr;                        // status program status register
 | 
			
		||||
    Bus bus;
 | 
			
		||||
    std::shared_ptr<Bus> bus;
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        uint32_t fiq[GPR_FIQ_BANKED_COUNT];
 | 
			
		||||
@@ -57,7 +58,5 @@ class Cpu {
 | 
			
		||||
    } spsr_banked; // banked saved program status registers
 | 
			
		||||
 | 
			
		||||
    void chg_mode(Mode from, Mode to);
 | 
			
		||||
 | 
			
		||||
    uint32_t& operator[](uint8_t idx);
 | 
			
		||||
    const uint32_t& operator[](uint8_t idx) const;
 | 
			
		||||
    std::string exec_arm(uint32_t insn);
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										294
									
								
								src/cpu/instruction.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								src/cpu/instruction.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,294 @@
 | 
			
		||||
#include "cpu.hh"
 | 
			
		||||
#include "cpu/utility.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include "util/log.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
using namespace logger;
 | 
			
		||||
 | 
			
		||||
std::string
 | 
			
		||||
Cpu::exec_arm(uint32_t insn) {
 | 
			
		||||
    Condition cond = static_cast<Condition>(get_bit_range(insn, 28, 31));
 | 
			
		||||
    std::string disassembled;
 | 
			
		||||
 | 
			
		||||
    auto pc_error = [](uint8_t r, const char* syn) {
 | 
			
		||||
        if (r == 15)
 | 
			
		||||
            log_error("Using PC (R15) as operand in {}", syn);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    auto pc_undefined = [](uint8_t r, const char* syn) {
 | 
			
		||||
        if (r == 15)
 | 
			
		||||
            log_warn("Using PC (R15) as operand in {}", syn);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Branch and exhcange
 | 
			
		||||
    if ((insn & 0x0ffffff0) == 0x012fff10) {
 | 
			
		||||
        static constexpr char syn[] = "BX";
 | 
			
		||||
 | 
			
		||||
        uint8_t rn = insn & 0b1111;
 | 
			
		||||
 | 
			
		||||
        pc_undefined(rn, syn);
 | 
			
		||||
 | 
			
		||||
        disassembled = fmt::format("{}{} R{:d}", syn, cond, rn);
 | 
			
		||||
 | 
			
		||||
        if (cpsr.condition(cond)) {
 | 
			
		||||
            State state = static_cast<State>(rn & 1);
 | 
			
		||||
 | 
			
		||||
            // set state
 | 
			
		||||
            cpsr.set_state(state);
 | 
			
		||||
 | 
			
		||||
            // copy to PC
 | 
			
		||||
            gpr[15] = gpr[rn];
 | 
			
		||||
 | 
			
		||||
            // ignore [1:0] bits for arm and 0 bit for thumb
 | 
			
		||||
            rst_nth_bit(gpr[15], 0);
 | 
			
		||||
            if (state == State::Arm)
 | 
			
		||||
                rst_nth_bit(gpr[15], 1);
 | 
			
		||||
        }
 | 
			
		||||
        // Branch
 | 
			
		||||
    } else if ((insn & 0x0e000000) == 0x0a000000) {
 | 
			
		||||
        static constexpr char syn[] = "B";
 | 
			
		||||
 | 
			
		||||
        bool link       = get_nth_bit(insn, 24);
 | 
			
		||||
        uint32_t offset = get_bit_range(insn, 0, 23);
 | 
			
		||||
 | 
			
		||||
        disassembled =
 | 
			
		||||
          fmt::format("{}{}{} {:#08X}", syn, (link ? "L" : ""), cond, offset);
 | 
			
		||||
 | 
			
		||||
        if (cpsr.condition(cond)) {
 | 
			
		||||
            // lsh 2 and sign extend the 26 bit offset to 32
 | 
			
		||||
            // bits
 | 
			
		||||
            offset <<= 2;
 | 
			
		||||
            if (get_nth_bit(offset, 25))
 | 
			
		||||
                offset |= 0xFC000000;
 | 
			
		||||
 | 
			
		||||
            if (link)
 | 
			
		||||
                gpr[14] = gpr[15] - ARM_INSTRUCTION_SIZE;
 | 
			
		||||
 | 
			
		||||
            gpr[15] += offset;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Multiply
 | 
			
		||||
    } else if ((insn & 0x0fc000f0) == 0x00000090) {
 | 
			
		||||
        static constexpr char syn[2][4] = { "MUL", "MLA" };
 | 
			
		||||
 | 
			
		||||
        uint8_t rm = get_bit_range(insn, 0, 3);
 | 
			
		||||
        uint8_t rs = get_bit_range(insn, 8, 11);
 | 
			
		||||
        uint8_t rn = get_bit_range(insn, 12, 15);
 | 
			
		||||
        uint8_t rd = get_bit_range(insn, 16, 19);
 | 
			
		||||
        bool s     = get_nth_bit(insn, 20);
 | 
			
		||||
        bool a     = get_nth_bit(insn, 21);
 | 
			
		||||
 | 
			
		||||
        if (rd == rm)
 | 
			
		||||
            log_error("rd and rm are not distinct in {} : {:d}", syn[a], rd);
 | 
			
		||||
 | 
			
		||||
        pc_error(rd, syn[a]);
 | 
			
		||||
        pc_error(rm, syn[a]);
 | 
			
		||||
        pc_error(rs, syn[a]);
 | 
			
		||||
 | 
			
		||||
        if (a) {
 | 
			
		||||
            pc_error(rn, syn[a]);
 | 
			
		||||
            disassembled = fmt::format("{}{}{} R{:d},R{:d},R{:d},R{:d}",
 | 
			
		||||
                                       syn[a],
 | 
			
		||||
                                       cond,
 | 
			
		||||
                                       (s ? "S" : ""),
 | 
			
		||||
                                       rd,
 | 
			
		||||
                                       rm,
 | 
			
		||||
                                       rs,
 | 
			
		||||
                                       rn);
 | 
			
		||||
        } else {
 | 
			
		||||
            disassembled = fmt::format("{}{}{} R{:d},R{:d},R{:d}",
 | 
			
		||||
                                       syn[a],
 | 
			
		||||
                                       cond,
 | 
			
		||||
                                       (s ? "S" : ""),
 | 
			
		||||
                                       rd,
 | 
			
		||||
                                       rm,
 | 
			
		||||
                                       rs);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cpsr.condition(cond)) {
 | 
			
		||||
            gpr[rd] = gpr[rm] * gpr[rs] + (a ? gpr[rn] : 0);
 | 
			
		||||
 | 
			
		||||
            if (s) {
 | 
			
		||||
                cpsr.set_z(!static_cast<bool>(gpr[rd]));
 | 
			
		||||
                cpsr.set_n(get_nth_bit(gpr[rd], 31));
 | 
			
		||||
                cpsr.set_c(0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Multiply long
 | 
			
		||||
    } else if ((insn & 0x0f8000f0) == 0x00800090) {
 | 
			
		||||
        static constexpr char syn[2][2][6] = { { "SMULL", "SMLAL" },
 | 
			
		||||
                                               { "UMULL", "UMLAL" } };
 | 
			
		||||
 | 
			
		||||
        uint8_t rm   = get_bit_range(insn, 0, 3);
 | 
			
		||||
        uint8_t rs   = get_bit_range(insn, 8, 11);
 | 
			
		||||
        uint8_t rdlo = get_bit_range(insn, 12, 15);
 | 
			
		||||
        uint8_t rdhi = get_bit_range(insn, 16, 19);
 | 
			
		||||
        bool s       = get_nth_bit(insn, 20);
 | 
			
		||||
        bool a       = get_nth_bit(insn, 21);
 | 
			
		||||
        bool u       = get_nth_bit(insn, 22);
 | 
			
		||||
 | 
			
		||||
        if (rdhi == rdlo || rdhi == rm || rdlo == rm)
 | 
			
		||||
            log_error("rdhi, rdlo and rm are not distinct in {}", syn[u][a]);
 | 
			
		||||
 | 
			
		||||
        pc_error(rdhi, syn[u][a]);
 | 
			
		||||
        pc_error(rdlo, syn[u][a]);
 | 
			
		||||
        pc_error(rm, syn[u][a]);
 | 
			
		||||
        pc_error(rs, syn[u][a]);
 | 
			
		||||
 | 
			
		||||
        disassembled = fmt::format("{}{}{} R{:d},R{:d},R{:d},R{:d}",
 | 
			
		||||
                                   syn[u][a],
 | 
			
		||||
                                   cond,
 | 
			
		||||
                                   (s ? "S" : ""),
 | 
			
		||||
                                   rdlo,
 | 
			
		||||
                                   rdhi,
 | 
			
		||||
                                   rm,
 | 
			
		||||
                                   rs);
 | 
			
		||||
 | 
			
		||||
        if (cpsr.condition(cond)) {
 | 
			
		||||
            if (u) {
 | 
			
		||||
                uint64_t eval = static_cast<uint64_t>(gpr[rm]) *
 | 
			
		||||
                                  static_cast<uint64_t>(gpr[rs]) +
 | 
			
		||||
                                (a ? static_cast<uint64_t>(gpr[rdhi]) << 32 |
 | 
			
		||||
                                       static_cast<uint64_t>(gpr[rdlo])
 | 
			
		||||
                                   : 0);
 | 
			
		||||
 | 
			
		||||
                gpr[rdlo] = get_bit_range(eval, 0, 31);
 | 
			
		||||
                gpr[rdhi] = get_bit_range(eval, 32, 63);
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                int64_t eval = static_cast<uint64_t>(gpr[rm]) *
 | 
			
		||||
                                 static_cast<int64_t>(gpr[rs]) +
 | 
			
		||||
                               (a ? static_cast<int64_t>(gpr[rdhi]) << 32 |
 | 
			
		||||
                                      static_cast<int64_t>(gpr[rdlo])
 | 
			
		||||
                                  : 0);
 | 
			
		||||
 | 
			
		||||
                gpr[rdlo] = get_bit_range(eval, 0, 31);
 | 
			
		||||
                gpr[rdhi] = get_bit_range(eval, 32, 63);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (s) {
 | 
			
		||||
                cpsr.set_z(!(static_cast<bool>(gpr[rdhi]) ||
 | 
			
		||||
                             static_cast<bool>(gpr[rdlo])));
 | 
			
		||||
                cpsr.set_n(get_nth_bit(gpr[rdhi], 31));
 | 
			
		||||
                cpsr.set_c(0);
 | 
			
		||||
                cpsr.set_v(0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Single data swap
 | 
			
		||||
    } else if ((insn & 0x0fb00ff0) == 0x01000090) {
 | 
			
		||||
        static constexpr char syn[] = "SWP";
 | 
			
		||||
 | 
			
		||||
        uint8_t rm = get_bit_range(insn, 0, 3);
 | 
			
		||||
        uint8_t rd = get_bit_range(insn, 12, 15);
 | 
			
		||||
        uint8_t rn = get_bit_range(insn, 16, 19);
 | 
			
		||||
        bool b     = get_nth_bit(insn, 22);
 | 
			
		||||
 | 
			
		||||
        pc_undefined(rm, syn);
 | 
			
		||||
        pc_undefined(rn, syn);
 | 
			
		||||
        pc_undefined(rd, syn);
 | 
			
		||||
 | 
			
		||||
        disassembled = fmt::format(
 | 
			
		||||
          "{}{}{} R{:d},R{:d},[R{:d}]", syn, cond, (b ? "B" : ""), rd, rm, rn);
 | 
			
		||||
 | 
			
		||||
        if (cpsr.condition(cond)) {
 | 
			
		||||
            if (b) {
 | 
			
		||||
                gpr[rd] = bus->read_byte(gpr[rn]);
 | 
			
		||||
                bus->write_byte(gpr[rn], gpr[rm] & 0xFF);
 | 
			
		||||
            } else {
 | 
			
		||||
                gpr[rd] = bus->read_word(gpr[rn]);
 | 
			
		||||
                bus->write_word(gpr[rn], gpr[rm]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Halfword transfer
 | 
			
		||||
        // TODO: create abstraction to reuse for block data and single data
 | 
			
		||||
        // transfer
 | 
			
		||||
    } else if ((insn & 0x0e000090) == 0x00000090) {
 | 
			
		||||
        static constexpr char syn[2][4] = { "STR", "LDR" };
 | 
			
		||||
 | 
			
		||||
        uint8_t rm = get_bit_range(insn, 0, 3);
 | 
			
		||||
        uint8_t h  = get_nth_bit(insn, 5);
 | 
			
		||||
        uint8_t s  = get_nth_bit(insn, 6);
 | 
			
		||||
        uint8_t rd = get_bit_range(insn, 12, 15);
 | 
			
		||||
        uint8_t rn = get_bit_range(insn, 16, 19);
 | 
			
		||||
        bool l     = get_nth_bit(insn, 20);
 | 
			
		||||
        bool w     = get_nth_bit(insn, 21);
 | 
			
		||||
        bool imm   = get_nth_bit(insn, 22);
 | 
			
		||||
        bool u     = get_nth_bit(insn, 23);
 | 
			
		||||
        bool p     = get_nth_bit(insn, 24);
 | 
			
		||||
        uint32_t offset;
 | 
			
		||||
 | 
			
		||||
        if (!p && w)
 | 
			
		||||
            log_error("Write-back enabled with post-indexing in {}", syn[l]);
 | 
			
		||||
 | 
			
		||||
        if (s && !l)
 | 
			
		||||
            log_error("Signed data found in {}", syn[l]);
 | 
			
		||||
 | 
			
		||||
        if (w)
 | 
			
		||||
            pc_error(rn, syn[l]);
 | 
			
		||||
        pc_error(rm, syn[l]);
 | 
			
		||||
 | 
			
		||||
        if (rd == 15 && !l && s && h)
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            offset = (imm ? get_bit_range(insn, 8, 11) << 4 | rm : gpr[rm]);
 | 
			
		||||
            std::string offset_str = fmt::format("{}{}{:d}",
 | 
			
		||||
                                                 (u ? "" : "-"),
 | 
			
		||||
                                                 (imm ? '#' : 'R'),
 | 
			
		||||
                                                 (imm ? offset : rm));
 | 
			
		||||
 | 
			
		||||
            disassembled = fmt::format(
 | 
			
		||||
              "{}{}{}{} R{:d}{}",
 | 
			
		||||
              syn[l],
 | 
			
		||||
              cond,
 | 
			
		||||
              (s ? "S" : ""),
 | 
			
		||||
              (h ? 'H' : 'B'),
 | 
			
		||||
              rd,
 | 
			
		||||
              (!offset ? fmt::format("[R{:d}]", rn)
 | 
			
		||||
               : p
 | 
			
		||||
                 ? fmt::format(",[R{:d},{}]{}", rn, offset_str, (w ? "!" : ""))
 | 
			
		||||
                 : fmt::format(",[R{:d}],{}", rn, offset_str)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cpsr.condition(cond)) {
 | 
			
		||||
            uint32_t address = (u ? gpr[rn] + offset : gpr[rn] - offset);
 | 
			
		||||
 | 
			
		||||
            // load
 | 
			
		||||
            if (l) {
 | 
			
		||||
                // signed
 | 
			
		||||
                if (s) {
 | 
			
		||||
                    // halfword
 | 
			
		||||
                    if (h) {
 | 
			
		||||
                        gpr[rd] = bus->read_halfword(address);
 | 
			
		||||
                        // sign extend the halfword
 | 
			
		||||
                        if (get_nth_bit(gpr[rd], 15))
 | 
			
		||||
                            gpr[rd] |= 0xffff0000;
 | 
			
		||||
                        // byte
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // sign extend the byte
 | 
			
		||||
                        gpr[rd] = bus->read_byte(address);
 | 
			
		||||
                        if (get_nth_bit(gpr[rd], 7))
 | 
			
		||||
                            gpr[rd] |= 0xffffff00;
 | 
			
		||||
                    }
 | 
			
		||||
                    // unsigned halfword
 | 
			
		||||
                } else if (h) {
 | 
			
		||||
                    gpr[rd] = bus->read_halfword(address);
 | 
			
		||||
                }
 | 
			
		||||
                // store
 | 
			
		||||
            } else {
 | 
			
		||||
                // halfword
 | 
			
		||||
                if (h) {
 | 
			
		||||
                    // take PC into consideration
 | 
			
		||||
                    if (rd == 15)
 | 
			
		||||
                        address += 12;
 | 
			
		||||
                    bus->write_halfword(address, gpr[rd]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return disassembled;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
lib_sources += files(
 | 
			
		||||
  'cpu.cc',
 | 
			
		||||
  'psr.cc'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
subdir('arm')
 | 
			
		||||
  'instruction.cc',
 | 
			
		||||
  'psr.cc',
 | 
			
		||||
  'utility.cc'
 | 
			
		||||
)
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
#include "psr.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include "util/log.hh"
 | 
			
		||||
 | 
			
		||||
Psr::Psr(uint32_t raw) {
 | 
			
		||||
    psr = raw & PSR_CLEAR_RESERVED;
 | 
			
		||||
@@ -16,9 +17,9 @@ Psr::set_mode(Mode mode) {
 | 
			
		||||
    psr |= static_cast<uint32_t>(mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
State
 | 
			
		||||
Psr::state() const {
 | 
			
		||||
    return get_nth_bit(psr, 5);
 | 
			
		||||
    return static_cast<State>(get_nth_bit(psr, 5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -47,3 +48,39 @@ GET_SET_NTH_BIT_FUNCTIONS(z, 30);
 | 
			
		||||
GET_SET_NTH_BIT_FUNCTIONS(n, 31);
 | 
			
		||||
 | 
			
		||||
#undef GET_SET_NTH_BIT_FUNCTIONS
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
Psr::condition(Condition cond) const {
 | 
			
		||||
    switch (cond) {
 | 
			
		||||
        case Condition::EQ:
 | 
			
		||||
            return z();
 | 
			
		||||
        case Condition::NE:
 | 
			
		||||
            return !z();
 | 
			
		||||
        case Condition::CS:
 | 
			
		||||
            return c();
 | 
			
		||||
        case Condition::CC:
 | 
			
		||||
            return !c();
 | 
			
		||||
        case Condition::MI:
 | 
			
		||||
            return n();
 | 
			
		||||
        case Condition::PL:
 | 
			
		||||
            return !n();
 | 
			
		||||
        case Condition::VS:
 | 
			
		||||
            return v();
 | 
			
		||||
        case Condition::VC:
 | 
			
		||||
            return !v();
 | 
			
		||||
        case Condition::HI:
 | 
			
		||||
            return c() && !z();
 | 
			
		||||
        case Condition::LS:
 | 
			
		||||
            return !c() || z();
 | 
			
		||||
        case Condition::GE:
 | 
			
		||||
            return n() == v();
 | 
			
		||||
        case Condition::LT:
 | 
			
		||||
            return n() != v();
 | 
			
		||||
        case Condition::GT:
 | 
			
		||||
            return !z() && (n() == v());
 | 
			
		||||
        case Condition::LE:
 | 
			
		||||
            return z() || (n() != v());
 | 
			
		||||
        case Condition::AL:
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +13,7 @@ class Psr {
 | 
			
		||||
    void set_mode(Mode mode);
 | 
			
		||||
 | 
			
		||||
    // State : [5]
 | 
			
		||||
    bool state() const;
 | 
			
		||||
    State state() const;
 | 
			
		||||
    void set_state(State state);
 | 
			
		||||
 | 
			
		||||
#define GET_SET_NTH_BIT_FUNCTIONS(name)                                        \
 | 
			
		||||
@@ -43,6 +42,8 @@ class Psr {
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								src/cpu/utility.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/cpu/utility.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const Condition cond) {
 | 
			
		||||
 | 
			
		||||
#define CASE(cond)                                                             \
 | 
			
		||||
    case Condition::cond:                                                      \
 | 
			
		||||
        os << #cond;                                                           \
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    switch (cond) {
 | 
			
		||||
        CASE(EQ)
 | 
			
		||||
        CASE(NE)
 | 
			
		||||
        CASE(CS)
 | 
			
		||||
        CASE(CC)
 | 
			
		||||
        CASE(MI)
 | 
			
		||||
        CASE(PL)
 | 
			
		||||
        CASE(VS)
 | 
			
		||||
        CASE(VC)
 | 
			
		||||
        CASE(HI)
 | 
			
		||||
        CASE(LS)
 | 
			
		||||
        CASE(GE)
 | 
			
		||||
        CASE(LT)
 | 
			
		||||
        CASE(GT)
 | 
			
		||||
        CASE(LE)
 | 
			
		||||
        case Condition::AL: {
 | 
			
		||||
            // empty
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#undef CASE
 | 
			
		||||
 | 
			
		||||
    return os;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,11 @@
 | 
			
		||||
#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,
 | 
			
		||||
@@ -15,3 +21,53 @@ 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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 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 {};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user