diff --git a/lua/autorun/lcpu_load.lua b/lua/autorun/lcpu_load.lua index 4b95770..04dd5be 100644 --- a/lua/autorun/lcpu_load.lua +++ b/lua/autorun/lcpu_load.lua @@ -1,6 +1,7 @@ AddCSLuaFile() --- prime the native lua module if running on the server +-- prime the native lua module & add clientside files to send +-- if running on the server if SERVER then require("lcpu_native") @@ -11,5 +12,4 @@ if SERVER then end AddCSLuaFile("entities/gmod_lcpu_cpu.lua") - AddCSLuaFile("lcpu/stool_helper.lua") end diff --git a/lua/entities/gmod_lcpu_cpu.lua b/lua/entities/gmod_lcpu_cpu.lua index 685b838..a0ccaac 100644 --- a/lua/entities/gmod_lcpu_cpu.lua +++ b/lua/entities/gmod_lcpu_cpu.lua @@ -10,10 +10,13 @@ function ENT:Initialize() self:SetMoveType(MOVETYPE_VPHYSICS) self:SetSolid(SOLID_VPHYSICS) -- 64 kb of ram for now. - self.cpu = LCPUNative.CreateCPU(64 * 1024) + self.cpu = LCPUNative.CreateCPU(128 * 1024) end function ENT:Think() + -- + if not self.cpu:PoweredOn() then return end + self.cpu:Cycle() -- Even though this is gated by tickrate I'm just trying to be nice here self:NextThink(CurTime() + 0.1) diff --git a/lua/weapons/gmod_tool/stools/lcpu.lua b/lua/weapons/gmod_tool/stools/lcpu.lua deleted file mode 100644 index 4452945..0000000 --- a/lua/weapons/gmod_tool/stools/lcpu.lua +++ /dev/null @@ -1,98 +0,0 @@ --- default vars -TOOL.Mode = "lcpu_lcpu" -TOOL.short_name = "lcpu" -TOOL.Category = "Lily <3" -TOOL.Name = "#tool.lcpu.name" - -if CLIENT then - language.Add("tool.lcpu.name", "LCPU Tool") - language.Add("tool.lcpu.desc", "Spawns a LCPU") - language.Add("tool.lcpu.model", "LCPU Model:") - TOOL.Information = { - { - name = "left", - text = "Spawn or update a LCPU" - }, - } - -- { name = "right", text = "Open editor" }, - -- { name = "reload", text = "Attach debugger" }, - -- { name = "reload_shift", text = "Shift+Reload: Clear" }, -end - -TOOL.ClientConVar = { - model = "models/cheeze/wires/cpu.mdl", -} - -if CLIENT then - ------------------------------------------------------------------------------ - -- Make sure firing animation is displayed clientside - ------------------------------------------------------------------------------ - function TOOL:LeftClick() - return true - end - - function TOOL:Reload() - return true - end - - function TOOL:RightClick() - return false - end -end - -if SERVER then - --function TOOL:Reload(trace) - -- if trace.Entity:IsPlayer() then return false end - -- local player = self:GetOwner() - - -- return true - --end - - - - function TOOL:LeftClick() - return true - end - - -- Right click: open editor - --function TOOL:RightClick(trace) - -- return true - --end -end - -if CLIENT then - ------------------------------------------------------------------------------ - -- Build tool control panel - ------------------------------------------------------------------------------ - function TOOL.BuildCPanel(panel) - print("bruh") - panel:AddControl( "Header", { Description = "#tool.lcpu.desc" } ) - panel:AddControl( - "Label", - { - Text = "LCPU settings:" - } - ) - - panel:AddControl( - "PropSelect", - { - Label = "#tool.lcpu.model", - ConVar = "model", - Height = 0, - Models = list.Get("Wire_gate_Models") - } - ) - - panel:AddControl( - "Label", - { - Text = "" - } - ) - end - -- function TOOL:DrawToolScreen(width, height) - -- local currentTime = os.date("*t") - -- CPULib.RenderCPUTool(currentTime.yday % 4,"CPU") - -- end -end diff --git a/lua/wire/stools/lcpu.lua b/lua/wire/stools/lcpu.lua new file mode 100644 index 0000000..621359f --- /dev/null +++ b/lua/wire/stools/lcpu.lua @@ -0,0 +1,88 @@ +-- TODO: I'm not sure if I should use the wirelib stuff +-- I depend on it anyways but /shrug +WireToolSetup.setCategory("Chips, Gates", "Advanced") +WireToolSetup.open("lcpu", "LCPU", "gmod_lcpu_cpu", nil, "LCPUs") +if CLIENT then + language.Add("Tool.wire_lcpu.name", "LCPU Tool") + language.Add("Tool.wire_lcpu.desc", "Spawns a LCPU") + language.Add("ToolWirelcpu_Model", "Model:") + TOOL.Information = { + { + name = "left", + text = "Create/Update LCPU" + }, + } + --{ name = "right", text = "Open editor" }, + --{ name = "reload", text = "Attach debugger" }, + --{ name = "reload_shift", text = "Shift+Reload: Clear" }, +end + +WireToolSetup.BaseLang() +WireToolSetup.SetupMax(7) +TOOL.ClientConVar = { + model = "models/cheeze/wires/cpu.mdl", +} + +if CLIENT then + function TOOL:LeftClick() + return true + end + + function TOOL:Reload() + return true + end + + function TOOL:RightClick() + return false + end +end + +if SERVER then + function TOOL:Reload(trace) + if trace.Entity:IsPlayer() then return false end + local player = self:GetOwner() + + return true + end + + -- Left click: spawn CPU or upload current program into it + function TOOL:CheckHitOwnClass(trace) + return trace.Entity:IsValid() and (trace.Entity:GetClass() == self.WireClass) + end + + function TOOL:LeftClick_Update(trace) + end + + function TOOL:MakeEnt(ply, model, Ang, trace) + local ent = WireLib.MakeWireEnt( + ply, + { + Class = self.WireClass, + Pos = trace.HitPos, + Angle = Ang, + Model = model + } + ) + + self:LeftClick_Update(trace) + + return ent + end + + -- Right click: open editor + function TOOL:RightClick(trace) + return true + end +end + +if CLIENT then + function TOOL.BuildCPanel(panel) + local modelPanel = WireDermaExts.ModelSelect(panel, "lcpu_cpu_model", list.Get("Wire_gate_Models"), 2) + panel:AddControl( + "Label", + { + Text = "" + } + ) + end +end diff --git a/native/projects/lcpu/CMakeLists.txt b/native/projects/lcpu/CMakeLists.txt index 222783b..ed11c9d 100644 --- a/native/projects/lcpu/CMakeLists.txt +++ b/native/projects/lcpu/CMakeLists.txt @@ -1,12 +1,12 @@ include(./gmod_headers.cmake) - add_library(lcpu_native SHARED + src/main.cpp + src/LcpuGlobals.cpp + src/LuaCpu.cpp + #src/LuaDevice.cpp src/SourceSink.cpp - - src/main.cpp - src/LuaCpu.cpp ) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") diff --git a/native/projects/lcpu/src/LcpuGlobals.cpp b/native/projects/lcpu/src/LcpuGlobals.cpp new file mode 100644 index 0000000..ce8d5c7 --- /dev/null +++ b/native/projects/lcpu/src/LcpuGlobals.cpp @@ -0,0 +1,45 @@ +#include "LcpuGlobals.hpp" + +#include + +#include "LuaCpu.hpp" +#include "LuaDevice.hpp" + +/// This should be bumped on any incompatible change to the native bindings +/// that would break older Lua code, or requires newer Lua code to run. +#define LCPU_MODULE_VERSION 1 + +LUA_FUNCTION(LCPUNative_CreateCPU) { + LUA->CheckType(1, GarrysMod::Lua::Type::Number); + auto memorySize = (u32)std::round(LUA->GetNumber(1)); + + // TODO: There's probably a way to like, ensure a per-player max. + if(memorySize > (64 * 1024 * 1024)) { + LUA->ThrowError("Over RAM size limit."); + } + + LuaCpu::Create(LUA, memorySize); + return 1; +} + +LUA_FUNCTION(LCPUNative_CreateDevice) { + //LuaDevice::Create(LUA); + return 0;//1; +} + +void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA) { + LuaCpu::Bind(LUA); + //LuaDevice::Bind(LUA); + + // clang-format off + LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB); + LUA->CreateTable(); + LUA->PushNumber(LCPU_MODULE_VERSION); + LUA->SetField(-2, "ModuleVersion"); + + LUA_SET_C_FUNCTION_NAME(LCPUNative_CreateCPU, "CreateCPU"); + LUA_SET_C_FUNCTION_NAME(LCPUNative_CreateDevice, "CreateDevice"); + LUA->SetField(-2, "LCPUNative"); + LUA->Pop(); + // clang-format on +} diff --git a/native/projects/lcpu/src/LcpuGlobals.hpp b/native/projects/lcpu/src/LcpuGlobals.hpp new file mode 100644 index 0000000..2779590 --- /dev/null +++ b/native/projects/lcpu/src/LcpuGlobals.hpp @@ -0,0 +1,3 @@ +#include "LuaHelpers.hpp" + +void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA); diff --git a/native/projects/lcpu/src/LuaCpu.cpp b/native/projects/lcpu/src/LuaCpu.cpp index 1850075..89a52e2 100644 --- a/native/projects/lcpu/src/LuaCpu.cpp +++ b/native/projects/lcpu/src/LuaCpu.cpp @@ -2,7 +2,8 @@ #include -#include "LuaMember.hpp" +#include "LuaDevice.hpp" +#include "LuaHelpers.hpp" // this is temporary from the thing @@ -11,7 +12,6 @@ struct SimpleUartDevice : public riscv::Bus::MmioDevice { constexpr static riscv::Address BASE_ADDRESS = 0x10000000; riscv::Address Base() const override { return BASE_ADDRESS; } - riscv::Address Size() const override { return 12; } // for now u32 Peek(riscv::Address address) override { @@ -26,83 +26,120 @@ struct SimpleUartDevice : public riscv::Bus::MmioDevice { void Poke(riscv::Address address, u32 value) override { if(address == BASE_ADDRESS) { char c = value & 0x000000ff; - fputc(c, stderr); + std::fputc(c, stderr); } } }; -int LuaCpu::__lua_typeid; +LUA_CLASS_BIND_VARIABLES_IMPLEMENT(LuaCpu); + +LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PoweredOn) { + LUA_CLASS_GET(LuaCpu, self, 1); + LUA->PushBool(self->poweredOn); + return 1; +} + +LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Cycle) { + LUA_CLASS_GET(LuaCpu, self, 1); + [&self]() { + if(!self->poweredOn) + return; + self->system->Step(); + }(); + return 0; +} + +LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOff) { + LUA_CLASS_GET(LuaCpu, self, 1); + [&self]() { + if(!self->poweredOn) + return; + + self->poweredOn = false; + self->system->bus->Reset(); + }(); + + return 0; +} + +LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOn) { + LUA_CLASS_GET(LuaCpu, self, 1); + [&self]() { + if(self->poweredOn) + return; + + self->poweredOn = true; + self->system->bus->Reset(); + }(); + return 0; +} + +LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Reset) { + LUA_CLASS_GET(LuaCpu, self, 1); + [&self]() { self->system->bus->Reset(); }(); + return 0; +} + +LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, AttachDevice) { + LUA_CLASS_GET(LuaCpu, self, 1); + bool result = false; +#if 0 + [&]() { + LUA_CLASS_GET(LuaDevice, device, 2); + if(!device) + return; // the bus is safe against this possibility, but + // I'd rather be doubly-safe tbh + + // Attach it + result = self->system->bus->AttachDevice(static_cast(device)); + }(); +#endif + LUA->PushBool(result); + return 1; +} void LuaCpu::Bind(GarrysMod::Lua::ILuaBase* LUA) { - lucore::LogInfo("In LuaCpu::Bind()"); - __lua_typeid = LUA->CreateMetaTable("LuaCpu"); - LUA->PushSpecial(GarrysMod::Lua::SPECIAL_REG); - LUA->PushNumber(__lua_typeid); - LUA->SetField(-2, "LuaCpu__typeid"); - LUA->Pop(); // Pop the registry - - LUA->Push(-1); - // This method is called when the GC is done with our stuff - LUA->PushCFunction(__gc); - LUA->SetField(-1, "__gc"); - - LUA->PushCFunction(Cycle); - LUA->SetField(-1, "Cycle"); - LUA->Pop(); + // clang-format off + LUA_CLASS_BIND_BEGIN(LuaCpu); + LUA_SET_C_FUNCTION(PoweredOn); + LUA_SET_C_FUNCTION(Cycle); + LUA_SET_C_FUNCTION(PowerOff); + LUA_SET_C_FUNCTION(PowerOn); + LUA_SET_C_FUNCTION(Reset); + LUA_SET_C_FUNCTION(AttachDevice); + LUA_CLASS_BIND_END(); + // clang-format on } void LuaCpu::Create(GarrysMod::Lua::ILuaBase* LUA, u32 memorySize) { - LUA->PushUserType(new LuaCpu(memorySize), __lua_typeid); -} - -LuaCpu::LuaCpu(u32 memorySize) { - system = riscv::System::Create(memorySize); - system->OnPowerOff = [&]() { this->OnSysconShutdown(); }; - - system->bus->AttachDevice(new SimpleUartDevice); + auto cpuWrapper = new LuaCpu(memorySize); // lame test code. this WILL be removed, I just want this for a quick test - auto fp = std::fopen("/home/lily/gs/gmod/garrysmod/addons/lcpu/native/projects/riscv_test_harness/test/test.bin", "rb"); + cpuWrapper->system->bus->AttachDevice(new SimpleUartDevice); + auto fp = std::fopen("/home/lily/test.bin", "rb"); if(fp) { std::fseek(fp, 0, SEEK_END); auto len = std::ftell(fp); std::fseek(fp, 0, SEEK_SET); - std::fread(system->ram->Raw(), 1, len, fp); + std::fread(cpuWrapper->system->ram->Raw(), 1, len, fp); std::fclose(fp); } + + LUA->PushUserType(cpuWrapper, __lua_typeid); +} + +LuaCpu::LuaCpu(u32 memorySize) { + lucore::LogInfo("in LuaCpu::LuaCpu(0x{:08x})\n", memorySize); + + poweredOn = true; + system = riscv::System::Create(memorySize); + system->OnPowerOff = [&]() { + poweredOn = false; + system->bus->Reset(); + }; } LuaCpu::~LuaCpu() { delete system; } - -void LuaCpu::CycleImpl() { - if(!poweredOn) - return; - - system->Step(); -} - -void LuaCpu::OnSysconShutdown() { - poweredOn = false; -} - -LUA_MEMBER_FUNCTION(LuaCpu, __gc) { - auto self = LUA->GetUserType(1, __lua_typeid); - if(self != nullptr) { // GetUserType returns nullptr on failure - delete self; - } - - return 0; -} - -LUA_MEMBER_FUNCTION(LuaCpu, Cycle) { - auto self = LUA->GetUserType(1, __lua_typeid); - if(!self) { - LUA->ThrowError("invalid self argument for LuaCpu:Cycle()"); - } - - self->CycleImpl(); - return 0; -} diff --git a/native/projects/lcpu/src/LuaCpu.hpp b/native/projects/lcpu/src/LuaCpu.hpp index bd08e6a..10729b7 100644 --- a/native/projects/lcpu/src/LuaCpu.hpp +++ b/native/projects/lcpu/src/LuaCpu.hpp @@ -1,33 +1,31 @@ +#pragma once + #include -#include "LuaMember.hpp" +#include "LuaHelpers.hpp" -// A work-in-progress +/// Bindings of [riscv::System] to Lua. struct LuaCpu { /// Lua binding stuff static void Bind(GarrysMod::Lua::ILuaBase* LUA); static void Create(GarrysMod::Lua::ILuaBase* LUA, u32 memorySize); + private: + LuaCpu(u32 memorySize); ~LuaCpu(); - private: - void CycleImpl(); + LUA_MEMBER_FUNCTION(PoweredOn); // Check if the CPU is powered on + LUA_MEMBER_FUNCTION(Cycle); // do a single cycle (called internally by LCPU entity) + LUA_MEMBER_FUNCTION(PowerOff); // power off and reset the LCPU + LUA_MEMBER_FUNCTION(PowerOn); // power on the LCPU + LUA_MEMBER_FUNCTION(Reset); // reset the LCPU + LUA_MEMBER_FUNCTION(AttachDevice); // attach a LuaDevice to this cpu - void OnSysconShutdown(); - - // LUA user type id. - static int __lua_typeid; - - // Metafunctions - LUA_MEMBER_FUNCTION_DECLARE(__gc) - LUA_MEMBER_FUNCTION_DECLARE(__tostring) - - // Called by the LCPU entity for specific tasks: - LUA_MEMBER_FUNCTION_DECLARE(Cycle) - LUA_MEMBER_FUNCTION_DECLARE(SetMemorySize) + // class binding stuff + LUA_CLASS_BIND_VARIABLES(private); // member variables riscv::System* system; - bool poweredOn = false; + bool poweredOn; }; diff --git a/native/projects/lcpu/src/LuaDevice.cpp b/native/projects/lcpu/src/LuaDevice.cpp new file mode 100644 index 0000000..0fffa0e --- /dev/null +++ b/native/projects/lcpu/src/LuaDevice.cpp @@ -0,0 +1,15 @@ +#include "LuaDevice.hpp" + +LUA_CLASS_BIND_VARIABLES_IMPLEMENT(LuaDevice); + +void LuaDevice::Bind(GarrysMod::Lua::ILuaBase* LUA) { + // clang-format off + LUA_CLASS_BIND_BEGIN(LuaDevice); + // todo handlers + LUA_CLASS_BIND_END(); + // clang-format on +} + +void LuaDevice::Create(GarrysMod::Lua::ILuaBase* LUA) { + LUA->PushUserType(new LuaDevice(), __lua_typeid); +} diff --git a/native/projects/lcpu/src/LuaDevice.hpp b/native/projects/lcpu/src/LuaDevice.hpp new file mode 100644 index 0000000..c983c53 --- /dev/null +++ b/native/projects/lcpu/src/LuaDevice.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "LuaHelpers.hpp" + +/// A work-in-progress binding of [riscv::Bus::MmioDevice] to lua +struct LuaDevice : public riscv::Bus::MmioDevice { + /// Lua binding stuff + static void Bind(GarrysMod::Lua::ILuaBase* LUA); + static void Create(GarrysMod::Lua::ILuaBase* LUA); + + riscv::Address Base() const override { return base; } + riscv::Address Size() const override { return size; } // I think this is right? + + u32 Peek(riscv::Address address) override; + void Poke(riscv::Address address, u32 value) override; + + private: + // class binding stuff + LUA_CLASS_BIND_VARIABLES(private); + + // Do not call these once attached to a bus. + LUA_MEMBER_FUNCTION(SetBase); + LUA_MEMBER_FUNCTION(SetSize); + + LUA_MEMBER_FUNCTION(SetClockHandler); + LUA_MEMBER_FUNCTION(SetResetHandler); + LUA_MEMBER_FUNCTION(SetPeekHandler); + LUA_MEMBER_FUNCTION(SetPokeHandler); + + riscv::Address base {}; + riscv::Address size {}; + + // ...? + GarrysMod::Lua::ILuaBase* LuaState; +}; diff --git a/native/projects/lcpu/src/LuaHelpers.hpp b/native/projects/lcpu/src/LuaHelpers.hpp new file mode 100644 index 0000000..980983b --- /dev/null +++ b/native/projects/lcpu/src/LuaHelpers.hpp @@ -0,0 +1,65 @@ +//! Helpers for lua binding +#pragma once + +#include +#include + +// These are like the official GMOD header LUA_FUNCTION but allow forward declaration +// and implementation inside of classes, making writing class bindings that much less +// of a PITA. Nifty! +#define LUA_MEMBER_FUNCTION(FUNC) \ + static int FUNC##__ImpStatic(GarrysMod::Lua::ILuaBase* LUA); \ + static int FUNC(lua_State* L) { \ + GarrysMod::Lua::ILuaBase* LUA = L->luabase; \ + LUA->SetState(L); \ + return FUNC##__ImpStatic(LUA); \ + } + +#define LUA_MEMBER_FUNCTION_IMPLEMENT(CLASS, FUNC) int CLASS::FUNC##__ImpStatic(GarrysMod::Lua::ILuaBase* LUA) + +// will make a "self" variable with the class +#define LUA_CLASS_GET(T, name, stackPos) \ + LUA->CheckType(stackPos, T::__lua_typeid); \ + auto name = LUA->GetUserType(stackPos, T::__lua_typeid); \ + if(!name) { \ + LUA->ThrowError("nullptr " #T " passed to function which requires a valid instance"); \ + } + +#define LUA_CLASS_BIND_VARIABLES(ACCESS_LEVEL) \ + public: \ + static int __lua_typeid; \ + ACCESS_LEVEL: \ + LUA_MEMBER_FUNCTION(__gc); + +#define LUA_CLASS_BIND_VARIABLES_IMPLEMENT(T) \ + int T::__lua_typeid = 0; \ + LUA_MEMBER_FUNCTION_IMPLEMENT(T, __gc) { \ + LUA->CheckType(1, T::__lua_typeid); \ + auto self = LUA->GetUserType(1, T::__lua_typeid); \ + if(self != nullptr) { /* GetUserType returns nullptr on failure */ \ + lucore::LogInfo("GCing {} object", #T); \ + delete self; \ + } \ + return 0; \ + } + +#define LUA_CLASS_BIND_BEGIN(T) \ + T::__lua_typeid = LUA->CreateMetaTable(#T); \ + LUA->PushSpecial(GarrysMod::Lua::SPECIAL_REG); \ + LUA->PushNumber(T::__lua_typeid); \ + LUA->SetField(-2, #T "__typeid"); \ + LUA->Pop(); /* pop registry */ \ + LUA->Push(-1); \ + LUA->SetField(-2, "__index"); \ + LUA_SET_C_FUNCTION(__gc) + +#define LUA_CLASS_BIND_END() LUA->Pop(); + +// Helpers for lua functions +#define LUA_SET_C_FUNCTION(name) \ + LUA->PushCFunction(name); \ + LUA->SetField(-2, #name); + +#define LUA_SET_C_FUNCTION_NAME(name, altName) \ + LUA->PushCFunction(name); \ + LUA->SetField(-2, altName); diff --git a/native/projects/lcpu/src/LuaMember.hpp b/native/projects/lcpu/src/LuaMember.hpp deleted file mode 100644 index 8e6cc94..0000000 --- a/native/projects/lcpu/src/LuaMember.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -// These are like the official GMOD header LUA_FUNCTION but allow forward declaration -// and implementation inside of classes. Pretty nifty! -#define LUA_MEMBER_FUNCTION_DECLARE(FUNC) \ - static int FUNC##__ImpStatic(GarrysMod::Lua::ILuaBase* LUA); \ - static int FUNC(lua_State* L) { \ - GarrysMod::Lua::ILuaBase* LUA = L->luabase; \ - LUA->SetState(L); \ - return FUNC##__ImpStatic(LUA); \ - } - -#define LUA_MEMBER_FUNCTION(CLASS, FUNC) int CLASS::FUNC##__ImpStatic(GarrysMod::Lua::ILuaBase* LUA) diff --git a/native/projects/lcpu/src/SourceSink.cpp b/native/projects/lcpu/src/SourceSink.cpp index 643becf..9254290 100644 --- a/native/projects/lcpu/src/SourceSink.cpp +++ b/native/projects/lcpu/src/SourceSink.cpp @@ -84,7 +84,7 @@ namespace lcpu { void SourceSink::OutputMessage(const lucore::Logger::MessageData& data) { auto formatted = - std::format("[LCPU Native/{}] [{}] {}", lucore::Logger::SeverityToString(data.severity), data.time, std::vformat(data.format, data.args)); + std::format("[LCPU/{}] [{}] {}", lucore::Logger::SeverityToString(data.severity), data.time, std::vformat(data.format, data.args)); tier0::Msg("%s\n", formatted.c_str()); } diff --git a/native/projects/lcpu/src/main.cpp b/native/projects/lcpu/src/main.cpp index 8ca1d73..0894afe 100644 --- a/native/projects/lcpu/src/main.cpp +++ b/native/projects/lcpu/src/main.cpp @@ -1,61 +1,15 @@ #include -#include #include #include - #include "SourceSink.hpp" -#include "LuaCpu.hpp" - - -LUA_FUNCTION(LCPUNative_CreateCPU) { - LUA->CheckType(1, GarrysMod::Lua::Type::Number); - auto memorySize = (u32)std::round(LUA->GetNumber(1)); - - if (memorySize > (64 * 1024 * 1024)) { - LUA->ThrowError("Over current RAM size limit."); - } - - //LuaCpu::Create(LUA, memorySize); - return 0; -} - -// Create a device object. This is internally used by the CPU to create Wire and other interface things. -LUA_FUNCTION(LCPUNative_CreateDevice) { - return 0; // for now, while LuaDevice doesn't exist? -} - -void LCPUNative_Bind(GarrysMod::Lua::ILuaBase* LUA) { - LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); - LUA->CreateTable(); - LUA->PushNumber(1); - LUA->SetField(-2, "ModuleVersion"); - - LUA->PushCFunction(LCPUNative_CreateCPU); - LUA->SetField(-2, "CreateCPU"); - - LUA->PushCFunction(LCPUNative_CreateDevice); - LUA->SetField(-2, "CreateDevice"); - LUA->SetField(-2, "LCPUNative"); - LUA->Pop(); -} - - +#include "LcpuGlobals.hpp" GMOD_MODULE_OPEN() { lucore::Logger::The().AttachSink(lcpu::SourceSink::The()); - lucore::LogInfo("LCPU Native Module!"); - - - // Let lua types bind - //LuaCpu::Bind(LUA); - - // Bind the global namespace - LCPUNative_Bind(LUA); - - + GlobalsBind(LUA); return 0; } diff --git a/native/projects/riscv/include/riscv/Bus.hpp b/native/projects/riscv/include/riscv/Bus.hpp index aacc81a..cea373f 100644 --- a/native/projects/riscv/include/riscv/Bus.hpp +++ b/native/projects/riscv/include/riscv/Bus.hpp @@ -38,9 +38,7 @@ namespace riscv { /// This function is called by the bus to clock devices. virtual void Clock() {} - // ability to interrupt - - // probably some reset functionality later on + virtual void Reset() {} template constexpr bool IsA() { @@ -126,6 +124,7 @@ namespace riscv { /// Clock all clocked devices mapped onto the bus.. void Clock(); + void Reset(); u8 PeekByte(Address address); u16 PeekShort(Address address); diff --git a/native/projects/riscv/include/riscv/CPU.hpp b/native/projects/riscv/include/riscv/CPU.hpp index e0e359b..08dab6e 100644 --- a/native/projects/riscv/include/riscv/CPU.hpp +++ b/native/projects/riscv/include/riscv/CPU.hpp @@ -27,25 +27,25 @@ namespace riscv { // 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: /// Set by [CPU::Trap] to tell the CPU it was trapped. diff --git a/native/projects/riscv/include/riscv/CPUTypes.hpp b/native/projects/riscv/include/riscv/CPUTypes.hpp index 30ff47d..9adb864 100644 --- a/native/projects/riscv/include/riscv/CPUTypes.hpp +++ b/native/projects/riscv/include/riscv/CPUTypes.hpp @@ -71,7 +71,7 @@ namespace riscv { struct GeneralPurposeRegisters { constexpr u32& operator[](Gpr gpr) { return operator[](static_cast(gpr)); } constexpr u32& operator[](usize index) { return gprs_[index]; } - u32 gprs_[32]; + u32 gprs_[32]{}; }; } // namespace riscv diff --git a/native/projects/riscv/include/riscv/Devices/ClntDevice.hpp b/native/projects/riscv/include/riscv/Devices/ClntDevice.hpp index 5c0d90c..9e243d2 100644 --- a/native/projects/riscv/include/riscv/Devices/ClntDevice.hpp +++ b/native/projects/riscv/include/riscv/Devices/ClntDevice.hpp @@ -15,6 +15,8 @@ namespace riscv::devices { bool Clocked() const override { return true; } void Clock() override; + void Reset() override; + u32 Peek(Address address) override; void Poke(Address address, u32 value) override; diff --git a/native/projects/riscv/src/Bus.cpp b/native/projects/riscv/src/Bus.cpp index 7f8206f..5459ba5 100644 --- a/native/projects/riscv/src/Bus.cpp +++ b/native/projects/riscv/src/Bus.cpp @@ -63,6 +63,12 @@ namespace riscv { cpu->Clock(); } + void Bus::Reset() { + for(auto device : devices) + device->Reset(); + cpu->Reset(); + } + u8 Bus::PeekByte(Address address) { if(auto dev = FindDeviceForAddress(address); dev) return dev->Upcast()->PeekByte(address); diff --git a/native/projects/riscv/src/Devices/ClntDevice.cpp b/native/projects/riscv/src/Devices/ClntDevice.cpp index 2e6f911..030cbbc 100644 --- a/native/projects/riscv/src/Devices/ClntDevice.cpp +++ b/native/projects/riscv/src/Devices/ClntDevice.cpp @@ -9,11 +9,7 @@ namespace riscv::devices { TIMERH_ADDRESS = ClntDevice::BASE_ADDRESS + 0xbffc; void ClntDevice::Clock() { - // TODO: handle timer - // If match low and high match the timer during a clock - // we should fire the interrupt, otherwise not do so - - u32 new_timer = timerCountLow + 1; + u32 new_timer = timerCountLow + 10; if(new_timer < timerCountLow) timerCountHigh++; timerCountLow = new_timer; @@ -25,16 +21,19 @@ namespace riscv::devices { } } + void ClntDevice::Reset() { + timerCountLow = 0; + timerCountHigh = 0; + timerMatchHigh = 0; + timerMatchLow = 0; + } + u32 ClntDevice::Peek(Address address) { switch(address) { case TIMERL_ADDRESS: return timerCountLow; - case TIMERH_ADDRESS: return timerCountHigh; - case MATCHL_ADDRESS: return timerMatchLow; - case MATCHH_ADDRESS: return timerMatchHigh; - default: return 0x0; } } @@ -42,12 +41,7 @@ namespace riscv::devices { void ClntDevice::Poke(Address address, u32 value) { switch(address) { case MATCHL_ADDRESS: timerMatchLow = value; break; - - case MATCHH_ADDRESS: - timerMatchHigh = value; - break; - - // ? + case MATCHH_ADDRESS: timerMatchHigh = value; break; default: lucore::LogInfo("CLNT({}) unhandled poke @ 0x{:08x} : 0x{:08x}", static_cast(this), address, value); break; } } diff --git a/native/projects/riscv/src/Devices/RamDevice.cpp b/native/projects/riscv/src/Devices/RamDevice.cpp index 33f6ccb..b4bb4a6 100644 --- a/native/projects/riscv/src/Devices/RamDevice.cpp +++ b/native/projects/riscv/src/Devices/RamDevice.cpp @@ -3,7 +3,7 @@ namespace riscv::devices { RamDevice::RamDevice(Address base, Address size) : memoryBase(base), memorySize(size) { - memory = new u8[size]; + memory = new u8[size]{}; LUCORE_CHECK(memory, "Could not allocate buffer for memory device with size 0x{:08x}.", size); } diff --git a/native/projects/riscv/src/System.cpp b/native/projects/riscv/src/System.cpp index a0c51b4..caaa94e 100644 --- a/native/projects/riscv/src/System.cpp +++ b/native/projects/riscv/src/System.cpp @@ -12,9 +12,6 @@ namespace riscv { system->clnt = new devices::ClntDevice(); system->syscon = new devices::SysconDevice(system); - // techinically this is done on construction but lets be hard about it - system->cpu->Reset(); - // attach everything into the bus if(!system->bus->AttachDevice(system->cpu)) return nullptr; @@ -25,6 +22,9 @@ namespace riscv { if(!system->bus->AttachDevice(system->ram)) return nullptr; + // reset the bus and all devices on it + system->bus->Reset(); + return system; } diff --git a/native/projects/riscv_test_harness/main.cpp b/native/projects/riscv_test_harness/main.cpp index 2aa35ec..056a222 100644 --- a/native/projects/riscv_test_harness/main.cpp +++ b/native/projects/riscv_test_harness/main.cpp @@ -5,6 +5,8 @@ #include #include +#include + /// simple 16550 UART implementation struct SimpleUartDevice : public riscv::Bus::MmioDevice { constexpr static riscv::Address BASE_ADDRESS = 0x10000000; @@ -59,6 +61,7 @@ int main(int argc, char** argv) { while(!shouldExit) { system->Step(); + //std::this_thread::sleep_for(std::chrono::milliseconds(100)); } delete system;