fixup luadevice binding a bit

This commit is contained in:
Lily Tsuru 2023-07-27 16:55:29 -04:00
parent edc5def251
commit 1d0830160b
10 changed files with 287 additions and 254 deletions

View File

@ -26,7 +26,7 @@ if SERVER then
print("size property is " .. device.Size) print("size property is " .. device.Size)
function device:Clock() function device:Clock()
print("a") print(self.Base)
end end
function device:Peek(address) function device:Peek(address)
@ -59,7 +59,7 @@ end
cpu:Cycle();cpu:Cycle();cpu:Cycle();cpu:Cycle(); cpu:Cycle();cpu:Cycle();cpu:Cycle();cpu:Cycle();
cpu:Cycle();cpu:Cycle();cpu:Cycle();cpu:Cycle(); cpu:Cycle();cpu:Cycle();cpu:Cycle();cpu:Cycle();
cpu:Cycle();cpu:Cycle();cpu:Cycle();cpu:Cycle(); cpu:Cycle();cpu:Cycle();cpu:Cycle();cpu:Cycle();
]] --]]
AddCSLuaFile("entities/gmod_lcpu_cpu.lua") AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
end end

View File

@ -4,7 +4,8 @@
#include "LuaCpu.hpp" #include "LuaCpu.hpp"
#include "LuaDevice.hpp" #include "LuaDevice.hpp"
LUA_FUNCTION(LCPUNative_CreateCPU) { namespace lcpu {
LUA_FUNCTION(LCPUNative_CreateCPU) {
LUA->CheckType(1, GarrysMod::Lua::Type::Number); LUA->CheckType(1, GarrysMod::Lua::Type::Number);
auto memorySize = static_cast<u32>(LUA->GetNumber(1)); auto memorySize = static_cast<u32>(LUA->GetNumber(1));
@ -14,18 +15,18 @@ LUA_FUNCTION(LCPUNative_CreateCPU) {
LuaCpu::Create(LUA, memorySize); LuaCpu::Create(LUA, memorySize);
return 1; return 1;
} }
LUA_FUNCTION(LCPUNative_CreateDevice) { LUA_FUNCTION(LCPUNative_CreateDevice) {
auto base = LUA->CheckNumber(1); auto base = LUA->CheckNumber(1);
auto size = LUA->CheckNumber(2); auto size = LUA->CheckNumber(2);
lucore::LogInfo("Creating Lua device object mapped @ 0x{:08x} with size 0x{:08x}", static_cast<riscv::Address>(base), lucore::LogInfo("Creating Lua device object mapped @ 0x{:08x} with size 0x{:08x}", static_cast<riscv::Address>(base),
static_cast<riscv::Address>(size)); static_cast<riscv::Address>(size));
LuaDevice::Create(LUA, static_cast<riscv::Address>(base), static_cast<riscv::Address>(size)); LuaDevice::Create(LUA, static_cast<riscv::Address>(base), static_cast<riscv::Address>(size));
return 1; return 1;
} }
void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA) { void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA) {
LuaCpu::RegisterClass(LUA); LuaCpu::RegisterClass(LUA);
LuaDevice::RegisterClass(LUA); LuaDevice::RegisterClass(LUA);
@ -40,4 +41,6 @@ void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA) {
LUA->SetField(-2, "LCPUNative"); LUA->SetField(-2, "LCPUNative");
LUA->Pop(); LUA->Pop();
// clang-format on // clang-format on
} }
} // namespace lcpu

View File

@ -1,7 +1,10 @@
#include "LuaHelpers.hpp" #include "LuaHelpers.hpp"
namespace lcpu {
/// This should be bumped on any incompatible change to the native bindings /// 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. /// that would break older Lua code, or requires newer Lua code to run.
#define LCPU_MODULE_VERSION 1 #define LCPU_MODULE_VERSION 1
void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA); void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA);
} // namespace lcpu

View File

@ -4,8 +4,8 @@
#include "LuaDevice.hpp" #include "LuaDevice.hpp"
// this is temporary from the thing // this is temporary from the test harness, and will be replaced
// at some point.
/// simple 16550 UART implementation /// simple 16550 UART implementation
struct SimpleUartDevice : public riscv::Bus::MmioDevice { struct SimpleUartDevice : public riscv::Bus::MmioDevice {
constexpr static riscv::Address BASE_ADDRESS = 0x10000000; constexpr static riscv::Address BASE_ADDRESS = 0x10000000;
@ -30,21 +30,22 @@ struct SimpleUartDevice : public riscv::Bus::MmioDevice {
} }
}; };
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PoweredOn) { namespace lcpu {
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PoweredOn) {
auto self = LuaCpu::FromLua(LUA, 1); auto self = LuaCpu::FromLua(LUA, 1);
LUA->PushBool(self->poweredOn); LUA->PushBool(self->poweredOn);
return 1; return 1;
} }
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Cycle) { LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Cycle) {
auto self = LuaCpu::FromLua(LUA, 1); auto self = LuaCpu::FromLua(LUA, 1);
if(!self->poweredOn) if(!self->poweredOn)
return 0; return 0;
self->system->Step(); self->system->Step();
return 0; return 0;
} }
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOff) { LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOff) {
auto self = LuaCpu::FromLua(LUA, 1); auto self = LuaCpu::FromLua(LUA, 1);
if(!self->poweredOn) if(!self->poweredOn)
return 0; return 0;
@ -52,9 +53,9 @@ LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOff) {
self->poweredOn = false; self->poweredOn = false;
self->system->bus->Reset(); self->system->bus->Reset();
return 0; return 0;
} }
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOn) { LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOn) {
auto self = LuaCpu::FromLua(LUA, 1); auto self = LuaCpu::FromLua(LUA, 1);
if(self->poweredOn) if(self->poweredOn)
return 0; return 0;
@ -62,24 +63,24 @@ LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, PowerOn) {
self->poweredOn = true; self->poweredOn = true;
self->system->bus->Reset(); self->system->bus->Reset();
return 0; return 0;
} }
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Reset) { LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Reset) {
auto self = LuaCpu::FromLua(LUA, 1); auto self = LuaCpu::FromLua(LUA, 1);
self->system->bus->Reset(); self->system->bus->Reset();
return 0; return 0;
} }
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, AttachDevice) { LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, AttachDevice) {
auto self = LuaCpu::FromLua(LUA, 1); auto self = LuaCpu::FromLua(LUA, 1);
auto device = LuaDevice::FromLua(LUA, 2); auto device = LuaDevice::FromLua(LUA, 2);
// Attach it // Attach it
LUA->PushBool(self->system->bus->AttachDevice(static_cast<riscv::Bus::Device*>(device))); LUA->PushBool(self->system->bus->AttachDevice(static_cast<riscv::Bus::Device*>(device)));
return 1; return 1;
} }
void LuaCpu::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) { void LuaCpu::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) {
RegisterClassStart(LUA); RegisterClassStart(LUA);
RegisterMethod("PoweredOn", PoweredOn); RegisterMethod("PoweredOn", PoweredOn);
@ -88,9 +89,9 @@ void LuaCpu::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) {
RegisterMethod("PowerOn", PowerOn); RegisterMethod("PowerOn", PowerOn);
RegisterMethod("Reset", Reset); RegisterMethod("Reset", Reset);
RegisterMethod("AttachDevice", AttachDevice); RegisterMethod("AttachDevice", AttachDevice);
} }
LuaCpu::LuaCpu(u32 memorySize) { LuaCpu::LuaCpu(u32 memorySize) {
poweredOn = true; poweredOn = true;
system = riscv::System::Create(memorySize); system = riscv::System::Create(memorySize);
system->OnPowerOff = [&]() { system->OnPowerOff = [&]() {
@ -109,8 +110,10 @@ LuaCpu::LuaCpu(u32 memorySize) {
std::fread(system->ram->Raw(), 1, len, fp); std::fread(system->ram->Raw(), 1, len, fp);
std::fclose(fp); std::fclose(fp);
} }
} }
LuaCpu::~LuaCpu() { LuaCpu::~LuaCpu() {
delete system; delete system;
} }
} // namespace lcpu

View File

@ -4,16 +4,18 @@
#include "LuaObject.hpp" #include "LuaObject.hpp"
/// Bindings of [riscv::System] to Lua. namespace lcpu {
struct LuaCpu : public lcpu::lua::LuaObject<LuaCpu> { /// Bindings of [riscv::System] to Lua.
struct LuaCpu : public lua::LuaObject<LuaCpu> {
/// Lua binding stuff /// Lua binding stuff
constexpr static const char* Name() { return "LuaCpu"; } constexpr static const char* Name() { return "LuaCpu"; }
static void RegisterClass(GarrysMod::Lua::ILuaBase* LUA); static void RegisterClass(GarrysMod::Lua::ILuaBase* LUA);
protected: protected:
friend struct lcpu::lua::LuaObject<LuaCpu>; friend struct lua::LuaObject<LuaCpu>;
LuaCpu(u32 memorySize); LuaCpu(u32 memorySize);
~LuaCpu(); ~LuaCpu();
private: private:
LUA_MEMBER_FUNCTION(PoweredOn); // Check if the CPU is powered on 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(Cycle); // do a single cycle (called internally by LCPU entity)
@ -25,4 +27,6 @@ struct LuaCpu : public lcpu::lua::LuaObject<LuaCpu> {
// member variables // member variables
riscv::System* system; riscv::System* system;
bool poweredOn; bool poweredOn;
}; };
} // namespace lcpu

View File

@ -1,6 +1,7 @@
#include "LuaDevice.hpp" #include "LuaDevice.hpp"
void LuaDevice::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) { namespace lcpu {
void LuaDevice::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) {
RegisterClassStart(LUA); RegisterClassStart(LUA);
RegisterGetter("Base", [](GarrysMod::Lua::ILuaBase* LUA) { RegisterGetter("Base", [](GarrysMod::Lua::ILuaBase* LUA) {
@ -12,15 +13,15 @@ void LuaDevice::RegisterClass(GarrysMod::Lua::ILuaBase* LUA) {
auto self = LuaDevice::FromLua(LUA, 1); auto self = LuaDevice::FromLua(LUA, 1);
LUA->PushNumber(static_cast<double>(self->size)); LUA->PushNumber(static_cast<double>(self->size));
}); });
} }
bool LuaDevice::Clocked() const { bool LuaDevice::Clocked() const {
// no real good rationale for checking here, // no real good rationale for checking here,
// since function calling does bail out properly // since function calling does bail out properly
return true; return true;
} }
void LuaDevice::Clock() { void LuaDevice::Clock() {
// clang-format off // clang-format off
lua->ReferencePush(GetTableReference()); lua->ReferencePush(GetTableReference());
lua->GetField(-1,"Clock"); lua->GetField(-1,"Clock");
@ -31,18 +32,18 @@ void LuaDevice::Clock() {
lua->Pop(); // pop the Clock function off the stack lua->Pop(); // pop the Clock function off the stack
} }
lua->Pop(); // pop the reference lua->Pop(); // pop the reference
// clang-format off // clang-format on
} }
riscv::Address LuaDevice::Base() const { riscv::Address LuaDevice::Base() const {
return base; return base;
} }
riscv::Address LuaDevice::Size() const { riscv::Address LuaDevice::Size() const {
return base; return base;
} }
u32 LuaDevice::Peek(riscv::Address address) { u32 LuaDevice::Peek(riscv::Address address) {
// clang-format off // clang-format off
lua->ReferencePush(GetTableReference()); lua->ReferencePush(GetTableReference());
lua->GetField(-1,"Peek"); lua->GetField(-1,"Peek");
@ -60,9 +61,9 @@ u32 LuaDevice::Peek(riscv::Address address) {
lua->Pop(); // pop the table reference lua->Pop(); // pop the table reference
// clang-format on // clang-format on
return 0xffffffff; return 0xffffffff;
} }
void LuaDevice::Poke(riscv::Address address, u32 value) { void LuaDevice::Poke(riscv::Address address, u32 value) {
// clang-format off // clang-format off
lua->ReferencePush(GetTableReference()); lua->ReferencePush(GetTableReference());
lua->GetField(-1,"Poke"); lua->GetField(-1,"Poke");
@ -76,9 +77,9 @@ void LuaDevice::Poke(riscv::Address address, u32 value) {
} }
lua->Pop(); // pop the table reference lua->Pop(); // pop the table reference
// clang-format on // clang-format on
} }
void LuaDevice::Reset() { void LuaDevice::Reset() {
// clang-format off // clang-format off
lua->ReferencePush(GetTableReference()); lua->ReferencePush(GetTableReference());
lua->GetField(-1,"Reset"); lua->GetField(-1,"Reset");
@ -90,7 +91,22 @@ void LuaDevice::Reset() {
} }
lua->Pop(); // pop the reference lua->Pop(); // pop the reference
// clang-format on // clang-format on
} }
LuaDevice::LuaDevice(riscv::Address base, riscv::Address size) : base(base), size(size) { LuaDevice::LuaDevice(riscv::Address base, riscv::Address size) : base(base), size(size) {
} }
void LuaDevice::AfterLuaInit() {
// Our Lua callbacks only get the table, not the actual userdata,
// ao we have to mirror things :( kinda sucks, but meh
// clang-format off
lua->ReferencePush(GetTableReference());
lua->PushNumber(static_cast<double>(base));
lua->SetField(-2, "Base");
lua->PushNumber(static_cast<double>(base));
lua->SetField(-2, "Size");
lua->Pop();
// clang-format on
}
} // namespace lcpu

View File

@ -5,8 +5,9 @@
#include "LuaHelpers.hpp" #include "LuaHelpers.hpp"
#include "LuaObject.hpp" #include "LuaObject.hpp"
/// A work-in-progress binding of [riscv::Bus::MmioDevice] to lua namespace lcpu {
struct LuaDevice : public riscv::Bus::MmioDevice, lcpu::lua::LuaObject<LuaDevice> { /// A work-in-progress binding of [riscv::Bus::MmioDevice] to lua
struct LuaDevice : public riscv::Bus::MmioDevice, lcpu::lua::LuaObject<LuaDevice> {
/// Lua binding stuff /// Lua binding stuff
constexpr static const char* Name() { return "LuaDevice"; } constexpr static const char* Name() { return "LuaDevice"; }
static void RegisterClass(GarrysMod::Lua::ILuaBase* LUA); static void RegisterClass(GarrysMod::Lua::ILuaBase* LUA);
@ -27,7 +28,10 @@ struct LuaDevice : public riscv::Bus::MmioDevice, lcpu::lua::LuaObject<LuaDevice
LuaDevice(riscv::Address base, riscv::Address size); LuaDevice(riscv::Address base, riscv::Address size);
~LuaDevice() = default; ~LuaDevice() = default;
void AfterLuaInit() override;
private: private:
riscv::Address base {}; riscv::Address base {};
riscv::Address size {}; riscv::Address size {};
}; };
} // namespace lcpu

View File

@ -1,4 +1,6 @@
//! Helpers for lua binding //! Helpers for binding Lua and C++.
//! If you want to bind a C++ class to Lua, see the
//! [lcpu::lua::LuaObject<TImpl>] type in LuaObject.hpp
#pragma once #pragma once
#include <GarrysMod/Lua/Interface.h> #include <GarrysMod/Lua/Interface.h>
@ -20,14 +22,6 @@
#define LUA_MEMBER_FUNCTION_IMPLEMENT(CLASS, FUNC) int CLASS::FUNC##__ImpStatic(GarrysMod::Lua::ILuaBase* LUA) #define LUA_MEMBER_FUNCTION_IMPLEMENT(CLASS, FUNC) int CLASS::FUNC##__ImpStatic(GarrysMod::Lua::ILuaBase* LUA)
// this synthesizes a lambda which takes the stack argument to get. this can actually also be
// stored as a variable for later usage (... if you so desire?)
#define LUA_CLASS_GET(T) \
[LUA](int stackPos) { \
LUA->CheckType(stackPos, T::__lua_typeid); \
return LUA->GetUserType<T>(stackPos, T::__lua_typeid); \
}
// Set a C function as a field. // Set a C function as a field.
#define LUA_SET_C_FUNCTION(name) \ #define LUA_SET_C_FUNCTION(name) \
LUA->PushCFunction(name); \ LUA->PushCFunction(name); \

View File

@ -10,6 +10,9 @@ namespace lcpu::lua {
/// A CRTP-based class which allows binding C++ to Lua, in a /// A CRTP-based class which allows binding C++ to Lua, in a
/// fairly sensible manner. /// fairly sensible manner.
///
/// Classes backed by this class can have arbitrary properties
/// created by Lua (using a backing table created by this object).
template <class TImpl> template <class TImpl>
struct LuaObject { struct LuaObject {
using CFunc = GarrysMod::Lua::CFunc; using CFunc = GarrysMod::Lua::CFunc;
@ -26,12 +29,15 @@ namespace lcpu::lua {
/// C++ registered value read-write. /// C++ registered value read-write.
static void RegisterSetter(const std::string& name, ILuaVoidFunc func) { setters()[name] = func; } static void RegisterSetter(const std::string& name, ILuaVoidFunc func) { setters()[name] = func; }
virtual void AfterLuaInit() {};
/// Create an instance of this type to give to Lua. /// Create an instance of this type to give to Lua.
/// addl. arguments are forwarded to the C++ constructor /// addl. arguments are forwarded to the C++ constructor
template <class... Args> template <class... Args>
static void Create(GarrysMod::Lua::ILuaBase* LUA, Args&&... args) { static void Create(GarrysMod::Lua::ILuaBase* LUA, Args&&... args) {
auto ptr = new TImpl(static_cast<Args&&>(args)...); auto ptr = new TImpl(static_cast<Args&&>(args)...);
ptr->InitLuaStuff(LUA); ptr->InitLuaStuff(LUA);
ptr->AfterLuaInit();
LUA->PushUserType(ptr, __lua_typeid); LUA->PushUserType(ptr, __lua_typeid);
} }
@ -85,14 +91,14 @@ namespace lcpu::lua {
LUA->CreateTable(); LUA->CreateTable();
tableReference = LUA->ReferenceCreate(); tableReference = LUA->ReferenceCreate();
// register some convinence things // register some convinence getters
RegisterGetter("Name", [](GarrysMod::Lua::ILuaBase* LUA) { LUA->PushString(TImpl::Name()); }); RegisterGetter("Name", [](GarrysMod::Lua::ILuaBase* LUA) { LUA->PushString(TImpl::Name()); });
} }
int GetTableReference() { return tableReference; } int GetTableReference() { return tableReference; }
LuaObject() = default; LuaObject() = default;
~LuaObject() { virtual ~LuaObject() {
// free the table reference // free the table reference
if(tableReference != -1) if(tableReference != -1)
lua->ReferenceFree(tableReference); lua->ReferenceFree(tableReference);

View File

@ -11,7 +11,7 @@ GMOD_MODULE_OPEN() {
lucore::Logger::The().AttachSink(lcpu::SourceSink::The()); lucore::Logger::The().AttachSink(lcpu::SourceSink::The());
lucore::LogInfo("LCPU Native Module! (ModuleVersion {})", LCPU_MODULE_VERSION); lucore::LogInfo("LCPU Native Module! (ModuleVersion {})", LCPU_MODULE_VERSION);
GlobalsBind(LUA); lcpu::GlobalsBind(LUA);
return 0; return 0;
} }