From fcc3562ecd6e761a038830618c198a71b9f6eb94 Mon Sep 17 00:00:00 2001 From: "anthony@rabine.fr" Date: Thu, 23 May 2024 15:33:04 +0200 Subject: [PATCH] Add comparison chip32 instructions, add debugger, add CPU window --- .gitmodules | 3 - firmware/chip32/chip32-syntax/LICENSE | 21 ++++++ .../chip32-syntax/chip32-syntax-0.0.1.vsix | Bin 0 -> 2951 bytes firmware/chip32/chip32-syntax/package.json | 29 ++++++++ .../syntaxes/chip32.tmLanguage.json | 27 +++++++ firmware/chip32/chip32_assembler.cpp | 15 +++- firmware/chip32/chip32_vm.c | 64 +++++++++++++++- firmware/chip32/chip32_vm.h | 12 ++- shared/story_project.cpp | 4 +- story-editor/CMakeLists.txt | 3 + .../libs/ImGuiColorTextEdit/TextEditor.cpp | 2 +- story-editor/libs/SDL_image | 1 - story-editor/scripts/media.asm | 47 ------------ story-editor/scripts/media.chip32 | 70 ++++++++++++++++++ story-editor/src/code_editor.cpp | 21 ++++-- story-editor/src/cpu_window.cpp | 63 ++++++++++++++++ story-editor/src/cpu_window.h | 19 +++++ story-editor/src/i_story_manager.h | 3 + story-editor/src/main_window.cpp | 48 ++++++++++-- story-editor/src/main_window.h | 9 ++- story-editor/src/node_engine/base_node.h | 2 +- story-editor/src/node_engine/media_node.cpp | 6 +- story-editor/src/properties_window.cpp | 14 +++- story-editor/src/resources_window.cpp | 2 +- 24 files changed, 399 insertions(+), 86 deletions(-) delete mode 100644 .gitmodules create mode 100644 firmware/chip32/chip32-syntax/LICENSE create mode 100644 firmware/chip32/chip32-syntax/chip32-syntax-0.0.1.vsix create mode 100644 firmware/chip32/chip32-syntax/package.json create mode 100644 firmware/chip32/chip32-syntax/syntaxes/chip32.tmLanguage.json delete mode 160000 story-editor/libs/SDL_image delete mode 100644 story-editor/scripts/media.asm create mode 100644 story-editor/scripts/media.chip32 create mode 100644 story-editor/src/cpu_window.cpp create mode 100644 story-editor/src/cpu_window.h 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 0000000000000000000000000000000000000000..3720416ff69d128a3236dcc9213fe123562fb107 GIT binary patch literal 2951 zcmai0c|6qZ-X1)|#2`zo628xkTrV@r4#Vk{$3 zA&+%Xk%y+N*|%(E;*9q_b#y-Ge9rgx$M3%Xx$fnBHVOBd%3#>VB2gv&?B(JIx>#OD~GO9-oW`R z)`TP3yte~G+Hx%EV1f_ygI#Rj#eBB7O(`K1ak?_ zau&T0Aua_++bZgXPmQW4B4@2I995s|L$U_0kDD&zF!(5VQ`ew)yoN7tUrp7cg`-+S z%CKo&;XR5gbo(-IrDK@KsWpftKU~w5a?vLJHR$cUOHkOWjQM@P6JjT1h*z=>!m9B;GN~T5@ zqwU9l41w@ZJkIxy9L5rrmYQ{UQXvrC+@{Et-0u_WCwbJwiv1Rj6-*FB%-tQDLK?x* z=Zo4ewb){OYf6Y6eSAfkQVKFxCSosD$EKy0O@90Q&f5mFMS~+Xohu==qQP5}?B^da zo>7IeQBqq^-!4th-|QtOT=B;*_am&wD(X7FotMa$^Gl2_?=5XsZvFU|Hea^Su>{aG zu0rhItMxLGKPfsgA552MnvX_hFJqRSlXd|XzjT3{&mMuyRKGL}03g8p+Z*_znSFqD zvR#w3*I$^>nlF$l1V8DTydD|8v&1FVtaF!R!wa;_>bBWye|`|B)gX*q@#722Uf2yy z?bvqRVU6mz7S7i2(p;%lj}x{Vnw0Il0@`uS!tVmvks3%74GC_jWTe3@wWNqu9rOEn z0n)=_!85(a^GT+5%bzZY`jgmWpKV6g@0@0C@qTO2B;B5?0?Iv>1shJ29&&rY+KZo{ z(zF|EjPckr5n$4H*a}LxW7BL)k4!4QXso?Dh9IF4!mZeL+<^NZR7q+3s_=B1Q3} z)sA$&C$OGddn0!w42Qtw4l}1NgB#nfb$DEV%891{eU~{=RPxjX7x<(6^UD%Kxz14} z2OHq~iW=veTqPjKa?##WR)^%CqH$;9leowP5pGBS9(hlqBB5ZstjATMs565TK_awl zkR`atM$--^z!1+!n#$C?hi%Mj2+p1w!QSsLn=M$VCs%OVV2x5y7fg{VMr-c_wNXAPaJzWU zKC1w^syHjoa?cVj&ysa*Y?r<5AM*5RJ%|~Z^Wj8t?AcdFuMgqeIxHvN7!_vhWu`nA z$akiUIS;%0)o!aZ^mbV-;2fZW=uwAYW)vy?2KZ-t?(3If^{ak=2`ME%Cl?zcH zfG;}mq5h>77&u~?5hMHg)G@yiZhw|Thgs2{CSD%=1*$}6q4JE)kCtyJq5=-2=B)({ zx+Ca#_<9473aNT3Tv3to_V%DQRXEnZa0a_)lQz;FJ=7hotvZAsbUCZ@2;%VNC`1 z>OYJc;B3_AU4KS9qvn*U9qds0=vs$EhGLvM?6?!|xj2$0msU7}yEOhxvmGSr67x0j(`A?gxnGPXAP9|hBDe)8xp;c{shoylZ<;%yJpzAlmu-dceX9q4 z{zW0bm?QUtDNrVb>j=N`t{$GZw-r&8t%RcC>H_z)GgOfq0N~G|Jl~3FQSnENa2;=1G?mD zg=oL=vD&ULCv}m|J$F@!mM}sO^=xF7EUyapsIjzOtO=~1{n(xy$g0%IQTyrntxQQD z6YZV|nI1U>xTFo~hJ`Tu)PRrdb&fjgoYA;#592uquYaFm!=*xHVsCwTex20haKc)4 z7jJbOZ%i{*aAVD>dR9oP-OCY69~;x{zcJTrxyGKRyuRBf)D_)vSUr+yZc)_1Lnl}@C_a3I7<~PyeYnp2uy%JK{K)v?;eNOXZGTK2R zhA1VW=_5T#dcE`R4nx}%v_XF!yDhV#`8U*~TiuO8#bV@L9k(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) {