From 8a04eade92c62adff43f8ccffd50129f04dea2e4 Mon Sep 17 00:00:00 2001 From: Amneesh Singh Date: Wed, 13 Sep 2023 03:44:36 +0530 Subject: [PATCH] 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 --- .gitmodules | 0 apps/target/main.cc | 15 +- include/bus.hh | 1 + include/cpu/cpu.hh | 1 + include/cpu/meson.build | 5 + include/cpu/psr.hh | 1 + .../insruction.hh => include/cpu/utility.hh | 30 ++ include/meson.build | 5 +- src/bus.cc | 35 ++- src/bus.hh | 14 +- src/cpu/arm/meson.build | 2 - src/cpu/cpu.cc | 26 +- src/cpu/cpu.hh | 9 +- src/cpu/instruction.cc | 294 ++++++++++++++++++ src/cpu/meson.build | 8 +- src/cpu/psr.cc | 41 ++- src/cpu/psr.hh | 5 +- src/cpu/utility.cc | 34 ++ src/cpu/utility.hh | 56 ++++ src/memory.cc | 19 +- src/meson.build | 7 +- src/util/bits.hh | 13 +- 22 files changed, 571 insertions(+), 50 deletions(-) delete mode 100644 .gitmodules create mode 120000 include/bus.hh create mode 120000 include/cpu/cpu.hh create mode 100644 include/cpu/meson.build create mode 120000 include/cpu/psr.hh rename src/cpu/arm/insruction.hh => include/cpu/utility.hh (51%) delete mode 100644 src/cpu/arm/meson.build create mode 100644 src/cpu/instruction.cc create mode 100644 src/cpu/utility.cc diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/apps/target/main.cc b/apps/target/main.cc index 76e7b5d..d70eb01 100644 --- a/apps/target/main.cc +++ b/apps/target/main.cc @@ -1,12 +1,18 @@ +#include "bus.hh" +#include "cpu/cpu.hh" #include "memory.hh" #include #include #include #include +#include #include int main(int argc, const char* argv[]) { + std::vector rom; + std::array bios; + auto usage = [argv]() { std::cerr << "Usage: " << argv[0] << " [-b ]" << std::endl; std::exit(EXIT_FAILURE); @@ -35,8 +41,6 @@ main(int argc, const char* argv[]) { try { std::ifstream ifile(rom_file, std::ios::in | std::ios::binary); - std::vector rom; - std::array bios; std::streampos bios_size; if (!ifile.is_open()) { @@ -68,11 +72,16 @@ main(int argc, const char* argv[]) { ifile.close(); - Memory memory(std::move(bios), std::move(rom)); } catch (const std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; return 1; } + { + Memory memory(std::move(bios), std::move(rom)); + Bus bus(std::make_shared(memory)); + Cpu cpu(std::make_shared(bus)); + cpu.step(); + } return 0; } diff --git a/include/bus.hh b/include/bus.hh new file mode 120000 index 0000000..915f1b4 --- /dev/null +++ b/include/bus.hh @@ -0,0 +1 @@ +../src/bus.hh \ No newline at end of file diff --git a/include/cpu/cpu.hh b/include/cpu/cpu.hh new file mode 120000 index 0000000..19daf50 --- /dev/null +++ b/include/cpu/cpu.hh @@ -0,0 +1 @@ +../../src/cpu/cpu.hh \ No newline at end of file diff --git a/include/cpu/meson.build b/include/cpu/meson.build new file mode 100644 index 0000000..3026ff2 --- /dev/null +++ b/include/cpu/meson.build @@ -0,0 +1,5 @@ +headers += files( + 'cpu.hh', + 'psr.hh', + 'utility.hh' +) \ No newline at end of file diff --git a/include/cpu/psr.hh b/include/cpu/psr.hh new file mode 120000 index 0000000..387500c --- /dev/null +++ b/include/cpu/psr.hh @@ -0,0 +1 @@ +../../src/cpu/psr.hh \ No newline at end of file diff --git a/src/cpu/arm/insruction.hh b/include/cpu/utility.hh similarity index 51% rename from src/cpu/arm/insruction.hh rename to include/cpu/utility.hh index f4083ce..a790ebd 100644 --- a/src/cpu/arm/insruction.hh +++ b/include/cpu/utility.hh @@ -1,3 +1,27 @@ +#pragma once + +#include +#include + +static constexpr size_t ARM_INSTRUCTION_SIZE = 4; +static constexpr size_t THUMB_INSTRUCTION_SIZE = 2; + +enum class Mode { + /* M[4:0] in PSR */ + User = 0b10000, + Fiq = 0b10001, + Irq = 0b10010, + Supervisor = 0b10011, + Abort = 0b10111, + Undefined = 0b11011, + System = 0b11111, +}; + +enum class State { + Arm = 0, + Thumb = 1 +}; + enum class Condition { EQ = 0b0000, NE = 0b0001, @@ -41,3 +65,9 @@ enum class ShiftType { 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 : ostream_formatter {}; diff --git a/include/meson.build b/include/meson.build index 4f332a5..b5d86db 100644 --- a/include/meson.build +++ b/include/meson.build @@ -1,6 +1,9 @@ headers = files( 'memory.hh', - 'header.hh' + 'bus.hh', + 'header.hh', ) +subdir('cpu') + install_headers(headers, subdir: meson.project_name(), preserve_path: true) \ No newline at end of file diff --git a/src/bus.cc b/src/bus.cc index 24cc819..bddda01 100644 --- a/src/bus.cc +++ b/src/bus.cc @@ -1,4 +1,35 @@ #include "bus.hh" +#include -Bus::Bus(Memory&& memory) - : memory(std::move(memory)) {} +Bus::Bus(std::shared_ptr memory) + : memory(memory) {} + +uint8_t +Bus::read_byte(size_t address) { + return memory->read(address); +} + +void +Bus::write_byte(size_t address, uint8_t byte) { + memory->write(address, byte); +} + +uint16_t +Bus::read_halfword(size_t address) { + return memory->read_halfword(address); +} + +void +Bus::write_halfword(size_t address, uint16_t halfword) { + memory->write_halfword(address, halfword); +} + +uint32_t +Bus::read_word(size_t address) { + return memory->read_word(address); +} + +void +Bus::write_word(size_t address, uint32_t word) { + memory->write_halfword(address, word); +} diff --git a/src/bus.hh b/src/bus.hh index e79f65d..5c8b815 100644 --- a/src/bus.hh +++ b/src/bus.hh @@ -1,11 +1,21 @@ #pragma once #include "memory.hh" +#include class Bus { public: - Bus(Memory&& memory); + Bus(std::shared_ptr memory); + + uint8_t read_byte(size_t address); + void write_byte(size_t address, uint8_t byte); + + uint16_t read_halfword(size_t address); + void write_halfword(size_t address, uint16_t halfword); + + uint32_t read_word(size_t address); + void write_word(size_t address, uint32_t word); private: - Memory memory; + std::shared_ptr memory; }; diff --git a/src/cpu/arm/meson.build b/src/cpu/arm/meson.build deleted file mode 100644 index 4673a60..0000000 --- a/src/cpu/arm/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -lib_sources += files( -) \ No newline at end of file diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc index b14e74b..b1fd50f 100644 --- a/src/cpu/cpu.cc +++ b/src/cpu/cpu.cc @@ -1,9 +1,12 @@ #include "cpu.hh" -#include "cpu/utility.hh" +#include "util/log.hh" +#include "utility.hh" #include #include -Cpu::Cpu(Bus bus) +using namespace logger; + +Cpu::Cpu(std::shared_ptr 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; + } } diff --git a/src/cpu/cpu.hh b/src/cpu/cpu.hh index a93fd6f..9d12b56 100644 --- a/src/cpu/cpu.hh +++ b/src/cpu/cpu.hh @@ -9,7 +9,8 @@ using std::size_t; class Cpu { public: - Cpu(Bus bus); + Cpu(std::shared_ptr 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; 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); }; diff --git a/src/cpu/instruction.cc b/src/cpu/instruction.cc new file mode 100644 index 0000000..2985ad2 --- /dev/null +++ b/src/cpu/instruction.cc @@ -0,0 +1,294 @@ +#include "cpu.hh" +#include "cpu/utility.hh" +#include "util/bits.hh" +#include "util/log.hh" +#include + +using namespace logger; + +std::string +Cpu::exec_arm(uint32_t insn) { + Condition cond = static_cast(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(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(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(gpr[rm]) * + static_cast(gpr[rs]) + + (a ? static_cast(gpr[rdhi]) << 32 | + static_cast(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(gpr[rm]) * + static_cast(gpr[rs]) + + (a ? static_cast(gpr[rdhi]) << 32 | + static_cast(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(gpr[rdhi]) || + static_cast(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; +} diff --git a/src/cpu/meson.build b/src/cpu/meson.build index 394799f..11d93d8 100644 --- a/src/cpu/meson.build +++ b/src/cpu/meson.build @@ -1,6 +1,6 @@ lib_sources += files( 'cpu.cc', - 'psr.cc' -) - -subdir('arm') \ No newline at end of file + 'instruction.cc', + 'psr.cc', + 'utility.cc' +) \ No newline at end of file diff --git a/src/cpu/psr.cc b/src/cpu/psr.cc index 6f72f66..c34df55 100644 --- a/src/cpu/psr.cc +++ b/src/cpu/psr.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(mode); } -bool +State Psr::state() const { - return get_nth_bit(psr, 5); + return static_cast(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; + } +} diff --git a/src/cpu/psr.hh b/src/cpu/psr.hh index c4b8cec..e7caed3 100644 --- a/src/cpu/psr.hh +++ b/src/cpu/psr.hh @@ -1,6 +1,5 @@ #pragma once -#include "util/bits.hh" #include "utility.hh" #include @@ -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; diff --git a/src/cpu/utility.cc b/src/cpu/utility.cc new file mode 100644 index 0000000..25c9861 --- /dev/null +++ b/src/cpu/utility.cc @@ -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; +} diff --git a/src/cpu/utility.hh b/src/cpu/utility.hh index 95e0f3c..a790ebd 100644 --- a/src/cpu/utility.hh +++ b/src/cpu/utility.hh @@ -1,5 +1,11 @@ #pragma once +#include +#include + +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 : ostream_formatter {}; diff --git a/src/memory.cc b/src/memory.cc index 768b392..c1edcd2 100644 --- a/src/memory.cc +++ b/src/memory.cc @@ -1,7 +1,11 @@ #include "memory.hh" #include "header.hh" +#include "util/bits.hh" #include "util/log.hh" #include "util/utils.hh" +#include + +using namespace logger; Memory::Memory(std::array&& bios, std::vector&& rom) noexcept @@ -13,20 +17,21 @@ Memory::Memory(std::array&& bios, , oam_obj_attr(0) , rom(std::move(rom)) { std::string bios_hash = crypto::sha256(bios.data(), bios.size()); - std::string expected_hash = + static constexpr char expected_hash[] = "fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570"; if (bios_hash != expected_hash) { - log_warn("BIOS hash failed to match, run at your own risk", - "\nExpected : ", + log_warn("BIOS hash failed to match, run at your own risk" + "\nExpected : {} " + "\nGot : {}", expected_hash, - "\nGot : ", bios_hash); } parse_header(); - log("Memory successfully initialised"); + log_info("Memory successfully initialised"); + log_info("Cartridge Title: {}", header.title); }; #define MATCHES(area) address >= area##_START&& address <= area##_END @@ -164,7 +169,7 @@ Memory::parse_header() { break; default: - log_error("HEADER: invalid unique code: ", rom[0xAC]); + log_error("HEADER: invalid unique code: {}", rom[0xAC]); } header.title_code[0] = rom[0xAD]; @@ -194,7 +199,7 @@ Memory::parse_header() { break; default: - log_error("HEADER: invalid destination/language - ", rom[0xAF]); + log_error("HEADER: invalid destination/language: {}", rom[0xAF]); } if (rom[0xB2] != 0x96) diff --git a/src/meson.build b/src/meson.build index 68d9c0f..28c6153 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,10 +6,13 @@ lib_sources = files( subdir('util') subdir('cpu') +fmt = dependency('fmt', version : '>=10.1.0') lib = library( meson.project_name(), lib_sources, - install: true + dependencies: [fmt], + install: true, + cpp_args: '-DFMT_HEADER_ONLY' ) -import('pkgconfig').generate(lib) \ No newline at end of file +import('pkgconfig').generate(lib) diff --git a/src/util/bits.hh b/src/util/bits.hh index 6acdab1..34c5c0f 100644 --- a/src/util/bits.hh +++ b/src/util/bits.hh @@ -8,7 +8,7 @@ using std::size_t; template inline bool get_nth_bit(Int num, size_t n) { - return (1 && (num >> n)); + return (num >> n) & 1; } template @@ -26,14 +26,15 @@ rst_nth_bit(Int& num, size_t n) { template inline void chg_nth_bit(Int& num, size_t n, bool x) { - num ^= (num ^ -x) & 1 << n; + num = (num & ~(1 << n)) | (x << n); } /// read range of bits from start to end inclusive -template +template inline Int -get_bit_range(Int& num, size_t start, size_t end) { - // NOTE: we do not require -1 if it is a signed integral (which it is not) - Int left = std::numeric_limits::digits - 1 - end; +get_bit_range(Int num, size_t start, size_t end) { + // NOTE: we do not require -1 if it is a signed integral + Int left = + std::numeric_limits::digits - (std::is_unsigned::value) - end; return num << left >> (left + start); }