misc fun changes
This commit is contained in:
parent
a5f7735d9a
commit
4f6ec38f22
|
@ -15,6 +15,8 @@ if SERVER then
|
|||
-- Uncomment this to enable debug logging (useful for troubleshooting bugs)
|
||||
--LCPUNative.EnableDebug()
|
||||
|
||||
include("lcpu/cvars.lua")
|
||||
|
||||
AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
|
||||
|
||||
-- Serverside devices (that don't depend on wiremod being loaded)
|
||||
|
|
|
@ -2,7 +2,6 @@ AddCSLuaFile()
|
|||
DEFINE_BASECLASS("base_wire_entity")
|
||||
ENT.PrintName = "LCPU"
|
||||
ENT.Author = "Lily <3"
|
||||
|
||||
-- no more, this deeply uses native APIs
|
||||
if CLIENT then return end
|
||||
|
||||
|
@ -11,27 +10,32 @@ if CLIENT then return end
|
|||
include("lcpu/devices/wire_interface.lua")
|
||||
|
||||
-- TODO: serverside convars to control execution rate & cycle count
|
||||
|
||||
function ENT:Initialize()
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
-- CPU callbacks?
|
||||
self.cpu = LCPUNative.CreateCPU(128 * 1024)
|
||||
self.uart = LCPU.Devices.UART(0x10000000)
|
||||
self.wireInterface = LCPU.Devices.WireInterface(0x11310000, self, 8, 8)
|
||||
|
||||
self.cpu:AttachDevice(self.uart)
|
||||
self.cpu:AttachDevice(self.wireInterface)
|
||||
|
||||
self:SetOverlayText("hi :)")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
-- Avoid running if the cpu is not powered on
|
||||
if not self.cpu:PoweredOn() then return end
|
||||
self.cpu:Cycle()
|
||||
|
||||
if LCPU.cycleCount ~= self.cpu.CycleCount then
|
||||
--print(string.format("bumping up cycle count to %d", LCPU.cycleCount));
|
||||
self.cpu.CycleCount = LCPU.cycleCount
|
||||
end
|
||||
|
||||
for i = 1, LCPU.tickCount do
|
||||
self.cpu:Cycle()
|
||||
end
|
||||
|
||||
-- Even though this is gated by tickrate I'm just trying to be nice here
|
||||
self:NextThink(CurTime() + 0.1)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
-- these are where all the cvars the addon uses go
|
||||
|
||||
|
||||
-- honestly I wonder if I could get away with models/classes instead of a global limitation
|
||||
--[[
|
||||
c class: basic
|
||||
c1: 128k ram, 1 tick, 1024 cycles
|
||||
c2: 512k ram, 4 ticks, 2048 cycles
|
||||
|
||||
b class: more suited to crazier programs
|
||||
b1: 1mb ram, 8 ticks, 4096 cycles
|
||||
b2: 2mb ram, 12 ticks, 6144 cycles
|
||||
|
||||
a class: higher performance
|
||||
a1: 4mb ram, 16 ticks, 8192 cycles
|
||||
a2: 8mb ram, 16 ticks, 12240 cycles
|
||||
|
||||
(this one will definitly be limited in some way if I ever do this since it is a walking lag machine in the making)
|
||||
s class: you don't like your gmod server very much
|
||||
s1: 64mb ram, 16 ticks, 16384 cycles
|
||||
]]
|
||||
|
||||
LCPU.tickCount = 4
|
||||
LCPU.cycleCount = 1024
|
||||
|
||||
-- cvars for limiting/reducing lcpu usage
|
||||
local lcpu_cpu_tick_count = CreateConVar("lcpu_cpu_tick_count", LCPU.tickCount, FCVAR_REPLICATED, "How many cycle steps a LCPU will do")
|
||||
local lcpu_cpu_cycle_count = CreateConVar("lcpu_cpu_cycle_count", LCPU.cycleCount, FCVAR_REPLICATED, "How many CPU cycles run in each CPU tick")
|
||||
|
||||
cvars.AddChangeCallback(
|
||||
"lcpu_cpu_tick_count",
|
||||
function()
|
||||
-- this seems reasonable enough right?
|
||||
LCPU.tickCount = math.Clamp(math.floor(lcpu_cpu_tick_count:GetInt()), 1, 16)
|
||||
end
|
||||
)
|
||||
|
||||
cvars.AddChangeCallback(
|
||||
"lcpu_cpu_cycle_count",
|
||||
function()
|
||||
-- these are NOT final values
|
||||
LCPU.cycleCount = math.Clamp(math.floor(lcpu_cpu_cycle_count:GetInt()), 1, 16384)
|
||||
end
|
||||
)
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <lucore/Logger.hpp>
|
||||
|
||||
#include "GarrysMod/Lua/LuaBase.h"
|
||||
#include "LuaDevice.hpp"
|
||||
|
||||
namespace lcpu {
|
||||
|
@ -56,6 +57,21 @@ namespace lcpu {
|
|||
void LuaCpu::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) {
|
||||
RegisterClassStart(LUA);
|
||||
|
||||
RegisterGetter("CycleCount", [](GarrysMod::Lua::ILuaBase* LUA) {
|
||||
auto self = FromLua(LUA, 1);
|
||||
LUA->PushNumber(self->system->cpu->GetCycleCount());
|
||||
});
|
||||
|
||||
RegisterSetter("CycleCount", [](GarrysMod::Lua::ILuaBase* LUA) {
|
||||
auto self = FromLua(LUA, 1);
|
||||
|
||||
auto newValue = static_cast<u32>(LUA->GetNumber(-1));
|
||||
if(newValue == 0) {
|
||||
LUA->ThrowError("Invalid value to set LuaCpu:CycleCount");
|
||||
}
|
||||
self->system->cpu->SetCycleCount(newValue);
|
||||
});
|
||||
|
||||
RegisterMethod("PoweredOn", PoweredOn);
|
||||
RegisterMethod("Cycle", Cycle);
|
||||
RegisterMethod("PowerOff", PowerOff);
|
||||
|
@ -67,9 +83,7 @@ namespace lcpu {
|
|||
LuaCpu::LuaCpu(u32 memorySize) {
|
||||
poweredOn = true;
|
||||
system = riscv::System::Create(memorySize);
|
||||
system->OnPowerOff = [&]() {
|
||||
poweredOn = false;
|
||||
};
|
||||
system->OnPowerOff = [&]() { poweredOn = false; };
|
||||
|
||||
// lame test code. this WILL be removed, I just want this for a quick test
|
||||
auto fp = std::fopen("/home/lily/test-gmod.bin", "rb");
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "GarrysMod/Lua/LuaBase.h"
|
||||
#include "GarrysMod/Lua/Types.h"
|
||||
#include "LuaHelpers.hpp"
|
||||
#include "lucore/Assert.hpp"
|
||||
|
||||
namespace lcpu::lua {
|
||||
|
||||
|
@ -45,7 +46,9 @@ namespace lcpu::lua {
|
|||
}
|
||||
|
||||
static TImpl* FromLua(GarrysMod::Lua::ILuaBase* LUA, int stackPos) {
|
||||
return LUA->GetUserType<TImpl>(stackPos, __lua_typeid);
|
||||
if(auto ptr = LUA->GetUserType<TImpl>(stackPos, __lua_typeid); ptr)
|
||||
return ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -76,6 +79,10 @@ namespace lcpu::lua {
|
|||
/// - __newindex
|
||||
///
|
||||
static void RegisterMetaFunction(GarrysMod::Lua::ILuaBase* LUA, const std::string& name, CFunc func) {
|
||||
LUCORE_CHECK(name != "__gc", "Attempting to overwrite __gc metamethod");
|
||||
LUCORE_CHECK(name != "__index", "Attempting to overwrite __index metamethod");
|
||||
LUCORE_CHECK(name != "__newindex", "Attempting to overwrite __newindex metamethod");
|
||||
|
||||
// clang-format off
|
||||
LUA->PushMetaTable(__lua_typeid);
|
||||
LUA->PushCFunction(func);
|
||||
|
@ -156,7 +163,6 @@ namespace lcpu::lua {
|
|||
LUA_CLASS_FUNCTION(LuaObject<TImpl>, __index) {
|
||||
auto self = FromLua(LUA, 1);
|
||||
|
||||
// If the key is something we support,
|
||||
if(LUA->GetType(2) == GarrysMod::Lua::Type::String) {
|
||||
auto& methods = LuaObject::methods();
|
||||
auto& getters = LuaObject::getters();
|
||||
|
@ -172,8 +178,6 @@ namespace lcpu::lua {
|
|||
getters[key](LUA);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lucore::LogDebug("LuaObject::__index({}) going to table", key);
|
||||
}
|
||||
|
||||
// Failing to look up an item is not fatal;
|
||||
|
@ -208,12 +212,8 @@ namespace lcpu::lua {
|
|||
setters[key](LUA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
lucore::LogDebug("LuaObject::__newindex({}) going to table", key);
|
||||
}
|
||||
|
||||
|
||||
// set the provided value onto the table
|
||||
// clang-format off
|
||||
LUA->ReferencePush(self->tableReference); // table
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
//! Lucore Assert Wrappers
|
||||
//!
|
||||
//! Lucore uses its own assertion system which is more flexible than the
|
||||
//! standard C library's assertion macros.
|
||||
//!
|
||||
//! They are not intended to be directly compatible with some of the quirks
|
||||
//! the Standard C library allows (like using assert() as an expression).
|
||||
//!
|
||||
//! They are:
|
||||
//! - LUCORE_ASSERT()
|
||||
//! - active in debug builds and removed on release
|
||||
//! - LUCORE_CHECK()
|
||||
//! - always active, even in release builds
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -18,7 +30,6 @@ namespace lucore {
|
|||
#define LUCORE_ASSERT(expr, format, ...)
|
||||
#endif
|
||||
|
||||
// CHECK() is always active, even in release builds
|
||||
#define LUCORE_CHECK(expr, fmt, ...) \
|
||||
if(!(expr)) [[unlikely]] { \
|
||||
auto msg = std::format("Check \"{}\" @ {}:{} failed with message: {}", #expr, __FILE__, __LINE__, std::format(fmt, ##__VA_ARGS__)); \
|
||||
|
|
|
@ -5,9 +5,14 @@
|
|||
|
||||
namespace lucore {
|
||||
|
||||
/// A platform-independent class for working with a shared library
|
||||
/// as a resource.
|
||||
struct Library {
|
||||
using Handle = void*;
|
||||
|
||||
/// Open a library regardless of if it's been loaded or not.
|
||||
static Unique<Library> Open(std::string_view name);
|
||||
|
||||
/// Open an already loaded library
|
||||
static Unique<Library> OpenExisting(std::string_view dllname);
|
||||
|
||||
|
@ -22,10 +27,17 @@ namespace lucore {
|
|||
}
|
||||
|
||||
private:
|
||||
struct ExistingTag{};
|
||||
constexpr static inline ExistingTag Existing{};
|
||||
|
||||
constexpr explicit Library(Handle handle) : handle(handle) {}
|
||||
constexpr explicit Library(Handle handle, ExistingTag) : handle(handle), existing(true) {}
|
||||
|
||||
void* SymbolImpl(const char* symbol);
|
||||
Handle handle {};
|
||||
|
||||
/// Tracks if this Library instance was created using [Library::OpenExisting].
|
||||
bool existing{false};
|
||||
};
|
||||
|
||||
} // namespace lucore
|
||||
|
|
|
@ -15,10 +15,16 @@ namespace lucore {
|
|||
|
||||
static constexpr std::string_view SeverityToString(MessageSeverity sev) {
|
||||
// This must match order of Logger::MessageSeverity.
|
||||
const char* MessageSeverityStringTable[] = { "Deb", "Inf", "Wrn", "Err", "Ftl" };
|
||||
const char* MessageSeverityStringTable[] = { "Debug", "Info", "Warn", "Error", "Fatal" };
|
||||
return MessageSeverityStringTable[static_cast<std::size_t>(sev)];
|
||||
}
|
||||
|
||||
struct MessageDataUnformatted {
|
||||
std::chrono::system_clock::time_point time;
|
||||
MessageSeverity severity;
|
||||
std::string_view message;
|
||||
};
|
||||
|
||||
/// Message data. This is only used by logger sinks.
|
||||
struct MessageData {
|
||||
std::chrono::system_clock::time_point time;
|
||||
|
@ -33,7 +39,8 @@ namespace lucore {
|
|||
virtual void OutputMessage(const MessageData& data) = 0;
|
||||
};
|
||||
|
||||
/// Get the single instance of the logger.
|
||||
/// Get the common instance of the logger.
|
||||
/// LogInfo() etc operates on this function only.
|
||||
static Logger& The();
|
||||
|
||||
Logger(const Logger&) = delete;
|
||||
|
@ -50,6 +57,15 @@ namespace lucore {
|
|||
/// Set the current log level.
|
||||
void SetLogLevel(MessageSeverity newLogLevel) { logLevel = newLogLevel; }
|
||||
|
||||
// TODO: sinks should get a "unformatted output" OutputMessage overload
|
||||
#if 0
|
||||
constexpr void Debug(std::string_view message) { VOut(MessageSeverity::Debug, message); }
|
||||
constexpr void Info(std::string_view message) { VOut(MessageSeverity::Info, message); }
|
||||
constexpr void Warning(std::string_view message) { VOut(MessageSeverity::Warning, message); }
|
||||
constexpr void Error(std::string_view message) { VOut(MessageSeverity::Error, message); }
|
||||
constexpr void Fatal(std::string_view message) { VOut(MessageSeverity::Fatal, message); }
|
||||
#endif
|
||||
|
||||
template <class... Args>
|
||||
inline void Debug(std::string_view fmt, Args... args) {
|
||||
VOut(MessageSeverity::Debug, fmt, std::make_format_args(std::forward<Args>(args)...));
|
||||
|
|
|
@ -16,6 +16,25 @@ namespace lucore {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
Unique<Library> Library::Open(std::string_view dllname) {
|
||||
auto name = FormatLibraryName(dllname);
|
||||
auto handle = detail::OsOpenLibrary(name.c_str());
|
||||
|
||||
if(!handle) {
|
||||
#ifndef _WIN32
|
||||
// Try without a `lib` prefix next. If this fails, give up.
|
||||
name = std::format("{}.so", dllname);
|
||||
handle = detail::OsOpenLibrary(name.c_str());
|
||||
if(!handle)
|
||||
return nullptr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
return Unique<Library>(new Library(handle));
|
||||
}
|
||||
|
||||
Unique<Library> Library::OpenExisting(std::string_view dllname) {
|
||||
auto name = FormatLibraryName(dllname);
|
||||
if(!detail::OsLibraryLoaded(name.c_str())) {
|
||||
|
@ -29,7 +48,7 @@ namespace lucore {
|
|||
#endif
|
||||
}
|
||||
|
||||
return Unique<Library>(new Library(detail::OsOpenLibrary(name.c_str())));
|
||||
return Unique<Library>(new Library(detail::OsOpenExistingLibrary(name.c_str()), Existing));
|
||||
}
|
||||
|
||||
bool Library::Loaded(std::string_view dllname) {
|
||||
|
@ -38,7 +57,11 @@ namespace lucore {
|
|||
|
||||
Library::~Library() {
|
||||
if(handle) {
|
||||
detail::OsFreeLibrary(handle);
|
||||
// See OsLibrary.win32.cpp for reasoning of this weird ifdef thing
|
||||
#ifdef _WIN32
|
||||
if(!existing)
|
||||
#endif
|
||||
detail::OsFreeLibrary(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include <bits/iterator_concepts.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <lucore/Logger.hpp>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Operating-system independent utilities for opening
|
||||
//! Operating-system independent API for opening
|
||||
//! shared libraries. This is currently a detail-only
|
||||
//! Lucore API, and its stability is NOT guaranteed.
|
||||
|
||||
|
@ -6,9 +6,11 @@ namespace lucore::detail {
|
|||
/// Opaque handle type for libraries.
|
||||
using OsLibraryHandle = void*;
|
||||
|
||||
/// Open a library.
|
||||
OsLibraryHandle OsOpenLibrary(const char* filename);
|
||||
|
||||
/// Open a library.
|
||||
OsLibraryHandle OsOpenExistingLibrary(const char* filename);
|
||||
|
||||
/// Query if the library with the given [filename] is loaded.
|
||||
bool OsLibraryLoaded(const char* filename);
|
||||
|
||||
|
|
|
@ -3,11 +3,19 @@
|
|||
#include <dlfcn.h>
|
||||
|
||||
namespace lucore::detail {
|
||||
|
||||
OsLibraryHandle OsOpenLibrary(const char* filename) {
|
||||
return dlopen(filename, RTLD_LAZY);
|
||||
}
|
||||
|
||||
OsLibraryHandle OsOpenExistingLibrary(const char* filename) {
|
||||
return dlopen(filename, RTLD_LAZY);
|
||||
}
|
||||
|
||||
bool OsLibraryLoaded(const char* filename) {
|
||||
// RTLD_NOLOAD tells the dynamic linker *not* to load
|
||||
// the module if it's not loaded in this process, which
|
||||
// allows us to test for if a module is loaded or not
|
||||
return dlopen(filename, RTLD_NOLOAD | RTLD_LAZY) != nullptr;
|
||||
}
|
||||
|
||||
|
@ -16,9 +24,8 @@ namespace lucore::detail {
|
|||
}
|
||||
|
||||
void OsFreeLibrary(OsLibraryHandle handle) {
|
||||
// The reference count on *Nix will be incremented by the launcher
|
||||
// process itself, therefore we do not risk accidentally pulling the
|
||||
// library out of the rug of the engine in either case.
|
||||
// The reference count on *Nix *will* be incremented by dlopen(),
|
||||
// therefore we do have to always free libraries.
|
||||
dlclose(handle);
|
||||
}
|
||||
} // namespace lucore::detail
|
||||
|
|
|
@ -6,7 +6,14 @@
|
|||
namespace lucore::detail {
|
||||
|
||||
OsLibraryHandle OsOpenLibrary(const char* filename) {
|
||||
return reinterpret_cast<OsLibraryHandle>(GetModuleHandleA(filename);
|
||||
return reinterpret_cast<OsLibraryHandle>(LoadLibraryA(filename));
|
||||
}
|
||||
|
||||
OsLibraryHandle OsOpenExistingLibrary(const char* filename) {
|
||||
if(!OsLibraryLoaded(filename))
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<OsLibraryHandle>(GetModuleHandleA(filename));
|
||||
}
|
||||
|
||||
bool OsLibraryLoaded(const char* filename) {
|
||||
|
@ -18,8 +25,11 @@ namespace lucore::detail {
|
|||
}
|
||||
|
||||
void OsFreeLibrary(OsLibraryHandle handle) {
|
||||
// GetModuleHandle*() does not increment the reference count;
|
||||
// therefore, we have nothing to do here on Windows.
|
||||
// Note that this function should never be called on a handle retrieved
|
||||
// from OsOpenExistingLibrary(); GetModuleHandle() does **not** increment
|
||||
// the module's reference count and therefore there is a real risk of accidentally
|
||||
// freeing the module and causing crashes
|
||||
FreeLibraryA(reinterpret_cast<HMODULE>(handle));
|
||||
}
|
||||
|
||||
} // namespace lucore::detail
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace lucore {
|
|||
|
||||
void StdoutSink::OutputMessage(const Logger::MessageData& data) {
|
||||
// This is kinda iffy, but required until more standard libraries support the C++23 <print>
|
||||
// header.
|
||||
// header (or C++23 in general, but that's a different can of worms.)
|
||||
struct FputcIterator {
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = void;
|
||||
|
|
|
@ -10,11 +10,17 @@
|
|||
namespace fs = std::filesystem;
|
||||
|
||||
namespace projgen::util {
|
||||
struct FCloseDeleter {
|
||||
void operator()(std::FILE* file) {
|
||||
if(file)
|
||||
std::fclose(file);
|
||||
}
|
||||
};
|
||||
|
||||
using UniqueFilePtr = std::unique_ptr<std::FILE, decltype(&std::fclose)>;
|
||||
using UniqueFilePtr = std::unique_ptr<std::FILE, FCloseDeleter>;
|
||||
|
||||
inline UniqueFilePtr UniqueFopen(std::string_view path, std::string_view mode) {
|
||||
return UniqueFilePtr(std::fopen(path.data(), mode.data()), &std::fclose);
|
||||
return UniqueFilePtr(std::fopen(path.data(), mode.data()));
|
||||
}
|
||||
|
||||
inline std::string ReadFileAsString(const fs::path& path) {
|
||||
|
|
|
@ -163,6 +163,9 @@ namespace projgen::make {
|
|||
|
||||
bool Write(const std::vector<std::unique_ptr<MakefileGeneratable>>& g) {
|
||||
for(auto& p : g) {
|
||||
WriteLine("# Generated by LCPU project generator\n");
|
||||
WriteLine("# Do not modify this file.\n");
|
||||
|
||||
auto generated_data = p->Generate();
|
||||
if(std::fwrite(generated_data.data(), 1, generated_data.length(), file.get()) != generated_data.length())
|
||||
return false;
|
||||
|
@ -175,7 +178,12 @@ namespace projgen::make {
|
|||
}
|
||||
|
||||
private:
|
||||
projgen::util::UniqueFilePtr file { nullptr, std::fclose };
|
||||
|
||||
void WriteLine(std::string_view line) {
|
||||
std::fwrite(line.data(), sizeof(char), line.length(), file.get());
|
||||
}
|
||||
|
||||
projgen::util::UniqueFilePtr file;
|
||||
};
|
||||
|
||||
} // namespace projgen::make
|
||||
|
|
|
@ -24,30 +24,38 @@ namespace riscv {
|
|||
extraflags |= 3; // Start in Machine mode
|
||||
}
|
||||
|
||||
constexpr u32 GetCycleCount() { return cycleCount; }
|
||||
constexpr void SetCycleCount(u32 value) {
|
||||
LUCORE_ASSERT(value != 0, "no <3");
|
||||
cycleCount = value;
|
||||
}
|
||||
|
||||
// TODO: Handlers for CSR read/write (if we need it?)
|
||||
|
||||
/// CPU state
|
||||
GeneralPurposeRegisters gpr{};
|
||||
u32 pc{};
|
||||
u32 mstatus{};
|
||||
u32 cyclel{};
|
||||
u32 cycleh{};
|
||||
u32 mscratch{};
|
||||
u32 mtvec{};
|
||||
u32 mie{};
|
||||
u32 mip{};
|
||||
GeneralPurposeRegisters gpr {};
|
||||
u32 pc {};
|
||||
u32 mstatus {};
|
||||
u32 cyclel {};
|
||||
u32 cycleh {};
|
||||
u32 mscratch {};
|
||||
u32 mtvec {};
|
||||
u32 mie {};
|
||||
u32 mip {};
|
||||
|
||||
u32 mepc{};
|
||||
u32 mtval{};
|
||||
u32 mcause{};
|
||||
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{};
|
||||
u32 extraflags {};
|
||||
|
||||
private:
|
||||
u32 cycleCount { 1024 };
|
||||
|
||||
/// Set by [CPU::Trap] to tell the CPU it was trapped.
|
||||
bool trapped { false };
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
namespace riscv {
|
||||
|
||||
void CPU::Clock() {
|
||||
Step(1024);
|
||||
Step(cycleCount);
|
||||
}
|
||||
|
||||
void CPU::Trap(u32 trapCode) {
|
||||
|
|
Loading…
Reference in New Issue