diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 08c168a..0000000 --- a/.gitmodules +++ /dev/null @@ -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 diff --git a/firmware/chip32/chip32-syntax/LICENSE b/firmware/chip32/chip32-syntax/LICENSE new file mode 100644 index 0000000..652bdbb --- /dev/null +++ b/firmware/chip32/chip32-syntax/LICENSE @@ -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. diff --git a/firmware/chip32/chip32-syntax/chip32-syntax-0.0.1.vsix b/firmware/chip32/chip32-syntax/chip32-syntax-0.0.1.vsix new file mode 100644 index 0000000..3720416 Binary files /dev/null and b/firmware/chip32/chip32-syntax/chip32-syntax-0.0.1.vsix differ diff --git a/firmware/chip32/chip32-syntax/package.json b/firmware/chip32/chip32-syntax/package.json new file mode 100644 index 0000000..6c1d8ad --- /dev/null +++ b/firmware/chip32/chip32-syntax/package.json @@ -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" + }] + } +} \ No newline at end of file diff --git a/firmware/chip32/chip32-syntax/syntaxes/chip32.tmLanguage.json b/firmware/chip32/chip32-syntax/syntaxes/chip32.tmLanguage.json new file mode 100644 index 0000000..58d8ba9 --- /dev/null +++ b/firmware/chip32/chip32-syntax/syntaxes/chip32.tmLanguage.json @@ -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" +} \ No newline at end of file diff --git a/firmware/chip32/chip32_assembler.cpp b/firmware/chip32/chip32_assembler.cpp index fa2780b..7e97963 100644 --- a/firmware/chip32/chip32_assembler.cpp +++ b/firmware/chip32/chip32_assembler.cpp @@ -55,7 +55,8 @@ static const uint32_t NbRegs = sizeof(AllRegs) / sizeof(AllRegs[0]); // Keep same order than the opcodes list!! static const std::string Mnemonics[] = { "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; @@ -166,7 +167,7 @@ bool Assembler::GetRegisterName(uint8_t reg, std::string ®Name) bool Assembler::CompileMnemonicArguments(Instr &instr) { - uint8_t ra, rb; + uint8_t ra, rb, rc; switch(instr.code.opcode) { @@ -239,6 +240,16 @@ bool Assembler::CompileMnemonicArguments(Instr &instr) instr.compiledArgs.push_back(rb); instr.compiledArgs.push_back(static_cast(strtol(instr.args[2].c_str(), NULL, 0))); 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: CHIP32_CHECK(instr, false, "Unsupported mnemonic: " + instr.mnemonic); break; diff --git a/firmware/chip32/chip32_vm.c b/firmware/chip32/chip32_vm.c index 9c85b03..4e81501 100644 --- a/firmware/chip32/chip32_vm.c +++ b/firmware/chip32/chip32_vm.c @@ -85,6 +85,18 @@ static inline uint32_t _NEXT_INT (chip32_ctx_t *ctx) static const OpCode OpCodes[] = OPCODES_LIST; 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 // ======================================================================================= @@ -162,8 +174,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx) const uint8_t reg = _NEXT_BYTE; _CHECK_REGISTER_VALID(reg) _CHECK_CAN_PUSH(1) - ctx->registers[SP] -= 4; - memcpy(&ctx->ram.mem[ctx->registers[SP]], &ctx->registers[reg], sizeof(uint32_t)); + push(ctx, ctx->registers[reg]); break; } case OP_POP: @@ -171,8 +182,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx) const uint8_t reg = _NEXT_BYTE; _CHECK_REGISTER_VALID(reg) _CHECK_CAN_POP(1) - memcpy(&ctx->registers[reg], &ctx->ram.mem[ctx->registers[SP]], sizeof(uint32_t)); - ctx->registers[SP] += 4; + ctx->registers[reg] = pop(ctx); break; } case OP_CALL: @@ -181,11 +191,23 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx) const uint8_t reg = _NEXT_BYTE; _CHECK_REGISTER_VALID(reg) 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; } case OP_RET: { 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; } case OP_STORE: @@ -353,6 +375,40 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx) } 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]++; diff --git a/firmware/chip32/chip32_vm.h b/firmware/chip32/chip32_vm.h index 0dc9d65..70370a2 100644 --- a/firmware/chip32/chip32_vm.h +++ b/firmware/chip32/chip32_vm.h @@ -80,6 +80,11 @@ typedef enum 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 + // 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 } chip32_instruction_t; @@ -122,7 +127,7 @@ typedef enum // special PC, SP, - RA, + RA, // count REGISTER_COUNT } chip32_register_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 }, \ { 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_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 diff --git a/shared/story_project.cpp b/shared/story_project.cpp index bee7212..57a5bd9 100644 --- a/shared/story_project.cpp +++ b/shared/story_project.cpp @@ -380,7 +380,7 @@ bool StoryProject::GenerateScript(std::string &codeStr) // Add our utility functions std::string buffer; - std::ifstream f("scripts/media.asm"); + std::ifstream f("scripts/media.chip32"); f.seekg(0, std::ios::end); buffer.resize(f.tellg()); 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 f = SysLib::RemoveFileExtension(FileName); - return "$" + f + " DC8 \"" + f + "." + extension + "\", 8\r\n"; + return "$" + FileName + " DC8 \"" + FileName + "\", 8\r\n"; } diff --git a/story-editor/CMakeLists.txt b/story-editor/CMakeLists.txt index 322e3e3..6e760bf 100644 --- a/story-editor/CMakeLists.txt +++ b/story-editor/CMakeLists.txt @@ -207,6 +207,9 @@ set(SRCS src/properties_window.cpp src/properties_window.h + src/cpu_window.cpp + src/cpu_window.h + src/gui.h src/gui.cpp diff --git a/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp b/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp index 5b07602..4570cc5 100644 --- a/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp +++ b/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp @@ -953,7 +953,7 @@ void TextEditor::Render() if (mBreakpoints.count(lineNo + 1) != 0) { 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 diff --git a/story-editor/libs/SDL_image b/story-editor/libs/SDL_image deleted file mode 160000 index 25e816f..0000000 --- a/story-editor/libs/SDL_image +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 25e816f614dbe4aa9fdaf89c248ae283f20038f9 diff --git a/story-editor/scripts/media.asm b/story-editor/scripts/media.asm deleted file mode 100644 index 0dff347..0000000 --- a/story-editor/scripts/media.asm +++ /dev/null @@ -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 - diff --git a/story-editor/scripts/media.chip32 b/story-editor/scripts/media.chip32 new file mode 100644 index 0000000..5575517 --- /dev/null +++ b/story-editor/scripts/media.chip32 @@ -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 diff --git a/story-editor/src/code_editor.cpp b/story-editor/src/code_editor.cpp index 708ad69..60fb774 100644 --- a/story-editor/src/code_editor.cpp +++ b/story-editor/src/code_editor.cpp @@ -1,5 +1,5 @@ #include "code_editor.h" - +#include "IconsMaterialDesignIcons.h" #include #include @@ -55,8 +55,6 @@ void CodeEditor::Draw() auto cpos = mEditor.GetCursorPosition(); - - ImGui::SetWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); if (ImGui::BeginMenuBar()) { @@ -119,17 +117,26 @@ void CodeEditor::Draw() ImGui::SameLine(); 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 { - m_breakPoints.insert(cpos.mLine); + m_breakPoints.insert(cpos.mLine + 1); } 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"); diff --git a/story-editor/src/cpu_window.cpp b/story-editor/src/cpu_window.cpp new file mode 100644 index 0000000..f2a7f8a --- /dev/null +++ b/story-editor/src/cpu_window.cpp @@ -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(); +} diff --git a/story-editor/src/cpu_window.h b/story-editor/src/cpu_window.h new file mode 100644 index 0000000..bb27004 --- /dev/null +++ b/story-editor/src/cpu_window.h @@ -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; + +}; + diff --git a/story-editor/src/i_story_manager.h b/story-editor/src/i_story_manager.h index 1936e0b..6b23d17 100644 --- a/story-editor/src/i_story_manager.h +++ b/story-editor/src/i_story_manager.h @@ -54,8 +54,11 @@ public: virtual std::list> GetNodeConnections(const std::string &nodeId) = 0; virtual void LoadBinaryStory(const std::string &filename) = 0; virtual void ToggleBreakpoint(int line) = 0; + virtual uint32_t GetRegister(int reg) = 0; virtual void Play() = 0; + virtual void Step() = 0; + virtual void Run() = 0; virtual void Ok() = 0; virtual void Stop() = 0; virtual void Pause() = 0; diff --git a/story-editor/src/main_window.cpp b/story-editor/src/main_window.cpp index 539e045..d34b7af 100644 --- a/story-editor/src/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -24,6 +24,7 @@ MainWindow::MainWindow() : m_libraryManager(*this) , m_emulatorWindow(*this) , m_codeEditorWindow(*this) + , m_cpuWindow(*this) , m_resourcesWindow(*this) , m_nodeEditorWindow(*this) , 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() { m_eventQueue.push({VmEventType::EvOkButton}); } + void MainWindow::Stop() { m_eventQueue.push({VmEventType::EvOkButton}); @@ -160,6 +172,12 @@ void MainWindow::ProcessStory() { 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; } else if (event.type == VmEventType::EvOkButton) @@ -191,13 +209,17 @@ void MainWindow::ProcessStory() 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)); + m_dbg.run_result = VM_WAIT_EVENT; m_dbg.free_run = false; - return; } - StepInstruction(); + + if (m_dbg.free_run) + { + StepInstruction(); + } } if (m_dbg.run_result == VM_FINISHED) @@ -729,6 +751,7 @@ void MainWindow::OpenProject(const std::string &uuid) m_codeEditorWindow.Enable(); m_resourcesWindow.Enable(); m_PropertiesWindow.Enable(); + m_cpuWindow.Enable(); } else { @@ -780,6 +803,7 @@ void MainWindow::CloseProject() m_codeEditorWindow.Disable(); m_resourcesWindow.Disable(); m_PropertiesWindow.Disable(); + m_cpuWindow.Disable(); RefreshProjectInformation(); } @@ -859,6 +883,7 @@ void MainWindow::Loop() m_codeEditorWindow.Draw(); m_resourcesWindow.Draw(); m_nodeEditorWindow.Draw(); + m_cpuWindow.Draw(); 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) { if (m_story->GenerateScript(m_currentCode)) @@ -1060,11 +1097,10 @@ void MainWindow::UpdateVmView() // Highlight next line in the test editor uint32_t pcVal = m_chip32_ctx.registers[PC]; - uint32_t line = 1; - if (m_story->GetAssemblyLine(pcVal, line)) + if (m_story->GetAssemblyLine(pcVal, m_dbg.line)) { - m_dbg.line = (line - 1); m_codeEditorWindow.HighlightLine(m_dbg.line); + std::cout << "Executing line: " << m_dbg.line << std::endl; } else { diff --git a/story-editor/src/main_window.h b/story-editor/src/main_window.h index 5004bc0..1a03f62 100644 --- a/story-editor/src/main_window.h +++ b/story-editor/src/main_window.h @@ -21,13 +21,14 @@ #include "audio_player.h" #include "library_manager.h" #include "library_window.h" +#include "cpu_window.h" struct DebugContext { uint32_t event_mask{0}; bool wait_event{0}; bool free_run{false}; - int line{-1}; + uint32_t line{0}; chip32_result_t run_result{VM_FINISHED}; std::set m_breakpoints; @@ -73,7 +74,7 @@ public: void Loop(); private: - enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished, EvStop}; + enum VmEventType { EvNoEvent, EvStep, EvRun, EvOkButton, EvPreviousButton, EvNextButton, EvAudioFinished, EvStop}; std::shared_ptr m_story; @@ -98,6 +99,7 @@ private: EmulatorWindow m_emulatorWindow; ConsoleWindow m_consoleWindow; CodeEditor m_codeEditorWindow; + CpuWindow m_cpuWindow; char m_project_name[256] = ""; @@ -140,8 +142,11 @@ private: virtual std::list> GetNodeConnections(const std::string &nodeId) override; virtual void LoadBinaryStory(const std::string &filename) override; virtual void ToggleBreakpoint(int line) override; + virtual uint32_t GetRegister(int reg) override; virtual void Play() override; + virtual void Step() override; + virtual void Run() override; virtual void Ok() override; virtual void Stop() override; virtual void Pause() override; diff --git a/story-editor/src/node_engine/base_node.h b/story-editor/src/node_engine/base_node.h index 6cdba04..4b42c8d 100644 --- a/story-editor/src/node_engine/base_node.h +++ b/story-editor/src/node_engine/base_node.h @@ -40,7 +40,7 @@ public: void SetId(const std::string &id) { m_uuid = id; } 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; } void FromJson(const nlohmann::json &); diff --git a/story-editor/src/node_engine/media_node.cpp b/story-editor/src/node_engine/media_node.cpp index e5154f3..4de0b0b 100644 --- a/story-editor/src/node_engine/media_node.cpp +++ b/story-editor/src/node_engine/media_node.cpp @@ -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 } - - // Generate choice table if needed (out ports > 1) std::stringstream ss; std::string label = ChoiceLabel(GetId()); @@ -121,7 +119,7 @@ std::string MediaNode::Build(IStoryProject &story, int nb_out_conns) if (img.size() > 0) { - ss << "lcons r0, $" << img << "\n"; + ss << "lcons r0, $" << m_image << "\n"; } else { @@ -130,7 +128,7 @@ std::string MediaNode::Build(IStoryProject &story, int nb_out_conns) if (snd.size() > 0) { - ss << "lcons r1, $" << snd << "\n"; + ss << "lcons r1, $" << m_sound << "\n"; } else { diff --git a/story-editor/src/properties_window.cpp b/story-editor/src/properties_window.cpp index cb16e65..b6a4efd 100644 --- a/story-editor/src/properties_window.cpp +++ b/story-editor/src/properties_window.cpp @@ -21,10 +21,20 @@ void PropertiesWindow::Draw() ImGui::SeparatorText("Selected node"); - + static std::shared_ptr prev; 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()); m_selectedNode->DrawProperties(); } diff --git a/story-editor/src/resources_window.cpp b/story-editor/src/resources_window.cpp index 06bfe75..d55fd2c 100644 --- a/story-editor/src/resources_window.cpp +++ b/story-editor/src/resources_window.cpp @@ -22,7 +22,7 @@ ResourcesWindow::~ResourcesWindow() void ResourcesWindow::ChooseFile() { 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) {