Use an output iterator for the lucore stdout sink

This commit is contained in:
Lily Tsuru 2023-07-18 00:47:10 -04:00
parent 58ee03c249
commit 6ebebae770
4 changed files with 70 additions and 14 deletions

View File

@ -1,3 +1,6 @@
#include <bits/iterator_concepts.h>
#include <cstddef>
#include <iostream>
#include <lucore/Logger.hpp>
@ -35,11 +38,31 @@ namespace lucore {
}
void StdoutSink::OutputMessage(const Logger::MessageData& data) {
// This is very nasty, but required until more standard libraries support the C++23 <print>
// This is kinda iffy, but required until more standard libraries support the C++23 <print>
// header.
std::puts(std::format("[Lucore/{}] [{}] {}", Logger::SeverityToString(data.severity),
data.time, std::vformat(data.format, data.args))
.c_str());
struct FileOutIterator {
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = void;
FileOutIterator(std::FILE* file) : file(file) {}
FileOutIterator& operator*() { return *this; }
FileOutIterator& operator++() { return *this; }
FileOutIterator& operator++(int) { return *this; }
FileOutIterator& operator=(const char& val) {
fputc(val, file);
return *this;
}
private:
std::FILE* file;
};
std::format_to(FileOutIterator(data.severity < Logger::MessageSeverity::Error ? stdout : stderr), "[Lucore/{}] [{}] {}\n",
Logger::SeverityToString(data.severity), data.time,
std::vformat(data.format, data.args));
}
void LoggerAttachStdout() {

View File

@ -29,12 +29,8 @@ namespace riscv {
/// the ability to... well, clock!
virtual void Clock() {}
// TODO(feat): Need to implement ability to generate interrupts
// from devices. This needs to be implemented to facilitate the
// implementation of the timer device as an actual Device implmentation
// instead of poorly hard-coding it into the CPU core logic.
//
// Also, default implementations of Peek* and Poke* should trap.
// TODO(feat): default implementations of Peek* and Poke* should exist
// and trap the CPU (similarly to what happens if a unmapped bus read occurs).
// Peek() -> reads a value from this device.
@ -49,6 +45,7 @@ namespace riscv {
};
Bus(CPU* cpu);
~Bus();
/// Attach a device to the bus.
@ -66,7 +63,6 @@ namespace riscv {
/// Clock all clocked devices.
void Clock();
//
u8 PeekByte(AddressT address);
u16 PeekShort(AddressT address);
u32 PeekWord(AddressT address);

View File

@ -1,11 +1,43 @@
#include <riscv/Bus.hpp>
#include <riscv/Types.hpp>
namespace riscv {
/** The CPU core. There will be one of these in a [System]. */
/** The CPU core. */
struct CPU {
struct State {
u32 gpr[32];
u32 pc;
u32 mstatus;
u32 cyclel;
u32 cycleh;
u32 timerl;
u32 timerh;
u32 timermatchl;
u32 timermatchh;
u32 mscratch;
u32 mtvec;
u32 mie;
u32 mip;
u32 mepc;
u32 mtval;
u32 mcause;
// Note: only a few bits are used. (Machine = 3, User = 0)
// Bits 0..1 = privilege.
// Bit 2 = WFI (Wait for interrupt)
// Bit 3+ = Load/Store reservation LSBs.
u32 extraflags;
};
State& GetState() { return state; }
private:
State state;
Bus bus;
};
}
} // namespace riscv

View File

@ -3,6 +3,11 @@
namespace riscv {
Bus::Bus(CPU* cpu)
: attachedCpu(cpu) {
}
Bus::~Bus() {
// Free all devices
for(auto& pair : mapped_devices)