test lua binding things

This commit is contained in:
Lily Tsuru 2023-07-24 06:50:18 -04:00
parent 90e684e1e3
commit 887b66bbb0
15 changed files with 368 additions and 25 deletions

3
.gitignore vendored
View File

@ -1,5 +1,6 @@
build/ build/
lua/bin # this one is created by the build script
module_build/
native/projects/riscv/ref native/projects/riscv/ref
.cache/ .cache/

View File

@ -2,15 +2,17 @@
# Build the LCPU addon for the reccomended environment # Build the LCPU addon for the reccomended environment
# and install it into the proper directory gmod wants native modules to be. # and install it into the proper directory gmod wants native modules to be.
# This expects to be ran in [gmod]/addons/[addon folder].
set -x set -x
cmake -Wno-dev -GNinja -S native -B build -DCMAKE_BUILD_TYPE=Release # where your game server is
ninja -C build GS_PATH="/home/lily/gs/gmod"
[[ ! -d '../../lua/bin' ]] && { cmake -Wno-dev -GNinja -S native -B module_build -DCMAKE_BUILD_TYPE=Release
mkdir -p ../../lua/bin ninja -C module_build
[[ ! -d "$GS_PATH/garrysmod/lua/bin" ]] && {
mkdir -p $GS_PATH/garrysmod/lua/bin
} }
cp -v build/projects/lcpu/*.dll ../../lua/bin cp -v module_build/projects/lcpu/*.dll $GS_PATH/garrysmod/lua/bin

View File

@ -1,3 +1,15 @@
-- skeleton load file to get gmod to recognize this as an addon
-- this will contain files later on in life.
AddCSLuaFile() AddCSLuaFile()
-- prime the native lua module if running on the server
if SERVER then
require("lcpu_native")
if LCPUNative.ModuleVersion != 1 then
print("Your LCPU native module is somehow lagging behind the Lua code. Please rebuild it.")
LCPUNative = nil
return
end
AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
AddCSLuaFile("lcpu/stool_helper.lua")
end

View File

@ -0,0 +1,20 @@
AddCSLuaFile()
DEFINE_BASECLASS("base_wire_entity") -- for now?
ENT.PrintName = "LCPU"
ENT.Author = "Lily <3"
-- no more, this deeply uses native APIs
if CLIENT then return end
function ENT:Initialize()
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
-- 64 kb of ram for now.
self.cpu = LCPUNative.CreateCPU(64 * 1024)
end
function ENT:Think()
self.cpu:Cycle()
-- Even though this is gated by tickrate I'm just trying to be nice here
self:NextThink(CurTime() + 0.1)
end

View File

@ -0,0 +1,98 @@
-- 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

View File

@ -2,8 +2,11 @@ include(./gmod_headers.cmake)
add_library(lcpu_native SHARED add_library(lcpu_native SHARED
src/main.cpp
src/SourceSink.cpp src/SourceSink.cpp
src/main.cpp
src/LuaCpu.cpp
) )
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")

View File

@ -0,0 +1,108 @@
#include "LuaCpu.hpp"
#include <lucore/Logger.hpp>
#include "LuaMember.hpp"
// this is temporary from the thing
/// simple 16550 UART implementation
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 {
switch(address) {
case BASE_ADDRESS: return '\0'; // just return 0 for the input register
case BASE_ADDRESS + 5: return 0x60; // active, but no keyboard input
}
return 0;
}
void Poke(riscv::Address address, u32 value) override {
if(address == BASE_ADDRESS) {
char c = value & 0x000000ff;
fputc(c, stderr);
}
}
};
int LuaCpu::__lua_typeid;
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();
}
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);
// 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");
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::fclose(fp);
}
}
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<LuaCpu>(1, __lua_typeid);
if(self != nullptr) { // GetUserType returns nullptr on failure
delete self;
}
return 0;
}
LUA_MEMBER_FUNCTION(LuaCpu, Cycle) {
auto self = LUA->GetUserType<LuaCpu>(1, __lua_typeid);
if(!self) {
LUA->ThrowError("invalid self argument for LuaCpu:Cycle()");
}
self->CycleImpl();
return 0;
}

View File

@ -0,0 +1,33 @@
#include <riscv/System.hpp>
#include "LuaMember.hpp"
// A work-in-progress
struct LuaCpu {
/// Lua binding stuff
static void Bind(GarrysMod::Lua::ILuaBase* LUA);
static void Create(GarrysMod::Lua::ILuaBase* LUA, u32 memorySize);
LuaCpu(u32 memorySize);
~LuaCpu();
private:
void CycleImpl();
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)
// member variables
riscv::System* system;
bool poweredOn = false;
};

View File

@ -0,0 +1,15 @@
#pragma once
#include <GarrysMod/Lua/Interface.h>
// 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)

View File

@ -1,16 +1,60 @@
#include <GarrysMod/Lua/Interface.h> #include <GarrysMod/Lua/Interface.h>
#include <lucore/Assert.hpp> #include <cmath>
#include <lucore/Logger.hpp>
#include <lucore/Types.hpp>
#include "SourceSink.hpp" #include "SourceSink.hpp"
LUA_FUNCTION(lcpu_native_test) { #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();
}
GMOD_MODULE_OPEN() { GMOD_MODULE_OPEN() {
lucore::Logger::The().AttachSink(lcpu::SourceSink::The()); lucore::Logger::The().AttachSink(lcpu::SourceSink::The());
lucore::LogInfo("LCPU Native Module loading"); lucore::LogInfo("LCPU Native Module!");
// Let lua types bind
//LuaCpu::Bind(LUA);
// Bind the global namespace
LCPUNative_Bind(LUA);
return 0; return 0;
} }

View File

@ -9,6 +9,10 @@ namespace riscv::devices {
RamDevice(Address base, Address size); RamDevice(Address base, Address size);
virtual ~RamDevice(); virtual ~RamDevice();
// Resize. DO NOT call this while actively using the memory,
// or you WILL crash.
void Resize(Address newSize);
// Implementation of Device interface // Implementation of Device interface
Address Base() const override; Address Base() const override;

View File

@ -279,9 +279,7 @@ namespace riscv {
// case 0xf12: rval = 0x00000000; break; //marchid // case 0xf12: rval = 0x00000000; break; //marchid
// case 0xf13: rval = 0x00000000; break; //mimpid // case 0xf13: rval = 0x00000000; break; //mimpid
// case 0xf14: rval = 0x00000000; break; //mhartid // case 0xf14: rval = 0x00000000; break; //mhartid
default: default: break;
// MINIRV32_OTHERCSR_READ(csrno, rval);
break;
} }
switch(microop) { switch(microop) {
@ -309,9 +307,7 @@ namespace riscv {
// case 0xf13: break; //mimpid // case 0xf13: break; //mimpid
// case 0xf14: break; //mhartid // case 0xf14: break; //mhartid
// case 0x301: break; //misa // case 0x301: break; //misa
default: default: break;
// MINIRV32_OTHERCSR_WRITE(csrno, writeval);
break;
} }
} else if(microop == 0x0) { // "SYSTEM" 0b000 } else if(microop == 0x0) { // "SYSTEM" 0b000
rdid = 0; rdid = 0;

View File

@ -1,7 +1,5 @@
#include <riscv/Devices/RamDevice.hpp> #include <riscv/Devices/RamDevice.hpp>
#include "riscv/Types.hpp"
namespace riscv::devices { namespace riscv::devices {
RamDevice::RamDevice(Address base, Address size) : memoryBase(base), memorySize(size) { RamDevice::RamDevice(Address base, Address size) : memoryBase(base), memorySize(size) {
@ -13,6 +11,15 @@ namespace riscv::devices {
delete[] memory; delete[] memory;
} }
void RamDevice::Resize(Address newSize) {
if(memory) {
delete[] memory;
}
memory = new u8[newSize];
memorySize = newSize;
}
Address RamDevice::Base() const { Address RamDevice::Base() const {
return memoryBase; return memoryBase;
} }

View File

@ -15,8 +15,8 @@ struct SimpleUartDevice : public riscv::Bus::MmioDevice {
u32 Peek(riscv::Address address) override { u32 Peek(riscv::Address address) override {
switch(address) { switch(address) {
case BASE_ADDRESS: return 0x60; // active, but no keyboard input case BASE_ADDRESS: return '\0'; // just return 0 for the input register
case BASE_ADDRESS + 5: return '\0'; case BASE_ADDRESS + 5: return 0x60; // active, but no keyboard input
} }
return 0; return 0;

View File

@ -53,8 +53,8 @@ void main() {
// Shut down the test harness once we're done testing. // Shut down the test harness once we're done testing.
puts("Tests done, shutting down test harness...\n"); puts("Tests done, shutting down test harness...\n");
SYSCON = 0x5555; //SYSCON = 0x5555;
// loop forever // loop forever
// for(;;); for(;;);
} }