lcpu: Lua devices now work!!

now i can like, actually finish this thing

i will probably commonize all the stuff the luadevice class is doing right now into its own object, since I think that it would be very useful to have elsewhere. but for now it's not common :(
This commit is contained in:
Lily Tsuru 2023-07-27 06:03:28 -04:00
parent b6d41d33fa
commit 40c539bf22
16 changed files with 282 additions and 383 deletions

View File

@ -1,15 +1,59 @@
AddCSLuaFile() AddCSLuaFile()
-- prime the native lua module & add clientside files to send -- prime the native lua module & add clientside files to send
-- if running on the server -- if running on the server
if SERVER then if SERVER then
require("lcpu_native") require("lcpu_native")
if LCPUNative.ModuleVersion ~= 1 then
if LCPUNative.ModuleVersion != 1 then
print("Your LCPU native module is somehow lagging behind the Lua code. Please rebuild it.") print("Your LCPU native module is somehow lagging behind the Lua code. Please rebuild it.")
LCPUNative = nil LCPUNative = nil
return return
end end
-- rapid iteration requires rapid solutions
--[[
device = LCPUNative.CreateDevice(0x100000f0, 0x10)
device.a = 12
device.apple = {}
--print(device)
--print(device.a)
--print(device.apple)
function device:Clock()
print("a")
end
function device:Peek(address)
print("peek @ " .. address)
if address == 0x100000f0 then return 0x1010 end -- it a test!
return 0x10000
end
function device:Poke(address, value)
if address == 0x100000f0 then
print("What you doing?")
end
end
function device:Reset()
print("device was reset")
end
cpu = LCPUNative.CreateCPU(64*1024)
cpu:AttachDevice(device)
print(device.Clock)
print(cpu)
-- unrolled test loops ftw
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,46 +4,51 @@ ENT.PrintName = "LCPU"
ENT.Author = "Lily <3" ENT.Author = "Lily <3"
-- no more, this deeply uses native APIs -- no more, this deeply uses native APIs
if CLIENT then return end if CLIENT then return end
function ENT:Initialize() function ENT:Initialize()
self:PhysicsInit(SOLID_VPHYSICS) self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS) self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS) self:SetSolid(SOLID_VPHYSICS)
-- 64 kb of ram for now. -- 64 kb of ram for now.
self.cpu = LCPUNative.CreateCPU(128 * 1024) self.cpu = LCPUNative.CreateCPU(128 * 1024)
print(self.cpu)
-- todo: cpu callbacks? once they become a thing
-- test device framework -- test device framework
-- this is how I ideally want to do things, -- (for once something works out how I wanted it to..)
-- dunno if it's possible self.test_device = LCPUNative.CreateDevice(0x11300000, 0x8)
self.test_device = LCPUNative.CreateDevice() self.test_device.register = 0x0
print(self.test_device)
self.test_device:SetBase(0x12000000) --function self.test_device:Clock()
self.test_device:SetSize(0x10) --print("TestDevice Clock()")
function self.test_device:Clock() --end
print("TestDevice Clock()")
end
function self.test_device:Peek(address) function self.test_device:Peek(address)
if address == 0x12000000 then --print("peek @ " .. address)
-- it a test! if address == self.Base then return CurTime() end -- it a test!
return CurTime() if address == self.Base + 4 then return self.register end
end
return 0x10000 return 0xffffffff
end end
function self.test_device:Poke(address, value) function self.test_device:Poke(address, value)
if address == 0x12000000 then print("poke of address " .. address .. " -> " .. value)
print("What you doing?") if address == self.Base + 4 then
print("LUAREG write")
self.register = value
end end
end end
function self.test_device:Reset()
print("device was reset")
-- clear the register
self.register = 0
end
self.cpu:AttachDevice(self.test_device) self.cpu:AttachDevice(self.test_device)
end end
function ENT:Think() function ENT:Think()
-- --
if not self.cpu:PoweredOn() then return end if not self.cpu:PoweredOn() then return end
self.cpu:Cycle() self.cpu:Cycle()
-- Even though this is gated by tickrate I'm just trying to be nice here -- Even though this is gated by tickrate I'm just trying to be nice here
self:NextThink(CurTime() + 0.1) self:NextThink(CurTime() + 0.1)

View File

@ -8,7 +8,6 @@ add_library(lcpu_native SHARED
# Support code # Support code
src/SourceSink.cpp src/SourceSink.cpp
src/LuaShared.cpp
) )
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@ -22,6 +21,7 @@ endif()
target_link_libraries(lcpu_native target_link_libraries(lcpu_native
gmod_headers gmod_headers
lucore::lucore lucore::lucore
riscv::riscv riscv::riscv
) )

View File

@ -1,9 +1,9 @@
#include "LcpuGlobals.hpp" #include "LcpuGlobals.hpp"
#include "GarrysMod/Lua/Interface.h"
#include "LuaCpu.hpp" #include "LuaCpu.hpp"
#include "LuaDevice.hpp" #include "LuaDevice.hpp"
#include "LuaHelpers.hpp"
LUA_FUNCTION(LCPUNative_CreateCPU) { LUA_FUNCTION(LCPUNative_CreateCPU) {
LUA->CheckType(1, GarrysMod::Lua::Type::Number); LUA->CheckType(1, GarrysMod::Lua::Type::Number);
@ -18,13 +18,16 @@ LUA_FUNCTION(LCPUNative_CreateCPU) {
} }
LUA_FUNCTION(LCPUNative_CreateDevice) { LUA_FUNCTION(LCPUNative_CreateDevice) {
LuaDevice::Create(LUA); auto base = LUA->CheckNumber(1);
auto size = LUA->CheckNumber(2);
lucore::LogInfo("Creating Lua device object mapped @ 0x{:08x} with size 0x{:08x}", 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::Bind(LUA); LuaCpu::Bind(LUA);
// LuaDevice::Bind(LUA); LuaDevice::Bind(LUA);
// clang-format off // clang-format off
LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB); LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB);

View File

@ -75,12 +75,7 @@ LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, Reset) {
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, AttachDevice) { LUA_MEMBER_FUNCTION_IMPLEMENT(LuaCpu, AttachDevice) {
auto self = LUA_CLASS_GET(LuaCpu)(1); auto self = LUA_CLASS_GET(LuaCpu)(1);
auto device = LUA_CLASS_GET(LuaDevice)(1); auto device = LUA_CLASS_GET(LuaDevice)(2);
// the bus is safe against this possibility, but
// I'd rather be doubly-safe tbh
if(!device)
LUA->ThrowError("Null device pointer");
// 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)));

View File

@ -1,42 +1,23 @@
#include "LuaDevice.hpp" #include "LuaDevice.hpp"
#include "LuaHelpers.hpp"
LUA_CLASS_BIND_VARIABLES_IMPLEMENT(LuaDevice); LUA_CLASS_BIND_VARIABLES_IMPLEMENT(LuaDevice);
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaDevice, SetBase) {
auto self = LUA_CLASS_GET(LuaDevice)(1);
if(self->bus)
LUA->ThrowError("Do not call this on an attached device");
self->base = static_cast<u32>(LUA->CheckNumber(2));
return 0;
}
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaDevice, SetSize) {
auto self = LUA_CLASS_GET(LuaDevice)(1);
if(self->bus)
LUA->ThrowError("Do not call this on an attached device");
self->size = static_cast<u32>(LUA->CheckNumber(2));
return 0;
}
bool LuaDevice::Clocked() const { bool LuaDevice::Clocked() const {
// Even if Lua devices may not have a clock handler // no real good rationale for checking here,
// installed there's no real non-awful way to check, // since function calling does bail out properly
// so just lie and say yes always.
return true; return true;
} }
void LuaDevice::Clock() { void LuaDevice::Clock() {
LuaState->PushUserType(this, __lua_typeid); LuaState->ReferencePush(tableReference);
LuaState->GetField(-2, "Clock"); LuaState->GetField(-1,"Clock");
if(!LuaState->IsType(-1, GarrysMod::Lua::Type::Function)) { if(LuaState->GetType(-1) == GarrysMod::Lua::Type::Function) {
LuaState->Pop(2); LuaState->Push(-2); // 'self' argument
return;
}
LuaState->Push(-2); // "self"
LuaState->Call(1, 0); LuaState->Call(1, 0);
LuaState->Pop(); } else {
LuaState->Pop(); // pop the Clock function off the stack
}
LuaState->Pop(); // pop the reference
} }
riscv::Address LuaDevice::Base() const { riscv::Address LuaDevice::Base() const {
@ -48,60 +29,144 @@ riscv::Address LuaDevice::Size() const {
} }
u32 LuaDevice::Peek(riscv::Address address) { u32 LuaDevice::Peek(riscv::Address address) {
LuaState->PushUserType(this, __lua_typeid); /*if(peekHandlerReference != -1) {
LuaState->GetField(-2, "Peek"); LuaState->ReferencePush(resetHandlerReference);
if(!LuaState->IsType(-1, GarrysMod::Lua::Type::Function)) { LuaState->PushNumber(static_cast<double>(address));
LuaState->Pop(2); LuaState->Call(1, 1);
return -1;
}
LuaState->Push(-2); // "self"
LuaState->PushNumber(address);
LuaState->Call(2, 1);
auto result = LuaState->GetNumber(-1); auto result = LuaState->GetNumber(-1);
LuaState->Pop(); LuaState->Pop();
return static_cast<u32>(result); return static_cast<u32>(result);
}*/
LuaState->ReferencePush(tableReference);
LuaState->GetField(-1,"Peek");
if(LuaState->GetType(-1) == GarrysMod::Lua::Type::Function) {
LuaState->Push(-2); // 'self' argument
LuaState->PushNumber(static_cast<double>(address));
LuaState->Call(2, 1);
auto result = static_cast<u32>(LuaState->GetNumber(-1));
LuaState->Pop(2); // pop result and the table off
return result;
} else {
LuaState->Pop(); // pop whatever Peek is off the stack
}
LuaState->Pop(); // pop the table reference
return 0xffffffff;
} }
void LuaDevice::Poke(riscv::Address address, u32 value) { void LuaDevice::Poke(riscv::Address address, u32 value) {
LuaState->PushUserType(this, __lua_typeid); /*if(pokeHandlerReference != -1) {
LuaState->GetField(-2, "Poke"); LuaState->ReferencePush(pokeHandlerReference);
if(!LuaState->IsType(-1, GarrysMod::Lua::Type::Function)) {
LuaState->Pop(2);
return;
}
LuaState->Push(-2); // "self"
LuaState->PushNumber(address); LuaState->PushNumber(address);
LuaState->PushNumber(value); LuaState->PushNumber(value);
LuaState->Call(2, 0);
}*/
LuaState->ReferencePush(tableReference);
LuaState->GetField(-1,"Poke");
if(LuaState->GetType(-1) == GarrysMod::Lua::Type::Function) {
LuaState->Push(-2); // 'self' argument
LuaState->PushNumber(static_cast<double>(address));
LuaState->PushNumber(static_cast<double>(value));
LuaState->Call(3, 0); LuaState->Call(3, 0);
LuaState->Pop(); } else {
LuaState->Pop(); // pop whatever Peek is
}
LuaState->Pop(); // pop the table reference
} }
void LuaDevice::Reset() { void LuaDevice::Reset() {
LuaState->PushUserType(this, __lua_typeid); /*if(resetHandlerReference != -1) {
LuaState->GetField(-2, "Reset"); LuaState->ReferencePush(resetHandlerReference);
if(!LuaState->IsType(-1, GarrysMod::Lua::Type::Function)) LuaState->Call(0, 0);
return; }*/
LuaState->Push(-2); // "self" LuaState->ReferencePush(tableReference);
LuaState->GetField(-1,"Reset");
if(LuaState->GetType(-1) == GarrysMod::Lua::Type::Function) {
LuaState->Push(-2); // 'self' argument
LuaState->Call(1, 0); LuaState->Call(1, 0);
LuaState->Pop(); } else {
LuaState->Pop(); // pop whatever reset is
}
LuaState->Pop(); // pop the reference
} }
LuaDevice::~LuaDevice() = default; LuaDevice::LuaDevice(riscv::Address base, riscv::Address size) : base(base), size(size) {
}
LuaDevice::~LuaDevice() {
// Free all refererences
if(tableReference == -1)
LuaState->ReferenceFree(tableReference);
}
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaDevice, __index) {
auto self = LUA_CLASS_GET(LuaDevice)(1);
//lucore::LogInfo("metamethod __index call");
// TODO: before moving this to a shared lua object class thing
// and moving the CPU class to use this way of doing things
// I should probably try and like, add stuff to ensure native
// methods can be registered as well,,
LUA->ReferencePush(self->tableReference);
LUA->Push(2);
LUA->GetTable(-2);
return 1; // the value
}
LUA_MEMBER_FUNCTION_IMPLEMENT(LuaDevice, __newindex) {
auto self = LUA_CLASS_GET(LuaDevice)(1);
//lucore::LogInfo("metamethod __newindex call");
// Always push onto the table.
// TODO: This function
// should error on attempt to __newindex any native methods
// (when moved to a shared place)
LUA->ReferencePush(self->tableReference);
LUA->Push(2);
LUA->Push(3);
LUA->SetTable(-3);
LUA->Pop();
return 0;
}
void LuaDevice::Bind(GarrysMod::Lua::ILuaBase* LUA) { void LuaDevice::Bind(GarrysMod::Lua::ILuaBase* LUA) {
// clang-format off // clang-format off
// TODO: I need to figure out how to like, set up metamethod stuff //LUA_CLASS_BIND_BEGIN(LuaDevice)
// so it all properly works. __lua_typeid = LUA->CreateMetaTable("LuaDevice");
LUA_CLASS_BIND_BEGIN(LuaDevice); LUA->PushSpecial(GarrysMod::Lua::SPECIAL_REG);
LUA_SET_C_FUNCTION(SetBase) LUA->PushNumber(__lua_typeid);
LUA_SET_C_FUNCTION(SetSize) LUA->SetField(-2, "LuaDevice__typeid");
LUA->Pop(); /* pop registry */
LUA_SET_C_FUNCTION(__gc)
LUA_SET_C_FUNCTION(__index)
LUA_SET_C_FUNCTION(__newindex)
LUA_CLASS_BIND_END(); LUA_CLASS_BIND_END();
// clang-format on // clang-format on
} }
void LuaDevice::Create(GarrysMod::Lua::ILuaBase* LUA) { void LuaDevice::Create(GarrysMod::Lua::ILuaBase* LUA, riscv::Address base, riscv::Address size) {
auto device = new LuaDevice(); auto device = new LuaDevice(base, size);
device->LuaState = LUA; device->LuaState = LUA;
LUA->CreateTable();
device->tableReference = LUA->ReferenceCreate();
LUA->Pop();
// push base/size properties for lua to have a looksee at !
// ideally these should be handled as metamethods in __index,
// but i don't quite feel like making gmod sol2 yet /shrug
LUA->ReferencePush(device->tableReference);
LUA->PushNumber(static_cast<double>(base));
LUA->SetField(-2, "Base");
LUA->PushNumber(static_cast<double>(base));
LUA->SetField(-2, "Size");
LUA->Pop();
LUA->PushUserType(device, __lua_typeid); LUA->PushUserType(device, __lua_typeid);
} }

View File

@ -8,7 +8,7 @@
struct LuaDevice : public riscv::Bus::MmioDevice { struct LuaDevice : public riscv::Bus::MmioDevice {
/// Lua binding stuff /// Lua binding stuff
static void Bind(GarrysMod::Lua::ILuaBase* LUA); static void Bind(GarrysMod::Lua::ILuaBase* LUA);
static void Create(GarrysMod::Lua::ILuaBase* LUA); static void Create(GarrysMod::Lua::ILuaBase* LUA, riscv::Address base, riscv::Address size);
~LuaDevice(); ~LuaDevice();
@ -26,14 +26,15 @@ struct LuaDevice : public riscv::Bus::MmioDevice {
// class binding stuff // class binding stuff
LUA_CLASS_BIND_VARIABLES(private); LUA_CLASS_BIND_VARIABLES(private);
// Do not call these once attached to a bus. LUA_MEMBER_FUNCTION(__index);
LUA_MEMBER_FUNCTION(SetBase); LUA_MEMBER_FUNCTION(__newindex);
LUA_MEMBER_FUNCTION(SetSize);
// GetBase/GetSize? LuaDevice(riscv::Address base, riscv::Address size);
riscv::Address base {}; riscv::Address base {};
riscv::Address size {}; riscv::Address size {};
GarrysMod::Lua::ILuaBase* LuaState; GarrysMod::Lua::ILuaBase* LuaState;
// this should be a common type tbh
int tableReference = -1;
}; };

View File

@ -43,12 +43,13 @@
LUA->CheckType(1, T::__lua_typeid); \ LUA->CheckType(1, T::__lua_typeid); \
auto self = LUA->GetUserType<T>(1, T::__lua_typeid); \ auto self = LUA->GetUserType<T>(1, T::__lua_typeid); \
if(self != nullptr) { /* GetUserType returns nullptr on failure */ \ if(self != nullptr) { /* GetUserType returns nullptr on failure */ \
lucore::LogInfo("GCing {} object", #T); \ lucore::LogInfo("GCing {} object @ {:p}", #T, static_cast<void*>(self)); \
delete self; \ delete self; \
} \ } \
return 0; \ return 0; \
} }
// Begin the Bind() method of a class. This just sets up boilerplate // Begin the Bind() method of a class. This just sets up boilerplate
// and required things to setup a class. // and required things to setup a class.
#define LUA_CLASS_BIND_BEGIN(T) \ #define LUA_CLASS_BIND_BEGIN(T) \
@ -73,3 +74,14 @@
#define LUA_SET_C_FUNCTION_NAME(name, altName) \ #define LUA_SET_C_FUNCTION_NAME(name, altName) \
LUA->PushCFunction(name); \ LUA->PushCFunction(name); \
LUA->SetField(-2, altName); LUA->SetField(-2, altName);
inline std::string GetLuaString(GarrysMod::Lua::ILuaBase* LUA, int stackPos) {
unsigned len{};
auto ptr = LUA->GetString(stackPos, &len);
if(ptr) {
return std::string(ptr, len);
} else {
return {};
}
}

View File

@ -1,38 +0,0 @@
#include "LuaShared.hpp"
#include <lucore/Assert.hpp>
#include <lucore/Library.hpp>
namespace lcpu::lua {
// A global pointer to the loaded instance of the lua_shared library.
lucore::Library* luaSharedLibrary = nullptr;
#define LUA_SHARED_FUNC(Retty, name, ...) Retty (*name)(__VA_ARGS__) = nullptr;
#include "LuaSharedFunctions.inc"
#undef LUA_SHARED_FUNC
void LoadLuaShared() {
// Open the lua_shared library
luaSharedLibrary = lucore::Library::OpenExisting("lua_shared");
LUCORE_CHECK(luaSharedLibrary != nullptr, "Could not open lua_shared library for some reason.");
// Load the functions from lua_shared
// This is helped quite a bit by using an x-macro
#define LUA_SHARED_FUNC(Retty, name, ...) \
name = luaSharedLibrary->Symbol<decltype(name)>(#name); \
LUCORE_CHECK(name != nullptr, "Could not load lua_shared function \"{}\"", #name);
#include "LuaSharedFunctions.inc"
#undef LUA_SHARED_FUNC
}
void UnloadLuaShared() {
LUCORE_ASSERT(luaSharedLibrary != nullptr, "UnloadLuaShared() should only be called if LoadLuaShared() was called");
delete luaSharedLibrary;
#define LUA_SHARED_FUNC(Retty, name, ...) name = nullptr;
#include "LuaSharedFunctions.inc"
#undef LUA_SHARED_FUNC
}
} // namespace lcpu::lua

View File

@ -1,56 +0,0 @@
//! Loader/types for lua_shared API. I plan to use this instead of the Garry's Mod
//! ILuaBase interface; they are interchangable (and in fact, less friction to use!)
#pragma once
#include <GarrysMod/Lua/Interface.h>
namespace lcpu::lua {
#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */
struct lua_Debug {
int event;
const char* name; /* (n) */
const char* namewhat; /* (n) `global', `local', `field', `method' */
const char* what; /* (S) `Lua', `C', `main', `tail' */
const char* source; /* (S) */
int currentline; /* (l) */
int nups; /* (u) number of upvalues */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
int i_ci; /* active function */
};
typedef int (*lua_CFunction)(lua_State* L);
typedef void* (*lua_Alloc)(void* ud, void* ptr, size_t osize, size_t nsize);
typedef const char* (*lua_Reader)(lua_State* L, void* ud, size_t* sz);
typedef int (*lua_Writer)(lua_State* L, const void* p, size_t sz, void* ud);
//typedef struct lua_Debug lua_Debug; /* activation record */
typedef void (*lua_Hook)(lua_State* L, lua_Debug* ar);
typedef struct luaL_Buffer {
char* p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State* L;
char buffer[8192];
} luaL_Buffer;
typedef struct luaL_Reg {
const char* name;
lua_CFunction func;
} luaL_Reg;
#define LUA_SHARED_FUNC(Retty, name, ...) extern Retty (*name)(__VA_ARGS__);
#include "LuaSharedFunctions.inc"
#undef LUA_SHARED_FUNC
/// Load lua_shared
void LoadLuaShared();
/// .. and unload it.
void UnloadLuaShared();
} // namespace lcpu::lua

View File

@ -1,128 +0,0 @@
//! This is an X-Macro file of all the interesting functions in lua_shared
LUA_SHARED_FUNC(lua_State*, luaL_newstate, void);
LUA_SHARED_FUNC(int, luaL_loadstring, lua_State *L, const char* code);
LUA_SHARED_FUNC(lua_CFunction, lua_atpanic, lua_State *L, lua_CFunction panicf);
LUA_SHARED_FUNC(void, lua_call, lua_State *L, int nargs, int nresults);
LUA_SHARED_FUNC(int, lua_checkstack, lua_State *L, int size);
LUA_SHARED_FUNC(void, lua_close, lua_State *L);
LUA_SHARED_FUNC(void, lua_concat, lua_State*L,int n);
LUA_SHARED_FUNC(int, lua_cpcall, lua_State *L, lua_CFunction func, void *ud);
LUA_SHARED_FUNC(void, lua_createtable, lua_State *L, int narray, int nrec);
LUA_SHARED_FUNC(int, lua_dump, lua_State *L, lua_Writer writer, void *data);
LUA_SHARED_FUNC(int, lua_equal, lua_State *L, int idx1, int idx2);
LUA_SHARED_FUNC(int, lua_error, lua_State *L);
LUA_SHARED_FUNC(int, lua_gc, lua_State *L, int what, int data);
LUA_SHARED_FUNC(lua_Alloc, lua_getallocf, lua_State *L, void **ud);
LUA_SHARED_FUNC(void, lua_getfenv, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_getfield, lua_State *L, int idx, const char *k);
LUA_SHARED_FUNC(lua_Hook, lua_gethook, lua_State *L);
LUA_SHARED_FUNC(int, lua_gethookcount, lua_State *L);
LUA_SHARED_FUNC(int, lua_gethookmask, lua_State *L);
LUA_SHARED_FUNC(int, lua_getinfo, lua_State *L, const char *what, lua_Debug *ar);
LUA_SHARED_FUNC(const char*, lua_getlocal, lua_State *L, const lua_Debug *ar, int n);
LUA_SHARED_FUNC(int, lua_getmetatable, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_getstack, lua_State *L, int level, lua_Debug *ar);
LUA_SHARED_FUNC(void, lua_gettable, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_gettop, lua_State *L);
LUA_SHARED_FUNC(const char*, lua_getupvalue, lua_State *L, int idx, int n);
LUA_SHARED_FUNC(void, lua_insert, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_iscfunction, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_isnumber, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_isstring, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_isuserdata, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_lessthan, lua_State *L, int idx1, int idx2);
LUA_SHARED_FUNC(int, lua_load, lua_State *L, lua_Reader reader, void *dt, const char *chunkname);
LUA_SHARED_FUNC(int, lua_loadx, lua_State *L, lua_Reader reader, void *dt, const char *chunkname, const char *mode);
LUA_SHARED_FUNC(lua_State*, lua_newstate, lua_Alloc f, void *ud);
LUA_SHARED_FUNC(lua_State*, lua_newthread, lua_State *L);
LUA_SHARED_FUNC(void*, lua_newuserdata, lua_State *L, size_t size);
LUA_SHARED_FUNC(int, lua_next, lua_State *L, int idx);
LUA_SHARED_FUNC(size_t, lua_objlen, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_pcall, lua_State *L, int nargs, int nresults, int errfunc);
LUA_SHARED_FUNC(void, lua_pushboolean, lua_State *L, int b);
LUA_SHARED_FUNC(void, lua_pushcclosure, lua_State *L, lua_CFunction f, int n);
LUA_SHARED_FUNC(const char*, lua_pushfstring, lua_State *L, const char *fmt, ...);
LUA_SHARED_FUNC(void, lua_pushlightuserdata, lua_State *L, void *p);
LUA_SHARED_FUNC(void, lua_pushlstring, lua_State *L, const char *str, size_t len);
LUA_SHARED_FUNC(void, lua_pushnil, lua_State *L);
LUA_SHARED_FUNC(void, lua_pushnumber, lua_State *L, double n);
LUA_SHARED_FUNC(void, lua_pushstring, lua_State *L, const char *str);
LUA_SHARED_FUNC(int, lua_pushthread, lua_State *L);
LUA_SHARED_FUNC(void, lua_pushvalue, lua_State *L, int idx);
LUA_SHARED_FUNC(const char*, lua_pushvfstring, lua_State *L, const char *fmt, char* argp);
LUA_SHARED_FUNC(int, lua_rawequal, lua_State *L, int idx1, int idx2);
LUA_SHARED_FUNC(void, lua_rawget, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_rawgeti, lua_State *L, int idx, int n);
LUA_SHARED_FUNC(void, lua_rawset, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_rawseti, lua_State *L, int idx, int n);
LUA_SHARED_FUNC(void, lua_remove, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_replace, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_setallocf, lua_State *L, lua_Alloc f, void *ud);
LUA_SHARED_FUNC(int, lua_setfenv, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_setfield, lua_State *L, int idx, const char *k);
LUA_SHARED_FUNC(int, lua_sethook, lua_State *L, lua_Hook func, int mask, int count);
LUA_SHARED_FUNC(const char *, lua_setlocal, lua_State *L, const lua_Debug *ar, int n);
LUA_SHARED_FUNC(int, lua_setmetatable, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_settable, lua_State *L, int idx);
LUA_SHARED_FUNC(void, lua_settop, lua_State *L, int idx);
LUA_SHARED_FUNC(const char*, lua_setupvalue, lua_State *L, int idx, int n);
LUA_SHARED_FUNC(int, lua_status, lua_State *L);
LUA_SHARED_FUNC(int, lua_toboolean, lua_State *L, int idx);
LUA_SHARED_FUNC(lua_CFunction, lua_tocfunction, lua_State *L, int idx);
LUA_SHARED_FUNC(const char*, lua_tolstring, lua_State *L, int idx, size_t *len);
LUA_SHARED_FUNC(double, lua_tonumber, lua_State *L, int idx);
LUA_SHARED_FUNC(const void*, lua_topointer, lua_State *L, int idx);
LUA_SHARED_FUNC(lua_State*, lua_tothread, lua_State *L, int idx);
LUA_SHARED_FUNC(void*, lua_touserdata, lua_State *L, int idx);
LUA_SHARED_FUNC(int, lua_type, lua_State *L, int idx);
LUA_SHARED_FUNC(const char*, lua_typename, lua_State *L, int t);
LUA_SHARED_FUNC(void*, lua_upvalueid, lua_State *L, int idx, int n);
LUA_SHARED_FUNC(void, lua_upvaluejoin, lua_State *L, int idx1, int n1, int idx2, int n2);
LUA_SHARED_FUNC(void, lua_xmove, lua_State *from, lua_State *to, int n);
LUA_SHARED_FUNC(int, lua_yield, lua_State *L, int nresults);
LUA_SHARED_FUNC(int, luaJIT_setmode, lua_State *L, int idx, int mode);
LUA_SHARED_FUNC(void, luaL_addlstring, luaL_Buffer *B, const char *s, size_t l);
LUA_SHARED_FUNC(void, luaL_addstring, luaL_Buffer *B, const char *s);
LUA_SHARED_FUNC(void, luaL_addvalue, luaL_Buffer *B);
LUA_SHARED_FUNC(int, luaL_argerror, lua_State *L, int narg, const char *msg);
LUA_SHARED_FUNC(void, luaL_buffinit, lua_State *L, luaL_Buffer *B);
LUA_SHARED_FUNC(int, luaL_callmeta, lua_State *L, int idx, const char *field);
LUA_SHARED_FUNC(void, luaL_checkany, lua_State *L, int idx);
LUA_SHARED_FUNC(const char*, luaL_checklstring, lua_State *L, int idx, size_t *len);
LUA_SHARED_FUNC(double, luaL_checknumber, lua_State *L, int idx);
LUA_SHARED_FUNC(int, luaL_checkoption, lua_State *L, int idx, const char *def, const char *const lst[]);
LUA_SHARED_FUNC(void, luaL_checkstack, lua_State *L, int size, const char *msg);
LUA_SHARED_FUNC(void, luaL_checktype, lua_State *L, int idx, int tt);
LUA_SHARED_FUNC(void*, luaL_checkudata, lua_State *L, int idx, const char *tname);
LUA_SHARED_FUNC(int, luaL_error, lua_State *L, const char *fmt, ...);
LUA_SHARED_FUNC(int, luaL_execresult, lua_State *L, int stat);
LUA_SHARED_FUNC(int, luaL_fileresult, lua_State *L, int stat, const char *fname);
LUA_SHARED_FUNC(const char*, luaL_findtable, lua_State *L, int idx, const char *fname, int szhint);
LUA_SHARED_FUNC(int, luaL_getmetafield, lua_State *L, int idx, const char *field);
LUA_SHARED_FUNC(const char*, luaL_gsub, lua_State *L, const char *s, const char *p, const char *r);
LUA_SHARED_FUNC(int, luaL_loadbuffer, lua_State *L, const char *buff, size_t sz, const char *name);
LUA_SHARED_FUNC(int, luaL_loadbufferx, lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
LUA_SHARED_FUNC(int, luaL_loadfile, lua_State *L, const char *filename);
LUA_SHARED_FUNC(int, luaL_loadfilex, lua_State *L, const char *filename, const char *mode);
LUA_SHARED_FUNC(int, luaL_newmetatable, lua_State *L, const char *tname);
LUA_SHARED_FUNC(void, luaL_openlib, lua_State *L, const char *libname, const luaL_Reg *l, int nup);
LUA_SHARED_FUNC(int, luaL_openlibs, lua_State *L);
LUA_SHARED_FUNC(const char*, luaL_optlstring, lua_State *L, int idx, const char *def, size_t *len);
LUA_SHARED_FUNC(double, luaL_optnumber, lua_State *L, int idx, double def);
LUA_SHARED_FUNC(char*, luaL_prepbuffer, luaL_Buffer *B);
LUA_SHARED_FUNC(void, luaL_pushresult, luaL_Buffer *B);
LUA_SHARED_FUNC(int, luaL_ref, lua_State *L, int t);
LUA_SHARED_FUNC(void, luaL_register, lua_State *L, const char *libname, const luaL_Reg *l);
LUA_SHARED_FUNC(void, luaL_traceback, lua_State *L, lua_State *L1, const char *msg, int level);
LUA_SHARED_FUNC(int, luaL_typerror, lua_State *L, int narg, const char *tname);
LUA_SHARED_FUNC(void, luaL_unref, lua_State *L, int t, int ref);
LUA_SHARED_FUNC(void, luaL_where, lua_State *L, int lvl);
LUA_SHARED_FUNC(int, luaopen_base, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_bit, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_debug, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_jit, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_math, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_os, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_package, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_string, lua_State *L);
LUA_SHARED_FUNC(int, luaopen_table, lua_State *L);

View File

@ -6,19 +6,15 @@
#include "LcpuGlobals.hpp" #include "LcpuGlobals.hpp"
#include "LuaShared.hpp"
GMOD_MODULE_OPEN() { GMOD_MODULE_OPEN() {
// Initialize our lua_shared binding. It is important we ca
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);
lcpu::lua::LoadLuaShared();
GlobalsBind(LUA); GlobalsBind(LUA);
return 0; return 0;
} }
GMOD_MODULE_CLOSE() { GMOD_MODULE_CLOSE() {
lcpu::lua::UnloadLuaShared();
return 0; return 0;
} }

View File

@ -105,14 +105,10 @@ namespace riscv {
virtual void Poke(Address address, u32 value) = 0; virtual void Poke(Address address, u32 value) = 0;
}; };
/// Bus destructor.
/// This frees the memory for all devices.
~Bus();
/// Attach a device to the bus. /// Attach a device to the bus.
/// ///
/// Note that once this function is called (and the device is successfully added), /// Note that once this function is called (and the device is successfully added),
/// the object pointed to by [device] is owned by the Bus object, and should not be deleted. /// the object pointed to by [device] should last at least as long as the bus.
/// ///
/// # Returns /// # Returns
/// This function returns true if the device was able to be put on the bus. /// This function returns true if the device was able to be put on the bus.

View File

@ -4,12 +4,6 @@
namespace riscv { namespace riscv {
Bus::~Bus() {
// Free all devices
for(auto device : devices)
delete device;
}
bool Bus::AttachDevice(Device* device) { bool Bus::AttachDevice(Device* device) {
if(!device) if(!device)
return false; return false;

View File

@ -30,7 +30,13 @@ namespace riscv {
System::~System() { System::~System() {
delete cpu; delete cpu;
delete bus; // the rest of the device pointers will be deleted by the bus. delete bus;
// delete our devices
// externally bound devices should clean themselves up
delete clnt;
delete syscon;
delete ram;
} }
void System::Step() { void System::Step() {

View File

@ -1,7 +1,7 @@
// a simple test program - this version would talk to a device // a simple test program - this version would talk to a device
// written in GLua // written in GLua
#include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h>
uint32_t strlen(const char* str) { uint32_t strlen(const char* str) {
if(!str) if(!str)
@ -12,7 +12,9 @@ uint32_t strlen(const char* str) {
return c - str; return c - str;
} }
#define GLUA_DEVICE *(volatile uint32_t*)0x12000000 #define GLUA_DEVICE_BASE 0x11300000 // base address of the lua test device
#define GLUA_DEVICE_WORLDTIME *(volatile uint32_t*)GLUA_DEVICE_BASE // world time register (read only)
#define GLUA_DEVICE_LUAREG *(volatile uint32_t*)(GLUA_DEVICE_BASE + 4) // lua register (read/write)
#define SYSCON *(volatile uint32_t*)0x11100000 #define SYSCON *(volatile uint32_t*)0x11100000
@ -70,9 +72,9 @@ void vprintf(const char* format, va_list val) {
for(int i = 0; i < fl; ++i) { for(int i = 0; i < fl; ++i) {
switch(format[i]) { switch(format[i]) {
case '%': case '%':
if(format[i+1] == '%') if(format[i + 1] == '%')
putc('%'); putc('%');
switch(format[i+1]) { switch(format[i + 1]) {
case 'i': case 'i':
case 'd': { case 'd': {
char a[32]; char a[32];
@ -81,6 +83,7 @@ void vprintf(const char* format, va_list val) {
const int al = strlen(a); const int al = strlen(a);
for(int j = 0; j < al; ++j) for(int j = 0; j < al; ++j)
putc(a[j]); putc(a[j]);
i++;
} break; } break;
case 's': { case 's': {
@ -89,16 +92,13 @@ void vprintf(const char* format, va_list val) {
puts("(null)"); puts("(null)");
else else
puts(p); puts(p);
i++;
}; };
default: default: putc(' '); break;
putc(' ');
break;
} }
break; break;
default: default: putc(format[i]); break;
putc(format[i]);
break;
} }
} }
} }
@ -110,13 +110,17 @@ void printf(const char* format, ...) {
va_end(val); va_end(val);
} }
void main() { void main() {
puts("fuck you garry I win"); puts("fuck you garry I win");
for(int i = 0; i < 256; ++i) for(int i = 0; i < 8; ++i)
printf("uhh %d\n", GLUA_DEVICE); printf("GLUA_DEVICE_WORLDTIME reading says -> %d\n", GLUA_DEVICE_WORLDTIME);
// try writing to it
GLUA_DEVICE_LUAREG = 0x1234;
for(int i = 0; i < 8; ++i)
printf("GLUA_DEVICE_LUAREG reading says -> %d\n", GLUA_DEVICE_LUAREG);
SYSCON = 0x5555; SYSCON = 0x5555;
} }