Add comparison chip32 instructions, add debugger, add CPU window

This commit is contained in:
anthony@rabine.fr 2024-05-23 15:33:04 +02:00
parent 5ed9233778
commit fcc3562ecd
24 changed files with 399 additions and 86 deletions

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "story-editor/libs/SDL_image"]
path = story-editor/libs/SDL_image
url = git@github.com:libsdl-org/SDL_image.git

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Anthony Rabine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"name": "chip32-syntax",
"displayName": "Chip32 Syntax Highlighting",
"description": "Syntax highlighting for Chip32 assembly language",
"version": "0.0.1",
"publisher": "Anthony Rabine",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/arabine/open-story-teller"},
"engines": {
"vscode": "^1.0.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [{
"id": "chip32",
"extensions": [".chip32"],
"aliases": ["Chip32", "chip32"]
}],
"grammars": [{
"language": "chip32",
"scopeName": "source.assembly",
"path": "./syntaxes/chip32.tmLanguage.json"
}]
}
}

View file

@ -0,0 +1,27 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Chip32",
"patterns": [
{
"match": "\\b(nop|halt|syscall|lcons|mov|push|pop|store|load|add|sub|mul|div|shiftl|shiftr|ishiftr|and|or|xor|not|call|ret|jump|jumpr|skipz|skipnz|eq|gt|lt)\\b",
"name": "keyword.control.assembly"
},
{
"match": "\\b(r[0-9]+|t[0-9]+|pc|sp|ra)\\b",
"name": "variable.parameter.register.assembly"
},
{
"match": "@",
"name": "keyword.operator.assembly"
},
{
"match": "\\b(0x[0-9a-fA-F]+)\\b",
"name": "constant.numeric.hex.assembly"
},
{
"match": ";.*",
"name": "comment.line.assembly"
}
],
"scopeName": "source.assembly"
}

View file

@ -55,7 +55,8 @@ static const uint32_t NbRegs = sizeof(AllRegs) / sizeof(AllRegs[0]);
// Keep same order than the opcodes list!! // Keep same order than the opcodes list!!
static const std::string Mnemonics[] = { static const std::string Mnemonics[] = {
"nop", "halt", "syscall", "lcons", "mov", "push", "pop", "store", "load", "add", "sub", "mul", "div", "nop", "halt", "syscall", "lcons", "mov", "push", "pop", "store", "load", "add", "sub", "mul", "div",
"shiftl", "shiftr", "ishiftr", "and", "or", "xor", "not", "call", "ret", "jump", "jumpr", "skipz", "skipnz" "shiftl", "shiftr", "ishiftr", "and", "or", "xor", "not", "call", "ret", "jump", "jumpr", "skipz", "skipnz",
"eq", "gt", "lt"
}; };
static OpCode OpCodes[] = OPCODES_LIST; static OpCode OpCodes[] = OPCODES_LIST;
@ -166,7 +167,7 @@ bool Assembler::GetRegisterName(uint8_t reg, std::string &regName)
bool Assembler::CompileMnemonicArguments(Instr &instr) bool Assembler::CompileMnemonicArguments(Instr &instr)
{ {
uint8_t ra, rb; uint8_t ra, rb, rc;
switch(instr.code.opcode) switch(instr.code.opcode)
{ {
@ -239,6 +240,16 @@ bool Assembler::CompileMnemonicArguments(Instr &instr)
instr.compiledArgs.push_back(rb); instr.compiledArgs.push_back(rb);
instr.compiledArgs.push_back(static_cast<uint32_t>(strtol(instr.args[2].c_str(), NULL, 0))); instr.compiledArgs.push_back(static_cast<uint32_t>(strtol(instr.args[2].c_str(), NULL, 0)));
break; break;
case OP_CMP_EQ:
case OP_CMP_GT:
case OP_CMP_LT:
GET_REG(instr.args[0], ra);
GET_REG(instr.args[1], rb);
GET_REG(instr.args[2], rc);
instr.compiledArgs.push_back(ra);
instr.compiledArgs.push_back(rb);
instr.compiledArgs.push_back(rc);
break;
default: default:
CHIP32_CHECK(instr, false, "Unsupported mnemonic: " + instr.mnemonic); CHIP32_CHECK(instr, false, "Unsupported mnemonic: " + instr.mnemonic);
break; break;

View file

@ -85,6 +85,18 @@ static inline uint32_t _NEXT_INT (chip32_ctx_t *ctx)
static const OpCode OpCodes[] = OPCODES_LIST; static const OpCode OpCodes[] = OPCODES_LIST;
static const uint16_t OpCodesSize = sizeof(OpCodes) / sizeof(OpCodes[0]); static const uint16_t OpCodesSize = sizeof(OpCodes) / sizeof(OpCodes[0]);
static void push(chip32_ctx_t *ctx, uint32_t val) {
ctx->registers[SP] -= 4;
ctx->ram.mem[ctx->registers[SP]] = val;
}
static uint32_t pop(chip32_ctx_t *ctx) {
uint32_t val = ctx->ram.mem[ctx->registers[SP]];
ctx->registers[SP] += 4;
return val;
}
// ======================================================================================= // =======================================================================================
// FUNCTIONS // FUNCTIONS
// ======================================================================================= // =======================================================================================
@ -162,8 +174,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
const uint8_t reg = _NEXT_BYTE; const uint8_t reg = _NEXT_BYTE;
_CHECK_REGISTER_VALID(reg) _CHECK_REGISTER_VALID(reg)
_CHECK_CAN_PUSH(1) _CHECK_CAN_PUSH(1)
ctx->registers[SP] -= 4; push(ctx, ctx->registers[reg]);
memcpy(&ctx->ram.mem[ctx->registers[SP]], &ctx->registers[reg], sizeof(uint32_t));
break; break;
} }
case OP_POP: case OP_POP:
@ -171,8 +182,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
const uint8_t reg = _NEXT_BYTE; const uint8_t reg = _NEXT_BYTE;
_CHECK_REGISTER_VALID(reg) _CHECK_REGISTER_VALID(reg)
_CHECK_CAN_POP(1) _CHECK_CAN_POP(1)
memcpy(&ctx->registers[reg], &ctx->ram.mem[ctx->registers[SP]], sizeof(uint32_t)); ctx->registers[reg] = pop(ctx);
ctx->registers[SP] += 4;
break; break;
} }
case OP_CALL: case OP_CALL:
@ -181,11 +191,23 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
const uint8_t reg = _NEXT_BYTE; const uint8_t reg = _NEXT_BYTE;
_CHECK_REGISTER_VALID(reg) _CHECK_REGISTER_VALID(reg)
ctx->registers[PC] = ctx->registers[reg] - 1; ctx->registers[PC] = ctx->registers[reg] - 1;
// Save Tx registers on stack
_CHECK_CAN_POP(10)
for (int i = 0; i < 10; i++) {
push(ctx, ctx->registers[T0 + i]);
}
break; break;
} }
case OP_RET: case OP_RET:
{ {
ctx->registers[PC] = ctx->registers[RA] - 1; ctx->registers[PC] = ctx->registers[RA] - 1;
// restore Tx registers from stack
for (int i = 0; i < 10; i++) {
ctx->registers[T9 - i] = pop(ctx);
}
break; break;
} }
case OP_STORE: case OP_STORE:
@ -353,6 +375,40 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
} }
break; break;
} }
case OP_CMP_EQ:
{
const uint8_t reg1 = _NEXT_BYTE;
const uint8_t reg2 = _NEXT_BYTE;
const uint8_t reg3 = _NEXT_BYTE;
_CHECK_REGISTER_VALID(reg1)
_CHECK_REGISTER_VALID(reg2)
_CHECK_REGISTER_VALID(reg3)
ctx->registers[reg1] = ctx->registers[reg2] == ctx->registers[reg3] ? 1 : 0;
break;
}
case OP_CMP_GT:
{
const uint8_t reg1 = _NEXT_BYTE;
const uint8_t reg2 = _NEXT_BYTE;
const uint8_t reg3 = _NEXT_BYTE;
_CHECK_REGISTER_VALID(reg1)
_CHECK_REGISTER_VALID(reg2)
_CHECK_REGISTER_VALID(reg3)
ctx->registers[reg1] = ctx->registers[reg2] > ctx->registers[reg3] ? 1 : 0;
break;
}
case OP_CMP_LT:
{
const uint8_t reg1 = _NEXT_BYTE;
const uint8_t reg2 = _NEXT_BYTE;
const uint8_t reg3 = _NEXT_BYTE;
_CHECK_REGISTER_VALID(reg1)
_CHECK_REGISTER_VALID(reg2)
_CHECK_REGISTER_VALID(reg3)
ctx->registers[reg1] = ctx->registers[reg2] < ctx->registers[reg3] ? 1 : 0;
break;
}
} }
ctx->registers[PC]++; ctx->registers[PC]++;

View file

@ -80,6 +80,11 @@ typedef enum
OP_SKIPZ = 24, ///< skip next instruction if zero, e.g.: skipz r0 OP_SKIPZ = 24, ///< skip next instruction if zero, e.g.: skipz r0
OP_SKIPNZ = 25, ///< skip next instruction if not zero, e.g.: skipnz r2 OP_SKIPNZ = 25, ///< skip next instruction if not zero, e.g.: skipnz r2
// Comparison
OP_CMP_EQ = 26, ///< compare two registers for equality, result in first e.g.: cmp_eq r4, r0, r1 (r4 = (r0 == r1 ? 1 : 0)
OP_CMP_GT = 27, ///< compare if first register is greater than the second, result in first e.g.: cmp_gt r4, r0, r1
OP_CMP_LT = 28, ///< compare if first register is less than the second, result in first e.g.: cmp_lt r4, r0, r1
INSTRUCTION_COUNT INSTRUCTION_COUNT
} chip32_instruction_t; } chip32_instruction_t;
@ -152,10 +157,11 @@ typedef struct {
#define OPCODES_LIST { { OP_NOP, 0, 0 }, { OP_HALT, 0, 0 }, { OP_SYSCALL, 1, 1 }, { OP_LCONS, 2, 5 }, \ #define OPCODES_LIST { { OP_NOP, 0, 0 }, { OP_HALT, 0, 0 }, { OP_SYSCALL, 1, 1 }, { OP_LCONS, 2, 5 }, \
{ OP_MOV, 2, 2 }, { OP_PUSH, 1, 1 }, {OP_POP, 1, 1 }, \ { OP_MOV, 2, 2 }, { OP_PUSH, 1, 1 }, {OP_POP, 1, 1 }, \
{ OP_STORE, 3, 4 }, { OP_LOAD, 3, 4 }, { OP_ADD, 2, 2 }, { OP_SUB, 2, 2 }, { OP_MUL, 2, 2 }, \ { OP_STORE, 3, 3 }, { OP_LOAD, 3, 3 }, { OP_ADD, 2, 2 }, { OP_SUB, 2, 2 }, { OP_MUL, 2, 2 }, \
{ OP_DIV, 2, 2 }, { OP_SHL, 2, 2 }, { OP_SHR, 2, 2 }, { OP_ISHR, 2, 2 }, { OP_AND, 2, 2 }, \ { OP_DIV, 2, 2 }, { OP_SHL, 2, 2 }, { OP_SHR, 2, 2 }, { OP_ISHR, 2, 2 }, { OP_AND, 2, 2 }, \
{ OP_OR, 2, 2 }, { OP_XOR, 2, 2 }, { OP_NOT, 1, 1 }, { OP_CALL, 1, 1 }, { OP_RET, 0, 0 }, \ { OP_OR, 2, 2 }, { OP_XOR, 2, 2 }, { OP_NOT, 1, 1 }, { OP_CALL, 1, 1 }, { OP_RET, 0, 0 }, \
{ OP_JUMP, 1, 2 }, { OP_JUMPR, 1, 1 }, { OP_SKIPZ, 1, 1 }, { OP_SKIPNZ, 1, 1 } } { OP_JUMP, 1, 2 }, { OP_JUMPR, 1, 1 }, { OP_SKIPZ, 1, 1 }, { OP_SKIPNZ, 1, 1 }, \
{ OP_CMP_EQ, 3, 3 }, { OP_CMP_GT, 3, 3 }, { OP_CMP_LT, 3, 3 } }
/** /**
Whole memory is 64KB Whole memory is 64KB

View file

@ -380,7 +380,7 @@ bool StoryProject::GenerateScript(std::string &codeStr)
// Add our utility functions // Add our utility functions
std::string buffer; std::string buffer;
std::ifstream f("scripts/media.asm"); std::ifstream f("scripts/media.chip32");
f.seekg(0, std::ios::end); f.seekg(0, std::ios::end);
buffer.resize(f.tellg()); buffer.resize(f.tellg());
f.seekg(0); f.seekg(0);
@ -580,7 +580,7 @@ std::string StoryProject::BuildFullAssetsPath(const std::string_view fileName) c
std::string StoryProject::FileToConstant(const std::string &FileName, const std::string &extension) std::string StoryProject::FileToConstant(const std::string &FileName, const std::string &extension)
{ {
std::string f = SysLib::RemoveFileExtension(FileName); std::string f = SysLib::RemoveFileExtension(FileName);
return "$" + f + " DC8 \"" + f + "." + extension + "\", 8\r\n"; return "$" + FileName + " DC8 \"" + FileName + "\", 8\r\n";
} }

View file

@ -207,6 +207,9 @@ set(SRCS
src/properties_window.cpp src/properties_window.cpp
src/properties_window.h src/properties_window.h
src/cpu_window.cpp
src/cpu_window.h
src/gui.h src/gui.h
src/gui.cpp src/gui.cpp

View file

@ -953,7 +953,7 @@ void TextEditor::Render()
if (mBreakpoints.count(lineNo + 1) != 0) if (mBreakpoints.count(lineNo + 1) != 0)
{ {
auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y); auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(start, end, mPalette[(int)PaletteIndex::Breakpoint]); drawList->AddCircleFilled(ImVec2(start.x + 8, start.y + 8), 5.0f, IM_COL32(255, 0, 0, 255), 12);
} }
// Draw error markers // Draw error markers

@ -1 +0,0 @@
Subproject commit 25e816f614dbe4aa9fdaf89c248ae283f20038f9

View file

@ -1,47 +0,0 @@
; Generic media choice manager
.media:
; Les adresses des différents medias sont dans la stack
; Arguments:
; r0: address d'une structure de type "media choice"
; Local:
; t0: loop counter
; t1: increment 1
; t2: increment 4
; t3: current media address
; t4: where to jump when OK button is pressed
; t5: address of the "choice" array
mov t5, r0 ; we save R0
.media_loop_start:
load t0, @t5, 4 ; Le premier élément est le nombre de choix possibles, t0 = 3 (exemple)
lcons t1, 1
lcons t2, 4
mov t3, t5
.media_loop:
add t3, t2 ; @++
; --------- We call a media transition node
load r0, @t3, 4 ; r0 = content in ram at address in T3
call r0 ; call subroutine
; Return argument in R0: the address of the node to call whe OK is pressed
; save it in t4
mov t4, r0
; wait for event (OK or wheel)
syscall 2
; Event is stored in R0
; ----- Test if event is OK button
lcons r1, 1 ; mask for OK button
and r1, r0 ; r1 = r1 AND r0
skipz r1 ; not OK, skip jump
jumpr t4 ; we do not plan to return here, so a jump is enough
; all other events mean: next node
sub t0, t1 ; i--
skipnz t0 ; if (r0) goto start_loop;
jump .media_loop_start
jump .media_loop

View file

@ -0,0 +1,70 @@
; Generic media choice manager
.media:
; Les adresses des différents medias sont dans la stack
; Arguments:
; r0: address d'une structure de type "media choice"
; Local:
; t0: current media address
; t1: increment 4
; t3: address of the first element in the choice array
; t4: address of the last element in the choice array
; t5: where to jump when OK button is pressed
mov t3, r0 ; on sauvegarde R0 (rx non préservés)
load r0, @t3, 4 ; Le premier élément est le nombre de choix possibles, ex: r0 = 12
lcons t1, 4
mul r0, t1 ; on calcule l'offset: r0 = nb_elements * 4 = 48
mov t4, t3 ; t4 = t3
add t4, r0 ; t4 pointe maintenant sur le dernier élément de la structure
add t3, t1 ; t3 pointe maintenant sur le premier élément
mov t0, t3 ; on commence sur le premier élément
.media_loop:
; --------- We call a media transition node
load r0, @t0, 4 ; Get the address located at memory T0
call r0 ; call subroutine
; Return argument in R0: the address of the node to call whe OK is pressed
mov t5, r0 ; save it
; wait for event (OK or wheel)
syscall 2
; Event is stored in R0
; 1 = ok
; 2 = previous
; 4 = next
; 8 = audio finished
; ----- Test if event is OK button
lcons r1, 1 ; mask for OK button
and r1, r0 ; r1 = r1 AND r0
skipz r1 ; not OK, skip jump
jumpr t5 ; we do not plan to return here, so a jump is enough
; test previous event
lcons r1, 2 ; mask for previous button
and r1, r0 ; r1 = r1 AND r0
skipz r1 ; not OK, skip jump
jump .media_previous
; all other events mean: next node
eq r0, t0, t4 ; t4 est le dernier élément
skipz r0 ; zéro, on peut incrémenter l'adresse
jump .media_set_first
add t0, t1 ; t0 += 4
jump .media_loop
.media_set_first: ; on reboucle sur le premier élément de la structure
mov t0, t3
jump .media_loop
.media_previous:
eq r0, t0, t3 ; on teste si on est au premier élément
skipz r0 ; zéro, on peut décrémenter l'adresse
jump .media_set_last
sub t0, t1 ; t0 += 4
jump .media_loop
.media_set_last: ; on reboucle sur le dernier élément de la structure
mov t0, t4
jump .media_loop

View file

@ -1,5 +1,5 @@
#include "code_editor.h" #include "code_editor.h"
#include "IconsMaterialDesignIcons.h"
#include <fstream> #include <fstream>
#include <memory> #include <memory>
@ -55,8 +55,6 @@ void CodeEditor::Draw()
auto cpos = mEditor.GetCursorPosition(); auto cpos = mEditor.GetCursorPosition();
ImGui::SetWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); ImGui::SetWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
@ -119,17 +117,26 @@ void CodeEditor::Draw()
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::SmallButton("Toggle breakpoint")) { if (ImGui::SmallButton("Toggle breakpoint")) {
if (m_breakPoints.contains(cpos.mLine)) if (m_breakPoints.contains(cpos.mLine + 1))
{ {
m_breakPoints.erase(cpos.mLine); m_breakPoints.erase(cpos.mLine + 1);
} }
else else
{ {
m_breakPoints.insert(cpos.mLine); m_breakPoints.insert(cpos.mLine + 1);
} }
mEditor.SetBreakpoints(m_breakPoints); mEditor.SetBreakpoints(m_breakPoints);
m_storyManager.ToggleBreakpoint(cpos.mLine); m_storyManager.ToggleBreakpoint(cpos.mLine + 1);
}
ImGui::SameLine();
if (ImGui::SmallButton(ICON_MDI_SKIP_NEXT "##step_instruction")) {
m_storyManager.Step();
}
ImGui::SameLine();
if (ImGui::SmallButton(ICON_MDI_PLAY "##run")) {
m_storyManager.Run();
} }
mEditor.Render("TextEditor"); mEditor.Render("TextEditor");

View file

@ -0,0 +1,63 @@
#include "cpu_window.h"
#include "gui.h"
#include "ImGuiFileDialog.h"
#include "IconsMaterialDesignIcons.h"
#include "chip32_vm.h"
static const char* CpuRegNames[] = {
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
"R8", "R9", "T0", "T1", "T2", "T3", "T4", "T5",
"T6", "T7", "T8", "T9", "PC", "SP", "RA"
};
CpuWindow::CpuWindow(IStoryManager &proj)
: WindowBase("CPU")
, m_story(proj)
{
}
void CpuWindow::Initialize()
{
}
void CpuWindow::Draw()
{
static ImVec2 size(320.0f, 240.0f);
WindowBase::BeginDraw();
ImGui::SetWindowSize(ImVec2(626, 744), ImGuiCond_FirstUseEver);
static ImGuiTableFlags tableFlags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
| ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
| ImGuiTableFlags_SizingFixedFit;
if (ImGui::BeginTable("cpu_table", 2, tableFlags))
{
ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed);
for (int i = 0; i < REGISTER_COUNT; i++)
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("%s",CpuRegNames[i]);
ImGui::TableSetColumnIndex(1);
ImGui::Text("0x%04X", m_story.GetRegister(i));
}
ImGui::EndTable();
}
WindowBase::EndDraw();
}

View file

@ -0,0 +1,19 @@
#pragma once
#include "window_base.h"
#include "i_story_manager.h"
#include "gui.h"
class CpuWindow : public WindowBase
{
public:
CpuWindow(IStoryManager &proj);
void Initialize();
virtual void Draw() override;
private:
IStoryManager &m_story;
};

View file

@ -54,8 +54,11 @@ public:
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) = 0; virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) = 0;
virtual void LoadBinaryStory(const std::string &filename) = 0; virtual void LoadBinaryStory(const std::string &filename) = 0;
virtual void ToggleBreakpoint(int line) = 0; virtual void ToggleBreakpoint(int line) = 0;
virtual uint32_t GetRegister(int reg) = 0;
virtual void Play() = 0; virtual void Play() = 0;
virtual void Step() = 0;
virtual void Run() = 0;
virtual void Ok() = 0; virtual void Ok() = 0;
virtual void Stop() = 0; virtual void Stop() = 0;
virtual void Pause() = 0; virtual void Pause() = 0;

View file

@ -24,6 +24,7 @@ MainWindow::MainWindow()
: m_libraryManager(*this) : m_libraryManager(*this)
, m_emulatorWindow(*this) , m_emulatorWindow(*this)
, m_codeEditorWindow(*this) , m_codeEditorWindow(*this)
, m_cpuWindow(*this)
, m_resourcesWindow(*this) , m_resourcesWindow(*this)
, m_nodeEditorWindow(*this) , m_nodeEditorWindow(*this)
, m_libraryWindow(*this, m_libraryManager) , m_libraryWindow(*this, m_libraryManager)
@ -77,11 +78,22 @@ void MainWindow::Play()
} }
void MainWindow::Step()
{
m_eventQueue.push({VmEventType::EvStep});
}
void MainWindow::Run()
{
m_eventQueue.push({VmEventType::EvRun});
}
void MainWindow::Ok() void MainWindow::Ok()
{ {
m_eventQueue.push({VmEventType::EvOkButton}); m_eventQueue.push({VmEventType::EvOkButton});
} }
void MainWindow::Stop() void MainWindow::Stop()
{ {
m_eventQueue.push({VmEventType::EvOkButton}); m_eventQueue.push({VmEventType::EvOkButton});
@ -160,6 +172,12 @@ void MainWindow::ProcessStory()
{ {
if (event.type == VmEventType::EvStep) if (event.type == VmEventType::EvStep)
{ {
StepInstruction();
m_dbg.run_result = VM_OK;
}
else if (event.type == VmEventType::EvRun)
{
m_dbg.free_run = true;
m_dbg.run_result = VM_OK; m_dbg.run_result = VM_OK;
} }
else if (event.type == VmEventType::EvOkButton) else if (event.type == VmEventType::EvOkButton)
@ -191,13 +209,17 @@ void MainWindow::ProcessStory()
if (m_dbg.run_result == VM_OK) if (m_dbg.run_result == VM_OK)
{ {
if (m_dbg.m_breakpoints.contains(m_dbg.line + 1)) if (m_dbg.m_breakpoints.contains(m_dbg.line))
{ {
// Log("Breakpoint on line: " + std::to_string(m_dbg.line + 1)); // Log("Breakpoint on line: " + std::to_string(m_dbg.line + 1));
m_dbg.run_result = VM_WAIT_EVENT;
m_dbg.free_run = false; m_dbg.free_run = false;
return;
} }
StepInstruction();
if (m_dbg.free_run)
{
StepInstruction();
}
} }
if (m_dbg.run_result == VM_FINISHED) if (m_dbg.run_result == VM_FINISHED)
@ -729,6 +751,7 @@ void MainWindow::OpenProject(const std::string &uuid)
m_codeEditorWindow.Enable(); m_codeEditorWindow.Enable();
m_resourcesWindow.Enable(); m_resourcesWindow.Enable();
m_PropertiesWindow.Enable(); m_PropertiesWindow.Enable();
m_cpuWindow.Enable();
} }
else else
{ {
@ -780,6 +803,7 @@ void MainWindow::CloseProject()
m_codeEditorWindow.Disable(); m_codeEditorWindow.Disable();
m_resourcesWindow.Disable(); m_resourcesWindow.Disable();
m_PropertiesWindow.Disable(); m_PropertiesWindow.Disable();
m_cpuWindow.Disable();
RefreshProjectInformation(); RefreshProjectInformation();
} }
@ -859,6 +883,7 @@ void MainWindow::Loop()
m_codeEditorWindow.Draw(); m_codeEditorWindow.Draw();
m_resourcesWindow.Draw(); m_resourcesWindow.Draw();
m_nodeEditorWindow.Draw(); m_nodeEditorWindow.Draw();
m_cpuWindow.Draw();
m_PropertiesWindow.SetSelectedNode(m_nodeEditorWindow.GetSelectedNode()); m_PropertiesWindow.SetSelectedNode(m_nodeEditorWindow.GetSelectedNode());
@ -982,6 +1007,18 @@ void MainWindow::ToggleBreakpoint(int line)
} }
} }
uint32_t MainWindow::GetRegister(int reg)
{
uint32_t regVal = 0;
if (reg >= 0 && reg < REGISTER_COUNT)
{
regVal = m_chip32_ctx.registers[reg];
}
return regVal;
}
void MainWindow::BuildNodes(bool compileonly) void MainWindow::BuildNodes(bool compileonly)
{ {
if (m_story->GenerateScript(m_currentCode)) if (m_story->GenerateScript(m_currentCode))
@ -1060,11 +1097,10 @@ void MainWindow::UpdateVmView()
// Highlight next line in the test editor // Highlight next line in the test editor
uint32_t pcVal = m_chip32_ctx.registers[PC]; uint32_t pcVal = m_chip32_ctx.registers[PC];
uint32_t line = 1; if (m_story->GetAssemblyLine(pcVal, m_dbg.line))
if (m_story->GetAssemblyLine(pcVal, line))
{ {
m_dbg.line = (line - 1);
m_codeEditorWindow.HighlightLine(m_dbg.line); m_codeEditorWindow.HighlightLine(m_dbg.line);
std::cout << "Executing line: " << m_dbg.line << std::endl;
} }
else else
{ {

View file

@ -21,13 +21,14 @@
#include "audio_player.h" #include "audio_player.h"
#include "library_manager.h" #include "library_manager.h"
#include "library_window.h" #include "library_window.h"
#include "cpu_window.h"
struct DebugContext struct DebugContext
{ {
uint32_t event_mask{0}; uint32_t event_mask{0};
bool wait_event{0}; bool wait_event{0};
bool free_run{false}; bool free_run{false};
int line{-1}; uint32_t line{0};
chip32_result_t run_result{VM_FINISHED}; chip32_result_t run_result{VM_FINISHED};
std::set<int> m_breakpoints; std::set<int> m_breakpoints;
@ -73,7 +74,7 @@ public:
void Loop(); void Loop();
private: private:
enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished, EvStop}; enum VmEventType { EvNoEvent, EvStep, EvRun, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished, EvStop};
std::shared_ptr<StoryProject> m_story; std::shared_ptr<StoryProject> m_story;
@ -98,6 +99,7 @@ private:
EmulatorWindow m_emulatorWindow; EmulatorWindow m_emulatorWindow;
ConsoleWindow m_consoleWindow; ConsoleWindow m_consoleWindow;
CodeEditor m_codeEditorWindow; CodeEditor m_codeEditorWindow;
CpuWindow m_cpuWindow;
char m_project_name[256] = ""; char m_project_name[256] = "";
@ -140,8 +142,11 @@ private:
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) override; virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(const std::string &nodeId) override;
virtual void LoadBinaryStory(const std::string &filename) override; virtual void LoadBinaryStory(const std::string &filename) override;
virtual void ToggleBreakpoint(int line) override; virtual void ToggleBreakpoint(int line) override;
virtual uint32_t GetRegister(int reg) override;
virtual void Play() override; virtual void Play() override;
virtual void Step() override;
virtual void Run() override;
virtual void Ok() override; virtual void Ok() override;
virtual void Stop() override; virtual void Stop() override;
virtual void Pause() override; virtual void Pause() override;

View file

@ -40,7 +40,7 @@ public:
void SetId(const std::string &id) { m_uuid = id; } void SetId(const std::string &id) { m_uuid = id; }
std::string GetId() const { return m_uuid; } std::string GetId() const { return m_uuid; }
void SeTitle(const std::string &title) { m_title = title; } void SetTitle(const std::string &title) { m_title = title; }
std::string GetTitle() const { return m_title; } std::string GetTitle() const { return m_title; }
void FromJson(const nlohmann::json &); void FromJson(const nlohmann::json &);

View file

@ -46,8 +46,6 @@ std::string MediaNode::GenerateConstants(IStoryProject &story, int nb_out_conns)
s += StoryProject::FileToConstant(m_sound, story.SoundExtension(m_sound)); // FIXME: Generate the extension setup in user option of output format s += StoryProject::FileToConstant(m_sound, story.SoundExtension(m_sound)); // FIXME: Generate the extension setup in user option of output format
} }
// Generate choice table if needed (out ports > 1) // Generate choice table if needed (out ports > 1)
std::stringstream ss; std::stringstream ss;
std::string label = ChoiceLabel(GetId()); std::string label = ChoiceLabel(GetId());
@ -121,7 +119,7 @@ std::string MediaNode::Build(IStoryProject &story, int nb_out_conns)
if (img.size() > 0) if (img.size() > 0)
{ {
ss << "lcons r0, $" << img << "\n"; ss << "lcons r0, $" << m_image << "\n";
} }
else else
{ {
@ -130,7 +128,7 @@ std::string MediaNode::Build(IStoryProject &story, int nb_out_conns)
if (snd.size() > 0) if (snd.size() > 0)
{ {
ss << "lcons r1, $" << snd << "\n"; ss << "lcons r1, $" << m_sound << "\n";
} }
else else
{ {

View file

@ -21,10 +21,20 @@ void PropertiesWindow::Draw()
ImGui::SeparatorText("Selected node"); ImGui::SeparatorText("Selected node");
static std::shared_ptr<BaseNodeWidget> prev;
if (m_selectedNode) if (m_selectedNode)
{ {
static char buf1[32] = ""; ImGui::InputText("Title", buf1, 32); static char buf1[100] = "";
if (prev != m_selectedNode)
{
prev = m_selectedNode;
// auto t = m_selectedNode->Base()->GetTitle();
strncpy (buf1, m_selectedNode->Base()->GetTitle().data(), sizeof(buf1)) ;
}
ImGui::InputText("Title", buf1, 32);
m_selectedNode->Base()->SetTitle(buf1);
ImGui::Text("Node ID: %s", m_selectedNode->Base()->GetId().data()); ImGui::Text("Node ID: %s", m_selectedNode->Base()->GetId().data());
m_selectedNode->DrawProperties(); m_selectedNode->DrawProperties();
} }

View file

@ -22,7 +22,7 @@ ResourcesWindow::~ResourcesWindow()
void ResourcesWindow::ChooseFile() void ResourcesWindow::ChooseFile()
{ {
static const char * soundFormats = ".wav,.mp3,.ogg,.flac"; static const char * soundFormats = ".wav,.mp3,.ogg,.flac";
static const char * imagesFormats = ".bmp *.png *.jpg"; static const char * imagesFormats = ".bmp,.png,.jpg";
if (m_showImportDialog) if (m_showImportDialog)
{ {