├── .gitattributes ├── host ├── ext │ ├── .clang-format │ ├── spdlog │ │ ├── fmt │ │ │ ├── bundled │ │ │ │ ├── locale.h │ │ │ │ └── fmt.license.rst │ │ │ ├── xchar.h │ │ │ ├── chrono.h │ │ │ ├── ostr.h │ │ │ ├── ranges.h │ │ │ ├── compile.h │ │ │ └── fmt.h │ │ ├── details │ │ │ ├── windows_include.h │ │ │ ├── periodic_worker-inl.h │ │ │ ├── console_globals.h │ │ │ ├── synchronous_factory.h │ │ │ ├── log_msg_buffer.h │ │ │ ├── null_mutex.h │ │ │ ├── log_msg-inl.h │ │ │ ├── log_msg.h │ │ │ ├── backtracer.h │ │ │ ├── log_msg_buffer-inl.h │ │ │ ├── file_helper.h │ │ │ ├── periodic_worker.h │ │ │ ├── backtracer-inl.h │ │ │ └── udp_client.h │ │ ├── version.h │ │ ├── fwd.h │ │ ├── async.cpp │ │ ├── formatter.h │ │ ├── sinks │ │ │ ├── sink-inl.h │ │ │ ├── sink.h │ │ │ ├── basic_file_sink-inl.h │ │ │ ├── stdout_color_sinks-inl.h │ │ │ ├── null_sink.h │ │ │ ├── ostream_sink.h │ │ │ ├── base_sink.h │ │ │ ├── msvc_sink.h │ │ │ ├── stdout_color_sinks.h │ │ │ ├── base_sink-inl.h │ │ │ ├── basic_file_sink.h │ │ │ ├── udp_sink.h │ │ │ ├── ringbuffer_sink.h │ │ │ └── tcp_sink.h │ │ ├── cfg │ │ │ ├── helpers.h │ │ │ ├── env.h │ │ │ └── argv.h │ │ ├── file_sinks.cpp │ │ ├── spdlog.cpp │ │ ├── stopwatch.h │ │ ├── common-inl.h │ │ └── async_logger.h │ ├── stb.c │ ├── imgui │ │ ├── imgui_filedialog │ │ │ ├── dirent │ │ │ │ └── LICENSE │ │ │ ├── LICENSE │ │ │ └── stb │ │ │ │ └── LICENSE │ │ └── CMakeLists.txt │ └── fmt │ │ └── format.cc ├── resources │ ├── clemens.rc │ ├── icon.icns │ └── clemens.ico ├── data │ └── dos_3_3_master.woz ├── images │ ├── LICENSE.md │ ├── eject_png.h │ └── folder_solid_png.h ├── strings │ ├── clem_debug.inl │ ├── clem_welcome.inl │ ├── clem_settings.inl │ └── clem_help.inl ├── version.h.in ├── shaders │ ├── source │ │ ├── hires.hlsl │ │ └── vertex.hlsl │ ├── hlsl │ │ └── super.ps │ ├── glsl │ │ └── super.fs │ └── d3d11.inl ├── clem_ui_settings.hpp ├── clem_host_utils.hpp ├── core │ ├── clem_disk_status.hpp │ ├── clem_disk_utils.hpp │ ├── clem_apple2gs_config.hpp │ ├── clem_snapshot.hpp │ └── clem_prodos_disk.hpp ├── clem_ui_save_snapshot.hpp ├── utils │ ├── dump_to_bin.py │ └── dump_compare.py ├── clem_audio.hpp ├── cinek │ ├── equation.hpp │ ├── keyframe.hpp │ ├── ckopts.h │ ├── encode.h │ ├── sequence.hpp │ ├── buffer.cpp │ ├── buffertypes.hpp │ └── equation.inl ├── clem_host_view.hpp ├── clem_startup_view.hpp ├── harness │ ├── CMakeLists.txt │ ├── test.json │ └── harness.hpp ├── clem_preamble.hpp ├── macos_bundle_info_plist.in ├── clem_host.cpp ├── clem_host.hpp ├── clem_ui_load_snapshot.hpp ├── clem_asset_browser.hpp ├── clem_l10n.cpp ├── clem_assets.hpp ├── clem_imgui.hpp ├── fonts │ └── FreeLicense.txt ├── clem_program_trace.hpp ├── clem_host_shared.hpp ├── clem_configuration.hpp ├── clem_l10n.hpp ├── clem_file_browser.hpp └── clem_host_utils.cpp ├── data.zip ├── external └── unity │ ├── unity_config.h │ └── CMakeLists.txt ├── docs ├── disk-tray.png ├── play-screen.png ├── control-panel.jpg ├── debug-screen.png ├── manual-setup.png ├── joystick-config.png ├── manual-setup-data.png ├── GamePort.md ├── Integration.md ├── Software.md ├── iwm_35_notes.txt ├── references.txt ├── Diagnostics.md ├── Mockingboard.md ├── ROM3_Reset.md ├── SCC.md └── EmulatorHostHelp.md ├── flatpak ├── com.cinekine.Clemens_16.png ├── com.cinekine.Clemens_32.png ├── com.cinekine.Clemens_64.png ├── com.cinekine.Clemens_128.png ├── com.cinekine.Clemens_256.png ├── com.cinekine.Clemens.desktop ├── buildFlatpak.sh ├── com.cinekine.Clemens.yaml └── com.cinekine.Clemens.appdata.xml ├── .gitignore ├── .clang-format ├── tests ├── utils.h ├── test_emulate_minimal.c ├── utils.c ├── cpu │ └── test_adc.c └── test_scc.c ├── clem_disasm.c ├── clem_locale.h ├── cmake └── CompilerOptions.cmake ├── devices ├── CMakeLists.txt ├── hddcard.h ├── mockingboard.h ├── slot7hdd_firmware.h ├── clem_peer.h └── prodos_hdd32.h ├── render.h ├── clem_timer.c ├── LICENSE.txt ├── clem_mmio.h ├── clem_drive.h ├── clem_vgc.h ├── app.c ├── clem_mem.h ├── .github └── workflows │ ├── build-windows.yml │ └── build-linux.yml └── clem_debug.h /.gitattributes: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /host/ext/.clang-format: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/data.zip -------------------------------------------------------------------------------- /external/unity/unity_config.h: -------------------------------------------------------------------------------- 1 | #define UNITY_INCLUDE_PRINT_FORMATTED 2 | -------------------------------------------------------------------------------- /docs/disk-tray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/disk-tray.png -------------------------------------------------------------------------------- /host/resources/clemens.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "clemens.ico" 2 | -------------------------------------------------------------------------------- /docs/play-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/play-screen.png -------------------------------------------------------------------------------- /docs/control-panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/control-panel.jpg -------------------------------------------------------------------------------- /docs/debug-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/debug-screen.png -------------------------------------------------------------------------------- /docs/manual-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/manual-setup.png -------------------------------------------------------------------------------- /docs/joystick-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/joystick-config.png -------------------------------------------------------------------------------- /host/resources/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/host/resources/icon.icns -------------------------------------------------------------------------------- /docs/manual-setup-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/docs/manual-setup-data.png -------------------------------------------------------------------------------- /host/data/dos_3_3_master.woz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/host/data/dos_3_3_master.woz -------------------------------------------------------------------------------- /host/images/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Attribution 2 | 3 | Various icon sets were used from https://fontawesome.com/icons/ 4 | -------------------------------------------------------------------------------- /host/resources/clemens.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/host/resources/clemens.ico -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/flatpak/com.cinekine.Clemens_16.png -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/flatpak/com.cinekine.Clemens_32.png -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/flatpak/com.cinekine.Clemens_64.png -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/flatpak/com.cinekine.Clemens_128.png -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samkusin/clemens_iigs/HEAD/flatpak/com.cinekine.Clemens_256.png -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/bundled/locale.h: -------------------------------------------------------------------------------- 1 | #include "xchar.h" 2 | #warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead 3 | -------------------------------------------------------------------------------- /host/ext/stb.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #include "stb_image.h" 3 | #define STB_TRUETYPE_IMPLEMENTATION 4 | #include "stb_truetype.h" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache/ 3 | .vscode/ 4 | .vs/ 5 | .flatpak-builder/ 6 | build/ 7 | dist/ 8 | data/*.rom 9 | data/*.bin 10 | compile_flags.txt 11 | 12 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | UseTab: Never 4 | --- 5 | Language: Cpp 6 | IndentWidth: 4 7 | TabWidth: 4 8 | ColumnLimit: 100 9 | AlignConsecutiveMacros: true 10 | -------------------------------------------------------------------------------- /host/strings/clem_debug.inl: -------------------------------------------------------------------------------- 1 | const char *kDebugNotAvailableWhileRunning[] = {"View not available while running."}; 2 | const char *kDebugDiskNoTrackData[] = {"No disk or data available for track."}; 3 | -------------------------------------------------------------------------------- /external/unity/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(unity STATIC 2 | ${CMAKE_CURRENT_SOURCE_DIR}/unity.c) 3 | 4 | target_compile_definitions(unity PUBLIC UNITY_INCLUDE_CONFIG_H) 5 | target_include_directories(unity PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Version=1.0 4 | Type=Application 5 | Name=Clemens IIgs 6 | Comment=An Apple IIgs Emulator and Debugger 7 | 8 | Icon=com.cinekine.Clemens.png 9 | Exec=clemens_iigs 10 | Terminal=true 11 | 12 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/windows_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NOMINMAX 4 | # define NOMINMAX // prevent windows redefining min/max 5 | #endif 6 | 7 | #ifndef WIN32_LEAN_AND_MEAN 8 | # define WIN32_LEAN_AND_MEAN 9 | #endif 10 | 11 | #include 12 | -------------------------------------------------------------------------------- /host/version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_VERSION_H 2 | #define CLEM_HOST_VERSION_H 3 | 4 | #define CLEM_HOST_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} 5 | #define CLEM_HOST_VERSION_MINOR ${PROJECT_VERSION_MINOR} 6 | #define CLEM_HOST_VERSION_PATCH ${PROJECT_VERSION_PATCH} 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /docs/GamePort.md: -------------------------------------------------------------------------------- 1 | ## References 2 | 3 | * Jim Sather's Understanding the Apple IIe (7-29) 4 | * Apple IIgs HW Reference 5 | 6 | ### I/O Programming 7 | 8 | * $C070 resets the paddle inputs 9 | * $C064 - $C067 for paddle inputs 10 | * $C060 - $C063 for switch inputs 11 | 12 | ### Testing with PREAD and PDL(n) 13 | -------------------------------------------------------------------------------- /tests/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_TESTS_UTILS_H 2 | #define CLEM_TESTS_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | extern uint8_t *clem_test_load_disk_image(const char *path, size_t *image_sz); 8 | extern void clem_test_save_disk_image(const char *path, const uint8_t *image, size_t image_sz); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /tests/test_emulate_minimal.c: -------------------------------------------------------------------------------- 1 | #include "unity.h" 2 | #include "emulator.h" 3 | 4 | void setUp(void) { 5 | 6 | } 7 | 8 | void tearDown(void) { 9 | 10 | } 11 | 12 | void test_clem_init(void) { 13 | 14 | } 15 | 16 | int main(void) { 17 | UNITY_BEGIN(); 18 | RUN_TEST(test_clem_init); 19 | return UNITY_END(); 20 | } 21 | -------------------------------------------------------------------------------- /host/shaders/source/hires.hlsl: -------------------------------------------------------------------------------- 1 | Texture2D hgr_tex: register(t0); 2 | Texture2D hcolor_tex: register(t1); 3 | sampler smp: register(s0); 4 | 5 | float4 main(float2 uv: TEXCOORD0, float4 color: COLOR0): SV_Target0 { 6 | float4 texl_hgr = hgr_tex.Sample(smp, uv); 7 | float4 texl_color = hcolor_tex.Sample(smp, texl_hgr.x / 7.0); 8 | return texl_color * color; 9 | } 10 | -------------------------------------------------------------------------------- /host/ext/spdlog/version.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #define SPDLOG_VER_MAJOR 1 7 | #define SPDLOG_VER_MINOR 11 8 | #define SPDLOG_VER_PATCH 0 9 | 10 | #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) 11 | -------------------------------------------------------------------------------- /host/ext/spdlog/fwd.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | namespace spdlog { 7 | class logger; 8 | class formatter; 9 | 10 | namespace sinks { 11 | class sink; 12 | } 13 | 14 | namespace level { 15 | enum level_enum : int; 16 | } 17 | 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /host/ext/spdlog/async.cpp: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #ifndef SPDLOG_COMPILED_LIB 5 | # error Please define SPDLOG_COMPILED_LIB to compile this file. 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | -------------------------------------------------------------------------------- /clem_disasm.c: -------------------------------------------------------------------------------- 1 | /* The Clemens Disassembler leverages the opcode definitions contained in the 2 | emulator portion. 3 | 4 | 1. To use, create a disassembler context 5 | 2. Set the context's current PC (program counter) 6 | 3. Set the context's current status (emulation, accumulator, index size) 7 | 4. Diassemble current instruction and return next *possible* PC values 8 | a) PC following current instruction 9 | b) PC if conditional branch was taken 10 | */ 11 | -------------------------------------------------------------------------------- /host/ext/spdlog/formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | class formatter 12 | { 13 | public: 14 | virtual ~formatter() = default; 15 | virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; 16 | virtual std::unique_ptr clone() const = 0; 17 | }; 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /clem_locale.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_LOCALE_H 2 | #define CLEM_LOCALE_H 3 | 4 | #include "clem_mmio_defs.h" 5 | 6 | #define CLEM_ADB_LOCALE_KEYB_US 0 7 | #define CLEM_ADB_LOCALE_KEYB_COUNT 1 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | * Converts UTF8 code to an ISO 8859-1 compliant code given the input keyboard 15 | * type. 16 | * 17 | * @return a 16-bit word (high 8-bits are the ADB modifier, and low 8-bits are the 18 | * keycode) 19 | */ 20 | uint16_t clem_iso_latin_1_to_adb_key_and_modifier(unsigned char ch, int keyb_type); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | #endif 26 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's xchar support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /docs/Integration.md: -------------------------------------------------------------------------------- 1 | 2 | 1. ROM loaded into memory 3 | 2. clemens_host_setup() 4 | 3. clemens_init() 5 | 4. Restore BRAM memory from storage 6 | 5. clemens_assign_audio_mix_buffer() 7 | 8 | 9 | ## Gotchas 10 | 11 | 1. Only one machine can run at a time 12 | 1. The machine is *mostly* self contained within `ClemensMachine` 13 | 2. Logging currently requires a global machine context 14 | 3. For now, if you need to run multiple machines at the same time, you'll have to mutex calls to `clemens_emulate()` 15 | 4. This limitation is annoying 16 | 5. It should be possible with some work to remove this limitation in a later release 17 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/chrono.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's chrono support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/ostr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ostream support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ranges support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /host/clem_ui_settings.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_SETTINGS_UI_HPP 2 | #define CLEM_HOST_SETTINGS_UI_HPP 3 | 4 | #include "clem_configuration.hpp" 5 | #include "clem_file_browser.hpp" 6 | 7 | class ClemensSettingsUI { 8 | public: 9 | ClemensSettingsUI(ClemensConfiguration &config); 10 | 11 | void start(); 12 | void stop(); 13 | 14 | bool frame(); 15 | 16 | private: 17 | ClemensConfiguration &config_; 18 | ClemensFileBrowser fileBrowser_; 19 | enum class Mode { None, Main, ROMFileBrowse }; 20 | Mode mode_; 21 | bool romFileExists_; 22 | 23 | int cardCounts_[CLEM_CARD_SLOT_COUNT]; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's compile-time support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /docs/Software.md: -------------------------------------------------------------------------------- 1 | # Supported Software 2 | 3 | ## Apple II+, IIe, IIc 4 | 5 | ### Solid 6 | 7 | ### Boots 8 | 9 | * Commando 10 | * Sammy Lightfoot 11 | * Stargate 12 | * Take 1 (Baudville) 13 | * Stickybear Town Builder 14 | 15 | ### Problematic 16 | 17 | * Oregon Trail - hangs. Likely there's something going on with 64K support. 18 | * Rescue Raiders 19 | * Boots to title screen 20 | * Add some more soft-switch support 21 | * Hard Hat Mack 22 | * Likely Requires Disk II card vs the IIgs internal ROM due to how BOOT0 23 | loads 16 sectors and seems to timeout at around sector #8 before the IIgs 24 | 'check startup disk' message comes up 25 | * -------------------------------------------------------------------------------- /host/clem_host_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_UTILS_HPP 2 | #define CLEM_HOST_UTILS_HPP 3 | 4 | #include "clem_types.h" 5 | 6 | #include 7 | 8 | // TODO: move into a new utility header for debugger tracing/listing 9 | 10 | struct ClemensTraceExecutedInstruction { 11 | uint64_t seq; 12 | uint32_t cycles_spent; 13 | uint32_t pc; 14 | uint16_t size; 15 | char opcode[4]; 16 | char operand[24]; 17 | 18 | static void initialize(); 19 | 20 | ClemensTraceExecutedInstruction &fromInstruction(const ClemensInstruction &instruction, 21 | const char *operand); 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /cmake/CompilerOptions.cmake: -------------------------------------------------------------------------------- 1 | 2 | 3 | if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 4 | string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT}") 5 | string(REGEX REPLACE "/EHsc*" "" CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT}") 6 | endif() 7 | 8 | if (CMAKE_C_COMPILER_ID MATCHES "MSVC") 9 | string(REGEX REPLACE "/Ob0" "/Ob1" CMAKE_C_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBUG_INIT}") 10 | endif() 11 | 12 | #[[ 13 | get_cmake_property(_varNames VARIABLES) 14 | list (REMOVE_DUPLICATES _varNames) 15 | list (SORT _varNames) 16 | foreach (_varName ${_varNames}) 17 | if (_varName MATCHES "_INIT$") 18 | message(STATUS "${_varName}=${${_varName}}") 19 | endif() 20 | endforeach() 21 | ]] 22 | -------------------------------------------------------------------------------- /devices/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # get_filename_component( 3 | # _CLEM_INCLUDE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY 4 | #) 5 | 6 | add_library(clemens_65816_smartport STATIC 7 | hddcard.c 8 | mockingboard.c 9 | prodos_hdd32.c) 10 | 11 | target_link_libraries(clemens_65816_smartport 12 | PUBLIC clemens_65816_serializer clemens_65816_mmio) 13 | 14 | add_library(clemens_65816_mockingboard STATIC 15 | mockingboard.c) 16 | 17 | target_link_libraries(clemens_65816_mockingboard 18 | PUBLIC clemens_65816_serializer) 19 | 20 | 21 | add_library(clemens_65816_serial_devices STATIC 22 | clem_peer.c) 23 | 24 | target_link_libraries(clemens_65816_serial_devices 25 | PUBLIC clemens_65816_mmio) 26 | 27 | -------------------------------------------------------------------------------- /host/core/clem_disk_status.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_DISK_STATUS_HPP 2 | #define CLEM_HOST_DISK_STATUS_HPP 3 | 4 | #include 5 | 6 | struct ClemensDiskDriveStatus { 7 | enum class Error { None, MountFailed, SaveFailed }; 8 | enum class Origin { None, DiskPort, CardPort }; 9 | std::string assetPath; 10 | bool isWriteProtected = false; 11 | bool isSpinning = false; 12 | bool isEjecting = false; 13 | bool isSaved = false; 14 | Error error = Error::None; 15 | Origin origin = Origin::None; 16 | 17 | void mount(const std::string &path, Origin o); 18 | void unmount(); 19 | void saveFailed(); 20 | void mountFailed(); 21 | void saved(); 22 | bool isMounted() const; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/periodic_worker-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | // stop the worker thread and join it 14 | SPDLOG_INLINE periodic_worker::~periodic_worker() 15 | { 16 | if (worker_thread_.joinable()) 17 | { 18 | { 19 | std::lock_guard lock(mutex_); 20 | active_ = false; 21 | } 22 | cv_.notify_one(); 23 | worker_thread_.join(); 24 | } 25 | } 26 | 27 | } // namespace details 28 | } // namespace spdlog 29 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/console_globals.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | struct console_mutex 13 | { 14 | using mutex_t = std::mutex; 15 | static mutex_t &mutex() 16 | { 17 | static mutex_t s_mutex; 18 | return s_mutex; 19 | } 20 | }; 21 | 22 | struct console_nullmutex 23 | { 24 | using mutex_t = null_mutex; 25 | static mutex_t &mutex() 26 | { 27 | static mutex_t s_mutex; 28 | return s_mutex; 29 | } 30 | }; 31 | } // namespace details 32 | } // namespace spdlog 33 | -------------------------------------------------------------------------------- /host/clem_ui_save_snapshot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_SAVE_SNAPSHOT_UI_HPP 2 | #define CLEM_HOST_SAVE_SNAPSHOT_UI_HPP 3 | 4 | class ClemensCommandQueue; 5 | class ClemensDisplay; 6 | 7 | class ClemensSaveSnapshotUI { 8 | public: 9 | bool isStarted() const; 10 | void start(ClemensCommandQueue &backend, bool isEmulatorRunning); 11 | bool frame(float width, float height, ClemensDisplay &display, ClemensCommandQueue &backend); 12 | void stop(ClemensCommandQueue &backend); 13 | void succeeded(); 14 | void fail(); 15 | 16 | private: 17 | enum class Mode { None, PromptForName, WaitForResponse, Succeeded, Failed, Cancelled }; 18 | 19 | Mode mode_ = Mode::None; 20 | bool interruptedExecution_ = false; 21 | char snapshotName_[128]; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tests/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | 6 | uint8_t *clem_test_load_disk_image(const char *path, size_t *image_sz) { 7 | uint8_t *data = NULL; 8 | FILE *fp = fopen(path, "rb"); 9 | long size; 10 | if (!fp) 11 | return NULL; 12 | fseek(fp, 0, SEEK_END); 13 | size = ftell(fp); 14 | fseek(fp, 0, SEEK_SET); 15 | data = malloc(size); 16 | fread(data, size, 1, fp); 17 | fclose(fp); 18 | *image_sz = size; 19 | return data; 20 | } 21 | 22 | void clem_test_save_disk_image(const char *path, const uint8_t *image, size_t image_sz) { 23 | FILE *fp = fopen(path, "wb"); 24 | long size; 25 | if (!fp) 26 | return; 27 | fwrite(image, image_sz, 1, fp); 28 | fclose(fp); 29 | } 30 | -------------------------------------------------------------------------------- /flatpak/buildFlatpak.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | GPG_KEY=$FLATPAK_CLEMENS_GPG_KEY 5 | 6 | 7 | function clearWorkDirs() { 8 | [[ -d .flatpak-builder ]] && rm -rf .flatpak-builder 9 | [[ -d flatpak-build ]] && rm -rf flatpak-build 10 | [[ -d flatpak-repo ]] && rm -rf flatpak-repo 11 | } 12 | 13 | 14 | flatpak install flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08 15 | 16 | clearWorkDirs 17 | [[ -f clemens.flatpak ]] && rm -f clemens.flatpak 18 | 19 | flatpak-builder --user --gpg-sign=${GPG_KEY} -v --keep-build-dirs --repo=flatpak-repo --install flatpak-build com.cinekine.Clemens.yaml 20 | flatpak build-bundle flatpak-repo clemens.flatpak com.cinekine.Clemens --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo 21 | 22 | [[ -f clemens.flatpak ]] && clearWorkDirs 23 | -------------------------------------------------------------------------------- /host/utils/dump_to_bin.py: -------------------------------------------------------------------------------- 1 | # consolidate one or more dump output files from the emulator into a single 2 | # binary file (useful for running through a disassembler.) 3 | 4 | import os 5 | import sys 6 | 7 | if len(sys.argv) < 3: 8 | print("Usage: {} ... ".format( 9 | os.path.basename(sys.argv[0]), sys.argv[0])) 10 | sys.exit(1) 11 | 12 | OUTPUT_FILENAME = sys.argv[1] 13 | INPUT_FILENAMES = sys.argv[2:] 14 | 15 | output_file = open(OUTPUT_FILENAME, mode='wb') 16 | for input_filename in INPUT_FILENAMES: 17 | with open(input_filename, 'r') as input_file: 18 | for line in input_file: 19 | _, data = tuple([part.strip() for part in line.split(':')]) 20 | output_bytes = bytes.fromhex(data) 21 | output_file.write(output_bytes) 22 | -------------------------------------------------------------------------------- /host/core/clem_disk_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_DISK_UTILS_HPP 2 | #define CLEM_HOST_DISK_UTILS_HPP 3 | 4 | #include "cinek/buffertypes.hpp" 5 | #include "clem_mmio_types.h" 6 | #include 7 | 8 | namespace ClemensDiskUtilities { 9 | 10 | constexpr unsigned kMaximumHDDSizeInMB = 32; 11 | constexpr unsigned kBlocksPerMB = 2048; 12 | 13 | std::string_view getDriveName(ClemensDriveType driveType); 14 | 15 | ClemensDriveType getDriveType(std::string_view driveName); 16 | 17 | bool createDisk(cinek::Range decodeBuffer, const std::string &path, 18 | ClemensDriveType driveType); 19 | 20 | // returns the number of blocks written (if == blockCount, then OK) 21 | unsigned createProDOSHardDisk(const std::string &path, unsigned blockCount); 22 | 23 | } // namespace ClemensDiskUtilities 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | 12 | SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const 13 | { 14 | return msg_level >= level_.load(std::memory_order_relaxed); 15 | } 16 | 17 | SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) 18 | { 19 | level_.store(log_level, std::memory_order_relaxed); 20 | } 21 | 22 | SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const 23 | { 24 | return static_cast(level_.load(std::memory_order_relaxed)); 25 | } 26 | -------------------------------------------------------------------------------- /host/ext/spdlog/cfg/helpers.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace cfg { 11 | namespace helpers { 12 | // 13 | // Init levels from given string 14 | // 15 | // Examples: 16 | // 17 | // set global level to debug: "debug" 18 | // turn off all logging except for logger1: "off,logger1=debug" 19 | // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" 20 | // 21 | SPDLOG_API void load_levels(const std::string &txt); 22 | } // namespace helpers 23 | 24 | } // namespace cfg 25 | } // namespace spdlog 26 | 27 | #ifdef SPDLOG_HEADER_ONLY 28 | # include "helpers-inl.h" 29 | #endif // SPDLOG_HEADER_ONLY 30 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/synchronous_factory.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "registry.h" 7 | 8 | namespace spdlog { 9 | 10 | // Default logger factory- creates synchronous loggers 11 | class logger; 12 | 13 | struct synchronous_factory 14 | { 15 | template 16 | static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) 17 | { 18 | auto sink = std::make_shared(std::forward(args)...); 19 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); 20 | details::registry::instance().initialize_logger(new_logger); 21 | return new_logger; 22 | } 23 | }; 24 | } // namespace spdlog 25 | -------------------------------------------------------------------------------- /host/shaders/source/vertex.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer Globals { 2 | float2 render_dims; // Render Target Resolution 3 | float2 display_ratio; // Ratio convert virtual to target 4 | float2 virtual_dims; // Emulator 'pixel' resolution 5 | float2 offsets; // x,y offset from top, left 6 | 7 | }; 8 | 9 | struct Input { 10 | float2 pos: POSITION; 11 | float2 uv: TEXCOORD0; 12 | float4 color: COLOR0; 13 | }; 14 | 15 | struct Output { 16 | float2 uv: TEXCOORD0; 17 | float4 color: COLOR0; 18 | float4 pos: SV_POSITION; 19 | }; 20 | 21 | Output main(Input input) { 22 | Output output; 23 | float2 t_pos = (input.pos * display_ratio + offsets) / render_dims; 24 | t_pos = (t_pos - 0.5) * float2(2.0, -2.0); 25 | output.pos = float4(t_pos, 0.5, 1.0); 26 | output.uv = input.uv; 27 | output.color = input.color; 28 | return output; 29 | } 30 | -------------------------------------------------------------------------------- /host/ext/spdlog/file_sinks.cpp: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #ifndef SPDLOG_COMPILED_LIB 5 | # error Please define SPDLOG_COMPILED_LIB to compile this file. 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | template class SPDLOG_API spdlog::sinks::basic_file_sink; 16 | template class SPDLOG_API spdlog::sinks::basic_file_sink; 17 | 18 | #include 19 | template class SPDLOG_API spdlog::sinks::rotating_file_sink; 20 | template class SPDLOG_API spdlog::sinks::rotating_file_sink; 21 | -------------------------------------------------------------------------------- /render.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_RENDER_H 2 | #define CLEM_RENDER_H 3 | 4 | #include "clem_mmio_types.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * @brief Renders indexed color into an 8-bit texture 12 | * 13 | * Note to support all graphics rendering modes, the output texture should be 14 | * at least 640 x 400 texels. Hires and Super hires 320 pixels are scaled 2x2 15 | * to fill out the texture. Double hires and 640 mode render pixels at 1x2. 16 | * 17 | * @param video 18 | * @param memory 19 | * @param aux 20 | * @param texture 21 | * @param width 22 | * @param height 23 | * @param stride 24 | */ 25 | void clemens_render_graphics(const ClemensVideo *video, const uint8_t *memory, const uint8_t *aux, 26 | uint8_t *texture, unsigned width, unsigned height, unsigned stride); 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /clem_timer.c: -------------------------------------------------------------------------------- 1 | #include "clem_device.h" 2 | #include "clem_mmio_defs.h" 3 | 4 | void clem_timer_reset(struct ClemensDeviceTimer *timer) { timer->flags = 0; } 5 | 6 | void clem_timer_sync(struct ClemensDeviceTimer *timer, uint32_t delta_us) { 7 | timer->irq_1sec_us += delta_us; 8 | timer->irq_qtrsec_us += delta_us; 9 | 10 | while (timer->irq_1sec_us >= CLEM_MEGA2_TIMER_1SEC_US) { 11 | timer->irq_1sec_us -= CLEM_MEGA2_TIMER_1SEC_US; 12 | if (timer->flags & CLEM_MMIO_TIMER_1SEC_ENABLED) { 13 | timer->irq_line |= CLEM_IRQ_TIMER_RTC_1SEC; 14 | } 15 | } 16 | while (timer->irq_qtrsec_us >= CLEM_MEGA2_TIMER_QSEC_US) { 17 | timer->irq_qtrsec_us -= CLEM_MEGA2_TIMER_QSEC_US; 18 | if (timer->flags & CLEM_MMIO_TIMER_QSEC_ENABLED) { 19 | timer->irq_line |= CLEM_IRQ_TIMER_QSEC; 20 | timer->flags |= CLEM_MMIO_TIMER_QSEC_IRQ; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /host/shaders/hlsl/super.ps: -------------------------------------------------------------------------------- 1 | /* 2 | More or less the same implementation as the GLSL version 3 | */ 4 | cbuffer Globals { 5 | float4 screen_params; 6 | float4 color_params; 7 | }; 8 | 9 | Texture2D screen_tex : register(t0); 10 | Texture2D color_tex : register(t1); 11 | sampler smp : register(s0); 12 | 13 | float4 main(float2 uv : TEXCOORD0, float4 color : COLOR0) : SV_Target0 { 14 | // color_index = 0 to 15 15 | // scanline = 0 to 199 scaled down using screen texel height (likely by 2) 16 | float color_index = floor(screen_tex.Sample(smp, uv).x * 255.0 / 16.0 + 0.5); 17 | float scanline = floor(uv.y * screen_params.y / screen_params.w + 0.5); 18 | float2 color_uv = 19 | float2((color_index + 0.5) * color_params.z / color_params.x, 20 | (scanline + 0.5) * color_params.w / color_params.y); 21 | float4 texl_color = color_tex.Sample(smp, color_uv); 22 | return texl_color * color; 23 | } 24 | -------------------------------------------------------------------------------- /host/strings/clem_welcome.inl: -------------------------------------------------------------------------------- 1 | const char *kWelcomeText[] = {R"md( 2 | # Clemens IIGS Emulator v%d.%d 3 | 4 | This release contains the following changes: 5 | 6 | - "User" mode GUI for regular use with larger view 7 | - macOS Intel and Apple Silicon support 8 | - Better emulation of system time based on the IIgs 28khz master clock frequency 9 | - IWM fixes for 3.5 disk timings and overall emulation speed 10 | - Dual Slot 7 smartport hard drive 11 | - Better emulation of all graphics modes 12 | - Ensoniq emulation improved 13 | - Mouse tracking for GSOS/System Software 14 | - Added fast disk and general fast mode emulation 15 | - Passes all System Diagnostic tests 16 | 17 | The following IIGS features are not yet supported: 18 | 19 | - Serial and Print Controllers 20 | - ROM 1 support 21 | - ROM 0 (//e-like) support 22 | - Emulator Localization (PAL, Monochrome) 23 | - Ethernet via Bridge Network 24 | - ROM 3 mouse emulation 25 | 26 | )md"}; 27 | -------------------------------------------------------------------------------- /host/clem_audio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_AUDIO_H 2 | #define CLEM_HOST_AUDIO_H 3 | 4 | #include "clem_mmio_types.h" 5 | 6 | #include 7 | #include 8 | 9 | class ClemensAudioDevice { 10 | public: 11 | ClemensAudioDevice(); 12 | ~ClemensAudioDevice(); 13 | 14 | unsigned getAudioFrequency() const; 15 | unsigned getBufferStride() const; 16 | 17 | void start(); 18 | void stop(); 19 | unsigned queue(const ClemensAudio &audio, bool flush); 20 | 21 | private: 22 | static void mixAudio(float *buffer, int num_frames, int num_channels, void *user_data); 23 | 24 | void mixClemensAudio(float *buffer, int num_frames, int num_channels); 25 | 26 | // audio sent to the hardware mixer 27 | uint8_t *queuedFrameBuffer_; 28 | uint32_t queuedFrameHead_; 29 | uint32_t queuedFrameTail_; 30 | uint32_t queuedFrameLimit_; 31 | uint32_t queuedFrameStride_; 32 | 33 | std::mutex queuedFrameMutex_; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /host/cinek/equation.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // equation.hpp 3 | // SampleCommon 4 | // 5 | // Created by Samir Sinha on 2/27/16. 6 | // Copyright © 2016 Cinekine. All rights reserved. 7 | // 8 | 9 | #ifndef CINEK_MATH_EQUATION_HPP 10 | #define CINEK_MATH_EQUATION_HPP 11 | 12 | #include "keyframe.hpp" 13 | 14 | namespace cinek { 15 | 16 | template struct equation { 17 | typedef keyframe<_property> keyframe_type; 18 | typedef typename keyframe_type::property_type property_type; 19 | typedef transition transition_type; 20 | transition_type type; 21 | equation(transition_type t = transition_type::kDefault) : type(t) {} 22 | void calc(property_type &out, const keyframe_type &left, const keyframe_type &right, 23 | double time) const; 24 | }; 25 | 26 | template 27 | void tweenProperty(_property &out, const keyframe<_property> &left, 28 | const keyframe<_property> &right, double scalar); 29 | 30 | } // namespace cinek 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | namespace sinks { 12 | class SPDLOG_API sink 13 | { 14 | public: 15 | virtual ~sink() = default; 16 | virtual void log(const details::log_msg &msg) = 0; 17 | virtual void flush() = 0; 18 | virtual void set_pattern(const std::string &pattern) = 0; 19 | virtual void set_formatter(std::unique_ptr sink_formatter) = 0; 20 | 21 | void set_level(level::level_enum log_level); 22 | level::level_enum level() const; 23 | bool should_log(level::level_enum msg_level) const; 24 | 25 | protected: 26 | // sink log level - default is all 27 | level_t level_{level::trace}; 28 | }; 29 | 30 | } // namespace sinks 31 | } // namespace spdlog 32 | 33 | #ifdef SPDLOG_HEADER_ONLY 34 | # include "sink-inl.h" 35 | #endif 36 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/log_msg_buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace spdlog { 9 | namespace details { 10 | 11 | // Extend log_msg with internal buffer to store its payload. 12 | // This is needed since log_msg holds string_views that points to stack data. 13 | 14 | class SPDLOG_API log_msg_buffer : public log_msg 15 | { 16 | memory_buf_t buffer; 17 | void update_string_views(); 18 | 19 | public: 20 | log_msg_buffer() = default; 21 | explicit log_msg_buffer(const log_msg &orig_msg); 22 | log_msg_buffer(const log_msg_buffer &other); 23 | log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 24 | log_msg_buffer &operator=(const log_msg_buffer &other); 25 | log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 26 | }; 27 | 28 | } // namespace details 29 | } // namespace spdlog 30 | 31 | #ifdef SPDLOG_HEADER_ONLY 32 | # include "log_msg_buffer-inl.h" 33 | #endif 34 | -------------------------------------------------------------------------------- /host/clem_host_view.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_APP_VIEW_HPP 2 | #define CLEM_HOST_APP_VIEW_HPP 3 | 4 | #include "clem_mmio_types.h" 5 | #include "clem_host.hpp" 6 | 7 | #include 8 | 9 | class ClemensHostView { 10 | public: 11 | enum class ViewType { Startup, Main }; 12 | 13 | public: 14 | virtual ~ClemensHostView() = default; 15 | 16 | // reflection on the host view being executed 17 | virtual ViewType getViewType() const = 0; 18 | // per frame execution, returning the next view type 19 | virtual ViewType frame(int width, int height, double deltaTime, ClemensHostInterop &interop) = 0; 20 | // application input from OS 21 | virtual void input(ClemensInputEvent input) = 0; 22 | // is the emulator accepting input events 23 | virtual bool emulatorHasFocus() const = 0; 24 | // paste text from the clipboard 25 | virtual void pasteText(const char *text, unsigned textSizeLimit) = 0; 26 | // application lost focus 27 | virtual void lostFocus() = 0; 28 | // application gained focus 29 | virtual void gainFocus() = 0; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Samir Sinha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /host/clem_startup_view.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_STARTUP_VIEW_HPP 2 | #define CLEM_HOST_STARTUP_VIEW_HPP 3 | 4 | #include "clem_configuration.hpp" 5 | #include "clem_host_view.hpp" 6 | 7 | #include 8 | 9 | class ClemensPreamble; 10 | 11 | class ClemensStartupView : public ClemensHostView { 12 | public: 13 | ClemensStartupView(ClemensConfiguration& config); 14 | 15 | public: 16 | ViewType getViewType() const final { return ViewType::Startup; } 17 | ViewType frame(int width, int height, double deltaTime, ClemensHostInterop &interop) final; 18 | void input(ClemensInputEvent) final; 19 | bool emulatorHasFocus() const final { return false; } 20 | void pasteText(const char *text, unsigned textSizeLimit) final; 21 | void lostFocus() final; 22 | void gainFocus() final; 23 | 24 | private: 25 | enum class Mode { Initial, ChangeDataDirectory, Preamble, SetupError, Aborted, Finished }; 26 | bool validateDirectories(); 27 | 28 | Mode mode_; 29 | ClemensConfiguration& config_; 30 | 31 | std::string setupError_; 32 | 33 | std::unique_ptr preamble_; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /clem_mmio.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_MMIO_H 2 | #define CLEM_MMIO_H 3 | 4 | #include "clem_mmio_types.h" 5 | #include "clem_types.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | void clem_mmio_reset(ClemensMMIO *mmio, struct ClemensTimeSpec *tspec); 12 | 13 | void clem_mmio_init(ClemensMMIO *mmio, struct ClemensDeviceDebugger *dev_debug, 14 | struct ClemensMemoryPageMap **bank_page_map, void *slot_expansion_rom, 15 | unsigned int fpi_ram_bank_count, unsigned int fpi_rom_bank_count, 16 | uint8_t *e0_bank, uint8_t *e1_bank, struct ClemensTimeSpec *tspec); 17 | 18 | uint8_t clem_mmio_read(ClemensMMIO *mmio, struct ClemensTimeSpec *tspec, uint16_t addr, 19 | uint8_t flags, bool *mega2_access); 20 | void clem_mmio_write(ClemensMMIO *mmio, struct ClemensTimeSpec *tspec, uint8_t data, uint16_t addr, 21 | uint8_t flags, bool *mega2_access); 22 | 23 | void clem_mmio_restore(ClemensMachine *clem, ClemensMMIO *mmio); 24 | void clem_mmio_bind_machine(ClemensMachine *clem, ClemensMMIO *mmio); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/fmt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016-2018 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | // 9 | // Include a bundled header-only copy of fmtlib or an external one. 10 | // By default spdlog include its own copy. 11 | // 12 | 13 | #if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format 14 | # include 15 | #elif !defined(SPDLOG_FMT_EXTERNAL) 16 | # if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) 17 | # define FMT_HEADER_ONLY 18 | # endif 19 | # ifndef FMT_USE_WINDOWS_H 20 | # define FMT_USE_WINDOWS_H 0 21 | # endif 22 | // enable the 'n' flag in for backward compatibility with fmt 6.x 23 | # define FMT_DEPRECATED_N_SPECIFIER 24 | // enable ostream formatting for backward compatibility with fmt 8.x 25 | # define FMT_DEPRECATED_OSTREAM 26 | 27 | # include 28 | # include 29 | 30 | #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib 31 | # include 32 | # include 33 | #endif 34 | -------------------------------------------------------------------------------- /host/harness/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(clemens_test_harness LANGUAGES C CXX) 4 | 5 | set(CLEMENS_TEST_COMMON_ASSETS 6 | "${CMAKE_CURRENT_BINARY_DIR}/data/dos_3_3_master.woz" 7 | "${CMAKE_CURRENT_BINARY_DIR}/data/ProDOS 16v1_3.2mg" 8 | "${CMAKE_CURRENT_BINARY_DIR}/data/ProDOS_2_4_2.dsk" 9 | "${CMAKE_CURRENT_BINARY_DIR}/data/System.Disk.po") 10 | 11 | add_custom_command(OUTPUT ${CLEMENS_TEST_COMMON_ASSETS} 12 | COMMAND ${CMAKE_COMMAND} -E tar xzf ${CLEMENS_TEST_ASSETS_ARCHIVE} 13 | WORKING_DIRECTORY ${CLEMENS_TEST_WORKING_DIRECTORY} 14 | DEPENDS ${CLEMENS_TEST_ASSETS_ARCHIVE} 15 | COMMENT "Unarchiving test assets into ${CMAKE_CURRENT_BINARY_DIR}" 16 | VERBATIM) 17 | 18 | add_executable(clemens_test_harness 19 | main.cpp 20 | harness.cpp 21 | ${CLEMENS_TEST_COMMON_ASSETS}) 22 | 23 | target_link_libraries(clemens_test_harness 24 | PRIVATE clemens_host_core ) 25 | 26 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 27 | target_link_libraries(clemens_test_harness PRIVATE pthread) 28 | endif() 29 | 30 | target_compile_definitions(clemens_test_harness PRIVATE JSON_NOEXCEPTION) 31 | -------------------------------------------------------------------------------- /host/ext/spdlog/cfg/env.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Init levels and patterns from env variables SPDLOG_LEVEL 11 | // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). 12 | // Note - fallback to "info" level on unrecognized levels 13 | // 14 | // Examples: 15 | // 16 | // set global level to debug: 17 | // export SPDLOG_LEVEL=debug 18 | // 19 | // turn off all logging except for logger1: 20 | // export SPDLOG_LEVEL="*=off,logger1=debug" 21 | // 22 | 23 | // turn off all logging except for logger1 and logger2: 24 | // export SPDLOG_LEVEL="off,logger1=debug,logger2=info" 25 | 26 | namespace spdlog { 27 | namespace cfg { 28 | inline void load_env_levels() 29 | { 30 | auto env_val = details::os::getenv("SPDLOG_LEVEL"); 31 | if (!env_val.empty()) 32 | { 33 | helpers::load_levels(env_val); 34 | } 35 | } 36 | 37 | } // namespace cfg 38 | } // namespace spdlog 39 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/null_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | // null, no cost dummy "mutex" and dummy "atomic" int 9 | 10 | namespace spdlog { 11 | namespace details { 12 | struct null_mutex 13 | { 14 | void lock() const {} 15 | void unlock() const {} 16 | }; 17 | 18 | struct null_atomic_int 19 | { 20 | int value; 21 | null_atomic_int() = default; 22 | 23 | explicit null_atomic_int(int new_value) 24 | : value(new_value) 25 | {} 26 | 27 | int load(std::memory_order = std::memory_order_relaxed) const 28 | { 29 | return value; 30 | } 31 | 32 | void store(int new_value, std::memory_order = std::memory_order_relaxed) 33 | { 34 | value = new_value; 35 | } 36 | 37 | int exchange(int new_value, std::memory_order = std::memory_order_relaxed) 38 | { 39 | std::swap(new_value, value); 40 | return new_value; // return value before the call 41 | } 42 | }; 43 | 44 | } // namespace details 45 | } // namespace spdlog 46 | -------------------------------------------------------------------------------- /host/ext/imgui/imgui_filedialog/dirent/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 1998-2019 Toni Ronkko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /host/ext/imgui/imgui_filedialog/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2022 Stephane Cuillerdier (aka Aiekick) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /host/clem_preamble.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_PREAMBLE_HPP 2 | #define CLEM_HOST_PREAMBLE_HPP 3 | 4 | #include "clem_host_shared.hpp" 5 | 6 | struct ClemensConfiguration; 7 | 8 | /** 9 | * @brief Handle pre-initialization and any other premlinary GUI before running the emulator. 10 | * 11 | * This class extends ClemensFront GUI by introducing the emulator and loading the configuration. 12 | * 13 | */ 14 | class ClemensPreamble { 15 | public: 16 | enum class Result { Ok, Active, Exit }; 17 | 18 | ClemensPreamble(ClemensConfiguration &config); 19 | 20 | Result frame(int width, int height); 21 | 22 | private: 23 | ClemensConfiguration &config_; 24 | enum Mode { 25 | // Load configuration and check whether to display welcome or proceed to 26 | // the emulator 27 | Start, 28 | // This is a new version (or first time run) so display the new version 29 | // welcome screen 30 | NewVersion, 31 | // First time user help 32 | FirstUse, 33 | // Something happened where we need to exit the app 34 | Exit, 35 | // Everything OK - run the emulator! 36 | Continue 37 | }; 38 | 39 | Mode mode_; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /host/cinek/keyframe.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // keyframe.hpp 3 | // SampleCommon 4 | // 5 | // Created by Samir Sinha on 2/25/16. 6 | // Copyright © 2016 Cinekine. All rights reserved. 7 | // 8 | 9 | #ifndef CINEK_MATH_KF_HPP 10 | #define CINEK_MATH_KF_HPP 11 | 12 | namespace cinek { 13 | 14 | enum class transition { 15 | kDefault, 16 | kLinear, 17 | kEase, 18 | kEaseIn, 19 | kEaseOut, 20 | kEaseCubic, 21 | kEaseInCubic, 22 | kEaseOutCubic, 23 | kSine 24 | }; 25 | 26 | /// The keyframe class defines a data point within a sequence 27 | /// 28 | template struct keyframe { 29 | typedef _property property_type; 30 | 31 | property_type prop; 32 | 33 | double time; 34 | 35 | keyframe(const property_type &property, float t) : prop(property), time(t) {} 36 | keyframe() : prop(), time(0.f) {} 37 | }; 38 | 39 | template 40 | bool operator<(const keyframe<_property> &a, const keyframe<_property> &b) { 41 | return a.time < b.time; 42 | } 43 | template 44 | bool operator==(const keyframe<_property> &a, const keyframe<_property> &b) { 45 | return a.time == b.time; 46 | } 47 | 48 | } // namespace cinek 49 | 50 | #endif /* keyframe_h */ 51 | -------------------------------------------------------------------------------- /host/macos_bundle_info_plist.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${MACOSX_BUNDLE_EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | ${MACOSX_BUNDLE_ICON_FILE} 11 | CFBundleIdentifier 12 | ${MACOSX_BUNDLE_GUI_IDENTIFIER} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${MACOSX_BUNDLE_BUNDLE_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | ${MACOSX_BUNDLE_SHORT_VERSION_STRING} 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | ${MACOSX_BUNDLE_BUNDLE_VERSION} 25 | CSResourcesFileMapped 26 | 27 | NSHumanReadableCopyright 28 | ${MACOSX_BUNDLE_COPYRIGHT} 29 | CFBundleIconFile 30 | icon.icns 31 | 32 | 33 | -------------------------------------------------------------------------------- /host/ext/spdlog/spdlog.cpp: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #ifndef SPDLOG_COMPILED_LIB 5 | #error Please define SPDLOG_COMPILED_LIB to compile this file. 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | // template instantiate logger constructor with sinks init list 24 | template SPDLOG_API spdlog::logger::logger(std::string name, 25 | sinks_init_list::iterator begin, 26 | sinks_init_list::iterator end); 27 | template class SPDLOG_API spdlog::sinks::base_sink; 28 | template class SPDLOG_API spdlog::sinks::base_sink; 29 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/log_msg-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace details { 14 | 15 | SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name, 16 | spdlog::level::level_enum lvl, spdlog::string_view_t msg) 17 | : logger_name(a_logger_name) 18 | , level(lvl) 19 | , time(log_time) 20 | #ifndef SPDLOG_NO_THREAD_ID 21 | , thread_id(os::thread_id()) 22 | #endif 23 | , source(loc) 24 | , payload(msg) 25 | {} 26 | 27 | SPDLOG_INLINE log_msg::log_msg( 28 | spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) 29 | : log_msg(os::now(), loc, a_logger_name, lvl, msg) 30 | {} 31 | 32 | SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) 33 | : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) 34 | {} 35 | 36 | } // namespace details 37 | } // namespace spdlog 38 | -------------------------------------------------------------------------------- /host/clem_host.cpp: -------------------------------------------------------------------------------- 1 | #include "clem_host.hpp" 2 | 3 | #if defined(CK3D_BACKEND_D3D11) 4 | #define SOKOL_D3D11 5 | #elif defined(CK3D_BACKEND_GL) 6 | #define SOKOL_GLCORE33 7 | #endif 8 | 9 | #include "imgui.h" 10 | 11 | #define SOKOL_IMPL 12 | #include "sokol/sokol_app.h" 13 | #include "sokol/sokol_audio.h" 14 | #include "sokol/sokol_gfx.h" 15 | #include "sokol/sokol_gfx_ext.h" 16 | #include "sokol/sokol_glue.h" 17 | #include "sokol/sokol_imgui.h" 18 | #include "sokol/sokol_time.h" 19 | 20 | 21 | static ClemensHostInterop *s_interop = nullptr; 22 | 23 | void clemens_host_init(struct ClemensHostInterop *interop) { s_interop = interop; } 24 | 25 | void clemens_host_update() { 26 | #if defined(WIN32) 27 | // augment the minimum height using the title bar metric 28 | // assuming the default style used by sokol_app 29 | RECT windowRect; 30 | windowRect.left = 0; 31 | windowRect.top = 0; 32 | windowRect.right = s_interop->minWindowWidth; 33 | windowRect.bottom = s_interop->minWindowHeight; 34 | AdjustWindowRectEx(&windowRect, 0, FALSE, WS_EX_OVERLAPPEDWINDOW); 35 | sapp_win32_set_min_window_size(windowRect.right - windowRect.left, 36 | windowRect.bottom - windowRect.top); 37 | #endif 38 | } 39 | 40 | void clemens_host_terminate() {} 41 | -------------------------------------------------------------------------------- /host/clem_host.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_H 2 | #define CLEM_HOST_H 3 | 4 | struct ClemensHostInterop { 5 | bool exitApp; 6 | bool mouseShow; 7 | 8 | // system/menu notifications to the main app 9 | bool nativeMenu; 10 | enum { 11 | None, 12 | PasteFromClipboard, 13 | LoadSnapshot, 14 | SaveSnapshot, 15 | Power, 16 | Shutdown, 17 | Reboot, 18 | Help, 19 | DiskHelp, 20 | Debugger, 21 | Standard, 22 | AspectView, 23 | JoystickConfig, 24 | MouseLock, 25 | MouseUnlock, 26 | PauseExecution, 27 | ContinueExecution, 28 | EnableFastMode, 29 | DisableFastMode, 30 | About 31 | } action; 32 | 33 | // events from the main app 34 | bool poweredOn; 35 | bool debuggerOn; 36 | bool allowConfigureJoystick; 37 | bool mouseLock; 38 | bool running; 39 | bool fastMode; 40 | unsigned viewWidth; // 0 = no change 41 | unsigned viewHeight; // 0 = no change 42 | unsigned minWindowWidth; 43 | unsigned minWindowHeight; 44 | }; 45 | 46 | void clemens_host_init(ClemensHostInterop *interop); 47 | 48 | void clemens_host_update(); 49 | 50 | void clemens_host_terminate(); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/basic_file_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers &event_handlers) 18 | : file_helper_{event_handlers} 19 | { 20 | file_helper_.open(filename, truncate); 21 | } 22 | 23 | template 24 | SPDLOG_INLINE const filename_t &basic_file_sink::filename() const 25 | { 26 | return file_helper_.filename(); 27 | } 28 | 29 | template 30 | SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) 31 | { 32 | memory_buf_t formatted; 33 | base_sink::formatter_->format(msg, formatted); 34 | file_helper_.write(formatted); 35 | } 36 | 37 | template 38 | SPDLOG_INLINE void basic_file_sink::flush_() 39 | { 40 | file_helper_.flush(); 41 | } 42 | 43 | } // namespace sinks 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/log_msg.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | struct SPDLOG_API log_msg 12 | { 13 | log_msg() = default; 14 | log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 15 | log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 16 | log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); 17 | log_msg(const log_msg &other) = default; 18 | log_msg &operator=(const log_msg &other) = default; 19 | 20 | string_view_t logger_name; 21 | level::level_enum level{level::off}; 22 | log_clock::time_point time; 23 | size_t thread_id{0}; 24 | 25 | // wrapping the formatted text with color (updated by pattern_formatter). 26 | mutable size_t color_range_start{0}; 27 | mutable size_t color_range_end{0}; 28 | 29 | source_loc source; 30 | string_view_t payload; 31 | }; 32 | } // namespace details 33 | } // namespace spdlog 34 | 35 | #ifdef SPDLOG_HEADER_ONLY 36 | # include "log_msg-inl.h" 37 | #endif 38 | -------------------------------------------------------------------------------- /host/harness/test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "act": "reset" 4 | }, 5 | { 6 | "act": "step", 7 | "param": 100 8 | }, 9 | { 10 | "act": "insert_disk", 11 | "param": { 12 | "drive": "s6d1", 13 | "disk": "data/dos_3_3_master.woz" 14 | } 15 | }, 16 | { 17 | "act": "step", 18 | "param": { 19 | "count": 100, 20 | "status": 10 21 | } 22 | }, 23 | { 24 | "act": "frame" 25 | }, 26 | { 27 | "act": "save", 28 | "param": "sample.clemens-sav" 29 | }, 30 | { 31 | "act": "eject_disk", 32 | "param": { 33 | "drive": "s6d1" 34 | } 35 | }, 36 | { 37 | "act": "step", 38 | "param": 100 39 | }, 40 | { 41 | "act": "load", 42 | "param": "sample.clemens-sav" 43 | }, 44 | { 45 | "act": "eject_disk", 46 | "param": { 47 | "drive": "s6d1" 48 | } 49 | }, 50 | { 51 | "act": "step", 52 | "param": 100 53 | }, 54 | { 55 | "act": "load", 56 | "param": "sample.clemens-sav" 57 | }, 58 | { 59 | "act": "eject_disk", 60 | "param": { 61 | "drive": "s6d1" 62 | } 63 | } 64 | ] 65 | -------------------------------------------------------------------------------- /host/clem_ui_load_snapshot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_LOAD_SNAPSHOT_UI_HPP 2 | #define CLEM_HOST_LOAD_SNAPSHOT_UI_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "core/clem_snapshot.hpp" 9 | 10 | class ClemensCommandQueue; 11 | 12 | class ClemensLoadSnapshotUI { 13 | public: 14 | bool isStarted() const; 15 | void start(ClemensCommandQueue &backend, const std::string &snapshotDir); 16 | bool frame(float width, float height, ClemensCommandQueue &backend); 17 | void stop(ClemensCommandQueue &backend); 18 | void succeeded(); 19 | void fail(); 20 | 21 | private: 22 | enum class Mode { None, Browser, WaitForResponse, Succeeded, Failed, Cancelled }; 23 | 24 | Mode mode_ = Mode::None; 25 | std::string snapshotDir_; 26 | char snapshotName_[128]; 27 | bool resumeExecutionOnExit_; 28 | 29 | void refresh(); 30 | void loadSnapshotImage(unsigned snapshotIndex); 31 | void freeSnapshotImage(); 32 | 33 | std::vector snapshotNames_; 34 | std::vector snapshotMetadatas_; 35 | 36 | uintptr_t snapshotImage_ = 0; 37 | int snapshotImageWidth_ = 0; 38 | int snapshotImageHeight_ = 0; 39 | int snapshotIndex_ = -1; 40 | struct tm snapshotTime_; 41 | bool doRefresh_ = false; 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /host/strings/clem_settings.inl: -------------------------------------------------------------------------------- 1 | const char *kSettingsNotAvailable[] = {"This setting is not available in this version."}; 2 | const char *kSettingsTabMachine[] = {"Machine"}; 3 | 4 | const char *kSettingsMachineSystemMemory[] = {"Memory"}; 5 | const char *kSettingsMachineSystemSetup[] = {"System Setup"}; 6 | const char *kSettingsMachineSystemSetupInfo[] = { 7 | "These options will take effect after power cycling the emulated machine."}; 8 | const char *kSettingsMachineROMFilename[] = {"ROM Filename"}; 9 | const char *kSettingsMachineCards[] = {"Cards"}; 10 | 11 | const char *kSettingsTabEmulation[] = {"Emulation"}; 12 | const char *kSettingsEmulationFastDisk[] = {"Fast Disk Mode"}; 13 | const char *kSettingsEmulationFaskDiskHelp[] = {R"txt( 14 | Enabling this mode will speed up disk access in most cases. 15 | 16 | Fast disk emulation may have an effect audio playback (i.e. Mockingboard) while the disk drive is active. It may cause undefined behavior for certain titles. Disabling this feature will result in authentic real-world timing (and sluggish disk access ca. 1987).)txt"}; 17 | 18 | const char *kSettingsROMFileWarning[] = {R"txt( 19 | A ROM 3 file is necessary to emulate an Apple IIGS. Without such a file, the emulator will hang on startup. 20 | )txt"}; 21 | 22 | const char *kSettingsROMFileError[] = {"The file cannot be found."}; 23 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/backtracer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // Store log messages in circular buffer. 14 | // Useful for storing debug data in case of error/warning happens. 15 | 16 | namespace spdlog { 17 | namespace details { 18 | class SPDLOG_API backtracer 19 | { 20 | mutable std::mutex mutex_; 21 | std::atomic enabled_{false}; 22 | circular_q messages_; 23 | 24 | public: 25 | backtracer() = default; 26 | backtracer(const backtracer &other); 27 | 28 | backtracer(backtracer &&other) SPDLOG_NOEXCEPT; 29 | backtracer &operator=(backtracer other); 30 | 31 | void enable(size_t size); 32 | void disable(); 33 | bool enabled() const; 34 | void push_back(const log_msg &msg); 35 | 36 | // pop all items in the q and apply the given fun on each of them. 37 | void foreach_pop(std::function fun); 38 | }; 39 | 40 | } // namespace details 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | # include "backtracer-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /devices/hddcard.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_CARD_HDDCARD_H 2 | #define CLEM_CARD_HDDCARD_H 3 | 4 | #include "clem_shared.h" 5 | 6 | typedef struct mpack_writer_t mpack_writer_t; 7 | typedef struct mpack_reader_t mpack_reader_t; 8 | 9 | typedef struct ClemensProdosHDD32 ClemensProdosHDD32; 10 | 11 | #define CLEM_CARD_HDD_STATUS_DRIVE_ON 1 12 | #define CLEM_CARD_HDD_STATUS_DRIVE_WRITE_PROT 2 13 | 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | void clem_card_hdd_initialize(ClemensCard *card); 20 | void clem_card_hdd_uninitialize(ClemensCard *card); 21 | void clem_card_hdd_mount(ClemensCard* card, ClemensProdosHDD32* hdd, uint8_t drive_index); 22 | 23 | ClemensProdosHDD32* clem_card_hdd_unmount(ClemensCard* card, uint8_t drive_index); 24 | void clem_card_hdd_serialize(mpack_writer_t* writer, ClemensCard* card); 25 | void clem_card_hdd_unserialize(mpack_reader_t* reader, ClemensCard* card, 26 | ClemensSerializerAllocateCb alloc_cb, 27 | void* context); 28 | unsigned clem_card_hdd_get_status(ClemensCard *card, uint8_t drive_index); 29 | void clem_card_hdd_lock(ClemensCard* card, uint8_t lock, uint8_t drive_index); 30 | uint8_t clem_card_hdd_drive_index_has_image(ClemensCard* card, uint8_t drive_index); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/stdout_color_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | template 16 | SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode) 17 | { 18 | return Factory::template create(logger_name, mode); 19 | } 20 | 21 | template 22 | SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode) 23 | { 24 | return Factory::template create(logger_name, mode); 25 | } 26 | 27 | template 28 | SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode) 29 | { 30 | return Factory::template create(logger_name, mode); 31 | } 32 | 33 | template 34 | SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode) 35 | { 36 | return Factory::template create(logger_name, mode); 37 | } 38 | } // namespace spdlog 39 | -------------------------------------------------------------------------------- /host/clem_asset_browser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_ASSET_BROWSER_HPP 2 | #define CLEM_HOST_ASSET_BROWSER_HPP 3 | 4 | #include "clem_file_browser.hpp" 5 | #include "core/clem_disk_asset.hpp" 6 | 7 | #include 8 | 9 | class ClemensAssetBrowser : public ClemensFileBrowser { 10 | 11 | public: 12 | ClemensAssetBrowser(); 13 | 14 | void setDiskType(ClemensDiskAsset::DiskType diskType); 15 | 16 | bool isSelectedFilePathNewFile() const { 17 | return createDiskImageType_ != ClemensDiskAsset::ImageNone; 18 | } 19 | 20 | protected: 21 | bool onCreateRecord(const std::filesystem::directory_entry &direntry, 22 | ClemensFileBrowser::Record &) final; 23 | std::string onDisplayRecord(const ClemensFileBrowser::Record &record) final; 24 | BrowserFinishedStatus onExtraSelectionUI(ImVec2 dimensions, Record &selectedRecord) final; 25 | 26 | private: 27 | ClemensDiskAsset::DiskType diskType_; 28 | 29 | // This should fit inside ClemensFileBrowser::Record::context and 30 | // compilation will fail if it doesn't 31 | struct ClemensAssetData { 32 | ClemensDiskAsset::DiskType diskType; 33 | ClemensDiskAsset::ImageType imageType; 34 | }; 35 | 36 | // used for creating asset files 37 | char createDiskFilename_[128]; 38 | int createDiskMBCount_; 39 | ClemensDiskAsset::ImageType createDiskImageType_; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /host/clem_l10n.cpp: -------------------------------------------------------------------------------- 1 | #include "clem_l10n.hpp" 2 | 3 | namespace ClemensL10N { 4 | 5 | #include "strings/clem_hotkeys.inl" 6 | #include "strings/clem_welcome.inl" 7 | 8 | const char *kExitMessage[] = {"Any unsaved progress will be lost.\nDo you want to exit?"}; 9 | const char *kModalDeleteSnapshot[] = {"Delete Snapshot"}; 10 | const char *kLabelDeleteConfirm[] = {"Are you sure you want to delete %s?"}; 11 | const char *kLabelDeleteFailed[] = {"Unable to delete the selected file."}; 12 | const char *kLabelDelete[] = {"Delete"}; 13 | const char *kLabelOk[] = {"Ok"}; 14 | const char *kLabelCancel[] = {"Cancel"}; 15 | const char *kTitleJoystickConfiguration[] = {"Joystick Configuration"}; 16 | const char *kLabelJoystickNone[] = {"No joysticks are available."}; 17 | const char *kLabelJoystickHelp[] = {"Adjust X and Y to set the desired center position."}; 18 | const char *kLabelJoystick2Help[] = {"Press the binding button to assign it to a joystick button."}; 19 | const char *kLabelJoystickButtonBinding[] = {"Press any joystick/gamepad button to bind Apple BTN %u"}; 20 | const char *kLabelJoystickId[] = {"Joystick #%u"}; 21 | const char *kLabelJoystickConfirm[] = {"Configure"}; 22 | const char* kButtonJoystickButton1[] = {"Btn 0"}; 23 | const char* kButtonJoystickButton2[] = {"Btn 1"}; 24 | 25 | #include "strings/clem_help.inl" 26 | #include "strings/clem_settings.inl" 27 | #include "strings/clem_debug.inl" 28 | 29 | } // namespace ClemensL10N 30 | -------------------------------------------------------------------------------- /host/ext/spdlog/cfg/argv.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | // 9 | // Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" 10 | // 11 | // set all loggers to debug level: 12 | // example.exe "SPDLOG_LEVEL=debug" 13 | 14 | // set logger1 to trace level 15 | // example.exe "SPDLOG_LEVEL=logger1=trace" 16 | 17 | // turn off all logging except for logger1 and logger2: 18 | // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" 19 | 20 | namespace spdlog { 21 | namespace cfg { 22 | 23 | // search for SPDLOG_LEVEL= in the args and use it to init the levels 24 | inline void load_argv_levels(int argc, const char **argv) 25 | { 26 | const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; 27 | for (int i = 1; i < argc; i++) 28 | { 29 | std::string arg = argv[i]; 30 | if (arg.find(spdlog_level_prefix) == 0) 31 | { 32 | auto levels_string = arg.substr(spdlog_level_prefix.size()); 33 | helpers::load_levels(levels_string); 34 | } 35 | } 36 | } 37 | 38 | inline void load_argv_levels(int argc, char **argv) 39 | { 40 | load_argv_levels(argc, const_cast(argv)); 41 | } 42 | 43 | } // namespace cfg 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/null_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | 15 | template 16 | class null_sink : public base_sink 17 | { 18 | protected: 19 | void sink_it_(const details::log_msg &) override {} 20 | void flush_() override {} 21 | }; 22 | 23 | using null_sink_mt = null_sink; 24 | using null_sink_st = null_sink; 25 | 26 | } // namespace sinks 27 | 28 | template 29 | inline std::shared_ptr null_logger_mt(const std::string &logger_name) 30 | { 31 | auto null_logger = Factory::template create(logger_name); 32 | null_logger->set_level(level::off); 33 | return null_logger; 34 | } 35 | 36 | template 37 | inline std::shared_ptr null_logger_st(const std::string &logger_name) 38 | { 39 | auto null_logger = Factory::template create(logger_name); 40 | null_logger->set_level(level::off); 41 | return null_logger; 42 | } 43 | 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /tests/cpu/test_adc.c: -------------------------------------------------------------------------------- 1 | #include "emulator.h" 2 | #include "unity.h" 3 | 4 | void setUp() {} 5 | 6 | void tearDown(void) {} 7 | 8 | void test_adc_imm(void) {} 9 | 10 | void test_adc_abs(void) {} 11 | 12 | void test_adc_abslong(void) {} 13 | 14 | void test_adc_dp(void) {} 15 | 16 | void test_adc_dp_indirect(void) {} 17 | 18 | void test_adc_dp_indirect_long(void) {} 19 | 20 | void test_adc_abs_i_x(void) {} 21 | 22 | void test_adc_abs_long_i_x(void) {} 23 | 24 | void test_adc_abs_i_y(void) {} 25 | 26 | void test_adc_dp_i_x(void) {} 27 | 28 | void test_adc_dp_i_indirect_x(void) {} 29 | 30 | void test_adc_dp_indirect_i_y(void) {} 31 | 32 | void test_adc_dp_indirect_long_i_y(void) {} 33 | 34 | void test_adc_stack_rel(void) {} 35 | 36 | void test_adc_stack_rel_indirect_i_y(void) {} 37 | 38 | int main(void) { 39 | UNITY_BEGIN(); 40 | 41 | RUN_TEST(test_adc_imm); 42 | RUN_TEST(test_adc_abs); 43 | RUN_TEST(test_adc_abslong); 44 | RUN_TEST(test_adc_dp); 45 | RUN_TEST(test_adc_dp_indirect); 46 | RUN_TEST(test_adc_dp_indirect_long); 47 | RUN_TEST(test_adc_abs_i_x); 48 | RUN_TEST(test_adc_abs_long_i_x); 49 | RUN_TEST(test_adc_abs_i_y); 50 | RUN_TEST(test_adc_dp_i_x); 51 | RUN_TEST(test_adc_dp_i_indirect_x); 52 | RUN_TEST(test_adc_dp_indirect_i_y); 53 | RUN_TEST(test_adc_dp_indirect_long_i_y); 54 | RUN_TEST(test_adc_stack_rel); 55 | RUN_TEST(test_adc_stack_rel_indirect_i_y); 56 | 57 | return UNITY_END(); 58 | } 59 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/ostream_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | template 15 | class ostream_sink final : public base_sink 16 | { 17 | public: 18 | explicit ostream_sink(std::ostream &os, bool force_flush = false) 19 | : ostream_(os) 20 | , force_flush_(force_flush) 21 | {} 22 | ostream_sink(const ostream_sink &) = delete; 23 | ostream_sink &operator=(const ostream_sink &) = delete; 24 | 25 | protected: 26 | void sink_it_(const details::log_msg &msg) override 27 | { 28 | memory_buf_t formatted; 29 | base_sink::formatter_->format(msg, formatted); 30 | ostream_.write(formatted.data(), static_cast(formatted.size())); 31 | if (force_flush_) 32 | { 33 | ostream_.flush(); 34 | } 35 | } 36 | 37 | void flush_() override 38 | { 39 | ostream_.flush(); 40 | } 41 | 42 | std::ostream &ostream_; 43 | bool force_flush_; 44 | }; 45 | 46 | using ostream_sink_mt = ostream_sink; 47 | using ostream_sink_st = ostream_sink; 48 | 49 | } // namespace sinks 50 | } // namespace spdlog 51 | -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens.yaml: -------------------------------------------------------------------------------- 1 | app-id: com.cinekine.Clemens 2 | 3 | runtime: org.freedesktop.Platform 4 | runtime-version: '22.08' 5 | sdk: org.freedesktop.Sdk 6 | 7 | command: clemens_iigs 8 | 9 | modules: 10 | - name: clemens 11 | 12 | buildsystem: simple 13 | build-commands: 14 | - cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -G Ninja -S . -B . 15 | - ninja 16 | - install -D host/clemens_iigs /app/bin/clemens_iigs 17 | - install -Dm755 flatpak/com.cinekine.Clemens.desktop -t /app/share/applications 18 | - install -Dm644 flatpak/com.cinekine.Clemens_16.png /app/share/icons/hicolor/16x16/apps/com.cinekine.Clemens.png 19 | - install -Dm644 flatpak/com.cinekine.Clemens_32.png /app/share/icons/hicolor/32x32/apps/com.cinekine.Clemens.png 20 | - install -Dm644 flatpak/com.cinekine.Clemens_64.png /app/share/icons/hicolor/64x64/apps/com.cinekine.Clemens.png 21 | - install -Dm644 flatpak/com.cinekine.Clemens_128.png /app/share/icons/hicolor/128x128/apps/com.cinekine.Clemens.png 22 | - install -Dm644 flatpak/com.cinekine.Clemens_256.png /app/share/icons/hicolor/256x256/apps/com.cinekine.Clemens.png 23 | - install -Dm644 flatpak/com.cinekine.Clemens.appdata.xml -t /app/share/metainfo 24 | 25 | sources: 26 | - type: dir 27 | path: .. 28 | dest: . 29 | 30 | finish-args: 31 | - --share=ipc 32 | - --socket=fallback-x11 33 | - --socket=wayland 34 | - --filesystem=host 35 | - --share=network 36 | - --device=dri 37 | -------------------------------------------------------------------------------- /host/ext/spdlog/fmt/bundled/fmt.license.rst: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - present, Victor Zverovich 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | --- Optional exception to the license --- 23 | 24 | As an exception, if, as a result of your compiling your source code, portions 25 | of this Software are embedded into a machine-executable object form of such 26 | source code, you may redistribute such embedded portions in such object form 27 | without including the above copyright and permission notices. 28 | -------------------------------------------------------------------------------- /clem_drive.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_DRIVE_H 2 | #define CLEM_DRIVE_H 3 | 4 | #include "clem_mmio_types.h" 5 | #include "clem_shared.h" 6 | 7 | #define CLEM_IWM_FLAG_MASK_PRE_STEP_CLEARED \ 8 | (CLEM_IWM_FLAG_WRPROTECT_SENSE + CLEM_IWM_FLAG_READ_DATA + CLEM_IWM_FLAG_READ_DATA_FAKE + \ 9 | CLEM_IWM_FLAG_WRITE_HI) 10 | 11 | #define CLEM_IWM_FLAG_WRITE_HEAD_ON (CLEM_IWM_FLAG_WRITE_DATA + CLEM_IWM_FLAG_WRITE_REQUEST) 12 | 13 | #define CLEM_IWM_DRIVE_INVALID_TRACK_POS 0xffffffff 14 | 15 | #define CLEM_IWM_DISK35_STATUS_STEP_IN 0x0001 16 | #define CLEM_IWM_DISK35_STATUS_IO_HEAD_HI 0x0002 17 | #define CLEM_IWM_DISK35_STATUS_EJECTED 0x0008 18 | #define CLEM_IWM_DISK35_STATUS_EJECTING 0x0010 19 | #define CLEM_IWM_DISK35_STATUS_STROBE 0x8000 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | void clem_disk_reset_drives(struct ClemensDriveBay *drives); 26 | void clem_disk_start_drive(struct ClemensDrive *drive); 27 | 28 | void clem_disk_35_start_eject(struct ClemensDrive *drive); 29 | 30 | void clem_disk_control(struct ClemensDrive *drive, unsigned *io_flags, unsigned in_phase, 31 | clem_clocks_duration_t clocks_dt); 32 | 33 | void clem_disk_step(struct ClemensDrive *drive, unsigned *io_flags); 34 | 35 | void clem_disk_write_head(struct ClemensDrive *drive, unsigned *io_flags); 36 | 37 | void clem_disk_update_head(struct ClemensDrive *drive, unsigned *io_flags); 38 | 39 | #ifdef __cplusplus 40 | } // extern "C" 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /devices/mockingboard.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_CARD_MOCKINGBOARD_H 2 | #define CLEM_CARD_MOCKINGBOARD_H 3 | 4 | #include "clem_shared.h" 5 | 6 | typedef struct mpack_writer_t mpack_writer_t; 7 | typedef struct mpack_reader_t mpack_reader_t; 8 | 9 | 10 | /* these are here for references - the actual functions are determined 11 | by which bits in the address register are set on io_read and io_write 12 | */ 13 | #define CLEM_CARD_MOCKINGBOARD_ORB1 0x00 14 | #define CLEM_CARD_MOCKINGBOARD_ORA1 0x01 15 | #define CLEM_CARD_MOCKINGBOARD_DDRB1 0x02 16 | #define CLEM_CARD_MOCKINGBOARD_DDRA1 0x03 17 | #define CLEM_CARD_MOCKINGBOARD_ORB2 0x80 18 | #define CLEM_CARD_MOCKINGBOARD_ORA2 0x81 19 | #define CLEM_CARD_MOCKINGBOARD_DDRB2 0x82 20 | #define CLEM_CARD_MOCKINGBOARD_DDRA2 0x83 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | void clem_card_mockingboard_initialize(ClemensCard *card); 27 | void clem_card_mockingboard_uninitialize(ClemensCard *card); 28 | void clem_card_mockingboard_serialize(mpack_writer_t* writer, ClemensCard* card); 29 | void clem_card_mockingboard_unserialize(mpack_reader_t* reader, ClemensCard* card, 30 | ClemensSerializerAllocateCb alloc_cb, 31 | void* context); 32 | unsigned clem_card_ay3_render(ClemensCard *card, float *samples_out, 33 | unsigned sample_limit, unsigned samples_per_frame, 34 | unsigned samples_per_second); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /host/clem_assets.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_ASSETS_HPP 2 | #define CLEM_HOST_ASSETS_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace ClemensHostAssets { 8 | 9 | enum ImageId { 10 | kInvalidImageId = -1, 11 | kPowerButton = 0, 12 | kPowerCycle, 13 | kSettings, 14 | kHelp, 15 | kDebugger, 16 | kLoad, 17 | kSave, 18 | kRunMachine, 19 | kStopMachine, 20 | kJoystick, 21 | kCard, 22 | kFastEmulate, 23 | kFolder, 24 | kDisk35, 25 | kDisk525, 26 | kDiskHDD, 27 | kLockDisk, 28 | kEjectDisk, 29 | kFirstNamedImage, 30 | kLastNamedImage = kFirstNamedImage + 64, 31 | kImageCount 32 | }; 33 | 34 | void initialize(); 35 | uintptr_t getImage(ImageId imageId); 36 | int getImageWidth(ImageId imageId); 37 | int getImageHeight(ImageId imageId); 38 | float getImageAspect(ImageId imageId); 39 | ImageId getImageFromName(std::string_view name); 40 | void terminate(); 41 | 42 | 43 | // this can be freed with freeLoadedBitmap(); 44 | uint8_t* loadBitmapFromPNG(const uint8_t *data, size_t dataSize, int* width, int* height); 45 | // only call this with bitmapas loaded with loadBitmapFromPNG 46 | void freeLoadedBitmap(uint8_t* data); 47 | // dynamically create texture images from PNG data 48 | uintptr_t loadImageFromPNG(const uint8_t *data, size_t dataSize, int* width, int* height); 49 | // only call for images that will be thrown out (i.e. from loadImageFromPNG) 50 | void freeLoadedImage(uintptr_t imageId); 51 | 52 | 53 | 54 | } // namespace ClemensHostAssets 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /host/cinek/ckopts.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2012 Cinekine Media 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 14 | * all 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 22 | * THE SOFTWARE. 23 | * 24 | * @file cinek/ckdefs.h 25 | * @author Samir Sinha 26 | * @date 11/1/2013 27 | * @brief C and C++ common macros and definitions 28 | * @copyright Cinekine 29 | */ 30 | 31 | #ifndef CINEK_OPTS_H 32 | #define CINEK_OPTS_H 33 | 34 | #ifndef NDEBUG 35 | #define CK_DEBUG 36 | #endif 37 | 38 | /* CINEK_OPTS_H */ 39 | #endif 40 | -------------------------------------------------------------------------------- /host/clem_imgui.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_IMGUI_HPP 2 | #define CLEM_HOST_IMGUI_HPP 3 | 4 | #include "imgui.h" 5 | 6 | #include "cinek/buffer.hpp" 7 | #include 8 | #include 9 | 10 | #define CLEM_HOST_OPEN_APPLE_UTF8 "\xee\x80\x90" 11 | #define CLEM_HOST_FOLDER_LEFT_UTF8 "\xee\x82\x98" 12 | #define CLEM_HOST_FOLDER_RIGHT_UTF8 "\xee\x82\x99" 13 | 14 | namespace ClemensHostImGui { 15 | 16 | constexpr unsigned kFontDefault = 0; 17 | constexpr unsigned kFontNarrow = 1; 18 | constexpr unsigned kFontDefaultMedium = 2; 19 | constexpr unsigned kFontNarrowMedium = 3; 20 | constexpr unsigned kFontTotalCount = 4; 21 | 22 | void FontSetup(ImVector &unicodeRanges, const cinek::ByteBuffer &systemFontLoBuffer, 23 | const cinek::ByteBuffer &systemFontHiBuffer); 24 | 25 | enum StatusBarFlags { StatusBarFlags_Inactive, StatusBarFlags_Active }; 26 | 27 | void StatusBarField(StatusBarFlags flags, const char *fmt, ...); 28 | void StatusBarField(StatusBarFlags flags, ImTextureID icon, const ImVec2 &size); 29 | 30 | // use styling to color the image only with transparent background 31 | bool IconButton(const char *strId, ImTextureID texId, const ImVec2 &size); 32 | 33 | // uses the ImGui markdown widget. 34 | // returns the link to navigate to if selected 35 | std::string Markdown(std::string_view markdown); 36 | 37 | // styling hooks for common widgets 38 | void PushStyleButtonEnabled(); 39 | void PushStyleButtonDisabled(); 40 | void PopStyleButton(); 41 | 42 | ImFont *Get80ColumnFont(); 43 | 44 | } // namespace ClemensHostImGui 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /host/harness/harness.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_TEST_HARNESS_HPP 2 | #define CLEM_HOST_TEST_HARNESS_HPP 3 | 4 | #include "core/clem_apple2gs.hpp" 5 | 6 | #include "json.hpp" 7 | 8 | #include 9 | 10 | class ClemensTestHarness : public ClemensSystemListener { 11 | public: 12 | ClemensTestHarness(); 13 | ~ClemensTestHarness(); 14 | bool hasFailed() const { return failed_; } 15 | 16 | bool run(nlohmann::json &command); 17 | 18 | private: 19 | static void opcode(struct ClemensInstruction *inst, const char *operand, void *userptr); 20 | 21 | void onClemensSystemMachineLog(int logLevel, const ClemensMachine *machine, 22 | const char *msg) final; 23 | void onClemensSystemLocalLog(int logLevel, const char *msg) final; 24 | void onClemensSystemWriteConfig(const ClemensAppleIIGS::Config &config) final; 25 | void onClemensInstruction(struct ClemensInstruction *inst, const char *operand) final; 26 | 27 | private: 28 | bool reset(); 29 | bool step(nlohmann::json params); 30 | bool insertDisk(nlohmann::json params); 31 | bool ejectDisk(nlohmann::json params); 32 | bool save(nlohmann::json params); 33 | bool load(nlohmann::json params); 34 | bool getFrame(nlohmann::json params); 35 | 36 | private: 37 | void step(unsigned cnt, unsigned statusStepRate); 38 | void printStatus(); 39 | 40 | template 41 | void localLog(int log_level, const char *type, const char *msg, Args... args); 42 | 43 | std::unique_ptr a2gs_; 44 | uint64_t execCounter_; 45 | bool failed_; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /clem_vgc.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_VGC_H 2 | #define CLEM_VGC_H 3 | 4 | #include "clem_mmio_types.h" 5 | 6 | /** 7 | * Video Interface 8 | * These functions emulate the various peripherals (internal and external) 9 | */ 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | void clem_vgc_reset(struct ClemensVGC *vgc); 16 | void clem_vgc_reset_scanlines(struct ClemensVGC *vgc); 17 | 18 | void clem_vgc_sync(struct ClemensVGC *vgc, struct ClemensClock *clock, const uint8_t *mega2_bank0, 19 | const uint8_t *mega2_bank1); 20 | 21 | void clem_vgc_scanline_enable_int(struct ClemensVGC *vgc, bool enable); 22 | 23 | void clem_vgc_set_mode(struct ClemensVGC *vgc, unsigned mode_flags); 24 | void clem_vgc_clear_mode(struct ClemensVGC *vgc, unsigned mode_flags); 25 | void clem_vgc_set_text_colors(struct ClemensVGC *vgc, unsigned fg_color, unsigned bg_color); 26 | 27 | void clem_vgc_set_region(struct ClemensVGC *vgc, uint8_t c02b_value); 28 | uint8_t clem_vgc_get_region(struct ClemensVGC *vgc); 29 | 30 | uint8_t clem_vgc_read_switch(struct ClemensVGC *vgc, struct ClemensClock *clock, uint8_t ioreg, 31 | uint8_t flags); 32 | 33 | void clem_vgc_write_switch(struct ClemensVGC *vgc, struct ClemensClock *clock, uint8_t ioreg, 34 | uint8_t value); 35 | 36 | void clem_vgc_shgr_scanline(struct ClemensScanline *scanline, uint8_t *dest, 37 | const uint8_t *src_bank); 38 | 39 | void clem_vgc_calc_counters(struct ClemensVGC *vgc, struct ClemensClock *clock, unsigned *v_counter, 40 | unsigned *h_counter); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /docs/iwm_35_notes.txt: -------------------------------------------------------------------------------- 1 | Entry 2 | ===== 3 | $42 = Command? == 1 for read 4 | $43 = Unit (16 * slot) + (128 * drive-1) == 16*5 + 0 == #$50 5 | $44,$45 = RAM address (buffer to write to?) 6 | $46,$47 = disk address (blocks?) 7 | $48,$49 = entry point 8 | 9 | Prodos Entry ($00C5xx) 10 | ====================== 11 | $0007F8 = #$C5 12 | 13 | $E10FB0 = Stores the incoming carry flag in bit 7 (always #$80) 14 | $E10FCB = #$04 15 | $E10FCC = value of $C036 (Speed) at start (#$84) 16 | 17 | 18 | Prodos Firmware ($FF5BAD) 19 | ========================= 20 | 21 | $E10FB6 = don't know = #$A5 on start from slot 5 boot 22 | $E10FB7 = xor of FB6? 23 | $E10FB8 = don't know = #$03 on start 24 | $E10FC6 = stored SLTROMSEL (=#$80) 25 | $E10FC7.FC8 = stored #$807e (SLTROMSEL and XOR SLTROMSEL with bits 0,8 = 0) 26 | $E10FC9 = processor status at entry with Decimal cleared 27 | $E114E2.1504 = saved zero page $40-$62 28 | 29 | 30 | $E10F28 = drive index? 31 | $E10F2B = set to 0 after calling SUB_IWM_35_GOTO_TRACK_0 (seems to mean lower head) 32 | $E10F2F = 0x80 or 0x00 33 | $E10F30.F34 = Sector header? 34 | $E10F3A = current 3.5" track number? 35 | $E10F44 = ??? (0x20 set if failed to find address header) 36 | 37 | $E10F69 = 96 AA D5 (address header in reverse) 38 | 39 | SUB_IWM_35_READ_SECTOR_HEADER 40 | ============================= 41 | X = drive index 42 | 43 | $E10F37 = $03 at start 44 | 45 | Call via E1 hook to FF/4C53 46 | Call SUB_IWM_35_CHECK_DISKRDY 47 | If not ready then... ? 48 | Call SUB_IWM_35_SET_HEAD_LO_HI 49 | Select drive head (from $F2B, if 0 then lower, if bit 7 on, then upper.) 50 | Find address header on disk 51 | -------------------------------------------------------------------------------- /host/ext/fmt/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | namespace detail { 12 | 13 | template FMT_API auto dragonbox::to_decimal(float x) noexcept 14 | -> dragonbox::decimal_fp; 15 | template FMT_API auto dragonbox::to_decimal(double x) noexcept 16 | -> dragonbox::decimal_fp; 17 | 18 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 19 | template FMT_API locale_ref::locale_ref(const std::locale& loc); 20 | template FMT_API auto locale_ref::get() const -> std::locale; 21 | #endif 22 | 23 | // Explicit instantiations for char. 24 | 25 | template FMT_API auto thousands_sep_impl(locale_ref) 26 | -> thousands_sep_result; 27 | template FMT_API auto decimal_point_impl(locale_ref) -> char; 28 | 29 | template FMT_API void buffer::append(const char*, const char*); 30 | 31 | // DEPRECATED! 32 | // There is no correspondent extern template in format.h because of 33 | // incompatibility between clang and gcc (#2377). 34 | template FMT_API void vformat_to(buffer&, string_view, 35 | basic_format_args, 36 | locale_ref); 37 | 38 | // Explicit instantiations for wchar_t. 39 | 40 | template FMT_API auto thousands_sep_impl(locale_ref) 41 | -> thousands_sep_result; 42 | template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; 43 | 44 | template FMT_API void buffer::append(const wchar_t*, const wchar_t*); 45 | 46 | } // namespace detail 47 | FMT_END_NAMESPACE 48 | -------------------------------------------------------------------------------- /devices/slot7hdd_firmware.h: -------------------------------------------------------------------------------- 1 | unsigned char slot7hdd_firmware_bytes[] = { 2 | 0xa9, 0x20, 0xa9, 0x00, 0xa9, 0x03, 0xc9, 0x00, 0xb0, 0x09, 0x18, 0x90, 3 | 0x01, 0x38, 0x08, 0x68, 0x18, 0x49, 0x01, 0x29, 0x01, 0x8b, 0x4b, 0xab, 4 | 0x8d, 0x7f, 0x07, 0x08, 0xad, 0xf0, 0xc7, 0x8d, 0xf8, 0x07, 0x68, 0x8d, 5 | 0xff, 0x07, 0xb0, 0x05, 0xad, 0x7f, 0x07, 0x80, 0x0c, 0xa2, 0x05, 0xbd, 6 | 0xe6, 0xc7, 0x95, 0x42, 0xca, 0x10, 0xf8, 0xa9, 0x01, 0x78, 0xae, 0xf1, 7 | 0xc7, 0xc9, 0x01, 0xd0, 0x17, 0x9e, 0x80, 0xc0, 0xbd, 0x80, 0xc0, 0x30, 8 | 0xfb, 0xa0, 0x00, 0xb9, 0x42, 0x00, 0x9d, 0x81, 0xc0, 0xc8, 0xc0, 0x06, 9 | 0xd0, 0xf5, 0x80, 0x41, 0xa9, 0x01, 0x9d, 0x80, 0xc0, 0xbd, 0x80, 0xc0, 10 | 0x30, 0xfb, 0xa5, 0x42, 0x48, 0xa5, 0x43, 0x48, 0xa0, 0x01, 0xb3, 0x04, 11 | 0x9d, 0x81, 0xc0, 0xc8, 0xb3, 0x04, 0x85, 0x42, 0xc8, 0xb3, 0x04, 0x85, 12 | 0x43, 0xa0, 0x00, 0xb1, 0x42, 0x9d, 0x81, 0xc0, 0xc8, 0xbd, 0x80, 0xc0, 13 | 0x30, 0xf5, 0xa3, 0x04, 0x18, 0x69, 0x03, 0x83, 0x04, 0xa9, 0x00, 0x63, 14 | 0x05, 0x83, 0x05, 0x68, 0x85, 0x43, 0x68, 0x85, 0x42, 0xa9, 0x80, 0x9d, 15 | 0x80, 0xc0, 0xbd, 0x80, 0xc0, 0x30, 0xfb, 0xa8, 0xbd, 0x81, 0xc0, 0x48, 16 | 0xad, 0xff, 0x07, 0x29, 0x01, 0xd0, 0x16, 0x98, 0x6a, 0x9b, 0xb9, 0x82, 17 | 0xc0, 0xaa, 0xb9, 0x83, 0xc0, 0xa8, 0xad, 0xff, 0x07, 0x29, 0x04, 0xd0, 18 | 0x01, 0x58, 0x68, 0xab, 0x60, 0x98, 0x6a, 0x68, 0xab, 0x58, 0xb0, 0x0d, 19 | 0xad, 0x00, 0x08, 0xf0, 0x08, 0xf4, 0x00, 0x00, 0xab, 0xab, 0x4c, 0x01, 20 | 0x08, 0xa5, 0x01, 0xcd, 0xf8, 0x07, 0xd0, 0x03, 0x4c, 0xba, 0xfa, 0x4c, 21 | 0x00, 0xe0, 0x01, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 22 | 0xc7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x97, 0x0a 24 | }; 25 | unsigned int slot7hdd_firmware_bytes_len = 256; 26 | -------------------------------------------------------------------------------- /docs/references.txt: -------------------------------------------------------------------------------- 1 | Important Corrections: 2 | http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.030.html 3 | 4 | 6502/65816: 5 | http://nparker.llx.com/a2/opcodes.html 6 | http://archive.6502.org/datasheets/wdc_65816_programming_manual.pdf 7 | 8 | 9 | Interrupts: 10 | http://6502.org/tutorials/interrupts.html 11 | https://www.pagetable.com/?p=410 12 | https://apple2.org.za/gswv/a2zine/faqs/csa2pfaq.html#012 13 | (mouse interrupts, can be correlate behavior with C041, C046 as its likely 14 | these IO addressed are used by mouse firmware for IIe emulation) 15 | 16 | The "B" Flag 17 | http://visual6502.org/wiki/index.php?title=6502_BRK_and_B_bit 18 | 19 | ROM Chip Select Apple //c and FPI for //gs 20 | https://retrocomputing.stackexchange.com/questions/11044/why-does-the-apple-iigs-fpi-chip-buffer-the-a14-address-signal-to-the-rom 21 | 22 | 23 | A good ADB addendum documenation for information not in the HW or FW refs: 24 | https://developer.apple.com/library/archive/technotes/hw/hw_01.html 25 | 26 | 27 | Registers: 28 | 29 | $c029 - new video register: Page 89-90 - Apple IIgs Hardware Reference 30 | $c035 - shadow Register 31 | 32 | VBL and counters: 33 | http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.039.html 34 | 60hz vertical? 35 | 36 | 37 | HW Reference: 38 | 39 | p53 - ghosting banks (when running with 1MB vs 8MB RAM expansion) 40 | 41 | 42 | Build ROM: 43 | 44 | D:\Apps\6502Tools\64tass\64tass.exe --long-address --nostart --m65816 .\testrom.65816.asm -o data\testrom.rom 45 | 46 | 47 | Self Test 48 | http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.095.html 49 | 50 | ProDOS bootloader: 51 | http://mirrors.apple2.org.za/ftp.apple.asimov.net/documentation/source_code/Apple%20ProDOS%20Boot%20Source.pdf 52 | -------------------------------------------------------------------------------- /docs/Diagnostics.md: -------------------------------------------------------------------------------- 1 | ## References 2 | * [Official diagnostics document]( 3 | https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Computers/Apple%20II/Apple%20IIGS/Documentation/Apple%20IIGS%20Diagnostics.pdf) 4 | 5 | ## ROM 3 6 | 7 | ### Self Test 5 8 | 9 | ### 01 (Speed Slow Stuck) 10 | 11 | Ref: Page 11, Speed Section. 12 | 13 | Version 0.5 and lower fails. 14 | 15 | X should output either 19 or 1A to pass. 16 | X outputs 1E. Investigating VERTCNT and underlying implementation. 17 | 18 | Timing is everything - Mega2 access might not be "slow" enough here to extend the time of the loop. 19 | https://youtu.be/LP5k15g_0AM?t=2946 20 | 21 | ``` 22 | 11237664 | FF | 6AF1 | ( 2) LDX #$00 | PC=6AF3, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=80, X=00, Y=04, 00110111 23 | 11237665 | FF | 6AF3 | ( 5) LDA $00C02E | PC=6AF7, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=9F, X=00, Y=04, 10110101 24 | 11237722 | FF | 6AF7 | ( 5) CMP $00C02E | PC=6AFB, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=9F, X=00, Y=04, 10110100 25 | 11237723 | FF | 6AFB | ( 2) BEQ $FA (-6) | PC=6AFD, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=9F, X=00, Y=04, 10110100 26 | 11237724 | FF | 6AFD | ( 5) LDA $00C02E | PC=6B01, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=A0, X=00, Y=04, 10110100 27 | 11237812 | FF | 6B01 | ( 2) INX | PC=6B02, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=A0, X=1E, Y=04, 00110101 28 | 11237813 | FF | 6B02 | ( 5) CMP $00C02E | PC=6B06, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=A0, X=1E, Y=04, 10110100 29 | 11237814 | FF | 6B06 | ( 2) BEQ $F9 (-7) | PC=6B08, PBR=FF, DBR=00, S=01FA, D=0000, e=0, A=A0, X=1E, Y=04, 10110100 30 | 11237815 | FF | 6B08 | ( 6) RTS | PC=6ACF, PBR=FF, DBR=00, S=01FC, D=0000, e=0, A=A0, X=1E, Y=04, 10110100 31 | ``` 32 | 33 | Solution: 34 | 35 | -------------------------------------------------------------------------------- /app.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "emulator.h" 6 | #include "emulator_mmio.h" 7 | 8 | /** 9 | * The Apple //gs Clements Emulator 10 | * 11 | * CPU 12 | * Mega II emulation 13 | * Memory 14 | * ROM 15 | * RAM 16 | * I/O 17 | * IWM 18 | * ADB (keyboard + mouse) 19 | * Ports 1-7 20 | * Ensoniq 21 | * 22 | * Approach: 23 | * 24 | */ 25 | int main(int argc, char *argv[]) { 26 | ClemensMachine machine; 27 | ClemensMMIO mmio; 28 | 29 | /* ROM 3 only */ 30 | FILE *fp = fopen("gs_rom_3.rom", "rb"); 31 | // FILE* fp = fopen("testrom.rom", "rb"); 32 | void *rom = NULL; 33 | if (fp == NULL) { 34 | fprintf(stderr, "No ROM\n"); 35 | return 1; 36 | } 37 | rom = malloc(CLEM_IIGS_ROM3_SIZE); 38 | if (fread(rom, 1, CLEM_IIGS_ROM3_SIZE, fp) != CLEM_IIGS_ROM3_SIZE) { 39 | fprintf(stderr, "Bad ROM\n"); 40 | return 1; 41 | } 42 | fclose(fp); 43 | 44 | memset(&machine, 0, sizeof(machine)); 45 | memset(&mmio, 0, sizeof(mmio)); 46 | clemens_init(&machine, 1000, 1000, rom, CLEM_IIGS_ROM3_SIZE >> 16, malloc(CLEM_IIGS_BANK_SIZE), 47 | malloc(CLEM_IIGS_BANK_SIZE), malloc(CLEM_IIGS_BANK_SIZE * 16), 16); 48 | clem_mmio_init(&mmio, &machine.dev_debug, machine.mem.bank_page_map, malloc(2048 * 7), 16, 49 | CLEM_IIGS_ROM3_SIZE >> 16, machine.mem.mega2_bank_map[0], 50 | machine.mem.mega2_bank_map[1], &machine.tspec); 51 | 52 | machine.cpu.pins.resbIn = false; 53 | machine.resb_counter = 3; 54 | 55 | while (machine.cpu.cycles_spent < 1024) { 56 | clemens_emulate_cpu(&machine); 57 | clemens_emulate_mmio(&machine, &mmio); 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/base_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | // 6 | // base sink templated over a mutex (either dummy or real) 7 | // concrete implementation should override the sink_it_() and flush_() methods. 8 | // locking is taken care of in this class - no locking needed by the 9 | // implementers.. 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | template 19 | class SPDLOG_API base_sink : public sink 20 | { 21 | public: 22 | base_sink(); 23 | explicit base_sink(std::unique_ptr formatter); 24 | ~base_sink() override = default; 25 | 26 | base_sink(const base_sink &) = delete; 27 | base_sink(base_sink &&) = delete; 28 | 29 | base_sink &operator=(const base_sink &) = delete; 30 | base_sink &operator=(base_sink &&) = delete; 31 | 32 | void log(const details::log_msg &msg) final; 33 | void flush() final; 34 | void set_pattern(const std::string &pattern) final; 35 | void set_formatter(std::unique_ptr sink_formatter) final; 36 | 37 | protected: 38 | // sink formatter 39 | std::unique_ptr formatter_; 40 | Mutex mutex_; 41 | 42 | virtual void sink_it_(const details::log_msg &msg) = 0; 43 | virtual void flush_() = 0; 44 | virtual void set_pattern_(const std::string &pattern); 45 | virtual void set_formatter_(std::unique_ptr sink_formatter); 46 | }; 47 | } // namespace sinks 48 | } // namespace spdlog 49 | 50 | #ifdef SPDLOG_HEADER_ONLY 51 | # include "base_sink-inl.h" 52 | #endif 53 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/msvc_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2016 Alexander Dalshov & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | 7 | #if defined(_WIN32) 8 | 9 | # include 10 | # include 11 | 12 | # include 13 | # include 14 | 15 | // Avoid including windows.h (https://stackoverflow.com/a/30741042) 16 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); 17 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 18 | 19 | namespace spdlog { 20 | namespace sinks { 21 | /* 22 | * MSVC sink (logging using OutputDebugStringA) 23 | */ 24 | template 25 | class msvc_sink : public base_sink 26 | { 27 | public: 28 | msvc_sink() = default; 29 | msvc_sink(bool check_ebugger_present) 30 | : check_debbugger_present_{check_ebugger_present} {}; 31 | 32 | protected: 33 | void sink_it_(const details::log_msg &msg) override 34 | { 35 | if (check_debbugger_present_ && !IsDebuggerPresent()) 36 | { 37 | return; 38 | } 39 | memory_buf_t formatted; 40 | base_sink::formatter_->format(msg, formatted); 41 | formatted.push_back('\0'); // add a null terminator for OutputDebugStringA 42 | OutputDebugStringA(formatted.data()); 43 | } 44 | 45 | void flush_() override {} 46 | 47 | bool check_debbugger_present_ = true; 48 | }; 49 | 50 | using msvc_sink_mt = msvc_sink; 51 | using msvc_sink_st = msvc_sink; 52 | 53 | using windebug_sink_mt = msvc_sink_mt; 54 | using windebug_sink_st = msvc_sink_st; 55 | 56 | } // namespace sinks 57 | } // namespace spdlog 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /host/core/clem_apple2gs_config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_APPLE2GS_CONFIG_HPP 2 | #define CLEM_HOST_APPLE2GS_CONFIG_HPP 3 | 4 | #include "clem_disk_status.hpp" 5 | #include "clem_mmio_types.h" 6 | #include "clem_smartport.h" 7 | 8 | #include 9 | #include 10 | 11 | constexpr unsigned kClemensHardDiskLimit = 2; 12 | constexpr unsigned kClemensSmartPortDiskLimit = CLEM_SMARTPORT_DRIVE_LIMIT + kClemensHardDiskLimit; 13 | // arbitrary - unlikely to ever need more 14 | constexpr unsigned kClemensCardLimitPerSlot = 8; 15 | 16 | constexpr const char *kClemensCardMockingboardName = "mockingboard_c"; 17 | constexpr const char *kClemensCardHardDiskName = "hddcard"; 18 | 19 | std::array getCardNamesForSlot(unsigned slotIndex); 20 | 21 | struct ClemensAppleIIGSConfig { 22 | // RAM in Kilobytes, not counting Mega 2 memory 23 | unsigned memory = 0; 24 | // Usually 48000 or equivalent to the target mix rate 25 | unsigned audioSamplesPerSecond = 0; 26 | // Baterry RAM as laid out on the IIGS 27 | std::array bram; 28 | // Drive images (can be empty) 29 | std::array diskImagePaths; 30 | std::array smartPortImagePaths; 31 | // Card namaes 32 | std::array cardNames; 33 | }; 34 | 35 | struct ClemensAppleIIGSFrame { 36 | ClemensMonitor monitor; 37 | ClemensVideo graphics; 38 | ClemensVideo text; 39 | ClemensAudio audio; 40 | std::array diskDriveStatuses; 41 | std::array smartPortStatuses; 42 | ClemensAppleIIGSFrame() : monitor{}, graphics{}, text{}, audio{} {} 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/stdout_color_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | # include 8 | #else 9 | # include 10 | #endif 11 | 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | #ifdef _WIN32 17 | using stdout_color_sink_mt = wincolor_stdout_sink_mt; 18 | using stdout_color_sink_st = wincolor_stdout_sink_st; 19 | using stderr_color_sink_mt = wincolor_stderr_sink_mt; 20 | using stderr_color_sink_st = wincolor_stderr_sink_st; 21 | #else 22 | using stdout_color_sink_mt = ansicolor_stdout_sink_mt; 23 | using stdout_color_sink_st = ansicolor_stdout_sink_st; 24 | using stderr_color_sink_mt = ansicolor_stderr_sink_mt; 25 | using stderr_color_sink_st = ansicolor_stderr_sink_st; 26 | #endif 27 | } // namespace sinks 28 | 29 | template 30 | std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); 31 | 32 | template 33 | std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); 34 | 35 | template 36 | std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); 37 | 38 | template 39 | std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); 40 | 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | # include "stdout_color_sinks-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /host/core/clem_snapshot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_SERIALIZER_HPP 2 | #define CLEM_HOST_SERIALIZER_HPP 3 | 4 | #include "clem_apple2gs_config.hpp" 5 | #include "external/mpack.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | class ClemensAppleIIGS; 16 | class ClemensSystemListener; 17 | 18 | struct ClemensSnapshotMetadata { 19 | time_t timestamp; 20 | std::array disks; 21 | std::array smartDisks; 22 | std::vector imageData; // png 23 | }; 24 | 25 | struct ClemensSnapshotPNG { 26 | const unsigned char* data; 27 | size_t size; 28 | }; 29 | 30 | class ClemensSnapshot { 31 | public: 32 | static constexpr uint32_t kClemensSnapshotVersion = 1; 33 | 34 | ClemensSnapshot(const std::string &path); 35 | 36 | bool serialize(ClemensAppleIIGS &gs, const ClemensSnapshotPNG& image, 37 | std::function customCb); 38 | std::unique_ptr 39 | unserialize(ClemensSystemListener &listener, 40 | std::function customCb); 41 | 42 | std::pair unserializeMetadata(); 43 | 44 | private: 45 | bool unserializeHeader(FILE *fp); 46 | std::pair unserializeMetadata(mpack_reader_t &reader); 47 | 48 | private: 49 | std::string path_; 50 | std::string origin_; 51 | enum class ValidationStep { None, Header, Metadata, Machine, Custom }; 52 | ValidationStep validationStep_; 53 | std::string validationData_; 54 | 55 | void validation(ValidationStep step); 56 | void validationError(const std::string &tag); 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /host/fonts/FreeLicense.txt: -------------------------------------------------------------------------------- 1 | KREATIVE SOFTWARE RELAY FONTS FREE USE LICENSE 2 | version 1.2f 3 | 4 | Permission is hereby granted, free of charge, to any person or entity (the "User") obtaining a copy of the included font files (the "Software") produced by Kreative Software, to utilize, display, embed, or redistribute the Software, subject to the following conditions: 5 | 6 | 1. The User may not sell copies of the Software for a fee. 7 | 8 | 1a. The User may give away copies of the Software free of charge provided this license and any documentation is included verbatim and credit is given to Kreative Korporation or Kreative Software. 9 | 10 | 2. The User may not modify, reverse-engineer, or create any derivative works of the Software. 11 | 12 | 3. Any Software carrying the following font names or variations thereof is not covered by this license and may not be used under the terms of this license: Jewel Hill, Miss Diode n Friends, This is Beckie's font! 13 | 14 | 3a. Any Software carrying a font name ending with the string "Pro CE" is not covered by this license and may not be used under the terms of this license. 15 | 16 | 4. This license becomes null and void if any of the above conditions are not met. 17 | 18 | 5. Kreative Software reserves the right to change this license at any time without notice. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE SOFTWARE OR FROM OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /host/images/eject_png.h: -------------------------------------------------------------------------------- 1 | unsigned char eject_png[] = { 2 | 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 3 | 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 4 | 0xf4, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 5 | 0x00, 0xd1, 0x49, 0x44, 0x41, 0x54, 0x58, 0x85, 0xed, 0x96, 0x31, 0x0e, 0xc2, 0x30, 0x0c, 0x45, 6 | 0xbf, 0xa3, 0x4a, 0xdc, 0x93, 0x03, 0x71, 0x03, 0xd6, 0x9e, 0x8e, 0x95, 0x81, 0xc9, 0x0c, 0x08, 7 | 0x29, 0x82, 0x34, 0xb1, 0x1d, 0x97, 0xdf, 0x01, 0x4f, 0x69, 0x94, 0xfe, 0xff, 0x14, 0x27, 0x8e, 8 | 0x45, 0x55, 0x31, 0x19, 0x0f, 0x00, 0xa7, 0xe8, 0xcf, 0xcb, 0x84, 0xb1, 0x36, 0xc6, 0xe2, 0x15, 9 | 0x29, 0x09, 0xe6, 0x96, 0xf9, 0x54, 0x80, 0x91, 0x89, 0x0b, 0xc2, 0x0b, 0x60, 0x15, 0x37, 0x43, 10 | 0x78, 0x00, 0xbc, 0xdb, 0x6b, 0x5a, 0x6f, 0x05, 0x88, 0x5e, 0x95, 0xcb, 0x68, 0x81, 0x18, 0xae, 11 | 0xe1, 0x19, 0xc0, 0x35, 0x08, 0x00, 0x0c, 0x6e, 0x86, 0x05, 0x60, 0xba, 0x50, 0xf4, 0x20, 0x46, 12 | 0x29, 0xc8, 0x30, 0xef, 0xea, 0xf4, 0x00, 0xb2, 0xcc, 0xbb, 0x7a, 0x5b, 0x00, 0xd9, 0xe6, 0x9b, 13 | 0xba, 0x2d, 0x80, 0xbd, 0xcc, 0x9b, 0xfa, 0x9f, 0x00, 0x7b, 0x9b, 0x7f, 0xf9, 0x94, 0xd6, 0xe4, 14 | 0x2f, 0x21, 0x4a, 0xfd, 0x41, 0x08, 0x8d, 0xbe, 0x86, 0x69, 0x51, 0x00, 0xdc, 0x99, 0x00, 0xef, 15 | 0x4a, 0xc8, 0x4a, 0x41, 0xb8, 0x21, 0x49, 0x07, 0x70, 0xb7, 0x52, 0x49, 0x21, 0x75, 0x4f, 0x48, 16 | 0x81, 0xa0, 0xa7, 0xa0, 0xde, 0x01, 0xc6, 0x41, 0x94, 0x43, 0x14, 0xa2, 0x1b, 0xc9, 0x1c, 0xc0, 17 | 0xab, 0x0e, 0xd0, 0x6a, 0x00, 0x70, 0x80, 0x43, 0xf8, 0x07, 0x28, 0x00, 0x56, 0x26, 0x00, 0xfd, 18 | 0x31, 0x7a, 0x02, 0x5f, 0xd9, 0x37, 0x2a, 0x9c, 0x0b, 0xf4, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x49, 19 | 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82}; 20 | unsigned int eject_png_len = 279; 21 | -------------------------------------------------------------------------------- /docs/Mockingboard.md: -------------------------------------------------------------------------------- 1 | # Mockingboard 2 | 3 | ## Milestones 4 | 5 | * Reference Null Implementation 6 | * Detection Code 7 | 8 | ## Architecture 9 | 10 | ### Use the external card slot system 11 | 12 | See `ClemensCard` inside `clem_types.h`. Like all card devices, the interface 13 | uses the memory I/O and sync pattern common to other Clemens MMIO subsystems. 14 | 15 | ### General Mockingboard Technical 16 | 17 | * The PSG (Programmable Sound Generator) has three tone oscillators 18 | * Accessible via channels A, B, C 19 | * NG (Noise Generator) 20 | * It's a AY-3-8910 chip 21 | * The target Mockingboard will be a 2 PSG device 22 | * There is one output per PSG/6522 23 | * There are two outputs to the Mockingboard 24 | * From the Apple II ($C400/$C480) MMIO access 25 | * Sends commands to a 6522 that then directs commands to the PSG 26 | * These registers map to 6522 registers 27 | * ORA 28 | * ORB 29 | * DDRA 30 | * DDRB 31 | * 6522 specific operations should also be supported 32 | * RS0-RS3 allow access to the above registers plus some additional 6522 33 | specific functions 34 | * Interrupts 35 | 36 | 37 | ### Clemens Integration 38 | 39 | * io_sync Execution of synth loop occurs and IRQ simulation 40 | * io_write will apply output to the synth engine 41 | * io_read ??? 42 | 43 | 44 | ### Host Integration 45 | 46 | See `iocards/mockingboard.c` for the full implementation. 47 | 48 | #### Investigation TODOs 49 | 50 | * Figure out how frequency synth changes occur - likely on a clock that won't 51 | sync with the emulator's framerate 52 | * Since we don't want to lose synth updates between emulator frames before the 53 | host audio system requests data for playback, we'll need to render audio 54 | on the fly 55 | * The Mockingboard interface queues commands and executes them when the host 56 | or emulated Clemens machine needs to access the current state 57 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/log_msg_buffer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) 14 | : log_msg{orig_msg} 15 | { 16 | buffer.append(logger_name.begin(), logger_name.end()); 17 | buffer.append(payload.begin(), payload.end()); 18 | update_string_views(); 19 | } 20 | 21 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) 22 | : log_msg{other} 23 | { 24 | buffer.append(logger_name.begin(), logger_name.end()); 25 | buffer.append(payload.begin(), payload.end()); 26 | update_string_views(); 27 | } 28 | 29 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} 30 | { 31 | update_string_views(); 32 | } 33 | 34 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) 35 | { 36 | log_msg::operator=(other); 37 | buffer.clear(); 38 | buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); 39 | update_string_views(); 40 | return *this; 41 | } 42 | 43 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT 44 | { 45 | log_msg::operator=(other); 46 | buffer = std::move(other.buffer); 47 | update_string_views(); 48 | return *this; 49 | } 50 | 51 | SPDLOG_INLINE void log_msg_buffer::update_string_views() 52 | { 53 | logger_name = string_view_t{buffer.data(), logger_name.size()}; 54 | payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; 55 | } 56 | 57 | } // namespace details 58 | } // namespace spdlog 59 | -------------------------------------------------------------------------------- /host/core/clem_prodos_disk.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_PRODOS_DISK_HPP 2 | #define CLEM_HOST_PRODOS_DISK_HPP 3 | 4 | #include "cinek/buffer.hpp" 5 | #include "clem_shared.h" 6 | #include "core/clem_disk_asset.hpp" 7 | #include "devices/prodos_hdd32.h" 8 | 9 | #include "clem_2img.h" 10 | 11 | #include 12 | 13 | // forward declarations 14 | typedef struct mpack_reader_t mpack_reader_t; 15 | typedef struct mpack_writer_t mpack_writer_t; 16 | 17 | struct ClemensDiskAsset; 18 | 19 | struct ClemensUnserializerContext { 20 | ClemensSerializerAllocateCb allocCb; 21 | void *allocUserPtr; 22 | }; 23 | 24 | // A wrapper for tbe emulator type ClemensProdosHDD32 25 | // And 26 | class ClemensProDOSDisk { 27 | public: 28 | ClemensProDOSDisk(); 29 | ClemensProDOSDisk(cinek::ByteBuffer backingBuffer); 30 | 31 | bool bind(ClemensSmartPortDevice &device, const ClemensDiskAsset &asset); 32 | bool save(); 33 | void release(ClemensSmartPortDevice &device); 34 | 35 | bool serialize(mpack_writer_t *writer, ClemensSmartPortDevice &device); 36 | bool unserialize(mpack_reader_t *reader, ClemensSmartPortDevice &device, 37 | ClemensUnserializerContext context); 38 | 39 | // direct access to the HDD for use by the card interface if needed 40 | ClemensProdosHDD32& getInterface() { return interface_; } 41 | 42 | private: 43 | static uint8_t doReadBlock(void *userContext, unsigned driveIndex, unsigned blockIndex, 44 | uint8_t *buffer); 45 | 46 | static uint8_t doWriteBlock(void *userContext, unsigned driveIndex, unsigned blockIndex, 47 | const uint8_t *buffer); 48 | static uint8_t doFlush(void *userContext, unsigned driveIndex); 49 | 50 | cinek::ByteBuffer storage_; 51 | cinek::Range blocks_; 52 | ClemensProdosHDD32 interface_; 53 | 54 | std::string assetPath_; 55 | Clemens2IMGDisk disk_; 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /devices/clem_peer.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_PERIPHERAL_PEER_DEVICE_H 2 | #define CLEM_PERIPHERAL_PEER_DEVICE_H 3 | 4 | #include "clem_shared.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define CLEM_PERI_PEER_QUEUE_SIZE 16 11 | 12 | /** 13 | * @brief Defines a peer for serial operations that can be built upon for devices 14 | * 15 | * The clocks timing is based on the relative clocks defined in clem_shared.h. 16 | * For serial operations to work, both the peer and the emulator needs to run 17 | * at the same clock rate. 18 | */ 19 | typedef struct { 20 | /* time of last call to transact */ 21 | clem_clocks_time_t last_transact_time; 22 | /* number of clocks until the next bit is sent or read */ 23 | clem_clocks_duration_t baud_gen_clocks_dt; 24 | clem_clocks_duration_t leftover_baud_gen_clocks_dt; 25 | 26 | uint8_t send_queue[CLEM_PERI_PEER_QUEUE_SIZE]; 27 | int send_queue_head; 28 | int send_queue_tail; 29 | uint8_t recv_queue[CLEM_PERI_PEER_QUEUE_SIZE]; 30 | int recv_queue_head; 31 | int recv_queue_tail; 32 | 33 | unsigned xmit_shift_reg; 34 | unsigned recv_shift_reg; 35 | } ClemensSerialPeer; 36 | 37 | void clem_serial_peer_init(ClemensSerialPeer *peer, struct ClemensClock *clock); 38 | 39 | void clem_serial_peer_set_baud_rate(ClemensSerialPeer *peer, enum ClemensSerialBaudRate baud_rate); 40 | 41 | // queues bytes 42 | unsigned clem_serial_peer_send_bytes(ClemensSerialPeer *peer, const uint8_t *bytes, 43 | unsigned byte_cnt); 44 | 45 | // returns the number of bytes received in the supplied bytes buffer (0 if none) 46 | unsigned clem_serial_peer_recv_byte(ClemensSerialPeer* peer, uint8_t* bytes, unsigned bytes_limit); 47 | 48 | void clem_serial_peer_transact(ClemensSerialPeer *peer, struct ClemensClock *clock, 49 | unsigned *serial_port); 50 | 51 | // TODO: serialization and unserialization 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/file_helper.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | // Helper class for file sinks. 13 | // When failing to open a file, retry several times(5) with a delay interval(10 ms). 14 | // Throw spdlog_ex exception on errors. 15 | 16 | class SPDLOG_API file_helper 17 | { 18 | public: 19 | file_helper() = default; 20 | explicit file_helper(const file_event_handlers &event_handlers); 21 | 22 | file_helper(const file_helper &) = delete; 23 | file_helper &operator=(const file_helper &) = delete; 24 | ~file_helper(); 25 | 26 | void open(const filename_t &fname, bool truncate = false); 27 | void reopen(bool truncate); 28 | void flush(); 29 | void close(); 30 | void write(const memory_buf_t &buf); 31 | size_t size() const; 32 | const filename_t &filename() const; 33 | 34 | // 35 | // return file path and its extension: 36 | // 37 | // "mylog.txt" => ("mylog", ".txt") 38 | // "mylog" => ("mylog", "") 39 | // "mylog." => ("mylog.", "") 40 | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") 41 | // 42 | // the starting dot in filenames is ignored (hidden files): 43 | // 44 | // ".mylog" => (".mylog". "") 45 | // "my_folder/.mylog" => ("my_folder/.mylog", "") 46 | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") 47 | static std::tuple split_by_extension(const filename_t &fname); 48 | 49 | private: 50 | const int open_tries_ = 5; 51 | const unsigned int open_interval_ = 10; 52 | std::FILE *fd_{nullptr}; 53 | filename_t filename_; 54 | file_event_handlers event_handlers_; 55 | }; 56 | } // namespace details 57 | } // namespace spdlog 58 | 59 | #ifdef SPDLOG_HEADER_ONLY 60 | # include "file_helper-inl.h" 61 | #endif 62 | -------------------------------------------------------------------------------- /host/ext/spdlog/stopwatch.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | // Stopwatch support for spdlog (using std::chrono::steady_clock). 10 | // Displays elapsed seconds since construction as double. 11 | // 12 | // Usage: 13 | // 14 | // spdlog::stopwatch sw; 15 | // ... 16 | // spdlog::debug("Elapsed: {} seconds", sw); => "Elapsed 0.005116733 seconds" 17 | // spdlog::info("Elapsed: {:.6} seconds", sw); => "Elapsed 0.005163 seconds" 18 | // 19 | // 20 | // If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use "duration_cast<..>(sw.elapsed())": 21 | // 22 | // #include 23 | //.. 24 | // using std::chrono::duration_cast; 25 | // using std::chrono::milliseconds; 26 | // spdlog::info("Elapsed {}", duration_cast(sw.elapsed())); => "Elapsed 5ms" 27 | 28 | namespace spdlog { 29 | class stopwatch 30 | { 31 | using clock = std::chrono::steady_clock; 32 | std::chrono::time_point start_tp_; 33 | 34 | public: 35 | stopwatch() 36 | : start_tp_{clock::now()} 37 | {} 38 | 39 | std::chrono::duration elapsed() const 40 | { 41 | return std::chrono::duration(clock::now() - start_tp_); 42 | } 43 | 44 | void reset() 45 | { 46 | start_tp_ = clock::now(); 47 | } 48 | }; 49 | } // namespace spdlog 50 | 51 | // Support for fmt formatting (e.g. "{:012.9}" or just "{}") 52 | namespace 53 | #ifdef SPDLOG_USE_STD_FORMAT 54 | std 55 | #else 56 | fmt 57 | #endif 58 | { 59 | 60 | template<> 61 | struct formatter : formatter 62 | { 63 | template 64 | auto format(const spdlog::stopwatch &sw, FormatContext &ctx) -> decltype(ctx.out()) 65 | { 66 | return formatter::format(sw.elapsed().count(), ctx); 67 | } 68 | }; 69 | } // namespace std 70 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/periodic_worker.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // periodic worker thread - periodically executes the given callback function. 7 | // 8 | // RAII over the owned thread: 9 | // creates the thread on construction. 10 | // stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first). 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | namespace spdlog { 18 | namespace details { 19 | 20 | class SPDLOG_API periodic_worker 21 | { 22 | public: 23 | template 24 | periodic_worker(const std::function &callback_fun, std::chrono::duration interval) 25 | { 26 | active_ = (interval > std::chrono::duration::zero()); 27 | if (!active_) 28 | { 29 | return; 30 | } 31 | 32 | worker_thread_ = std::thread([this, callback_fun, interval]() { 33 | for (;;) 34 | { 35 | std::unique_lock lock(this->mutex_); 36 | if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) 37 | { 38 | return; // active_ == false, so exit this thread 39 | } 40 | callback_fun(); 41 | } 42 | }); 43 | } 44 | periodic_worker(const periodic_worker &) = delete; 45 | periodic_worker &operator=(const periodic_worker &) = delete; 46 | // stop the worker thread and join it 47 | ~periodic_worker(); 48 | 49 | private: 50 | bool active_; 51 | std::thread worker_thread_; 52 | std::mutex mutex_; 53 | std::condition_variable cv_; 54 | }; 55 | } // namespace details 56 | } // namespace spdlog 57 | 58 | #ifdef SPDLOG_HEADER_ONLY 59 | # include "periodic_worker-inl.h" 60 | #endif 61 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/base_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | template 16 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() 17 | : formatter_{details::make_unique()} 18 | {} 19 | 20 | template 21 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink(std::unique_ptr formatter) 22 | : formatter_{std::move(formatter)} 23 | {} 24 | 25 | template 26 | void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) 27 | { 28 | std::lock_guard lock(mutex_); 29 | sink_it_(msg); 30 | } 31 | 32 | template 33 | void SPDLOG_INLINE spdlog::sinks::base_sink::flush() 34 | { 35 | std::lock_guard lock(mutex_); 36 | flush_(); 37 | } 38 | 39 | template 40 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) 41 | { 42 | std::lock_guard lock(mutex_); 43 | set_pattern_(pattern); 44 | } 45 | 46 | template 47 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) 48 | { 49 | std::lock_guard lock(mutex_); 50 | set_formatter_(std::move(sink_formatter)); 51 | } 52 | 53 | template 54 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) 55 | { 56 | set_formatter_(details::make_unique(pattern)); 57 | } 58 | 59 | template 60 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) 61 | { 62 | formatter_ = std::move(sink_formatter); 63 | } 64 | -------------------------------------------------------------------------------- /host/strings/clem_help.inl: -------------------------------------------------------------------------------- 1 | 2 | const char *kEmulatorHelp[] = {R"md( 3 | # Clemens IIGS 4 | 5 | Clemens IIGS is a cross-platform Apple IIGS emulator for both casual use and development of Apple IIGS software. 6 | 7 | Below are a list of key IIGS features supported by this emulator, followed by a list of missing features. 8 | 9 | First time users will be prompted to set a location where the emulator will store its data. Also users will be prompted to locate a ROM (version 3 only as of this writing) that will be copied to the directory specified in the last step. 10 | 11 | ## Key Features 12 | 13 | * ROM 3 supported 14 | * All Apple IIGS modes including 3200 color (experimental) 15 | * All Apple II graphics modes 16 | * Ensoniq and Mockingboard (Slot 4) audio 17 | * Joystick 18 | * Save/Load snapshots 19 | * Most disk image formats (.2mg, .woz, .po, .do, .dsk, .hdv) 20 | 21 | ## Missing Features 22 | 23 | * ROM 1 support 24 | * Host desktop mouse integration 25 | * Serial (SCC) communications 26 | * Monochrome display 27 | * Uthernet 28 | )md"}; 29 | 30 | const char *kDiskSelectionHelp[] = {R"md( 31 | ## Disk Selection 32 | 33 | The disk tray resides on the top left most section of the interface. 34 | 35 | Each widget represents a physical disk slot. 36 | 37 | * **s5d1** and **s5d2** disks were 800K 3.5" disk images used to distribute most Apple IIgs titles 38 | * **s6d1** and **s6d2** disks were 140K 5.25" disk images used to legacy Apple II titles 39 | * **s7d1** and **s7d2** are disks that can support up to 32MB hard drive images 40 | 41 | All disk widgets have eject buttons. Currently s7d1 and s7d2 do not support write protection. 42 | 43 | )md"}; 44 | 45 | const char *kDebuggerHelp[] = {R"md( 46 | ## Debugger Help 47 | 48 | To enter the debugger from user mode (the default, minimal interface) see the Hotkeys tab for the key combination. 49 | 50 | From user mode you can also enter debugger mode by pressing the bug icon on the lower left of the screen. 51 | 52 | Once in debugger mode, type 'help' in the terminal to display a full list of available commands. 53 | )md"}; 54 | -------------------------------------------------------------------------------- /host/clem_program_trace.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_PROGRAM_TRACE_HPP 2 | #define CLEM_HOST_PROGRAM_TRACE_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "clem_host_utils.hpp" 11 | 12 | class ClemensProgramTrace { 13 | public: 14 | ClemensProgramTrace(); 15 | 16 | void enableToolboxLogging(bool enable); 17 | void enableIWMLogging(bool enable); 18 | 19 | bool isToolboxLoggingEnabled() const { return enableToolboxLogging_; } 20 | bool isIWMLoggingEnabled() const { return enableIWMLogging_; } 21 | 22 | ClemensTraceExecutedInstruction &addExecutedInstruction(uint64_t seq, 23 | const ClemensInstruction &instruction, 24 | const char *operand, 25 | const ClemensMachine &machineState); 26 | 27 | void reset(); 28 | 29 | bool exportTrace(const char *filename); 30 | 31 | private: 32 | // | :: | Opcode Operand 33 | struct Action { 34 | uint32_t prev; 35 | uint32_t next; 36 | uint64_t seq; 37 | ClemensTraceExecutedInstruction inst; 38 | ClemensCPURegs regs; 39 | bool emulation; 40 | }; 41 | 42 | uint32_t actionAnchor_; 43 | uint32_t actionCurrent_; 44 | std::vector actions_; 45 | std::vector freeActionIndices_; 46 | 47 | struct Toolbox { 48 | uint16_t call; 49 | uint16_t pc; 50 | uint8_t pbr; 51 | }; 52 | std::vector toolboxCalls_; 53 | 54 | struct MemoryOperation { 55 | uint64_t seq; 56 | char opname[4]; 57 | uint16_t pc; 58 | uint16_t adr; 59 | uint8_t pbr; 60 | uint8_t dbr; 61 | uint8_t value; // this could be parts of a 16-bit value 62 | }; 63 | std::vector memoryOps_; 64 | 65 | bool enableToolboxLogging_; 66 | bool enableIWMLogging_; 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /docs/ROM3_Reset.md: -------------------------------------------------------------------------------- 1 | 2 | # The RESET sequence for the Apple IIgs 3 | 4 | 1. Set address bit 17 to point to bank 01 using Bit 0 of NEWVIDEO (seems to be 5 | always true, so this is just to assert this is the case on the hardware) 6 | 2. Reset the stack pointer to $01FB 7 | 3. Invoke a subroutine to perform some (likely?) cold-boot first-time 8 | initialization 9 | 10 | ## RESET Internal Subroutine (SUB_RESET_INTERNAL) 11 | 12 | 1. Set up some ENTRY points for toolbox-like calls made by the monitor firmware 13 | 1. E1V_FF7629 14 | 2. E1V_FFA9AA 15 | 2. Invokes a ENT_FWR_7629_TOOLBOX ($A3) 16 | 1. Ensures Native Mode + Fast Speed + 8-bit registers 17 | 2. Invokes API_FWR_7629_TOOLBOX which runs in native mode 18 | 19 | ## BRAM Storage 20 | 21 | https://www.techtalkz.com/threads/any-raw-data-specs-for-the-apple-iigs-bram.189163/page-2#post-794483 22 | 23 | According to Michael Fischer on page 74 of "Apple IIgs Technical 24 | Reference" (Osborne McGraw Hill ISBN 0-07-881009-4): 25 | 26 | "The values in the BatteryRAM are also stored, on a system startup, in 27 | a buffer at $E1/02C0-03BF. When the Control Panel is called, it 28 | ensures that the current BatteryRAM values are placed in the buffer. 29 | Changes made by the user in the Control Panel are made to the values 30 | in the buffer. When you quit the Control Panel, the changes are stored 31 | in the BatteryRAM." 32 | 33 | ### API_FWR_7629_TOOLBOX 34 | 35 | This is used by the Monitor firmware as well. Y = {Function} 36 | 37 | #### Function $A3 38 | 39 | 1. Likely BRAM validation check on boot 40 | 2. RAM storage in $E1 $2C0-$3BF : BRAM and 32-bit checksum at end 41 | 42 | ## ADB Sync 43 | 44 | 1. Sets modes to all $00 (assuming default BRAM parameters.) 45 | 2. First ADB call to the system 46 | 47 | ## Self vs Burn-in Diagnostixs Check 48 | 49 | 1. $C046 polled here with $C061/$C062 on boot uses the 'DIAGTYPE' definition 50 | 2. If $C061/BTN0 or $C062/BTN1 do self or burn-in diagnostics 51 | 3. 52 | 53 | 54 | # ProDOS firmware 55 | 56 | - SUB_FWR_PRODOS_SECTOR_READ 57 | - looks for a matching sector header 58 | - -------------------------------------------------------------------------------- /flatpak/com.cinekine.Clemens.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.cinekine.Clemens 4 | 5 | Clemens 6 | An Apple IIgs Emulator and Debugger written in C/C++ for Windows and Linux. 7 | Samir Sinha 8 | samir@cinekine.com 9 | 10 | MIT 11 | MIT 12 | 13 | https://github.com/samkusin/clemens_iigs 14 | https://github.com/samkusin/clemens_iigs/wiki 15 | 16 | 17 |

18 | The Clemens IIgs emulator is an attempt at writing a modern emulator 19 | for the Apple IIgs machine. Its design focuses on developers versus 20 | casual play, providing tools to debug IIgs applications at runtime. 21 | My eventual goal is to provide a solid Apple IIgs backend and debugger 22 | with a functional frontend. 23 |

24 |
25 | 26 | com.cinekine.Clemens.desktop 27 | 28 | 29 | 30 | https://camo.githubusercontent.com/643069cb14ad6cbdc3d5523f3fb4139dd43d9cd6b75812c13131093f5491a95a/68747470733a2f2f73616d697273696e68612e636f6d2f696d616765732f7a616e795f736d616c6c2e676966 31 | 32 | 33 | https://camo.githubusercontent.com/6c586093f5b6a3fdca70cec494c96f559c05ca9a583d3b76133d9357b53d7d4a/68747470733a2f2f73616d697273696e68612e636f6d2f696d616765732f646f74632d7469746c652e676966 34 | 35 | 36 | 37 | 38 | 39 | 40 |

Initial Flatpak for testing.

41 |
42 |
43 |
44 | 45 |
46 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/basic_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | /* 17 | * Trivial file sink with single file as target 18 | */ 19 | template 20 | class basic_file_sink final : public base_sink 21 | { 22 | public: 23 | explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}); 24 | const filename_t &filename() const; 25 | 26 | protected: 27 | void sink_it_(const details::log_msg &msg) override; 28 | void flush_() override; 29 | 30 | private: 31 | details::file_helper file_helper_; 32 | }; 33 | 34 | using basic_file_sink_mt = basic_file_sink; 35 | using basic_file_sink_st = basic_file_sink; 36 | 37 | } // namespace sinks 38 | 39 | // 40 | // factory functions 41 | // 42 | template 43 | inline std::shared_ptr basic_logger_mt( 44 | const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) 45 | { 46 | return Factory::template create(logger_name, filename, truncate, event_handlers); 47 | } 48 | 49 | template 50 | inline std::shared_ptr basic_logger_st( 51 | const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) 52 | { 53 | return Factory::template create(logger_name, filename, truncate, event_handlers); 54 | } 55 | 56 | } // namespace spdlog 57 | 58 | #ifdef SPDLOG_HEADER_ONLY 59 | # include "basic_file_sink-inl.h" 60 | #endif 61 | -------------------------------------------------------------------------------- /tests/test_scc.c: -------------------------------------------------------------------------------- 1 | #include "clem_mmio_types.h" 2 | #include "clem_scc.h" 3 | #include "emulator.h" 4 | #include "unity.h" 5 | 6 | #include "clem_device.h" 7 | #include "clem_mmio_defs.h" 8 | 9 | #include 10 | #include 11 | 12 | static struct ClemensDeviceSCC scc_dev; 13 | 14 | void setUp(void) { 15 | memset(&scc_dev, 0, sizeof(scc_dev)); 16 | // clem_scc_reset(&scc_dev); 17 | } 18 | 19 | void tearDown(void) {} 20 | 21 | void test_scc_reset(void) {} 22 | 23 | void test_scc_transmit_sync(void) {} 24 | 25 | void test_scc_tdd_null_modem(void) { 26 | /* An attempt at a simple null-modem connection between the 'test' and 27 | the SCC to iterate on the initial functionality. RTS/CTS/Tx/Rx 28 | functionality will be tested 29 | 30 | Send bytes from the test bit generator to the SCC 31 | Send bytes from the SCC to the test bit generator 32 | 33 | DTE/SCC PORT DCE/Peer 34 | ============================================================ 35 | 1. Peer -> SCC tranmission 36 | RTS TX_D_HI ---------------------> CTS 37 | RxD RX_D_LO <--------------------- TxD 38 | . . 39 | . . 40 | 41 | 42 | CTS HSKI <------------------ RTS 43 | DTR DTR ---------------------> CD 44 | DCD GPI <--------------------- DTR 45 | */ 46 | 47 | // mini_db8 = 0 48 | // db9 = 0 49 | // clem_comms_peer_init(&serial_peer); 50 | // clem_comms_peer_queue_send_text(&serial_peer, "Hello World"); 51 | // while clem_comms_peer_can_send(&serial_peer): 52 | // db9 = clem_comms_peer_communicate(&serial_peer, mini_db8_to_db9(mini_db8)) 53 | // mini_db8 = clem_scc_serial_communicate(&scc, db9_to_mini_db8(db9)) 54 | } 55 | 56 | int main(void) { 57 | UNITY_BEGIN(); 58 | RUN_TEST(test_scc_reset); 59 | RUN_TEST(test_scc_transmit_sync); 60 | RUN_TEST(test_scc_tdd_null_modem); 61 | return UNITY_END(); 62 | } 63 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/udp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | # include 11 | #else 12 | # include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // Simple udp client sink 21 | // Sends formatted log via udp 22 | 23 | namespace spdlog { 24 | namespace sinks { 25 | 26 | struct udp_sink_config 27 | { 28 | std::string server_host; 29 | uint16_t server_port; 30 | 31 | udp_sink_config(std::string host, uint16_t port) 32 | : server_host{std::move(host)} 33 | , server_port{port} 34 | {} 35 | }; 36 | 37 | template 38 | class udp_sink : public spdlog::sinks::base_sink 39 | { 40 | public: 41 | // host can be hostname or ip address 42 | explicit udp_sink(udp_sink_config sink_config) 43 | : client_{sink_config.server_host, sink_config.server_port} 44 | {} 45 | 46 | ~udp_sink() override = default; 47 | 48 | protected: 49 | void sink_it_(const spdlog::details::log_msg &msg) override 50 | { 51 | spdlog::memory_buf_t formatted; 52 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 53 | client_.send(formatted.data(), formatted.size()); 54 | } 55 | 56 | void flush_() override {} 57 | details::udp_client client_; 58 | }; 59 | 60 | using udp_sink_mt = udp_sink; 61 | using udp_sink_st = udp_sink; 62 | 63 | } // namespace sinks 64 | 65 | // 66 | // factory functions 67 | // 68 | template 69 | inline std::shared_ptr udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) 70 | { 71 | return Factory::template create(logger_name, skin_config); 72 | } 73 | 74 | } // namespace spdlog 75 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/backtracer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | namespace spdlog { 10 | namespace details { 11 | SPDLOG_INLINE backtracer::backtracer(const backtracer &other) 12 | { 13 | std::lock_guard lock(other.mutex_); 14 | enabled_ = other.enabled(); 15 | messages_ = other.messages_; 16 | } 17 | 18 | SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT 19 | { 20 | std::lock_guard lock(other.mutex_); 21 | enabled_ = other.enabled(); 22 | messages_ = std::move(other.messages_); 23 | } 24 | 25 | SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) 26 | { 27 | std::lock_guard lock(mutex_); 28 | enabled_ = other.enabled(); 29 | messages_ = std::move(other.messages_); 30 | return *this; 31 | } 32 | 33 | SPDLOG_INLINE void backtracer::enable(size_t size) 34 | { 35 | std::lock_guard lock{mutex_}; 36 | enabled_.store(true, std::memory_order_relaxed); 37 | messages_ = circular_q{size}; 38 | } 39 | 40 | SPDLOG_INLINE void backtracer::disable() 41 | { 42 | std::lock_guard lock{mutex_}; 43 | enabled_.store(false, std::memory_order_relaxed); 44 | } 45 | 46 | SPDLOG_INLINE bool backtracer::enabled() const 47 | { 48 | return enabled_.load(std::memory_order_relaxed); 49 | } 50 | 51 | SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) 52 | { 53 | std::lock_guard lock{mutex_}; 54 | messages_.push_back(log_msg_buffer{msg}); 55 | } 56 | 57 | // pop all items in the q and apply the given fun on each of them. 58 | SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) 59 | { 60 | std::lock_guard lock{mutex_}; 61 | while (!messages_.empty()) 62 | { 63 | auto &front_msg = messages_.front(); 64 | fun(front_msg); 65 | messages_.pop_front(); 66 | } 67 | } 68 | } // namespace details 69 | } // namespace spdlog 70 | -------------------------------------------------------------------------------- /host/images/folder_solid_png.h: -------------------------------------------------------------------------------- 1 | unsigned char folder_solid_png[] = { 2 | 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 3 | 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 4 | 0x08, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x69, 0x71, 0xde, 0x00, 0x00, 0x00, 5 | 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 6 | 0x01, 0x05, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x9b, 0x41, 0x0e, 7 | 0x84, 0x20, 0x10, 0x04, 0x1b, 0xe3, 0x43, 0xf7, 0xff, 0x7f, 0xd8, 0xb0, 8 | 0x27, 0x36, 0xc4, 0x15, 0xd9, 0x03, 0x58, 0xc4, 0xe9, 0x3a, 0x19, 0x43, 9 | 0x9c, 0xa6, 0x64, 0xd4, 0x03, 0x4a, 0xc6, 0x98, 0xc8, 0xa4, 0x9c, 0x73, 10 | 0x6f, 0x4c, 0x77, 0xc0, 0x3f, 0x75, 0x06, 0x5c, 0x63, 0x0a, 0x7b, 0xe3, 11 | 0xfc, 0x88, 0x49, 0xb7, 0xae, 0xb7, 0x94, 0x8c, 0xa3, 0x80, 0xd1, 0x13, 12 | 0x3f, 0xa3, 0xd4, 0x58, 0x42, 0xc4, 0x56, 0x1d, 0xdf, 0x31, 0xf9, 0x9a, 13 | 0xbb, 0xeb, 0x9d, 0xb2, 0xf5, 0x87, 0x4c, 0xe5, 0x05, 0xd7, 0xff, 0x3e, 14 | 0x04, 0xc9, 0xbb, 0x81, 0xb6, 0x02, 0xbd, 0x02, 0x24, 0xb8, 0x15, 0x56, 15 | 0x10, 0x20, 0x81, 0x12, 0x76, 0xb2, 0xf8, 0x81, 0x99, 0x39, 0x9a, 0x6d, 16 | 0xd6, 0xfa, 0x0e, 0x78, 0x1a, 0xcd, 0xef, 0x90, 0x55, 0x5a, 0xe0, 0x4e, 17 | 0xb2, 0x2a, 0x21, 0x11, 0x05, 0x14, 0xb2, 0x14, 0x5b, 0x80, 0x24, 0x0b, 18 | 0xc8, 0xd1, 0x05, 0x84, 0x5f, 0x01, 0x16, 0x60, 0x01, 0x74, 0x00, 0x1a, 19 | 0x0b, 0xa0, 0x03, 0xd0, 0x58, 0x00, 0x1d, 0x80, 0xc6, 0x02, 0xe8, 0x00, 20 | 0x34, 0x16, 0x40, 0x07, 0xa0, 0xb1, 0x00, 0x3a, 0x00, 0x8d, 0x05, 0xd0, 21 | 0x01, 0x68, 0x2c, 0x80, 0x0e, 0x40, 0x63, 0x01, 0x74, 0x00, 0x1a, 0x0b, 22 | 0xa0, 0x03, 0xd0, 0x58, 0x00, 0x1d, 0x80, 0xc6, 0x02, 0xe8, 0x00, 0x34, 23 | 0x16, 0x40, 0x07, 0xa0, 0xb1, 0x00, 0x3a, 0x00, 0x8d, 0x05, 0xd0, 0x01, 24 | 0x68, 0x2c, 0x40, 0xd2, 0x9b, 0x0e, 0x41, 0xb2, 0xc2, 0x5e, 0x61, 0x14, 25 | 0xb7, 0x00, 0x1d, 0x80, 0xa6, 0x08, 0x58, 0xe2, 0xef, 0x0d, 0x80, 0xe4, 26 | 0x15, 0x50, 0x1d, 0x47, 0x5b, 0x05, 0x49, 0xfa, 0xdd, 0x2d, 0x5e, 0x24, 27 | 0x3c, 0xf9, 0xad, 0x10, 0xed, 0x46, 0x1b, 0x63, 0x2e, 0xf8, 0x00, 0x01, 28 | 0x03, 0x1d, 0xc5, 0x33, 0x6b, 0xb6, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x49, 29 | 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 30 | }; 31 | unsigned int folder_solid_png_len = 331; 32 | -------------------------------------------------------------------------------- /host/ext/imgui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | project(imgui LANGUAGES CXX) 3 | 4 | 5 | set(IMGUI_EXTENSION_SOURCES 6 | "${CMAKE_CURRENT_SOURCE_DIR}/imgui_filedialog/ImGuiFileDialog.cpp") 7 | 8 | set(IMGUI_SOURCES 9 | "${CMAKE_CURRENT_SOURCE_DIR}/imgui.h" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/imstb_rectpack.h" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/imstb_textedit.h" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/imstb_truetype.h" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/imgui.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/imgui_draw.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/imgui_tables.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/imgui_widgets.cpp" 17 | ${IMGUI_EXTENSION_SOURCES}) 18 | 19 | add_library(imgui STATIC ${IMGUI_SOURCES}) 20 | target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 21 | 22 | # TODO: this should be part of a toolchain file 23 | if(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 24 | target_compile_options(imgui PRIVATE -Wall -Wextra -pedantic) 25 | target_compile_options(imgui PUBLIC -fno-exceptions) 26 | target_compile_options(imgui PUBLIC -fno-rtti) 27 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 28 | # Removing MSVC options that are less necessary for game / simulation 29 | # development. 30 | # 31 | # CRT_SECURE_NO_WARNINGS removes the C11-ish enforcement of using secure 32 | # versions of classic C APIs that MSVC enforces instead of relying on a 33 | # catch-all language dialect option like GCC/Clang 34 | # 35 | # ITERATOR_DEBUG_LEVEL set to 0 removes std container debugging enhancements 36 | # specific to MSVC's implementation 37 | # 38 | # Remove Exceptions and RTTI ON defaults to eliminate warnings when we disable them 39 | 40 | string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 41 | string(REGEX REPLACE "/EHsc*" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 42 | 43 | target_compile_definitions(imgui PUBLIC _CRT_SECURE_NO_WARNINGS _ITERATOR_DEBUG_LEVEL=0) 44 | target_compile_options(imgui PUBLIC /EHs-c-) 45 | target_compile_definitions(imgui PUBLIC _HAS_EXCEPTIONS=0 FMT_EXCEPTIONS=0) 46 | target_compile_options(imgui PUBLIC /GR-) 47 | else() 48 | message(WARNING "Unsupported compiler") 49 | endif() 50 | -------------------------------------------------------------------------------- /devices/prodos_hdd32.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_SMARTPORT_PRODOS_HDD32_H 2 | #define CLEM_SMARTPORT_PRODOS_HDD32_H 3 | 4 | #include "clem_shared.h" 5 | #include "clem_smartport.h" 6 | 7 | #include 8 | 9 | typedef struct mpack_writer_t mpack_writer_t; 10 | typedef struct mpack_reader_t mpack_reader_t; 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | /** 17 | * @brief Defines a shallow implementation of a simple Hard Drive interface 18 | */ 19 | struct ClemensProdosHDD32 { 20 | void *user_context; 21 | unsigned drive_index; 22 | unsigned block_limit; 23 | unsigned current_block_index; 24 | 25 | /** 26 | * @brief Callback to read a block of data from the host resident drive 27 | * 28 | */ 29 | uint8_t (*read_block)(void *user_context, unsigned drive_index, unsigned block_index, 30 | uint8_t *buffer); 31 | /** 32 | * @brief Call to write data to the host resident drive 33 | * 34 | */ 35 | uint8_t (*write_block)(void *user_context, unsigned drive_index, unsigned block_index, 36 | const uint8_t *buffer); 37 | /** Flush the host resideent device (write all contents, etc - This is optional depending on 38 | * how read_block and write_block were implemented.*/ 39 | uint8_t (*flush)(void *user_context, unsigned drive_index); 40 | }; 41 | 42 | void clem_smartport_prodos_hdd32_initialize(struct ClemensSmartPortDevice *device, 43 | struct ClemensProdosHDD32 *impl); 44 | void clem_smartport_prodos_hdd32_uninitialize(struct ClemensSmartPortDevice *device); 45 | void clem_smartport_prodos_hdd32_serialize(mpack_writer_t *writer, 46 | struct ClemensSmartPortDevice *device, 47 | const struct ClemensProdosHDD32 *hdd); 48 | bool clem_smartport_prodos_hdd32_unserialize(mpack_reader_t *reader, 49 | struct ClemensSmartPortDevice *device, 50 | struct ClemensProdosHDD32 *hdd, 51 | ClemensSerializerAllocateCb alloc_cb, void *context); 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | #endif 57 | -------------------------------------------------------------------------------- /host/cinek/encode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Cinekine Media 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 14 | * all 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 22 | * THE SOFTWARE. 23 | * 24 | * @file cinek/encode.h 25 | * @author Samir Sinha 26 | * @date 6/13/2019 27 | * @brief BaseN encoding and decoding of buffers 28 | * @copyright Cinekine 29 | */ 30 | 31 | #ifndef CINEK_ENCODE_H 32 | #define CINEK_ENCODE_H 33 | 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | unsigned int base64_encode_len(unsigned int src_len); 40 | 41 | unsigned int base64_encode( 42 | char* out, 43 | const unsigned char* src, 44 | unsigned int len 45 | ); 46 | 47 | unsigned int base64_decode_len(const char* src, unsigned int len); 48 | 49 | unsigned int base64_decode( 50 | unsigned char* out, 51 | const char *src, 52 | unsigned int len 53 | ); 54 | 55 | unsigned int cinek_encode_hex( 56 | char* result, 57 | unsigned int size, 58 | const unsigned char* source, 59 | unsigned int sourceSize 60 | ); 61 | 62 | unsigned int cinek_decode_hex( 63 | unsigned char* result, 64 | unsigned int size, 65 | const char* source 66 | ); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /host/clem_host_shared.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_SHARED_HPP 2 | #define CLEM_HOST_SHARED_HPP 3 | 4 | #include "clem_disk.h" 5 | #include "clem_mmio_types.h" 6 | #include "clem_smartport.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define CLEM_HOST_LIBRARY_DIR "library" 15 | #define CLEM_HOST_SNAPSHOT_DIR "snapshots" 16 | #define CLEM_HOST_TRACES_DIR "traces" 17 | 18 | struct ClemensBackendOutputText { 19 | int level; 20 | std::string text; 21 | }; 22 | 23 | struct ClemensBackendExecutedInstruction { 24 | ClemensInstruction data; 25 | char operand[32]; 26 | }; 27 | 28 | struct ClemensBackendDiskDriveState { 29 | std::string imagePath; 30 | bool isWriteProtected; 31 | bool isSpinning; 32 | bool isEjecting; 33 | bool saveFailed; 34 | }; 35 | 36 | struct ClemensBackendBreakpoint { 37 | enum Type { Undefined, Execute, DataRead, Write, IRQ, BRK }; 38 | Type type; 39 | uint32_t address; 40 | }; 41 | 42 | enum class ClemensBackendMachineProperty { 43 | RegA, 44 | RegB, 45 | RegC, 46 | RegX, 47 | RegY, 48 | RegP, 49 | RegD, 50 | RegSP, 51 | RegDBR, 52 | RegPBR, 53 | RegPC 54 | }; 55 | 56 | struct ClemensBackendCommand { 57 | enum Type { 58 | Undefined, 59 | Terminate, 60 | ResetMachine, 61 | RunMachine, 62 | StepMachine, 63 | InsertDisk, 64 | EjectDisk, 65 | InsertSmartPortDisk, 66 | EjectSmartPortDisk, 67 | Input, 68 | Break, 69 | AddBreakpoint, 70 | DelBreakpoint, 71 | WriteProtectDisk, 72 | DebugMemoryPage, 73 | WriteMemory, 74 | DebugLogLevel, 75 | DebugProgramTrace, 76 | SaveMachine, 77 | LoadMachine, 78 | RunScript, 79 | FastDiskEmulation, 80 | DebugMessage, 81 | SendText, 82 | SaveBinary, 83 | LoadBinary, 84 | FastMode, 85 | DebugPrintMemory 86 | }; 87 | Type type = Undefined; 88 | std::string operand; 89 | }; 90 | 91 | struct ClemensBackendResult { 92 | ClemensBackendCommand cmd; 93 | enum Type { Succeeded, Failed }; 94 | Type type; 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /clem_mem.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_MEM_H 2 | #define CLEM_MEM_H 3 | 4 | #include "clem_types.h" 5 | 6 | /** 7 | * Memory Mapping Controller 8 | * 9 | * A major part of What makes a 65816 an 'Apple IIgs' machine. The goals of 10 | * this module are to emulate accessing both FPI and the Mega2 memory. From 11 | * this, the MMC controls read/write access to I/O registers that drive the 12 | * various 'machine' components (aka the main method of accessing devices 13 | * from machine instructions - Memory Mapped I/O) 14 | * 15 | * The Mega2 is particularly tricky due to this 'slow RAM' + shadowing methods 16 | * of access. Specific state to determine what pages to access and where when 17 | * emulating 8-bit Apple II devices is particular tricky. 18 | * 19 | * This module admittedly covers a lot. It must support 'slow' accesses to 20 | * Mega2 memory, shadowing, bank switching, I/O, etc. Fortunately the I/O 21 | * registers and techniques here are well documented by 1980s Apple literature. 22 | * 23 | * Things to consider (a development TODO) 24 | * - The IIgs Technical Introduction is a good start for those unfamiliar with 25 | * what's described above 26 | * - The IIgs Firmware Reference from 1987 gives some excellent background on 27 | * what's going on under the hood on startup and how the components work 28 | * together. It's a good reference for certain I/O registers in $C0xx space 29 | * - The IIgs Hardware Reference is another source for what the $Cxxx pages 30 | * are for, registers, and details about these components from a programming 31 | * standpoint. Much of this module uses this as a source 32 | * - Also some old //e technical docs - of which include even more details. 33 | * Seems the earlier machines even have more technical documentation. 34 | * 35 | */ 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | void clem_mem_create_page_mapping(struct ClemensMemoryPageInfo *page, uint8_t page_idx, 42 | uint8_t bank_read_idx, uint8_t bank_write_idx); 43 | 44 | void clem_read(ClemensMachine *clem, uint8_t *data, uint16_t adr, uint8_t bank, uint8_t flags); 45 | void clem_write(ClemensMachine *clem, uint8_t data, uint16_t adr, uint8_t bank, uint8_t flags); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /host/clem_configuration.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_CONFIGURATION_HPP 2 | #define CLEM_HOST_CONFIGURATION_HPP 3 | 4 | #include "core/clem_apple2gs_config.hpp" 5 | 6 | #include 7 | 8 | #if defined(CLEMENS_PLATFORM_WINDOWS) 9 | #define CLEM_HOST_COMPANY_NAME "Cinekine" 10 | #define CLEM_HOST_APPLICATION_NAME "Clemens" 11 | #else 12 | #define CLEM_HOST_COMPANY_NAME "cinekine" 13 | #define CLEM_HOST_APPLICATION_NAME "Clemens" 14 | #endif 15 | 16 | #define CLEM_EMULATOR_RAM_MINIMUM 256U 17 | #define CLEM_EMULATOR_RAM_DEFAULT 4096U 18 | #define CLEM_EMULATOR_RAM_MAXIMUM 8192U 19 | 20 | #include 21 | #include 22 | 23 | namespace ClemensHostStyle { 24 | constexpr float kSideBarMinWidth = 160.0f; 25 | constexpr int kScreenWidth = 720; 26 | constexpr int kScreenHeight = 480; 27 | constexpr int kDiskTrayHeight = 320; 28 | } 29 | 30 | struct ClemensJoystickBindings { 31 | int axisAdj[2]; 32 | unsigned button[2]; 33 | }; 34 | 35 | struct ClemensConfiguration { 36 | enum class ViewMode { 37 | Windowed, 38 | Fullscreen 39 | }; 40 | 41 | std::string iniPathname; 42 | unsigned majorVersion; 43 | unsigned minorVersion; 44 | std::string dataDirectory; 45 | std::string romFilename; 46 | int logLevel; 47 | ViewMode viewMode; 48 | bool poweredOn; 49 | bool hybridInterfaceEnabled; 50 | 51 | std::array joystickBindings; 52 | 53 | ClemensAppleIIGSConfig gs; 54 | 55 | bool fastEmulationEnabled; 56 | 57 | ClemensConfiguration(); 58 | ClemensConfiguration(std::string pathname, std::string datadir); 59 | ClemensConfiguration(const ClemensConfiguration &other) { copyFrom(other); } 60 | ClemensConfiguration &operator=(const ClemensConfiguration &other) { 61 | copyFrom(other); 62 | return *this; 63 | } 64 | 65 | bool isNewInstall() const { return majorVersion == 0 && minorVersion == 0; } 66 | 67 | // clears the dirty flag 68 | bool save(); 69 | // sets the dirty flag 70 | void setDirty(); 71 | 72 | private: 73 | void copyFrom(const ClemensConfiguration &other); 74 | static int handler(void *user, const char *section, const char *name, const char *value); 75 | bool isDirty; 76 | }; 77 | 78 | ClemensConfiguration findConfiguration(); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /docs/SCC.md: -------------------------------------------------------------------------------- 1 | # SCC Zilog 8530 Emulation for the Apple IIGS 2 | 3 | ## Serial Communications 4 | 5 | ### Basics 6 | 7 | Three simple 'wires' connecting two devices - Transmit, Receive and Ground - 8 | represent a minimal serial connection. Ground (GND) is ignored for emulation 9 | purposes. Transmit (TxD) and Receive (RxD) lines perform just those tasks for a 10 | serial endpoint. 11 | 12 | The SCC controls the signaling on these wires with additional pins. To control 13 | these pins, applications send commands to the SCC via I/O register access. 14 | 15 | The Zilog 8530 provides two serial channels A and B. On the Apple IIGS, these 16 | channels are used for Slot 1/Printer (A) and Slot 2/Modem (B) control. 17 | 18 | ### Control 19 | 20 | Basic flow control is offered through the Zilog 'Modem Control Logic' unit for 21 | each channel. As mentioned above, these pins are both read and controlled 22 | using the command interface. The Clemens emulator calls such interfaces, 23 | "GLU's" - glue? - borrowed from various IIGS references. 24 | 25 | #### Signals 26 | 27 | Signal names followed by emulated port pin with peripheral. 28 | 29 | * TxD (DB8-3) - transmit bit at current baud rate 30 | * RxD (DB8-5) - receive bit at current baud rate 31 | * RTS (DB8-7) - request to send (send me more data so I can receive it) 32 | * CTS (DB8-7) - clear to send (i should transmit more data when possible) 33 | * DTR (DB8-1) - data terminal ready (signals to initiate comms) 34 | * DSR (DB8-2) - data set ready / handshake (signals to another computer that it's ready) 35 | * DCD (NONE) - carrier signal from a modem 36 | - Zilog supports this for RS-232 37 | - IIGS port doesn't have this connection 38 | 39 | The Zilog supports more signals that may be unused by the IIGS (i.e. like DCD.) 40 | Implementation will depend on practical need. 41 | 42 | ## Terminal Emulation 43 | 44 | - Simple interrupts 45 | - Device layer (like cards) with 46 | - DTR 47 | - CTS (HSKI) 48 | - DCD (GPI) 49 | - RTS (TX_D_HI) 50 | - TxD 51 | - RxD 52 | 53 | 54 | ## References 55 | 56 | https://ia801901.us.archive.org/30/items/bitsavers_zilogdataBUSSCCZ8530SCCSerialCommunicationsControl_13081094/00-2057-03_Z8030_Z-BUS_SCC_Z8530_SCC_Serial_Communications_Controller_Technical_Manual_Sep1986.pdf 57 | 58 | http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.018.html 59 | -------------------------------------------------------------------------------- /host/shaders/glsl/super.fs: -------------------------------------------------------------------------------- 1 | /* 2 | contains a matrix of 16 colors per scanline. Each color is 3 | a 4x4 texel to account for bleedover 4 | 5 | is the common 1024 x 512 target that contains *all* of the 6 | screen modes. 7 | - for super-hires, each pixel is a 1x2 texel 8 | - 320 mode duplicates the pixel horizontally on the CPU side 9 | 10 | contains a few useful values 11 | - screen_tex width 12 | - screen_tex height 13 | - screen_texel_width (likely 1) 14 | - screen_texel_height (likely 2) 15 | 16 | contains a few useful values 17 | - color_tex width 18 | - color_tex height 19 | - color texel width (likely 4) 20 | - color_texel height (likely 4) 21 | 22 | To support palette switching (for > 256 colors per frame) the `color_tex` 23 | as described above is a matrix of 16 colors horizontally and 200 of them 24 | vertically (4x4 actual pixels on the texture) 25 | 26 | applies to the `screen_tex`. 27 | applies to the `screen_tex` and is a value from ((0 - 255) + 8) / 16. 28 | 29 | ((1.0 - V) * screen_params.y + 0.5 )/ screen_params.w 30 | 31 | foreach screen_tex pixel with (U, V) and COLOR: 32 | color_index = floor((sample(screen_tex, UV) * 255.0 / 16.0) + 0.5) 33 | scanline = floor((1.0 - V) * screen_params.y + 0.5); 34 | color_uv = ( 35 | (color_index + 0.5) / 16.0f, 36 | 1.0 - ((scanline + 0.5) * color_params.w) / color_tex.y 37 | ) 38 | frag_color = sample(color_tex, color_uv) * COLOR 39 | */ 40 | #version 330 41 | 42 | uniform sampler2D screen_tex; 43 | uniform sampler2D color_tex; 44 | uniform vec4 screen_params; 45 | uniform vec4 color_params; 46 | 47 | in vec4 color; 48 | in vec2 uv; 49 | out vec4 frag_color; 50 | 51 | void main() { 52 | // color_index = 0 to 15 53 | // scanline = 0 to 199 scaled down using screen texel height (likely by 2) 54 | float color_index = floor(texture(screen_tex, uv).x * 255.0 / 16.0 + 0.5); 55 | float scanline = floor((1.0 - uv.t) * screen_params.y / screen_params.w + 0.5); 56 | vec2 color_uv = vec2( 57 | (color_index + 0.5) * color_params.z / color_params.x, 58 | 1.0 - (scanline + 0.5) * color_params.w / color_params.y); 59 | frag_color = texture(color_tex, color_uv); 60 | } 61 | -------------------------------------------------------------------------------- /host/cinek/sequence.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // sequence.hpp 3 | // SampleCommon 4 | // 5 | // Created by Samir Sinha on 3/1/16. 6 | // Copyright © 2016 Cinekine. All rights reserved. 7 | // 8 | 9 | #ifndef CINEK_MATH_SEQUENCE_HPP 10 | #define CINEK_MATH_SEQUENCE_HPP 11 | 12 | #include "equation.hpp" 13 | #include "keyframe.hpp" 14 | #include 15 | 16 | namespace cinek { 17 | 18 | template class sequence { 19 | public: 20 | typedef _Keyframe keyframe_type; 21 | typedef transition transition_type; 22 | typedef typename keyframe_type::property_type property_type; 23 | typedef _PropertyId property_key_type; 24 | typedef equation equation_type; 25 | 26 | sequence(); 27 | 28 | sequence(const property_key_type &propId, int kfcount); 29 | 30 | sequence(const property_key_type &propId, double startTime, const keyframe_type &kfA, 31 | const keyframe_type &kfB, transition_type trans, int kfcount); 32 | 33 | sequence(const sequence &other) = delete; 34 | sequence &operator=(const sequence &seq) = delete; 35 | 36 | sequence(sequence &&other); 37 | sequence &operator=(sequence &&other); 38 | 39 | void insertKeyframe(const keyframe_type &kf, transition_type transIn); 40 | void insertKeyframeEquation(const keyframe_type &kf, equation_type &eq); 41 | 42 | void setEndTransition(transition_type transIn); 43 | 44 | /// Calculates the sequence's animated property based on the specified 45 | /// time. 46 | /// @param prop The output property name and value 47 | /// @param time The time value following the sequence's start time - 48 | /// that is, 'time' and AnimationSequence::startTime() 49 | /// should come from the same source. It is not time 50 | /// relative to startTime but an absolute value. 51 | /// @return If True, indicates sequence has completed 52 | bool calcPropertyAtTime(property_type &prop, double time) const; 53 | 54 | const property_key_type &propertyId() const { return _propertyId; } 55 | 56 | double startTime() const { return _startTime; } 57 | 58 | private: 59 | property_key_type _propertyId; 60 | 61 | std::vector _frames; 62 | std::vector _transitions; 63 | 64 | double _startTime; 65 | }; 66 | 67 | } // namespace cinek 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /host/ext/spdlog/common-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace level { 15 | 16 | #if __cplusplus >= 201703L 17 | constexpr 18 | #endif 19 | static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; 20 | 21 | static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; 22 | 23 | SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT 24 | { 25 | return level_string_views[l]; 26 | } 27 | 28 | SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT 29 | { 30 | return short_level_names[l]; 31 | } 32 | 33 | SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT 34 | { 35 | auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); 36 | if (it != std::end(level_string_views)) 37 | return static_cast(std::distance(std::begin(level_string_views), it)); 38 | 39 | // check also for "warn" and "err" before giving up.. 40 | if (name == "warn") 41 | { 42 | return level::warn; 43 | } 44 | if (name == "err") 45 | { 46 | return level::err; 47 | } 48 | return level::off; 49 | } 50 | } // namespace level 51 | 52 | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) 53 | : msg_(std::move(msg)) 54 | {} 55 | 56 | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) 57 | { 58 | #ifdef SPDLOG_USE_STD_FORMAT 59 | msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); 60 | #else 61 | memory_buf_t outbuf; 62 | fmt::format_system_error(outbuf, last_errno, msg.c_str()); 63 | msg_ = fmt::to_string(outbuf); 64 | #endif 65 | } 66 | 67 | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT 68 | { 69 | return msg_.c_str(); 70 | } 71 | 72 | SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) 73 | { 74 | SPDLOG_THROW(spdlog_ex(msg, last_errno)); 75 | } 76 | 77 | SPDLOG_INLINE void throw_spdlog_ex(std::string msg) 78 | { 79 | SPDLOG_THROW(spdlog_ex(std::move(msg))); 80 | } 81 | 82 | } // namespace spdlog 83 | -------------------------------------------------------------------------------- /.github/workflows/build-windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows All Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ 'main' ] 7 | tags: 8 | - 'v*' 9 | paths: 10 | - "**" 11 | - "!.github/**" 12 | - ".github/workflows/build-windows.yml" 13 | pull_request: 14 | branches: [ 'main' ] 15 | 16 | env: 17 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 18 | BUILD_TYPE: Release 19 | 20 | jobs: 21 | build: 22 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 23 | # You can convert this to a matrix build if you need cross-platform coverage. 24 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 25 | runs-on: windows-2019 26 | 27 | steps: 28 | - uses: actions/checkout@v3 29 | 30 | - name: Add msbuild to PATH 31 | uses: microsoft/setup-msbuild@v1.1.3 32 | 33 | - name: Configure CMake 34 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 35 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 36 | run: | 37 | cmake -B ${{github.workspace}}/build -G "Visual Studio 16 2019" -A x64 -DBUILD_TESTING=OFF -DCMAKE_SYSTEM_VERSION=10.0.18392.0 38 | 39 | - name: Build 40 | # Build your program with the given configuration 41 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 42 | 43 | # - name: Test 44 | # working-directory: ${{github.workspace}}/build 45 | # run: ctest -C ${{env.BUILD_TYPE}} 46 | 47 | - name: Package 48 | if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_type == 'tag')}} 49 | run: | 50 | cd ${{github.workspace}}/build 51 | cpack --config CPackConfig.cmake 52 | 53 | - name: Archive production artifacts 54 | if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_type == 'tag')}} 55 | uses: actions/upload-artifact@v3 56 | with: 57 | name: clemens_iigs-${{github.ref_name}}-${{runner.os}} 58 | path: | 59 | ${{github.workspace}}/build/out/*.zip 60 | ${{github.workspace}}/build/out/*.sha256 61 | -------------------------------------------------------------------------------- /host/cinek/buffer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file buffer.cpp 3 | * 4 | * 5 | * \note Created by Samir Sinha on 1/19/20. 6 | * Copyright (c) 2020 Cinekine. All rights reserved. 7 | */ 8 | 9 | #include "buffer.hpp" 10 | 11 | namespace cinek { 12 | 13 | // specialization to ensure alignment based on malloc style behavior 14 | template <> auto BufferBase::forwardSize(int32_t sz) -> Range { 15 | return forwardSize(sz, true); 16 | } 17 | 18 | template <> auto BufferBase::forwardSize(int32_t sz, bool align) -> Range { 19 | Range range; 20 | size_t offset; 21 | 22 | if (align) { 23 | constexpr uintptr_t kAlign = CK_ARCH_MALLOC_ALIGN_BYTES; 24 | offset = (uint8_t *)CK_ALIGN_PTR(tail_, kAlign) - tail_; 25 | // TODO: Reevaluate this equation - seems we'll always allocate another 26 | // pool block if our remaining bytes == memSize, since offset in that 27 | // case will return 'align'. 28 | if (offset == kAlign) 29 | offset = 0; 30 | } else { 31 | offset = 0; 32 | } 33 | 34 | range.first = tail_ + offset; 35 | range.second = range.first + sz; 36 | if (range.second > limit_ || range.second < head_) { 37 | CK_ASSERT(false); 38 | range.second = limit_; 39 | } 40 | tail_ = range.second; 41 | /* - DO NOT ZERO OUT memory 42 | for (auto* t = range.first; t != range.second; ++t) { 43 | ::new(t) uint8_t(); 44 | } 45 | */ 46 | return range; 47 | } 48 | 49 | template <> auto BufferBase::forwardSize(int32_t sz) -> Range { 50 | Range range; 51 | constexpr uintptr_t kAlign = CK_ARCH_ALIGN_BYTES; 52 | size_t offset = (char *)CK_ALIGN_PTR(tail_, kAlign) - tail_; 53 | // TODO: Reevaluate this equation - seems we'll always allocate another 54 | // pool block if our remaining bytes == memSize, since offset in that 55 | // case will return 'align'. 56 | if (offset == kAlign) 57 | offset = 0; 58 | 59 | range.first = tail_ + offset; 60 | range.second = range.first + sz; 61 | if (range.second > limit_ || range.second < head_) { 62 | CK_ASSERT(false); 63 | range.second = limit_; 64 | } 65 | tail_ = range.second; 66 | /* - DO NOT ZERO OUT memory 67 | for (auto* t = range.first; t != range.second; ++t) { 68 | ::new(t) uint8_t(); 69 | } 70 | */ 71 | return range; 72 | } 73 | 74 | } // namespace cinek 75 | -------------------------------------------------------------------------------- /host/clem_l10n.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_LI0N_HPP 2 | #define CLEM_HOST_LI0N_HPP 3 | 4 | #define CLEM_L10N_LABEL(_name_) ClemensL10N::_name_[ClemensL10N::kLanguageDefault] 5 | 6 | #define CLEM_L10N_OK_LABEL ClemensL10N::kLabelOk[ClemensL10N::kLanguageDefault] 7 | #define CLEM_L10N_CANCEL_LABEL ClemensL10N::kLabelCancel[ClemensL10N::kLanguageDefault] 8 | 9 | namespace ClemensL10N { 10 | 11 | extern const char *kExitMessage[]; 12 | 13 | extern const char *kWelcomeText[]; 14 | extern const char *kGSKeyboardCommands[]; 15 | extern const char *kMouseUnlock[]; 16 | extern const char *kSettingsTabMachine[]; 17 | extern const char *kSettingsNotAvailable[]; 18 | extern const char *kSettingsMachineSystemSetup[]; 19 | extern const char *kSettingsMachineSystemSetupInfo[]; 20 | extern const char *kSettingsMachineROMFilename[]; 21 | extern const char *kSettingsMachineSystemMemory[]; 22 | extern const char *kSettingsMachineCards[]; 23 | extern const char *kSettingsTabEmulation[]; 24 | extern const char *kSettingsEmulationFastDisk[]; 25 | extern const char *kSettingsEmulationFaskDiskHelp[]; 26 | extern const char *kSettingsROMFileWarning[]; 27 | extern const char *kSettingsROMFileError[]; 28 | 29 | extern const char *kEmulatorHelp[]; 30 | extern const char *kDiskSelectionHelp[]; 31 | extern const char *kDebuggerHelp[]; 32 | 33 | extern const char *kModalDeleteSnapshot[]; 34 | 35 | extern const char *kLabelDelete[]; 36 | extern const char *kLabelOk[]; 37 | extern const char *kLabelCancel[]; 38 | extern const char *kLabelDeleteConfirm[]; 39 | extern const char *kLabelDeleteFailed[]; 40 | 41 | extern const char *kDebugNotAvailableWhileRunning[]; 42 | extern const char *kDebugDiskNoTrackData[]; 43 | 44 | extern const char* kTitleJoystickConfiguration[]; 45 | extern const char* kLabelJoystickConfirm[]; 46 | extern const char* kLabelJoystickButtonBinding[]; 47 | extern const char* kLabelJoystickNone[]; 48 | extern const char* kLabelJoystickId[]; 49 | extern const char* kLabelJoystickHelp[]; 50 | extern const char* kLabelJoystick2Help[]; 51 | extern const char* kButtonJoystickButton1[]; 52 | extern const char* kButtonJoystickButton2[]; 53 | 54 | // shortcuts 55 | extern const char *kHybridModeShortcutText[]; 56 | extern const char *kLockMouseShortcutText[]; 57 | extern const char *kTogglePauseShortcutText[]; 58 | extern const char *kFastModeShortCutText[]; 59 | 60 | constexpr unsigned kLanguageDefault = 0; 61 | 62 | } // namespace ClemensL10N 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/ringbuffer_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "spdlog/sinks/base_sink.h" 7 | #include "spdlog/details/circular_q.h" 8 | #include "spdlog/details/log_msg_buffer.h" 9 | #include "spdlog/details/null_mutex.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | /* 18 | * Ring buffer sink 19 | */ 20 | template 21 | class ringbuffer_sink final : public base_sink 22 | { 23 | public: 24 | explicit ringbuffer_sink(size_t n_items) 25 | : q_{n_items} 26 | {} 27 | 28 | std::vector last_raw(size_t lim = 0) 29 | { 30 | std::lock_guard lock(base_sink::mutex_); 31 | auto items_available = q_.size(); 32 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 33 | std::vector ret; 34 | ret.reserve(n_items); 35 | for (size_t i = (items_available - n_items); i < items_available; i++) 36 | { 37 | ret.push_back(q_.at(i)); 38 | } 39 | return ret; 40 | } 41 | 42 | std::vector last_formatted(size_t lim = 0) 43 | { 44 | std::lock_guard lock(base_sink::mutex_); 45 | auto items_available = q_.size(); 46 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 47 | std::vector ret; 48 | ret.reserve(n_items); 49 | for (size_t i = (items_available - n_items); i < items_available; i++) 50 | { 51 | memory_buf_t formatted; 52 | base_sink::formatter_->format(q_.at(i), formatted); 53 | ret.push_back(std::move(SPDLOG_BUF_TO_STRING(formatted))); 54 | } 55 | return ret; 56 | } 57 | 58 | protected: 59 | void sink_it_(const details::log_msg &msg) override 60 | { 61 | q_.push_back(details::log_msg_buffer{msg}); 62 | } 63 | void flush_() override {} 64 | 65 | private: 66 | details::circular_q q_; 67 | }; 68 | 69 | using ringbuffer_sink_mt = ringbuffer_sink; 70 | using ringbuffer_sink_st = ringbuffer_sink; 71 | 72 | } // namespace sinks 73 | 74 | } // namespace spdlog 75 | -------------------------------------------------------------------------------- /host/clem_file_browser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_HOST_FILE_BROWSER_HPP 2 | #define CLEM_HOST_FILE_BROWSER_HPP 3 | 4 | #include "imgui.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // Using the ClemensFileBrowser 15 | // - Display files according to a filter at the 'current directory' 16 | // - Highlight (single click) of directories and files 17 | // - Select (double click) of directory descends into directory 18 | // - Select of file is a signal to end browsing 19 | // 20 | 21 | class ClemensFileBrowser { 22 | public: 23 | ClemensFileBrowser(); 24 | 25 | void setCurrentDirectory(const std::string &directory); 26 | void forceRefresh(); 27 | 28 | void frame(ImVec2 size); 29 | 30 | // user selected the current highlight 31 | bool isSelected() const; 32 | bool isCancelled() const; 33 | bool isDone() const; 34 | 35 | // gets the currently selected or highlighted item 36 | std::string getCurrentPathname() const; 37 | std::string getCurrentDirectory() const; 38 | size_t getFileSize() const; 39 | 40 | protected: 41 | struct Record { 42 | std::string path; 43 | std::string name; 44 | size_t size = 0; 45 | std::time_t fileTime = 0; 46 | uint8_t context[16]; 47 | bool isDirectory; 48 | }; 49 | enum class BrowserFinishedStatus { None, Selected, Cancelled }; 50 | 51 | virtual bool onCreateRecord(const std::filesystem::directory_entry & /* direntry */, 52 | Record & /* entryRecord */) { 53 | return true; 54 | } 55 | virtual std::string onDisplayRecord(const Record &record); 56 | virtual BrowserFinishedStatus onExtraSelectionUI(ImVec2 /* dimensions*/, 57 | Record & /* selectedRecord*/) { 58 | return BrowserFinishedStatus::None; 59 | } 60 | 61 | private: 62 | using Records = std::vector; 63 | Records getRecordsFromDirectory(std::string directoryPathname); 64 | 65 | std::future getRecordsResult_; 66 | // list of records on the current path; 67 | std::filesystem::path currentDirectoryPath_; 68 | Record selectedRecord_; 69 | std::vector records_; 70 | std::chrono::steady_clock::time_point nextRefreshTime_; 71 | 72 | BrowserFinishedStatus selectionStatus_; 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /host/ext/spdlog/sinks/tcp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | # include 11 | #else 12 | # include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #pragma once 21 | 22 | // Simple tcp client sink 23 | // Connects to remote address and send the formatted log. 24 | // Will attempt to reconnect if connection drops. 25 | // If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. 26 | 27 | namespace spdlog { 28 | namespace sinks { 29 | 30 | struct tcp_sink_config 31 | { 32 | std::string server_host; 33 | int server_port; 34 | bool lazy_connect = false; // if true connect on first log call instead of on construction 35 | 36 | tcp_sink_config(std::string host, int port) 37 | : server_host{std::move(host)} 38 | , server_port{port} 39 | {} 40 | }; 41 | 42 | template 43 | class tcp_sink : public spdlog::sinks::base_sink 44 | { 45 | public: 46 | // connect to tcp host/port or throw if failed 47 | // host can be hostname or ip address 48 | 49 | explicit tcp_sink(tcp_sink_config sink_config) 50 | : config_{std::move(sink_config)} 51 | { 52 | if (!config_.lazy_connect) 53 | { 54 | this->client_.connect(config_.server_host, config_.server_port); 55 | } 56 | } 57 | 58 | ~tcp_sink() override = default; 59 | 60 | protected: 61 | void sink_it_(const spdlog::details::log_msg &msg) override 62 | { 63 | spdlog::memory_buf_t formatted; 64 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 65 | if (!client_.is_connected()) 66 | { 67 | client_.connect(config_.server_host, config_.server_port); 68 | } 69 | client_.send(formatted.data(), formatted.size()); 70 | } 71 | 72 | void flush_() override {} 73 | tcp_sink_config config_; 74 | details::tcp_client client_; 75 | }; 76 | 77 | using tcp_sink_mt = tcp_sink; 78 | using tcp_sink_st = tcp_sink; 79 | 80 | } // namespace sinks 81 | } // namespace spdlog 82 | -------------------------------------------------------------------------------- /docs/EmulatorHostHelp.md: -------------------------------------------------------------------------------- 1 | # Clemens IIGS 2 | 3 | Clemens IIGS is a cross-platform Apple IIGS emulator for both casual use and development of Apple IIGS software. 4 | 5 | Below are a list of key IIGS features supported by this emulator, followed by a list of missing features. 6 | 7 | First time users will be prompted to set a location where the emulator will store its data. Also users will be prompted to locate a ROM (version 3 only as of this writing) that will be copied to the directory specified in the last step. 8 | 9 | ## Key Features 10 | 11 | * ROM 3 supported 12 | * All Apple IIGS modes including 3200 color (experimental) 13 | * All Apple II graphics modes 14 | * Ensoniq and Mockingboard (Slot 4) audio 15 | * Joystick 16 | * Save/Load snapshots 17 | * Most disk image formats (.2mg, .woz, .po, .do, .dsk, .hdv) 18 | * Smartport Hard Drives (32MB only on Slot 2, Drive 1) 19 | 20 | ## Missing Features 21 | 22 | * ROM 1 support 23 | * Serial (SCC) communications 24 | * PAL display 25 | * Monochrome display 26 | 27 | ## Mouse Control 28 | 29 | Currently to use the mouse in a IIGS application, the emulator locks the mouse to the view (i.e. mouselock.) 30 | 31 | To transfer control of the mouse to the IIGS session, click within the view. To exit the view, follow the instructions shown in the bottom of the view. This instruction is also detailed in the Key Bindings section. 32 | 33 | ## Key Bindings (Linux) 34 | 35 | The Tux/Super key when combined with number keys will treat them as function keys. For example: 36 | 37 | - Tux + 1 = F1 38 | - Tux + 2 = F2 39 | - Tux + Minus = F11 40 | - Tux + Equals = F12 41 | - Tux + Ctrl + Equals = CTRL-RESET 42 | - Tux + Ctrl + Alt + Equals = CTRL-ALT-RESET (reboot) 43 | - Tux + Ctrl + Left Alt + 1 to enter the Control Panel 44 | - Tux + Ctrl + Left Alt + Minus to switch to Debugger Mode 45 | 46 | To restore mouse control to the system, press both ALT keys and CTRL. 47 | 48 | ## Key Bindings (Windows) 49 | 50 | - Ctrl + F12 for Control RESET 51 | - Ctrl + Right Alt + F12 to reboot the system 52 | - Ctrl + Left Alt + F1 to reboot and enter the Control Panel 53 | - Ctrl + Left Alt + F11 to switch to Debugger Mode 54 | 55 | To restore mouse control to the system, press both ALT keys and CTRL. 56 | 57 | ## Key Bindings (MacOS) 58 | 59 | - Ctrl + F12 for CTRL-RESET 60 | - Ctrl + Command + F12 to reboot the system 61 | - Ctrl + Option + F1 to enter the Control Panel 62 | - Ctrl + Option + F11 to switch to Debugger Mode 63 | 64 | To restore mouse control to the system, press Ctrl + Option + Command. 65 | 66 | -------------------------------------------------------------------------------- /clem_debug.h: -------------------------------------------------------------------------------- 1 | #ifndef CLEM_DEBUG_H 2 | #define CLEM_DEBUG_H 3 | 4 | /* TODO: something a little less reliant on clib */ 5 | #include 6 | #include 7 | 8 | #define CLEM_ASSERT(_cond_) \ 9 | do { \ 10 | assert(_cond_); \ 11 | } while (0) 12 | 13 | #define CLEM_UNIMPLEMENTED(...) \ 14 | do { \ 15 | clem_debug_log(CLEM_DEBUG_LOG_UNIMPL, __VA_ARGS__); \ 16 | } while (0) 17 | 18 | #define CLEM_WARN(...) \ 19 | do { \ 20 | clem_debug_log(CLEM_DEBUG_LOG_WARN, __VA_ARGS__); \ 21 | } while (0) 22 | 23 | #define CLEM_LOG(...) \ 24 | do { \ 25 | clem_debug_log(CLEM_DEBUG_LOG_INFO, __VA_ARGS__); \ 26 | } while (0) 27 | 28 | #define CLEM_DEBUG(...) \ 29 | do { \ 30 | clem_debug_log(CLEM_DEBUG_LOG_DEBUG, __VA_ARGS__); \ 31 | } while (0) 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | typedef struct ClemensMachine ClemensMachine; 38 | struct ClemensDeviceDebugger; 39 | 40 | void clem_debug_reset(struct ClemensDeviceDebugger *dbg); 41 | void clem_debug_break(struct ClemensDeviceDebugger *dbg, unsigned debug_reason, unsigned param0, 42 | unsigned param1); 43 | 44 | void clem_debug_context(ClemensMachine *context); 45 | 46 | void clem_debug_log(int log_level, const char *fmt, ...); 47 | 48 | char *clem_debug_acquire_trace(unsigned amt); 49 | void clem_debug_trace_flush(); 50 | 51 | void clemens_debug_status_toolbox(ClemensMachine *context, unsigned id); 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /host/ext/spdlog/async_logger.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Fast asynchronous logger. 7 | // Uses pre allocated queue. 8 | // Creates a single back thread to pop messages from the queue and log them. 9 | // 10 | // Upon each log write the logger: 11 | // 1. Checks if its log level is enough to log the message 12 | // 2. Push a new copy of the message to a queue (or block the caller until 13 | // space is available in the queue) 14 | // Upon destruction, logs all remaining messages in the queue before 15 | // destructing.. 16 | 17 | #include 18 | 19 | namespace spdlog { 20 | 21 | // Async overflow policy - block by default. 22 | enum class async_overflow_policy 23 | { 24 | block, // Block until message can be enqueued 25 | overrun_oldest // Discard oldest message in the queue if full when trying to 26 | // add new item. 27 | }; 28 | 29 | namespace details { 30 | class thread_pool; 31 | } 32 | 33 | class SPDLOG_API async_logger final : public std::enable_shared_from_this, public logger 34 | { 35 | friend class details::thread_pool; 36 | 37 | public: 38 | template 39 | async_logger(std::string logger_name, It begin, It end, std::weak_ptr tp, 40 | async_overflow_policy overflow_policy = async_overflow_policy::block) 41 | : logger(std::move(logger_name), begin, end) 42 | , thread_pool_(std::move(tp)) 43 | , overflow_policy_(overflow_policy) 44 | {} 45 | 46 | async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, 47 | async_overflow_policy overflow_policy = async_overflow_policy::block); 48 | 49 | async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, 50 | async_overflow_policy overflow_policy = async_overflow_policy::block); 51 | 52 | std::shared_ptr clone(std::string new_name) override; 53 | 54 | protected: 55 | void sink_it_(const details::log_msg &msg) override; 56 | void flush_() override; 57 | void backend_sink_it_(const details::log_msg &incoming_log_msg); 58 | void backend_flush_(); 59 | 60 | private: 61 | std::weak_ptr thread_pool_; 62 | async_overflow_policy overflow_policy_; 63 | }; 64 | } // namespace spdlog 65 | 66 | #ifdef SPDLOG_HEADER_ONLY 67 | # include "async_logger-inl.h" 68 | #endif 69 | -------------------------------------------------------------------------------- /host/cinek/buffertypes.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Cinekine Media 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 14 | * all 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 22 | * THE SOFTWARE. 23 | * 24 | * @file cinek/buffer.hpp 25 | * @author Samir Sinha 26 | * @date 7/7/2020 27 | * @brief essential types for buffer 28 | * @copyright Cinekine 29 | */ 30 | 31 | #ifndef CINEK_V2_BUFFER_TYPES_HPP 32 | #define CINEK_V2_BUFFER_TYPES_HPP 33 | 34 | #include 35 | #include 36 | 37 | namespace cinek { 38 | 39 | struct BufferString 40 | { 41 | BufferString() = default; 42 | BufferString(int32_t i, int32_t c): index(i), count(c) {} 43 | explicit operator bool() const { return index >= 0 && count != 0; } 44 | int32_t index = 0; 45 | int32_t count = 0; 46 | }; 47 | 48 | template using Range = std::pair; 49 | template using ConstRange = std::pair; 50 | template ConstRange ConstCastRange(Range& range) { 51 | return ConstRange { range.first, range.second }; 52 | } 53 | 54 | template int32_t length(Range range) { 55 | return static_cast(range.second - range.first); 56 | } 57 | 58 | template int32_t length(ConstRange range) { 59 | return static_cast(range.second - range.first); 60 | } 61 | 62 | template class BufferBase; 63 | template class Buffer; 64 | 65 | } // namespace cinek 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /host/clem_host_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "clem_host_utils.hpp" 2 | #include "devices/mockingboard.h" 3 | 4 | #include 5 | 6 | static uint32_t kAddrModeSizes[kClemensCPUAddrMode_Count]; 7 | 8 | void ClemensTraceExecutedInstruction::initialize() { 9 | // these are 8-bit sizes that are augmented by the instruction opcode width 10 | // (opc8) 11 | kAddrModeSizes[kClemensCPUAddrMode_None] = 1; 12 | kAddrModeSizes[kClemensCPUAddrMode_Immediate] = 2; 13 | kAddrModeSizes[kClemensCPUAddrMode_Absolute] = 3; 14 | kAddrModeSizes[kClemensCPUAddrMode_AbsoluteLong] = 4; 15 | kAddrModeSizes[kClemensCPUAddrMode_DirectPage] = 2; 16 | kAddrModeSizes[kClemensCPUAddrMode_DirectPageIndirect] = 2; 17 | kAddrModeSizes[kClemensCPUAddrMode_DirectPageIndirectLong] = 2; 18 | kAddrModeSizes[kClemensCPUAddrMode_Absolute_X] = 3; 19 | kAddrModeSizes[kClemensCPUAddrMode_AbsoluteLong_X] = 4; 20 | kAddrModeSizes[kClemensCPUAddrMode_Absolute_Y] = 3; 21 | kAddrModeSizes[kClemensCPUAddrMode_DirectPage_X] = 2; 22 | kAddrModeSizes[kClemensCPUAddrMode_DirectPage_Y] = 2; 23 | kAddrModeSizes[kClemensCPUAddrMode_DirectPage_X_Indirect] = 2; 24 | kAddrModeSizes[kClemensCPUAddrMode_DirectPage_Indirect_Y] = 2; 25 | kAddrModeSizes[kClemensCPUAddrMode_DirectPage_IndirectLong_Y] = 2; 26 | kAddrModeSizes[kClemensCPUAddrMode_MoveBlock] = 3; 27 | kAddrModeSizes[kClemensCPUAddrMode_Stack_Relative] = 2; 28 | kAddrModeSizes[kClemensCPUAddrMode_Stack_Relative_Indirect_Y] = 2; 29 | kAddrModeSizes[kClemensCPUAddrMode_PCRelative] = 2; 30 | kAddrModeSizes[kClemensCPUAddrMode_PCRelativeLong] = 3; 31 | kAddrModeSizes[kClemensCPUAddrMode_PC] = 3; 32 | kAddrModeSizes[kClemensCPUAddrMode_PCIndirect] = 3; 33 | kAddrModeSizes[kClemensCPUAddrMode_PCIndirect_X] = 3; 34 | kAddrModeSizes[kClemensCPUAddrMode_PCLong] = 4; 35 | kAddrModeSizes[kClemensCPUAddrMode_PCLongIndirect] = 3; 36 | kAddrModeSizes[kClemensCPUAddrMode_Operand] = 2; 37 | } 38 | 39 | ClemensTraceExecutedInstruction & 40 | ClemensTraceExecutedInstruction::fromInstruction(const ClemensInstruction &instruction, 41 | const char *oper) { 42 | strncpy(opcode, instruction.desc->name, sizeof(opcode)); 43 | opcode[sizeof(opcode) - 1] = '\0'; 44 | strncpy(operand, oper, sizeof(operand) - 1); 45 | operand[sizeof(operand) - 1] = '\0'; 46 | cycles_spent = instruction.cycles_spent; 47 | pc = (uint32_t(instruction.pbr) << 16) | instruction.addr; 48 | size = kAddrModeSizes[instruction.desc->addr_mode]; 49 | 50 | return *this; 51 | } 52 | -------------------------------------------------------------------------------- /host/shaders/d3d11.inl: -------------------------------------------------------------------------------- 1 | const char *VS_VERTEX_SOURCE = 2 | "cbuffer Globals {\n" 3 | " float2 render_dims;\n" 4 | " float2 display_ratio;\n" 5 | " float2 virtual_dims;\n" 6 | " float2 offsets;\n" 7 | "};\n" 8 | "struct Input {\n" 9 | " float2 pos: POSITION;\n" 10 | " float2 uv: TEXCOORD1;\n" 11 | " float4 color: COLOR1;\n" 12 | "};\n" 13 | "struct Output {\n" 14 | " float2 uv: TEXCOORD0;\n" 15 | " float4 color: COLOR0;\n" 16 | " float4 pos: SV_POSITION;\n" 17 | "};\n" 18 | "Output main(Input input) {\n" 19 | " Output output;\n" 20 | " float2 t_pos = (input.pos * display_ratio + offsets) / render_dims;\n" 21 | " t_pos = (t_pos - 0.5) * float2(2.0, -2.0);\n" 22 | " output.pos = float4(t_pos, 0.5, 1.0);\n" 23 | " output.uv = input.uv;\n" 24 | " output.color = input.color;\n" 25 | " return output;\n" 26 | "}\n"; 27 | 28 | const char *FS_TEXT_SOURCE = 29 | "Texture2D tex: register(t0);\n" 30 | "sampler smp: register(s0);\n" 31 | "float4 main(float2 uv: TEXCOORD0, float4 color: COLOR0): SV_Target0 {\n" 32 | " float4 texl = tex.Sample(smp, uv);\n" 33 | " return texl.xxxx * color;\n" 34 | "}\n"; 35 | 36 | const char *FS_HIRES_SOURCE = 37 | "Texture2D hgr_tex: register(t0);\n" 38 | "Texture2D hcolor_tex: register(t1);\n" 39 | "sampler smp: register(s0);\n" 40 | "float4 main(float2 uv: TEXCOORD0, float4 color: COLOR0): SV_Target0 {\n" 41 | " float4 texl_hgr = hgr_tex.Sample(smp, uv);\n" 42 | " float4 texl_color = hcolor_tex.Sample(smp, float2(texl_hgr.x, 0.0));\n" 43 | " return texl_color;\n" 44 | "};\n"; 45 | 46 | const char *FS_SUPER_SOURCE = R"hlsl( 47 | cbuffer Globals { 48 | float4 screen_params; 49 | float4 color_params; 50 | }; 51 | 52 | Texture2D screen_tex : register(t0); 53 | Texture2D color_tex : register(t1); 54 | sampler smp : register(s0); 55 | 56 | float4 main(float2 uv : TEXCOORD0, float4 color : COLOR0) : SV_Target0 { 57 | // color_index = 0 to 15 58 | // scanline = 0 to 199 scaled down using screen texel height (likely by 2) 59 | float color_index = floor(screen_tex.Sample(smp, uv).x * 255.0 / 16.0 + 0.5); 60 | float scanline = floor(uv.y * screen_params.y / screen_params.w + 0.5); 61 | float2 color_uv = 62 | float2((color_index + 0.5) * color_params.z / color_params.x, 63 | (scanline + 0.5) * color_params.w / color_params.y); 64 | float4 texl_color = color_tex.Sample(smp, color_uv); 65 | return texl_color * color; 66 | } 67 | )hlsl"; 68 | -------------------------------------------------------------------------------- /host/ext/imgui/imgui_filedialog/stb/LICENSE: -------------------------------------------------------------------------------- 1 | This software is available under 2 licenses -- choose whichever you prefer. 2 | ------------------------------------------------------------------------------ 3 | ALTERNATIVE A - MIT License 4 | Copyright (c) 2017 Sean Barrett 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | ------------------------------------------------------------------------------ 21 | ALTERNATIVE B - Public Domain (www.unlicense.org) 22 | This is free and unencumbered software released into the public domain. 23 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 24 | software, either in source code form or as a compiled binary, for any purpose, 25 | commercial or non-commercial, and by any means. 26 | In jurisdictions that recognize copyright laws, the author or authors of this 27 | software dedicate any and all copyright interest in the software to the public 28 | domain. We make this dedication for the benefit of the public at large and to 29 | the detriment of our heirs and successors. We intend this dedication to be an 30 | overt act of relinquishment in perpetuity of all present and future rights to 31 | this software under copyright law. 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 36 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 37 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 38 | -------------------------------------------------------------------------------- /host/utils/dump_compare.py: -------------------------------------------------------------------------------- 1 | INPUT_FILES = [ 2 | 'reference.txt', 3 | 'memory_00.txt' 4 | ] 5 | 6 | def create_memory_bytes(lines): 7 | memory = bytearray(65536) 8 | 9 | for idx, line in enumerate(lines): 10 | items = line.split(':') 11 | if len(items) != 2: 12 | raise RuntimeError( 13 | 'Invalid memory line found line {}'.format(idx + 1)) 14 | address = int(items[0], 16) 15 | hex_string = items[1].strip() 16 | byte_count = len(hex_string) // 2 17 | while byte_count > 0: 18 | byte_count -= 1 19 | hex_byte = hex_string[(byte_count * 2):(byte_count * 2) + 2] 20 | memory[address + byte_count] = int(hex_byte, 16) 21 | 22 | return memory 23 | 24 | 25 | def diff_banks(ref_bank, test_bank): 26 | if len(ref_bank) != len(test_bank): 27 | print('Banks are of a different size') 28 | 29 | byte_limit = min(len(ref_bank), len(test_bank)) 30 | byte_start = 0 31 | byte_end = 0 32 | 33 | while byte_end < byte_limit: 34 | if ref_bank[byte_end] == test_bank[byte_end]: 35 | if byte_start != byte_end: 36 | print('${:04X} to ${:04X}'.format(byte_start, byte_end - 1)) 37 | hex_bytes_a = ref_bank[byte_start:byte_end] 38 | hex_bytes_b = test_bank[byte_start:byte_end] 39 | 40 | adr_start = byte_start 41 | while len(hex_bytes_a) > 0: 42 | hex_string = ' '.join(['{:02X}'.format(v) for v in hex_bytes_a[0:16]]) 43 | print('A ${:04X}: '.format(adr_start) + hex_string) 44 | hex_string = ' '.join(['{:02X}'.format(v) for v in hex_bytes_b[0:16]]) 45 | print('B ${:04X}: '.format(adr_start) + hex_string) 46 | adr_start += min(16, len(hex_bytes_a)) 47 | hex_bytes_a = hex_bytes_a[16:] 48 | hex_bytes_b = hex_bytes_b[16:] 49 | 50 | print('\n') 51 | 52 | byte_end += 1 53 | byte_start = byte_end 54 | else: 55 | byte_end += 1 56 | 57 | 58 | memory_banks = [] 59 | for input_file in INPUT_FILES: 60 | lines = open(input_file, 'r').readlines() 61 | memory_banks.append(create_memory_bytes(lines)) 62 | 63 | # first file is the reference 64 | # second file and later are the ones to compare against 65 | 66 | if not memory_banks: 67 | raise RuntimeError('Requires at least two memory dump files') 68 | 69 | reference_bank = memory_banks[0] 70 | memory_banks = memory_banks[1:] 71 | for test_bank in memory_banks: 72 | diff_banks(reference_bank, test_bank) 73 | -------------------------------------------------------------------------------- /host/cinek/equation.inl: -------------------------------------------------------------------------------- 1 | // 2 | // equation.inl 3 | // SampleCommon 4 | // 5 | // Created by Samir Sinha on 2/28/16. 6 | // Copyright © 2016 Cinekine. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | namespace cinek { 12 | 13 | template 14 | void equation<_property>::calc(property_type &out, const keyframe_type &left, 15 | const keyframe_type &right, double time) const { 16 | if (time < left.time) { 17 | out = left.prop; 18 | return; 19 | } 20 | if (time > right.time) { 21 | out = right.prop; 22 | return; 23 | } 24 | 25 | double timeRange = right.time - left.time; 26 | double timeIn = time - left.time; 27 | if (timeRange < timeIn) 28 | timeIn = timeRange; 29 | 30 | auto scalar = timeIn / timeRange; 31 | 32 | switch (type) { 33 | case transition_type::kLinear: 34 | break; 35 | case transition_type::kEaseIn: { 36 | scalar = -(scalar * (scalar - 2)); 37 | } break; 38 | case transition_type::kEaseOut: { 39 | scalar = scalar * scalar; 40 | } break; 41 | case transition_type::kEase: { 42 | // scalar = (2 * scalar) or (2*t/T) 43 | float scalarX2 = 2.f * scalar; 44 | if (scalarX2 < 1.f) { 45 | scalar = 0.5f * scalarX2 * scalarX2; 46 | } else { 47 | scalarX2 -= 1.f; 48 | scalar = 0.5f * (scalarX2 * (scalarX2 - 2) - 1); 49 | } 50 | } break; 51 | case transition_type::kEaseInCubic: { 52 | float scalarMin1 = scalar - 1; 53 | scalar = scalarMin1 * scalarMin1 * scalarMin1 + 1; 54 | } break; 55 | case transition_type::kEaseOutCubic: { 56 | scalar = scalar * scalar * scalar; 57 | } break; 58 | case transition_type::kEaseCubic: { 59 | // scalar = (2 * scalar) or (2*t/T) 60 | float scalarX2 = 2.f * scalar; 61 | if (scalarX2 < 1.f) { 62 | scalar = 0.5f * scalarX2 * scalarX2 * scalarX2; 63 | } else { 64 | scalarX2 -= 2.f; 65 | scalar = 0.5f * (scalarX2 * scalarX2 * scalarX2 + 2); 66 | } 67 | } break; 68 | case transition_type::kSine: { 69 | scalar = -0.5f * (std::cos(M_PI * scalar) - 1); 70 | } break; 71 | default: 72 | break; 73 | }; 74 | 75 | tweenProperty<_property>(out, left, right, scalar); 76 | } 77 | 78 | template 79 | void tweenProperty(_property &out, const keyframe<_property> &left, 80 | const keyframe<_property> &right, double scalar) { 81 | out = left.prop + (right.prop - left.prop) * scalar; 82 | } 83 | 84 | } // namespace cinek 85 | -------------------------------------------------------------------------------- /host/ext/spdlog/details/udp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Helper RAII over unix udp client socket. 7 | // Will throw on construction if the socket creation failed. 8 | 9 | #ifdef _WIN32 10 | # error "include udp_client-windows.h instead" 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace spdlog { 26 | namespace details { 27 | 28 | class udp_client 29 | { 30 | static constexpr int TX_BUFFER_SIZE = 1024 * 10; 31 | int socket_ = -1; 32 | struct sockaddr_in sockAddr_; 33 | 34 | void cleanup_() 35 | { 36 | if (socket_ != -1) 37 | { 38 | ::close(socket_); 39 | socket_ = -1; 40 | } 41 | } 42 | 43 | public: 44 | udp_client(const std::string &host, uint16_t port) 45 | { 46 | socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); 47 | if (socket_ < 0) 48 | { 49 | throw_spdlog_ex("error: Create Socket Failed!"); 50 | } 51 | 52 | int option_value = TX_BUFFER_SIZE; 53 | if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) 54 | { 55 | cleanup_(); 56 | throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); 57 | } 58 | 59 | sockAddr_.sin_family = AF_INET; 60 | sockAddr_.sin_port = htons(port); 61 | 62 | if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) 63 | { 64 | cleanup_(); 65 | throw_spdlog_ex("error: Invalid address!"); 66 | } 67 | 68 | ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); 69 | } 70 | 71 | ~udp_client() 72 | { 73 | cleanup_(); 74 | } 75 | 76 | int fd() const 77 | { 78 | return socket_; 79 | } 80 | 81 | // Send exactly n_bytes of the given data. 82 | // On error close the connection and throw. 83 | void send(const char *data, size_t n_bytes) 84 | { 85 | ssize_t toslen = 0; 86 | socklen_t tolen = sizeof(struct sockaddr); 87 | if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) 88 | { 89 | throw_spdlog_ex("sendto(2) failed", errno); 90 | } 91 | } 92 | }; 93 | } // namespace details 94 | } // namespace spdlog 95 | -------------------------------------------------------------------------------- /.github/workflows/build-linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux All Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ "main" ] 7 | tags: 8 | - 'v*' 9 | paths: 10 | - "**" 11 | - "!.github/**" 12 | - ".github/workflows/build-linux.yml" 13 | pull_request: 14 | branches: [ 'main' ] 15 | 16 | env: 17 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 18 | BUILD_TYPE: Release 19 | 20 | jobs: 21 | build: 22 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 23 | # You can convert this to a matrix build if you need cross-platform coverage. 24 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 25 | runs-on: ubuntu-20.04 26 | 27 | steps: 28 | - uses: actions/checkout@v3 29 | 30 | - name: Prerequisites 31 | # Needed for X11 extensions and audio builds 32 | run: | 33 | sudo apt-get update 34 | sudo apt-get install -y libxi-dev libxcursor-dev libasound2-dev mesa-common-dev 35 | 36 | - name: Configure CMake 37 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 38 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 39 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 40 | 41 | - name: Build 42 | # Build your program with the given configuration 43 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 44 | 45 | # - name: Test 46 | # working-directory: ${{github.workspace}}/build 47 | # Execute tests defined by the CMake configuration. 48 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 49 | # run: ctest -C ${{env.BUILD_TYPE}} 50 | 51 | - name: Package Release 52 | if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_type == 'tag')}} 53 | run: | 54 | cd ${{github.workspace}}/build 55 | cpack --config CPackConfig.cmake 56 | 57 | - name: Archive Release Artifacts 58 | if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_type == 'tag')}} 59 | uses: actions/upload-artifact@v3 60 | with: 61 | name: clemens_iigs-${{github.ref_name}}-${{runner.os}} 62 | path: | 63 | ${{github.workspace}}/build/out/*.deb 64 | ${{github.workspace}}/build/out/*.rpm 65 | ${{github.workspace}}/build/out/*.sha256 66 | --------------------------------------------------------------------------------