lcpu: FINALLY begin implementing the addon!!
This commit is contained in:
parent
887b66bbb0
commit
c69dc8d753
|
@ -1,6 +1,7 @@
|
||||||
AddCSLuaFile()
|
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
|
if SERVER then
|
||||||
require("lcpu_native")
|
require("lcpu_native")
|
||||||
|
|
||||||
|
@ -11,5 +12,4 @@ if SERVER then
|
||||||
end
|
end
|
||||||
|
|
||||||
AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
|
AddCSLuaFile("entities/gmod_lcpu_cpu.lua")
|
||||||
AddCSLuaFile("lcpu/stool_helper.lua")
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,10 +10,13 @@ function ENT:Initialize()
|
||||||
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(64 * 1024)
|
self.cpu = LCPUNative.CreateCPU(128 * 1024)
|
||||||
end
|
end
|
||||||
|
|
||||||
function ENT:Think()
|
function ENT:Think()
|
||||||
|
--
|
||||||
|
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)
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
@ -1,12 +1,12 @@
|
||||||
include(./gmod_headers.cmake)
|
include(./gmod_headers.cmake)
|
||||||
|
|
||||||
|
|
||||||
add_library(lcpu_native SHARED
|
add_library(lcpu_native SHARED
|
||||||
|
src/main.cpp
|
||||||
|
src/LcpuGlobals.cpp
|
||||||
|
src/LuaCpu.cpp
|
||||||
|
#src/LuaDevice.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")
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "LcpuGlobals.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "LuaHelpers.hpp"
|
||||||
|
|
||||||
|
void GlobalsBind(GarrysMod::Lua::ILuaBase* LUA);
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
#include <lucore/Logger.hpp>
|
#include <lucore/Logger.hpp>
|
||||||
|
|
||||||
#include "LuaMember.hpp"
|
#include "LuaDevice.hpp"
|
||||||
|
#include "LuaHelpers.hpp"
|
||||||
|
|
||||||
// this is temporary from the thing
|
// this is temporary from the thing
|
||||||
|
|
||||||
|
@ -11,7 +12,6 @@ struct SimpleUartDevice : public riscv::Bus::MmioDevice {
|
||||||
constexpr static riscv::Address BASE_ADDRESS = 0x10000000;
|
constexpr static riscv::Address BASE_ADDRESS = 0x10000000;
|
||||||
|
|
||||||
riscv::Address Base() const override { return BASE_ADDRESS; }
|
riscv::Address Base() const override { return BASE_ADDRESS; }
|
||||||
|
|
||||||
riscv::Address Size() const override { return 12; } // for now
|
riscv::Address Size() const override { return 12; } // for now
|
||||||
|
|
||||||
u32 Peek(riscv::Address address) override {
|
u32 Peek(riscv::Address address) override {
|
||||||
|
@ -26,83 +26,120 @@ struct SimpleUartDevice : public riscv::Bus::MmioDevice {
|
||||||
void Poke(riscv::Address address, u32 value) override {
|
void Poke(riscv::Address address, u32 value) override {
|
||||||
if(address == BASE_ADDRESS) {
|
if(address == BASE_ADDRESS) {
|
||||||
char c = value & 0x000000ff;
|
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<riscv::Bus::Device*>(device));
|
||||||
|
}();
|
||||||
|
#endif
|
||||||
|
LUA->PushBool(result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void LuaCpu::Bind(GarrysMod::Lua::ILuaBase* LUA) {
|
void LuaCpu::Bind(GarrysMod::Lua::ILuaBase* LUA) {
|
||||||
lucore::LogInfo("In LuaCpu::Bind()");
|
// clang-format off
|
||||||
__lua_typeid = LUA->CreateMetaTable("LuaCpu");
|
LUA_CLASS_BIND_BEGIN(LuaCpu);
|
||||||
LUA->PushSpecial(GarrysMod::Lua::SPECIAL_REG);
|
LUA_SET_C_FUNCTION(PoweredOn);
|
||||||
LUA->PushNumber(__lua_typeid);
|
LUA_SET_C_FUNCTION(Cycle);
|
||||||
LUA->SetField(-2, "LuaCpu__typeid");
|
LUA_SET_C_FUNCTION(PowerOff);
|
||||||
LUA->Pop(); // Pop the registry
|
LUA_SET_C_FUNCTION(PowerOn);
|
||||||
|
LUA_SET_C_FUNCTION(Reset);
|
||||||
LUA->Push(-1);
|
LUA_SET_C_FUNCTION(AttachDevice);
|
||||||
// This method is called when the GC is done with our stuff
|
LUA_CLASS_BIND_END();
|
||||||
LUA->PushCFunction(__gc);
|
// clang-format on
|
||||||
LUA->SetField(-1, "__gc");
|
|
||||||
|
|
||||||
LUA->PushCFunction(Cycle);
|
|
||||||
LUA->SetField(-1, "Cycle");
|
|
||||||
LUA->Pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaCpu::Create(GarrysMod::Lua::ILuaBase* LUA, u32 memorySize) {
|
void LuaCpu::Create(GarrysMod::Lua::ILuaBase* LUA, u32 memorySize) {
|
||||||
LUA->PushUserType(new LuaCpu(memorySize), __lua_typeid);
|
auto cpuWrapper = new LuaCpu(memorySize);
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// 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) {
|
if(fp) {
|
||||||
std::fseek(fp, 0, SEEK_END);
|
std::fseek(fp, 0, SEEK_END);
|
||||||
auto len = std::ftell(fp);
|
auto len = std::ftell(fp);
|
||||||
std::fseek(fp, 0, SEEK_SET);
|
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);
|
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() {
|
LuaCpu::~LuaCpu() {
|
||||||
delete system;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <riscv/System.hpp>
|
#include <riscv/System.hpp>
|
||||||
|
|
||||||
#include "LuaMember.hpp"
|
#include "LuaHelpers.hpp"
|
||||||
|
|
||||||
// A work-in-progress
|
/// Bindings of [riscv::System] to Lua.
|
||||||
struct LuaCpu {
|
struct LuaCpu {
|
||||||
/// 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, u32 memorySize);
|
static void Create(GarrysMod::Lua::ILuaBase* LUA, u32 memorySize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
LuaCpu(u32 memorySize);
|
LuaCpu(u32 memorySize);
|
||||||
~LuaCpu();
|
~LuaCpu();
|
||||||
|
|
||||||
private:
|
LUA_MEMBER_FUNCTION(PoweredOn); // Check if the CPU is powered on
|
||||||
void CycleImpl();
|
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();
|
// class binding stuff
|
||||||
|
LUA_CLASS_BIND_VARIABLES(private);
|
||||||
// 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
|
// member variables
|
||||||
riscv::System* system;
|
riscv::System* system;
|
||||||
bool poweredOn = false;
|
bool poweredOn;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <riscv/Bus.hpp>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
|
@ -0,0 +1,65 @@
|
||||||
|
//! Helpers for lua binding
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <GarrysMod/Lua/Interface.h>
|
||||||
|
#include <lucore/Logger.hpp>
|
||||||
|
|
||||||
|
// 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<T>(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<T>(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);
|
|
@ -1,15 +0,0 @@
|
||||||
#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)
|
|
|
@ -84,7 +84,7 @@ namespace lcpu {
|
||||||
|
|
||||||
void SourceSink::OutputMessage(const lucore::Logger::MessageData& data) {
|
void SourceSink::OutputMessage(const lucore::Logger::MessageData& data) {
|
||||||
auto formatted =
|
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());
|
tier0::Msg("%s\n", formatted.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,15 @@
|
||||||
#include <GarrysMod/Lua/Interface.h>
|
#include <GarrysMod/Lua/Interface.h>
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <lucore/Logger.hpp>
|
#include <lucore/Logger.hpp>
|
||||||
#include <lucore/Types.hpp>
|
#include <lucore/Types.hpp>
|
||||||
|
|
||||||
#include "SourceSink.hpp"
|
#include "SourceSink.hpp"
|
||||||
|
|
||||||
#include "LuaCpu.hpp"
|
#include "LcpuGlobals.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!");
|
lucore::LogInfo("LCPU Native Module!");
|
||||||
|
GlobalsBind(LUA);
|
||||||
|
|
||||||
// Let lua types bind
|
|
||||||
//LuaCpu::Bind(LUA);
|
|
||||||
|
|
||||||
// Bind the global namespace
|
|
||||||
LCPUNative_Bind(LUA);
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,7 @@ namespace riscv {
|
||||||
/// This function is called by the bus to clock devices.
|
/// This function is called by the bus to clock devices.
|
||||||
virtual void Clock() {}
|
virtual void Clock() {}
|
||||||
|
|
||||||
// ability to interrupt
|
virtual void Reset() {}
|
||||||
|
|
||||||
// probably some reset functionality later on
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
constexpr bool IsA() {
|
constexpr bool IsA() {
|
||||||
|
@ -126,6 +124,7 @@ namespace riscv {
|
||||||
|
|
||||||
/// Clock all clocked devices mapped onto the bus..
|
/// Clock all clocked devices mapped onto the bus..
|
||||||
void Clock();
|
void Clock();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
u8 PeekByte(Address address);
|
u8 PeekByte(Address address);
|
||||||
u16 PeekShort(Address address);
|
u16 PeekShort(Address address);
|
||||||
|
|
|
@ -27,25 +27,25 @@ namespace riscv {
|
||||||
// TODO: Handlers for CSR read/write (if we need it?)
|
// TODO: Handlers for CSR read/write (if we need it?)
|
||||||
|
|
||||||
/// CPU state
|
/// CPU state
|
||||||
GeneralPurposeRegisters gpr;
|
GeneralPurposeRegisters gpr{};
|
||||||
u32 pc;
|
u32 pc{};
|
||||||
u32 mstatus;
|
u32 mstatus{};
|
||||||
u32 cyclel;
|
u32 cyclel{};
|
||||||
u32 cycleh;
|
u32 cycleh{};
|
||||||
u32 mscratch;
|
u32 mscratch{};
|
||||||
u32 mtvec;
|
u32 mtvec{};
|
||||||
u32 mie;
|
u32 mie{};
|
||||||
u32 mip;
|
u32 mip{};
|
||||||
|
|
||||||
u32 mepc;
|
u32 mepc{};
|
||||||
u32 mtval;
|
u32 mtval{};
|
||||||
u32 mcause;
|
u32 mcause{};
|
||||||
|
|
||||||
// Note: only a few bits are used. (Machine = 3, User = 0)
|
// Note: only a few bits are used. (Machine = 3, User = 0)
|
||||||
// Bits 0..1 = privilege.
|
// Bits 0..1 = privilege.
|
||||||
// Bit 2 = WFI (Wait for interrupt)
|
// Bit 2 = WFI (Wait for interrupt)
|
||||||
// Bit 3+ = Load/Store reservation LSBs.
|
// Bit 3+ = Load/Store reservation LSBs.
|
||||||
u32 extraflags;
|
u32 extraflags{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Set by [CPU::Trap] to tell the CPU it was trapped.
|
/// Set by [CPU::Trap] to tell the CPU it was trapped.
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace riscv {
|
||||||
struct GeneralPurposeRegisters {
|
struct GeneralPurposeRegisters {
|
||||||
constexpr u32& operator[](Gpr gpr) { return operator[](static_cast<usize>(gpr)); }
|
constexpr u32& operator[](Gpr gpr) { return operator[](static_cast<usize>(gpr)); }
|
||||||
constexpr u32& operator[](usize index) { return gprs_[index]; }
|
constexpr u32& operator[](usize index) { return gprs_[index]; }
|
||||||
u32 gprs_[32];
|
u32 gprs_[32]{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace riscv
|
} // namespace riscv
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace riscv::devices {
|
||||||
bool Clocked() const override { return true; }
|
bool Clocked() const override { return true; }
|
||||||
void Clock() override;
|
void Clock() override;
|
||||||
|
|
||||||
|
void Reset() override;
|
||||||
|
|
||||||
u32 Peek(Address address) override;
|
u32 Peek(Address address) override;
|
||||||
void Poke(Address address, u32 value) override;
|
void Poke(Address address, u32 value) override;
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,12 @@ namespace riscv {
|
||||||
cpu->Clock();
|
cpu->Clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bus::Reset() {
|
||||||
|
for(auto device : devices)
|
||||||
|
device->Reset();
|
||||||
|
cpu->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
u8 Bus::PeekByte(Address address) {
|
u8 Bus::PeekByte(Address address) {
|
||||||
if(auto dev = FindDeviceForAddress(address); dev)
|
if(auto dev = FindDeviceForAddress(address); dev)
|
||||||
return dev->Upcast<MemoryDevice*>()->PeekByte(address);
|
return dev->Upcast<MemoryDevice*>()->PeekByte(address);
|
||||||
|
|
|
@ -9,11 +9,7 @@ namespace riscv::devices {
|
||||||
TIMERH_ADDRESS = ClntDevice::BASE_ADDRESS + 0xbffc;
|
TIMERH_ADDRESS = ClntDevice::BASE_ADDRESS + 0xbffc;
|
||||||
|
|
||||||
void ClntDevice::Clock() {
|
void ClntDevice::Clock() {
|
||||||
// TODO: handle timer
|
u32 new_timer = timerCountLow + 10;
|
||||||
// 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;
|
|
||||||
if(new_timer < timerCountLow)
|
if(new_timer < timerCountLow)
|
||||||
timerCountHigh++;
|
timerCountHigh++;
|
||||||
timerCountLow = new_timer;
|
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) {
|
u32 ClntDevice::Peek(Address address) {
|
||||||
switch(address) {
|
switch(address) {
|
||||||
case TIMERL_ADDRESS: return timerCountLow;
|
case TIMERL_ADDRESS: return timerCountLow;
|
||||||
|
|
||||||
case TIMERH_ADDRESS: return timerCountHigh;
|
case TIMERH_ADDRESS: return timerCountHigh;
|
||||||
|
|
||||||
case MATCHL_ADDRESS: return timerMatchLow;
|
case MATCHL_ADDRESS: return timerMatchLow;
|
||||||
|
|
||||||
case MATCHH_ADDRESS: return timerMatchHigh;
|
case MATCHH_ADDRESS: return timerMatchHigh;
|
||||||
|
|
||||||
default: return 0x0;
|
default: return 0x0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,12 +41,7 @@ namespace riscv::devices {
|
||||||
void ClntDevice::Poke(Address address, u32 value) {
|
void ClntDevice::Poke(Address address, u32 value) {
|
||||||
switch(address) {
|
switch(address) {
|
||||||
case MATCHL_ADDRESS: timerMatchLow = value; break;
|
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<void*>(this), address, value); break;
|
default: lucore::LogInfo("CLNT({}) unhandled poke @ 0x{:08x} : 0x{:08x}", static_cast<void*>(this), address, value); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
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) {
|
||||||
memory = new u8[size];
|
memory = new u8[size]{};
|
||||||
LUCORE_CHECK(memory, "Could not allocate buffer for memory device with size 0x{:08x}.", size);
|
LUCORE_CHECK(memory, "Could not allocate buffer for memory device with size 0x{:08x}.", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,6 @@ namespace riscv {
|
||||||
system->clnt = new devices::ClntDevice();
|
system->clnt = new devices::ClntDevice();
|
||||||
system->syscon = new devices::SysconDevice(system);
|
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
|
// attach everything into the bus
|
||||||
if(!system->bus->AttachDevice(system->cpu))
|
if(!system->bus->AttachDevice(system->cpu))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -25,6 +22,9 @@ namespace riscv {
|
||||||
if(!system->bus->AttachDevice(system->ram))
|
if(!system->bus->AttachDevice(system->ram))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// reset the bus and all devices on it
|
||||||
|
system->bus->Reset();
|
||||||
|
|
||||||
return system;
|
return system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <lucore/StdoutSink.hpp>
|
#include <lucore/StdoutSink.hpp>
|
||||||
#include <riscv/System.hpp>
|
#include <riscv/System.hpp>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
/// 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;
|
||||||
|
@ -59,6 +61,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
while(!shouldExit) {
|
while(!shouldExit) {
|
||||||
system->Step();
|
system->Step();
|
||||||
|
//std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
delete system;
|
delete system;
|
||||||
|
|
Loading…
Reference in New Issue