refactor: make linter happy
also add a few unused coprocessor instructions Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
8
.clang-tidy
Normal file
8
.clang-tidy
Normal file
@@ -0,0 +1,8 @@
|
||||
Checks: '
|
||||
, clang-analyzer-*
|
||||
, cppcoreguidelines-*
|
||||
, -cppcoreguidelines-avoid-magic-numbers
|
||||
, -cppcoreguidelines-pro-bounds-constant-array-index
|
||||
, -cppcoreguidelines-macro-usage
|
||||
, -cppcoreguidelines-avoid-const-or-ref-data-members
|
||||
'
|
28
.github/workflows/main.yml
vendored
Normal file
28
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: matar
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
env:
|
||||
BUILDDIR: build
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: cachix/install-nix-action@v20
|
||||
with:
|
||||
extra_nix_config: |
|
||||
auto-optimise-store = true
|
||||
experimental-features = nix-command flakes
|
||||
|
||||
- name: meson build
|
||||
run: nix develop -c meson setup $BUILDDIR
|
||||
|
||||
- name: clang-format check
|
||||
run: nix develop -c ninja clang-format-check -C $BUILDDIR
|
||||
|
||||
- name: clang-tidy check
|
||||
run: nix develop -c ninja clang-tidy -C $BUILDDIR
|
||||
|
||||
- name: ninja compile
|
||||
run: nix develop -c ninja -C $BUILDDIR
|
@@ -8,10 +8,12 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
int
|
||||
main(int argc, const char* argv[]) {
|
||||
std::vector<uint8_t> rom;
|
||||
std::array<uint8_t, Memory::BIOS_SIZE> bios;
|
||||
std::array<uint8_t, Memory::BIOS_SIZE> bios = { 0 };
|
||||
|
||||
auto usage = [argv]() {
|
||||
std::cerr << "Usage: " << argv[0] << " <file> [-b <bios>]" << std::endl;
|
||||
@@ -85,3 +87,5 @@ main(int argc, const char* argv[]) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOLINTEND
|
||||
|
@@ -8,7 +8,7 @@
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"i686-linux"
|
||||
# "i686-linux"
|
||||
];
|
||||
eachSystem = with nixpkgs.lib; f: foldAttrs mergeAttrs { }
|
||||
(map (s: mapAttrs (_: v: { ${s} = v; }) (f s)) systems);
|
||||
@@ -53,10 +53,6 @@
|
||||
packages = nativeBuildInputs ++ (with pkgs; [
|
||||
# dev tools
|
||||
clang-tools_16
|
||||
|
||||
# other tools
|
||||
valgrind
|
||||
llvm.lldb
|
||||
]);
|
||||
};
|
||||
default = matar;
|
||||
|
@@ -40,6 +40,12 @@ enum class Condition {
|
||||
AL = 0b1110
|
||||
};
|
||||
|
||||
// https://fmt.dev/dev/api.html#std-ostream-support
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Condition cond);
|
||||
template<>
|
||||
struct fmt::formatter<Condition> : ostream_formatter {};
|
||||
|
||||
enum class OpCode {
|
||||
AND = 0b0000,
|
||||
EOR = 0b0001,
|
||||
@@ -68,6 +74,6 @@ enum class ShiftType {
|
||||
|
||||
// https://fmt.dev/dev/api.html#std-ostream-support
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Condition cond);
|
||||
operator<<(std::ostream& os, const ShiftType cond);
|
||||
template<>
|
||||
struct fmt::formatter<Condition> : ostream_formatter {};
|
||||
struct fmt::formatter<ShiftType> : ostream_formatter {};
|
||||
|
@@ -7,10 +7,10 @@
|
||||
using namespace logger;
|
||||
|
||||
Cpu::Cpu(Bus& bus)
|
||||
: gpr(0)
|
||||
: bus(std::make_shared<Bus>(bus))
|
||||
, gpr({ 0 })
|
||||
, cpsr(0)
|
||||
, spsr(0)
|
||||
, bus(std::make_shared<Bus>(bus))
|
||||
, gpr_banked({ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 } })
|
||||
, spsr_banked({ 0, 0, 0, 0, 0 }) {
|
||||
cpsr.set_mode(Mode::System);
|
||||
@@ -18,20 +18,25 @@ Cpu::Cpu(Bus& bus)
|
||||
cpsr.set_fiq_disabled(true);
|
||||
cpsr.set_state(State::Arm);
|
||||
log_info("CPU successfully initialised");
|
||||
|
||||
// PC is always two instructions ahead in the pipeline
|
||||
pc += 2 * ARM_INSTRUCTION_SIZE;
|
||||
}
|
||||
|
||||
/* change modes */
|
||||
void
|
||||
Cpu::chg_mode(Mode from, Mode to) {
|
||||
Cpu::chg_mode(const Mode to) {
|
||||
Mode from = cpsr.mode();
|
||||
|
||||
if (from == to)
|
||||
return;
|
||||
|
||||
/* TODO: replace visible registers with view once I understand how to
|
||||
* concatenate views */
|
||||
#define STORE_BANKED(mode, MODE) \
|
||||
std::copy(gpr + GPR_##MODE##_BANKED_FIRST, \
|
||||
gpr + GPR_##MODE##_BANKED_FIRST + GPR_##MODE##_BANKED_COUNT, \
|
||||
gpr_banked.mode)
|
||||
std::copy(gpr.begin() + GPR_##MODE##_FIRST, \
|
||||
gpr.begin() + GPR_COUNT - 1, \
|
||||
gpr_banked.mode.begin())
|
||||
|
||||
switch (from) {
|
||||
case Mode::Fiq:
|
||||
@@ -66,9 +71,9 @@ Cpu::chg_mode(Mode from, Mode to) {
|
||||
}
|
||||
|
||||
#define RESTORE_BANKED(mode, MODE) \
|
||||
std::copy(gpr_banked.mode, \
|
||||
gpr_banked.mode + GPR_##MODE##_BANKED_COUNT, \
|
||||
gpr + GPR_##MODE##_BANKED_FIRST)
|
||||
std::copy(gpr_banked.mode.begin(), \
|
||||
gpr_banked.mode.end(), \
|
||||
gpr.begin() + GPR_##MODE##_FIRST)
|
||||
|
||||
switch (to) {
|
||||
case Mode::Fiq:
|
||||
@@ -109,11 +114,15 @@ Cpu::chg_mode(Mode from, Mode to) {
|
||||
|
||||
void
|
||||
Cpu::step() {
|
||||
uint32_t insn = 0xffffffff;
|
||||
uint32_t cur_pc = pc - 2 * ARM_INSTRUCTION_SIZE;
|
||||
|
||||
if (cpsr.state() == State::Arm) {
|
||||
std::string disassembled = exec_arm(insn);
|
||||
log_info("{:#010X} : {}", gpr[15], disassembled);
|
||||
gpr[15] += ARM_INSTRUCTION_SIZE;
|
||||
log_info("{:#034b}", bus->read_word(cur_pc));
|
||||
|
||||
std::string disassembled = exec_arm(bus->read_word(cur_pc));
|
||||
|
||||
log_info("{:#010X} : {}", cur_pc, disassembled);
|
||||
|
||||
pc += ARM_INSTRUCTION_SIZE;
|
||||
}
|
||||
}
|
||||
|
@@ -13,40 +13,32 @@ class Cpu {
|
||||
void step();
|
||||
|
||||
private:
|
||||
static constexpr size_t GPR_FIQ_BANKED_FIRST = 8;
|
||||
static constexpr size_t GPR_FIQ_BANKED_COUNT = 7;
|
||||
static constexpr size_t GPR_COUNT = 16;
|
||||
|
||||
static constexpr size_t GPR_SVC_BANKED_FIRST = 13;
|
||||
static constexpr size_t GPR_SVC_BANKED_COUNT = 2;
|
||||
static constexpr size_t GPR_FIQ_FIRST = 8;
|
||||
static constexpr size_t GPR_SVC_FIRST = 13;
|
||||
static constexpr size_t GPR_ABT_FIRST = 13;
|
||||
static constexpr size_t GPR_IRQ_FIRST = 13;
|
||||
static constexpr size_t GPR_UND_FIRST = 13;
|
||||
static constexpr size_t GPR_SYS_USR_FIRST = 8;
|
||||
|
||||
static constexpr size_t GPR_ABT_BANKED_FIRST = 13;
|
||||
static constexpr size_t GPR_ABT_BANKED_COUNT = 2;
|
||||
|
||||
static constexpr size_t GPR_IRQ_BANKED_FIRST = 13;
|
||||
static constexpr size_t GPR_IRQ_BANKED_COUNT = 2;
|
||||
|
||||
static constexpr size_t GPR_UND_BANKED_FIRST = 13;
|
||||
static constexpr size_t GPR_UND_BANKED_COUNT = 2;
|
||||
|
||||
static constexpr size_t GPR_SYS_USR_BANKED_FIRST = 8;
|
||||
static constexpr size_t GPR_SYS_USR_BANKED_COUNT = 7;
|
||||
|
||||
static constexpr size_t GPR_VISIBLE_COUNT = 16;
|
||||
|
||||
uint32_t gpr[GPR_VISIBLE_COUNT]; // general purpose registers
|
||||
Psr cpsr; // current program status register
|
||||
Psr spsr; // status program status register
|
||||
std::shared_ptr<Bus> bus;
|
||||
std::array<uint32_t, GPR_COUNT> gpr; // general purpose registers
|
||||
|
||||
Psr cpsr; // current program status register
|
||||
Psr spsr; // status program status register
|
||||
|
||||
uint32_t& pc = gpr[15];
|
||||
|
||||
struct {
|
||||
uint32_t fiq[GPR_FIQ_BANKED_COUNT];
|
||||
uint32_t svc[GPR_SVC_BANKED_COUNT];
|
||||
uint32_t abt[GPR_ABT_BANKED_COUNT];
|
||||
uint32_t irq[GPR_IRQ_BANKED_COUNT];
|
||||
uint32_t und[GPR_UND_BANKED_COUNT];
|
||||
std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
|
||||
std::array<uint32_t, GPR_COUNT - GPR_SVC_FIRST - 1> svc;
|
||||
std::array<uint32_t, GPR_COUNT - GPR_ABT_FIRST - 1> abt;
|
||||
std::array<uint32_t, GPR_COUNT - GPR_IRQ_FIRST - 1> irq;
|
||||
std::array<uint32_t, GPR_COUNT - GPR_UND_FIRST - 1> und;
|
||||
|
||||
// visible registers before the mode switch
|
||||
uint32_t old[GPR_SYS_USR_BANKED_COUNT];
|
||||
std::array<uint32_t, GPR_COUNT - GPR_SYS_USR_FIRST> old;
|
||||
} gpr_banked; // banked general purpose registers
|
||||
|
||||
struct {
|
||||
@@ -57,6 +49,6 @@ class Cpu {
|
||||
Psr und;
|
||||
} spsr_banked; // banked saved program status registers
|
||||
|
||||
void chg_mode(Mode from, Mode to);
|
||||
std::string exec_arm(uint32_t insn);
|
||||
void chg_mode(const Mode to);
|
||||
std::string exec_arm(const uint32_t insn);
|
||||
};
|
||||
|
@@ -5,25 +5,27 @@
|
||||
#include <cstdint>
|
||||
|
||||
using namespace logger;
|
||||
using std::array;
|
||||
using stringv = std::string_view;
|
||||
|
||||
std::string
|
||||
Cpu::exec_arm(uint32_t insn) {
|
||||
Cpu::exec_arm(const 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) {
|
||||
auto pc_error = [](uint8_t r, stringv syn) {
|
||||
if (r == 15)
|
||||
log_error("Using PC (R15) as operand in {}", syn);
|
||||
};
|
||||
|
||||
auto pc_undefined = [](uint8_t r, const char* syn) {
|
||||
auto pc_undefined = [](uint8_t r, stringv 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";
|
||||
static constexpr stringv syn = "BX";
|
||||
|
||||
uint8_t rn = insn & 0b1111;
|
||||
|
||||
@@ -38,16 +40,16 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
cpsr.set_state(state);
|
||||
|
||||
// copy to PC
|
||||
gpr[15] = gpr[rn];
|
||||
pc = gpr[rn];
|
||||
|
||||
// ignore [1:0] bits for arm and 0 bit for thumb
|
||||
rst_nth_bit(gpr[15], 0);
|
||||
rst_nth_bit(pc, 0);
|
||||
if (state == State::Arm)
|
||||
rst_nth_bit(gpr[15], 1);
|
||||
rst_nth_bit(pc, 1);
|
||||
}
|
||||
// Branch
|
||||
} else if ((insn & 0x0E000000) == 0x0A000000) {
|
||||
static constexpr char syn[] = "B";
|
||||
static constexpr stringv syn = "B";
|
||||
|
||||
bool link = get_nth_bit(insn, 24);
|
||||
uint32_t offset = get_bit_range(insn, 0, 23);
|
||||
@@ -63,14 +65,14 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
offset |= 0xFC000000;
|
||||
|
||||
if (link)
|
||||
gpr[14] = gpr[15] - ARM_INSTRUCTION_SIZE;
|
||||
gpr[14] = pc - ARM_INSTRUCTION_SIZE;
|
||||
|
||||
gpr[15] += offset;
|
||||
pc += offset - ARM_INSTRUCTION_SIZE;
|
||||
}
|
||||
|
||||
// Multiply
|
||||
} else if ((insn & 0x0FC000F0) == 0x00000090) {
|
||||
static constexpr char syn[2][4] = { "MUL", "MLA" };
|
||||
static constexpr array<stringv, 2> syn = { "MUL", "MLA" };
|
||||
|
||||
uint8_t rm = get_bit_range(insn, 0, 3);
|
||||
uint8_t rs = get_bit_range(insn, 8, 11);
|
||||
@@ -117,8 +119,9 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
}
|
||||
// Multiply long
|
||||
} else if ((insn & 0x0F8000F0) == 0x00800090) {
|
||||
static constexpr char syn[2][2][6] = { { "SMULL", "SMLAL" },
|
||||
{ "UMULL", "UMLAL" } };
|
||||
static constexpr array<array<stringv, 2>, 2> syn = {
|
||||
{ { "SMULL", "SMLAL" }, { "UMULL", "UMLAL" } }
|
||||
};
|
||||
|
||||
uint8_t rm = get_bit_range(insn, 0, 3);
|
||||
uint8_t rs = get_bit_range(insn, 8, 11);
|
||||
@@ -157,7 +160,7 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
gpr[rdhi] = get_bit_range(eval, 32, 63);
|
||||
|
||||
} else {
|
||||
int64_t eval = static_cast<uint64_t>(gpr[rm]) *
|
||||
int64_t eval = static_cast<int64_t>(gpr[rm]) *
|
||||
static_cast<int64_t>(gpr[rs]) +
|
||||
(a ? static_cast<int64_t>(gpr[rdhi]) << 32 |
|
||||
static_cast<int64_t>(gpr[rdlo])
|
||||
@@ -178,7 +181,7 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
|
||||
// Single data swap
|
||||
} else if ((insn & 0x0FB00FF0) == 0x01000090) {
|
||||
static constexpr char syn[] = "SWP";
|
||||
static constexpr stringv syn = "SWP";
|
||||
|
||||
uint8_t rm = get_bit_range(insn, 0, 3);
|
||||
uint8_t rd = get_bit_range(insn, 12, 15);
|
||||
@@ -206,32 +209,32 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
// 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" };
|
||||
static constexpr array<stringv, 2> syn_ = { "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;
|
||||
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 = 0;
|
||||
|
||||
std::string syn =
|
||||
fmt::format("{}{}{}", syn_[l], (s ? "S" : ""), (h ? 'H' : 'B'));
|
||||
|
||||
if (!p && w)
|
||||
log_error("Write-back enabled with post-indexing in {}", syn[l]);
|
||||
log_error("Write-back enabled with post-indexing in {}", syn);
|
||||
|
||||
if (s && !l)
|
||||
log_error("Signed data found in {}", syn[l]);
|
||||
log_error("Signed data found in {}", syn);
|
||||
|
||||
if (w)
|
||||
pc_error(rn, syn[l]);
|
||||
pc_error(rm, syn[l]);
|
||||
|
||||
if (rd == 15 && !l && s && h)
|
||||
;
|
||||
pc_error(rn, syn);
|
||||
pc_error(rm, syn);
|
||||
|
||||
{
|
||||
offset = (imm ? get_bit_range(insn, 8, 11) << 4 | rm : gpr[rm]);
|
||||
@@ -241,8 +244,8 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
(imm ? offset : rm));
|
||||
|
||||
disassembled = fmt::format(
|
||||
"{}{}{}{} R{:d}{}",
|
||||
syn[l],
|
||||
"{}{}{}{} R{:d},{}",
|
||||
syn_[l],
|
||||
cond,
|
||||
(s ? "S" : ""),
|
||||
(h ? 'H' : 'B'),
|
||||
@@ -254,7 +257,10 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
}
|
||||
|
||||
if (cpsr.condition(cond)) {
|
||||
uint32_t address = (u ? gpr[rn] + offset : gpr[rn] - offset);
|
||||
uint32_t address = gpr[rn];
|
||||
|
||||
if (p)
|
||||
address += (u ? offset : -offset);
|
||||
|
||||
// load
|
||||
if (l) {
|
||||
@@ -287,7 +293,92 @@ Cpu::exec_arm(uint32_t insn) {
|
||||
bus->write_halfword(address, gpr[rd]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!p)
|
||||
address += (u ? offset : -offset);
|
||||
|
||||
if (!p || w)
|
||||
gpr[rn] = address;
|
||||
}
|
||||
|
||||
// Software Interrupt
|
||||
// What to do here?
|
||||
} else if ((insn & 0x0F000000) == 0x0F000000) {
|
||||
static constexpr stringv syn = "SWI";
|
||||
|
||||
if (cpsr.condition(cond)) {
|
||||
chg_mode(Mode::Supervisor);
|
||||
pc = 0x08;
|
||||
spsr = cpsr;
|
||||
}
|
||||
|
||||
disassembled = fmt::format("{}{} 0", syn, cond);
|
||||
|
||||
// Coprocessor data transfer
|
||||
} else if ((insn & 0x0E000000) == 0x0C000000) {
|
||||
static constexpr array<stringv, 2> syn = { "STC", "LDC" };
|
||||
|
||||
[[maybe_unused]] uint8_t offset = get_bit_range(insn, 0, 7);
|
||||
uint8_t cpn = get_bit_range(insn, 8, 11);
|
||||
uint8_t crd = get_bit_range(insn, 12, 15);
|
||||
[[maybe_unused]] uint8_t rn = get_bit_range(insn, 16, 19);
|
||||
bool l = get_nth_bit(insn, 20);
|
||||
[[maybe_unused]] bool w = get_nth_bit(insn, 21);
|
||||
bool n = get_nth_bit(insn, 22);
|
||||
[[maybe_unused]] bool u = get_nth_bit(insn, 23);
|
||||
[[maybe_unused]] bool p = get_nth_bit(insn, 24);
|
||||
|
||||
disassembled = fmt::format(
|
||||
"{}{}{} p{},c{},{}", syn[l], cond, (n ? "L" : ""), cpn, crd, "a.");
|
||||
|
||||
log_error("Unimplemented instruction: {}", syn[l]);
|
||||
|
||||
// Coprocessor data operation
|
||||
} else if ((insn & 0x0F000010) == 0x0E000000) {
|
||||
static constexpr stringv syn = "CDP";
|
||||
|
||||
uint8_t crm = get_bit_range(insn, 0, 4);
|
||||
uint8_t cp = get_bit_range(insn, 5, 7);
|
||||
uint8_t cpn = get_bit_range(insn, 8, 11);
|
||||
uint8_t crd = get_bit_range(insn, 12, 15);
|
||||
uint8_t crn = get_bit_range(insn, 16, 19);
|
||||
uint8_t cp_opc = get_bit_range(insn, 20, 23);
|
||||
|
||||
disassembled = fmt::format("{}{} p{},{},c{},c{},c{},{}",
|
||||
syn,
|
||||
cond,
|
||||
cpn,
|
||||
cp_opc,
|
||||
crd,
|
||||
crn,
|
||||
crm,
|
||||
cp);
|
||||
|
||||
log_error("Unimplemented instruction: {}", syn);
|
||||
|
||||
// Coprocessor register transfer
|
||||
} else if ((insn & 0x0F000010) == 0x0E000010) {
|
||||
static constexpr array<stringv, 2> syn = { "MCR", "MRC" };
|
||||
|
||||
uint8_t crm = get_bit_range(insn, 0, 4);
|
||||
uint8_t cp = get_bit_range(insn, 5, 7);
|
||||
uint8_t cpn = get_bit_range(insn, 8, 11);
|
||||
uint8_t rd = get_bit_range(insn, 12, 15);
|
||||
uint8_t crn = get_bit_range(insn, 16, 19);
|
||||
bool l = get_nth_bit(insn, 20);
|
||||
uint8_t cp_opc = get_bit_range(insn, 21, 23);
|
||||
|
||||
disassembled = fmt::format("{}{} p{},{},c{},c{},c{},{}",
|
||||
syn[l],
|
||||
cond,
|
||||
cpn,
|
||||
cp_opc,
|
||||
rd,
|
||||
crn,
|
||||
crm,
|
||||
cp);
|
||||
|
||||
log_error("Unimplemented instruction: {}", syn[l]);
|
||||
}
|
||||
|
||||
return disassembled;
|
||||
|
@@ -2,9 +2,8 @@
|
||||
#include "util/bits.hh"
|
||||
#include "util/log.hh"
|
||||
|
||||
Psr::Psr(uint32_t raw) {
|
||||
psr = raw & PSR_CLEAR_RESERVED;
|
||||
}
|
||||
Psr::Psr(uint32_t raw)
|
||||
: psr(raw & PSR_CLEAR_RESERVED) {}
|
||||
|
||||
Mode
|
||||
Psr::mode() const {
|
||||
|
@@ -32,3 +32,23 @@ operator<<(std::ostream& os, const Condition cond) {
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const ShiftType shift_type) {
|
||||
|
||||
#define CASE(type) \
|
||||
case ShiftType::type: \
|
||||
os << #type; \
|
||||
break;
|
||||
|
||||
switch (shift_type) {
|
||||
CASE(LSL)
|
||||
CASE(LSR)
|
||||
CASE(ASR)
|
||||
CASE(ROR)
|
||||
}
|
||||
|
||||
#undef CASE
|
||||
|
||||
return os;
|
||||
}
|
||||
|
@@ -40,6 +40,12 @@ enum class Condition {
|
||||
AL = 0b1110
|
||||
};
|
||||
|
||||
// https://fmt.dev/dev/api.html#std-ostream-support
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Condition cond);
|
||||
template<>
|
||||
struct fmt::formatter<Condition> : ostream_formatter {};
|
||||
|
||||
enum class OpCode {
|
||||
AND = 0b0000,
|
||||
EOR = 0b0001,
|
||||
@@ -68,6 +74,6 @@ enum class ShiftType {
|
||||
|
||||
// https://fmt.dev/dev/api.html#std-ostream-support
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const Condition cond);
|
||||
operator<<(std::ostream& os, const ShiftType cond);
|
||||
template<>
|
||||
struct fmt::formatter<Condition> : ostream_formatter {};
|
||||
struct fmt::formatter<ShiftType> : ostream_formatter {};
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef struct {
|
||||
@@ -33,9 +34,9 @@ typedef struct {
|
||||
};
|
||||
|
||||
uint32_t entrypoint;
|
||||
char title[12];
|
||||
std::string title;
|
||||
std::string title_code;
|
||||
UniqueCode unique_code;
|
||||
char title_code[2];
|
||||
I18n i18n;
|
||||
uint8_t version;
|
||||
BootMode multiboot;
|
||||
|
@@ -10,14 +10,14 @@ using namespace logger;
|
||||
Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
||||
std::vector<uint8_t>&& rom) noexcept
|
||||
: bios(std::move(bios))
|
||||
, board_wram(0)
|
||||
, chip_wram(0)
|
||||
, palette_ram(0)
|
||||
, vram(0)
|
||||
, oam_obj_attr(0)
|
||||
, board_wram({ 0 })
|
||||
, chip_wram({ 0 })
|
||||
, palette_ram({ 0 })
|
||||
, vram({ 0 })
|
||||
, oam_obj_attr({ 0 })
|
||||
, rom(std::move(rom)) {
|
||||
std::string bios_hash = crypto::sha256(bios.data(), bios.size());
|
||||
static constexpr char expected_hash[] =
|
||||
std::string bios_hash = crypto::sha256(this->bios);
|
||||
static constexpr std::string_view expected_hash =
|
||||
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
||||
|
||||
if (bios_hash != expected_hash) {
|
||||
@@ -137,7 +137,7 @@ Memory::parse_header() {
|
||||
log_info("HEADER: BIOS debugger bits not set to 0");
|
||||
|
||||
// game info
|
||||
std::copy(&rom[0xA0], &rom[0xA0 + 12], header.title);
|
||||
header.title = std::string(&rom[0xA0], &rom[0xA0 + 12]);
|
||||
|
||||
switch (rom[0xAC]) {
|
||||
case 'A':
|
||||
@@ -172,8 +172,7 @@ Memory::parse_header() {
|
||||
log_error("HEADER: invalid unique code: {}", rom[0xAC]);
|
||||
}
|
||||
|
||||
header.title_code[0] = rom[0xAD];
|
||||
header.title_code[1] = rom[0xAE];
|
||||
header.title_code = std::string(&rom[0xAD], &rom[0xAE]);
|
||||
|
||||
switch (rom[0xAF]) {
|
||||
case 'J':
|
||||
|
@@ -29,7 +29,7 @@ class Memory {
|
||||
|
||||
#define DECL_MEMORY(name, ident, start, end) \
|
||||
MEMORY_REGION(name, start, end) \
|
||||
uint8_t ident[name##_END - name##_START + 1];
|
||||
std::array<uint8_t, name##_END - name##_START + 1> ident;
|
||||
|
||||
MEMORY_REGION(BIOS, 0x00000000, 0x00003FFF)
|
||||
std::array<uint8_t, BIOS_SIZE> bios;
|
||||
|
@@ -3,7 +3,6 @@ lib_sources = files(
|
||||
'bus.cc'
|
||||
)
|
||||
|
||||
subdir('util')
|
||||
subdir('cpu')
|
||||
|
||||
fmt = dependency('fmt', version : '>=10.1.0')
|
||||
|
@@ -3,54 +3,55 @@
|
||||
#include <fmt/ostream.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace logger {
|
||||
inline std::ostream& stream = std::clog;
|
||||
using fmt::print;
|
||||
using std::clog;
|
||||
|
||||
namespace logger {
|
||||
namespace ansi {
|
||||
static constexpr char RED[] = "\033[31m";
|
||||
static constexpr char YELLOW[] = "\033[33m";
|
||||
static constexpr char MAGENTA[] = "\033[35m";
|
||||
static constexpr char WHITE[] = "\033[37m";
|
||||
static constexpr char BOLD[] = "\033[1m";
|
||||
static constexpr char RESET[] = "\033[0m";
|
||||
static constexpr std::string_view RED = "\033[31m";
|
||||
static constexpr std::string_view YELLOW = "\033[33m";
|
||||
static constexpr std::string_view MAGENTA = "\033[35m";
|
||||
static constexpr std::string_view WHITE = "\033[37m";
|
||||
static constexpr std::string_view BOLD = "\033[1m";
|
||||
static constexpr std::string_view RESET = "\033[0m";
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void
|
||||
log_raw(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||
fmt::println(stream, fmt, std::forward<Args>(args)...);
|
||||
fmt::println(clog, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void
|
||||
log_debug(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||
fmt::print(stream, "{}{}[DEBUG] ", ansi::MAGENTA, ansi::BOLD);
|
||||
print(clog, "{}{}[DEBUG] ", ansi::MAGENTA, ansi::BOLD);
|
||||
log_raw(fmt, std::forward<Args>(args)...);
|
||||
fmt::print(stream, ansi::RESET);
|
||||
print(clog, ansi::RESET);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void
|
||||
log_info(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||
fmt::print(stream, "{}[INFO] ", ansi::WHITE);
|
||||
print(clog, "{}[INFO] ", ansi::WHITE);
|
||||
log_raw(fmt, std::forward<Args>(args)...);
|
||||
fmt::print(stream, ansi::RESET);
|
||||
print(clog, ansi::RESET);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void
|
||||
log_warn(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||
fmt::print(stream, "{}[WARN] ", ansi::YELLOW);
|
||||
print(clog, "{}[WARN] ", ansi::YELLOW);
|
||||
log_raw(fmt, std::forward<Args>(args)...);
|
||||
fmt::print(stream, ansi::RESET);
|
||||
print(clog, ansi::RESET);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void
|
||||
log_error(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||
fmt::print(stream, "{}{}[ERROR] ", ansi::RED, ansi::BOLD);
|
||||
print(clog, "{}{}[ERROR] ", ansi::RED, ansi::BOLD);
|
||||
log_raw(fmt, std::forward<Args>(args)...);
|
||||
fmt::print(stream, ansi::RESET);
|
||||
print(clog, ansi::RESET);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,3 +0,0 @@
|
||||
lib_sources += files(
|
||||
'utils.cc'
|
||||
)
|
@@ -1,113 +0,0 @@
|
||||
#include "utils.hh"
|
||||
#include <bit>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace crypto {
|
||||
|
||||
using std::rotr;
|
||||
|
||||
std::string
|
||||
sha256(const uint8_t* data, const size_t size) {
|
||||
// Assuming 1 byte = 8 bits
|
||||
std::stringstream string;
|
||||
size_t k = 512 - (size * 8 + 65) % 512;
|
||||
size_t L = size + (65 + k) / 8;
|
||||
size_t i, j;
|
||||
bool c = 0;
|
||||
|
||||
static constexpr uint32_t K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
uint32_t h[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
|
||||
|
||||
for (i = 0; i < L; i += 64) {
|
||||
size_t n = (size > i ? size - i : 0);
|
||||
uint32_t h0[8];
|
||||
uint32_t w[64] = { 0 };
|
||||
|
||||
if (n == 64)
|
||||
c = 1;
|
||||
|
||||
if (n >= 64) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
w[j] = data[i + j * 4] << 24 | data[i + j * 4 + 1] << 16 |
|
||||
data[i + j * 4 + 2] << 8 | data[i + j * 4 + 3];
|
||||
}
|
||||
} else {
|
||||
uint8_t cur[64] = { 0 };
|
||||
|
||||
if (n) {
|
||||
std::copy(data + i, data + size, cur);
|
||||
cur[n] = 0x80;
|
||||
} else if (c) {
|
||||
cur[n] = 0x80;
|
||||
}
|
||||
|
||||
if (n < 54) {
|
||||
for (j = 56; j < 64; j++) {
|
||||
cur[j] = (size * 8 >> ((63 - j) * 8)) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
w[j] = cur[j * 4] << 24 | cur[j * 4 + 1] << 16 |
|
||||
cur[j * 4 + 2] << 8 | cur[j * 4 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 16; j < 64; j++) {
|
||||
uint32_t s0 =
|
||||
rotr(w[j - 15], 7) ^ rotr(w[j - 15], 18) ^ (w[j - 15] >> 3);
|
||||
uint32_t s1 =
|
||||
rotr(w[j - 2], 17) ^ rotr(w[j - 2], 19) ^ (w[j - 2] >> 10);
|
||||
|
||||
w[j] = w[j - 16] + w[j - 7] + s0 + s1;
|
||||
}
|
||||
|
||||
std::copy(h, h + 8, h0);
|
||||
|
||||
for (j = 0; j < 64; j++) {
|
||||
uint32_t s1 = rotr(h0[4], 6) ^ rotr(h0[4], 11) ^ rotr(h0[4], 25);
|
||||
uint32_t ch = (h0[4] & h0[5]) ^ (~h0[4] & h0[6]);
|
||||
uint32_t t1 = h0[7] + s1 + ch + K[j] + w[j];
|
||||
uint32_t s0 = rotr(h0[0], 2) ^ rotr(h0[0], 13) ^ rotr(h0[0], 22);
|
||||
uint32_t maj = (h0[0] & h0[1]) ^ (h0[0] & h0[2]) ^ (h0[1] & h0[2]);
|
||||
uint32_t t2 = s0 + maj;
|
||||
|
||||
h0[7] = h0[6];
|
||||
h0[6] = h0[5];
|
||||
h0[5] = h0[4];
|
||||
h0[4] = h0[3] + t1;
|
||||
h0[3] = h0[2];
|
||||
h0[2] = h0[1];
|
||||
h0[1] = h0[0];
|
||||
h0[0] = t1 + t2;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
h[j] += h0[j];
|
||||
}
|
||||
|
||||
string << std::hex << std::setfill('0');
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
for (i = 0; i < 4; i++)
|
||||
string << std::setw(2) << ((h[j] >> (24 - i * 8)) & 0xFF);
|
||||
|
||||
return string.str();
|
||||
}
|
||||
}
|
@@ -1,10 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <fmt/core.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// Why I wrote this myself? I do not know
|
||||
// I will off myself 😹😹😹😹
|
||||
namespace crypto {
|
||||
|
||||
using std::rotr;
|
||||
|
||||
template<typename std::size_t N>
|
||||
std::string
|
||||
sha256(const uint8_t* data, const size_t size);
|
||||
sha256(std::array<uint8_t, N>& data) {
|
||||
// Assuming 1 byte = 8 bits
|
||||
std::string string;
|
||||
size_t k = 512 - (N * 8 + 65) % 512;
|
||||
size_t L = N + (65 + k) / 8;
|
||||
size_t i = 0, j = 0;
|
||||
bool c = 0;
|
||||
|
||||
static constexpr std::array<uint32_t, 64> K = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
std::array<uint32_t, 8> h = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372,
|
||||
0xa54ff53a, 0x510e527f, 0x9b05688c,
|
||||
0x1f83d9ab, 0x5be0cd19 };
|
||||
|
||||
for (i = 0; i < L; i += 64) {
|
||||
size_t n = (N > i ? N - i : 0);
|
||||
|
||||
std::array<uint32_t, 8> h0 = { 0 };
|
||||
std::array<uint32_t, 64> w = { 0 };
|
||||
|
||||
if (n == 64)
|
||||
c = 1;
|
||||
|
||||
if (n >= 64) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
w[j] = data[i + j * 4] << 24 | data[i + j * 4 + 1] << 16 |
|
||||
data[i + j * 4 + 2] << 8 | data[i + j * 4 + 3];
|
||||
}
|
||||
} else {
|
||||
std::array<uint32_t, 64> cur = { 0 };
|
||||
|
||||
if (n) {
|
||||
std::copy(data.begin() + i, data.begin() + N, cur.begin());
|
||||
cur[n] = 0x80;
|
||||
} else if (c) {
|
||||
cur[n] = 0x80;
|
||||
}
|
||||
|
||||
if (n < 54) {
|
||||
for (j = 56; j < 64; j++) {
|
||||
cur[j] = (N * 8 >> ((63 - j) * 8)) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
w[j] = cur[j * 4] << 24 | cur[j * 4 + 1] << 16 |
|
||||
cur[j * 4 + 2] << 8 | cur[j * 4 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 16; j < 64; j++) {
|
||||
uint32_t s0 =
|
||||
rotr(w[j - 15], 7) ^ rotr(w[j - 15], 18) ^ (w[j - 15] >> 3);
|
||||
uint32_t s1 =
|
||||
rotr(w[j - 2], 17) ^ rotr(w[j - 2], 19) ^ (w[j - 2] >> 10);
|
||||
|
||||
w[j] = w[j - 16] + w[j - 7] + s0 + s1;
|
||||
}
|
||||
|
||||
std::copy(h.begin(), h.end(), h0.begin());
|
||||
|
||||
for (j = 0; j < 64; j++) {
|
||||
uint32_t s1 = rotr(h0[4], 6) ^ rotr(h0[4], 11) ^ rotr(h0[4], 25);
|
||||
uint32_t ch = (h0[4] & h0[5]) ^ (~h0[4] & h0[6]);
|
||||
uint32_t t1 = h0[7] + s1 + ch + K[j] + w[j];
|
||||
uint32_t s0 = rotr(h0[0], 2) ^ rotr(h0[0], 13) ^ rotr(h0[0], 22);
|
||||
uint32_t maj = (h0[0] & h0[1]) ^ (h0[0] & h0[2]) ^ (h0[1] & h0[2]);
|
||||
uint32_t t2 = s0 + maj;
|
||||
|
||||
h0[7] = h0[6];
|
||||
h0[6] = h0[5];
|
||||
h0[5] = h0[4];
|
||||
h0[4] = h0[3] + t1;
|
||||
h0[3] = h0[2];
|
||||
h0[2] = h0[1];
|
||||
h0[1] = h0[0];
|
||||
h0[0] = t1 + t2;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
h[j] += h0[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
for (i = 0; i < 4; i++)
|
||||
fmt::format_to(std::back_inserter(string),
|
||||
"{:02x}",
|
||||
((h[j] >> (24 - i * 8)) & 0xFF));
|
||||
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user