log: encapsulate logger
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
@@ -6,4 +6,5 @@ Checks: '
|
|||||||
, -cppcoreguidelines-macro-usage
|
, -cppcoreguidelines-macro-usage
|
||||||
, -cppcoreguidelines-avoid-const-or-ref-data-members
|
, -cppcoreguidelines-avoid-const-or-ref-data-members
|
||||||
, -cppcoreguidelines-non-private-member-variables-in-classes
|
, -cppcoreguidelines-non-private-member-variables-in-classes
|
||||||
|
, -cppcoreguidelines-avoid-non-const-global-variables
|
||||||
'
|
'
|
@@ -1,6 +1,7 @@
|
|||||||
#include "bus.hh"
|
#include "bus.hh"
|
||||||
#include "cpu/cpu.hh"
|
#include "cpu/cpu.hh"
|
||||||
#include "memory.hh"
|
#include "memory.hh"
|
||||||
|
#include "util/loglevel.hh"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -84,6 +85,8 @@ main(int argc, const char* argv[]) {
|
|||||||
std::flush(std::cout);
|
std::flush(std::cout);
|
||||||
std::flush(std::cout);
|
std::flush(std::cout);
|
||||||
|
|
||||||
|
matar::set_log_level(matar::LogLevel::Debug);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
matar::Memory memory(std::move(bios), std::move(rom));
|
matar::Memory memory(std::move(bios), std::move(rom));
|
||||||
matar::Bus bus(memory);
|
matar::Bus bus(memory);
|
||||||
|
@@ -7,5 +7,6 @@ headers = files(
|
|||||||
inc = include_directories('.')
|
inc = include_directories('.')
|
||||||
|
|
||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
|
subdir('util')
|
||||||
|
|
||||||
install_headers(headers, subdir: meson.project_name(), preserve_path: true)
|
install_headers(headers, subdir: meson.project_name(), preserve_path: true)
|
14
include/util/loglevel.hh
Normal file
14
include/util/loglevel.hh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace matar {
|
||||||
|
enum class LogLevel {
|
||||||
|
Off = 1 << 0,
|
||||||
|
Error = 1 << 1,
|
||||||
|
Warn = 1 << 2,
|
||||||
|
Info = 1 << 3,
|
||||||
|
Debug = 1 << 4
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
set_log_level(LogLevel level);
|
||||||
|
}
|
3
include/util/meson.build
Normal file
3
include/util/meson.build
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
headers += files(
|
||||||
|
'loglevel.hh'
|
||||||
|
)
|
@@ -2,27 +2,24 @@
|
|||||||
#include "util/bits.hh"
|
#include "util/bits.hh"
|
||||||
#include "util/log.hh"
|
#include "util/log.hh"
|
||||||
|
|
||||||
using namespace logger;
|
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
void
|
void
|
||||||
CpuImpl::exec_arm(const arm::Instruction instruction) {
|
CpuImpl::exec_arm(const arm::Instruction instruction) {
|
||||||
Condition cond = instruction.condition;
|
Condition cond = instruction.condition;
|
||||||
arm::InstructionData data = instruction.data;
|
arm::InstructionData data = instruction.data;
|
||||||
|
|
||||||
debug(cpsr.condition(cond));
|
|
||||||
if (!cpsr.condition(cond)) {
|
if (!cpsr.condition(cond)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pc_error = [](uint8_t r) {
|
auto pc_error = [](uint8_t r) {
|
||||||
if (r == PC_INDEX)
|
if (r == PC_INDEX)
|
||||||
log_error("Using PC (R15) as operand register");
|
glogger.error("Using PC (R15) as operand register");
|
||||||
};
|
};
|
||||||
|
|
||||||
auto pc_warn = [](uint8_t r) {
|
auto pc_warn = [](uint8_t r) {
|
||||||
if (r == PC_INDEX)
|
if (r == PC_INDEX)
|
||||||
log_warn("Using PC (R15) as operand register");
|
glogger.warn("Using PC (R15) as operand register");
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace arm;
|
using namespace arm;
|
||||||
@@ -62,7 +59,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
},
|
},
|
||||||
[this, pc_error](Multiply& data) {
|
[this, pc_error](Multiply& data) {
|
||||||
if (data.rd == data.rm)
|
if (data.rd == data.rm)
|
||||||
log_error("rd and rm are not distinct in {}",
|
glogger.error("rd and rm are not distinct in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
|
|
||||||
pc_error(data.rd);
|
pc_error(data.rd);
|
||||||
@@ -81,7 +78,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
[this, pc_error](MultiplyLong& data) {
|
[this, pc_error](MultiplyLong& data) {
|
||||||
if (data.rdhi == data.rdlo || data.rdhi == data.rm ||
|
if (data.rdhi == data.rdlo || data.rdhi == data.rm ||
|
||||||
data.rdlo == data.rm)
|
data.rdlo == data.rm)
|
||||||
log_error("rdhi, rdlo and rm are not distinct in {}",
|
glogger.error("rdhi, rdlo and rm are not distinct in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
|
|
||||||
pc_error(data.rdhi);
|
pc_error(data.rdhi);
|
||||||
@@ -123,7 +120,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
cpsr.set_v(0);
|
cpsr.set_v(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[](Undefined) { log_warn("Undefined instruction"); },
|
[](Undefined) { glogger.warn("Undefined instruction"); },
|
||||||
[this, pc_error](SingleDataSwap& data) {
|
[this, pc_error](SingleDataSwap& data) {
|
||||||
pc_error(data.rm);
|
pc_error(data.rm);
|
||||||
pc_error(data.rn);
|
pc_error(data.rn);
|
||||||
@@ -142,11 +139,11 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
uint32_t address = gpr[data.rn];
|
uint32_t address = gpr[data.rn];
|
||||||
|
|
||||||
if (!data.pre && data.write)
|
if (!data.pre && data.write)
|
||||||
log_warn("Write-back enabled with post-indexing in {}",
|
glogger.warn("Write-back enabled with post-indexing in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
|
|
||||||
if (data.rn == PC_INDEX && data.write)
|
if (data.rn == PC_INDEX && data.write)
|
||||||
log_warn("Write-back enabled with base register as PC {}",
|
glogger.warn("Write-back enabled with base register as PC {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
|
|
||||||
if (data.write)
|
if (data.write)
|
||||||
@@ -216,11 +213,11 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
|
||||||
if (!data.pre && data.write)
|
if (!data.pre && data.write)
|
||||||
log_error("Write-back enabled with post-indexing in {}",
|
glogger.error("Write-back enabled with post-indexing in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
|
|
||||||
if (data.sign && !data.load)
|
if (data.sign && !data.load)
|
||||||
log_error("Signed data found in {}", typeid(data).name());
|
glogger.error("Signed data found in {}", typeid(data).name());
|
||||||
|
|
||||||
if (data.write)
|
if (data.write)
|
||||||
pc_warn(data.rn);
|
pc_warn(data.rn);
|
||||||
@@ -294,7 +291,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
pc_error(data.rn);
|
pc_error(data.rn);
|
||||||
|
|
||||||
if (cpsr.mode() == Mode::User && data.s) {
|
if (cpsr.mode() == Mode::User && data.s) {
|
||||||
log_error("Bit S is set outside priviliged modes in {}",
|
glogger.error("Bit S is set outside priviliged modes in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +301,8 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
chg_mode(Mode::User);
|
chg_mode(Mode::User);
|
||||||
|
|
||||||
if (data.write) {
|
if (data.write) {
|
||||||
log_error("Write-back enable for user bank registers in {}",
|
glogger.error(
|
||||||
|
"Write-back enable for user bank registers in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -358,7 +356,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
},
|
},
|
||||||
[this, pc_error](PsrTransfer& data) {
|
[this, pc_error](PsrTransfer& data) {
|
||||||
if (data.spsr && cpsr.mode() == Mode::User) {
|
if (data.spsr && cpsr.mode() == Mode::User) {
|
||||||
log_error("Accessing SPSR in User mode in {}",
|
glogger.error("Accessing SPSR in User mode in {}",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,7 +511,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
if (data.set) {
|
if (data.set) {
|
||||||
if (data.rd == PC_INDEX) {
|
if (data.rd == PC_INDEX) {
|
||||||
if (cpsr.mode() == Mode::User)
|
if (cpsr.mode() == Mode::User)
|
||||||
log_error("Running {} in User mode",
|
glogger.error("Running {} in User mode",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
spsr = cpsr;
|
spsr = cpsr;
|
||||||
} else {
|
} else {
|
||||||
@@ -536,7 +534,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
spsr = cpsr;
|
spsr = cpsr;
|
||||||
},
|
},
|
||||||
[](auto& data) {
|
[](auto& data) {
|
||||||
log_error("Unimplemented {} instruction", typeid(data).name());
|
glogger.error("Unimplemented {} instruction", typeid(data).name());
|
||||||
} },
|
} },
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
@@ -4,8 +4,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
using namespace logger;
|
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
CpuImpl::CpuImpl(const Bus& bus) noexcept
|
CpuImpl::CpuImpl(const Bus& bus) noexcept
|
||||||
: bus(std::make_shared<Bus>(bus))
|
: bus(std::make_shared<Bus>(bus))
|
||||||
@@ -19,7 +17,7 @@ CpuImpl::CpuImpl(const Bus& bus) noexcept
|
|||||||
cpsr.set_irq_disabled(true);
|
cpsr.set_irq_disabled(true);
|
||||||
cpsr.set_fiq_disabled(true);
|
cpsr.set_fiq_disabled(true);
|
||||||
cpsr.set_state(State::Arm);
|
cpsr.set_state(State::Arm);
|
||||||
log_info("CPU successfully initialised");
|
glogger.info("CPU successfully initialised");
|
||||||
|
|
||||||
// PC always points to two instructions ahead
|
// PC always points to two instructions ahead
|
||||||
// PC - 2 is the instruction being executed
|
// PC - 2 is the instruction being executed
|
||||||
@@ -121,14 +119,13 @@ CpuImpl::step() {
|
|||||||
uint32_t cur_pc = pc - 2 * arm::INSTRUCTION_SIZE;
|
uint32_t cur_pc = pc - 2 * arm::INSTRUCTION_SIZE;
|
||||||
|
|
||||||
if (cpsr.state() == State::Arm) {
|
if (cpsr.state() == State::Arm) {
|
||||||
debug(cur_pc);
|
|
||||||
uint32_t x = bus->read_word(cur_pc);
|
uint32_t x = bus->read_word(cur_pc);
|
||||||
arm::Instruction instruction(x);
|
arm::Instruction instruction(x);
|
||||||
log_info("{:#034b}", x);
|
glogger.info("{:#034b}", x);
|
||||||
|
|
||||||
exec_arm(instruction);
|
exec_arm(instruction);
|
||||||
|
|
||||||
log_info("0x{:08X} : {}", cur_pc, instruction.disassemble());
|
glogger.info("0x{:08X} : {}", cur_pc, instruction.disassemble());
|
||||||
|
|
||||||
if (is_flushed) {
|
if (is_flushed) {
|
||||||
// if flushed, do not increment the PC, instead set it to two
|
// if flushed, do not increment the PC, instead set it to two
|
||||||
|
@@ -6,8 +6,6 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace logger;
|
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
||||||
std::vector<uint8_t>&& rom)
|
std::vector<uint8_t>&& rom)
|
||||||
@@ -23,7 +21,7 @@ Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
|||||||
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
||||||
|
|
||||||
if (bios_hash != expected_hash) {
|
if (bios_hash != expected_hash) {
|
||||||
log_warn("BIOS hash failed to match, run at your own risk"
|
glogger.warn("BIOS hash failed to match, run at your own risk"
|
||||||
"\nExpected : {} "
|
"\nExpected : {} "
|
||||||
"\nGot : {}",
|
"\nGot : {}",
|
||||||
expected_hash,
|
expected_hash,
|
||||||
@@ -32,8 +30,8 @@ Memory::Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
|
|||||||
|
|
||||||
parse_header();
|
parse_header();
|
||||||
|
|
||||||
log_info("Memory successfully initialised");
|
glogger.info("Memory successfully initialised");
|
||||||
log_info("Cartridge Title: {}", header.title);
|
glogger.info("Cartridge Title: {}", header.title);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MATCHES(area) address >= area##_START&& address <= area##_END
|
#define MATCHES(area) address >= area##_START&& address <= area##_END
|
||||||
@@ -59,7 +57,7 @@ Memory::read(size_t address) const {
|
|||||||
} else if (MATCHES(ROM_2)) {
|
} else if (MATCHES(ROM_2)) {
|
||||||
return rom[address - ROM_2_START];
|
return rom[address - ROM_2_START];
|
||||||
} else {
|
} else {
|
||||||
log_error("Invalid memory region accessed");
|
glogger.error("Invalid memory region accessed");
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +83,7 @@ Memory::write(size_t address, uint8_t byte) {
|
|||||||
} else if (MATCHES(ROM_2)) {
|
} else if (MATCHES(ROM_2)) {
|
||||||
rom[address - ROM_2_START] = byte;
|
rom[address - ROM_2_START] = byte;
|
||||||
} else {
|
} else {
|
||||||
log_error("Invalid memory region accessed");
|
glogger.error("Invalid memory region accessed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +92,7 @@ Memory::write(size_t address, uint8_t byte) {
|
|||||||
uint16_t
|
uint16_t
|
||||||
Memory::read_halfword(size_t address) const {
|
Memory::read_halfword(size_t address) const {
|
||||||
if (address & 0b01)
|
if (address & 0b01)
|
||||||
log_warn("Reading a non aligned halfword address");
|
glogger.warn("Reading a non aligned halfword address");
|
||||||
|
|
||||||
return read(address) | read(address + 1) << 8;
|
return read(address) | read(address + 1) << 8;
|
||||||
}
|
}
|
||||||
@@ -102,7 +100,7 @@ Memory::read_halfword(size_t address) const {
|
|||||||
void
|
void
|
||||||
Memory::write_halfword(size_t address, uint16_t halfword) {
|
Memory::write_halfword(size_t address, uint16_t halfword) {
|
||||||
if (address & 0b01)
|
if (address & 0b01)
|
||||||
log_warn("Writing to a non aligned halfword address");
|
glogger.warn("Writing to a non aligned halfword address");
|
||||||
|
|
||||||
write(address, halfword & 0xFF);
|
write(address, halfword & 0xFF);
|
||||||
write(address + 1, halfword >> 8 & 0xFF);
|
write(address + 1, halfword >> 8 & 0xFF);
|
||||||
@@ -111,7 +109,7 @@ Memory::write_halfword(size_t address, uint16_t halfword) {
|
|||||||
uint32_t
|
uint32_t
|
||||||
Memory::read_word(size_t address) const {
|
Memory::read_word(size_t address) const {
|
||||||
if (address & 0b11)
|
if (address & 0b11)
|
||||||
log_warn("Reading a non aligned word address");
|
glogger.warn("Reading a non aligned word address");
|
||||||
|
|
||||||
return read(address) | read(address + 1) << 8 | read(address + 2) << 16 |
|
return read(address) | read(address + 1) << 8 | read(address + 2) << 16 |
|
||||||
read(address + 3) << 24;
|
read(address + 3) << 24;
|
||||||
@@ -120,7 +118,7 @@ Memory::read_word(size_t address) const {
|
|||||||
void
|
void
|
||||||
Memory::write_word(size_t address, uint32_t word) {
|
Memory::write_word(size_t address, uint32_t word) {
|
||||||
if (address & 0b11)
|
if (address & 0b11)
|
||||||
log_warn("Writing to a non aligned word address");
|
glogger.warn("Writing to a non aligned word address");
|
||||||
|
|
||||||
write(address, word & 0xFF);
|
write(address, word & 0xFF);
|
||||||
write(address + 1, word >> 8 & 0xFF);
|
write(address + 1, word >> 8 & 0xFF);
|
||||||
@@ -142,7 +140,7 @@ Memory::parse_header() {
|
|||||||
|
|
||||||
// nintendo logo
|
// nintendo logo
|
||||||
if (rom[0x9C] != 0x21)
|
if (rom[0x9C] != 0x21)
|
||||||
log_info("HEADER: BIOS debugger bits not set to 0");
|
glogger.info("HEADER: BIOS debugger bits not set to 0");
|
||||||
|
|
||||||
// game info
|
// game info
|
||||||
header.title = std::string(&rom[0xA0], &rom[0xA0 + 12]);
|
header.title = std::string(&rom[0xA0], &rom[0xA0 + 12]);
|
||||||
@@ -177,7 +175,7 @@ Memory::parse_header() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_error("HEADER: invalid unique code: {}", rom[0xAC]);
|
glogger.error("HEADER: invalid unique code: {}", rom[0xAC]);
|
||||||
}
|
}
|
||||||
|
|
||||||
header.title_code = std::string(&rom[0xAD], &rom[0xAE]);
|
header.title_code = std::string(&rom[0xAD], &rom[0xAE]);
|
||||||
@@ -206,15 +204,16 @@ Memory::parse_header() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_error("HEADER: invalid destination/language: {}", rom[0xAF]);
|
glogger.error("HEADER: invalid destination/language: {}",
|
||||||
|
rom[0xAF]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rom[0xB2] != 0x96)
|
if (rom[0xB2] != 0x96)
|
||||||
log_error("HEADER: invalid fixed byte at 0xB2");
|
glogger.error("HEADER: invalid fixed byte at 0xB2");
|
||||||
|
|
||||||
for (size_t i = 0xB5; i < 0xBC; i++) {
|
for (size_t i = 0xB5; i < 0xBC; i++) {
|
||||||
if (rom[i] != 0x00)
|
if (rom[i] != 0x00)
|
||||||
log_error("HEADER: invalid fixed bytes at 0xB5");
|
glogger.error("HEADER: invalid fixed bytes at 0xB5");
|
||||||
}
|
}
|
||||||
|
|
||||||
header.version = rom[0xBC];
|
header.version = rom[0xBC];
|
||||||
@@ -228,7 +227,7 @@ Memory::parse_header() {
|
|||||||
chk &= 0xFF;
|
chk &= 0xFF;
|
||||||
|
|
||||||
if (chk != rom[0xBD])
|
if (chk != rom[0xBD])
|
||||||
log_error("HEADER: checksum does not match");
|
glogger.error("HEADER: checksum does not match");
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiboot not required right now
|
// multiboot not required right now
|
||||||
|
@@ -3,9 +3,9 @@ lib_sources = files(
|
|||||||
'bus.cc'
|
'bus.cc'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
subdir('util')
|
||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
|
|
||||||
|
|
||||||
lib_cpp_args = [ ]
|
lib_cpp_args = [ ]
|
||||||
|
|
||||||
fmt = dependency('fmt', version : '>=10.1.0', static: true)
|
fmt = dependency('fmt', version : '>=10.1.0', static: true)
|
||||||
|
8
src/util/log.cc
Normal file
8
src/util/log.cc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "log.hh"
|
||||||
|
|
||||||
|
logging::Logger glogger = logging::Logger();
|
||||||
|
|
||||||
|
void
|
||||||
|
matar::set_log_level(LogLevel level) {
|
||||||
|
glogger.set_level(level);
|
||||||
|
}
|
@@ -1,12 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/loglevel.hh"
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using fmt::print;
|
namespace logging {
|
||||||
using std::clog;
|
|
||||||
|
|
||||||
namespace logger {
|
|
||||||
namespace ansi {
|
namespace ansi {
|
||||||
static constexpr std::string_view RED = "\033[31m";
|
static constexpr std::string_view RED = "\033[31m";
|
||||||
static constexpr std::string_view YELLOW = "\033[33m";
|
static constexpr std::string_view YELLOW = "\033[33m";
|
||||||
@@ -16,43 +14,69 @@ static constexpr std::string_view BOLD = "\033[1m";
|
|||||||
static constexpr std::string_view RESET = "\033[0m";
|
static constexpr std::string_view RESET = "\033[0m";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
using fmt::print;
|
||||||
inline void
|
|
||||||
log_raw(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
class Logger {
|
||||||
fmt::println(clog, fmt, std::forward<Args>(args)...);
|
using LogLevel = matar::LogLevel;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Logger(LogLevel level = LogLevel::Debug)
|
||||||
|
: level(0) {
|
||||||
|
set_level(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
void log(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||||
log_debug(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
fmt::println(stream, fmt, std::forward<Args>(args)...);
|
||||||
print(clog, "{}{}[DEBUG] ", ansi::MAGENTA, ansi::BOLD);
|
|
||||||
log_raw(fmt, std::forward<Args>(args)...);
|
|
||||||
print(clog, ansi::RESET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
void debug(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||||
log_info(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
if (level & static_cast<uint8_t>(LogLevel::Debug)) {
|
||||||
print(clog, "{}[INFO] ", ansi::WHITE);
|
print(stream, "{}{}[DEBUG] ", ansi::MAGENTA, ansi::BOLD);
|
||||||
log_raw(fmt, std::forward<Args>(args)...);
|
log(fmt, std::forward<Args>(args)...);
|
||||||
print(clog, ansi::RESET);
|
print(stream, ansi::RESET);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
void info(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||||
log_warn(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
if (level & static_cast<uint8_t>(LogLevel::Info)) {
|
||||||
print(clog, "{}[WARN] ", ansi::YELLOW);
|
print(stream, "{}[INFO] ", ansi::WHITE);
|
||||||
log_raw(fmt, std::forward<Args>(args)...);
|
log(fmt, std::forward<Args>(args)...);
|
||||||
print(clog, ansi::RESET);
|
print(stream, ansi::RESET);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void
|
void warn(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||||
log_error(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
if (level & static_cast<uint8_t>(LogLevel::Warn)) {
|
||||||
print(clog, "{}{}[ERROR] ", ansi::RED, ansi::BOLD);
|
print(stream, "{}[WARN] ", ansi::YELLOW);
|
||||||
log_raw(fmt, std::forward<Args>(args)...);
|
log(fmt, std::forward<Args>(args)...);
|
||||||
print(clog, ansi::RESET);
|
print(stream, ansi::RESET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define debug(value) logger::log_debug("{} = {}", #value, value)
|
template<typename... Args>
|
||||||
|
void error(const fmt::format_string<Args...>& fmt, Args&&... args) {
|
||||||
|
if (level & static_cast<uint8_t>(LogLevel::Error)) {
|
||||||
|
print(stream, "{}{}[ERROR] ", ansi::RED, ansi::BOLD);
|
||||||
|
log(fmt, std::forward<Args>(args)...);
|
||||||
|
print(stream, ansi::RESET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_level(LogLevel level) {
|
||||||
|
this->level = (static_cast<uint8_t>(level) << 1) - 1;
|
||||||
|
}
|
||||||
|
void set_stream(std::ostream& stream) { this->stream = stream; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t level;
|
||||||
|
std::reference_wrapper<std::ostream> stream = std::clog;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern logging::Logger glogger;
|
||||||
|
|
||||||
|
#define debug(x) logger.debug("{} = {}", #x, x);
|
||||||
|
3
src/util/meson.build
Normal file
3
src/util/meson.build
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
lib_sources += files(
|
||||||
|
'log.cc'
|
||||||
|
)
|
8
tests/main.cc
Normal file
8
tests/main.cc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "util/loglevel.hh"
|
||||||
|
#include <catch2/catch_session.hpp>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[]) {
|
||||||
|
matar::set_log_level(matar::LogLevel::Off);
|
||||||
|
return Catch::Session().run(argc, argv);
|
||||||
|
}
|
@@ -4,11 +4,13 @@ tests_deps = [
|
|||||||
|
|
||||||
src = include_directories('../src')
|
src = include_directories('../src')
|
||||||
|
|
||||||
tests_sources = files()
|
tests_sources = files(
|
||||||
|
'main.cc'
|
||||||
|
)
|
||||||
|
|
||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
|
|
||||||
catch2 = dependency('catch2-with-main', version: '>=3.4.0', static: true)
|
catch2 = dependency('catch2', version: '>=3.4.0', static: true)
|
||||||
catch2_tests = executable(
|
catch2_tests = executable(
|
||||||
'matar_tests',
|
'matar_tests',
|
||||||
tests_sources,
|
tests_sources,
|
||||||
|
Reference in New Issue
Block a user