lcpu/lua: Move Lua device implementations into seperate "LCPU.Devices" namespace
This commit is contained in:
parent
8eb4b6ef41
commit
d3cee95b14
|
@ -3,5 +3,8 @@ build/
|
||||||
module_build/
|
module_build/
|
||||||
native/projects/riscv/ref
|
native/projects/riscv/ref
|
||||||
|
|
||||||
|
# for now
|
||||||
|
native/projects/projgen
|
||||||
|
|
||||||
.cache/
|
.cache/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
56
ideas.md
56
ideas.md
|
@ -22,50 +22,56 @@ This is basically the working ideas for the LCPU project.
|
||||||
- Write assembly/C/C++ code using a tiny project system (source for them would go in server data folder ?)
|
- Write assembly/C/C++ code using a tiny project system (source for them would go in server data folder ?)
|
||||||
- At the root of a project, a `project.json` file is expected to exist, with contents like:
|
- At the root of a project, a `project.json` file is expected to exist, with contents like:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"project": {
|
"Project": {
|
||||||
// All configurations for a project.
|
"Name": "test",
|
||||||
"configurations": {
|
|
||||||
"debug": {
|
|
||||||
"CCompileFlags": "-O0 -g ${BaseCCompileFlags}",
|
|
||||||
"CppCompileFlags": "-O0 -g ${BaseCppCompileFlags}",
|
|
||||||
"LinkerScript": "binary.ld",
|
|
||||||
},
|
|
||||||
"release": {
|
|
||||||
"CCompileFlags": "-O2 ${BaseCCompileFlags}",
|
|
||||||
"CppCompileFlags": "-O2 ${BaseCppCompileFlags}",
|
|
||||||
"LinkerScript": "binary.ld",
|
|
||||||
"LinkerFlags": "-Wl,--gc-sections"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Obviously you can use separate subdirectories;
|
// Define all build configurations here
|
||||||
// this is just a very very simple baremetal program.
|
"Configurations": {
|
||||||
"Sources": [
|
"Debug": {
|
||||||
"startup.S",
|
"CCompileFlags": "-O0 ${BaseCCompileFlags}",
|
||||||
"main.cpp"
|
"CppCompileFlags": "-O0 ${BaseCppCompileFlags}"
|
||||||
]
|
},
|
||||||
}
|
"Release": {
|
||||||
|
"CCompileFlags": "-O2 ${BaseCCompileFlags}",
|
||||||
|
"CppCompileFlags": "-O2 ${BaseCppCompileFlags}",
|
||||||
|
// If a variable is unset it will usually default to
|
||||||
|
// ${Base${VariableName}}
|
||||||
|
"LinkerFlags": "-Wl,--gc-sections ${BaseLinkerFlags}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"Sources": [
|
||||||
|
"binary.ld",
|
||||||
|
"start.S",
|
||||||
|
"main.c"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `BaseCCompileFlags` and `BaseCppCompileFlags` are defaulted to sane values for each language.
|
- `BaseCCompileFlags` and `BaseCppCompileFlags` are defaulted to sane values for each language.
|
||||||
|
|
||||||
- This will be transpiled into a `Makefile` by the addon.
|
- This will be transpiled into a `Makefile` by the addon.
|
||||||
- A standalone tool will be provided and used for transpiling `project.json` to a `Makefile` (and maybe even passed into the container and transpiled there, to reduce the actions on the host to just the podman run?)
|
- A standalone tool will be provided and used for transpiling `project.json` to a `Makefile` (and maybe even passed into the container and transpiled there, to reduce the actions on the host to just the podman run?)
|
||||||
- which is then run with `make` in a temporary podman container which only has access to the source code for the project (and nothing else, besides riscv tools).
|
- which, when a Build is done in GMod; is then run with `make` in a temporary podman container which only has access to the source code for the project (and nothing else, besides riscv tools).
|
||||||
- Command line is probably something like `make CONFIG=${config}`
|
- Command line is probably something like `make CONFIG=${config}`
|
||||||
- the output binary will be stored alongside the source code on the server side, with a name like `${name}-${config}.bin`
|
- the output binary will be stored alongside the source code on the server side, with a name like `${name}-${config}.bin`
|
||||||
- This file can then be selected for loading (without uploading from the client).
|
- This file can then be selected for loading (without needing to be uploaded from the client).
|
||||||
|
|
||||||
|
|
||||||
- There is no conditional compilation in the `project.json` system
|
- There is no conditional compilation in the `project.json` system
|
||||||
- All files in a project are always built by that project.
|
- All files in a project are always built by that project.
|
||||||
|
|
||||||
|
- No notion of subprojects/build dependencies other than GCC generated dependencies
|
||||||
|
- This is meant to be simple for easy development in GMod. If you want complex build features you can export the project onto your own computer and use `lcpu_projgen` to generate Makefiles (which you can then maintain)
|
||||||
|
|
||||||
- Text editor used to edit project source files
|
- Text editor used to edit project source files
|
||||||
- Use the Wire editor? (we need wiremod anyways, and the text editor is.. OK I suppose.)
|
- Use the Wire editor? (we need wiremod anyways, and the text editor is.. OK I suppose.)
|
||||||
|
- Or I guess I could try getting Monaco to play nicely with DHTML
|
||||||
|
|
||||||
- Some example projects?
|
- Some example projects?
|
||||||
|
- A simple bare metal "Hello World"
|
||||||
- I joke about it, but an RTOS would be really nice and a good stress test of the project system (for usage in "real" projects.)
|
- I joke about it, but an RTOS would be really nice and a good stress test of the project system (for usage in "real" projects.)
|
||||||
|
|
||||||
## Moderation/administration tools
|
## Moderation/administration tools
|
||||||
|
|
|
@ -9,7 +9,14 @@ if SERVER then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
LCPU = {};
|
||||||
|
LCPU.Devices = {};
|
||||||
|
|
||||||
--LCPUNative.EnableDebug()
|
--LCPUNative.EnableDebug()
|
||||||
|
|
||||||
AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
|
AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
|
||||||
|
|
||||||
|
-- Serverside devices
|
||||||
|
include("lcpu/devices/uart.lua")
|
||||||
|
include("lcpu/devices/gmlua_test.lua")
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,69 +12,16 @@ 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)
|
||||||
|
|
||||||
|
-- CPU callbacks?
|
||||||
self.cpu = LCPUNative.CreateCPU(128 * 1024)
|
self.cpu = LCPUNative.CreateCPU(128 * 1024)
|
||||||
|
|
||||||
-- UART
|
-- UART & GLua test device
|
||||||
self.uart = LCPUNative.CreateDevice(0x10000000, 0xc)
|
self.uart = LCPU.Devices.UART(0x10000000)
|
||||||
self.uart.buffer = ""
|
self.test_device = LCPU.Devices.LuaTest()
|
||||||
|
|
||||||
function self.uart:Peek(address)
|
self.cpu:AttachDevice(self.uart)
|
||||||
if address == self.Base then return 0 end
|
self.cpu:AttachDevice(self.test_device)
|
||||||
if address == self.Base + 5 then return 0x60 end --
|
|
||||||
return 0xffffffff
|
|
||||||
end
|
|
||||||
|
|
||||||
function self.uart:Poke(address, value)
|
|
||||||
if address == self.Base then
|
|
||||||
local c = bit.band(value, 0x000000ff)
|
|
||||||
if c == 0 then return end
|
|
||||||
|
|
||||||
-- Newline, reset the buffer
|
|
||||||
if c == 0xa then
|
|
||||||
print(self.buffer)
|
|
||||||
self:Reset()
|
|
||||||
else
|
|
||||||
-- Not a newline so we can keep going with it
|
|
||||||
self.buffer = self.buffer .. string.char(c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function self.uart:Reset()
|
|
||||||
self.buffer = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
-- todo: cpu callbacks? once they become a thing
|
|
||||||
-- test device framework
|
|
||||||
-- (for once something works out how I wanted it to..)
|
|
||||||
self.test_device = LCPUNative.CreateDevice(0x11300000, 0x8)
|
|
||||||
self.test_device.register = 0x0
|
|
||||||
|
|
||||||
function self.test_device:Peek(address)
|
|
||||||
--print(string.format("TestDevice:Peek @ 0x%08x", address))
|
|
||||||
if address == self.Base then return CurTime() end -- it a test!
|
|
||||||
if address == self.Base + 4 then return self.register end
|
|
||||||
|
|
||||||
return 0xffffffff
|
|
||||||
end
|
|
||||||
|
|
||||||
function self.test_device:Poke(address, value)
|
|
||||||
--print(string.format("TestDevice:Poke @ 0x%08x -> 0x%08x", address, value))
|
|
||||||
if address == self.Base + 4 then
|
|
||||||
--print("LUAREG write")
|
|
||||||
self.register = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function self.test_device:Reset()
|
|
||||||
--print("TestDevice:Reset")
|
|
||||||
-- clear the register
|
|
||||||
self.register = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
self.cpu:AttachDevice(self.uart);
|
|
||||||
self.cpu:AttachDevice(self.test_device);
|
|
||||||
|
|
||||||
self:SetOverlayText("hi :)")
|
self:SetOverlayText("hi :)")
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
-- Lua test device. This'll probably get removed soon, this is just for testing
|
||||||
|
-- that Lua->C++ interop actually works like it should
|
||||||
|
|
||||||
|
function LCPU.Devices.LuaTest()
|
||||||
|
local test_device = LCPUNative.CreateDevice(0x11300000, 0x8)
|
||||||
|
test_device.register = 0x0
|
||||||
|
|
||||||
|
function test_device:Peek(address)
|
||||||
|
--print(string.format("TestDevice:Peek @ 0x%08x", address))
|
||||||
|
if address == self.Base then return CurTime() end -- it a test!
|
||||||
|
if address == self.Base + 4 then return self.register end
|
||||||
|
|
||||||
|
return 0xffffffff
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_device:Poke(address, value)
|
||||||
|
--print(string.format("TestDevice:Poke @ 0x%08x -> 0x%08x", address, value))
|
||||||
|
if address == self.Base + 4 then
|
||||||
|
--print("LUAREG write")
|
||||||
|
self.register = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_device:Reset()
|
||||||
|
--print("TestDevice:Reset")
|
||||||
|
-- clear the register
|
||||||
|
self.register = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return test_device
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
-- UART device
|
||||||
|
-- For now, this just prints to the server console.
|
||||||
|
function LCPU.Devices.UART(base)
|
||||||
|
local uart = LCPUNative.CreateDevice(base, 0xc)
|
||||||
|
uart.buffer = ""
|
||||||
|
|
||||||
|
function uart:Peek(address)
|
||||||
|
if address == self.Base then return 0 end
|
||||||
|
if address == self.Base + 5 then return 0x60 end -- Active, but no keyboard input
|
||||||
|
return 0xffffffff
|
||||||
|
end
|
||||||
|
|
||||||
|
function uart:Poke(address, value)
|
||||||
|
if address == self.Base then
|
||||||
|
local c = bit.band(value, 0x000000ff)
|
||||||
|
if c == 0 then return end
|
||||||
|
|
||||||
|
-- On newline or reaching length limit
|
||||||
|
-- print the buffer and then reset it
|
||||||
|
if c == 0xa or #self.buffer >= 256 then
|
||||||
|
print(string.format("UART: %s", self.buffer))
|
||||||
|
self:Reset()
|
||||||
|
else
|
||||||
|
-- Not a newline so we can keep going with it
|
||||||
|
self.buffer = self.buffer .. string.char(c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function uart:Reset()
|
||||||
|
self.buffer = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
return uart
|
||||||
|
end
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"Project": {
|
||||||
|
"Name": "test",
|
||||||
|
|
||||||
|
"Configurations": {
|
||||||
|
"Debug": {
|
||||||
|
"CCompileFlags": "-O0 ${BaseCCompileFlags}",
|
||||||
|
"CppCompileFlags": "-O0 ${BaseCppCompileFlags}"
|
||||||
|
},
|
||||||
|
"Release": {
|
||||||
|
"CCompileFlags": "-O2 ${BaseCCompileFlags}",
|
||||||
|
"CppCompileFlags": "-O2 ${BaseCppCompileFlags}",
|
||||||
|
"LinkerFlags": "-Wl,--gc-sections ${BaseLinkerFlags}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"Sources": [
|
||||||
|
"binary.ld",
|
||||||
|
"start.S",
|
||||||
|
"main.c"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue