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 <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// NOLINTBEGIN
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char* argv[]) {
|
main(int argc, const char* argv[]) {
|
||||||
std::vector<uint8_t> rom;
|
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]() {
|
auto usage = [argv]() {
|
||||||
std::cerr << "Usage: " << argv[0] << " <file> [-b <bios>]" << std::endl;
|
std::cerr << "Usage: " << argv[0] << " <file> [-b <bios>]" << std::endl;
|
||||||
@@ -85,3 +87,5 @@ main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOLINTEND
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
systems = [
|
systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
"i686-linux"
|
# "i686-linux"
|
||||||
];
|
];
|
||||||
eachSystem = with nixpkgs.lib; f: foldAttrs mergeAttrs { }
|
eachSystem = with nixpkgs.lib; f: foldAttrs mergeAttrs { }
|
||||||
(map (s: mapAttrs (_: v: { ${s} = v; }) (f s)) systems);
|
(map (s: mapAttrs (_: v: { ${s} = v; }) (f s)) systems);
|
||||||
@@ -53,10 +53,6 @@
|
|||||||
packages = nativeBuildInputs ++ (with pkgs; [
|
packages = nativeBuildInputs ++ (with pkgs; [
|
||||||
# dev tools
|
# dev tools
|
||||||
clang-tools_16
|
clang-tools_16
|
||||||
|
|
||||||
# other tools
|
|
||||||
valgrind
|
|
||||||
llvm.lldb
|
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
default = matar;
|
default = matar;
|
||||||
|
@@ -40,6 +40,12 @@ enum class Condition {
|
|||||||
AL = 0b1110
|
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 {
|
enum class OpCode {
|
||||||
AND = 0b0000,
|
AND = 0b0000,
|
||||||
EOR = 0b0001,
|
EOR = 0b0001,
|
||||||
@@ -68,6 +74,6 @@ enum class ShiftType {
|
|||||||
|
|
||||||
// https://fmt.dev/dev/api.html#std-ostream-support
|
// https://fmt.dev/dev/api.html#std-ostream-support
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& os, const Condition cond);
|
operator<<(std::ostream& os, const ShiftType cond);
|
||||||
template<>
|
template<>
|
||||||
struct fmt::formatter<Condition> : ostream_formatter {};
|
struct fmt::formatter<ShiftType> : ostream_formatter {};
|
||||||
|
@@ -7,10 +7,10 @@
|
|||||||
using namespace logger;
|
using namespace logger;
|
||||||
|
|
||||||
Cpu::Cpu(Bus& bus)
|
Cpu::Cpu(Bus& bus)
|
||||||
: gpr(0)
|
: bus(std::make_shared<Bus>(bus))
|
||||||
|
, gpr({ 0 })
|
||||||
, cpsr(0)
|
, cpsr(0)
|
||||||
, spsr(0)
|
, spsr(0)
|
||||||
, bus(std::make_shared<Bus>(bus))
|
|
||||||
, 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::System);
|
||||||
@@ -18,20 +18,25 @@ Cpu::Cpu(Bus& bus)
|
|||||||
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 += 2 * ARM_INSTRUCTION_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change modes */
|
/* change modes */
|
||||||
void
|
void
|
||||||
Cpu::chg_mode(Mode from, Mode to) {
|
Cpu::chg_mode(const Mode to) {
|
||||||
|
Mode from = cpsr.mode();
|
||||||
|
|
||||||
if (from == to)
|
if (from == to)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* TODO: replace visible registers with view once I understand how to
|
/* TODO: replace visible registers with view once I understand how to
|
||||||
* concatenate views */
|
* concatenate views */
|
||||||
#define STORE_BANKED(mode, MODE) \
|
#define STORE_BANKED(mode, MODE) \
|
||||||
std::copy(gpr + GPR_##MODE##_BANKED_FIRST, \
|
std::copy(gpr.begin() + GPR_##MODE##_FIRST, \
|
||||||
gpr + GPR_##MODE##_BANKED_FIRST + GPR_##MODE##_BANKED_COUNT, \
|
gpr.begin() + GPR_COUNT - 1, \
|
||||||
gpr_banked.mode)
|
gpr_banked.mode.begin())
|
||||||
|
|
||||||
switch (from) {
|
switch (from) {
|
||||||
case Mode::Fiq:
|
case Mode::Fiq:
|
||||||
@@ -66,9 +71,9 @@ Cpu::chg_mode(Mode from, Mode to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define RESTORE_BANKED(mode, MODE) \
|
#define RESTORE_BANKED(mode, MODE) \
|
||||||
std::copy(gpr_banked.mode, \
|
std::copy(gpr_banked.mode.begin(), \
|
||||||
gpr_banked.mode + GPR_##MODE##_BANKED_COUNT, \
|
gpr_banked.mode.end(), \
|
||||||
gpr + GPR_##MODE##_BANKED_FIRST)
|
gpr.begin() + GPR_##MODE##_FIRST)
|
||||||
|
|
||||||
switch (to) {
|
switch (to) {
|
||||||
case Mode::Fiq:
|
case Mode::Fiq:
|
||||||
@@ -109,11 +114,15 @@ Cpu::chg_mode(Mode from, Mode to) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
Cpu::step() {
|
Cpu::step() {
|
||||||
uint32_t insn = 0xffffffff;
|
uint32_t cur_pc = pc - 2 * ARM_INSTRUCTION_SIZE;
|
||||||
|
|
||||||
if (cpsr.state() == State::Arm) {
|
if (cpsr.state() == State::Arm) {
|
||||||
std::string disassembled = exec_arm(insn);
|
log_info("{:#034b}", bus->read_word(cur_pc));
|
||||||
log_info("{:#010X} : {}", gpr[15], disassembled);
|
|
||||||
gpr[15] += ARM_INSTRUCTION_SIZE;
|
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();
|
void step();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t GPR_FIQ_BANKED_FIRST = 8;
|
static constexpr size_t GPR_COUNT = 16;
|
||||||
static constexpr size_t GPR_FIQ_BANKED_COUNT = 7;
|
|
||||||
|
|
||||||
static constexpr size_t GPR_SVC_BANKED_FIRST = 13;
|
static constexpr size_t GPR_FIQ_FIRST = 8;
|
||||||
static constexpr size_t GPR_SVC_BANKED_COUNT = 2;
|
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::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 {
|
struct {
|
||||||
uint32_t fiq[GPR_FIQ_BANKED_COUNT];
|
std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
|
||||||
uint32_t svc[GPR_SVC_BANKED_COUNT];
|
std::array<uint32_t, GPR_COUNT - GPR_SVC_FIRST - 1> svc;
|
||||||
uint32_t abt[GPR_ABT_BANKED_COUNT];
|
std::array<uint32_t, GPR_COUNT - GPR_ABT_FIRST - 1> abt;
|
||||||
uint32_t irq[GPR_IRQ_BANKED_COUNT];
|
std::array<uint32_t, GPR_COUNT - GPR_IRQ_FIRST - 1> irq;
|
||||||
uint32_t und[GPR_UND_BANKED_COUNT];
|
std::array<uint32_t, GPR_COUNT - GPR_UND_FIRST - 1> und;
|
||||||
|
|
||||||
// visible registers before the mode switch
|
// 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
|
} gpr_banked; // banked general purpose registers
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -57,6 +49,6 @@ class Cpu {
|
|||||||
Psr und;
|
Psr und;
|
||||||
} spsr_banked; // banked saved program status registers
|
} spsr_banked; // banked saved program status registers
|
||||||
|
|
||||||
void chg_mode(Mode from, Mode to);
|
void chg_mode(const Mode to);
|
||||||
std::string exec_arm(uint32_t insn);
|
std::string exec_arm(const uint32_t insn);
|
||||||
};
|
};
|
||||||
|
@@ -5,25 +5,27 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
using namespace logger;
|
using namespace logger;
|
||||||
|
using std::array;
|
||||||
|
using stringv = std::string_view;
|
||||||
|
|
||||||
std::string
|
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));
|
Condition cond = static_cast<Condition>(get_bit_range(insn, 28, 31));
|
||||||
std::string disassembled;
|
std::string disassembled;
|
||||||
|
|
||||||
auto pc_error = [](uint8_t r, const char* syn) {
|
auto pc_error = [](uint8_t r, stringv syn) {
|
||||||
if (r == 15)
|
if (r == 15)
|
||||||
log_error("Using PC (R15) as operand in {}", syn);
|
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)
|
if (r == 15)
|
||||||
log_warn("Using PC (R15) as operand in {}", syn);
|
log_warn("Using PC (R15) as operand in {}", syn);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Branch and exhcange
|
// Branch and exhcange
|
||||||
if ((insn & 0x0FFFFFF0) == 0x012FFF10) {
|
if ((insn & 0x0FFFFFF0) == 0x012FFF10) {
|
||||||
static constexpr char syn[] = "BX";
|
static constexpr stringv syn = "BX";
|
||||||
|
|
||||||
uint8_t rn = insn & 0b1111;
|
uint8_t rn = insn & 0b1111;
|
||||||
|
|
||||||
@@ -38,16 +40,16 @@ Cpu::exec_arm(uint32_t insn) {
|
|||||||
cpsr.set_state(state);
|
cpsr.set_state(state);
|
||||||
|
|
||||||
// copy to PC
|
// copy to PC
|
||||||
gpr[15] = gpr[rn];
|
pc = gpr[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(gpr[15], 0);
|
rst_nth_bit(pc, 0);
|
||||||
if (state == State::Arm)
|
if (state == State::Arm)
|
||||||
rst_nth_bit(gpr[15], 1);
|
rst_nth_bit(pc, 1);
|
||||||
}
|
}
|
||||||
// Branch
|
// Branch
|
||||||
} else if ((insn & 0x0E000000) == 0x0A000000) {
|
} else if ((insn & 0x0E000000) == 0x0A000000) {
|
||||||
static constexpr char syn[] = "B";
|
static constexpr stringv syn = "B";
|
||||||
|
|
||||||
bool link = get_nth_bit(insn, 24);
|
bool link = get_nth_bit(insn, 24);
|
||||||
uint32_t offset = get_bit_range(insn, 0, 23);
|
uint32_t offset = get_bit_range(insn, 0, 23);
|
||||||
@@ -63,14 +65,14 @@ Cpu::exec_arm(uint32_t insn) {
|
|||||||
offset |= 0xFC000000;
|
offset |= 0xFC000000;
|
||||||
|
|
||||||
if (link)
|
if (link)
|
||||||
gpr[14] = gpr[15] - ARM_INSTRUCTION_SIZE;
|
gpr[14] = pc - ARM_INSTRUCTION_SIZE;
|
||||||
|
|
||||||
gpr[15] += offset;
|
pc += offset - ARM_INSTRUCTION_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply
|
// Multiply
|
||||||
} else if ((insn & 0x0FC000F0) == 0x00000090) {
|
} 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 rm = get_bit_range(insn, 0, 3);
|
||||||
uint8_t rs = get_bit_range(insn, 8, 11);
|
uint8_t rs = get_bit_range(insn, 8, 11);
|
||||||
@@ -117,8 +119,9 @@ Cpu::exec_arm(uint32_t insn) {
|
|||||||
}
|
}
|
||||||
// Multiply long
|
// Multiply long
|
||||||
} else if ((insn & 0x0F8000F0) == 0x00800090) {
|
} else if ((insn & 0x0F8000F0) == 0x00800090) {
|
||||||
static constexpr char syn[2][2][6] = { { "SMULL", "SMLAL" },
|
static constexpr array<array<stringv, 2>, 2> syn = {
|
||||||
{ "UMULL", "UMLAL" } };
|
{ { "SMULL", "SMLAL" }, { "UMULL", "UMLAL" } }
|
||||||
|
};
|
||||||
|
|
||||||
uint8_t rm = get_bit_range(insn, 0, 3);
|
uint8_t rm = get_bit_range(insn, 0, 3);
|
||||||
uint8_t rs = get_bit_range(insn, 8, 11);
|
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);
|
gpr[rdhi] = get_bit_range(eval, 32, 63);
|
||||||
|
|
||||||
} else {
|
} 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]) +
|
static_cast<int64_t>(gpr[rs]) +
|
||||||
(a ? static_cast<int64_t>(gpr[rdhi]) << 32 |
|
(a ? static_cast<int64_t>(gpr[rdhi]) << 32 |
|
||||||
static_cast<int64_t>(gpr[rdlo])
|
static_cast<int64_t>(gpr[rdlo])
|
||||||
@@ -178,7 +181,7 @@ Cpu::exec_arm(uint32_t insn) {
|
|||||||
|
|
||||||
// Single data swap
|
// Single data swap
|
||||||
} else if ((insn & 0x0FB00FF0) == 0x01000090) {
|
} 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 rm = get_bit_range(insn, 0, 3);
|
||||||
uint8_t rd = get_bit_range(insn, 12, 15);
|
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
|
// TODO: create abstraction to reuse for block data and single data
|
||||||
// transfer
|
// transfer
|
||||||
} else if ((insn & 0x0E000090) == 0x00000090) {
|
} 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 rm = get_bit_range(insn, 0, 3);
|
||||||
uint8_t h = get_nth_bit(insn, 5);
|
uint8_t h = get_nth_bit(insn, 5);
|
||||||
uint8_t s = get_nth_bit(insn, 6);
|
uint8_t s = get_nth_bit(insn, 6);
|
||||||
uint8_t rd = get_bit_range(insn, 12, 15);
|
uint8_t rd = get_bit_range(insn, 12, 15);
|
||||||
uint8_t rn = get_bit_range(insn, 16, 19);
|
uint8_t rn = get_bit_range(insn, 16, 19);
|
||||||
bool l = get_nth_bit(insn, 20);
|
bool l = get_nth_bit(insn, 20);
|
||||||
bool w = get_nth_bit(insn, 21);
|
bool w = get_nth_bit(insn, 21);
|
||||||
bool imm = get_nth_bit(insn, 22);
|
bool imm = get_nth_bit(insn, 22);
|
||||||
bool u = get_nth_bit(insn, 23);
|
bool u = get_nth_bit(insn, 23);
|
||||||
bool p = get_nth_bit(insn, 24);
|
bool p = get_nth_bit(insn, 24);
|
||||||
uint32_t offset;
|
uint32_t offset = 0;
|
||||||
|
|
||||||
|
std::string syn =
|
||||||
|
fmt::format("{}{}{}", syn_[l], (s ? "S" : ""), (h ? 'H' : 'B'));
|
||||||
|
|
||||||
if (!p && w)
|
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)
|
if (s && !l)
|
||||||
log_error("Signed data found in {}", syn[l]);
|
log_error("Signed data found in {}", syn);
|
||||||
|
|
||||||
if (w)
|
if (w)
|
||||||
pc_error(rn, syn[l]);
|
pc_error(rn, syn);
|
||||||
pc_error(rm, syn[l]);
|
pc_error(rm, syn);
|
||||||
|
|
||||||
if (rd == 15 && !l && s && h)
|
|
||||||
;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
offset = (imm ? get_bit_range(insn, 8, 11) << 4 | rm : gpr[rm]);
|
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));
|
(imm ? offset : rm));
|
||||||
|
|
||||||
disassembled = fmt::format(
|
disassembled = fmt::format(
|
||||||
"{}{}{}{} R{:d}{}",
|
"{}{}{}{} R{:d},{}",
|
||||||
syn[l],
|
syn_[l],
|
||||||
cond,
|
cond,
|
||||||
(s ? "S" : ""),
|
(s ? "S" : ""),
|
||||||
(h ? 'H' : 'B'),
|
(h ? 'H' : 'B'),
|
||||||
@@ -254,7 +257,10 @@ Cpu::exec_arm(uint32_t insn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cpsr.condition(cond)) {
|
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
|
// load
|
||||||
if (l) {
|
if (l) {
|
||||||
@@ -287,7 +293,92 @@ Cpu::exec_arm(uint32_t insn) {
|
|||||||
bus->write_halfword(address, gpr[rd]);
|
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;
|
return disassembled;
|
||||||
|
@@ -2,9 +2,8 @@
|
|||||||
#include "util/bits.hh"
|
#include "util/bits.hh"
|
||||||
#include "util/log.hh"
|
#include "util/log.hh"
|
||||||
|
|
||||||
Psr::Psr(uint32_t raw) {
|
Psr::Psr(uint32_t raw)
|
||||||
psr = raw & PSR_CLEAR_RESERVED;
|
: psr(raw & PSR_CLEAR_RESERVED) {}
|
||||||
}
|
|
||||||
|
|
||||||
Mode
|
Mode
|
||||||
Psr::mode() const {
|
Psr::mode() const {
|
||||||
|
@@ -32,3 +32,23 @@ operator<<(std::ostream& os, const Condition cond) {
|
|||||||
|
|
||||||
return os;
|
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
|
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 {
|
enum class OpCode {
|
||||||
AND = 0b0000,
|
AND = 0b0000,
|
||||||
EOR = 0b0001,
|
EOR = 0b0001,
|
||||||
@@ -68,6 +74,6 @@ enum class ShiftType {
|
|||||||
|
|
||||||
// https://fmt.dev/dev/api.html#std-ostream-support
|
// https://fmt.dev/dev/api.html#std-ostream-support
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& os, const Condition cond);
|
operator<<(std::ostream& os, const ShiftType cond);
|
||||||
template<>
|
template<>
|
||||||
struct fmt::formatter<Condition> : ostream_formatter {};
|
struct fmt::formatter<ShiftType> : ostream_formatter {};
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -33,9 +34,9 @@ typedef struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint32_t entrypoint;
|
uint32_t entrypoint;
|
||||||
char title[12];
|
std::string title;
|
||||||
|
std::string title_code;
|
||||||
UniqueCode unique_code;
|
UniqueCode unique_code;
|
||||||
char title_code[2];
|
|
||||||
I18n i18n;
|
I18n i18n;
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
BootMode multiboot;
|
BootMode multiboot;
|
||||||
|
@@ -10,14 +10,14 @@ using namespace logger;
|
|||||||
Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
||||||
std::vector<uint8_t>&& rom) noexcept
|
std::vector<uint8_t>&& rom) noexcept
|
||||||
: bios(std::move(bios))
|
: bios(std::move(bios))
|
||||||
, board_wram(0)
|
, board_wram({ 0 })
|
||||||
, chip_wram(0)
|
, chip_wram({ 0 })
|
||||||
, palette_ram(0)
|
, palette_ram({ 0 })
|
||||||
, vram(0)
|
, vram({ 0 })
|
||||||
, oam_obj_attr(0)
|
, oam_obj_attr({ 0 })
|
||||||
, rom(std::move(rom)) {
|
, rom(std::move(rom)) {
|
||||||
std::string bios_hash = crypto::sha256(bios.data(), bios.size());
|
std::string bios_hash = crypto::sha256(this->bios);
|
||||||
static constexpr char expected_hash[] =
|
static constexpr std::string_view expected_hash =
|
||||||
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
||||||
|
|
||||||
if (bios_hash != expected_hash) {
|
if (bios_hash != expected_hash) {
|
||||||
@@ -137,7 +137,7 @@ Memory::parse_header() {
|
|||||||
log_info("HEADER: BIOS debugger bits not set to 0");
|
log_info("HEADER: BIOS debugger bits not set to 0");
|
||||||
|
|
||||||
// game info
|
// game info
|
||||||
std::copy(&rom[0xA0], &rom[0xA0 + 12], header.title);
|
header.title = std::string(&rom[0xA0], &rom[0xA0 + 12]);
|
||||||
|
|
||||||
switch (rom[0xAC]) {
|
switch (rom[0xAC]) {
|
||||||
case 'A':
|
case 'A':
|
||||||
@@ -172,8 +172,7 @@ Memory::parse_header() {
|
|||||||
log_error("HEADER: invalid unique code: {}", rom[0xAC]);
|
log_error("HEADER: invalid unique code: {}", rom[0xAC]);
|
||||||
}
|
}
|
||||||
|
|
||||||
header.title_code[0] = rom[0xAD];
|
header.title_code = std::string(&rom[0xAD], &rom[0xAE]);
|
||||||
header.title_code[1] = rom[0xAE];
|
|
||||||
|
|
||||||
switch (rom[0xAF]) {
|
switch (rom[0xAF]) {
|
||||||
case 'J':
|
case 'J':
|
||||||
|
@@ -29,7 +29,7 @@ class Memory {
|
|||||||
|
|
||||||
#define DECL_MEMORY(name, ident, start, end) \
|
#define DECL_MEMORY(name, ident, start, end) \
|
||||||
MEMORY_REGION(name, 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)
|
MEMORY_REGION(BIOS, 0x00000000, 0x00003FFF)
|
||||||
std::array<uint8_t, BIOS_SIZE> bios;
|
std::array<uint8_t, BIOS_SIZE> bios;
|
||||||
|
@@ -3,7 +3,6 @@ lib_sources = files(
|
|||||||
'bus.cc'
|
'bus.cc'
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('util')
|
|
||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
|
|
||||||
fmt = dependency('fmt', version : '>=10.1.0')
|
fmt = dependency('fmt', version : '>=10.1.0')
|
||||||
|
@@ -3,54 +3,55 @@
|
|||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace logger {
|
using fmt::print;
|
||||||
inline std::ostream& stream = std::clog;
|
using std::clog;
|
||||||
|
|
||||||
|
namespace logger {
|
||||||
namespace ansi {
|
namespace ansi {
|
||||||
static constexpr char RED[] = "\033[31m";
|
static constexpr std::string_view RED = "\033[31m";
|
||||||
static constexpr char YELLOW[] = "\033[33m";
|
static constexpr std::string_view YELLOW = "\033[33m";
|
||||||
static constexpr char MAGENTA[] = "\033[35m";
|
static constexpr std::string_view MAGENTA = "\033[35m";
|
||||||
static constexpr char WHITE[] = "\033[37m";
|
static constexpr std::string_view WHITE = "\033[37m";
|
||||||
static constexpr char BOLD[] = "\033[1m";
|
static constexpr std::string_view BOLD = "\033[1m";
|
||||||
static constexpr char RESET[] = "\033[0m";
|
static constexpr std::string_view RESET = "\033[0m";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
inline void
|
||||||
log_raw(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
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>
|
template<typename... Args>
|
||||||
inline void
|
inline void
|
||||||
log_debug(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
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)...);
|
log_raw(fmt, std::forward<Args>(args)...);
|
||||||
fmt::print(stream, ansi::RESET);
|
print(clog, ansi::RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
inline void
|
||||||
log_info(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
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)...);
|
log_raw(fmt, std::forward<Args>(args)...);
|
||||||
fmt::print(stream, ansi::RESET);
|
print(clog, ansi::RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
inline void
|
||||||
log_warn(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
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)...);
|
log_raw(fmt, std::forward<Args>(args)...);
|
||||||
fmt::print(stream, ansi::RESET);
|
print(clog, ansi::RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
inline void
|
||||||
log_error(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
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)...);
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <bit>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// Why I wrote this myself? I do not know
|
// Why I wrote this myself? I do not know
|
||||||
// I will off myself 😹😹😹😹
|
// I will off myself 😹😹😹😹
|
||||||
namespace crypto {
|
namespace crypto {
|
||||||
|
|
||||||
|
using std::rotr;
|
||||||
|
|
||||||
|
template<typename std::size_t N>
|
||||||
std::string
|
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