├── .gitignore ├── risc-example ├── riscv ├── meson.build ├── subprojects │ └── kern │ │ ├── source │ │ └── main.cpp │ │ ├── meson.build │ │ └── include │ │ └── types.hpp └── linker.ld ├── emulator ├── external │ ├── glad │ │ ├── CMakeLists.txt │ │ └── include │ │ │ └── KHR │ │ │ └── khrplatform.h │ └── ImGui │ │ ├── CMakeLists.txt │ │ ├── include │ │ ├── imgui_vc_extensions.h │ │ ├── imgui_impl_glfw.h │ │ ├── imgui_freetype.h │ │ ├── imgui_impl_opengl3.h │ │ ├── imconfig.h │ │ ├── TextEditor.h │ │ ├── imnodes.h │ │ └── imstb_rectpack.h │ │ └── source │ │ └── imgui_vc_extensions.cpp ├── source │ ├── main.cpp │ ├── ui │ │ └── window.cpp │ └── devices │ │ └── cpu │ │ └── core │ │ └── core.cpp ├── include │ ├── risc.hpp │ ├── devices │ │ ├── device.hpp │ │ ├── cpu │ │ │ ├── core │ │ │ │ ├── io_pin.hpp │ │ │ │ ├── mmio │ │ │ │ │ ├── memory.hpp │ │ │ │ │ ├── device.hpp │ │ │ │ │ ├── uart.hpp │ │ │ │ │ └── gpio.hpp │ │ │ │ ├── core.hpp │ │ │ │ ├── registers.hpp │ │ │ │ ├── address_space.hpp │ │ │ │ └── instructions.hpp │ │ │ └── cpu.hpp │ │ ├── led.hpp │ │ ├── button.hpp │ │ └── pin_header.hpp │ ├── ui │ │ ├── views │ │ │ ├── view.hpp │ │ │ ├── view_pcb.hpp │ │ │ └── view_control.hpp │ │ └── window.hpp │ ├── log.hpp │ ├── board │ │ ├── board_test.hpp │ │ ├── board.hpp │ │ └── track.hpp │ ├── utils.hpp │ └── elf.hpp └── CMakeLists.txt ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | emulator/.idea 2 | emulator/cmake-build-* 3 | risc-example/build 4 | -------------------------------------------------------------------------------- /risc-example/riscv: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'clang' 3 | cpp = 'clang++' 4 | ar = 'llvm-ar' 5 | strip = 'llvm-strip' 6 | 7 | [properties] 8 | needs_exe_wrapper = true -------------------------------------------------------------------------------- /emulator/external/glad/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(glad) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") 7 | 8 | add_library(glad STATIC 9 | source/glad.c 10 | ) 11 | 12 | target_include_directories(glad PUBLIC include) 13 | 14 | target_link_libraries(glad PRIVATE dl) -------------------------------------------------------------------------------- /emulator/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | int main() { 8 | vc::ui::Window window; 9 | vc::pcb::TestBoard board; 10 | 11 | 12 | window.addView(board); 13 | window.addView(board); 14 | 15 | window.loop(); 16 | } -------------------------------------------------------------------------------- /emulator/include/risc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | using u8 = std::uint8_t; 7 | using u16 = std::uint16_t; 8 | using u32 = std::uint32_t; 9 | using u64 = std::uint64_t; 10 | 11 | using i8 = std::int8_t; 12 | using i16 = std::int16_t; 13 | using i32 = std::int32_t; 14 | using i64 = std::int64_t; 15 | 16 | #define NO_MANGLE extern "C" 17 | #define PACKED [[gnu::packed]] -------------------------------------------------------------------------------- /emulator/include/devices/device.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #define IMGUI_DEFINE_MATH_OPERATORS 5 | #include 6 | #include 7 | 8 | namespace vc::dev { 9 | 10 | class Device { 11 | public: 12 | Device() = default; 13 | virtual ~Device() = default; 14 | 15 | virtual void tick() = 0; 16 | virtual bool needsUpdate() = 0; 17 | virtual void reset() = 0; 18 | }; 19 | 20 | } -------------------------------------------------------------------------------- /risc-example/meson.build: -------------------------------------------------------------------------------- 1 | project('riscv-example', 2 | [ 'c', 'cpp' ], 3 | license: [ 'GPLv2' ], 4 | default_options: [ 'c_std=c11', 'cpp_std=c++2a', 'b_asneeded=false', 'b_lundef=false'], 5 | version: '1.0.0' 6 | ) 7 | 8 | c_args = [ '--target=riscv64' ] 9 | cpp_args = [ ] + c_args 10 | 11 | # Make sure the project gets cross compiled 12 | assert(meson.is_cross_build(), 'This project can only be cross-compiled. Make sure to call meson with the "--cross-file=asgard" option!') 13 | 14 | 15 | kernel = subproject('kern').get_variable('dep') -------------------------------------------------------------------------------- /emulator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(RISC_Console) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | find_package(fmt REQUIRED) 7 | 8 | add_executable(RISC_Console 9 | source/devices/cpu/core/core.cpp 10 | 11 | source/ui/window.cpp 12 | 13 | source/main.cpp 14 | ) 15 | 16 | #add_definitions("-DDEBUG") 17 | 18 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui) 19 | 20 | target_include_directories(RISC_Console PUBLIC include ${FMT_INCLUDE_DIRS}) 21 | target_link_libraries(RISC_Console PUBLIC fmt imgui) -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/io_pin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace vc::dev::cpu { 4 | 5 | class IOPin { 6 | public: 7 | [[nodiscard]] 8 | auto getValue() { 9 | auto copy = this->value; 10 | this->value.reset(); 11 | return copy; 12 | } 13 | 14 | void setValue(u8 value) { 15 | this->value = value; 16 | } 17 | 18 | [[nodiscard]] 19 | bool hasValue() { 20 | return this->value.has_value(); 21 | } 22 | private: 23 | std::optional value; 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /emulator/include/ui/views/view.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace vc::ui { 13 | 14 | class View { 15 | public: 16 | explicit View(std::string_view name) : viewName(name) { } 17 | virtual ~View() = default; 18 | 19 | virtual void drawContent() = 0; 20 | 21 | virtual void draw() final { 22 | if (ImGui::Begin(this->viewName.c_str())) { 23 | this->drawContent(); 24 | ImGui::End(); 25 | } 26 | } 27 | 28 | private: 29 | std::string viewName; 30 | }; 31 | 32 | } -------------------------------------------------------------------------------- /risc-example/subprojects/kern/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print(const char* string) { 4 | char *UARTA_TX = reinterpret_cast(0x5000'0004); 5 | 6 | for (const char* s = string; *s != 0x00; s++) 7 | *UARTA_TX = *s; 8 | } 9 | 10 | int main() { 11 | print("Hello RISC-V!\n"); 12 | 13 | volatile u8 *GPIOA_CR = reinterpret_cast(0x6000'0000); 14 | volatile u8 *GPIOA_IN = reinterpret_cast(0x6000'0004); 15 | volatile u8 *GPIOA_OUT = reinterpret_cast(0x6000'0008); 16 | 17 | *GPIOA_CR = 0b10; 18 | while (true) { 19 | if (*GPIOA_IN == 0b01) 20 | *GPIOA_OUT = 0b10; 21 | else 22 | *GPIOA_OUT = 0b00; 23 | } 24 | } 25 | 26 | [[gnu::section(".crt0")]] 27 | [[gnu::naked]] 28 | extern "C" void _start() { 29 | asm("lui sp, 0x10020"); 30 | asm("tail main"); 31 | } -------------------------------------------------------------------------------- /emulator/include/ui/views/view_pcb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #define IMGUI_DEFINE_MATH_OPERATORS 12 | #include 13 | 14 | namespace vc::ui { 15 | 16 | class ViewPCB : public View { 17 | public: 18 | explicit ViewPCB(pcb::Board &board) : View("PCB"), board(board) { } 19 | 20 | void drawContent() override { 21 | auto drawList = ImGui::GetWindowDrawList(); 22 | auto windowPos = ImGui::GetWindowPos(); 23 | auto windowSize = ImGui::GetWindowSize(); 24 | 25 | board.setPosition(windowPos + (windowSize - board.getDimensions()) / 2); 26 | board.draw(drawList); 27 | } 28 | 29 | private: 30 | pcb::Board &board; 31 | std::string console = "Console: "; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /emulator/include/ui/window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct GLFWwindow; 8 | 9 | namespace vc::ui { 10 | 11 | class View; 12 | 13 | class Window { 14 | public: 15 | Window(); 16 | ~Window(); 17 | 18 | void loop(); 19 | 20 | template 21 | auto& addView(Args&&... args) { 22 | auto view = new T(std::forward(args)...); 23 | this->views.push_back(view); 24 | 25 | return *view; 26 | } 27 | 28 | private: 29 | void frameBegin(); 30 | void frame(); 31 | void frameEnd(); 32 | 33 | void initGLFW(); 34 | void initImGui(); 35 | void deinitGLFW(); 36 | void deinitImGui(); 37 | 38 | GLFWwindow *windowHandle = nullptr; 39 | 40 | double targetFps = 60.0; 41 | double lastFrameTime = 0.0; 42 | 43 | std::vector views; 44 | }; 45 | 46 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/mmio/memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace vc::dev::cpu::mmio { 8 | 9 | class Memory : public MMIODevice { 10 | public: 11 | Memory(u64 base, size_t size) : MMIODevice("Internal Memory", base, size) { 12 | this->data.resize(size); 13 | } 14 | 15 | [[nodiscard]] 16 | u8& byte(u64 offset) noexcept override { 17 | return this->data[offset]; 18 | } 19 | 20 | [[nodiscard]] 21 | u16& halfWord(u64 offset) noexcept override { 22 | return *reinterpret_cast(&this->data[offset]); 23 | } 24 | 25 | [[nodiscard]] 26 | u32& word(u64 offset) noexcept override { 27 | return *reinterpret_cast(&this->data[offset]); 28 | } 29 | 30 | [[nodiscard]] 31 | u64& doubleWord(u64 offset) noexcept override { 32 | return *reinterpret_cast(&this->data[offset]); 33 | } 34 | 35 | private: 36 | std::vector data; 37 | }; 38 | 39 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /risc-example/subprojects/kern/meson.build: -------------------------------------------------------------------------------- 1 | project('kernel', 2 | [ 'c', 'cpp' ], 3 | license: [ 'GPLv2' ], 4 | default_options: [ 'c_std=c11', 'cpp_std=c++2a', 'b_asneeded=false', 'b_lundef=false'], 5 | version: '1.0.0' 6 | ) 7 | 8 | c_args = [ '--target=riscv64', '-mno-relax' ] 9 | cpp_args = [ ] + c_args 10 | link_args = [ '--target=riscv64', '-ffreestanding', '-nodefaultlibs', '-fuse-ld=lld', '-T../linker.ld' ] 11 | 12 | # Make sure the project gets cross compiled 13 | assert(meson.is_cross_build(), 'This project can only be cross-compiled. Make sure to call meson with the "--cross-file=asgard" option!') 14 | 15 | 16 | # Source files and include directories 17 | source_files = [ 18 | 'source/main.cpp', 19 | ] 20 | 21 | include_dirs = include_directories('include') 22 | 23 | 24 | # Executable building 25 | elf = executable( 26 | 'kernel.elf', 27 | source_files, 28 | native: false, 29 | c_args: c_args, 30 | cpp_args: cpp_args, 31 | link_args: link_args, 32 | name_prefix: '', 33 | dependencies: [ ], 34 | include_directories: include_dirs 35 | ) 36 | 37 | dep = declare_dependency(include_directories: include_dirs, link_with: elf) -------------------------------------------------------------------------------- /emulator/include/devices/led.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vc::dev { 6 | 7 | class LED : public Device, public pcb::Connectable { 8 | public: 9 | explicit LED(ImVec2 pos) { 10 | this->setPosition(pos); 11 | this->setSize({ 20, 10 }); 12 | } 13 | 14 | auto get(std::string_view name) { 15 | return this->getTrack(name); 16 | } 17 | 18 | void tick() override { 19 | for (auto &trackName : this->getConnectedTrackNames()) { 20 | auto track = this->getTrack(trackName); 21 | 22 | if (track->hasValue()) 23 | glowing = track->getValue().value(); 24 | } 25 | } 26 | 27 | bool needsUpdate() override { return true; } 28 | void reset() override { 29 | glowing = false; 30 | } 31 | 32 | void draw(ImVec2 start, ImDrawList *drawList) override { 33 | drawList->AddRectFilled(start + getPosition(), start + getPosition() + getSize(), ImColor(0xA0, 0xA0, 0xA0, 0xFF)); 34 | drawList->AddRectFilled(start + getPosition() + ImVec2(5, 0), start + getPosition() + getSize() - ImVec2(5, 0), glowing ? ImColor(0xA0, 0x10, 0x10, 0xFF) : ImColor(0x30, 0x10, 0x10, 0xFF)); 35 | } 36 | 37 | private: 38 | bool glowing = false; 39 | }; 40 | 41 | } -------------------------------------------------------------------------------- /risc-example/subprojects/kern/include/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using u8 = unsigned char; 4 | using i8 = signed char; 5 | 6 | using u16 = unsigned short; 7 | using i16 = signed short; 8 | 9 | using u32 = unsigned int; 10 | using i32 = signed int; 11 | 12 | using u64 = unsigned long; 13 | using i64 = signed long; 14 | 15 | using u128 = __uint128_t; 16 | using i128 = __int128_t; 17 | 18 | using f32 = float; 19 | using f64 = double; 20 | using f128 = long double; 21 | 22 | 23 | static_assert(sizeof(u8) == 1, "u8 type not 8 bit long!"); 24 | static_assert(sizeof(i8) == 1, "i8 type not 8 bit long!"); 25 | 26 | static_assert(sizeof(u16) == 2, "u16 type not 16 bit long!"); 27 | static_assert(sizeof(i16) == 2, "i16 type not 16 bit long!"); 28 | 29 | static_assert(sizeof(u32) == 4, "u32 type not 32 bit long!"); 30 | static_assert(sizeof(i32) == 4, "i32 type not 32 bit long!"); 31 | 32 | static_assert(sizeof(u64) == 8, "u64 type not 64 bit long!"); 33 | static_assert(sizeof(i64) == 8, "i64 type not 64 bit long!"); 34 | 35 | static_assert(sizeof(u128) == 16, "u128 type not 128 bit long!"); 36 | static_assert(sizeof(i128) == 16, "i128 type not 128 bit long!"); 37 | 38 | static_assert(sizeof(f32) == 4, "f32 type not 32 bit long!"); 39 | static_assert(sizeof(f64) == 8, "f64 type not 64 bit long!"); 40 | static_assert(sizeof(f128) == 16, "f128 type not 128 bit long!"); -------------------------------------------------------------------------------- /emulator/include/log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace vc::log { 7 | 8 | void debug(std::string_view fmt, auto ... args) { 9 | #if defined(DEBUG) 10 | fmt::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG] "); 11 | fmt::print(fmt, args...); 12 | fmt::print("\n"); 13 | fflush(stdout); 14 | #endif 15 | } 16 | 17 | void info(std::string_view fmt, auto ... args) { 18 | fmt::print(fg(fmt::color::cornflower_blue) | fmt::emphasis::bold, "[INFO] "); 19 | fmt::print(fmt, args...); 20 | fmt::print("\n"); 21 | fflush(stdout); 22 | } 23 | 24 | void warn(std::string_view fmt, auto ... args) { 25 | fmt::print(fg(fmt::color::light_golden_rod_yellow) | fmt::emphasis::bold, "[WARN] "); 26 | fmt::print(fmt, args...); 27 | fmt::print("\n"); 28 | fflush(stdout); 29 | } 30 | 31 | void error(std::string_view fmt, auto ... args) { 32 | fmt::print(fg(fmt::color::light_coral) | fmt::emphasis::bold, "[ERROR] "); 33 | fmt::print(fmt, args...); 34 | fmt::print("\n"); 35 | fflush(stdout); 36 | } 37 | 38 | void fatal(std::string_view fmt, auto ... args) { 39 | fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "[FATAL] "); 40 | fmt::print(fmt, args...); 41 | fmt::print("\n"); 42 | fflush(stdout); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /emulator/include/devices/button.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vc::dev { 6 | 7 | class Button : public Device, public pcb::Connectable { 8 | public: 9 | explicit Button(ImVec2 pos) { 10 | this->setPosition(pos); 11 | this->setSize({ 31, 31 }); 12 | } 13 | 14 | auto get(std::string_view name) { 15 | return this->getTrack(name); 16 | } 17 | 18 | void tick() override { 19 | for (auto &trackName : this->getConnectedTrackNames()) { 20 | auto track = this->getTrack(trackName); 21 | track->setValue(this->pressed); 22 | } 23 | } 24 | 25 | bool needsUpdate() override { return true; } 26 | void reset() override { 27 | pressed = false; 28 | } 29 | 30 | void draw(ImVec2 start, ImDrawList *drawList) override { 31 | this->pressed = ImGui::IsMouseHoveringRect(start + getPosition(), start + getPosition() + getSize()) && ImGui::IsMouseDown(ImGuiMouseButton_Left); 32 | 33 | drawList->AddRectFilled(start + getPosition(), start + getPosition() + getSize(), ImColor(0xA0, 0xA0, 0xA0, 0xFF)); 34 | drawList->AddCircleFilled(start + getPosition() + getSize() / 2, 9, this->pressed ? ImColor(0x80, 0x20, 0x20, 0xFF) : ImColor(0xA0, 0x20, 0x20, 0xFF)); 35 | } 36 | 37 | private: 38 | bool pressed = false; 39 | }; 40 | 41 | } -------------------------------------------------------------------------------- /emulator/external/ImGui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(imgui) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | find_package(PkgConfig REQUIRED) 7 | find_package(Freetype REQUIRED) 8 | pkg_search_module(GLM REQUIRED glm) 9 | pkg_search_module(GLFW REQUIRED glfw3) 10 | 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") 12 | 13 | add_library(imgui STATIC 14 | source/imgui.cpp 15 | source/imgui_demo.cpp 16 | source/imgui_draw.cpp 17 | source/imgui_freetype.cpp 18 | source/imgui_impl_glfw.cpp 19 | source/imgui_impl_opengl3.cpp 20 | source/imgui_tables.cpp 21 | source/imgui_widgets.cpp 22 | 23 | source/TextEditor.cpp 24 | 25 | source/imgui_vc_extensions.cpp 26 | 27 | source/imnodes.cpp 28 | 29 | source/implot.cpp 30 | source/implot_items.cpp 31 | source/implot_demo.cpp 32 | 33 | fonts/fontawesome_font.c 34 | ) 35 | 36 | add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD) 37 | 38 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../glad ${CMAKE_CURRENT_BINARY_DIR}/external/glad) 39 | 40 | target_include_directories(imgui PUBLIC include fonts ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS}) 41 | 42 | target_link_directories(imgui PUBLIC ${GLM_INCLUDE_DIRS} ${GLFW_LIBRARY_DIRS}) 43 | 44 | if (WIN32) 45 | target_link_libraries(imgui Freetype::Freetype glad glfw3) 46 | elseif (UNIX) 47 | target_link_libraries(imgui Freetype::Freetype glad glfw) 48 | endif() 49 | -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imgui_vc_extensions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace ImGui { 8 | 9 | bool Hyperlink(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); 10 | bool BulletHyperlink(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); 11 | bool DescriptionButton(const char* label, const char* description, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); 12 | 13 | void UnderlinedText(const char* label, ImColor color, const ImVec2& size_arg = ImVec2(0, 0)); 14 | 15 | void Disabled(const std::function &widgets, bool disabled); 16 | void TextSpinner(const char* label); 17 | 18 | void Header(const char *label, bool firstEntry = false); 19 | 20 | inline bool HasSecondPassed() { 21 | return static_cast(ImGui::GetTime() * 100) % 100 <= static_cast(ImGui::GetIO().DeltaTime * 100); 22 | } 23 | 24 | std::tuple LoadImageFromPath(const char *path); 25 | void UnloadImage(ImTextureID texture); 26 | 27 | enum ImGuiCustomCol { 28 | ImGuiCustomCol_DescButton, 29 | ImGuiCustomCol_DescButtonHovered, 30 | ImGuiCustomCol_DescButtonActive, 31 | ImGuiCustomCol_COUNT 32 | }; 33 | 34 | struct ImHexCustomData { 35 | ImVec4 Colors[ImGuiCustomCol_COUNT]; 36 | }; 37 | 38 | ImU32 GetCustomColorU32(ImGuiCustomCol idx, float alpha_mul = 1.0F); 39 | 40 | void StyleCustomColorsDark(); 41 | void StyleCustomColorsLight(); 42 | void StyleCustomColorsClassic(); 43 | } -------------------------------------------------------------------------------- /risc-example/linker.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1M 3 | RAM (rwx) : ORIGIN = 0x10000000, LENGTH = 2M 4 | } 5 | 6 | ENTRY(_start); 7 | 8 | SECTIONS { 9 | .crt0 : { 10 | 11 | } >FLASH 12 | 13 | .text : { 14 | *(.text) 15 | *(.text*) 16 | 17 | KEEP(*(.init)) 18 | KEEP(*(.fini)) 19 | } >RAM 20 | 21 | .rodata : { 22 | . = ALIGN(4); 23 | *(.rodata) 24 | *(.rodata*) 25 | . = ALIGN(4); 26 | } >RAM 27 | 28 | .preinit_array : { 29 | PROVIDE_HIDDEN (__preinit_array_start = .); 30 | KEEP (*(.preinit_array*)) 31 | PROVIDE_HIDDEN (__preinit_array_end = .); 32 | } >RAM 33 | 34 | .init_array : { 35 | PROVIDE_HIDDEN (__init_array_start = .); 36 | KEEP (*(SORT(.init_array.*))) 37 | KEEP (*(.init_array*)) 38 | PROVIDE_HIDDEN (__init_array_end = .); 39 | } >RAM 40 | 41 | .fini_array : { 42 | PROVIDE_HIDDEN (__fini_array_start = .); 43 | KEEP (*(SORT(.fini_array.*))) 44 | KEEP (*(.fini_array*)) 45 | PROVIDE_HIDDEN (__fini_array_end = .); 46 | } >RAM 47 | 48 | .data : { 49 | . = ALIGN(4); 50 | _data_begin_ = .; 51 | *(.data) 52 | *(.data*) 53 | 54 | . = ALIGN(4); 55 | _data_end_ = .; 56 | } >RAM 57 | 58 | .bss : { 59 | . = ALIGN(4); 60 | _bss_start_ = .; 61 | *(.bss) 62 | *(.bss*) 63 | *(COMMON) 64 | . = ALIGN(4); 65 | _bss_end_ = .; 66 | } >RAM 67 | 68 | /DISCARD/ : { 69 | *(.ARM.*) 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PCB Emulator 2 | 3 | A simple C++20 PCB Emulator 4 | 5 | ## Components 6 | 7 | - Multi-core RISC-V controller 8 | - Button 9 | - LED 10 | - Pin Header 11 | 12 | ## Example 13 | 14 | The following GIF shows the interaction between a button, and LED and a UART Pin Header with a RISC-V CPU on a custom PCB. 15 | ![](https://i.imgur.com/Jm9cIdq.gif) 16 | 17 | The RISC-V controller is currently running the following code. 18 | ```cpp 19 | #include 20 | 21 | void print(const char* string) { 22 | char *UARTA_TX = reinterpret_cast(0x5000'0004); 23 | 24 | for (const char* s = string; *s != 0x00; s++) 25 | *UARTA_TX = *s; 26 | } 27 | 28 | int main() { 29 | print("Hello RISC-V!\n"); 30 | 31 | volatile u8 *GPIOA_CR = reinterpret_cast(0x6000'0000); 32 | volatile u8 *GPIOA_IN = reinterpret_cast(0x6000'0004); 33 | volatile u8 *GPIOA_OUT = reinterpret_cast(0x6000'0008); 34 | 35 | *GPIOA_CR = 0b10; 36 | while (true) { 37 | if (*GPIOA_IN == 0b01) 38 | *GPIOA_OUT = 0b10; 39 | else 40 | *GPIOA_OUT = 0b00; 41 | } 42 | } 43 | 44 | [[gnu::section(".crt0")]] 45 | [[gnu::naked]] 46 | extern "C" void _start() { 47 | asm("lui sp, 0x10020"); 48 | asm("tail main"); 49 | } 50 | ``` 51 | 52 | The controller used on the TestBoard PCB has the following memory mappings: 53 | - `1 MiB Flash Memory` at `0x0000'0000` 54 | - `2 MiB RAM Memory` at `0x1000'0000` 55 | - `UART-A` at `0x5000'0000` 56 | - `GPIO-A` at `0x6000'0000` 57 | 58 | On-Board peripherals are connected to the following controller Pins: 59 | - `UART-A TX` on Pin 0 60 | - `Button-A` on Pin 1 61 | - `LED-A` on Pin 2 -------------------------------------------------------------------------------- /emulator/include/ui/views/view_control.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace vc::ui { 13 | 14 | class ViewControl : public View { 15 | public: 16 | explicit ViewControl(pcb::Board &board) : View("Control"), board(board) { 17 | 18 | } 19 | 20 | ~ViewControl() override { 21 | this->board.powerDown(); 22 | this->boardThread.join(); 23 | } 24 | 25 | void drawContent() override { 26 | ImGui::Disabled([this] { 27 | if (ImGui::Button("Power up PCB")) { 28 | if (!this->boardRunning) { 29 | this->boardRunning = true; 30 | this->boardThread = std::thread([this] { 31 | this->board.powerUp(); 32 | this->boardRunning = false; 33 | }); 34 | } 35 | } 36 | }, this->boardRunning); 37 | 38 | ImGui::Disabled([this] { 39 | if (ImGui::Button("Unplug PCB")) { 40 | this->board.powerDown(); 41 | } 42 | }, !this->boardRunning); 43 | 44 | if (this->boardRunning) { 45 | ImGui::TextSpinner("PCB running..."); 46 | } else if (this->boardThread.joinable()) { 47 | this->boardThread.join(); 48 | } 49 | } 50 | 51 | private: 52 | pcb::Board &board; 53 | std::thread boardThread; 54 | bool boardRunning = false; 55 | }; 56 | 57 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/mmio/device.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace vc::dev::cpu::mmio { 8 | 9 | class MMIODevice { 10 | public: 11 | MMIODevice(std::string_view name, u64 base, size_t size) : name(name), base(base), size(size) { } 12 | 13 | constexpr auto operator<=>(const MMIODevice &other) const { 14 | return this->base <=> other.base; 15 | } 16 | 17 | [[nodiscard]] 18 | constexpr auto getBase() const noexcept { 19 | return this->base; 20 | } 21 | 22 | [[nodiscard]] 23 | constexpr auto getEnd() const noexcept { 24 | return this->base + this->size - 1; 25 | } 26 | 27 | [[nodiscard]] 28 | constexpr auto getSize() const noexcept { 29 | return this->size; 30 | } 31 | 32 | virtual void doTick() noexcept final { 33 | if (needsUpdate()) { 34 | this->tick(); 35 | } 36 | } 37 | 38 | [[nodiscard]] 39 | virtual u8& byte(u64 offset) noexcept = 0; 40 | 41 | [[nodiscard]] 42 | virtual u16& halfWord(u64 offset) noexcept = 0; 43 | 44 | [[nodiscard]] 45 | virtual u32& word(u64 offset) noexcept = 0; 46 | 47 | [[nodiscard]] 48 | virtual u64& doubleWord(u64 offset) noexcept = 0; 49 | 50 | virtual bool needsUpdate() noexcept { return false; } 51 | 52 | [[nodiscard]] 53 | std::string_view getName() const { 54 | return this->name; 55 | } 56 | protected: 57 | virtual void tick() noexcept { } 58 | 59 | private: 60 | std::string name; 61 | u64 base; 62 | u64 size; 63 | }; 64 | 65 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/mmio/uart.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace vc::dev::cpu::mmio { 8 | 9 | class UART : public MMIODevice { 10 | public: 11 | UART(u64 base) : MMIODevice("UART", base, sizeof(registers)) { 12 | 13 | } 14 | 15 | [[nodiscard]] 16 | u8& byte(u64 offset) noexcept override { 17 | this->valueChanged = true; 18 | return *(reinterpret_cast(&this->registers) + offset); 19 | } 20 | 21 | [[nodiscard]] 22 | u16& halfWord(u64 offset) noexcept override { 23 | this->valueChanged = true; 24 | return *reinterpret_cast((reinterpret_cast(&this->registers) + offset)); 25 | } 26 | 27 | [[nodiscard]] 28 | u32& word(u64 offset) noexcept override { 29 | this->valueChanged = true; 30 | return *reinterpret_cast((reinterpret_cast(&this->registers) + offset)); 31 | } 32 | 33 | [[nodiscard]] 34 | u64& doubleWord(u64 offset) noexcept override { 35 | this->valueChanged = true; 36 | return *reinterpret_cast((reinterpret_cast(&this->registers) + offset)); 37 | } 38 | 39 | cpu::IOPin txPin; 40 | 41 | private: 42 | 43 | void tick() noexcept override { 44 | txPin.setValue(static_cast(registers.TX)); 45 | registers.TX = 0x00; 46 | this->valueChanged = false; 47 | } 48 | 49 | bool needsUpdate() noexcept override { 50 | return this->valueChanged; 51 | } 52 | 53 | struct { 54 | u32 CR; 55 | u32 TX; 56 | u32 RX; 57 | } registers; 58 | 59 | bool valueChanged = false; 60 | }; 61 | 62 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/mmio/gpio.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace vc::dev::cpu::mmio { 8 | 9 | class GPIO : public MMIODevice { 10 | public: 11 | GPIO(u64 base) : MMIODevice("GPIO", base, sizeof(registers)) { 12 | registers = { 0 }; 13 | } 14 | 15 | [[nodiscard]] 16 | u8& byte(u64 offset) noexcept override { 17 | return *(reinterpret_cast(&this->registers) + offset); 18 | } 19 | 20 | [[nodiscard]] 21 | u16& halfWord(u64 offset) noexcept override { 22 | return *reinterpret_cast((reinterpret_cast(&this->registers) + offset)); 23 | } 24 | 25 | [[nodiscard]] 26 | u32& word(u64 offset) noexcept override { 27 | return *reinterpret_cast((reinterpret_cast(&this->registers) + offset)); 28 | } 29 | 30 | [[nodiscard]] 31 | u64& doubleWord(u64 offset) noexcept override { 32 | return *reinterpret_cast((reinterpret_cast(&this->registers) + offset)); 33 | } 34 | 35 | std::array gpioPins; 36 | 37 | private: 38 | 39 | void tick() noexcept override { 40 | u32 offset = 0; 41 | registers.IN = 0x00; 42 | for (auto &pin : gpioPins) { 43 | if (registers.CR & (0b01 << offset)) /* Output */{ 44 | pin.setValue((static_cast(registers.OUT) & (0b01 << offset)) == 0x00 ? 0 : 1); 45 | } else /* Input */ { 46 | if (pin.hasValue()) 47 | registers.IN |= (pin.getValue().value() == 0x00 ? 0 : 1) << offset; 48 | } 49 | 50 | offset++; 51 | } 52 | } 53 | 54 | bool needsUpdate() noexcept override { 55 | return true; 56 | } 57 | 58 | struct { 59 | u32 CR; 60 | u32 IN; 61 | u32 OUT; 62 | } registers; 63 | }; 64 | 65 | } -------------------------------------------------------------------------------- /emulator/include/devices/pin_header.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vc::dev { 6 | 7 | class PinHeader : public Device, public pcb::Connectable { 8 | public: 9 | explicit PinHeader(ImVec2 pos) { 10 | this->setPosition(pos); 11 | } 12 | 13 | auto get(std::string_view name) { 14 | return this->getTrack(name); 15 | } 16 | 17 | void tick() override { } 18 | bool needsUpdate() override { return this->dataAvailable(); } 19 | void reset() override { 20 | this->receivedData.clear(); 21 | } 22 | 23 | void draw(ImVec2 start, ImDrawList *drawList) override { 24 | this->numPins = this->getConnectedTrackNames().size(); 25 | this->setSize({ 19.0F * this->numPins, 19.0F }); 26 | 27 | drawList->AddRectFilled(start + getPosition(), start + getPosition() + getSize(), ImColor(0x10, 0x10, 0x10, 0xFF)); 28 | 29 | for (auto i = 0; i < this->numPins; i++) { 30 | drawList->AddCircleFilled(ImVec2(start + getPosition() + ImVec2(9 + 19 * i, 10)), 4, ImColor(0xB0, 0xB0, 0xC0, 0xFF)); 31 | } 32 | 33 | for (auto &trackName : this->getConnectedTrackNames()) { 34 | auto c = this->get(trackName)->getValue(); 35 | if (c.has_value()) 36 | receivedData[std::string(trackName)] += (char)*c; 37 | } 38 | 39 | if (ImGui::IsMouseHoveringRect(start + getPosition(), start + getPosition() + getSize())) { 40 | ImGui::BeginTooltip(); 41 | ImGui::TextUnformatted("Connected Tracks"); 42 | ImGui::Separator(); 43 | for (auto &trackName : this->getConnectedTrackNames()) { 44 | ImGui::Text("%s: %s", trackName.data(), receivedData[std::string(trackName)].c_str()); 45 | } 46 | ImGui::EndTooltip(); 47 | } 48 | } 49 | 50 | private: 51 | u32 numPins = 1; 52 | std::map receivedData; 53 | }; 54 | 55 | } -------------------------------------------------------------------------------- /emulator/include/board/board_test.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace vc::pcb { 15 | 16 | class TestBoard : public Board { 17 | public: 18 | TestBoard() : Board("Test Board", { 500, 300 }), 19 | cpu(createDevice(1, ImVec2{ 50, 50 })), 20 | uartHeader(createDevice(ImVec2{ 200, 250 })), 21 | buttonA(createDevice(ImVec2({ 300, 250 }))), 22 | ledA(createDevice(ImVec2({ 100, 200 }))), 23 | 24 | cpuFlash(0x0000'0000, 1_MiB), 25 | cpuRam(0x1000'0000, 2_MiB), 26 | cpuUartA(0x5000'0000), 27 | cpuGpioA(0x6000'0000) { 28 | auto &cpuAddressSpace = cpu.getAddressSpace(); 29 | 30 | cpu.attachToPin(0, cpuUartA.txPin); 31 | cpu.attachToPin(1, cpuGpioA.gpioPins[0]); 32 | cpu.attachToPin(2, cpuGpioA.gpioPins[1]); 33 | 34 | cpuAddressSpace.addDevice(cpuFlash); 35 | cpuAddressSpace.addDevice(cpuRam); 36 | cpuAddressSpace.addDevice(cpuUartA); 37 | cpuAddressSpace.addDevice(cpuGpioA); 38 | 39 | cpuAddressSpace.loadELF("kernel.elf"); 40 | 41 | this->createTrack(Direction::MOSI, "uarta_tx", cpu, uartHeader, true); 42 | this->createTrack(Direction::MISO, "buttona", cpu, buttonA); 43 | this->createTrack(Direction::MOSI, "leda", cpu, ledA); 44 | cpu.attachPinToTrack(0, "uarta_tx"); 45 | cpu.attachPinToTrack(1, "buttona"); 46 | cpu.attachPinToTrack(2, "leda"); 47 | } 48 | 49 | dev::cpu::mmio::Memory cpuFlash; 50 | dev::cpu::mmio::Memory cpuRam; 51 | dev::cpu::mmio::UART cpuUartA; 52 | dev::cpu::mmio::GPIO cpuGpioA; 53 | 54 | dev::CPUDevice &cpu; 55 | dev::PinHeader &uartHeader; 56 | dev::Button &buttonA; 57 | dev::LED &ledA; 58 | }; 59 | 60 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/core.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace vc::dev::cpu { 12 | 13 | class Core { 14 | public: 15 | explicit Core(AddressSpace &addressSpace) : addressSpace(addressSpace) { } 16 | 17 | void execute(); 18 | 19 | [[nodiscard]] 20 | bool isHalted() const { return halted; } 21 | 22 | void reset() { 23 | this->regs.pc = 0x00; 24 | for (u8 r = 1; r < 32; r++) 25 | this->regs.x[r] = 0x00; 26 | this->halted = false; 27 | } 28 | 29 | void halt(std::string_view message = "", auto ... params) { 30 | if (!message.empty()) 31 | log::fatal(message, params...); 32 | 33 | log::fatal("Halted CPU Core at {:#x}", regs.pc); 34 | using namespace std::literals::chrono_literals; 35 | std::this_thread::sleep_for(200ms); 36 | this->halted = true; 37 | } 38 | 39 | private: 40 | constexpr void executeCompressedInstruction(const CompressedInstruction &instr); 41 | constexpr void executeInstruction(const Instruction &instr); 42 | 43 | constexpr void executeOPInstruction(const Instruction &instr); 44 | constexpr void executeOPIMMInstruction(const Instruction &instr); 45 | constexpr void executeOPIMM32Instruction(const Instruction &instr); 46 | constexpr void executeBRANCHInstruction(const Instruction &instr); 47 | constexpr void executeLOADInstruction(const Instruction &instr); 48 | constexpr void executeSTOREInstruction(const Instruction &instr); 49 | 50 | constexpr void executeC0Instruction(const CompressedInstruction &instr); 51 | constexpr void executeC1Instruction(const CompressedInstruction &instr); 52 | constexpr void executeC2Instruction(const CompressedInstruction &instr); 53 | 54 | u64 nextPC; 55 | bool halted = true; 56 | AddressSpace &addressSpace; 57 | Registers regs; 58 | }; 59 | 60 | } -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imgui_impl_glfw.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for GLFW 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Clipboard support. 7 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 8 | // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. 9 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). 10 | 11 | // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 12 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 13 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 14 | 15 | // About GLSL version: 16 | // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. 17 | // Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! 18 | 19 | #pragma once 20 | #include "imgui.h" // IMGUI_IMPL_API 21 | 22 | struct GLFWwindow; 23 | 24 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); 25 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); 26 | IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); 27 | IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); 28 | 29 | // GLFW callbacks 30 | // - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any. 31 | // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks. 32 | IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 33 | IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); 34 | IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 35 | IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); 36 | -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imgui_freetype.h: -------------------------------------------------------------------------------- 1 | // dear imgui: wrapper to use FreeType (instead of stb_truetype) 2 | // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype 3 | // Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut 4 | 5 | #pragma once 6 | 7 | #include "imgui.h" // IMGUI_API, ImFontAtlas 8 | 9 | namespace ImGuiFreeType 10 | { 11 | // Hinting greatly impacts visuals (and glyph sizes). 12 | // When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output. 13 | // The Default hinting mode usually looks good, but may distort glyphs in an unusual way. 14 | // The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. 15 | 16 | // You can set those flags on a per font basis in ImFontConfig::RasterizerFlags. 17 | // Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts. 18 | enum RasterizerFlags 19 | { 20 | // By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. 21 | NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. 22 | NoAutoHint = 1 << 1, // Disable auto-hinter. 23 | ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter. 24 | LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. 25 | MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. 26 | Bold = 1 << 5, // Styling: Should we artificially embolden the font? 27 | Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? 28 | Monochrome = 1 << 7 // Disable anti-aliasing. Combine this with MonoHinting for best results! 29 | }; 30 | 31 | IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); 32 | 33 | // By default ImGuiFreeType will use IM_ALLOC()/IM_FREE(). 34 | // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired: 35 | IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); 36 | } 37 | -------------------------------------------------------------------------------- /emulator/include/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define TOKEN_CONCAT_IMPL(x, y) x ## y 9 | #define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y) 10 | #define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__) 11 | 12 | namespace vc::util { 13 | 14 | template 15 | constexpr Output signExtend(auto value) { 16 | if ((value & (1 << (Bits - 1))) == 0) 17 | return value; 18 | else { 19 | std::make_unsigned_t mask = std::numeric_limits::max() << Bits; 20 | return value | mask; 21 | } 22 | } 23 | 24 | #define SCOPE_GUARD ::vc::util::scope_guard::ScopeGuardOnExit() + [&]() 25 | #define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD 26 | 27 | namespace scope_guard { 28 | 29 | template 30 | class ScopeGuardImpl { 31 | private: 32 | F m_func; 33 | bool m_active; 34 | public: 35 | constexpr ScopeGuardImpl(F func) : m_func(std::move(func)), m_active(true) { } 36 | ~ScopeGuardImpl() { if (this->m_active) { this->m_func(); } } 37 | 38 | void release() { this->m_active = false; } 39 | 40 | ScopeGuardImpl(ScopeGuardImpl &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) { 41 | other.cancel(); 42 | } 43 | 44 | ScopeGuardImpl& operator=(ScopeGuardImpl &&) = delete; 45 | }; 46 | 47 | enum class ScopeGuardOnExit { }; 48 | 49 | template 50 | constexpr ScopeGuardImpl operator+(ScopeGuardOnExit, F&& f) { 51 | return ScopeGuardImpl(std::forward(f)); 52 | } 53 | 54 | } 55 | 56 | namespace detail { 57 | template 58 | auto build_array_impl(std::index_sequence, Model&& model) 59 | { 60 | constexpr auto size = sizeof...(Is) + 1; 61 | return std::array, size> 62 | { 63 | // N-1 copies 64 | (Is, model)..., 65 | 66 | // followed by perfect forwarding for the last one 67 | std::forward(model) 68 | }; 69 | } 70 | } 71 | 72 | template 73 | auto build_array(std::integral_constant, Type&& model) { 74 | return detail::build_array_impl(std::make_index_sequence(), 75 | std::forward(model)); 76 | } 77 | 78 | } 79 | 80 | constexpr auto operator ""_kiB(unsigned long long kiB) { 81 | return kiB * 1024; 82 | } 83 | 84 | constexpr auto operator ""_MiB(unsigned long long MiB) { 85 | return operator ""_kiB(MiB) * 1024; 86 | } 87 | 88 | constexpr auto operator ""_GiB(unsigned long long GiB) { 89 | return operator ""_MiB(GiB) * 1024; 90 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/registers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace vc::dev::cpu { 4 | 5 | struct Registers { 6 | 7 | struct Register { 8 | constexpr virtual Register& operator=(u64) = 0; 9 | constexpr virtual operator u64() = 0; 10 | }; 11 | 12 | struct ZeroRegister : public Register { 13 | constexpr ZeroRegister& operator=(u64) override { return *this; } 14 | constexpr operator u64() override { return 0; } 15 | }; 16 | 17 | struct GPRegister : public Register { 18 | constexpr GPRegister& operator=(u64 v) override { this->value = v; return *this; } 19 | constexpr operator u64() override { return this->value; } 20 | private: 21 | u64 value = 0; 22 | }; 23 | 24 | struct { 25 | 26 | constexpr Register& operator[](u8 index) { 27 | if (index == 0) { 28 | return zeroRegister; 29 | } else if (index <= 31) { 30 | return gpRegisters[index]; 31 | } else { 32 | __builtin_unreachable(); 33 | } 34 | } 35 | 36 | private: 37 | ZeroRegister zeroRegister; 38 | GPRegister gpRegisters[32]; 39 | } x; 40 | 41 | GPRegister &zero = static_cast(x[0]); 42 | GPRegister &ra = static_cast(x[1]); 43 | GPRegister &sp = static_cast(x[2]); 44 | GPRegister &gp = static_cast(x[3]); 45 | GPRegister &tp = static_cast(x[4]); 46 | GPRegister &t0 = static_cast(x[5]); 47 | GPRegister &t1 = static_cast(x[6]); 48 | GPRegister &t2 = static_cast(x[7]); 49 | GPRegister &fp = static_cast(x[8]); 50 | GPRegister &s0 = static_cast(x[8]); 51 | GPRegister &s1 = static_cast(x[9]); 52 | GPRegister &a0 = static_cast(x[10]); 53 | GPRegister &a1 = static_cast(x[11]); 54 | GPRegister &a2 = static_cast(x[12]); 55 | GPRegister &a3 = static_cast(x[13]); 56 | GPRegister &a4 = static_cast(x[14]); 57 | GPRegister &a5 = static_cast(x[15]); 58 | GPRegister &a6 = static_cast(x[16]); 59 | GPRegister &a7 = static_cast(x[17]); 60 | GPRegister &s2 = static_cast(x[18]); 61 | GPRegister &s3 = static_cast(x[19]); 62 | GPRegister &s4 = static_cast(x[20]); 63 | GPRegister &s5 = static_cast(x[21]); 64 | GPRegister &s6 = static_cast(x[22]); 65 | GPRegister &s7 = static_cast(x[23]); 66 | GPRegister &s8 = static_cast(x[24]); 67 | GPRegister &s9 = static_cast(x[25]); 68 | GPRegister &s10 = static_cast(x[26]); 69 | GPRegister &s11 = static_cast(x[27]); 70 | GPRegister &t3 = static_cast(x[28]); 71 | GPRegister &t4 = static_cast(x[29]); 72 | GPRegister &t5 = static_cast(x[30]); 73 | GPRegister &t6 = static_cast(x[31]); 74 | 75 | u64 pc = 0; 76 | }; 77 | 78 | } -------------------------------------------------------------------------------- /emulator/include/board/board.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #define IMGUI_DEFINE_MATH_OPERATORS 14 | #include 15 | 16 | namespace vc::pcb { 17 | 18 | class Board { 19 | public: 20 | explicit Board(std::string_view name, ImVec2 size) : boardName(name), dimensions(size) { } 21 | virtual ~Board() { 22 | this->powerDown(); 23 | 24 | for (auto &device : this->devices) 25 | delete device; 26 | 27 | for (auto &[name, track] : this->tracks) 28 | delete track; 29 | } 30 | 31 | void powerUp() { 32 | this->hasPower = true; 33 | 34 | for (auto &device : this->devices) 35 | device->reset(); 36 | 37 | bool doneWork; 38 | do { 39 | doneWork = false; 40 | for (auto &device : this->devices) { 41 | if (device->needsUpdate()) { 42 | device->tick(); 43 | doneWork = true; 44 | } 45 | } 46 | } while (doneWork && this->hasPower); 47 | } 48 | 49 | void powerDown() { 50 | this->hasPower = false; 51 | } 52 | 53 | [[nodiscard]] 54 | std::string_view getName() const { 55 | return this->boardName; 56 | } 57 | 58 | virtual void draw(ImDrawList *drawList) { 59 | drawList->AddRectFilled(getPosition(), getPosition() + getDimensions(), ImColor(0x09, 0x91, 0x32, 0xFF)); 60 | 61 | for (auto &[name, track] : this->tracks) { 62 | auto [from, to] = track->getEndpoints(); 63 | 64 | auto startPos = getPosition() + from->getPosition() + from->getSize() / 2; 65 | auto endPos = getPosition() + to->getPosition() + to->getSize() / 2; 66 | auto middlePos = startPos.x - getPosition().x > startPos.y - getPosition().y ? ImVec2(startPos.x, endPos.y) : ImVec2(endPos.x, startPos.y); 67 | 68 | drawList->AddLine(startPos, middlePos, ImColor(0x19, 0xC1, 0x62, 0xFF), 3); 69 | drawList->AddLine(middlePos, endPos, ImColor(0x19, 0xC1, 0x62, 0xFF), 3); 70 | } 71 | 72 | 73 | for (auto &device : this->devices) { 74 | if (auto connectable = dynamic_cast(device); connectable != nullptr) { 75 | connectable->draw(getPosition(), drawList); 76 | } 77 | } 78 | } 79 | 80 | [[nodiscard]] 81 | ImVec2 getPosition() const { 82 | return this->position; 83 | } 84 | 85 | void setPosition(ImVec2 pos) { 86 | this->position = pos; 87 | } 88 | 89 | [[nodiscard]] 90 | ImVec2 getDimensions() const { 91 | return this->dimensions; 92 | } 93 | 94 | protected: 95 | template T, typename ...Args> 96 | auto& createDevice(Args&&... args) { 97 | auto device = new T(std::forward(args)...); 98 | this->devices.push_back(device); 99 | 100 | return *device; 101 | } 102 | 103 | void createTrack(Direction direction, const std::string &name, pcb::Connectable &from, pcb::Connectable &to, bool buffered = false) { 104 | if (this->tracks.contains(name)) return; 105 | 106 | auto track = new Track(direction, buffered, &from, &to); 107 | this->tracks.insert({ name, track }); 108 | 109 | from.linkTrack(name, track); 110 | to.linkTrack(name, track); 111 | } 112 | 113 | private: 114 | bool hasPower = false; 115 | std::string boardName; 116 | std::list devices; 117 | std::map tracks; 118 | 119 | ImVec2 position; 120 | ImVec2 dimensions; 121 | }; 122 | 123 | } -------------------------------------------------------------------------------- /emulator/include/board/track.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #define IMGUI_DEFINE_MATH_OPERATORS 12 | #include 13 | 14 | namespace vc::pcb { 15 | 16 | class Connectable; 17 | 18 | enum class Direction { 19 | MISO, 20 | MOSI 21 | }; 22 | 23 | class Track { 24 | public: 25 | Track(Direction direction, bool buffered, Connectable *from, Connectable *to) : direction(direction), buffered(buffered), from(from), to(to) { 26 | 27 | } 28 | 29 | [[nodiscard]] 30 | std::optional getValue() { 31 | std::scoped_lock lk(this->modifyMutex); 32 | 33 | if (this->buffered) { 34 | if (this->receivedData.empty()) 35 | return { }; 36 | auto item = this->receivedData.front(); 37 | this->receivedData.pop(); 38 | return item; 39 | } else { 40 | if (!this->value.has_value()) 41 | return { }; 42 | auto item = this->value.value(); 43 | this->value.reset(); 44 | return item; 45 | } 46 | } 47 | 48 | [[nodiscard]] 49 | bool hasValue() { 50 | std::scoped_lock lock(this->modifyMutex); 51 | 52 | if (this->buffered) 53 | return !this->receivedData.empty(); 54 | else 55 | return this->value.has_value(); 56 | } 57 | 58 | void setValue(u8 value) { 59 | std::scoped_lock lock(this->modifyMutex); 60 | 61 | if (this->buffered) 62 | this->receivedData.emplace(value); 63 | else 64 | this->value = value; 65 | } 66 | 67 | [[nodiscard]] 68 | std::pair getEndpoints() const { 69 | return { from, to }; 70 | } 71 | 72 | [[nodiscard]] 73 | Direction getDirection() const { 74 | return this->direction; 75 | } 76 | 77 | private: 78 | Direction direction; 79 | bool buffered; 80 | std::mutex modifyMutex; 81 | std::optional value; 82 | std::queue receivedData; 83 | 84 | Connectable *from, *to; 85 | }; 86 | 87 | class Connectable { 88 | public: 89 | friend class Board; 90 | protected: 91 | auto getTrack(std::string_view name) { 92 | return this->connectedTracks[std::string(name)]; 93 | } 94 | 95 | void linkTrack(const std::string &name, pcb::Track *track) { 96 | this->connectedTracks.insert({ name, track }); 97 | } 98 | 99 | [[nodiscard]] 100 | bool dataAvailable() { 101 | for (auto &[name, track] : this->connectedTracks) 102 | if (track->hasValue()) 103 | return true; 104 | 105 | return false; 106 | } 107 | 108 | auto getConnectedTrackNames() { 109 | std::vector result; 110 | 111 | for (auto &[name, track] : this->connectedTracks) 112 | result.push_back(name); 113 | 114 | return result; 115 | } 116 | 117 | 118 | virtual void draw(ImVec2 start, ImDrawList *drawList) { 119 | drawList->AddRectFilled(start + position, start + position + size, ImColor(0x10, 0x10, 0x10, 0xFF)); 120 | } 121 | 122 | public: 123 | [[nodiscard]] 124 | ImVec2 getPosition() const { 125 | return this->position; 126 | } 127 | 128 | void setPosition(ImVec2 pos) { 129 | this->position = pos; 130 | } 131 | 132 | [[nodiscard]] 133 | ImVec2 getSize() const { 134 | return this->size; 135 | } 136 | 137 | void setSize(ImVec2 size) { 138 | this->size = size; 139 | } 140 | 141 | private: 142 | std::map connectedTracks; 143 | 144 | ImVec2 position; 145 | ImVec2 size; 146 | }; 147 | 148 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/cpu.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace vc::dev { 12 | 13 | class CPUDevice : public vc::dev::Device, public pcb::Connectable { 14 | public: 15 | explicit CPUDevice(u32 numCores, ImVec2 pos) { 16 | for (u32 i = 0; i < numCores; i++) 17 | this->cores.emplace_back(addressSpace); 18 | 19 | this->setPosition(pos); 20 | this->setSize({ 100, 100 }); 21 | 22 | for (auto &mmio : this->addressSpace.getDevices()) { 23 | if (auto connectable = dynamic_cast(mmio); connectable != nullptr) { 24 | connectable->setPosition(this->getPosition()); 25 | connectable->setSize(this->getSize()); 26 | } 27 | } 28 | } 29 | 30 | ~CPUDevice() override = default; 31 | 32 | void tick() override { 33 | for (auto &core : this->cores) { 34 | try { 35 | core.execute(); 36 | } catch (cpu::AccessFaultException &e) { 37 | core.halt("Access Fault exception thrown!"); 38 | } catch (cpu::UnalignedAccessException &e) { 39 | core.halt("Unaligned Access exception thrown!"); 40 | } catch (...) { 41 | core.halt("Unknown exception thrown!"); 42 | } 43 | } 44 | 45 | for (auto &[trackName, pinNumber] : this->pinToTrackConnections) { 46 | auto &pin = this->pins[pinNumber]; 47 | auto track = this->getTrack(trackName); 48 | 49 | if (track->getDirection() == pcb::Direction::MOSI && pin->hasValue()) { 50 | track->setValue(pin->getValue().value()); 51 | } 52 | 53 | if (track->getDirection() == pcb::Direction::MISO && track->hasValue()) { 54 | pin->setValue(track->getValue().value()); 55 | } 56 | } 57 | } 58 | 59 | bool needsUpdate() override { 60 | for (auto &core : this->cores) { 61 | if (!core.isHalted()) 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | void reset() override { 69 | for (auto &core : this->cores) 70 | core.reset(); 71 | } 72 | 73 | auto& getAddressSpace() { 74 | return this->addressSpace; 75 | } 76 | 77 | void draw(ImVec2 start, ImDrawList *drawList) override { 78 | drawList->AddRectFilled(start + getPosition(), start + getPosition() + getSize(), ImColor(0x10, 0x10, 0x10, 0xFF)); 79 | drawList->AddText(start + getPosition() + ImVec2(10, 10), ImColor(0xFFFFFFFF), fmt::format("RISC-V\n {} Core", this->cores.size()).c_str()); 80 | 81 | if (ImGui::IsMouseHoveringRect(start + getPosition(), start + getPosition() + getSize())) { 82 | ImGui::BeginTooltip(); 83 | if (this->needsUpdate()) 84 | ImGui::TextSpinner("Running..."); 85 | else 86 | ImGui::TextUnformatted("Halted"); 87 | 88 | ImGui::Separator(); 89 | 90 | for (auto &device : this->getAddressSpace().getDevices()) { 91 | ImGui::TextUnformatted(fmt::format("{}: 0x{:016X} - 0x{:016X}", device->getName(), device->getBase(), device->getEnd()).c_str()); 92 | } 93 | 94 | ImGui::EndTooltip(); 95 | } 96 | } 97 | 98 | void attachToPin(u32 pinNumber, cpu::IOPin &pin) { 99 | this->pins.insert({ pinNumber, &pin }); 100 | } 101 | 102 | void attachPinToTrack(u32 pinNumber, std::string_view trackName) { 103 | this->pinToTrackConnections[std::string(trackName)] = pinNumber; 104 | } 105 | 106 | private: 107 | cpu::AddressSpace addressSpace; 108 | std::vector cores; 109 | std::map pins; 110 | std::map pinToTrackConnections; 111 | }; 112 | 113 | } -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline 2 | // - Desktop GL: 2.x 3.x 4.x 3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) 4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) 5 | 6 | // Implemented features: 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! 8 | // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. 9 | 10 | // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 11 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 12 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 13 | 14 | // About Desktop OpenGL function loaders: 15 | // Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. 16 | // Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). 17 | // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. 18 | 19 | // About GLSL version: 20 | // The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. 21 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" 22 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. 23 | 24 | #pragma once 25 | #include "imgui.h" // IMGUI_IMPL_API 26 | 27 | // Backend API 28 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); 29 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 30 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 31 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 32 | 33 | // (Optional) Called by Init/NewFrame/Shutdown 34 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 35 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 36 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 37 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 38 | 39 | // Specific OpenGL ES versions 40 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten 41 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android 42 | 43 | // Attempt to auto-detect the default Desktop GL loader based on available header files. 44 | // If auto-detection fails or doesn't select the same GL loader file as used by your application, 45 | // you are likely to get a crash in ImGui_ImplOpenGL3_Init(). 46 | // You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 47 | #if !defined(IMGUI_IMPL_OPENGL_ES2) \ 48 | && !defined(IMGUI_IMPL_OPENGL_ES3) \ 49 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ 50 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ 51 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ 52 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \ 53 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \ 54 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \ 55 | && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) 56 | 57 | // Try to detect GLES on matching platforms 58 | #if defined(__APPLE__) 59 | #include "TargetConditionals.h" 60 | #endif 61 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) 62 | #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" 63 | #elif defined(__EMSCRIPTEN__) 64 | #define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" 65 | 66 | // Otherwise try to detect supported Desktop OpenGL loaders.. 67 | #elif defined(__has_include) 68 | #if __has_include() 69 | #define IMGUI_IMPL_OPENGL_LOADER_GLEW 70 | #elif __has_include() 71 | #define IMGUI_IMPL_OPENGL_LOADER_GLAD 72 | #elif __has_include() 73 | #define IMGUI_IMPL_OPENGL_LOADER_GLAD2 74 | #elif __has_include() 75 | #define IMGUI_IMPL_OPENGL_LOADER_GL3W 76 | #elif __has_include() 77 | #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3 78 | #elif __has_include() 79 | #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2 80 | #else 81 | #error "Cannot detect OpenGL loader!" 82 | #endif 83 | #else 84 | #define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository 85 | #endif 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/address_space.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace vc::dev::cpu { 10 | 11 | struct AccessFaultException : public std::exception { }; 12 | struct UnalignedAccessException : public std::exception { }; 13 | 14 | struct byte_tag {}; 15 | struct hword_tag {}; 16 | struct word_tag {}; 17 | struct dword_tag {}; 18 | 19 | class AddressSpace { 20 | public: 21 | void addDevice(mmio::MMIODevice &device) { 22 | for (const auto mappedDevice : this->devices) { 23 | if (device.getBase() >= mappedDevice->getBase() && device.getEnd() <= mappedDevice->getEnd() || mappedDevice->getBase() >= device.getBase() && mappedDevice->getEnd() <= device.getEnd()) 24 | log::fatal("Tried to map device to occupied address range"); 25 | } 26 | 27 | this->devices.insert(&device); 28 | } 29 | 30 | auto& operator()(u64 address, byte_tag) { 31 | auto device = findDevice(address, 1); 32 | if (device == nullptr) { 33 | log::error("Invalid memory access at {:#x}", address); 34 | throw AccessFaultException(); 35 | } 36 | 37 | return device->byte(address - device->getBase()); 38 | } 39 | 40 | auto& operator()(u64 address, hword_tag) { 41 | auto device = findDevice(address, 2); 42 | if (device == nullptr) { 43 | log::error("Invalid memory access at {:#x}", address); 44 | throw AccessFaultException(); 45 | } 46 | return device->halfWord(address - device->getBase()); 47 | } 48 | 49 | auto& operator()(u64 address, word_tag) { 50 | auto device = findDevice(address, 4); 51 | if (device == nullptr) { 52 | log::error("Invalid memory access at {:#x}", address); 53 | throw AccessFaultException(); 54 | } 55 | return device->word(address - device->getBase()); 56 | } 57 | 58 | auto& operator()(u64 address, dword_tag) { 59 | auto device = findDevice(address, 8); 60 | if (device == nullptr) { 61 | log::error("Invalid memory access at {:#x}", address); 62 | throw AccessFaultException(); 63 | } 64 | return device->doubleWord(address - device->getBase()); 65 | } 66 | 67 | void tickDevices() { 68 | for (auto &device : this->devices) 69 | device->doTick(); 70 | } 71 | 72 | bool loadELF(std::string_view path) { 73 | std::vector buffer; 74 | 75 | { 76 | FILE *file = fopen(path.data(), "rb"); 77 | if (file == nullptr) return false; 78 | ON_SCOPE_EXIT { fclose(file); }; 79 | 80 | fseek(file, 0, SEEK_END); 81 | size_t size = ftell(file); 82 | rewind(file); 83 | 84 | buffer.resize(size, 0x00); 85 | fread(buffer.data(), buffer.size(), 1, file); 86 | } 87 | 88 | { 89 | elf64_hdr elfHeader = { 0 }; 90 | std::memcpy(&elfHeader, buffer.data() + 0, sizeof(elf64_hdr)); 91 | std::vector programHeader(elfHeader.e_phnum - 1, { 0 }); 92 | std::memcpy(programHeader.data(), buffer.data() + elfHeader.e_phoff, elfHeader.e_phentsize * programHeader.size()); 93 | 94 | for (const auto &pheader : programHeader) { 95 | for (u32 offset = 0; offset < pheader.p_filesz; offset++) 96 | this->operator()(pheader.p_paddr + offset, byte_tag{}) = buffer[pheader.p_offset + offset]; 97 | log::info("Mapped section to {:#x}:{:#x}", pheader.p_paddr, pheader.p_paddr + pheader.p_memsz); 98 | } 99 | } 100 | 101 | return true; 102 | } 103 | 104 | [[nodiscard]] 105 | auto& getDevices() { 106 | return this->devices; 107 | } 108 | private: 109 | [[nodiscard]] 110 | mmio::MMIODevice* findDevice(u64 address, u8 accessSize) const { 111 | auto device = std::find_if(devices.begin(), devices.end(), [&](mmio::MMIODevice *curr){ 112 | return address >= curr->getBase() && address <= curr->getEnd() - accessSize; 113 | }); 114 | 115 | if (device == devices.end()) return nullptr; 116 | 117 | return *device; 118 | } 119 | 120 | std::set devices; 121 | }; 122 | 123 | } -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | //#define IMGUI_API __declspec( dllexport ) 25 | //#define IMGUI_API __declspec( dllimport ) 26 | 27 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 28 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 29 | 30 | //---- Disable all of Dear ImGui or don't implement standard windows. 31 | // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. 32 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 33 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. 34 | //#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty. 35 | 36 | //---- Don't implement some functions to reduce linkage requirements. 37 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 38 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 39 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 40 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 41 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 42 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 43 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 44 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 45 | 46 | //---- Include imgui_user.h at the end of imgui.h as a convenience 47 | //#define IMGUI_INCLUDE_IMGUI_USER_H 48 | 49 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 50 | //#define IMGUI_USE_BGRA_PACKED_COLOR 51 | 52 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 53 | //#define IMGUI_USE_WCHAR32 54 | 55 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 56 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 57 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 58 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 59 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 60 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 61 | 62 | //---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 63 | // Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. 64 | // #define IMGUI_USE_STB_SPRINTF 65 | 66 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 67 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 68 | /* 69 | #define IM_VEC2_CLASS_EXTRA \ 70 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 71 | operator MyVec2() const { return MyVec2(x,y); } 72 | 73 | #define IM_VEC4_CLASS_EXTRA \ 74 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 75 | operator MyVec4() const { return MyVec4(x,y,z,w); } 76 | */ 77 | 78 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 79 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 80 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 81 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 82 | //#define ImDrawIdx unsigned int 83 | 84 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 85 | //struct ImDrawList; 86 | //struct ImDrawCmd; 87 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 88 | //#define ImDrawCallback MyImDrawCallback 89 | 90 | //---- Debug Tools: Macro to break in Debugger 91 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 92 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 93 | //#define IM_DEBUG_BREAK __debugbreak() 94 | 95 | //---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), 96 | // (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) 97 | // This adds a small runtime cost which is why it is not enabled by default. 98 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 99 | 100 | //---- Debug Tools: Enable slower asserts 101 | //#define IMGUI_DEBUG_PARANOID 102 | 103 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 104 | /* 105 | namespace ImGui 106 | { 107 | void MyFunction(const char* name, const MyMatrix44& v); 108 | } 109 | */ 110 | -------------------------------------------------------------------------------- /emulator/source/ui/window.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace vc::ui { 20 | 21 | Window::Window() { 22 | this->initGLFW(); 23 | this->initImGui(); 24 | } 25 | 26 | Window::~Window() { 27 | this->deinitImGui(); 28 | this->deinitGLFW(); 29 | 30 | for (auto &view : this->views) 31 | delete view; 32 | } 33 | 34 | void Window::loop() { 35 | this->lastFrameTime = glfwGetTime(); 36 | while (!glfwWindowShouldClose(this->windowHandle)) { 37 | if (!glfwGetWindowAttrib(this->windowHandle, GLFW_VISIBLE) || glfwGetWindowAttrib(this->windowHandle, GLFW_ICONIFIED)) 38 | glfwWaitEvents(); 39 | 40 | glfwPollEvents(); 41 | 42 | this->frameBegin(); 43 | this->frame(); 44 | this->frameEnd(); 45 | } 46 | } 47 | 48 | void Window::frameBegin() { 49 | ImGui_ImplOpenGL3_NewFrame(); 50 | ImGui_ImplGlfw_NewFrame(); 51 | ImGui::NewFrame(); 52 | 53 | ImGuiViewport* viewport = ImGui::GetMainViewport(); 54 | ImGui::SetNextWindowPos(viewport->GetWorkPos()); 55 | ImGui::SetNextWindowSize(viewport->GetWorkSize()); 56 | ImGui::SetNextWindowViewport(viewport->ID); 57 | ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); 58 | ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); 59 | 60 | ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking 61 | | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse 62 | | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize 63 | | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus 64 | | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; 65 | 66 | ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; 67 | 68 | if (ImGui::Begin("DockSpace", nullptr, windowFlags)) { 69 | ImGui::PopStyleVar(2); 70 | 71 | ImGui::DockSpace(ImGui::GetID("MainDock"), ImVec2(0.0f, ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeightWithSpacing() - 1)); 72 | 73 | if (ImGui::BeginMenuBar()) { 74 | 75 | if (ImGui::BeginMenu("File")) ImGui::EndMenu(); 76 | 77 | ImGui::EndMenuBar(); 78 | } 79 | 80 | } 81 | ImGui::End(); 82 | } 83 | 84 | void Window::frame() { 85 | for (auto &view : this->views) 86 | view->draw(); 87 | } 88 | 89 | void Window::frameEnd() { 90 | ImGui::Render(); 91 | 92 | int displayWidth, displayHeight; 93 | glfwGetFramebufferSize(this->windowHandle, &displayWidth, &displayHeight); 94 | glViewport(0, 0, displayWidth, displayHeight); 95 | glClearColor(0.45f, 0.55f, 0.60f, 1.00f); 96 | glClear(GL_COLOR_BUFFER_BIT); 97 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 98 | 99 | GLFWwindow* backup_current_context = glfwGetCurrentContext(); 100 | ImGui::UpdatePlatformWindows(); 101 | ImGui::RenderPlatformWindowsDefault(); 102 | glfwMakeContextCurrent(backup_current_context); 103 | 104 | glfwSwapBuffers(this->windowHandle); 105 | 106 | std::this_thread::sleep_for(std::chrono::milliseconds(u64((this->lastFrameTime + 1 / (ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow) ? this->targetFps : 5.0) - glfwGetTime()) * 1000))); 107 | this->lastFrameTime = glfwGetTime(); 108 | } 109 | 110 | 111 | void Window::initGLFW() { 112 | glfwSetErrorCallback([](int error, const char* desc) { 113 | log::error("GLFW Error [{}] : {}", error, desc); 114 | }); 115 | 116 | if (!glfwInit()) 117 | throw std::runtime_error("Failed to initialize GLFW!"); 118 | 119 | #ifdef __APPLE__ 120 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 121 | #endif 122 | 123 | if (auto *monitor = glfwGetPrimaryMonitor(); monitor) { 124 | float xscale, yscale; 125 | glfwGetMonitorContentScale(monitor, &xscale, &yscale); 126 | } 127 | 128 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 129 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 130 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 131 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 132 | 133 | this->windowHandle = glfwCreateWindow(1280, 720, "Virtual Console", nullptr, nullptr); 134 | 135 | glfwSetWindowUserPointer(this->windowHandle, this); 136 | 137 | if (this->windowHandle == nullptr) 138 | throw std::runtime_error("Failed to create window!"); 139 | 140 | glfwMakeContextCurrent(this->windowHandle); 141 | glfwSwapInterval(1); 142 | 143 | glfwSetWindowPosCallback(this->windowHandle, [](GLFWwindow *window, int x, int y) { 144 | auto win = static_cast(glfwGetWindowUserPointer(window)); 145 | win->frameBegin(); 146 | win->frame(); 147 | win->frameEnd(); 148 | }); 149 | 150 | glfwSetWindowSizeCallback(this->windowHandle, [](GLFWwindow *window, int width, int height) { 151 | auto win = static_cast(glfwGetWindowUserPointer(window)); 152 | win->frameBegin(); 153 | win->frame(); 154 | win->frameEnd(); 155 | }); 156 | 157 | glfwSetKeyCallback(this->windowHandle, [](GLFWwindow *window, int key, int scancode, int action, int mods) { 158 | 159 | auto keyName = glfwGetKeyName(key, scancode); 160 | if (keyName != nullptr) 161 | key = std::toupper(keyName[0]); 162 | 163 | if (action == GLFW_PRESS) { 164 | auto &io = ImGui::GetIO(); 165 | io.KeysDown[key] = true; 166 | io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; 167 | io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; 168 | io.KeyAlt = (mods & GLFW_MOD_ALT) != 0; 169 | } 170 | else if (action == GLFW_RELEASE) { 171 | auto &io = ImGui::GetIO(); 172 | io.KeysDown[key] = false; 173 | io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; 174 | io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; 175 | io.KeyAlt = (mods & GLFW_MOD_ALT) != 0; 176 | } 177 | }); 178 | 179 | glfwSetWindowSizeLimits(this->windowHandle, 720, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); 180 | 181 | if (gladLoadGL() == 0) 182 | throw std::runtime_error("Failed to initialize OpenGL loader!"); 183 | } 184 | 185 | void Window::initImGui() { 186 | IMGUI_CHECKVERSION(); 187 | 188 | GImGui = ImGui::CreateContext(); 189 | 190 | ImGuiIO& io = ImGui::GetIO(); 191 | ImGuiStyle& style = ImGui::GetStyle(); 192 | 193 | io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard; 194 | #if !defined(OS_LINUX) 195 | io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; 196 | #endif 197 | 198 | 199 | io.ConfigViewportsNoTaskBarIcon = true; 200 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; 201 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; 202 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; 203 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; 204 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; 205 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; 206 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; 207 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; 208 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; 209 | io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; 210 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; 211 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; 212 | io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; 213 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; 214 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; 215 | io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; 216 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; 217 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; 218 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; 219 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; 220 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; 221 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; 222 | 223 | io.Fonts->Clear(); 224 | 225 | ImFontConfig cfg; 226 | cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true; 227 | cfg.SizePixels = 13.0f; 228 | io.Fonts->AddFontDefault(&cfg); 229 | 230 | cfg.MergeMode = true; 231 | 232 | ImWchar fontAwesomeRange[] = { 233 | ICON_MIN_FA, ICON_MAX_FA, 234 | 0 235 | }; 236 | std::uint8_t *px; 237 | int w, h; 238 | io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 11.0f, &cfg, fontAwesomeRange); 239 | io.Fonts->GetTexDataAsRGBA32(&px, &w, &h); 240 | 241 | // Create new font atlas 242 | GLuint tex; 243 | glGenTextures(1, &tex); 244 | glBindTexture(GL_TEXTURE_2D, tex); 245 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 246 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 247 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA8, GL_UNSIGNED_INT, px); 248 | io.Fonts->SetTexID(reinterpret_cast(tex)); 249 | 250 | 251 | style.WindowMenuButtonPosition = ImGuiDir_None; 252 | style.IndentSpacing = 10.0F; 253 | 254 | ImGui_ImplGlfw_InitForOpenGL(this->windowHandle, true); 255 | 256 | ImGui_ImplOpenGL3_Init("#version 150"); 257 | } 258 | 259 | void Window::deinitGLFW() { 260 | glfwDestroyWindow(this->windowHandle); 261 | glfwTerminate(); 262 | } 263 | 264 | void Window::deinitImGui() { 265 | ImGui_ImplOpenGL3_Shutdown(); 266 | ImGui_ImplGlfw_Shutdown(); 267 | ImGui::DestroyContext(); 268 | } 269 | 270 | } -------------------------------------------------------------------------------- /emulator/include/devices/cpu/core/instructions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define INSTRUCTION_FORMAT(name, ...) struct { __VA_ARGS__ } name; static_assert(sizeof(name) == InstructionSize, "Instruction Format " #name " is invalid!") 6 | #define COMPRESSED_INSTRUCTION_FORMAT(name, ...) struct { __VA_ARGS__ } name; static_assert(sizeof(name) == CompressedInstructionSize, "Compressed instruction Format " #name " is invalid!") 7 | 8 | namespace vc::dev::cpu { 9 | 10 | using instr_t = u32; 11 | using comp_instr_t = u16; 12 | 13 | constexpr static inline size_t InstructionSize = sizeof(instr_t); 14 | constexpr static inline size_t CompressedInstructionSize = sizeof(comp_instr_t); 15 | 16 | enum class Opcode : u8 { 17 | LUI = 0b0110111, 18 | AUIPC = 0b0010111, 19 | JAL = 0b1101111, 20 | JALR = 0b1100111, 21 | BRANCH = 0b1100011, 22 | LOAD = 0b0000011, 23 | STORE = 0b0100011, 24 | OP_IMM = 0b0010011, 25 | OP_IMM32 = 0b0011011, 26 | MISC_MEM = 0b0001111, 27 | SYSTEM = 0b1110011, 28 | OP = 0b0100011, 29 | OP_32 = 0b0111011, 30 | AMO = 0b0101111, 31 | LOAD_FP = 0b0000111, 32 | STORE_FP = 0b0100111, 33 | FMADD = 0b1000011, 34 | FMSUB = 0b1000111, 35 | FNMADD = 0b1001111, 36 | FNMSUB = 0b1001011, 37 | OP_FP = 0b1010011, 38 | }; 39 | 40 | enum class CompressedOpcode : u8 { 41 | C0 = 0b00, 42 | C1 = 0b01, 43 | C2 = 0b10, 44 | }; 45 | 46 | enum class C0Funct : u8 { 47 | C_ADDI4SPN = 0b000 48 | }; 49 | 50 | enum class C1Funct : u8 { 51 | C_ADDI = 0b000, 52 | C_ADDIW = 0b001, 53 | C_LI = 0b010, 54 | C_LUI = 0b011, 55 | C_ANDI = 0b100 56 | }; 57 | 58 | enum class C2Funct : u8 { 59 | C_JUMP = 0b100, 60 | C_LDSP = 0b011, 61 | C_SDSP = 0b111 62 | }; 63 | 64 | enum class OPFunc3 : u8 { 65 | ADD = 0b000 66 | }; 67 | 68 | enum class OPFunc7 : u8 { 69 | ADD = 0b0000000 70 | }; 71 | 72 | enum class OPIMMFunc : u8 { 73 | ADDI = 0b000, 74 | XORI = 0b100, 75 | ORI = 0b110, 76 | ANDI = 0b111 77 | }; 78 | 79 | enum class OPIMM32Func : u8 { 80 | ADDIW = 0b000 81 | }; 82 | 83 | enum class STOREFunc : u8 { 84 | SB = 0b000, 85 | SH = 0b001, 86 | SW = 0b010, 87 | SD = 0b011, 88 | }; 89 | 90 | enum class LOADFunc : u8 { 91 | LB = 0b000, 92 | LD = 0b011, 93 | LBU = 0b100 94 | }; 95 | 96 | enum class BRANCHFunc : u8 { 97 | BEQ = 0b000, 98 | BNE = 0b001 99 | }; 100 | 101 | union Instruction { 102 | 103 | union { 104 | INSTRUCTION_FORMAT(R, 105 | instr_t opcode : 7; 106 | instr_t rd : 5; 107 | instr_t funct3 : 3; 108 | instr_t rs1 : 5; 109 | instr_t rs2 : 5; 110 | instr_t funct7 : 7; 111 | ); 112 | 113 | INSTRUCTION_FORMAT(I, 114 | instr_t opcode : 7; 115 | instr_t rd : 5; 116 | instr_t funct3 : 3; 117 | instr_t rs1 : 5; 118 | instr_t imm0_11 : 12; 119 | 120 | constexpr u32 getImmediate() const { return this->imm0_11; } 121 | constexpr void setImmediate(u32 value) { this->imm0_11 = value; } 122 | ); 123 | 124 | INSTRUCTION_FORMAT(S, 125 | instr_t opcode : 7; 126 | instr_t imm0_4 : 5; 127 | instr_t funct3 : 3; 128 | instr_t rs1 : 5; 129 | instr_t rs2 : 5; 130 | instr_t imm5_11 : 7; 131 | 132 | constexpr u32 getImmediate() const { return (this->imm5_11 << 5) | this->imm0_4; } 133 | constexpr void setImmediate(u32 value) { this->imm0_4 = value & 0b11111; this->imm5_11 = value >> 5; } 134 | ); 135 | 136 | INSTRUCTION_FORMAT(U, 137 | instr_t opcode : 7; 138 | instr_t rd : 5; 139 | instr_t imm12_31 : 20; 140 | 141 | constexpr u32 getImmediate() const { return this->imm12_31 << 12; } 142 | constexpr void setImmediate(u32 value) { this->imm12_31 = value >> 12; } 143 | ); 144 | 145 | } Base; 146 | 147 | union { 148 | INSTRUCTION_FORMAT(R, 149 | instr_t opcode : 7; 150 | instr_t rd : 5; 151 | instr_t funct3 : 3; 152 | instr_t rs1 : 5; 153 | instr_t rs2 : 5; 154 | instr_t funct7 : 7; 155 | ); 156 | 157 | INSTRUCTION_FORMAT(I, 158 | instr_t opcode : 7; 159 | instr_t rd : 5; 160 | instr_t funct3 : 3; 161 | instr_t rs1 : 5; 162 | instr_t imm0_11 : 12; 163 | 164 | constexpr u32 getImmediate() const { return this->imm0_11; } 165 | ); 166 | 167 | INSTRUCTION_FORMAT(S, 168 | instr_t opcode : 7; 169 | instr_t imm0_4 : 5; 170 | instr_t funct3 : 3; 171 | instr_t rs1 : 5; 172 | instr_t rs2 : 5; 173 | instr_t imm5_11 : 7; 174 | 175 | constexpr u32 getImmediate() const { return (this->imm5_11 << 5) | this->imm0_4; } 176 | ); 177 | 178 | INSTRUCTION_FORMAT(B, 179 | instr_t opcode : 7; 180 | instr_t imm11 : 1; 181 | instr_t imm1_4 : 4; 182 | instr_t funct3 : 3; 183 | instr_t rs1 : 5; 184 | instr_t rs2 : 5; 185 | instr_t imm5_10 : 6; 186 | instr_t imm12 : 1; 187 | 188 | constexpr u32 getImmediate() const { return ((this->imm12 << 12) | (this->imm11 << 11) | (this->imm5_10 << 5) | (this->imm1_4 << 1)) >> 1; } 189 | ); 190 | 191 | INSTRUCTION_FORMAT(U, 192 | instr_t opcode : 7; 193 | instr_t rd : 5; 194 | instr_t imm12_31 : 20; 195 | 196 | constexpr u32 getImmediate() const { return this->imm12_31 << 12; } 197 | ); 198 | 199 | INSTRUCTION_FORMAT(J, 200 | instr_t opcode : 7; 201 | instr_t rd : 5; 202 | instr_t imm12_19 : 8; 203 | instr_t imm11 : 1; 204 | instr_t imm1_10 : 10; 205 | instr_t imm20 : 1; 206 | 207 | constexpr u32 getImmediate() const { return ((this->imm20 << 20) | (this->imm12_19 << 12) | (this->imm11 << 11) | (this->imm1_10 << 1)) >> 1; } 208 | ); 209 | } Immediate; 210 | 211 | [[nodiscard]] 212 | constexpr Opcode getOpcode() const { 213 | return static_cast(Base.R.opcode); 214 | } 215 | 216 | [[nodiscard]] 217 | constexpr u8 getFunction3() const { 218 | return Base.R.funct3; 219 | } 220 | }; 221 | static_assert(sizeof(Instruction) == InstructionSize, "Instruction union invalid!"); 222 | 223 | union CompressedInstruction { 224 | 225 | COMPRESSED_INSTRUCTION_FORMAT(CR, 226 | comp_instr_t opcode : 2; 227 | comp_instr_t rs2 : 5; 228 | comp_instr_t rd : 5; 229 | comp_instr_t funct4 : 4; 230 | ); 231 | 232 | COMPRESSED_INSTRUCTION_FORMAT(CI, 233 | comp_instr_t opcode : 2; 234 | comp_instr_t imm1 : 3; 235 | comp_instr_t imm2 : 2; 236 | comp_instr_t rd : 5; 237 | comp_instr_t imm3 : 1; 238 | comp_instr_t funct3 : 3; 239 | ); 240 | 241 | COMPRESSED_INSTRUCTION_FORMAT(CSS, 242 | comp_instr_t opcode : 2; 243 | comp_instr_t rs2 : 5; 244 | comp_instr_t imm : 6; 245 | comp_instr_t funct3 : 3; 246 | ); 247 | 248 | COMPRESSED_INSTRUCTION_FORMAT(CIW, 249 | comp_instr_t opcode : 2; 250 | comp_instr_t rd : 3; 251 | comp_instr_t imm : 8; 252 | comp_instr_t funct3 : 3; 253 | ); 254 | 255 | COMPRESSED_INSTRUCTION_FORMAT(CL, 256 | comp_instr_t opcode : 2; 257 | comp_instr_t rd : 3; 258 | comp_instr_t imm1 : 2; 259 | comp_instr_t rs1 : 3; 260 | comp_instr_t imm2 : 3; 261 | comp_instr_t funct3 : 3; 262 | ); 263 | 264 | COMPRESSED_INSTRUCTION_FORMAT(CS, 265 | comp_instr_t opcode : 2; 266 | comp_instr_t rs2 : 3; 267 | comp_instr_t imm1 : 2; 268 | comp_instr_t rs1 : 3; 269 | comp_instr_t imm2 : 3; 270 | comp_instr_t funct3 : 3; 271 | ); 272 | 273 | COMPRESSED_INSTRUCTION_FORMAT(CB, 274 | comp_instr_t opcode : 2; 275 | comp_instr_t offset1 : 5; 276 | comp_instr_t rs1 : 3; 277 | comp_instr_t offset2 : 3; 278 | comp_instr_t funct3 : 3; 279 | ); 280 | 281 | COMPRESSED_INSTRUCTION_FORMAT(CJ, 282 | comp_instr_t opcode : 2; 283 | comp_instr_t target : 11; 284 | comp_instr_t funct3 : 3; 285 | ); 286 | 287 | [[nodiscard]] 288 | constexpr CompressedOpcode getOpcode() const { 289 | return static_cast(CJ.opcode); 290 | } 291 | 292 | [[nodiscard]] 293 | constexpr u8 getFunction3() const { 294 | return CJ.funct3; 295 | } 296 | 297 | [[nodiscard]] 298 | constexpr u8 getFunction4() const { 299 | return CR.funct4; 300 | } 301 | 302 | }; 303 | } -------------------------------------------------------------------------------- /emulator/external/ImGui/source/imgui_vc_extensions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #define IMGUI_DEFINE_MATH_OPERATORS 6 | #include 7 | #undef IMGUI_DEFINE_MATH_OPERATORS 8 | 9 | #define STB_IMAGE_IMPLEMENTATION 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | namespace ImGui { 17 | 18 | bool Hyperlink(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) { 19 | ImGuiWindow* window = GetCurrentWindow(); 20 | if (window->SkipItems) 21 | return false; 22 | 23 | ImGuiContext& g = *GImGui; 24 | const ImGuiStyle& style = g.Style; 25 | const ImGuiID id = window->GetID(label); 26 | const ImVec2 label_size = CalcTextSize(label, NULL, true); 27 | 28 | ImVec2 pos = window->DC.CursorPos; 29 | ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y); 30 | 31 | const ImRect bb(pos, pos + size); 32 | if (!ItemAdd(bb, id)) 33 | return false; 34 | 35 | if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) 36 | flags |= ImGuiButtonFlags_Repeat; 37 | bool hovered, held; 38 | bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); 39 | 40 | // Render 41 | const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive); 42 | PushStyleColor(ImGuiCol_Text, ImU32(col)); 43 | TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting 44 | GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col)); 45 | PopStyleColor(); 46 | 47 | IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); 48 | return pressed; 49 | } 50 | 51 | bool BulletHyperlink(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) { 52 | ImGuiWindow* window = GetCurrentWindow(); 53 | if (window->SkipItems) 54 | return false; 55 | 56 | ImGuiContext& g = *GImGui; 57 | const ImGuiStyle& style = g.Style; 58 | const ImGuiID id = window->GetID(label); 59 | const ImVec2 label_size = CalcTextSize(label, NULL, true); 60 | 61 | ImVec2 pos = window->DC.CursorPos; 62 | ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y) + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f); 63 | 64 | const ImRect bb(pos, pos + size); 65 | if (!ItemAdd(bb, id)) 66 | return false; 67 | 68 | if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) 69 | flags |= ImGuiButtonFlags_Repeat; 70 | bool hovered, held; 71 | bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); 72 | 73 | // Render 74 | const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive); 75 | PushStyleColor(ImGuiCol_Text, ImU32(col)); 76 | RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), col); 77 | RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), label, nullptr, false); 78 | GetWindowDrawList()->AddLine(bb.Min + ImVec2(style.FramePadding.x, size.y), pos + size, ImU32(col)); 79 | ImGui::NewLine(); 80 | PopStyleColor(); 81 | 82 | IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); 83 | return pressed; 84 | } 85 | 86 | bool DescriptionButton(const char* label, const char* description, const ImVec2& size_arg, ImGuiButtonFlags flags) { 87 | ImGuiWindow* window = GetCurrentWindow(); 88 | if (window->SkipItems) 89 | return false; 90 | 91 | ImGuiContext& g = *GImGui; 92 | const ImGuiStyle& style = g.Style; 93 | const ImGuiID id = window->GetID(label); 94 | const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), NULL, true); 95 | const ImVec2 label_size = CalcTextSize(label, NULL, true); 96 | 97 | ImVec2 pos = window->DC.CursorPos; 98 | if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) 99 | pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y; 100 | ImVec2 size = CalcItemSize(size_arg, text_size.x + style.FramePadding.x * 4.0f, text_size.y + style.FramePadding.y * 4.0f); 101 | 102 | const ImRect bb(pos, pos + size); 103 | ItemSize(size, style.FramePadding.y); 104 | if (!ItemAdd(bb, id)) 105 | return false; 106 | 107 | if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) 108 | flags |= ImGuiButtonFlags_Repeat; 109 | bool hovered, held; 110 | bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); 111 | 112 | ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0, 0.5)); 113 | 114 | // Render 115 | const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered : ImGuiCustomCol_DescButton); 116 | RenderNavHighlight(bb, id); 117 | RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); 118 | PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive)); 119 | RenderTextWrapped(bb.Min + style.FramePadding * 2, label, nullptr, CalcWrapWidthForPos(window->DC.CursorPos, window->DC.TextWrapPos)); 120 | PopStyleColor(); 121 | PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text)); 122 | RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, NULL, &text_size, style.ButtonTextAlign, &bb); 123 | PopStyleColor(); 124 | 125 | ImGui::PopStyleVar(); 126 | 127 | // Automatically close popups 128 | //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) 129 | // CloseCurrentPopup(); 130 | 131 | IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); 132 | return pressed; 133 | } 134 | 135 | void UnderlinedText(const char* label, ImColor color, const ImVec2& size_arg) { 136 | ImGuiWindow* window = GetCurrentWindow(); 137 | 138 | const ImVec2 label_size = CalcTextSize(label, NULL, true); 139 | 140 | ImVec2 pos = window->DC.CursorPos; 141 | ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y); 142 | 143 | PushStyleColor(ImGuiCol_Text, ImU32(color)); 144 | TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting 145 | GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(color)); 146 | PopStyleColor(); 147 | } 148 | 149 | void Disabled(const std::function &widgets, bool disabled) { 150 | if (disabled) { 151 | ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); 152 | ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5F); 153 | widgets(); 154 | ImGui::PopStyleVar(); 155 | ImGui::PopItemFlag(); 156 | } else { 157 | widgets(); 158 | } 159 | } 160 | 161 | void TextSpinner(const char* label) { 162 | ImGui::Text("[%c] %s", "|/-\\"[ImU32(ImGui::GetTime() * 20) % 4], label); 163 | } 164 | 165 | void Header(const char *label, bool firstEntry) { 166 | if (!firstEntry) 167 | ImGui::NewLine(); 168 | ImGui::TextUnformatted(label); 169 | ImGui::Separator(); 170 | } 171 | 172 | ImU32 GetCustomColorU32(ImGuiCustomCol idx, float alpha_mul) { 173 | auto& customData = *static_cast(GImGui->IO.UserData); 174 | ImVec4 c = customData.Colors[idx]; 175 | c.w *= GImGui->Style.Alpha * alpha_mul; 176 | return ColorConvertFloat4ToU32(c); 177 | } 178 | 179 | void StyleCustomColorsDark() { 180 | auto &colors = static_cast(GImGui->IO.UserData)->Colors; 181 | 182 | colors[ImGuiCustomCol_DescButton] = ImColor(20, 20, 20); 183 | colors[ImGuiCustomCol_DescButtonHovered] = ImColor(40, 40, 40); 184 | colors[ImGuiCustomCol_DescButtonActive] = ImColor(60, 60, 60); 185 | } 186 | 187 | void StyleCustomColorsLight() { 188 | auto &colors = static_cast(GImGui->IO.UserData)->Colors; 189 | 190 | colors[ImGuiCustomCol_DescButton] = ImColor(230, 230, 230); 191 | colors[ImGuiCustomCol_DescButtonHovered] = ImColor(210, 210, 210); 192 | colors[ImGuiCustomCol_DescButtonActive] = ImColor(190, 190, 190); 193 | } 194 | 195 | void StyleCustomColorsClassic() { 196 | auto &colors = static_cast(GImGui->IO.UserData)->Colors; 197 | 198 | colors[ImGuiCustomCol_DescButton] = ImColor(40, 40, 80); 199 | colors[ImGuiCustomCol_DescButtonHovered] = ImColor(60, 60, 100); 200 | colors[ImGuiCustomCol_DescButtonActive] = ImColor(80, 80, 120); 201 | } 202 | 203 | std::tuple LoadImageFromPath(const char *path) { 204 | int imageWidth = 0; 205 | int imageHeight = 0; 206 | 207 | unsigned char* imageData = stbi_load(path, &imageWidth, &imageHeight, nullptr, 4); 208 | if (imageData == nullptr) 209 | return { nullptr, -1, -1 }; 210 | 211 | GLuint texture; 212 | glGenTextures(1, &texture); 213 | glBindTexture(GL_TEXTURE_2D, texture); 214 | 215 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 216 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 217 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 218 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 219 | 220 | #if defined(GL_UNPACK_ROW_LENGTH) 221 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 222 | #endif 223 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); 224 | stbi_image_free(imageData); 225 | 226 | return { reinterpret_cast(static_cast(texture)), imageWidth, imageHeight }; 227 | } 228 | 229 | void UnloadImage(ImTextureID texture) { 230 | auto glTextureId = static_cast(reinterpret_cast(texture)); 231 | glDeleteTextures(1, &glTextureId); 232 | } 233 | 234 | } -------------------------------------------------------------------------------- /emulator/external/glad/include/KHR/khrplatform.h: -------------------------------------------------------------------------------- 1 | #ifndef __khrplatform_h_ 2 | #define __khrplatform_h_ 3 | 4 | /* 5 | ** Copyright (c) 2008-2018 The Khronos Group Inc. 6 | ** 7 | ** Permission is hereby granted, free of charge, to any person obtaining a 8 | ** copy of this software and/or associated documentation files (the 9 | ** "Materials"), to deal in the Materials without restriction, including 10 | ** without limitation the rights to use, copy, modify, merge, publish, 11 | ** distribute, sublicense, and/or sell copies of the Materials, and to 12 | ** permit persons to whom the Materials are furnished to do so, subject to 13 | ** the following conditions: 14 | ** 15 | ** The above copyright notice and this permission notice shall be included 16 | ** in all copies or substantial portions of the Materials. 17 | ** 18 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 25 | */ 26 | 27 | /* Khronos platform-specific types and definitions. 28 | * 29 | * The master copy of khrplatform.h is maintained in the Khronos EGL 30 | * Registry repository at https://github.com/KhronosGroup/EGL-Registry 31 | * The last semantic modification to khrplatform.h was at commit ID: 32 | * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 33 | * 34 | * Adopters may modify this file to suit their platform. Adopters are 35 | * encouraged to submit platform specific modifications to the Khronos 36 | * group so that they can be included in future versions of this file. 37 | * Please submit changes by filing pull requests or issues on 38 | * the EGL Registry repository linked above. 39 | * 40 | * 41 | * See the Implementer's Guidelines for information about where this file 42 | * should be located on your system and for more details of its use: 43 | * http://www.khronos.org/registry/implementers_guide.pdf 44 | * 45 | * This file should be included as 46 | * #include 47 | * by Khronos client API header files that use its types and defines. 48 | * 49 | * The types in khrplatform.h should only be used to define API-specific types. 50 | * 51 | * Types defined in khrplatform.h: 52 | * khronos_int8_t signed 8 bit 53 | * khronos_uint8_t unsigned 8 bit 54 | * khronos_int16_t signed 16 bit 55 | * khronos_uint16_t unsigned 16 bit 56 | * khronos_int32_t signed 32 bit 57 | * khronos_uint32_t unsigned 32 bit 58 | * khronos_int64_t signed 64 bit 59 | * khronos_uint64_t unsigned 64 bit 60 | * khronos_intptr_t signed same number of bits as a pointer 61 | * khronos_uintptr_t unsigned same number of bits as a pointer 62 | * khronos_ssize_t signed size 63 | * khronos_usize_t unsigned size 64 | * khronos_float_t signed 32 bit floating point 65 | * khronos_time_ns_t unsigned 64 bit time in nanoseconds 66 | * khronos_utime_nanoseconds_t unsigned time interval or absolute time in 67 | * nanoseconds 68 | * khronos_stime_nanoseconds_t signed time interval in nanoseconds 69 | * khronos_boolean_enum_t enumerated boolean type. This should 70 | * only be used as a base type when a client API's boolean type is 71 | * an enum. Client APIs which use an integer or other type for 72 | * booleans cannot use this as the base type for their boolean. 73 | * 74 | * Tokens defined in khrplatform.h: 75 | * 76 | * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. 77 | * 78 | * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. 79 | * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. 80 | * 81 | * Calling convention macros defined in this file: 82 | * KHRONOS_APICALL 83 | * KHRONOS_APIENTRY 84 | * KHRONOS_APIATTRIBUTES 85 | * 86 | * These may be used in function prototypes as: 87 | * 88 | * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( 89 | * int arg1, 90 | * int arg2) KHRONOS_APIATTRIBUTES; 91 | */ 92 | 93 | #if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) 94 | # define KHRONOS_STATIC 1 95 | #endif 96 | 97 | /*------------------------------------------------------------------------- 98 | * Definition of KHRONOS_APICALL 99 | *------------------------------------------------------------------------- 100 | * This precedes the return type of the function in the function prototype. 101 | */ 102 | #if defined(KHRONOS_STATIC) 103 | /* If the preprocessor constant KHRONOS_STATIC is defined, make the 104 | * header compatible with static linking. */ 105 | # define KHRONOS_APICALL 106 | #elif defined(_WIN32) 107 | # define KHRONOS_APICALL __declspec(dllimport) 108 | #elif defined (__SYMBIAN32__) 109 | # define KHRONOS_APICALL IMPORT_C 110 | #elif defined(__ANDROID__) 111 | # define KHRONOS_APICALL __attribute__((visibility("default"))) 112 | #else 113 | # define KHRONOS_APICALL 114 | #endif 115 | 116 | /*------------------------------------------------------------------------- 117 | * Definition of KHRONOS_APIENTRY 118 | *------------------------------------------------------------------------- 119 | * This follows the return type of the function and precedes the function 120 | * name in the function prototype. 121 | */ 122 | #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) 123 | /* Win32 but not WinCE */ 124 | # define KHRONOS_APIENTRY __stdcall 125 | #else 126 | # define KHRONOS_APIENTRY 127 | #endif 128 | 129 | /*------------------------------------------------------------------------- 130 | * Definition of KHRONOS_APIATTRIBUTES 131 | *------------------------------------------------------------------------- 132 | * This follows the closing parenthesis of the function prototype arguments. 133 | */ 134 | #if defined (__ARMCC_2__) 135 | #define KHRONOS_APIATTRIBUTES __softfp 136 | #else 137 | #define KHRONOS_APIATTRIBUTES 138 | #endif 139 | 140 | /*------------------------------------------------------------------------- 141 | * basic type definitions 142 | *-----------------------------------------------------------------------*/ 143 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) 144 | 145 | 146 | /* 147 | * Using 148 | */ 149 | #include 150 | typedef int32_t khronos_int32_t; 151 | typedef uint32_t khronos_uint32_t; 152 | typedef int64_t khronos_int64_t; 153 | typedef uint64_t khronos_uint64_t; 154 | #define KHRONOS_SUPPORT_INT64 1 155 | #define KHRONOS_SUPPORT_FLOAT 1 156 | 157 | #elif defined(__VMS ) || defined(__sgi) 158 | 159 | /* 160 | * Using 161 | */ 162 | #include 163 | typedef int32_t khronos_int32_t; 164 | typedef uint32_t khronos_uint32_t; 165 | typedef int64_t khronos_int64_t; 166 | typedef uint64_t khronos_uint64_t; 167 | #define KHRONOS_SUPPORT_INT64 1 168 | #define KHRONOS_SUPPORT_FLOAT 1 169 | 170 | #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) 171 | 172 | /* 173 | * Win32 174 | */ 175 | typedef __int32 khronos_int32_t; 176 | typedef unsigned __int32 khronos_uint32_t; 177 | typedef __int64 khronos_int64_t; 178 | typedef unsigned __int64 khronos_uint64_t; 179 | #define KHRONOS_SUPPORT_INT64 1 180 | #define KHRONOS_SUPPORT_FLOAT 1 181 | 182 | #elif defined(__sun__) || defined(__digital__) 183 | 184 | /* 185 | * Sun or Digital 186 | */ 187 | typedef int khronos_int32_t; 188 | typedef unsigned int khronos_uint32_t; 189 | #if defined(__arch64__) || defined(_LP64) 190 | typedef long int khronos_int64_t; 191 | typedef unsigned long int khronos_uint64_t; 192 | #else 193 | typedef long long int khronos_int64_t; 194 | typedef unsigned long long int khronos_uint64_t; 195 | #endif /* __arch64__ */ 196 | #define KHRONOS_SUPPORT_INT64 1 197 | #define KHRONOS_SUPPORT_FLOAT 1 198 | 199 | #elif 0 200 | 201 | /* 202 | * Hypothetical platform with no float or int64 support 203 | */ 204 | typedef int khronos_int32_t; 205 | typedef unsigned int khronos_uint32_t; 206 | #define KHRONOS_SUPPORT_INT64 0 207 | #define KHRONOS_SUPPORT_FLOAT 0 208 | 209 | #else 210 | 211 | /* 212 | * Generic fallback 213 | */ 214 | #include 215 | typedef int32_t khronos_int32_t; 216 | typedef uint32_t khronos_uint32_t; 217 | typedef int64_t khronos_int64_t; 218 | typedef uint64_t khronos_uint64_t; 219 | #define KHRONOS_SUPPORT_INT64 1 220 | #define KHRONOS_SUPPORT_FLOAT 1 221 | 222 | #endif 223 | 224 | 225 | /* 226 | * Types that are (so far) the same on all platforms 227 | */ 228 | typedef signed char khronos_int8_t; 229 | typedef unsigned char khronos_uint8_t; 230 | typedef signed short int khronos_int16_t; 231 | typedef unsigned short int khronos_uint16_t; 232 | 233 | /* 234 | * Types that differ between LLP64 and LP64 architectures - in LLP64, 235 | * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears 236 | * to be the only LLP64 architecture in current use. 237 | */ 238 | #ifdef _WIN64 239 | typedef signed long long int khronos_intptr_t; 240 | typedef unsigned long long int khronos_uintptr_t; 241 | typedef signed long long int khronos_ssize_t; 242 | typedef unsigned long long int khronos_usize_t; 243 | #else 244 | typedef signed long int khronos_intptr_t; 245 | typedef unsigned long int khronos_uintptr_t; 246 | typedef signed long int khronos_ssize_t; 247 | typedef unsigned long int khronos_usize_t; 248 | #endif 249 | 250 | #if KHRONOS_SUPPORT_FLOAT 251 | /* 252 | * Float type 253 | */ 254 | typedef float khronos_float_t; 255 | #endif 256 | 257 | #if KHRONOS_SUPPORT_INT64 258 | /* Time types 259 | * 260 | * These types can be used to represent a time interval in nanoseconds or 261 | * an absolute Unadjusted System Time. Unadjusted System Time is the number 262 | * of nanoseconds since some arbitrary system event (e.g. since the last 263 | * time the system booted). The Unadjusted System Time is an unsigned 264 | * 64 bit value that wraps back to 0 every 584 years. Time intervals 265 | * may be either signed or unsigned. 266 | */ 267 | typedef khronos_uint64_t khronos_utime_nanoseconds_t; 268 | typedef khronos_int64_t khronos_stime_nanoseconds_t; 269 | #endif 270 | 271 | /* 272 | * Dummy value used to pad enum types to 32 bits. 273 | */ 274 | #ifndef KHRONOS_MAX_ENUM 275 | #define KHRONOS_MAX_ENUM 0x7FFFFFFF 276 | #endif 277 | 278 | /* 279 | * Enumerated boolean type 280 | * 281 | * Values other than zero should be considered to be true. Therefore 282 | * comparisons should not be made against KHRONOS_TRUE. 283 | */ 284 | typedef enum { 285 | KHRONOS_FALSE = 0, 286 | KHRONOS_TRUE = 1, 287 | KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM 288 | } khronos_boolean_enum_t; 289 | 290 | #endif /* __khrplatform_h_ */ 291 | -------------------------------------------------------------------------------- /emulator/external/ImGui/include/TextEditor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "imgui.h" 12 | 13 | class TextEditor 14 | { 15 | public: 16 | enum class PaletteIndex 17 | { 18 | Default, 19 | Keyword, 20 | Number, 21 | String, 22 | CharLiteral, 23 | Punctuation, 24 | Preprocessor, 25 | Identifier, 26 | KnownIdentifier, 27 | PreprocIdentifier, 28 | Comment, 29 | MultiLineComment, 30 | Background, 31 | Cursor, 32 | Selection, 33 | ErrorMarker, 34 | Breakpoint, 35 | LineNumber, 36 | CurrentLineFill, 37 | CurrentLineFillInactive, 38 | CurrentLineEdge, 39 | Max 40 | }; 41 | 42 | enum class SelectionMode 43 | { 44 | Normal, 45 | Word, 46 | Line 47 | }; 48 | 49 | struct Breakpoint 50 | { 51 | int mLine; 52 | bool mEnabled; 53 | std::string mCondition; 54 | 55 | Breakpoint() 56 | : mLine(-1) 57 | , mEnabled(false) 58 | {} 59 | }; 60 | 61 | // Represents a character coordinate from the user's point of view, 62 | // i. e. consider an uniform grid (assuming fixed-width font) on the 63 | // screen as it is rendered, and each cell has its own coordinate, starting from 0. 64 | // Tabs are counted as [1..mTabSize] count empty spaces, depending on 65 | // how many space is necessary to reach the next tab stop. 66 | // For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4, 67 | // because it is rendered as " ABC" on the screen. 68 | struct Coordinates 69 | { 70 | int mLine, mColumn; 71 | Coordinates() : mLine(0), mColumn(0) {} 72 | Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn) 73 | { 74 | assert(aLine >= 0); 75 | assert(aColumn >= 0); 76 | } 77 | static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; } 78 | 79 | bool operator ==(const Coordinates& o) const 80 | { 81 | return 82 | mLine == o.mLine && 83 | mColumn == o.mColumn; 84 | } 85 | 86 | bool operator !=(const Coordinates& o) const 87 | { 88 | return 89 | mLine != o.mLine || 90 | mColumn != o.mColumn; 91 | } 92 | 93 | bool operator <(const Coordinates& o) const 94 | { 95 | if (mLine != o.mLine) 96 | return mLine < o.mLine; 97 | return mColumn < o.mColumn; 98 | } 99 | 100 | bool operator >(const Coordinates& o) const 101 | { 102 | if (mLine != o.mLine) 103 | return mLine > o.mLine; 104 | return mColumn > o.mColumn; 105 | } 106 | 107 | bool operator <=(const Coordinates& o) const 108 | { 109 | if (mLine != o.mLine) 110 | return mLine < o.mLine; 111 | return mColumn <= o.mColumn; 112 | } 113 | 114 | bool operator >=(const Coordinates& o) const 115 | { 116 | if (mLine != o.mLine) 117 | return mLine > o.mLine; 118 | return mColumn >= o.mColumn; 119 | } 120 | }; 121 | 122 | struct Identifier 123 | { 124 | Coordinates mLocation; 125 | std::string mDeclaration; 126 | }; 127 | 128 | typedef std::string String; 129 | typedef std::unordered_map Identifiers; 130 | typedef std::unordered_set Keywords; 131 | typedef std::map ErrorMarkers; 132 | typedef std::unordered_set Breakpoints; 133 | typedef std::array Palette; 134 | typedef uint8_t Char; 135 | 136 | struct Glyph 137 | { 138 | Char mChar; 139 | PaletteIndex mColorIndex = PaletteIndex::Default; 140 | bool mComment : 1; 141 | bool mMultiLineComment : 1; 142 | bool mPreprocessor : 1; 143 | 144 | Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex), 145 | mComment(false), mMultiLineComment(false), mPreprocessor(false) {} 146 | }; 147 | 148 | typedef std::vector Line; 149 | typedef std::vector Lines; 150 | 151 | struct LanguageDefinition 152 | { 153 | typedef std::pair TokenRegexString; 154 | typedef std::vector TokenRegexStrings; 155 | typedef bool(*TokenizeCallback)(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex); 156 | 157 | std::string mName; 158 | Keywords mKeywords; 159 | Identifiers mIdentifiers; 160 | Identifiers mPreprocIdentifiers; 161 | std::string mCommentStart, mCommentEnd, mSingleLineComment; 162 | char mPreprocChar; 163 | bool mAutoIndentation; 164 | 165 | TokenizeCallback mTokenize; 166 | 167 | TokenRegexStrings mTokenRegexStrings; 168 | 169 | bool mCaseSensitive; 170 | 171 | LanguageDefinition() 172 | : mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true) 173 | { 174 | } 175 | 176 | static const LanguageDefinition& CPlusPlus(); 177 | static const LanguageDefinition& HLSL(); 178 | static const LanguageDefinition& GLSL(); 179 | static const LanguageDefinition& C(); 180 | static const LanguageDefinition& SQL(); 181 | static const LanguageDefinition& AngelScript(); 182 | static const LanguageDefinition& Lua(); 183 | }; 184 | 185 | TextEditor(); 186 | ~TextEditor(); 187 | 188 | void SetLanguageDefinition(const LanguageDefinition& aLanguageDef); 189 | const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; } 190 | 191 | const Palette& GetPalette() const { return mPaletteBase; } 192 | void SetPalette(const Palette& aValue); 193 | 194 | void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; } 195 | void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; } 196 | 197 | void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false); 198 | void SetText(const std::string& aText); 199 | std::string GetText() const; 200 | 201 | void SetTextLines(const std::vector& aLines); 202 | std::vector GetTextLines() const; 203 | 204 | std::string GetSelectedText() const; 205 | std::string GetCurrentLineText()const; 206 | 207 | int GetTotalLines() const { return (int)mLines.size(); } 208 | bool IsOverwrite() const { return mOverwrite; } 209 | 210 | void SetReadOnly(bool aValue); 211 | bool IsReadOnly() const { return mReadOnly; } 212 | bool IsTextChanged() const { return mTextChanged; } 213 | bool IsCursorPositionChanged() const { return mCursorPositionChanged; } 214 | 215 | bool IsColorizerEnabled() const { return mColorizerEnabled; } 216 | void SetColorizerEnable(bool aValue); 217 | 218 | Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); } 219 | void SetCursorPosition(const Coordinates& aPosition); 220 | 221 | inline void SetHandleMouseInputs (bool aValue){ mHandleMouseInputs = aValue;} 222 | inline bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; } 223 | 224 | inline void SetHandleKeyboardInputs (bool aValue){ mHandleKeyboardInputs = aValue;} 225 | inline bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; } 226 | 227 | inline void SetImGuiChildIgnored (bool aValue){ mIgnoreImGuiChild = aValue;} 228 | inline bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; } 229 | 230 | inline void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; } 231 | inline bool IsShowingWhitespaces() const { return mShowWhitespaces; } 232 | 233 | void SetTabSize(int aValue); 234 | inline int GetTabSize() const { return mTabSize; } 235 | 236 | void InsertText(const std::string& aValue); 237 | void InsertText(const char* aValue); 238 | 239 | void MoveUp(int aAmount = 1, bool aSelect = false); 240 | void MoveDown(int aAmount = 1, bool aSelect = false); 241 | void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false); 242 | void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false); 243 | void MoveTop(bool aSelect = false); 244 | void MoveBottom(bool aSelect = false); 245 | void MoveHome(bool aSelect = false); 246 | void MoveEnd(bool aSelect = false); 247 | 248 | void SetSelectionStart(const Coordinates& aPosition); 249 | void SetSelectionEnd(const Coordinates& aPosition); 250 | void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal); 251 | void SelectWordUnderCursor(); 252 | void SelectAll(); 253 | bool HasSelection() const; 254 | 255 | void Copy(); 256 | void Cut(); 257 | void Paste(); 258 | void Delete(); 259 | 260 | bool CanUndo() const; 261 | bool CanRedo() const; 262 | void Undo(int aSteps = 1); 263 | void Redo(int aSteps = 1); 264 | 265 | static const Palette& GetDarkPalette(); 266 | static const Palette& GetLightPalette(); 267 | static const Palette& GetRetroBluePalette(); 268 | 269 | private: 270 | typedef std::vector> RegexList; 271 | 272 | struct EditorState 273 | { 274 | Coordinates mSelectionStart; 275 | Coordinates mSelectionEnd; 276 | Coordinates mCursorPosition; 277 | }; 278 | 279 | class UndoRecord 280 | { 281 | public: 282 | UndoRecord() {} 283 | ~UndoRecord() {} 284 | 285 | UndoRecord( 286 | const std::string& aAdded, 287 | const TextEditor::Coordinates aAddedStart, 288 | const TextEditor::Coordinates aAddedEnd, 289 | 290 | const std::string& aRemoved, 291 | const TextEditor::Coordinates aRemovedStart, 292 | const TextEditor::Coordinates aRemovedEnd, 293 | 294 | TextEditor::EditorState& aBefore, 295 | TextEditor::EditorState& aAfter); 296 | 297 | void Undo(TextEditor* aEditor); 298 | void Redo(TextEditor* aEditor); 299 | 300 | std::string mAdded; 301 | Coordinates mAddedStart; 302 | Coordinates mAddedEnd; 303 | 304 | std::string mRemoved; 305 | Coordinates mRemovedStart; 306 | Coordinates mRemovedEnd; 307 | 308 | EditorState mBefore; 309 | EditorState mAfter; 310 | }; 311 | 312 | typedef std::vector UndoBuffer; 313 | 314 | void ProcessInputs(); 315 | void Colorize(int aFromLine = 0, int aCount = -1); 316 | void ColorizeRange(int aFromLine = 0, int aToLine = 0); 317 | void ColorizeInternal(); 318 | float TextDistanceToLineStart(const Coordinates& aFrom) const; 319 | void EnsureCursorVisible(); 320 | int GetPageSize() const; 321 | std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const; 322 | Coordinates GetActualCursorCoordinates() const; 323 | Coordinates SanitizeCoordinates(const Coordinates& aValue) const; 324 | void Advance(Coordinates& aCoordinates) const; 325 | void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd); 326 | int InsertTextAt(Coordinates& aWhere, const char* aValue); 327 | void AddUndo(UndoRecord& aValue); 328 | Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const; 329 | Coordinates FindWordStart(const Coordinates& aFrom) const; 330 | Coordinates FindWordEnd(const Coordinates& aFrom) const; 331 | Coordinates FindNextWord(const Coordinates& aFrom) const; 332 | int GetCharacterIndex(const Coordinates& aCoordinates) const; 333 | int GetCharacterColumn(int aLine, int aIndex) const; 334 | int GetLineCharacterCount(int aLine) const; 335 | int GetLineMaxColumn(int aLine) const; 336 | bool IsOnWordBoundary(const Coordinates& aAt) const; 337 | void RemoveLine(int aStart, int aEnd); 338 | void RemoveLine(int aIndex); 339 | Line& InsertLine(int aIndex); 340 | void EnterCharacter(ImWchar aChar, bool aShift); 341 | void Backspace(); 342 | void DeleteSelection(); 343 | std::string GetWordUnderCursor() const; 344 | std::string GetWordAt(const Coordinates& aCoords) const; 345 | ImU32 GetGlyphColor(const Glyph& aGlyph) const; 346 | 347 | void HandleKeyboardInputs(); 348 | void HandleMouseInputs(); 349 | void Render(); 350 | 351 | float mLineSpacing; 352 | Lines mLines; 353 | EditorState mState; 354 | UndoBuffer mUndoBuffer; 355 | int mUndoIndex; 356 | 357 | int mTabSize; 358 | bool mOverwrite; 359 | bool mReadOnly; 360 | bool mWithinRender; 361 | bool mScrollToCursor; 362 | bool mScrollToTop; 363 | bool mTextChanged; 364 | bool mColorizerEnabled; 365 | float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor. 366 | int mLeftMargin; 367 | bool mCursorPositionChanged; 368 | int mColorRangeMin, mColorRangeMax; 369 | SelectionMode mSelectionMode; 370 | bool mHandleKeyboardInputs; 371 | bool mHandleMouseInputs; 372 | bool mIgnoreImGuiChild; 373 | bool mShowWhitespaces; 374 | 375 | Palette mPaletteBase; 376 | Palette mPalette; 377 | LanguageDefinition mLanguageDefinition; 378 | RegexList mRegexList; 379 | 380 | bool mCheckComments; 381 | Breakpoints mBreakpoints; 382 | ErrorMarkers mErrorMarkers; 383 | ImVec2 mCharAdvance; 384 | Coordinates mInteractiveStart, mInteractiveEnd; 385 | std::string mLineBuffer; 386 | uint64_t mStartTime; 387 | 388 | float mLastClick; 389 | }; 390 | 391 | bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); 392 | bool TokenizeCStyleCharacterLiteral(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); 393 | bool TokenizeCStyleIdentifier(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); 394 | bool TokenizeCStyleNumber(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); 395 | bool TokenizeCStylePunctuation(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imnodes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct ImVec2; 6 | 7 | namespace imnodes 8 | { 9 | enum ColorStyle 10 | { 11 | ColorStyle_NodeBackground = 0, 12 | ColorStyle_NodeBackgroundHovered, 13 | ColorStyle_NodeBackgroundSelected, 14 | ColorStyle_NodeOutline, 15 | ColorStyle_TitleBar, 16 | ColorStyle_TitleBarHovered, 17 | ColorStyle_TitleBarSelected, 18 | ColorStyle_Link, 19 | ColorStyle_LinkHovered, 20 | ColorStyle_LinkSelected, 21 | ColorStyle_Pin, 22 | ColorStyle_PinHovered, 23 | ColorStyle_BoxSelector, 24 | ColorStyle_BoxSelectorOutline, 25 | ColorStyle_GridBackground, 26 | ColorStyle_GridLine, 27 | ColorStyle_Count 28 | }; 29 | 30 | enum StyleVar 31 | { 32 | StyleVar_GridSpacing = 0, 33 | StyleVar_NodeCornerRounding, 34 | StyleVar_NodePaddingHorizontal, 35 | StyleVar_NodePaddingVertical, 36 | StyleVar_NodeBorderThickness, 37 | StyleVar_LinkThickness, 38 | StyleVar_LinkLineSegmentsPerLength, 39 | StyleVar_LinkHoverDistance, 40 | StyleVar_PinCircleRadius, 41 | StyleVar_PinQuadSideLength, 42 | StyleVar_PinTriangleSideLength, 43 | StyleVar_PinLineThickness, 44 | StyleVar_PinHoverRadius, 45 | StyleVar_PinOffset 46 | }; 47 | 48 | enum StyleFlags 49 | { 50 | StyleFlags_None = 0, 51 | StyleFlags_NodeOutline = 1 << 0, 52 | StyleFlags_GridLines = 1 << 2 53 | }; 54 | 55 | // This enum controls the way attribute pins look. 56 | enum PinShape 57 | { 58 | PinShape_Circle, 59 | PinShape_CircleFilled, 60 | PinShape_Triangle, 61 | PinShape_TriangleFilled, 62 | PinShape_Quad, 63 | PinShape_QuadFilled 64 | }; 65 | 66 | // This enum controls the way the attribute pins behave. 67 | enum AttributeFlags 68 | { 69 | AttributeFlags_None = 0, 70 | // Allow detaching a link by left-clicking and dragging the link at a pin it is connected to. 71 | // NOTE: the user has to actually delete the link for this to work. A deleted link can be 72 | // detected by calling IsLinkDestroyed() after EndNodeEditor(). 73 | AttributeFlags_EnableLinkDetachWithDragClick = 1 << 0, 74 | // Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows 75 | // for previewing the creation of a link while dragging it across attributes. See here for demo: 76 | // https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to 77 | // actually delete the link for this to work. A deleted link can be detected by calling 78 | // IsLinkDestroyed() after EndNodeEditor(). 79 | AttributeFlags_EnableLinkCreationOnSnap = 1 << 1 80 | }; 81 | 82 | struct IO 83 | { 84 | struct EmulateThreeButtonMouse 85 | { 86 | EmulateThreeButtonMouse(); 87 | 88 | // Controls whether this feature is enabled or not. 89 | bool enabled; 90 | const bool* modifier; // The keyboard modifier to use with the mouse left click. Set to 91 | // &ImGuiIO::KeyAlt by default. 92 | } emulate_three_button_mouse; 93 | 94 | struct LinkDetachWithModifierClick 95 | { 96 | LinkDetachWithModifierClick(); 97 | 98 | // Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL 99 | // by default (i.e. this feature is disabled). To enable the feature, set the link to point 100 | // to, for example, &ImGuiIO::KeyCtrl. 101 | // 102 | // Left-clicking a link with this modifier pressed will detach that link. NOTE: the user has 103 | // to actually delete the link for this to work. A deleted link can be detected by calling 104 | // IsLinkDestroyed() after EndNodeEditor(). 105 | const bool* modifier; 106 | } link_detach_with_modifier_click; 107 | 108 | IO(); 109 | }; 110 | 111 | struct Style 112 | { 113 | float grid_spacing; 114 | 115 | float node_corner_rounding; 116 | float node_padding_horizontal; 117 | float node_padding_vertical; 118 | float node_border_thickness; 119 | 120 | float link_thickness; 121 | float link_line_segments_per_length; 122 | float link_hover_distance; 123 | 124 | // The following variables control the look and behavior of the pins. The default size of each 125 | // pin shape is balanced to occupy approximately the same surface area on the screen. 126 | 127 | // The circle radius used when the pin shape is either PinShape_Circle or PinShape_CircleFilled. 128 | float pin_circle_radius; 129 | // The quad side length used when the shape is either PinShape_Quad or PinShape_QuadFilled. 130 | float pin_quad_side_length; 131 | // The equilateral triangle side length used when the pin shape is either PinShape_Triangle or 132 | // PinShape_TriangleFilled. 133 | float pin_triangle_side_length; 134 | // The thickness of the line used when the pin shape is not filled. 135 | float pin_line_thickness; 136 | // The radius from the pin's center position inside of which it is detected as being hovered 137 | // over. 138 | float pin_hover_radius; 139 | // Offsets the pins' positions from the edge of the node to the outside of the node. 140 | float pin_offset; 141 | 142 | // By default, StyleFlags_NodeOutline and StyleFlags_Gridlines are enabled. 143 | StyleFlags flags; 144 | // Set these mid-frame using Push/PopColorStyle. You can index this color array with with a 145 | // ColorStyle enum value. 146 | unsigned int colors[ColorStyle_Count]; 147 | 148 | Style(); 149 | }; 150 | 151 | // An editor context corresponds to a set of nodes in a single workspace (created with a single 152 | // Begin/EndNodeEditor pair) 153 | // 154 | // By default, the library creates an editor context behind the scenes, so using any of the imnodes 155 | // functions doesn't require you to explicitly create a context. 156 | struct EditorContext; 157 | 158 | EditorContext* EditorContextCreate(); 159 | void EditorContextFree(EditorContext*); 160 | void EditorContextSet(EditorContext*); 161 | ImVec2 EditorContextGetPanning(); 162 | void EditorContextResetPanning(const ImVec2& pos); 163 | void EditorContextMoveToNode(const int node_id); 164 | 165 | // Initialize the node editor system. 166 | void Initialize(); 167 | void Shutdown(); 168 | 169 | IO& GetIO(); 170 | 171 | // Returns the global style struct. See the struct declaration for default values. 172 | Style& GetStyle(); 173 | // Style presets matching the dear imgui styles of the same name. 174 | void StyleColorsDark(); // on by default 175 | void StyleColorsClassic(); 176 | void StyleColorsLight(); 177 | 178 | // The top-level function call. Call this before calling BeginNode/EndNode. Calling this function 179 | // will result the node editor grid workspace being rendered. 180 | void BeginNodeEditor(); 181 | void EndNodeEditor(); 182 | 183 | // Use PushColorStyle and PopColorStyle to modify Style::colors mid-frame. 184 | void PushColorStyle(ColorStyle item, unsigned int color); 185 | void PopColorStyle(); 186 | void PushStyleVar(StyleVar style_item, float value); 187 | void PopStyleVar(); 188 | 189 | // id can be any positive or negative integer, but INT_MIN is currently reserved for internal use. 190 | void BeginNode(int id); 191 | void EndNode(); 192 | 193 | ImVec2 GetNodeDimensions(int id); 194 | 195 | // Place your node title bar content (such as the node title, using ImGui::Text) between the 196 | // following function calls. These functions have to be called before adding any attributes, or the 197 | // layout of the node will be incorrect. 198 | void BeginNodeTitleBar(); 199 | void EndNodeTitleBar(); 200 | 201 | // Attributes are ImGui UI elements embedded within the node. Attributes can have pin shapes 202 | // rendered next to them. Links are created between pins. 203 | // 204 | // The activity status of an attribute can be checked via the IsAttributeActive() and 205 | // IsAnyAttributeActive() function calls. This is one easy way of checking for any changes made to 206 | // an attribute's drag float UI, for instance. 207 | // 208 | // Each attribute id must be unique. 209 | 210 | // Create an input attribute block. The pin is rendered on left side. 211 | void BeginInputAttribute(int id, PinShape shape = PinShape_CircleFilled); 212 | void EndInputAttribute(); 213 | // Create an output attribute block. The pin is rendered on the right side. 214 | void BeginOutputAttribute(int id, PinShape shape = PinShape_CircleFilled); 215 | void EndOutputAttribute(); 216 | // Create a static attribute block. A static attribute has no pin, and therefore can't be linked to 217 | // anything. However, you can still use IsAttributeActive() and IsAnyAttributeActive() to check for 218 | // attribute activity. 219 | void BeginStaticAttribute(int id); 220 | void EndStaticAttribute(); 221 | 222 | // Push a single AttributeFlags value. By default, only AttributeFlags_None is set. 223 | void PushAttributeFlag(AttributeFlags flag); 224 | void PopAttributeFlag(); 225 | 226 | // Render a link between attributes. 227 | // The attributes ids used here must match the ids used in Begin(Input|Output)Attribute function 228 | // calls. The order of start_attr and end_attr doesn't make a difference for rendering the link. 229 | void Link(int id, int start_attribute_id, int end_attribute_id); 230 | 231 | // Enable or disable the ability to click and drag a specific node. 232 | void SetNodeDraggable(int node_id, const bool draggable); 233 | 234 | // The node's position can be expressed in three coordinate systems: 235 | // * screen space coordinates, -- the origin is the upper left corner of the window. 236 | // * editor space coordinates -- the origin is the upper left corner of the node editor window 237 | // * grid space coordinates, -- the origin is the upper left corner of the node editor window, 238 | // translated by the current editor panning vector (see EditorContextGetPanning() and 239 | // EditorContextResetPanning()) 240 | 241 | // Use the following functions to get and set the node's coordinates in these coordinate systems. 242 | 243 | void SetNodeScreenSpacePos(int node_id, const ImVec2& screen_space_pos); 244 | void SetNodeEditorSpacePos(int node_id, const ImVec2& editor_space_pos); 245 | void SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos); 246 | 247 | ImVec2 GetNodeScreenSpacePos(const int node_id); 248 | ImVec2 GetNodeEditorSpacePos(const int node_id); 249 | ImVec2 GetNodeGridSpacePos(const int node_id); 250 | 251 | // Returns true if the current node editor canvas is being hovered over by the mouse, and is not 252 | // blocked by any other windows. 253 | bool IsEditorHovered(); 254 | // The following functions return true if a UI element is being hovered over by the mouse cursor. 255 | // Assigns the id of the UI element being hovered over to the function argument. Use these functions 256 | // after EndNodeEditor() has been called. 257 | bool IsNodeHovered(int* node_id); 258 | bool IsLinkHovered(int* link_id); 259 | bool IsPinHovered(int* attribute_id); 260 | 261 | // Use The following two functions to query the number of selected nodes or links in the current 262 | // editor. Use after calling EndNodeEditor(). 263 | int NumSelectedNodes(); 264 | int NumSelectedLinks(); 265 | // Get the selected node/link ids. The pointer argument should point to an integer array with at 266 | // least as many elements as the respective NumSelectedNodes/NumSelectedLinks function call 267 | // returned. 268 | void GetSelectedNodes(int* node_ids); 269 | void GetSelectedLinks(int* link_ids); 270 | 271 | // Clears the list of selected nodes/links. Useful if you want to delete a selected node or link. 272 | void ClearNodeSelection(); 273 | void ClearLinkSelection(); 274 | 275 | // Was the previous attribute active? This will continuously return true while the left mouse button 276 | // is being pressed over the UI content of the attribute. 277 | bool IsAttributeActive(); 278 | // Was any attribute active? If so, sets the active attribute id to the output function argument. 279 | bool IsAnyAttributeActive(int* attribute_id = NULL); 280 | 281 | // Use the following functions to query a change of state for an existing link, or new link. Call 282 | // these after EndNodeEditor(). 283 | 284 | // Did the user start dragging a new link from a pin? 285 | bool IsLinkStarted(int* started_at_attribute_id); 286 | // Did the user drop the dragged link before attaching it to a pin? 287 | // There are two different kinds of situations to consider when handling this event: 288 | // 1) a link which is created at a pin and then dropped 289 | // 2) an existing link which is detached from a pin and then dropped 290 | // Use the including_detached_links flag to control whether this function triggers when the user 291 | // detaches a link and drops it. 292 | bool IsLinkDropped(int* started_at_attribute_id = NULL, bool including_detached_links = true); 293 | // Did the user finish creating a new link? 294 | bool IsLinkCreated( 295 | int* started_at_attribute_id, 296 | int* ended_at_attribute_id, 297 | bool* created_from_snap = NULL); 298 | bool IsLinkCreated( 299 | int* started_at_node_id, 300 | int* started_at_attribute_id, 301 | int* ended_at_node_id, 302 | int* ended_at_attribute_id, 303 | bool* created_from_snap = NULL); 304 | 305 | // Was an existing link detached from a pin by the user? The detached link's id is assigned to the 306 | // output argument link_id. 307 | bool IsLinkDestroyed(int* link_id); 308 | 309 | // Use the following functions to write the editor context's state to a string, or directly to a 310 | // file. The editor context is serialized in the INI file format. 311 | 312 | const char* SaveCurrentEditorStateToIniString(size_t* data_size = NULL); 313 | const char* SaveEditorStateToIniString(const EditorContext* editor, size_t* data_size = NULL); 314 | 315 | void LoadCurrentEditorStateFromIniString(const char* data, size_t data_size); 316 | void LoadEditorStateFromIniString(EditorContext* editor, const char* data, size_t data_size); 317 | 318 | void SaveCurrentEditorStateToIniFile(const char* file_name); 319 | void SaveEditorStateToIniFile(const EditorContext* editor, const char* file_name); 320 | 321 | void LoadCurrentEditorStateFromIniFile(const char* file_name); 322 | void LoadEditorStateFromIniFile(EditorContext* editor, const char* file_name); 323 | } // namespace imnodes 324 | -------------------------------------------------------------------------------- /emulator/source/devices/cpu/core/core.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define INSTRUCTION(category, type, ...) { .category = { .type = { __VA_ARGS__ } } } 5 | 6 | #define INSTR_LOG(fmt, ...) log::debug("({:#x}) " fmt, regs.pc, __VA_ARGS__) 7 | 8 | namespace vc::dev::cpu { 9 | 10 | [[nodiscard]] 11 | constexpr u8 getOpcode(const u8 &address) { 12 | return address & 0b0111'1111; 13 | } 14 | 15 | void Core::execute() { 16 | if (this->halted) return; 17 | 18 | auto opcode = getOpcode(this->addressSpace(regs.pc, byte_tag())); 19 | 20 | /* Check if instruction is compressed */ 21 | if ((opcode & 0b11) != 0b11) { 22 | const auto &instr = reinterpret_cast(this->addressSpace(regs.pc, hword_tag())); 23 | 24 | this->nextPC = regs.pc + CompressedInstructionSize; 25 | executeCompressedInstruction(instr); 26 | } else { 27 | const auto &instr = reinterpret_cast(this->addressSpace(regs.pc, word_tag())); 28 | 29 | this->nextPC = regs.pc + InstructionSize; 30 | executeInstruction(instr); 31 | } 32 | 33 | addressSpace.tickDevices(); 34 | 35 | regs.pc = this->nextPC; 36 | } 37 | 38 | constexpr void Core::executeInstruction(const Instruction &instr) { 39 | switch (instr.getOpcode()) { 40 | case Opcode::OP_IMM: 41 | executeOPIMMInstruction(instr); 42 | break; 43 | case Opcode::OP_IMM32: 44 | executeOPIMM32Instruction(instr); 45 | break; 46 | case Opcode::STORE: 47 | executeSTOREInstruction(instr); 48 | break; 49 | case Opcode::LOAD: 50 | executeLOADInstruction(instr); 51 | break; 52 | case Opcode::AUIPC: 53 | { 54 | auto &i = instr.Base.U; 55 | INSTR_LOG("AUIPC x{}, #{:#x}", i.rd, i.getImmediate()); 56 | regs.x[i.rd] = regs.pc + i.getImmediate(); 57 | break; 58 | } 59 | case Opcode::JAL: 60 | { 61 | auto &i = instr.Immediate.J; 62 | INSTR_LOG("JAL #{:#x}", regs.pc + (util::signExtend<20, i64>(i.getImmediate()) * 2)); 63 | 64 | auto link = this->nextPC; 65 | this->nextPC = regs.pc + util::signExtend<20, i64>(i.getImmediate()) * 2; 66 | regs.x[i.rd] = link; 67 | 68 | break; 69 | } 70 | case Opcode::JALR: 71 | { 72 | auto &i = instr.Base.I; 73 | INSTR_LOG("JALR x{}, x{}, #{:#x}", i.rd, i.rs1, util::signExtend<12, i64>(i.getImmediate())); 74 | 75 | auto link = this->nextPC; 76 | this->nextPC = (util::signExtend<12, i64>(i.getImmediate()) + regs.x[i.rs1]) & u64(~0b1); 77 | regs.x[i.rd] = link; 78 | 79 | break; 80 | } 81 | case Opcode::BRANCH: 82 | executeBRANCHInstruction(instr); 83 | break; 84 | case Opcode::LUI: 85 | { 86 | auto &i = instr.Base.U; 87 | INSTR_LOG("LUI x{}, #{:#x}", i.rd, util::signExtend<20, i64>(i.getImmediate())); 88 | regs.x[i.rd] = util::signExtend<12, u64>(i.getImmediate()); 89 | break; 90 | } 91 | 92 | default: this->halt("Invalid instruction {:x}", instr.getOpcode()); 93 | } 94 | } 95 | 96 | constexpr void Core::executeOPInstruction(const Instruction &instr) { 97 | const auto &i = instr.Base.R; 98 | 99 | #define IS_FUNC(instruction, type) (instruction.funct3 == instr_t(OPFunc3::type) && instruction.funct7 == instr_t(OPFunc7::type)) 100 | 101 | if (IS_FUNC(i, ADD)) { 102 | regs.x[i.rd] = regs.x[i.rs1] + regs.x[i.rs2]; 103 | } else { 104 | this->halt("Invalid OP function {:x} {:x}", i.funct3, i.funct7); 105 | } 106 | 107 | #undef IS_FUNC 108 | } 109 | 110 | constexpr void Core::executeOPIMMInstruction(const Instruction &instr) { 111 | const auto &i = instr.Base.I; 112 | 113 | switch (static_cast(instr.getFunction3())) { 114 | case OPIMMFunc::XORI: 115 | { 116 | INSTR_LOG("XORI x{}, x{}, #{:#x}", i.rd, i.rs1, util::signExtend<12, i64>(i.getImmediate())); 117 | regs.x[i.rd] = regs.x[i.rs1] ^ util::signExtend<12, i64>(i.getImmediate()); 118 | break; 119 | } 120 | case OPIMMFunc::ORI: 121 | { 122 | INSTR_LOG("ORI x{}, x{}, #{:#x}", i.rd, i.rs1, util::signExtend<12, i64>(i.getImmediate())); 123 | regs.x[i.rd] = regs.x[i.rs1] | util::signExtend<12, i64>(i.getImmediate()); 124 | break; 125 | } 126 | case OPIMMFunc::ADDI: 127 | { 128 | INSTR_LOG("ADDI x{}, x{}, #{:#x}", i.rd, i.rs1, util::signExtend<12, i64>(i.getImmediate())); 129 | regs.x[i.rd] = regs.x[i.rs1] + util::signExtend<12, i64>(i.getImmediate()); 130 | break; 131 | } 132 | case OPIMMFunc::ANDI: 133 | { 134 | INSTR_LOG("ANDI x{}, x{}, #{:#x}", i.rd, i.rs1, util::signExtend<12, i64>(i.getImmediate())); 135 | regs.x[i.rd] = regs.x[i.rs1] & util::signExtend<12, i64>(i.getImmediate()); 136 | break; 137 | } 138 | default: this->halt("Invalid OPIMM function {:x}", instr.getFunction3()); 139 | } 140 | } 141 | 142 | constexpr void Core::executeOPIMM32Instruction(const Instruction &instr) { 143 | const auto &i = instr.Base.I; 144 | 145 | switch (static_cast(instr.getFunction3())) { 146 | case OPIMM32Func::ADDIW: 147 | { 148 | INSTR_LOG("ADDIW x{}, x{}, #{:#x}", i.rd, i.rs1, util::signExtend<12, i32>(i.getImmediate())); 149 | regs.x[i.rd] = util::signExtend<32, i64>((util::signExtend<12, i32>(i.getImmediate()) + regs.x[i.rs1]) & 0xFFFF'FFFF); 150 | break; 151 | } 152 | default: this->halt("Invalid OPIMM32 function {:x}", instr.getFunction3()); 153 | } 154 | } 155 | 156 | constexpr void Core::executeBRANCHInstruction(const Instruction &instr) { 157 | const auto &i = instr.Immediate.B; 158 | 159 | switch (static_cast(instr.getFunction3())) { 160 | case BRANCHFunc::BEQ: 161 | { 162 | INSTR_LOG("BEQ x{}, x{}, #{:#x}", i.rs1, i.rs2, regs.pc + (util::signExtend<20, i64>(i.getImmediate()) * 2)); 163 | if (regs.x[i.rs1] == regs.x[i.rs2]) { 164 | this->nextPC = regs.pc + util::signExtend<20, i64>(i.getImmediate()) * 2; 165 | } 166 | 167 | break; 168 | } 169 | case BRANCHFunc::BNE: 170 | { 171 | INSTR_LOG("BNE x{}, x{}, #{:#x}", i.rs1, i.rs2, regs.pc + (util::signExtend<20, i64>(i.getImmediate()) * 2)); 172 | if (regs.x[i.rs1] != regs.x[i.rs2]) { 173 | this->nextPC = regs.pc + util::signExtend<20, i64>(i.getImmediate()) * 2; 174 | } 175 | 176 | break; 177 | } 178 | default: this->halt("Invalid BRANCH function {:x}", instr.getFunction3()); 179 | } 180 | } 181 | 182 | constexpr void Core::executeLOADInstruction(const Instruction &instr) { 183 | const auto &i = instr.Base.I; 184 | 185 | switch (static_cast(instr.getFunction3())) { 186 | case LOADFunc::LB: 187 | { 188 | INSTR_LOG("LB x{}, #{:#x}(x{})", i.rd, util::signExtend<12, i32>(i.getImmediate()), i.rs1); 189 | regs.x[i.rd] = addressSpace(regs.x[i.rs1] + util::signExtend<12, i32>(i.getImmediate()), byte_tag{}); 190 | break; 191 | } 192 | case LOADFunc::LD: 193 | { 194 | INSTR_LOG("LD x{}, #{:#x}(x{})", i.rd, util::signExtend<12, i32>(i.getImmediate()), i.rs1); 195 | regs.x[i.rd] = addressSpace(regs.x[i.rs1] + util::signExtend<12, i32>(i.getImmediate()), dword_tag{}); 196 | break; 197 | } 198 | case LOADFunc::LBU: 199 | { 200 | INSTR_LOG("LBU x{}, #{:#x}(x{})", i.rd, i.getImmediate(), i.rs1); 201 | regs.x[i.rd] = addressSpace(regs.x[i.rs1] + i.getImmediate(), byte_tag{}); 202 | break; 203 | } 204 | default: this->halt("Invalid LOAD function {:x}", instr.getFunction3()); 205 | } 206 | } 207 | 208 | constexpr void Core::executeSTOREInstruction(const Instruction &instr) { 209 | const auto &i = instr.Base.S; 210 | 211 | switch (static_cast(instr.getFunction3())) { 212 | case STOREFunc::SB: 213 | { 214 | INSTR_LOG("SB x{}, #{:#x}(x{})", i.rs2, util::signExtend<12, i32>(i.getImmediate()), i.rs1); 215 | addressSpace(util::signExtend<12, i64>(i.getImmediate()) + regs.x[i.rs1], byte_tag{}) = regs.x[i.rs2]; 216 | break; 217 | } 218 | case STOREFunc::SH: 219 | { 220 | INSTR_LOG("SH x{}, #{:#x}(x{})", i.rs2, util::signExtend<12, i32>(i.getImmediate()), i.rs1); 221 | addressSpace(util::signExtend<12, i64>(i.getImmediate()) + regs.x[i.rs1], hword_tag{}) = regs.x[i.rs2]; 222 | break; 223 | } 224 | case STOREFunc::SW: 225 | { 226 | INSTR_LOG("SW x{}, #{:#x}(x{})", i.rs2, util::signExtend<12, i32>(i.getImmediate()), i.rs1); 227 | addressSpace(util::signExtend<12, i64>(i.getImmediate()) + regs.x[i.rs1], word_tag{}) = regs.x[i.rs2]; 228 | break; 229 | } 230 | case STOREFunc::SD: 231 | { 232 | INSTR_LOG("SD x{}, #{:#x}(x{})", i.rs2, util::signExtend<12, i32>(i.getImmediate()), i.rs1); 233 | addressSpace(util::signExtend<12, i64>(i.getImmediate()) + regs.x[i.rs1], dword_tag{}) = regs.x[i.rs2]; 234 | break; 235 | } 236 | default: this->halt("Invalid STORE function {:x}", instr.getFunction3()); 237 | } 238 | } 239 | 240 | 241 | /* Compressed instructions */ 242 | 243 | constexpr void Core::executeCompressedInstruction(const CompressedInstruction &instr) { 244 | switch (instr.getOpcode()) { 245 | case CompressedOpcode::C0: 246 | executeC0Instruction(instr); 247 | break; 248 | case CompressedOpcode::C1: 249 | executeC1Instruction(instr); 250 | break; 251 | case CompressedOpcode::C2: 252 | executeC2Instruction(instr); 253 | break; 254 | default: this->halt("Unknown compressed opcode {:x}!", instr.getOpcode()); 255 | } 256 | } 257 | 258 | constexpr void Core::executeC0Instruction(const CompressedInstruction &instr) { 259 | Instruction expanded = { 0 }; 260 | switch (static_cast(instr.getFunction3())) { 261 | case C0Funct::C_ADDI4SPN: 262 | { 263 | auto &i = instr.CIW; 264 | 265 | if (i.imm == 0) 266 | this->halt("Illegal instruction at {:#x}!", regs.pc); 267 | 268 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::OP_IMM), .rd = instr_t(i.rd + 8), .funct3 = instr_t(OPIMMFunc::ADDI), .rs1 = 2); 269 | expanded.Base.I.setImmediate(i.imm / 4); 270 | break; 271 | } 272 | default: this->halt("Invalid C0 function {:x}", instr.getFunction3()); 273 | } 274 | 275 | executeInstruction(expanded); 276 | } 277 | 278 | constexpr void Core::executeC1Instruction(const CompressedInstruction &instr) { 279 | Instruction expanded = { 0 }; 280 | switch (static_cast(instr.getFunction3())) { 281 | case C1Funct::C_ADDI: 282 | { 283 | auto &i = instr.CI; 284 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::OP_IMM), .rd = i.rd, .funct3 = instr_t(OPIMMFunc::ADDI), .rs1 = i.rd); 285 | expanded.Base.I.setImmediate(util::signExtend<6, i32>((i.imm3 << 5) | (i.imm2 << 3) | (i.imm1))); 286 | break; 287 | } 288 | case C1Funct::C_ADDIW: 289 | { 290 | auto &i = instr.CI; 291 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::OP_IMM32), .rd = i.rd, .funct3 = instr_t(OPIMM32Func::ADDIW), .rs1 = i.rd); 292 | expanded.Base.I.setImmediate(util::signExtend<6, i32>((i.imm3 << 5) | (i.imm2 << 3) | (i.imm1))); 293 | break; 294 | } 295 | case C1Funct::C_LI: 296 | { 297 | auto &i = instr.CI; 298 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::OP_IMM), .rd = i.rd, .funct3 = instr_t(OPIMMFunc::ADDI), .rs1 = 0); 299 | expanded.Base.I.setImmediate(util::signExtend<6, u32>((i.imm3 << 5) | (i.imm2 << 3) | (i.imm1))); 300 | break; 301 | } 302 | case C1Funct::C_LUI: 303 | { 304 | auto &i = instr.CI; 305 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::OP_IMM), .rd = i.rd, .funct3 = instr_t(OPIMMFunc::ADDI), .rs1 = i.rd); 306 | expanded.Base.I.setImmediate(util::signExtend<9, i32>((i.imm3 << 9) | ((i.imm1 >> 1) << 7) | ((i.imm2 & 0b01) << 6) | ((i.imm1 & 0b001) << 5) | (((i.imm1 & 0b010) >> 1) << 4))); 307 | break; 308 | } 309 | case C1Funct::C_ANDI: 310 | { 311 | auto &i = instr.CI; 312 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::OP_IMM), .rd = i.rd, .funct3 = instr_t(OPIMMFunc::ANDI), .rs1 = i.rd); 313 | expanded.Base.I.setImmediate(util::signExtend<6, i32>((i.imm3 << 5) | (i.imm2 << 3) | (i.imm1))); 314 | break; 315 | } 316 | default: this->halt("Invalid C1 function {:x}", instr.getFunction3()); 317 | } 318 | executeInstruction(expanded); 319 | } 320 | 321 | constexpr void Core::executeC2Instruction(const CompressedInstruction &instr) { 322 | Instruction expanded = { 0 }; 323 | switch (static_cast(instr.getFunction3())) { 324 | case C2Funct::C_JUMP: 325 | { 326 | auto &i = instr.CR; 327 | 328 | if (i.rd != 0 && i.funct4 == 0b1000 && i.rs2 != 0) /* C.MV */ { 329 | expanded = INSTRUCTION(Base, R, .opcode = instr_t(Opcode::LOAD), .rd = i.rd, .funct3 = instr_t(OPFunc3::ADD), .rs1 = 0, .rs2 = i.rs2, .funct7 = instr_t(OPFunc7::ADD)); 330 | } else if (i.rd != 0 && i.funct4 == 0b1000 && i.rs2 == 0) /* C.JR */ { 331 | INSTR_LOG("C.JR x{}, x{}, #{:#x}", 0, i.rd, 0); 332 | this->nextPC = regs.x[i.rd]; 333 | return; 334 | } else { 335 | this->halt("Invalid C2 C_JUMP function {:x}", instr.getFunction4()); 336 | } 337 | 338 | break; 339 | } 340 | case C2Funct::C_LDSP: 341 | { 342 | auto &i = instr.CI; 343 | expanded = INSTRUCTION(Base, I, .opcode = instr_t(Opcode::LOAD), .rd = i.rd, .funct3 = instr_t(LOADFunc::LD), .rs1 = 2); 344 | expanded.Base.I.setImmediate((i.imm1 << 6) | (i.imm3 << 5) | (i.imm2 << 3)); 345 | break; 346 | } 347 | case C2Funct::C_SDSP: 348 | { 349 | auto &i = instr.CSS; 350 | expanded = INSTRUCTION(Base, S, .opcode = instr_t(Opcode::STORE), .funct3 = instr_t(STOREFunc::SD), .rs1 = 2, .rs2 = i.rs2); 351 | expanded.Base.S.setImmediate(i.imm); 352 | break; 353 | } 354 | default: this->halt("Invalid C2 function {:x}", instr.getFunction3()); 355 | } 356 | 357 | executeInstruction(expanded); 358 | } 359 | 360 | } -------------------------------------------------------------------------------- /emulator/include/elf.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 3 | #ifndef _UAPI_LINUX_ELF_H 4 | #define _UAPI_LINUX_ELF_H 5 | 6 | #include 7 | 8 | /* 32-bit ELF base types. */ 9 | typedef u32 Elf32_Addr; 10 | typedef u16 Elf32_Half; 11 | typedef u32 Elf32_Off; 12 | typedef i32 Elf32_Sword; 13 | typedef u32 Elf32_Word; 14 | 15 | /* 64-bit ELF base types. */ 16 | typedef u64 Elf64_Addr; 17 | typedef u16 Elf64_Half; 18 | typedef i16 Elf64_SHalf; 19 | typedef u64 Elf64_Off; 20 | typedef i32 Elf64_Sword; 21 | typedef u32 Elf64_Word; 22 | typedef u64 Elf64_Xword; 23 | typedef i64 Elf64_Sxword; 24 | 25 | /* These constants are for the segment types stored in the image headers */ 26 | #define PT_NULL 0 27 | #define PT_LOAD 1 28 | #define PT_DYNAMIC 2 29 | #define PT_INTERP 3 30 | #define PT_NOTE 4 31 | #define PT_SHLIB 5 32 | #define PT_PHDR 6 33 | #define PT_TLS 7 /* Thread local storage segment */ 34 | #define PT_LOOS 0x60000000 /* OS-specific */ 35 | #define PT_HIOS 0x6fffffff /* OS-specific */ 36 | #define PT_LOPROC 0x70000000 37 | #define PT_HIPROC 0x7fffffff 38 | #define PT_GNU_EH_FRAME 0x6474e550 39 | #define PT_GNU_PROPERTY 0x6474e553 40 | 41 | #define PT_GNU_STACK (PT_LOOS + 0x474e551) 42 | 43 | /* 44 | * Extended Numbering 45 | * 46 | * If the real number of program header table entries is larger than 47 | * or equal to PN_XNUM(0xffff), it is set to sh_info field of the 48 | * section header at index 0, and PN_XNUM is set to e_phnum 49 | * field. Otherwise, the section header at index 0 is zero 50 | * initialized, if it exists. 51 | * 52 | * Specifications are available in: 53 | * 54 | * - Oracle: Linker and Libraries. 55 | * Part No: 817–1984–19, August 2011. 56 | * https://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf 57 | * 58 | * - System V ABI AMD64 Architecture Processor Supplement 59 | * Draft Version 0.99.4, 60 | * January 13, 2010. 61 | * http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf 62 | */ 63 | #define PN_XNUM 0xffff 64 | 65 | /* These constants define the different elf file types */ 66 | #define ET_NONE 0 67 | #define ET_REL 1 68 | #define ET_EXEC 2 69 | #define ET_DYN 3 70 | #define ET_CORE 4 71 | #define ET_LOPROC 0xff00 72 | #define ET_HIPROC 0xffff 73 | 74 | /* This is the info that is needed to parse the dynamic section of the file */ 75 | #define DT_NULL 0 76 | #define DT_NEEDED 1 77 | #define DT_PLTRELSZ 2 78 | #define DT_PLTGOT 3 79 | #define DT_HASH 4 80 | #define DT_STRTAB 5 81 | #define DT_SYMTAB 6 82 | #define DT_RELA 7 83 | #define DT_RELASZ 8 84 | #define DT_RELAENT 9 85 | #define DT_STRSZ 10 86 | #define DT_SYMENT 11 87 | #define DT_INIT 12 88 | #define DT_FINI 13 89 | #define DT_SONAME 14 90 | #define DT_RPATH 15 91 | #define DT_SYMBOLIC 16 92 | #define DT_REL 17 93 | #define DT_RELSZ 18 94 | #define DT_RELENT 19 95 | #define DT_PLTREL 20 96 | #define DT_DEBUG 21 97 | #define DT_TEXTREL 22 98 | #define DT_JMPREL 23 99 | #define DT_ENCODING 32 100 | #define OLD_DT_LOOS 0x60000000 101 | #define DT_LOOS 0x6000000d 102 | #define DT_HIOS 0x6ffff000 103 | #define DT_VALRNGLO 0x6ffffd00 104 | #define DT_VALRNGHI 0x6ffffdff 105 | #define DT_ADDRRNGLO 0x6ffffe00 106 | #define DT_ADDRRNGHI 0x6ffffeff 107 | #define DT_VERSYM 0x6ffffff0 108 | #define DT_RELACOUNT 0x6ffffff9 109 | #define DT_RELCOUNT 0x6ffffffa 110 | #define DT_FLAGS_1 0x6ffffffb 111 | #define DT_VERDEF 0x6ffffffc 112 | #define DT_VERDEFNUM 0x6ffffffd 113 | #define DT_VERNEED 0x6ffffffe 114 | #define DT_VERNEEDNUM 0x6fffffff 115 | #define OLD_DT_HIOS 0x6fffffff 116 | #define DT_LOPROC 0x70000000 117 | #define DT_HIPROC 0x7fffffff 118 | 119 | /* This info is needed when parsing the symbol table */ 120 | #define STB_LOCAL 0 121 | #define STB_GLOBAL 1 122 | #define STB_WEAK 2 123 | 124 | #define STT_NOTYPE 0 125 | #define STT_OBJECT 1 126 | #define STT_FUNC 2 127 | #define STT_SECTION 3 128 | #define STT_FILE 4 129 | #define STT_COMMON 5 130 | #define STT_TLS 6 131 | 132 | #define ELF_ST_BIND(x) ((x) >> 4) 133 | #define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) 134 | #define ELF32_ST_BIND(x) ELF_ST_BIND(x) 135 | #define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) 136 | #define ELF64_ST_BIND(x) ELF_ST_BIND(x) 137 | #define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) 138 | 139 | typedef struct dynamic{ 140 | Elf32_Sword d_tag; 141 | union{ 142 | Elf32_Sword d_val; 143 | Elf32_Addr d_ptr; 144 | } d_un; 145 | } Elf32_Dyn; 146 | 147 | typedef struct { 148 | Elf64_Sxword d_tag; /* entry tag value */ 149 | union { 150 | Elf64_Xword d_val; 151 | Elf64_Addr d_ptr; 152 | } d_un; 153 | } Elf64_Dyn; 154 | 155 | /* The following are used with relocations */ 156 | #define ELF32_R_SYM(x) ((x) >> 8) 157 | #define ELF32_R_TYPE(x) ((x) & 0xff) 158 | 159 | #define ELF64_R_SYM(i) ((i) >> 32) 160 | #define ELF64_R_TYPE(i) ((i) & 0xffffffff) 161 | 162 | typedef struct elf32_rel { 163 | Elf32_Addr r_offset; 164 | Elf32_Word r_info; 165 | } Elf32_Rel; 166 | 167 | typedef struct elf64_rel { 168 | Elf64_Addr r_offset; /* Location at which to apply the action */ 169 | Elf64_Xword r_info; /* index and type of relocation */ 170 | } Elf64_Rel; 171 | 172 | typedef struct elf32_rela{ 173 | Elf32_Addr r_offset; 174 | Elf32_Word r_info; 175 | Elf32_Sword r_addend; 176 | } Elf32_Rela; 177 | 178 | typedef struct elf64_rela { 179 | Elf64_Addr r_offset; /* Location at which to apply the action */ 180 | Elf64_Xword r_info; /* index and type of relocation */ 181 | Elf64_Sxword r_addend; /* Constant addend used to compute value */ 182 | } Elf64_Rela; 183 | 184 | typedef struct elf32_sym{ 185 | Elf32_Word st_name; 186 | Elf32_Addr st_value; 187 | Elf32_Word st_size; 188 | unsigned char st_info; 189 | unsigned char st_other; 190 | Elf32_Half st_shndx; 191 | } Elf32_Sym; 192 | 193 | typedef struct elf64_sym { 194 | Elf64_Word st_name; /* Symbol name, index in string tbl */ 195 | unsigned char st_info; /* Type and binding attributes */ 196 | unsigned char st_other; /* No defined meaning, 0 */ 197 | Elf64_Half st_shndx; /* Associated section index */ 198 | Elf64_Addr st_value; /* Value of the symbol */ 199 | Elf64_Xword st_size; /* Associated symbol size */ 200 | } Elf64_Sym; 201 | 202 | 203 | #define EI_NIDENT 16 204 | 205 | typedef struct elf32_hdr{ 206 | unsigned char e_ident[EI_NIDENT]; 207 | Elf32_Half e_type; 208 | Elf32_Half e_machine; 209 | Elf32_Word e_version; 210 | Elf32_Addr e_entry; /* Entry point */ 211 | Elf32_Off e_phoff; 212 | Elf32_Off e_shoff; 213 | Elf32_Word e_flags; 214 | Elf32_Half e_ehsize; 215 | Elf32_Half e_phentsize; 216 | Elf32_Half e_phnum; 217 | Elf32_Half e_shentsize; 218 | Elf32_Half e_shnum; 219 | Elf32_Half e_shstrndx; 220 | } Elf32_Ehdr; 221 | 222 | typedef struct elf64_hdr { 223 | unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ 224 | Elf64_Half e_type; 225 | Elf64_Half e_machine; 226 | Elf64_Word e_version; 227 | Elf64_Addr e_entry; /* Entry point virtual address */ 228 | Elf64_Off e_phoff; /* Program header table file offset */ 229 | Elf64_Off e_shoff; /* Section header table file offset */ 230 | Elf64_Word e_flags; 231 | Elf64_Half e_ehsize; 232 | Elf64_Half e_phentsize; 233 | Elf64_Half e_phnum; 234 | Elf64_Half e_shentsize; 235 | Elf64_Half e_shnum; 236 | Elf64_Half e_shstrndx; 237 | } Elf64_Ehdr; 238 | 239 | /* These constants define the permissions on sections in the program 240 | header, p_flags. */ 241 | #define PF_R 0x4 242 | #define PF_W 0x2 243 | #define PF_X 0x1 244 | 245 | typedef struct elf32_phdr{ 246 | Elf32_Word p_type; 247 | Elf32_Off p_offset; 248 | Elf32_Addr p_vaddr; 249 | Elf32_Addr p_paddr; 250 | Elf32_Word p_filesz; 251 | Elf32_Word p_memsz; 252 | Elf32_Word p_flags; 253 | Elf32_Word p_align; 254 | } Elf32_Phdr; 255 | 256 | typedef struct elf64_phdr { 257 | Elf64_Word p_type; 258 | Elf64_Word p_flags; 259 | Elf64_Off p_offset; /* Segment file offset */ 260 | Elf64_Addr p_vaddr; /* Segment virtual address */ 261 | Elf64_Addr p_paddr; /* Segment physical address */ 262 | Elf64_Xword p_filesz; /* Segment size in file */ 263 | Elf64_Xword p_memsz; /* Segment size in memory */ 264 | Elf64_Xword p_align; /* Segment alignment, file & memory */ 265 | } Elf64_Phdr; 266 | 267 | /* sh_type */ 268 | #define SHT_NULL 0 269 | #define SHT_PROGBITS 1 270 | #define SHT_SYMTAB 2 271 | #define SHT_STRTAB 3 272 | #define SHT_RELA 4 273 | #define SHT_HASH 5 274 | #define SHT_DYNAMIC 6 275 | #define SHT_NOTE 7 276 | #define SHT_NOBITS 8 277 | #define SHT_REL 9 278 | #define SHT_SHLIB 10 279 | #define SHT_DYNSYM 11 280 | #define SHT_NUM 12 281 | #define SHT_LOPROC 0x70000000 282 | #define SHT_HIPROC 0x7fffffff 283 | #define SHT_LOUSER 0x80000000 284 | #define SHT_HIUSER 0xffffffff 285 | 286 | /* sh_flags */ 287 | #define SHF_WRITE 0x1 288 | #define SHF_ALLOC 0x2 289 | #define SHF_EXECINSTR 0x4 290 | #define SHF_RELA_LIVEPATCH 0x00100000 291 | #define SHF_RO_AFTER_INIT 0x00200000 292 | #define SHF_MASKPROC 0xf0000000 293 | 294 | /* special section indexes */ 295 | #define SHN_UNDEF 0 296 | #define SHN_LORESERVE 0xff00 297 | #define SHN_LOPROC 0xff00 298 | #define SHN_HIPROC 0xff1f 299 | #define SHN_LIVEPATCH 0xff20 300 | #define SHN_ABS 0xfff1 301 | #define SHN_COMMON 0xfff2 302 | #define SHN_HIRESERVE 0xffff 303 | 304 | typedef struct elf32_shdr { 305 | Elf32_Word sh_name; 306 | Elf32_Word sh_type; 307 | Elf32_Word sh_flags; 308 | Elf32_Addr sh_addr; 309 | Elf32_Off sh_offset; 310 | Elf32_Word sh_size; 311 | Elf32_Word sh_link; 312 | Elf32_Word sh_info; 313 | Elf32_Word sh_addralign; 314 | Elf32_Word sh_entsize; 315 | } Elf32_Shdr; 316 | 317 | typedef struct elf64_shdr { 318 | Elf64_Word sh_name; /* Section name, index in string tbl */ 319 | Elf64_Word sh_type; /* Type of section */ 320 | Elf64_Xword sh_flags; /* Miscellaneous section attributes */ 321 | Elf64_Addr sh_addr; /* Section virtual addr at execution */ 322 | Elf64_Off sh_offset; /* Section file offset */ 323 | Elf64_Xword sh_size; /* Size of section in bytes */ 324 | Elf64_Word sh_link; /* Index of another section */ 325 | Elf64_Word sh_info; /* Additional section information */ 326 | Elf64_Xword sh_addralign; /* Section alignment */ 327 | Elf64_Xword sh_entsize; /* Entry size if section holds table */ 328 | } Elf64_Shdr; 329 | 330 | #define EI_MAG0 0 /* e_ident[] indexes */ 331 | #define EI_MAG1 1 332 | #define EI_MAG2 2 333 | #define EI_MAG3 3 334 | #define EI_CLASS 4 335 | #define EI_DATA 5 336 | #define EI_VERSION 6 337 | #define EI_OSABI 7 338 | #define EI_PAD 8 339 | 340 | #define ELFMAG0 0x7f /* EI_MAG */ 341 | #define ELFMAG1 'E' 342 | #define ELFMAG2 'L' 343 | #define ELFMAG3 'F' 344 | #define ELFMAG "\177ELF" 345 | #define SELFMAG 4 346 | 347 | #define ELFCLASSNONE 0 /* EI_CLASS */ 348 | #define ELFCLASS32 1 349 | #define ELFCLASS64 2 350 | #define ELFCLASSNUM 3 351 | 352 | #define ELFDATANONE 0 /* e_ident[EI_DATA] */ 353 | #define ELFDATA2LSB 1 354 | #define ELFDATA2MSB 2 355 | 356 | #define EV_NONE 0 /* e_version, EI_VERSION */ 357 | #define EV_CURRENT 1 358 | #define EV_NUM 2 359 | 360 | #define ELFOSABI_NONE 0 361 | #define ELFOSABI_LINUX 3 362 | 363 | #ifndef ELF_OSABI 364 | #define ELF_OSABI ELFOSABI_NONE 365 | #endif 366 | 367 | /* 368 | * Notes used in ET_CORE. Architectures export some of the arch register sets 369 | * using the corresponding note types via the PTRACE_GETREGSET and 370 | * PTRACE_SETREGSET requests. 371 | * The note name for all these is "LINUX". 372 | */ 373 | #define NT_PRSTATUS 1 374 | #define NT_PRFPREG 2 375 | #define NT_PRPSINFO 3 376 | #define NT_TASKSTRUCT 4 377 | #define NT_AUXV 6 378 | /* 379 | * Note to userspace developers: size of NT_SIGINFO note may increase 380 | * in the future to accomodate more fields, don't assume it is fixed! 381 | */ 382 | #define NT_SIGINFO 0x53494749 383 | #define NT_FILE 0x46494c45 384 | #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ 385 | #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ 386 | #define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ 387 | #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ 388 | #define NT_PPC_TAR 0x103 /* Target Address Register */ 389 | #define NT_PPC_PPR 0x104 /* Program Priority Register */ 390 | #define NT_PPC_DSCR 0x105 /* Data Stream Control Register */ 391 | #define NT_PPC_EBB 0x106 /* Event Based Branch Registers */ 392 | #define NT_PPC_PMU 0x107 /* Performance Monitor Registers */ 393 | #define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ 394 | #define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ 395 | #define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ 396 | #define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ 397 | #define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ 398 | #define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */ 399 | #define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */ 400 | #define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */ 401 | #define NT_PPC_PKEY 0x110 /* Memory Protection Keys registers */ 402 | #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ 403 | #define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ 404 | #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ 405 | #define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ 406 | #define NT_S390_TIMER 0x301 /* s390 timer register */ 407 | #define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ 408 | #define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ 409 | #define NT_S390_CTRS 0x304 /* s390 control registers */ 410 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ 411 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ 412 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ 413 | #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ 414 | #define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ 415 | #define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ 416 | #define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */ 417 | #define NT_S390_GS_BC 0x30c /* s390 guarded storage broadcast control block */ 418 | #define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */ 419 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ 420 | #define NT_ARM_TLS 0x401 /* ARM TLS register */ 421 | #define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ 422 | #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ 423 | #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ 424 | #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */ 425 | #define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */ 426 | #define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */ 427 | #define NT_ARM_PACG_KEYS 0x408 /* ARM pointer authentication generic key */ 428 | #define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* arm64 tagged address control (prctl()) */ 429 | #define NT_ARM_PAC_ENABLED_KEYS 0x40a /* arm64 ptr auth enabled keys (prctl()) */ 430 | #define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ 431 | #define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ 432 | #define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ 433 | #define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode */ 434 | #define NT_MIPS_MSA 0x802 /* MIPS SIMD registers */ 435 | 436 | /* Note types with note name "GNU" */ 437 | #define NT_GNU_PROPERTY_TYPE_0 5 438 | 439 | /* Note header in a PT_NOTE section */ 440 | typedef struct elf32_note { 441 | Elf32_Word n_namesz; /* Name size */ 442 | Elf32_Word n_descsz; /* Content size */ 443 | Elf32_Word n_type; /* Content type */ 444 | } Elf32_Nhdr; 445 | 446 | /* Note header in a PT_NOTE section */ 447 | typedef struct elf64_note { 448 | Elf64_Word n_namesz; /* Name size */ 449 | Elf64_Word n_descsz; /* Content size */ 450 | Elf64_Word n_type; /* Content type */ 451 | } Elf64_Nhdr; 452 | 453 | /* .note.gnu.property types for EM_AARCH64: */ 454 | #define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 455 | 456 | /* Bits for GNU_PROPERTY_AARCH64_FEATURE_1_BTI */ 457 | #define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0) 458 | 459 | #endif /* _UAPI_LINUX_ELF_H */ -------------------------------------------------------------------------------- /emulator/external/ImGui/include/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.00. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Added STBRP__CDECL 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_rect_pack.h - v1.00 - public domain - rectangle packing 8 | // Sean Barrett 2014 9 | // 10 | // Useful for e.g. packing rectangular textures into an atlas. 11 | // Does not do rotation. 12 | // 13 | // Not necessarily the awesomest packing method, but better than 14 | // the totally naive one in stb_truetype (which is primarily what 15 | // this is meant to replace). 16 | // 17 | // Has only had a few tests run, may have issues. 18 | // 19 | // More docs to come. 20 | // 21 | // No memory allocations; uses qsort() and assert() from stdlib. 22 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 23 | // 24 | // This library currently uses the Skyline Bottom-Left algorithm. 25 | // 26 | // Please note: better rectangle packers are welcome! Please 27 | // implement them to the same API, but with a different init 28 | // function. 29 | // 30 | // Credits 31 | // 32 | // Library 33 | // Sean Barrett 34 | // Minor features 35 | // Martins Mozeiko 36 | // github:IntellectualKitty 37 | // 38 | // Bugfixes / warning fixes 39 | // Jeremy Jaussaud 40 | // Fabian Giesen 41 | // 42 | // Version history: 43 | // 44 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 | // 0.99 (2019-02-07) warning fixes 46 | // 0.11 (2017-03-03) return packing success/fail result 47 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 48 | // 0.09 (2016-08-27) fix compiler warnings 49 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 50 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 51 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 52 | // 0.05: added STBRP_ASSERT to allow replacing assert 53 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 54 | // 0.01: initial release 55 | // 56 | // LICENSE 57 | // 58 | // See end of file for license information. 59 | 60 | ////////////////////////////////////////////////////////////////////////////// 61 | // 62 | // INCLUDE SECTION 63 | // 64 | 65 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 66 | #define STB_INCLUDE_STB_RECT_PACK_H 67 | 68 | #define STB_RECT_PACK_VERSION 1 69 | 70 | #ifdef STBRP_STATIC 71 | #define STBRP_DEF static 72 | #else 73 | #define STBRP_DEF extern 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" { 78 | #endif 79 | 80 | typedef struct stbrp_context stbrp_context; 81 | typedef struct stbrp_node stbrp_node; 82 | typedef struct stbrp_rect stbrp_rect; 83 | 84 | #ifdef STBRP_LARGE_RECTS 85 | typedef int stbrp_coord; 86 | #else 87 | typedef unsigned short stbrp_coord; 88 | #endif 89 | 90 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 | // Assign packed locations to rectangles. The rectangles are of type 92 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 | // are 'num_rects' many of them. 94 | // 95 | // Rectangles which are successfully packed have the 'was_packed' flag 96 | // set to a non-zero value and 'x' and 'y' store the minimum location 97 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 | // if you imagine y increasing downwards). Rectangles which do not fit 99 | // have the 'was_packed' flag set to 0. 100 | // 101 | // You should not try to access the 'rects' array from another thread 102 | // while this function is running, as the function temporarily reorders 103 | // the array while it executes. 104 | // 105 | // To pack into another rectangle, you need to call stbrp_init_target 106 | // again. To continue packing into the same rectangle, you can call 107 | // this function again. Calling this multiple times with multiple rect 108 | // arrays will probably produce worse packing results than calling it 109 | // a single time with the full rectangle array, but the option is 110 | // available. 111 | // 112 | // The function returns 1 if all of the rectangles were successfully 113 | // packed and 0 otherwise. 114 | 115 | struct stbrp_rect 116 | { 117 | // reserved for your use: 118 | int id; 119 | 120 | // input: 121 | stbrp_coord w, h; 122 | 123 | // output: 124 | stbrp_coord x, y; 125 | int was_packed; // non-zero if valid packing 126 | 127 | }; // 16 bytes, nominally 128 | 129 | 130 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 | // Initialize a rectangle packer to: 132 | // pack a rectangle that is 'width' by 'height' in dimensions 133 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 | // 135 | // You must call this function every time you start packing into a new target. 136 | // 137 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 | // the following stbrp_pack_rects() call (or calls), but can be freed after 139 | // the call (or calls) finish. 140 | // 141 | // Note: to guarantee best results, either: 142 | // 1. make sure 'num_nodes' >= 'width' 143 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 | // 145 | // If you don't do either of the above things, widths will be quantized to multiples 146 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 | // 148 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 | // may run out of temporary storage and be unable to pack some rectangles. 150 | 151 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 | // Optionally call this function after init but before doing any packing to 153 | // change the handling of the out-of-temp-memory scenario, described above. 154 | // If you call init again, this will be reset to the default (false). 155 | 156 | 157 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 | // Optionally select which packing heuristic the library should use. Different 159 | // heuristics will produce better/worse results for different data sets. 160 | // If you call init again, this will be reset to the default. 161 | 162 | enum 163 | { 164 | STBRP_HEURISTIC_Skyline_default=0, 165 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 | STBRP_HEURISTIC_Skyline_BF_sortHeight 167 | }; 168 | 169 | 170 | ////////////////////////////////////////////////////////////////////////////// 171 | // 172 | // the details of the following structures don't matter to you, but they must 173 | // be visible so you can handle the memory allocations for them 174 | 175 | struct stbrp_node 176 | { 177 | stbrp_coord x,y; 178 | stbrp_node *next; 179 | }; 180 | 181 | struct stbrp_context 182 | { 183 | int width; 184 | int height; 185 | int align; 186 | int init_mode; 187 | int heuristic; 188 | int num_nodes; 189 | stbrp_node *active_head; 190 | stbrp_node *free_head; 191 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 | }; 193 | 194 | #ifdef __cplusplus 195 | } 196 | #endif 197 | 198 | #endif 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | // 202 | // IMPLEMENTATION SECTION 203 | // 204 | 205 | #ifdef STB_RECT_PACK_IMPLEMENTATION 206 | #ifndef STBRP_SORT 207 | #include 208 | #define STBRP_SORT qsort 209 | #endif 210 | 211 | #ifndef STBRP_ASSERT 212 | #include 213 | #define STBRP_ASSERT assert 214 | #endif 215 | 216 | // [DEAR IMGUI] Added STBRP__CDECL 217 | #ifdef _MSC_VER 218 | #define STBRP__NOTUSED(v) (void)(v) 219 | #define STBRP__CDECL __cdecl 220 | #else 221 | #define STBRP__NOTUSED(v) (void)sizeof(v) 222 | #define STBRP__CDECL 223 | #endif 224 | 225 | enum 226 | { 227 | STBRP__INIT_skyline = 1 228 | }; 229 | 230 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 231 | { 232 | switch (context->init_mode) { 233 | case STBRP__INIT_skyline: 234 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 | context->heuristic = heuristic; 236 | break; 237 | default: 238 | STBRP_ASSERT(0); 239 | } 240 | } 241 | 242 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 243 | { 244 | if (allow_out_of_mem) 245 | // if it's ok to run out of memory, then don't bother aligning them; 246 | // this gives better packing, but may fail due to OOM (even though 247 | // the rectangles easily fit). @TODO a smarter approach would be to only 248 | // quantize once we've hit OOM, then we could get rid of this parameter. 249 | context->align = 1; 250 | else { 251 | // if it's not ok to run out of memory, then quantize the widths 252 | // so that num_nodes is always enough nodes. 253 | // 254 | // I.e. num_nodes * align >= width 255 | // align >= width / num_nodes 256 | // align = ceil(width/num_nodes) 257 | 258 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 259 | } 260 | } 261 | 262 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 263 | { 264 | int i; 265 | #ifndef STBRP_LARGE_RECTS 266 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 267 | #endif 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | #ifdef STBRP_LARGE_RECTS 287 | context->extra[1].y = (1<<30); 288 | #else 289 | context->extra[1].y = 65535; 290 | #endif 291 | context->extra[1].next = NULL; 292 | } 293 | 294 | // find minimum y position if it starts at x1 295 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 296 | { 297 | stbrp_node *node = first; 298 | int x1 = x0 + width; 299 | int min_y, visited_width, waste_area; 300 | 301 | STBRP__NOTUSED(c); 302 | 303 | STBRP_ASSERT(first->x <= x0); 304 | 305 | #if 0 306 | // skip in case we're past the node 307 | while (node->next->x <= x0) 308 | ++node; 309 | #else 310 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 311 | #endif 312 | 313 | STBRP_ASSERT(node->x <= x0); 314 | 315 | min_y = 0; 316 | waste_area = 0; 317 | visited_width = 0; 318 | while (node->x < x1) { 319 | if (node->y > min_y) { 320 | // raise min_y higher. 321 | // we've accounted for all waste up to min_y, 322 | // but we'll now add more waste for everything we've visted 323 | waste_area += visited_width * (node->y - min_y); 324 | min_y = node->y; 325 | // the first time through, visited_width might be reduced 326 | if (node->x < x0) 327 | visited_width += node->next->x - x0; 328 | else 329 | visited_width += node->next->x - node->x; 330 | } else { 331 | // add waste area 332 | int under_width = node->next->x - node->x; 333 | if (under_width + visited_width > width) 334 | under_width = width - visited_width; 335 | waste_area += under_width * (min_y - node->y); 336 | visited_width += under_width; 337 | } 338 | node = node->next; 339 | } 340 | 341 | *pwaste = waste_area; 342 | return min_y; 343 | } 344 | 345 | typedef struct 346 | { 347 | int x,y; 348 | stbrp_node **prev_link; 349 | } stbrp__findresult; 350 | 351 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 352 | { 353 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 354 | stbrp__findresult fr; 355 | stbrp_node **prev, *node, *tail, **best = NULL; 356 | 357 | // align to multiple of c->align 358 | width = (width + c->align - 1); 359 | width -= width % c->align; 360 | STBRP_ASSERT(width % c->align == 0); 361 | 362 | // if it can't possibly fit, bail immediately 363 | if (width > c->width || height > c->height) { 364 | fr.prev_link = NULL; 365 | fr.x = fr.y = 0; 366 | return fr; 367 | } 368 | 369 | node = c->active_head; 370 | prev = &c->active_head; 371 | while (node->x + width <= c->width) { 372 | int y,waste; 373 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 374 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 375 | // bottom left 376 | if (y < best_y) { 377 | best_y = y; 378 | best = prev; 379 | } 380 | } else { 381 | // best-fit 382 | if (y + height <= c->height) { 383 | // can only use it if it first vertically 384 | if (y < best_y || (y == best_y && waste < best_waste)) { 385 | best_y = y; 386 | best_waste = waste; 387 | best = prev; 388 | } 389 | } 390 | } 391 | prev = &node->next; 392 | node = node->next; 393 | } 394 | 395 | best_x = (best == NULL) ? 0 : (*best)->x; 396 | 397 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 398 | // 399 | // e.g, if fitting 400 | // 401 | // ____________________ 402 | // |____________________| 403 | // 404 | // into 405 | // 406 | // | | 407 | // | ____________| 408 | // |____________| 409 | // 410 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 411 | // 412 | // This makes BF take about 2x the time 413 | 414 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 415 | tail = c->active_head; 416 | node = c->active_head; 417 | prev = &c->active_head; 418 | // find first node that's admissible 419 | while (tail->x < width) 420 | tail = tail->next; 421 | while (tail) { 422 | int xpos = tail->x - width; 423 | int y,waste; 424 | STBRP_ASSERT(xpos >= 0); 425 | // find the left position that matches this 426 | while (node->next->x <= xpos) { 427 | prev = &node->next; 428 | node = node->next; 429 | } 430 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 431 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 432 | if (y + height <= c->height) { 433 | if (y <= best_y) { 434 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 435 | best_x = xpos; 436 | STBRP_ASSERT(y <= best_y); 437 | best_y = y; 438 | best_waste = waste; 439 | best = prev; 440 | } 441 | } 442 | } 443 | tail = tail->next; 444 | } 445 | } 446 | 447 | fr.prev_link = best; 448 | fr.x = best_x; 449 | fr.y = best_y; 450 | return fr; 451 | } 452 | 453 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 454 | { 455 | // find best position according to heuristic 456 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 457 | stbrp_node *node, *cur; 458 | 459 | // bail if: 460 | // 1. it failed 461 | // 2. the best node doesn't fit (we don't always check this) 462 | // 3. we're out of memory 463 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 464 | res.prev_link = NULL; 465 | return res; 466 | } 467 | 468 | // on success, create new node 469 | node = context->free_head; 470 | node->x = (stbrp_coord) res.x; 471 | node->y = (stbrp_coord) (res.y + height); 472 | 473 | context->free_head = node->next; 474 | 475 | // insert the new node into the right starting point, and 476 | // let 'cur' point to the remaining nodes needing to be 477 | // stiched back in 478 | 479 | cur = *res.prev_link; 480 | if (cur->x < res.x) { 481 | // preserve the existing one, so start testing with the next one 482 | stbrp_node *next = cur->next; 483 | cur->next = node; 484 | cur = next; 485 | } else { 486 | *res.prev_link = node; 487 | } 488 | 489 | // from here, traverse cur and free the nodes, until we get to one 490 | // that shouldn't be freed 491 | while (cur->next && cur->next->x <= res.x + width) { 492 | stbrp_node *next = cur->next; 493 | // move the current node to the free list 494 | cur->next = context->free_head; 495 | context->free_head = cur; 496 | cur = next; 497 | } 498 | 499 | // stitch the list back in 500 | node->next = cur; 501 | 502 | if (cur->x < res.x + width) 503 | cur->x = (stbrp_coord) (res.x + width); 504 | 505 | #ifdef _DEBUG 506 | cur = context->active_head; 507 | while (cur->x < context->width) { 508 | STBRP_ASSERT(cur->x < cur->next->x); 509 | cur = cur->next; 510 | } 511 | STBRP_ASSERT(cur->next == NULL); 512 | 513 | { 514 | int count=0; 515 | cur = context->active_head; 516 | while (cur) { 517 | cur = cur->next; 518 | ++count; 519 | } 520 | cur = context->free_head; 521 | while (cur) { 522 | cur = cur->next; 523 | ++count; 524 | } 525 | STBRP_ASSERT(count == context->num_nodes+2); 526 | } 527 | #endif 528 | 529 | return res; 530 | } 531 | 532 | // [DEAR IMGUI] Added STBRP__CDECL 533 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 534 | { 535 | const stbrp_rect *p = (const stbrp_rect *) a; 536 | const stbrp_rect *q = (const stbrp_rect *) b; 537 | if (p->h > q->h) 538 | return -1; 539 | if (p->h < q->h) 540 | return 1; 541 | return (p->w > q->w) ? -1 : (p->w < q->w); 542 | } 543 | 544 | // [DEAR IMGUI] Added STBRP__CDECL 545 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 546 | { 547 | const stbrp_rect *p = (const stbrp_rect *) a; 548 | const stbrp_rect *q = (const stbrp_rect *) b; 549 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 550 | } 551 | 552 | #ifdef STBRP_LARGE_RECTS 553 | #define STBRP__MAXVAL 0xffffffff 554 | #else 555 | #define STBRP__MAXVAL 0xffff 556 | #endif 557 | 558 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 559 | { 560 | int i, all_rects_packed = 1; 561 | 562 | // we use the 'was_packed' field internally to allow sorting/unsorting 563 | for (i=0; i < num_rects; ++i) { 564 | rects[i].was_packed = i; 565 | } 566 | 567 | // sort according to heuristic 568 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 569 | 570 | for (i=0; i < num_rects; ++i) { 571 | if (rects[i].w == 0 || rects[i].h == 0) { 572 | rects[i].x = rects[i].y = 0; // empty rect needs no space 573 | } else { 574 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 575 | if (fr.prev_link) { 576 | rects[i].x = (stbrp_coord) fr.x; 577 | rects[i].y = (stbrp_coord) fr.y; 578 | } else { 579 | rects[i].x = rects[i].y = STBRP__MAXVAL; 580 | } 581 | } 582 | } 583 | 584 | // unsort 585 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 586 | 587 | // set was_packed flags and all_rects_packed status 588 | for (i=0; i < num_rects; ++i) { 589 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 590 | if (!rects[i].was_packed) 591 | all_rects_packed = 0; 592 | } 593 | 594 | // return the all_rects_packed status 595 | return all_rects_packed; 596 | } 597 | #endif 598 | 599 | /* 600 | ------------------------------------------------------------------------------ 601 | This software is available under 2 licenses -- choose whichever you prefer. 602 | ------------------------------------------------------------------------------ 603 | ALTERNATIVE A - MIT License 604 | Copyright (c) 2017 Sean Barrett 605 | Permission is hereby granted, free of charge, to any person obtaining a copy of 606 | this software and associated documentation files (the "Software"), to deal in 607 | the Software without restriction, including without limitation the rights to 608 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 | of the Software, and to permit persons to whom the Software is furnished to do 610 | so, subject to the following conditions: 611 | The above copyright notice and this permission notice shall be included in all 612 | copies or substantial portions of the Software. 613 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 619 | SOFTWARE. 620 | ------------------------------------------------------------------------------ 621 | ALTERNATIVE B - Public Domain (www.unlicense.org) 622 | This is free and unencumbered software released into the public domain. 623 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 | software, either in source code form or as a compiled binary, for any purpose, 625 | commercial or non-commercial, and by any means. 626 | In jurisdictions that recognize copyright laws, the author or authors of this 627 | software dedicate any and all copyright interest in the software to the public 628 | domain. We make this dedication for the benefit of the public at large and to 629 | the detriment of our heirs and successors. We intend this dedication to be an 630 | overt act of relinquishment in perpetuity of all present and future rights to 631 | this software under copyright law. 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 637 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 638 | ------------------------------------------------------------------------------ 639 | */ 640 | --------------------------------------------------------------------------------