mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-08 09:43:32 +01:00
Multiple runtime fixes, first build+execution with graphical nodes
This commit is contained in:
parent
d6df8b65ab
commit
47552d4719
7 changed files with 148 additions and 44 deletions
|
|
@ -118,12 +118,18 @@ private:
|
||||||
auto* varNode = inputNode->GetAs<VariableNode>();
|
auto* varNode = inputNode->GetAs<VariableNode>();
|
||||||
if (varNode) {
|
if (varNode) {
|
||||||
auto var = varNode->GetVariable();
|
auto var = varNode->GetVariable();
|
||||||
// Generate code to load the variable value
|
|
||||||
// FIXME: hardcoded 4 bytes, replace by actual real variable size
|
if (var)
|
||||||
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n";
|
{
|
||||||
m_assembly << " push r" << reg << "\n";
|
// Generate code to load the variable value
|
||||||
// Assuming we have a function to load the variable value
|
// FIXME: hardcoded 4 bytes, replace by actual real variable size
|
||||||
// m_assembly << " load r0, " << varNode->GetVariableName() << "\n";
|
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n";
|
||||||
|
m_assembly << " push r" << reg << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("ERROR! Variable not set in node: " + inputNode->node->GetId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
reg++;
|
reg++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ PrintNode::PrintNode(const std::string &type)
|
||||||
// Create empty variable in memory
|
// Create empty variable in memory
|
||||||
auto v = std::make_shared<Variable>(m_label);
|
auto v = std::make_shared<Variable>(m_label);
|
||||||
v->SetTextValue("");
|
v->SetTextValue("");
|
||||||
|
v->SetConstant(true);
|
||||||
m_label = v->GetLabel();
|
m_label = v->GetLabel();
|
||||||
m_variables[m_label] = v;
|
m_variables[m_label] = v;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ StoryProject::StoryProject(ILogger &log)
|
||||||
: m_log(log)
|
: m_log(log)
|
||||||
{
|
{
|
||||||
// registerNode<MediaNode>("media-node");
|
// registerNode<MediaNode>("media-node");
|
||||||
registerNode<FunctionNode>("operator-node");
|
registerNode<OperatorNode>("operator-node");
|
||||||
registerNode<FunctionNode>("function-node");
|
registerNode<FunctionNode>("function-node");
|
||||||
registerNode<VariableNode>("variable-node");
|
registerNode<VariableNode>("variable-node");
|
||||||
registerNode<PrintNode>("print-node");
|
registerNode<PrintNode>("print-node");
|
||||||
|
|
@ -384,6 +384,7 @@ bool StoryProject::UseResource(const std::string &label)
|
||||||
|
|
||||||
bool StoryProject::GenerateScript(std::string &codeStr)
|
bool StoryProject::GenerateScript(std::string &codeStr)
|
||||||
{
|
{
|
||||||
|
bool retCode = true;
|
||||||
std::stringstream code;
|
std::stringstream code;
|
||||||
|
|
||||||
// Empty resources usage
|
// Empty resources usage
|
||||||
|
|
@ -403,43 +404,40 @@ bool StoryProject::GenerateScript(std::string &codeStr)
|
||||||
// Create generator
|
// Create generator
|
||||||
AssemblyGeneratorChip32 generator(context);
|
AssemblyGeneratorChip32 generator(context);
|
||||||
|
|
||||||
|
try
|
||||||
generator.Reset();
|
|
||||||
|
|
||||||
// Generate header comments
|
|
||||||
generator.GenerateHeader();
|
|
||||||
|
|
||||||
// Generate data section
|
|
||||||
generator.StartSection(AssemblyGenerator::Section::DATA);
|
|
||||||
for (const auto & p : m_pages)
|
|
||||||
{
|
{
|
||||||
p->BuildNodesVariables(generator);
|
generator.Reset();
|
||||||
|
|
||||||
|
// Generate header comments
|
||||||
|
generator.GenerateHeader();
|
||||||
|
|
||||||
|
// Generate text section
|
||||||
|
generator.StartSection(AssemblyGenerator::Section::TEXT);
|
||||||
|
for (const auto & p : m_pages)
|
||||||
|
{
|
||||||
|
p->BuildNodes(generator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate data section
|
||||||
|
generator.StartSection(AssemblyGenerator::Section::DATA);
|
||||||
|
for (const auto & p : m_pages)
|
||||||
|
{
|
||||||
|
p->BuildNodesVariables(generator);
|
||||||
|
}
|
||||||
|
generator.GenerateGlobalVariables(m_variables);
|
||||||
|
|
||||||
|
generator.GenerateExit();
|
||||||
|
|
||||||
}
|
}
|
||||||
generator.GenerateGlobalVariables(m_variables);
|
catch (const std::exception &e)
|
||||||
|
|
||||||
// Generate text section
|
|
||||||
generator.StartSection(AssemblyGenerator::Section::TEXT);
|
|
||||||
|
|
||||||
for (const auto & p : m_pages)
|
|
||||||
{
|
{
|
||||||
p->BuildNodes(generator);
|
m_log.Log(e.what(), true);
|
||||||
|
retCode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.GenerateExit();
|
|
||||||
|
|
||||||
codeStr = generator.GetAssembly();
|
codeStr = generator.GetAssembly();
|
||||||
|
|
||||||
// Add our utility functions
|
return retCode;
|
||||||
// std::string buffer;
|
|
||||||
|
|
||||||
// std::ifstream f("scripts/media.chip32");
|
|
||||||
// f.seekg(0, std::ios::end);
|
|
||||||
// buffer.resize(f.tellg());
|
|
||||||
// f.seekg(0);
|
|
||||||
// f.read(buffer.data(), buffer.size());
|
|
||||||
// codeStr += buffer;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StoryProject::GenerateBinary(const std::string &code, Chip32::Assembler::Error &err)
|
bool StoryProject::GenerateBinary(const std::string &code, Chip32::Assembler::Error &err)
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ uint8_t vm_syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
if (m_chip32_ctx.registers[R0] != 0)
|
if (m_chip32_ctx.registers[R0] != 0)
|
||||||
{
|
{
|
||||||
// image file name address is in R0
|
// image file name address is in R0
|
||||||
// QString imageFile = m_model.BuildFullImagePath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
// QString imageFile = m_model.BuildFullImagePath(GetStringFromMemory(m_chip32_ctx.registers[R0]));
|
||||||
// m_ostHmiDock->SetImage(imageFile);
|
// m_ostHmiDock->SetImage(imageFile);
|
||||||
get_file_from_memory(ImageFile, m_chip32_ctx.registers[R0]);
|
get_file_from_memory(ImageFile, m_chip32_ctx.registers[R0]);
|
||||||
fs_task_image_start(ImageFile);
|
fs_task_image_start(ImageFile);
|
||||||
|
|
@ -96,7 +96,7 @@ uint8_t vm_syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
if (m_chip32_ctx.registers[R1] != 0)
|
if (m_chip32_ctx.registers[R1] != 0)
|
||||||
{
|
{
|
||||||
// sound file name address is in R1
|
// sound file name address is in R1
|
||||||
// QString soundFile = m_model.BuildFullSoundPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
// QString soundFile = m_model.BuildFullSoundPath(GetStringFromMemory(m_chip32_ctx.registers[R1]));
|
||||||
// qDebug() << ", Sound: " << soundFile;
|
// qDebug() << ", Sound: " << soundFile;
|
||||||
// m_model.PlaySoundFile(soundFile);
|
// m_model.PlaySoundFile(soundFile);
|
||||||
get_file_from_memory(SoundFile, m_chip32_ctx.registers[R1]);
|
get_file_from_memory(SoundFile, m_chip32_ctx.registers[R1]);
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,30 @@ void BaseNodeWidget::FrameStart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_firstFrame = false;
|
m_firstFrame = false;
|
||||||
|
|
||||||
|
|
||||||
|
// Title
|
||||||
|
|
||||||
|
const char * text = m_base->GetTypeName().c_str();
|
||||||
|
// Obtenir la position courante du curseur
|
||||||
|
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||||
|
|
||||||
|
// Définir les dimensions du texte
|
||||||
|
ImVec2 text_size = ImGui::CalcTextSize(text);
|
||||||
|
|
||||||
|
// Ajouter un padding autour du texte
|
||||||
|
float padding = 5.0f;
|
||||||
|
ImVec2 rect_min = ImVec2(pos.x - padding, pos.y - padding);
|
||||||
|
ImVec2 rect_max = ImVec2(pos.x + text_size.x + padding, pos.y + text_size.y + padding);
|
||||||
|
|
||||||
|
// Définir la couleur du rectangle (bleu avec transparence)
|
||||||
|
ImU32 bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 1.0f));
|
||||||
|
|
||||||
|
// Dessiner le rectangle de fond
|
||||||
|
ImGui::GetWindowDrawList()->AddRectFilled(rect_min, rect_max, bg_color);
|
||||||
|
|
||||||
|
// Afficher le texte
|
||||||
|
ImGui::TextUnformatted(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseNodeWidget::FrameEnd()
|
void BaseNodeWidget::FrameEnd()
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ MainWindow::~MainWindow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string MainWindow::GetFileNameFromMemory(uint32_t addr)
|
std::string MainWindow::GetStringFromMemory(uint32_t addr)
|
||||||
{
|
{
|
||||||
char strBuf[100];
|
char strBuf[100];
|
||||||
bool isRam = addr & 0x80000000;
|
bool isRam = addr & 0x80000000;
|
||||||
|
|
@ -77,6 +77,7 @@ std::string MainWindow::GetFileNameFromMemory(uint32_t addr)
|
||||||
return strBuf;
|
return strBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::Play()
|
void MainWindow::Play()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -268,7 +269,36 @@ void MainWindow::ProcessStory()
|
||||||
}
|
}
|
||||||
else if (m_dbg.run_result > VM_OK)
|
else if (m_dbg.run_result > VM_OK)
|
||||||
{
|
{
|
||||||
Log("VM critical error", true);
|
std::string error = "VM Error: ";
|
||||||
|
switch (m_dbg.run_result)
|
||||||
|
{
|
||||||
|
case VM_ERR_STACK_OVERFLOW:
|
||||||
|
error += "Stack overflow";
|
||||||
|
break;
|
||||||
|
case VM_ERR_STACK_UNDERFLOW:
|
||||||
|
error += "Stack underflow";
|
||||||
|
break;
|
||||||
|
case VM_ERR_INVALID_ADDRESS:
|
||||||
|
error += "Invalid address";
|
||||||
|
break;
|
||||||
|
case VM_ERR_UNSUPPORTED_OPCODE:
|
||||||
|
error += "Invalid address";
|
||||||
|
break;
|
||||||
|
case VM_ERR_UNKNOWN_OPCODE:
|
||||||
|
error += "Unknown opcode";
|
||||||
|
break;
|
||||||
|
case VM_ERR_UNHANDLED_INTERRUPT:
|
||||||
|
error += "Unhandled interrupt";
|
||||||
|
break;
|
||||||
|
case VM_ERR_INVALID_REGISTER:
|
||||||
|
error += "Invalid register";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error += "Unknown error";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error += " (line: " + std::to_string(m_dbg.line) + ")";
|
||||||
|
Log(error, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In this case, we wait for single step debugger
|
// In this case, we wait for single step debugger
|
||||||
|
|
@ -289,7 +319,7 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
if (m_chip32_ctx.registers[R0] != 0)
|
if (m_chip32_ctx.registers[R0] != 0)
|
||||||
{
|
{
|
||||||
// image file name address is in R0
|
// image file name address is in R0
|
||||||
std::string imageFile = m_story->BuildFullAssetsPath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
std::string imageFile = m_story->BuildFullAssetsPath(GetStringFromMemory(m_chip32_ctx.registers[R0]));
|
||||||
Log("Image: " + imageFile);
|
Log("Image: " + imageFile);
|
||||||
m_emulatorWindow.SetImage(imageFile);
|
m_emulatorWindow.SetImage(imageFile);
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +331,7 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
if (m_chip32_ctx.registers[R1] != 0)
|
if (m_chip32_ctx.registers[R1] != 0)
|
||||||
{
|
{
|
||||||
// sound file name address is in R1
|
// sound file name address is in R1
|
||||||
std::string soundFile = m_story->BuildFullAssetsPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
std::string soundFile = m_story->BuildFullAssetsPath(GetStringFromMemory(m_chip32_ctx.registers[R1]));
|
||||||
Log("Sound: " + soundFile);
|
Log("Sound: " + soundFile);
|
||||||
m_player.Play(soundFile);
|
m_player.Play(soundFile);
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +355,52 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
// if timeout is set to zero, wait for infinite and beyond
|
// if timeout is set to zero, wait for infinite and beyond
|
||||||
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
||||||
}
|
}
|
||||||
|
else if (code == 3)
|
||||||
|
{
|
||||||
|
// FIXME
|
||||||
|
}
|
||||||
|
else // Printf
|
||||||
|
if (code == 4)
|
||||||
|
{
|
||||||
|
// In R0: string with escaped characters
|
||||||
|
// R1: Number of arguments
|
||||||
|
// R2, R3 ... arguments
|
||||||
|
|
||||||
|
// Integers: stored in registers by values
|
||||||
|
// Strings: first character address in register
|
||||||
|
|
||||||
|
std::string text = GetStringFromMemory(ctx->registers[R0]);
|
||||||
|
|
||||||
|
int arg_count = ctx->registers[R1];
|
||||||
|
char working_buf[200] = {0};
|
||||||
|
|
||||||
|
switch(arg_count){
|
||||||
|
case 0:
|
||||||
|
Log(text);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2]);
|
||||||
|
Log(working_buf);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3]);
|
||||||
|
Log(working_buf);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]);
|
||||||
|
Log(working_buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// WAIT (sleep)
|
||||||
|
else if (code == 5)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(ctx->registers[R0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return retCode;
|
return retCode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ private:
|
||||||
|
|
||||||
void UpdateVmView();
|
void UpdateVmView();
|
||||||
uint8_t Syscall(chip32_ctx_t *ctx, uint8_t code);
|
uint8_t Syscall(chip32_ctx_t *ctx, uint8_t code);
|
||||||
std::string GetFileNameFromMemory(uint32_t addr);
|
std::string GetStringFromMemory(uint32_t addr);
|
||||||
void ProcessStory();
|
void ProcessStory();
|
||||||
void StepInstruction();
|
void StepInstruction();
|
||||||
void RefreshProjectInformation();
|
void RefreshProjectInformation();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue