revert loggingsystem usage until I feel safe requiring x64 gmod
This commit is contained in:
parent
0d6646f8cb
commit
e3ffcb02c2
|
@ -0,0 +1,8 @@
|
||||||
|
Copyright 2023 Lily Tsuru <lily.modeco80@protonmail.ch>
|
||||||
|
Portions copyright 2022 Charles Lohr (CNLohr)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
33
README.md
33
README.md
|
@ -5,13 +5,36 @@ LCPU is an alternative CPU core addon for GMod/Wiremod.
|
||||||
It provides:
|
It provides:
|
||||||
|
|
||||||
- A standard RISC-V architechure (rv32ima) CPU core, implemented in native code
|
- A standard RISC-V architechure (rv32ima) CPU core, implemented in native code
|
||||||
- No wiremod native code embargos here!
|
- No wiremod native code embargos here, so we get actually good performance without half our SENTs becoming lag machine fodder!
|
||||||
- Interoperation with the Wiremod addon (and addons which implement Wiremod integration)
|
- Interoperation with the Wiremod addon (and addons which implement Wiremod integration)
|
||||||
|
|
||||||
# Building Native Module
|
This addon (for now) works with both the non-beta branch and the x86-64 beta branches of GMod.
|
||||||
|
|
||||||
TODO: Steps to build the LCPU native module on Windows and Linux
|
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
This repository is set up in the exact directory structure to be a Legacy Addon; therefore once you have built the native module (TODO), adding it to a server should work fine.
|
This repository is set up to be a Filesystem Addon; therefore, workflows which clone repositories from Git and put them in addons/ should be able to work with the LCPU addon just fine.
|
||||||
|
|
||||||
|
Preliminary installation steps:
|
||||||
|
|
||||||
|
```
|
||||||
|
garrysmod/addons$ git clone --recursive https://github.com/modeco80/gmod-lcpu.git lcpu
|
||||||
|
garrysmod/addons$ cd lcpu
|
||||||
|
|
||||||
|
# Build the LCPU native module. These steps build the linux64 version of the module
|
||||||
|
# on linux; you'll need to alter it if you want to build for 32-bit.
|
||||||
|
garrysmod/addons/lcpu$ cmake -Wno-dev -GNinja -S native -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
garrysmod/addons/lcpu$ ninja -C build
|
||||||
|
|
||||||
|
# Install the native module (Linux)
|
||||||
|
# For Windows you can do the same thing, just replace this
|
||||||
|
# with how you'd do it in batch (or use Explorer, I'm not your dad)
|
||||||
|
garrysmod/addons/lcpu$ [[ ! -d '../../lua/bin']] && mkdir -p ../../lua/bin && cp build/projects/lcpu/*.dll ../../lua/bin
|
||||||
|
|
||||||
|
# Tada!
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Special Thanks
|
||||||
|
|
||||||
|
[CNLohr](https://github.com/CNLohr) - I may not like the mini-rv32ima code that much, but it did still help a lot (and my emulation core library is based off it, with tons of refactoring and a C++ rewrite to boot.)
|
||||||
|
|
2
ideas.md
2
ideas.md
|
@ -8,7 +8,6 @@ This is basically the working ideas for the LCPU project.
|
||||||
- RISC-V rv32ima core
|
- RISC-V rv32ima core
|
||||||
- Would supporting more than one CPU core type be worthwhile? If so, the project is relatively setup for such workflow...
|
- Would supporting more than one CPU core type be worthwhile? If so, the project is relatively setup for such workflow...
|
||||||
- Controllable paramaters (RAM size, ...)
|
- Controllable paramaters (RAM size, ...)
|
||||||
- Our own framebuffer screen SENT (since wiremod decided to go stupid mode and saw off the gpu)
|
|
||||||
|
|
||||||
## Code upload
|
## Code upload
|
||||||
|
|
||||||
|
@ -63,3 +62,4 @@ This is basically the working ideas for the LCPU project.
|
||||||
- Wiremod interopability
|
- Wiremod interopability
|
||||||
- Wiremod GPIO peripheral (to interface with wire world)
|
- Wiremod GPIO peripheral (to interface with wire world)
|
||||||
- special Console Screen peripheral (interfacing specifically with it)
|
- special Console Screen peripheral (interfacing specifically with it)
|
||||||
|
- frambuffer peripheral which uses the Digital Screen
|
||||||
|
|
|
@ -3,126 +3,62 @@
|
||||||
#include <lucore/Library.hpp>
|
#include <lucore/Library.hpp>
|
||||||
#include <lucore/Types.hpp>
|
#include <lucore/Types.hpp>
|
||||||
|
|
||||||
|
// The old non-beta branch of GMod on Linux has multiple tier0 libraries for client and server.
|
||||||
|
// This compatibility define allows to support that case (for now).
|
||||||
|
#define LCPU_SUPPORT_OLD_GMOD
|
||||||
|
|
||||||
namespace tier0 {
|
namespace tier0 {
|
||||||
// TODO: For now this'll leak..
|
// TODO: For now this'll leak..
|
||||||
lucore::Library* library = nullptr;
|
lucore::Library* library = nullptr;
|
||||||
|
|
||||||
/// Minimally Source compatiable Color type
|
using Msg_t = void (*)(const char*, ...);
|
||||||
/// (Even more POD than Source)
|
Msg_t Msg {};
|
||||||
struct Color {
|
|
||||||
constexpr explicit Color(u8 r, u8 g, u8 b, u8 a) {
|
|
||||||
colors[0] = r;
|
|
||||||
colors[1] = g;
|
|
||||||
colors[2] = b;
|
|
||||||
colors[3] = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 colors[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
using LoggingChannelID_t = s32;
|
|
||||||
enum LoggingSeverity_t {
|
|
||||||
LS_MESSAGE,
|
|
||||||
LS_WARNING,
|
|
||||||
LS_ASSERT,
|
|
||||||
LS_ERROR,
|
|
||||||
|
|
||||||
LS_HIGHEST_SEVERITY
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LoggingChannelFlags_t { LCF_CONSOLE_ONLY = 1, LCF_DO_NOT_ECHO = 2 };
|
|
||||||
|
|
||||||
using RegisterTagsFunc = void (*)();
|
|
||||||
|
|
||||||
// LoggingSystem_ APIs
|
|
||||||
using RegisterLoggingChannel_t = LoggingChannelID_t (*)(const char*, RegisterTagsFunc,
|
|
||||||
int flags, LoggingSeverity_t severity,
|
|
||||||
Color color);
|
|
||||||
using Log_t = s32 (*)(LoggingChannelID_t, LoggingSeverity_t, const char*, ...);
|
|
||||||
using GetChannelColor_t = Color (*)(LoggingChannelID_t);
|
|
||||||
|
|
||||||
RegisterLoggingChannel_t LoggingSystem_RegisterLoggingChannel {};
|
|
||||||
Log_t LoggingSystem_Log {};
|
|
||||||
GetChannelColor_t LoggingSystem_GetChannelColor {};
|
|
||||||
|
|
||||||
} // namespace tier0
|
} // namespace tier0
|
||||||
|
|
||||||
namespace lcpu {
|
namespace lcpu {
|
||||||
|
|
||||||
tier0::LoggingChannelID_t gSourceSinkLoggerChannel { -1 };
|
|
||||||
|
|
||||||
SourceSink& SourceSink::The() {
|
SourceSink& SourceSink::The() {
|
||||||
static SourceSink sink;
|
static SourceSink sink;
|
||||||
return sink;
|
return sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceSink::Init() {
|
SourceSink::SourceSink() {
|
||||||
// Modern 64-bit GMod has one tier0 library.
|
#ifdef LCPU_SUPPORT_OLD_GMOD
|
||||||
// I am not supporting non-x86-64 branch servers, so this is OK and I don't need to
|
constexpr static std::string_view tier0_libraries[] {
|
||||||
// do any library scanning nonsense to pick the correct one.
|
#ifdef __linux__
|
||||||
//
|
"tier0_srv"
|
||||||
// (note that the x86-64 branch also includes 32-bit binaries, rather
|
#endif
|
||||||
// weirdly. You can build the module for this too, but not the non-x86-64 branch
|
"tier0"
|
||||||
// 32-bit GMod, and it also shares having only one tier0 library.)
|
};
|
||||||
|
|
||||||
|
for(auto lib : tier0_libraries) {
|
||||||
|
if(lucore::Library::Loaded(lib)) {
|
||||||
|
// Found the correct tier0 library to open; use that.
|
||||||
|
tier0::library = lucore::Library::Open(lib);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// The x86-64 branch of GMod, including the 32-bit binaries in the branch,
|
||||||
|
// have a single tier0 library, which makes the codepath much simpler.
|
||||||
tier0::library = lucore::Library::Open("tier0");
|
tier0::library = lucore::Library::Open("tier0");
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GRAB_SYMBOL(name, T) tier0::name = tier0::library->Symbol<T>(#name);
|
#define GRAB_SYMBOL(name, T) tier0::name = tier0::library->Symbol<T>(#name);
|
||||||
|
GRAB_SYMBOL(Msg, tier0::Msg_t);
|
||||||
|
}
|
||||||
|
|
||||||
GRAB_SYMBOL(LoggingSystem_RegisterLoggingChannel, tier0::RegisterLoggingChannel_t);
|
SourceSink::~SourceSink() {
|
||||||
GRAB_SYMBOL(LoggingSystem_Log, tier0::Log_t);
|
delete tier0::library;
|
||||||
GRAB_SYMBOL(LoggingSystem_GetChannelColor, tier0::GetChannelColor_t);
|
|
||||||
|
|
||||||
gSourceSinkLoggerChannel = tier0::LoggingSystem_RegisterLoggingChannel(
|
|
||||||
"LCPU Native", nullptr, 0, tier0::LS_MESSAGE, tier0::Color(0xff, 0x99, 0x00, 0xff));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceSink::OutputMessage(const lucore::Logger::MessageData& data) {
|
void SourceSink::OutputMessage(const lucore::Logger::MessageData& data) {
|
||||||
auto formatted =
|
auto formatted =
|
||||||
std::format("[LCPU Native/{}] [{}] {}\n", lucore::Logger::SeverityToString(data.severity),
|
std::format("[LCPU Native/{}] [{}] {}", lucore::Logger::SeverityToString(data.severity),
|
||||||
data.time, std::vformat(data.format, data.args));
|
data.time, std::vformat(data.format, data.args));
|
||||||
auto lucore_to_source = [severity = data.severity]() -> tier0::LoggingSeverity_t {
|
|
||||||
using enum lucore::Logger::MessageSeverity;
|
|
||||||
switch(severity) {
|
|
||||||
case Info:
|
|
||||||
return tier0::LS_MESSAGE;
|
|
||||||
case Warning:
|
|
||||||
return tier0::LS_WARNING;
|
|
||||||
case Error:
|
|
||||||
return tier0::LS_WARNING;
|
|
||||||
case Fatal:
|
|
||||||
return tier0::LS_ASSERT;
|
|
||||||
default:
|
|
||||||
return tier0::LS_MESSAGE;
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
#if 0
|
tier0::Msg("%s\n", formatted.c_str());
|
||||||
// This is a pretty stupid hack for console colors on Linux.
|
|
||||||
// I don't really like it that much tbh, wish tier0 supported this.
|
|
||||||
auto color = tier0::LoggingSystem_GetChannelColor(gSourceSinkLoggerChannel);
|
|
||||||
|
|
||||||
{
|
|
||||||
using enum lucore::Logger::MessageSeverity;
|
|
||||||
switch(data.severity) {
|
|
||||||
case Warning:
|
|
||||||
color = tier0::Color(0xff, 0xff, 0x0, 0xff);
|
|
||||||
break;
|
|
||||||
case Error:
|
|
||||||
case Fatal:
|
|
||||||
color = tier0::Color(0xff, 0x0, 0x0, 0xff);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tier0::LoggingSystem_Log(gSourceSinkLoggerChannel, lucore_to_source,
|
|
||||||
"\033[38;2;%d;%d;%dm%s\033[0m", color.colors[0], color.colors[1],
|
|
||||||
color.colors[2], formatted.c_str());
|
|
||||||
#else
|
|
||||||
tier0::LoggingSystem_Log(gSourceSinkLoggerChannel, lucore_to_source, "%s",
|
|
||||||
formatted.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace lcpu
|
} // namespace lcpu
|
||||||
|
|
|
@ -7,9 +7,10 @@ namespace lcpu {
|
||||||
struct SourceSink : public lucore::Logger::Sink {
|
struct SourceSink : public lucore::Logger::Sink {
|
||||||
static SourceSink& The();
|
static SourceSink& The();
|
||||||
|
|
||||||
static void Init();
|
SourceSink();
|
||||||
|
~SourceSink();
|
||||||
|
|
||||||
void OutputMessage(const lucore::Logger::MessageData& data) override;
|
void OutputMessage(const lucore::Logger::MessageData& data) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace lcpu
|
||||||
|
|
|
@ -5,13 +5,9 @@
|
||||||
#include <lucore/Assert.hpp>
|
#include <lucore/Assert.hpp>
|
||||||
|
|
||||||
GMOD_MODULE_OPEN() {
|
GMOD_MODULE_OPEN() {
|
||||||
// Initalize the source logging sink and attach it to the lucore logger.
|
|
||||||
lcpu::SourceSink::Init();
|
|
||||||
lucore::Logger::The().AttachSink(lcpu::SourceSink::The());
|
lucore::Logger::The().AttachSink(lcpu::SourceSink::The());
|
||||||
|
|
||||||
lucore::LogInfo("Hello Source World :) {} {}", 123.456, "This should work");
|
lucore::LogInfo("LCPU Native Module loading");
|
||||||
lucore::LogWarning("test");
|
|
||||||
LUCORE_CHECK(false, "this should bring the process down");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,28 @@ project(lucore
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(lucore
|
add_library(lucore
|
||||||
|
# Assertion/Check failure handling
|
||||||
src/Assert.cpp
|
src/Assert.cpp
|
||||||
|
|
||||||
|
# Logging functionality
|
||||||
src/Logger.cpp
|
src/Logger.cpp
|
||||||
src/StdoutSink.cpp
|
src/StdoutSink.cpp
|
||||||
|
|
||||||
src/OsLibrary.cpp
|
# Dynamic library wrappers
|
||||||
src/Library.cpp
|
src/Library.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Target-specific Lucore sources.
|
||||||
|
if(WIN32)
|
||||||
|
target_sources(lucore PRIVATE
|
||||||
|
src/OsLibrary.win32.cpp
|
||||||
|
)
|
||||||
|
elseif(UNIX)
|
||||||
|
target_sources(lucore PRIVATE
|
||||||
|
src/OsLibrary.linux.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_compile_features(lucore PUBLIC cxx_std_20)
|
target_compile_features(lucore PUBLIC cxx_std_20)
|
||||||
target_include_directories(lucore PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
target_include_directories(lucore PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ namespace lucore {
|
||||||
/// Get the single instance of the logger.
|
/// Get the single instance of the logger.
|
||||||
static Logger& The();
|
static Logger& The();
|
||||||
|
|
||||||
Logger() = default;
|
|
||||||
Logger(const Logger&) = delete;
|
Logger(const Logger&) = delete;
|
||||||
Logger(Logger&&) = delete;
|
Logger(Logger&&) = delete;
|
||||||
|
|
||||||
|
@ -76,6 +75,7 @@ namespace lucore {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Logger() = default;
|
||||||
void VOut(MessageSeverity severity, std::string_view format, std::format_args args);
|
void VOut(MessageSeverity severity, std::string_view format, std::format_args args);
|
||||||
|
|
||||||
MessageSeverity logLevel { MessageSeverity::Info };
|
MessageSeverity logLevel { MessageSeverity::Info };
|
||||||
|
|
|
@ -3,15 +3,13 @@
|
||||||
namespace lucore {
|
namespace lucore {
|
||||||
|
|
||||||
/// A logger sink implementation that prints to standard output.
|
/// A logger sink implementation that prints to standard output.
|
||||||
/// Not used by the lcpu native module, but could be used by applications
|
|
||||||
/// using lucore later on.
|
|
||||||
struct StdoutSink : public Logger::Sink {
|
struct StdoutSink : public Logger::Sink {
|
||||||
static StdoutSink& The();
|
static StdoutSink& The();
|
||||||
|
|
||||||
virtual void OutputMessage(const Logger::MessageData& data) override;
|
virtual void OutputMessage(const Logger::MessageData& data) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Attach the stdout logger sink to the logger.
|
/// Attach the stdout logger sink to the global Lucore logger.
|
||||||
void LoggerAttachStdout();
|
void LoggerAttachStdout();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
#include "OsLibrary.hpp"
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include "OsLibrary.win32.cpp"
|
|
||||||
#elif defined(__linux__)
|
|
||||||
#include "OsLibrary.linux.cpp"
|
|
||||||
#else
|
|
||||||
#error No OsLibrary implementation for this platform
|
|
||||||
#endif
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "OsLibrary.hpp"
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
namespace lucore::detail {
|
namespace lucore::detail {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "OsLibrary.hpp"
|
||||||
|
|
||||||
#define _WIN32_LEAN_AND_MEAN
|
#define _WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
@ -20,4 +22,4 @@ namespace lucore::detail {
|
||||||
// therefore, we have nothing to do here on Windows.
|
// therefore, we have nothing to do here on Windows.
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace lucore::detail
|
||||||
|
|
|
@ -1,28 +1,34 @@
|
||||||
#include <riscv/Types.hpp>
|
|
||||||
#include <lucore/OptionalRef.hpp>
|
#include <lucore/OptionalRef.hpp>
|
||||||
|
#include <riscv/Types.hpp>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace riscv {
|
namespace riscv {
|
||||||
|
|
||||||
struct CPU;
|
struct CPU;
|
||||||
|
|
||||||
/// An address bus.
|
/// An address/memory bus. No virtual address translation is implemented;
|
||||||
|
/// all addresses/devices are placed in physical addresses.
|
||||||
struct Bus {
|
struct Bus {
|
||||||
|
/// Interface all memory bus devices use.
|
||||||
struct Device {
|
struct Device {
|
||||||
|
Device() = default;
|
||||||
|
|
||||||
|
// Devices have no need to be copied or moved.
|
||||||
|
Device(const Device&) = delete;
|
||||||
|
Device(Device&&) = delete;
|
||||||
|
|
||||||
virtual ~Device() = default;
|
virtual ~Device() = default;
|
||||||
|
|
||||||
// How many bytes does this device occupy of address space?
|
/// How many bytes does this device occupy of address space? This should
|
||||||
|
/// effectively be a constant, and should probably not change during CPU execution.
|
||||||
virtual AddressT Size() const = 0;
|
virtual AddressT Size() const = 0;
|
||||||
|
|
||||||
// Used to allow bus devices to know when they are attached to a memory bus,
|
/// Used to allow bus devices to know when they are attached to a memory bus,
|
||||||
// and ultimately, an instance of a System
|
/// and ultimately, an instance of a System
|
||||||
virtual void Attached(Bus* memoryBus, AddressT baseAddress) = 0;
|
virtual void Attached(Bus* memoryBus, AddressT baseAddress) = 0;
|
||||||
|
|
||||||
/// Is this device clocked?
|
/// Does this device require a clock "signal"?
|
||||||
virtual bool Clocked() const { return false; }
|
virtual bool Clocked() const { return false; }
|
||||||
|
|
||||||
/// This function is called to give clocked devices
|
/// This function is called to give clocked devices
|
||||||
|
@ -32,8 +38,7 @@ namespace riscv {
|
||||||
// TODO(feat): default implementations of Peek* and Poke* should exist
|
// TODO(feat): default implementations of Peek* and Poke* should exist
|
||||||
// and trap the CPU (similarly to what happens if a unmapped bus read occurs).
|
// and trap the CPU (similarly to what happens if a unmapped bus read occurs).
|
||||||
|
|
||||||
|
/// Peek() -> reads a value from this device.
|
||||||
// Peek() -> reads a value from this device.
|
|
||||||
virtual u8 PeekByte(AddressT offset) = 0;
|
virtual u8 PeekByte(AddressT offset) = 0;
|
||||||
virtual u16 PeekShort(AddressT offset) = 0;
|
virtual u16 PeekShort(AddressT offset) = 0;
|
||||||
virtual u32 PeekWord(AddressT offset) = 0;
|
virtual u32 PeekWord(AddressT offset) = 0;
|
||||||
|
@ -42,7 +47,6 @@ namespace riscv {
|
||||||
virtual void PokeByte(AddressT offset, u8 value) = 0;
|
virtual void PokeByte(AddressT offset, u8 value) = 0;
|
||||||
virtual void PokeShort(AddressT offset, u16 value) = 0;
|
virtual void PokeShort(AddressT offset, u16 value) = 0;
|
||||||
virtual void PokeWord(AddressT offset, u32 value) = 0;
|
virtual void PokeWord(AddressT offset, u32 value) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Bus(CPU* cpu);
|
Bus(CPU* cpu);
|
||||||
|
@ -60,7 +64,7 @@ namespace riscv {
|
||||||
/// - The provided base address overlaps a already attached device in some way
|
/// - The provided base address overlaps a already attached device in some way
|
||||||
bool AttachDevice(AddressT baseAddress, Device* device);
|
bool AttachDevice(AddressT baseAddress, Device* device);
|
||||||
|
|
||||||
/// Clock all clocked devices.
|
/// Clock all clocked devices mapped onto the bus..
|
||||||
void Clock();
|
void Clock();
|
||||||
|
|
||||||
u8 PeekByte(AddressT address);
|
u8 PeekByte(AddressT address);
|
||||||
|
@ -70,16 +74,14 @@ namespace riscv {
|
||||||
void PokeByte(AddressT address, u8 value);
|
void PokeByte(AddressT address, u8 value);
|
||||||
void PokeShort(AddressT address, u16 value);
|
void PokeShort(AddressT address, u16 value);
|
||||||
void PokeWord(AddressT address, u32 value);
|
void PokeWord(AddressT address, u32 value);
|
||||||
private:
|
|
||||||
|
|
||||||
|
private:
|
||||||
lucore::OptionalRef<Device> FindDeviceForAddress(AddressT address) const;
|
lucore::OptionalRef<Device> FindDeviceForAddress(AddressT address) const;
|
||||||
|
|
||||||
CPU* attachedCpu{};
|
CPU* attachedCpu {};
|
||||||
|
|
||||||
// TODO: if this ends up being a hotpath replace with ankerl::unordered_dense
|
// TODO: if this ends up being a hotpath replace with ankerl::unordered_dense
|
||||||
std::unordered_map<AddressT, Device*> mapped_devices;
|
std::unordered_map<AddressT, Device*> mapped_devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace riscv
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
|
|
||||||
namespace riscv {
|
namespace riscv {
|
||||||
|
|
||||||
/** The CPU core. */
|
/// The CPU core.
|
||||||
struct CPU {
|
struct CPU {
|
||||||
|
/// CPU core state.
|
||||||
struct State {
|
struct State {
|
||||||
u32 gpr[32];
|
u32 gpr[32];
|
||||||
u32 pc;
|
u32 pc;
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
|
|
||||||
#include <riscv/Bus.hpp>
|
#include <riscv/Bus.hpp>
|
||||||
|
|
||||||
#include "riscv/Types.hpp"
|
|
||||||
|
|
||||||
namespace riscv::devices {
|
namespace riscv::devices {
|
||||||
|
|
||||||
|
/// A block of RAM which can be used by the CPU.
|
||||||
struct RamDevice : public Bus::Device {
|
struct RamDevice : public Bus::Device {
|
||||||
RamDevice(AddressT size);
|
RamDevice(AddressT size);
|
||||||
virtual ~RamDevice();
|
virtual ~RamDevice();
|
||||||
|
|
||||||
AddressT Size() const override;
|
|
||||||
|
|
||||||
// Implementation of Device interface
|
// Implementation of Device interface
|
||||||
|
|
||||||
|
AddressT Size() const override;
|
||||||
|
|
||||||
void Attached(Bus* bus, AddressT base) override;
|
void Attached(Bus* bus, AddressT base) override;
|
||||||
|
|
||||||
u8 PeekByte(AddressT address) override;
|
u8 PeekByte(AddressT address) override;
|
||||||
|
@ -24,7 +22,7 @@ namespace riscv::devices {
|
||||||
void PokeWord(AddressT address, u32 value) override;
|
void PokeWord(AddressT address, u32 value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// helper used for implementing stuff
|
/// helper used for implementing Peek/Poke API
|
||||||
template <class T>
|
template <class T>
|
||||||
constexpr usize AddressToIndex(AddressT address) {
|
constexpr usize AddressToIndex(AddressT address) {
|
||||||
return ((address - baseAddress) % memorySize) / sizeof(T);
|
return ((address - baseAddress) % memorySize) / sizeof(T);
|
||||||
|
|
Loading…
Reference in New Issue