diff --git a/.gitignore b/.gitignore index f07a0cd..4dd31af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -# For now, ignore user builds -# We will eventually change to a custom -# build system. -# So hold on -/bin -/out +# For now, ignore user builds +# We will eventually change to a custom +# build system. +# So hold on +/bin +/out diff --git a/LICENSE b/LICENSE index 68c2521..7fca2fb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,18 +1,18 @@ -MIT License - -Copyright (c) 2026 SpiderLang - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. +MIT License + +Copyright (c) 2026 SpiderLang + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 5c82273..d329cc8 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# spider-runtime -This is the Spider runtime (aka, the virtual machine) that executes the Spider byte code. - -## Code Etiquette - - Do not use \r\n - - Do not use any encoding besides UTF-8 - - Always comment global functions, variables, classes, member variables and methods. - - Do not modify the autogenerated files. - - If using an LLM, use private mode and tell it you're working on an old modem. - - If using an AI agent, don't. - - You need to re-run the pygen.ipynb to be up to date with the .xlsx instructions file. - -Failure to uphold the code etiquette will result in a slap in the wrist, with a hammer. +# spider-runtime +This is the Spider runtime (aka, the virtual machine) that executes the Spider byte code. + +## Code Etiquette + - Do not use \r\n + - Do not use any encoding besides UTF-8 + - Always comment global functions, variables, classes, member variables and methods. + - Do not modify the autogenerated files. + - If using an LLM, use private mode and tell it you're working on an old modem. + - If using an AI agent, don't. + - You need to re-run the pygen.ipynb to be up to date with the .xlsx instructions file. + +Failure to uphold the code etiquette will result in a slap in the wrist, with a hammer. diff --git a/build/esp32/Makefile b/build/esp32/Makefile new file mode 100644 index 0000000..a81821d --- /dev/null +++ b/build/esp32/Makefile @@ -0,0 +1,56 @@ +# ========================================================== # +# Spider Runtime - ESP32 Build System # +# Toolchain: Espressif ESP-IDF (xtensa-esp-elf-g++) # +# ========================================================== # + +CC := xtensa-esp-elf-g++ +TARGET := spider_esp32.elf +SRCDIR := ../../src +BUILDDIR := bin +TARGETDIR := out +SRCEXT := cpp +OBJEXT := o + +ESP_FLAGS := -DESP32 -DSPIDER_DISTRO_MICRO -DSPIDER_OS_NONE -mlongcalls -ffunction-sections -fdata-sections -fno-exceptions -fno-rtti + +CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING $(ESP_FLAGS) +LFLAGS := -Wl,--gc-sections -mlongcalls +INC := -I../../src/ + +# Exclude desktop-only modules +EXCLUDE := $(SRCDIR)/spider/runtime/util/Terminal.cpp \ + $(SRCDIR)/spider/runtime/debug/LiveDebug.cpp \ + $(SRCDIR)/spider/SpiderRuntime.cpp + +# ESP32 specific entry point +EXTRA := $(SRCDIR)/spider/main_esp32.cpp + +SOURCES := $(filter-out $(EXCLUDE), $(shell find $(SRCDIR) -type f -name "*.$(SRCEXT)" 2>/dev/null)) $(EXTRA) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) + +all: directories $(TARGET) + @echo "Build complete: $(TARGETDIR)/$(TARGET)" + +remake: cleaner all + +directories: + @mkdir -p $(TARGETDIR) + @mkdir -p $(BUILDDIR) + +clean: + @$(RM) -rf $(BUILDDIR) + +cleaner: clean + @$(RM) -rf $(TARGETDIR) + +$(TARGET): $(OBJECTS) + @echo "Linking $(TARGET)..." + $(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ + @echo "Done!" + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(dir $@) + @echo "Compiling $<..." + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +.PHONY: all remake clean cleaner diff --git a/build/esp32/bin/spider/main_esp32.o b/build/esp32/bin/spider/main_esp32.o new file mode 100644 index 0000000..f8c2995 Binary files /dev/null and b/build/esp32/bin/spider/main_esp32.o differ diff --git a/build/esp32/bin/spider/runtime/Runtime.o b/build/esp32/bin/spider/runtime/Runtime.o new file mode 100644 index 0000000..3a12a87 Binary files /dev/null and b/build/esp32/bin/spider/runtime/Runtime.o differ diff --git a/build/esp32/bin/spider/runtime/cpu/CPU.o b/build/esp32/bin/spider/runtime/cpu/CPU.o new file mode 100644 index 0000000..7ec5a86 Binary files /dev/null and b/build/esp32/bin/spider/runtime/cpu/CPU.o differ diff --git a/build/esp32/bin/spider/runtime/instr/Instr_00-1F.o b/build/esp32/bin/spider/runtime/instr/Instr_00-1F.o new file mode 100644 index 0000000..2bd1f92 Binary files /dev/null and b/build/esp32/bin/spider/runtime/instr/Instr_00-1F.o differ diff --git a/build/esp32/bin/spider/runtime/math/Quat.o b/build/esp32/bin/spider/runtime/math/Quat.o new file mode 100644 index 0000000..44f83c4 Binary files /dev/null and b/build/esp32/bin/spider/runtime/math/Quat.o differ diff --git a/build/esp32/bin/spider/runtime/memory/ByteArray.o b/build/esp32/bin/spider/runtime/memory/ByteArray.o new file mode 100644 index 0000000..9c17633 Binary files /dev/null and b/build/esp32/bin/spider/runtime/memory/ByteArray.o differ diff --git a/build/esp32/bin/spider/runtime/memory/RAM.o b/build/esp32/bin/spider/runtime/memory/RAM.o new file mode 100644 index 0000000..1ea50fa Binary files /dev/null and b/build/esp32/bin/spider/runtime/memory/RAM.o differ diff --git a/build/esp32/bin/spider/runtime/reel/InstrReel.o b/build/esp32/bin/spider/runtime/reel/InstrReel.o new file mode 100644 index 0000000..9b89f16 Binary files /dev/null and b/build/esp32/bin/spider/runtime/reel/InstrReel.o differ diff --git a/build/esp32/bin/spider/runtime/reel/InstrReelDyn.o b/build/esp32/bin/spider/runtime/reel/InstrReelDyn.o new file mode 100644 index 0000000..17d3eeb Binary files /dev/null and b/build/esp32/bin/spider/runtime/reel/InstrReelDyn.o differ diff --git a/build/esp32/bin/spider/runtime/reel/InstrReelFixed.o b/build/esp32/bin/spider/runtime/reel/InstrReelFixed.o new file mode 100644 index 0000000..060a1f7 Binary files /dev/null and b/build/esp32/bin/spider/runtime/reel/InstrReelFixed.o differ diff --git a/build/esp32/gen_makefile.py b/build/esp32/gen_makefile.py new file mode 100644 index 0000000..a29d28c --- /dev/null +++ b/build/esp32/gen_makefile.py @@ -0,0 +1,64 @@ +tab = '\t' +dollar = '$' + +content = f"""# ========================================================== # +# Spider Runtime - ESP32 Build System # +# Toolchain: Espressif ESP-IDF (xtensa-esp-elf-g++) # +# ========================================================== # + +CC := xtensa-esp-elf-g++ +TARGET := spider_esp32.elf +SRCDIR := ../../src +BUILDDIR := bin +TARGETDIR := out +SRCEXT := cpp +OBJEXT := o + +ESP_FLAGS := -DESP32 -DSPIDER_DISTRO_MICRO -DSPIDER_OS_NONE -mlongcalls -ffunction-sections -fdata-sections -fno-exceptions -fno-rtti + +CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING {dollar}(ESP_FLAGS) +LFLAGS := -Wl,--gc-sections -mlongcalls +INC := -I../../src/ + +# Exclude desktop-only modules +EXCLUDE := {dollar}(SRCDIR)/spider/runtime/util/Terminal.cpp \\ + {dollar}(SRCDIR)/spider/runtime/debug/LiveDebug.cpp \\ + {dollar}(SRCDIR)/spider/SpiderRuntime.cpp + +# ESP32 specific entry point +EXTRA := {dollar}(SRCDIR)/spider/main_esp32.cpp + +SOURCES := {dollar}(filter-out {dollar}(EXCLUDE), {dollar}(shell find {dollar}(SRCDIR) -type f -name "*.{dollar}(SRCEXT)" 2>/dev/null)) {dollar}(EXTRA) +OBJECTS := {dollar}(patsubst {dollar}(SRCDIR)/%,{dollar}(BUILDDIR)/%,{dollar}(SOURCES:.{dollar}(SRCEXT)=.{dollar}(OBJEXT))) + +all: directories {dollar}(TARGET) +{tab}@echo "Build complete: {dollar}(TARGETDIR)/{dollar}(TARGET)" + +remake: cleaner all + +directories: +{tab}@mkdir -p {dollar}(TARGETDIR) +{tab}@mkdir -p {dollar}(BUILDDIR) + +clean: +{tab}@{dollar}(RM) -rf {dollar}(BUILDDIR) + +cleaner: clean +{tab}@{dollar}(RM) -rf {dollar}(TARGETDIR) + +{dollar}(TARGET): {dollar}(OBJECTS) +{tab}@echo "Linking {dollar}(TARGET)..." +{tab}{dollar}(CC) {dollar}(LFLAGS) -o {dollar}(TARGETDIR)/{dollar}(TARGET) {dollar}^ +{tab}@echo "Done!" + +{dollar}(BUILDDIR)/%.{dollar}(OBJEXT): {dollar}(SRCDIR)/%.{dollar}(SRCEXT) +{tab}@mkdir -p {dollar}(dir {dollar}@) +{tab}@echo "Compiling {dollar}<..." +{tab}{dollar}(CC) {dollar}(CFLAGS) {dollar}(INC) -c -o {dollar}@ {dollar}< + +.PHONY: all remake clean cleaner +""" + +with open('Makefile', 'w', newline='\n') as f: + f.write(content) +print("Makefile generated successfully!") diff --git a/build/esp32/out/spider_esp32.elf b/build/esp32/out/spider_esp32.elf new file mode 100644 index 0000000..a101fde Binary files /dev/null and b/build/esp32/out/spider_esp32.elf differ diff --git a/makefile b/makefile index 8ec5941..b68f29f 100644 --- a/makefile +++ b/makefile @@ -1,65 +1,65 @@ -#Compiler and Linker -CC := g++ - -#The Target Binary Program -TARGET := out.exe - -#The Directories, Source, Includes, Objects, Binary and Resources -SRCDIR := src -BUILDDIR := bin -TARGETDIR := out -SRCEXT := cpp -DEPEXT := d -OBJEXT := o - -#Flags, Libraries and Includes -ROOT := ./ -CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING -LFLAGS := -Wall -std=c++20 -static -LIB := -INC := -I./src/ - -#--------------------------------------------------------------------------------- -#DO NOT EDIT BELOW THIS LINE -#--------------------------------------------------------------------------------- -SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) -OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) - -#Defauilt Make -all: directories $(TARGET) - -#Remake -remake: cleaner all - -#Make the Directories -directories: - @mkdir -p $(TARGETDIR) - @mkdir -p $(BUILDDIR) - -#Clean only Objecst -clean: - @$(RM) -rf $(BUILDDIR) - -#Full Clean, Objects and Binaries -cleaner: clean - @$(RM) -rf $(TARGETDIR) - -#Pull in dependency info for *existing* .o files --include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) - -#Link -$(TARGET): $(OBJECTS) - $(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ $(LIB) - -#Compile -$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) $(INC) -c -o $@ $< - @$(CC) $(CFLAGS) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) - @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp - @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) - @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) - @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp - -#Non-File Targets +#Compiler and Linker +CC := g++ + +#The Target Binary Program +TARGET := out.exe + +#The Directories, Source, Includes, Objects, Binary and Resources +SRCDIR := src +BUILDDIR := bin +TARGETDIR := out +SRCEXT := cpp +DEPEXT := d +OBJEXT := o + +#Flags, Libraries and Includes +ROOT := ./ +CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING +LFLAGS := -Wall -std=c++20 -static +LIB := +INC := -I./src/ + +#--------------------------------------------------------------------------------- +#DO NOT EDIT BELOW THIS LINE +#--------------------------------------------------------------------------------- +SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) + +#Defauilt Make +all: directories $(TARGET) + +#Remake +remake: cleaner all + +#Make the Directories +directories: + @mkdir -p $(TARGETDIR) + @mkdir -p $(BUILDDIR) + +#Clean only Objecst +clean: + @$(RM) -rf $(BUILDDIR) + +#Full Clean, Objects and Binaries +cleaner: clean + @$(RM) -rf $(TARGETDIR) + +#Pull in dependency info for *existing* .o files +-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) + +#Link +$(TARGET): $(OBJECTS) + $(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ $(LIB) + +#Compile +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + @$(CC) $(CFLAGS) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) + @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp + @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) + @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) + @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + +#Non-File Targets .PHONY: all remake clean cleaner resources \ No newline at end of file diff --git a/pygen.ipynb b/pygen.ipynb index 4d88ae5..ad85b00 100644 --- a/pygen.ipynb +++ b/pygen.ipynb @@ -1,471 +1,471 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "21877801", - "metadata": {}, - "source": [ - "## Python Generator\n", - "\n", - "This python notebook will serve to generate the necessary code to\n", - "generate some things from Spider.\n", - "\n", - "Specifically, it will generate the CPU instructions (currently)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b0fcd533", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Repo root : ./ -> (True)\n", - "CPU.hpp : .//src//spider/runtime/cpu/CPU.hpp -> (True)\n", - "XLSX : .//docs//Spider Instructions.xlsx -> (True)\n", - "Output dir: .//autogen/ -> (True)\n" - ] - } - ], - "source": [ - "# setup directories\n", - "import os\n", - "\n", - "# [CHANGE]\n", - "# Since we're running on a local environment (i hope)\n", - "# we can just signal a relative directory.\n", - "REPO_ROOT = './'\n", - "DOCS_ROOT = f'{REPO_ROOT}/docs/'\n", - "SRC_ROOT = f'{REPO_ROOT}/src/'\n", - "\n", - "# Where CPU.hpp lives — this is the file we will inject generated code into.\n", - "CPU_HPP_PATH = f'{SRC_ROOT}/spider/runtime/cpu/CPU.hpp'\n", - "\n", - "# Where the Excel instruction sheet lives. Allocate the .xlsx file in the project's root folder.\n", - "# NOTE: The file I uploaded has a space instead of underscore!\n", - "XLSX_PATH = f'{DOCS_ROOT}/Spider Instructions.xlsx'\n", - "\n", - "# Output folder for any standalone generated files.\n", - "OUT_DIR = f'{REPO_ROOT}/autogen/'\n", - "\n", - "# Create the output directory if it does not exist yet.\n", - "# exist_ok=True means no error if it already exists.\n", - "os.makedirs(OUT_DIR, exist_ok=True)\n", - "\n", - "def dir_exists(path:str):\n", - " return os.path.exists(path) and os.path.isdir(path)\n", - "def file_exists(path:str):\n", - " return os.path.exists(path) and os.path.isfile(path)\n", - "\n", - "print(f'Repo root : {REPO_ROOT } -> ({ dir_exists(REPO_ROOT )})')\n", - "print(f'CPU.hpp : {CPU_HPP_PATH} -> ({file_exists(CPU_HPP_PATH)})')\n", - "print(f'XLSX : {XLSX_PATH } -> ({file_exists(XLSX_PATH )})')\n", - "print(f'Output dir: {OUT_DIR } -> ({ dir_exists(OUT_DIR )})')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "b33de8ac", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--- Sample output for NOP ---\n", - " // [System] 0x000 — NOP: No Operation\n", - " // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n", - " // Operation: Nothing\n", - " void NOP();\n", - "\n" - ] - } - ], - "source": [ - "# Implement here some kind of \"C++\" printer\n", - "\n", - "# ── Indent used throughout the generated block ──────────────────────────────\n", - "INDENT = ' ' # 8 spaces — matches the indentation inside CPU.hpp\n", - "\n", - "def format_instruction(byte_code: str, mnemonic: str, name: str,\n", - " group: str, params: int,\n", - " addr_mask_1: str, addr_mask_2: str,\n", - " type_mask: str, operation: str) -> str:\n", - " \"\"\"\n", - " Returns a single C++ instruction declaration as a string.\n", - "\n", - " Each instruction becomes a commented constant inside the CPU class.\n", - " Format:\n", - " // [GROUP] 0xBYTE — MNEMONIC: Name\n", - " // Params: N | AddrMask1: XX AddrMask2: XX | TypeMask: XX\n", - " // Operation: ...\n", - " MNEMONIC\n", - " \"\"\"\n", - " lines = []\n", - "\n", - " # Header comment: group, opcode, mnemonic and human-readable name.\n", - " lines.append(f'{INDENT}// [{group}] 0x{byte_code} — {mnemonic}: {name}')\n", - "\n", - " # Second comment line: parameter count, addressing masks, type size mask.\n", - " lines.append(f'{INDENT}// Params: {params} | '\n", - " f'AddrMask1: {addr_mask_1} AddrMask2: {addr_mask_2} | '\n", - " f'TypeMask: {type_mask}')\n", - "\n", - " # Third comment line: what this instruction actually does.\n", - " lines.append(f'{INDENT}// Operation: {operation}')\n", - "\n", - " # The declaration itself — just the mnemonic name, matching NOP/SPDR style.\n", - " lines.append(f'{INDENT}void {mnemonic}();') # method declaration inside CPU class # enum value: NAME = 0xOPCODE,\n", - "\n", - " # Empty line between instructions for readability.\n", - " lines.append('')\n", - "\n", - " return '\\n'.join(lines)\n", - "\n", - "\n", - "def format_block(instructions: list) -> str:\n", - " \"\"\"\n", - " Joins all individual instruction strings into one complete block.\n", - " This is the text that will be injected between the pygen-target markers.\n", - " \"\"\"\n", - " # Join every formatted instruction into one big string.\n", - " return '\\n'.join(instructions)\n", - "\n", - "\n", - "# Print what one instruction looks like.\n", - "sample = format_instruction('000','NOP','No Operation','System',0,'00','00','00','Nothing')\n", - "print('--- Sample output for NOP ---')\n", - "print(sample)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "58645013", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Real instructions : 126\n", - "Reserved slots : 14\n", - "Duplicate check : PASSED\n", - "\n", - "Groups found:\n", - "group\n", - "Integer 19\n", - "System 15\n", - "Bit Wise 14\n", - "Boolean 12\n", - "Branch 12\n", - "Casts 10\n", - "Floating Point 10\n", - "Memory 9\n", - "Trigonometric 7\n", - "Exponential 6\n", - "Matrix 6\n", - "SIMD 5\n", - "Easter Eggs 1\n", - "\n", - "First 5 instructions:\n", - " byte_code mnemonic group params addr_mask_1 type_mask\n", - "0 000 NOP System 0 00 00\n", - "1 001 SPDR System 0 00 00\n", - "2 002 MMODE System 1 05 01\n", - "3 003 INT System 1 1F 0F\n", - "4 004 LRV System 1 1F 0C\n" - ] - } - ], - "source": [ - "# read the instruction sheet with pandas\n", - "\n", - "\n", - "import pandas as pd\n", - "\n", - "# -- Load --------------------------------------------------------------------\n", - "# The data is on the 'Instructions' sheet. Header is on row index 6 (0-based),\n", - "# so we skip the first 6 rows of decorative merged cells.\n", - "raw = pd.read_excel(XLSX_PATH, sheet_name='Instructions', header=6)\n", - "\n", - "# Rename the two unnamed columns that hold the two addressing mode masks.\n", - "# In the sheet they appear after 'Acc. Addr. Mode Mask' with no header label.\n", - "raw.columns = [\n", - " 'skip_0', # empty column A\n", - " 'skip_1', # 'Base Instr.' label column\n", - " 'byte_code', # opcode hex string e.g. '000'\n", - " 'mnemonic', # short name e.g. 'NOP'\n", - " 'name', # full name e.g. 'No Operation'\n", - " 'group', # category e.g. 'System'\n", - " 'params', # number of parameters (0, 1, or 2)\n", - " 'imp', # addressing mode: Implied\n", - " 'imm', # addressing mode: Immediate\n", - " 'abs', # addressing mode: Absolute\n", - " 'reg', # addressing mode: Register\n", - " 'ind', # addressing mode: Indirect\n", - " 'ptr', # addressing mode: Pointer\n", - " 'idx', # addressing mode: Indexed\n", - " 'sca', # addressing mode: Scaled\n", - " 'dis', # addressing mode: Displaced\n", - " 'addr_mask_1', # accepted addressing mode mask for param 1\n", - " 'addr_mask_2', # accepted addressing mode mask for param 2\n", - " 'B', # type size: Byte (1 byte) supported?\n", - " 'S', # type size: Short (2 bytes) supported?\n", - " 'I', # type size: Int (4 bytes) supported?\n", - " 'L', # type size: Long (8 bytes) supported?\n", - " 'F', # type size: Float supported?\n", - " 'D', # type size: Double supported?\n", - " 'type_mask', # combined type size mask as hex string\n", - " 'operation', # human-readable description of what the instruction does\n", - " 'skip_2', # trailing empty column\n", - "]\n", - "\n", - "# ── Filter ───────────────────────────────────────────────────────────────────\n", - "# Keep only rows that have a byte_code value (drops empty rows at the bottom).\n", - "df = raw[raw['byte_code'].notna()].copy()\n", - "\n", - "# Separate reserved slots from real instructions.\n", - "# Reserved entries have '(reserved)' in the mnemonic column.\n", - "is_reserved = df['mnemonic'].astype(str).str.contains('reserved', case=False, na=False)\n", - "reserved_df = df[is_reserved].copy() # keep for reference\n", - "instrs_df = df[~is_reserved & df['mnemonic'].notna()].copy() # real instructions only\n", - "\n", - "# Skip incomplete entries — rows with no group are placeholder slots (e.g. Int 1-6 Slot)\n", - "# that have no defined behaviour yet. Keeping them would generate invalid C++ identifiers.\n", - "instrs_df = instrs_df[instrs_df['group'].notna()].copy()\n", - "\n", - "# ── Clean ────────────────────────────────────────────────────────────────────\n", - "# Fill NaN masks with '00' (means 'no modes accepted' — safe default).\n", - "instrs_df['addr_mask_1'] = instrs_df['addr_mask_1'].fillna('00').astype(str).str.strip()\n", - "instrs_df['addr_mask_2'] = instrs_df['addr_mask_2'].fillna('00').astype(str).str.strip()\n", - "instrs_df['type_mask'] = instrs_df['type_mask'].fillna('00').astype(str).str.strip()\n", - "instrs_df['params'] = instrs_df['params'].fillna(0).astype(int)\n", - "instrs_df['name'] = instrs_df['name'].fillna('').astype(str).str.strip()\n", - "instrs_df['group'] = instrs_df['group'].fillna('Unknown').astype(str).str.strip()\n", - "instrs_df['operation'] = instrs_df['operation'].fillna('').astype(str).str.strip()\n", - "\n", - "# ── Sanitize mnemonics ──────────────────────────────────────────────────────\n", - "# C++ identifiers cannot contain spaces. Replace spaces with underscores and\n", - "# convert to uppercase so 'Int 1 Slot' becomes 'INT_1_SLOT'.\n", - "instrs_df['mnemonic'] = (\n", - " instrs_df['mnemonic']\n", - " .astype(str)\n", - " .str.strip() # remove leading/trailing whitespace\n", - " .str.replace(' ', '_') # replace internal spaces with underscores\n", - " .str.upper() # uppercase for consistency\n", - ")\n", - "\n", - "# ── Validate: duplicate mnemonics ────────────────────────────────────────────\n", - "# Duplicates in real instruction names would cause C++ compilation errors.\n", - "# We abort here rather than generating broken code.\n", - "mnemonic_counts = instrs_df['mnemonic'].value_counts()\n", - "duplicates = mnemonic_counts[mnemonic_counts > 1]\n", - "if not duplicates.empty:\n", - " # Show which mnemonics are duplicated before raising the error.\n", - " raise ValueError(f'Duplicate mnemonics found — fix the sheet before generating:\\n{duplicates}')\n", - "\n", - "print(f'Real instructions : {len(instrs_df)}')\n", - "print(f'Reserved slots : {len(reserved_df)}')\n", - "print(f'Duplicate check : PASSED')\n", - "print(f'\\nGroups found:')\n", - "print(instrs_df['group'].value_counts().to_string())\n", - "print(f'\\nFirst 5 instructions:')\n", - "print(instrs_df[['byte_code','mnemonic','group','params','addr_mask_1','type_mask']].head().to_string())\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "452bc76c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Masks written to: .//autogen/InstructionMasks.hpp\n", - "Lines generated : 268\n" - ] - } - ], - "source": [ - "# well, then export the masks (TODO)\n", - "\n", - "\n", - "# ── Build the masks header content ──────────────────────────────────────────\n", - "lines = []\n", - "\n", - "# Standard C++ header guard — prevents the file from being included more than once.\n", - "lines.append('#pragma once')\n", - "lines.append('// AUTO-GENERATED by pygen.ipynb — DO NOT EDIT MANUALLY')\n", - "lines.append('#include ')\n", - "lines.append('')\n", - "lines.append('namespace spider {')\n", - "lines.append('')\n", - "\n", - "# ── Addressing mode mask table ───────────────────────────────────────────────\n", - "# Each instruction has two masks (one per parameter).\n", - "# We write them as a constexpr array so the VM can look them up at runtime\n", - "# using the opcode as the index.\n", - "lines.append('// Addressing mode masks — indexed by opcode.')\n", - "lines.append('// [opcode][0] = mask for param 1, [opcode][1] = mask for param 2')\n", - "lines.append('constexpr u8 ADDR_MODE_MASKS[][2] = {')\n", - "\n", - "for _, row in instrs_df.iterrows():\n", - " # Convert the hex string mask to an integer for the C++ literal.\n", - " m1 = row['addr_mask_1'].replace('.0','').strip() # remove pandas float artefact\n", - " m2 = row['addr_mask_2'].replace('.0','').strip()\n", - " m1 = m1 if m1 != 'nan' else '00'\n", - " m2 = m2 if m2 != 'nan' else '00'\n", - " # Each row: { 0xMASK1, 0xMASK2 }, // MNEMONIC\n", - " lines.append(f' {{ 0x{m1.upper()}, 0x{m2.upper()} }}, // {row[\"mnemonic\"]}')\n", - "\n", - "lines.append('};')\n", - "lines.append('')\n", - "\n", - "# ── Type size mask table ─────────────────────────────────────────────────────\n", - "# A single byte per instruction encoding which type sizes it accepts.\n", - "lines.append('// Type size masks — indexed by opcode.')\n", - "lines.append('constexpr u8 TYPE_SIZE_MASKS[] = {')\n", - "\n", - "for _, row in instrs_df.iterrows():\n", - " tm = str(row['type_mask']).replace('.0','').strip()\n", - " tm = tm if tm != 'nan' else '00'\n", - " lines.append(f' 0x{tm.upper()}, // {row[\"mnemonic\"]}')\n", - "\n", - "lines.append('};')\n", - "lines.append('')\n", - "lines.append('} // namespace spider')\n", - "\n", - "# ── Write to file ────────────────────────────────────────────────────────────\n", - "masks_path = os.path.join(OUT_DIR, 'InstructionMasks.hpp')\n", - "with open(masks_path, 'w', encoding='utf-8') as f:\n", - " # Join with Unix line endings only — repo etiquette says no \\r\\n.\n", - " f.write('\\n'.join(lines))\n", - "\n", - "print(f'Masks written to: {masks_path}')\n", - "print(f'Lines generated : {len(lines)}')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "5aaebef0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Instructions formatted: 126\n", - "\n", - "--- Preview (first 2 instructions) ---\n", - " // [System] 0x000 — NOP: No Operation\n", - " // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n", - " // Operation: Nothing\n", - " void NOP();\n", - "\n", - " // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA\n", - " // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n", - " // Operation: (Spider Version) -> RA\n", - " void SPDR();\n", - "\n", - "\n", - "CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n", - "Total lines in updated file: 674\n" - ] - } - ], - "source": [ - "# print the CPU Instructions\n", - "\n", - "# ── Generate all instruction declarations ───────────────────────────────────\n", - "formatted = []\n", - "\n", - "for _, row in instrs_df.iterrows():\n", - " # Clean each field — remove pandas float artefacts like '00.0'\n", - " byte_code = str(row['byte_code']).strip()\n", - " mnemonic = str(row['mnemonic']).strip()\n", - " name = str(row['name']).strip()\n", - " group = str(row['group']).strip()\n", - " params = int(row['params'])\n", - " addr_mask_1 = str(row['addr_mask_1']).replace('.0', '').strip()\n", - " addr_mask_2 = str(row['addr_mask_2']).replace('.0', '').strip()\n", - " type_mask = str(row['type_mask']).replace('.0', '').strip()\n", - " operation = str(row['operation']).strip()\n", - "\n", - " # Call the C++ printer from Cell 2 to format this instruction.\n", - " formatted.append(format_instruction(\n", - " byte_code, mnemonic, name, group,\n", - " params, addr_mask_1, addr_mask_2,\n", - " type_mask, operation\n", - " ))\n", - "\n", - "# Combine all declarations into one block string.\n", - "generated_block = format_block(formatted)\n", - "\n", - "print(f'Instructions formatted: {len(formatted)}')\n", - "print('\\n--- Preview (first 2 instructions) ---')\n", - "print('\\n'.join(formatted[:2]))\n", - "\n", - "# ── Inject into CPU.hpp ──────────────────────────────────────────────────────\n", - "# The markers tell us exactly where to insert the generated block.\n", - "MARKER_OPEN = '// //'\n", - "MARKER_CLOSE = '// //'\n", - "\n", - "# Read the current CPU.hpp content.\n", - "with open(CPU_HPP_PATH, 'r', encoding='utf-8') as f:\n", - " original = f.read()\n", - "\n", - "# Verify both markers exist before modifying anything.\n", - "# If either is missing, the file was edited by hand — abort to avoid corruption.\n", - "if MARKER_OPEN not in original:\n", - " raise ValueError(f'Open marker not found in CPU.hpp: {MARKER_OPEN}')\n", - "if MARKER_CLOSE not in original:\n", - " raise ValueError(f'Close marker not found in CPU.hpp: {MARKER_CLOSE}')\n", - "\n", - "# Split the file into 3 parts around the pygen-target markers.\n", - "# before : everything up to and including the open marker\n", - "# after : from the close marker onward (including it)\n", - "before = original[:original.index(MARKER_OPEN) + len(MARKER_OPEN)]\n", - "after = original[original.index(MARKER_CLOSE):]\n", - "\n", - "# Reassemble: keep before, inject the generated block, then restore after.\n", - "updated = before + '\\n' + generated_block + '\\n' + INDENT + after\n", - "\n", - "# Write back using UTF-8 and Unix line endings only (repo etiquette: no \\r\\n).\n", - "with open(CPU_HPP_PATH, 'w', encoding='utf-8', newline='\\n') as f:\n", - " f.write(updated)\n", - "\n", - "print(f'\\nCPU.hpp updated successfully at: {CPU_HPP_PATH}')\n", - "print(f'Total lines in updated file: {len(updated.splitlines())}')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "21877801", + "metadata": {}, + "source": [ + "## Python Generator\n", + "\n", + "This python notebook will serve to generate the necessary code to\n", + "generate some things from Spider.\n", + "\n", + "Specifically, it will generate the CPU instructions (currently)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0fcd533", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Repo root : ./ -> (True)\n", + "CPU.hpp : .//src//spider/runtime/cpu/CPU.hpp -> (True)\n", + "XLSX : .//docs//Spider Instructions.xlsx -> (True)\n", + "Output dir: .//autogen/ -> (True)\n" + ] + } + ], + "source": [ + "# setup directories\n", + "import os\n", + "\n", + "# [CHANGE]\n", + "# Since we're running on a local environment (i hope)\n", + "# we can just signal a relative directory.\n", + "REPO_ROOT = './'\n", + "DOCS_ROOT = f'{REPO_ROOT}/docs/'\n", + "SRC_ROOT = f'{REPO_ROOT}/src/'\n", + "\n", + "# Where CPU.hpp lives — this is the file we will inject generated code into.\n", + "CPU_HPP_PATH = f'{SRC_ROOT}/spider/runtime/cpu/CPU.hpp'\n", + "\n", + "# Where the Excel instruction sheet lives. Allocate the .xlsx file in the project's root folder.\n", + "# NOTE: The file I uploaded has a space instead of underscore!\n", + "XLSX_PATH = f'{DOCS_ROOT}/Spider Instructions.xlsx'\n", + "\n", + "# Output folder for any standalone generated files.\n", + "OUT_DIR = f'{REPO_ROOT}/autogen/'\n", + "\n", + "# Create the output directory if it does not exist yet.\n", + "# exist_ok=True means no error if it already exists.\n", + "os.makedirs(OUT_DIR, exist_ok=True)\n", + "\n", + "def dir_exists(path:str):\n", + " return os.path.exists(path) and os.path.isdir(path)\n", + "def file_exists(path:str):\n", + " return os.path.exists(path) and os.path.isfile(path)\n", + "\n", + "print(f'Repo root : {REPO_ROOT } -> ({ dir_exists(REPO_ROOT )})')\n", + "print(f'CPU.hpp : {CPU_HPP_PATH} -> ({file_exists(CPU_HPP_PATH)})')\n", + "print(f'XLSX : {XLSX_PATH } -> ({file_exists(XLSX_PATH )})')\n", + "print(f'Output dir: {OUT_DIR } -> ({ dir_exists(OUT_DIR )})')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b33de8ac", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- Sample output for NOP ---\n", + " // [System] 0x000 — NOP: No Operation\n", + " // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n", + " // Operation: Nothing\n", + " void NOP();\n", + "\n" + ] + } + ], + "source": [ + "# Implement here some kind of \"C++\" printer\n", + "\n", + "# ── Indent used throughout the generated block ──────────────────────────────\n", + "INDENT = ' ' # 8 spaces — matches the indentation inside CPU.hpp\n", + "\n", + "def format_instruction(byte_code: str, mnemonic: str, name: str,\n", + " group: str, params: int,\n", + " addr_mask_1: str, addr_mask_2: str,\n", + " type_mask: str, operation: str) -> str:\n", + " \"\"\"\n", + " Returns a single C++ instruction declaration as a string.\n", + "\n", + " Each instruction becomes a commented constant inside the CPU class.\n", + " Format:\n", + " // [GROUP] 0xBYTE — MNEMONIC: Name\n", + " // Params: N | AddrMask1: XX AddrMask2: XX | TypeMask: XX\n", + " // Operation: ...\n", + " MNEMONIC\n", + " \"\"\"\n", + " lines = []\n", + "\n", + " # Header comment: group, opcode, mnemonic and human-readable name.\n", + " lines.append(f'{INDENT}// [{group}] 0x{byte_code} — {mnemonic}: {name}')\n", + "\n", + " # Second comment line: parameter count, addressing masks, type size mask.\n", + " lines.append(f'{INDENT}// Params: {params} | '\n", + " f'AddrMask1: {addr_mask_1} AddrMask2: {addr_mask_2} | '\n", + " f'TypeMask: {type_mask}')\n", + "\n", + " # Third comment line: what this instruction actually does.\n", + " lines.append(f'{INDENT}// Operation: {operation}')\n", + "\n", + " # The declaration itself — just the mnemonic name, matching NOP/SPDR style.\n", + " lines.append(f'{INDENT}void {mnemonic}();') # method declaration inside CPU class # enum value: NAME = 0xOPCODE,\n", + "\n", + " # Empty line between instructions for readability.\n", + " lines.append('')\n", + "\n", + " return '\\n'.join(lines)\n", + "\n", + "\n", + "def format_block(instructions: list) -> str:\n", + " \"\"\"\n", + " Joins all individual instruction strings into one complete block.\n", + " This is the text that will be injected between the pygen-target markers.\n", + " \"\"\"\n", + " # Join every formatted instruction into one big string.\n", + " return '\\n'.join(instructions)\n", + "\n", + "\n", + "# Print what one instruction looks like.\n", + "sample = format_instruction('000','NOP','No Operation','System',0,'00','00','00','Nothing')\n", + "print('--- Sample output for NOP ---')\n", + "print(sample)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "58645013", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Real instructions : 126\n", + "Reserved slots : 14\n", + "Duplicate check : PASSED\n", + "\n", + "Groups found:\n", + "group\n", + "Integer 19\n", + "System 15\n", + "Bit Wise 14\n", + "Boolean 12\n", + "Branch 12\n", + "Casts 10\n", + "Floating Point 10\n", + "Memory 9\n", + "Trigonometric 7\n", + "Exponential 6\n", + "Matrix 6\n", + "SIMD 5\n", + "Easter Eggs 1\n", + "\n", + "First 5 instructions:\n", + " byte_code mnemonic group params addr_mask_1 type_mask\n", + "0 000 NOP System 0 00 00\n", + "1 001 SPDR System 0 00 00\n", + "2 002 MMODE System 1 05 01\n", + "3 003 INT System 1 1F 0F\n", + "4 004 LRV System 1 1F 0C\n" + ] + } + ], + "source": [ + "# read the instruction sheet with pandas\n", + "\n", + "\n", + "import pandas as pd\n", + "\n", + "# -- Load --------------------------------------------------------------------\n", + "# The data is on the 'Instructions' sheet. Header is on row index 6 (0-based),\n", + "# so we skip the first 6 rows of decorative merged cells.\n", + "raw = pd.read_excel(XLSX_PATH, sheet_name='Instructions', header=6)\n", + "\n", + "# Rename the two unnamed columns that hold the two addressing mode masks.\n", + "# In the sheet they appear after 'Acc. Addr. Mode Mask' with no header label.\n", + "raw.columns = [\n", + " 'skip_0', # empty column A\n", + " 'skip_1', # 'Base Instr.' label column\n", + " 'byte_code', # opcode hex string e.g. '000'\n", + " 'mnemonic', # short name e.g. 'NOP'\n", + " 'name', # full name e.g. 'No Operation'\n", + " 'group', # category e.g. 'System'\n", + " 'params', # number of parameters (0, 1, or 2)\n", + " 'imp', # addressing mode: Implied\n", + " 'imm', # addressing mode: Immediate\n", + " 'abs', # addressing mode: Absolute\n", + " 'reg', # addressing mode: Register\n", + " 'ind', # addressing mode: Indirect\n", + " 'ptr', # addressing mode: Pointer\n", + " 'idx', # addressing mode: Indexed\n", + " 'sca', # addressing mode: Scaled\n", + " 'dis', # addressing mode: Displaced\n", + " 'addr_mask_1', # accepted addressing mode mask for param 1\n", + " 'addr_mask_2', # accepted addressing mode mask for param 2\n", + " 'B', # type size: Byte (1 byte) supported?\n", + " 'S', # type size: Short (2 bytes) supported?\n", + " 'I', # type size: Int (4 bytes) supported?\n", + " 'L', # type size: Long (8 bytes) supported?\n", + " 'F', # type size: Float supported?\n", + " 'D', # type size: Double supported?\n", + " 'type_mask', # combined type size mask as hex string\n", + " 'operation', # human-readable description of what the instruction does\n", + " 'skip_2', # trailing empty column\n", + "]\n", + "\n", + "# ── Filter ───────────────────────────────────────────────────────────────────\n", + "# Keep only rows that have a byte_code value (drops empty rows at the bottom).\n", + "df = raw[raw['byte_code'].notna()].copy()\n", + "\n", + "# Separate reserved slots from real instructions.\n", + "# Reserved entries have '(reserved)' in the mnemonic column.\n", + "is_reserved = df['mnemonic'].astype(str).str.contains('reserved', case=False, na=False)\n", + "reserved_df = df[is_reserved].copy() # keep for reference\n", + "instrs_df = df[~is_reserved & df['mnemonic'].notna()].copy() # real instructions only\n", + "\n", + "# Skip incomplete entries — rows with no group are placeholder slots (e.g. Int 1-6 Slot)\n", + "# that have no defined behaviour yet. Keeping them would generate invalid C++ identifiers.\n", + "instrs_df = instrs_df[instrs_df['group'].notna()].copy()\n", + "\n", + "# ── Clean ────────────────────────────────────────────────────────────────────\n", + "# Fill NaN masks with '00' (means 'no modes accepted' — safe default).\n", + "instrs_df['addr_mask_1'] = instrs_df['addr_mask_1'].fillna('00').astype(str).str.strip()\n", + "instrs_df['addr_mask_2'] = instrs_df['addr_mask_2'].fillna('00').astype(str).str.strip()\n", + "instrs_df['type_mask'] = instrs_df['type_mask'].fillna('00').astype(str).str.strip()\n", + "instrs_df['params'] = instrs_df['params'].fillna(0).astype(int)\n", + "instrs_df['name'] = instrs_df['name'].fillna('').astype(str).str.strip()\n", + "instrs_df['group'] = instrs_df['group'].fillna('Unknown').astype(str).str.strip()\n", + "instrs_df['operation'] = instrs_df['operation'].fillna('').astype(str).str.strip()\n", + "\n", + "# ── Sanitize mnemonics ──────────────────────────────────────────────────────\n", + "# C++ identifiers cannot contain spaces. Replace spaces with underscores and\n", + "# convert to uppercase so 'Int 1 Slot' becomes 'INT_1_SLOT'.\n", + "instrs_df['mnemonic'] = (\n", + " instrs_df['mnemonic']\n", + " .astype(str)\n", + " .str.strip() # remove leading/trailing whitespace\n", + " .str.replace(' ', '_') # replace internal spaces with underscores\n", + " .str.upper() # uppercase for consistency\n", + ")\n", + "\n", + "# ── Validate: duplicate mnemonics ────────────────────────────────────────────\n", + "# Duplicates in real instruction names would cause C++ compilation errors.\n", + "# We abort here rather than generating broken code.\n", + "mnemonic_counts = instrs_df['mnemonic'].value_counts()\n", + "duplicates = mnemonic_counts[mnemonic_counts > 1]\n", + "if not duplicates.empty:\n", + " # Show which mnemonics are duplicated before raising the error.\n", + " raise ValueError(f'Duplicate mnemonics found — fix the sheet before generating:\\n{duplicates}')\n", + "\n", + "print(f'Real instructions : {len(instrs_df)}')\n", + "print(f'Reserved slots : {len(reserved_df)}')\n", + "print(f'Duplicate check : PASSED')\n", + "print(f'\\nGroups found:')\n", + "print(instrs_df['group'].value_counts().to_string())\n", + "print(f'\\nFirst 5 instructions:')\n", + "print(instrs_df[['byte_code','mnemonic','group','params','addr_mask_1','type_mask']].head().to_string())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "452bc76c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Masks written to: .//autogen/InstructionMasks.hpp\n", + "Lines generated : 268\n" + ] + } + ], + "source": [ + "# well, then export the masks (TODO)\n", + "\n", + "\n", + "# ── Build the masks header content ──────────────────────────────────────────\n", + "lines = []\n", + "\n", + "# Standard C++ header guard — prevents the file from being included more than once.\n", + "lines.append('#pragma once')\n", + "lines.append('// AUTO-GENERATED by pygen.ipynb — DO NOT EDIT MANUALLY')\n", + "lines.append('#include ')\n", + "lines.append('')\n", + "lines.append('namespace spider {')\n", + "lines.append('')\n", + "\n", + "# ── Addressing mode mask table ───────────────────────────────────────────────\n", + "# Each instruction has two masks (one per parameter).\n", + "# We write them as a constexpr array so the VM can look them up at runtime\n", + "# using the opcode as the index.\n", + "lines.append('// Addressing mode masks — indexed by opcode.')\n", + "lines.append('// [opcode][0] = mask for param 1, [opcode][1] = mask for param 2')\n", + "lines.append('constexpr u8 ADDR_MODE_MASKS[][2] = {')\n", + "\n", + "for _, row in instrs_df.iterrows():\n", + " # Convert the hex string mask to an integer for the C++ literal.\n", + " m1 = row['addr_mask_1'].replace('.0','').strip() # remove pandas float artefact\n", + " m2 = row['addr_mask_2'].replace('.0','').strip()\n", + " m1 = m1 if m1 != 'nan' else '00'\n", + " m2 = m2 if m2 != 'nan' else '00'\n", + " # Each row: { 0xMASK1, 0xMASK2 }, // MNEMONIC\n", + " lines.append(f' {{ 0x{m1.upper()}, 0x{m2.upper()} }}, // {row[\"mnemonic\"]}')\n", + "\n", + "lines.append('};')\n", + "lines.append('')\n", + "\n", + "# ── Type size mask table ─────────────────────────────────────────────────────\n", + "# A single byte per instruction encoding which type sizes it accepts.\n", + "lines.append('// Type size masks — indexed by opcode.')\n", + "lines.append('constexpr u8 TYPE_SIZE_MASKS[] = {')\n", + "\n", + "for _, row in instrs_df.iterrows():\n", + " tm = str(row['type_mask']).replace('.0','').strip()\n", + " tm = tm if tm != 'nan' else '00'\n", + " lines.append(f' 0x{tm.upper()}, // {row[\"mnemonic\"]}')\n", + "\n", + "lines.append('};')\n", + "lines.append('')\n", + "lines.append('} // namespace spider')\n", + "\n", + "# ── Write to file ────────────────────────────────────────────────────────────\n", + "masks_path = os.path.join(OUT_DIR, 'InstructionMasks.hpp')\n", + "with open(masks_path, 'w', encoding='utf-8') as f:\n", + " # Join with Unix line endings only — repo etiquette says no \\r\\n.\n", + " f.write('\\n'.join(lines))\n", + "\n", + "print(f'Masks written to: {masks_path}')\n", + "print(f'Lines generated : {len(lines)}')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5aaebef0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Instructions formatted: 126\n", + "\n", + "--- Preview (first 2 instructions) ---\n", + " // [System] 0x000 — NOP: No Operation\n", + " // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n", + " // Operation: Nothing\n", + " void NOP();\n", + "\n", + " // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA\n", + " // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n", + " // Operation: (Spider Version) -> RA\n", + " void SPDR();\n", + "\n", + "\n", + "CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n", + "Total lines in updated file: 674\n" + ] + } + ], + "source": [ + "# print the CPU Instructions\n", + "\n", + "# ── Generate all instruction declarations ───────────────────────────────────\n", + "formatted = []\n", + "\n", + "for _, row in instrs_df.iterrows():\n", + " # Clean each field — remove pandas float artefacts like '00.0'\n", + " byte_code = str(row['byte_code']).strip()\n", + " mnemonic = str(row['mnemonic']).strip()\n", + " name = str(row['name']).strip()\n", + " group = str(row['group']).strip()\n", + " params = int(row['params'])\n", + " addr_mask_1 = str(row['addr_mask_1']).replace('.0', '').strip()\n", + " addr_mask_2 = str(row['addr_mask_2']).replace('.0', '').strip()\n", + " type_mask = str(row['type_mask']).replace('.0', '').strip()\n", + " operation = str(row['operation']).strip()\n", + "\n", + " # Call the C++ printer from Cell 2 to format this instruction.\n", + " formatted.append(format_instruction(\n", + " byte_code, mnemonic, name, group,\n", + " params, addr_mask_1, addr_mask_2,\n", + " type_mask, operation\n", + " ))\n", + "\n", + "# Combine all declarations into one block string.\n", + "generated_block = format_block(formatted)\n", + "\n", + "print(f'Instructions formatted: {len(formatted)}')\n", + "print('\\n--- Preview (first 2 instructions) ---')\n", + "print('\\n'.join(formatted[:2]))\n", + "\n", + "# ── Inject into CPU.hpp ──────────────────────────────────────────────────────\n", + "# The markers tell us exactly where to insert the generated block.\n", + "MARKER_OPEN = '// //'\n", + "MARKER_CLOSE = '// //'\n", + "\n", + "# Read the current CPU.hpp content.\n", + "with open(CPU_HPP_PATH, 'r', encoding='utf-8') as f:\n", + " original = f.read()\n", + "\n", + "# Verify both markers exist before modifying anything.\n", + "# If either is missing, the file was edited by hand — abort to avoid corruption.\n", + "if MARKER_OPEN not in original:\n", + " raise ValueError(f'Open marker not found in CPU.hpp: {MARKER_OPEN}')\n", + "if MARKER_CLOSE not in original:\n", + " raise ValueError(f'Close marker not found in CPU.hpp: {MARKER_CLOSE}')\n", + "\n", + "# Split the file into 3 parts around the pygen-target markers.\n", + "# before : everything up to and including the open marker\n", + "# after : from the close marker onward (including it)\n", + "before = original[:original.index(MARKER_OPEN) + len(MARKER_OPEN)]\n", + "after = original[original.index(MARKER_CLOSE):]\n", + "\n", + "# Reassemble: keep before, inject the generated block, then restore after.\n", + "updated = before + '\\n' + generated_block + '\\n' + INDENT + after\n", + "\n", + "# Write back using UTF-8 and Unix line endings only (repo etiquette: no \\r\\n).\n", + "with open(CPU_HPP_PATH, 'w', encoding='utf-8', newline='\\n') as f:\n", + " f.write(updated)\n", + "\n", + "print(f'\\nCPU.hpp updated successfully at: {CPU_HPP_PATH}')\n", + "print(f'Total lines in updated file: {len(updated.splitlines())}')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/spider-runtime.code-workspace b/spider-runtime.code-workspace index 07b9241..18175fd 100644 --- a/spider-runtime.code-workspace +++ b/spider-runtime.code-workspace @@ -1,21 +1,21 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "gitlens.remotes": [ - { - "domain": "git.sintekanalytics.com", - "type": "Gitea", - "name": "Sintek Analytics' Git", - "protocol": "https", - } - ], - "C_Cpp.default.includePath": [ - "./src" - ], - "terminal.integrated.defaultProfile.windows": "MSYS2 UCRT" - } +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "gitlens.remotes": [ + { + "domain": "git.sintekanalytics.com", + "type": "Gitea", + "name": "Sintek Analytics' Git", + "protocol": "https", + } + ], + "C_Cpp.default.includePath": [ + "./src" + ], + "terminal.integrated.defaultProfile.windows": "MSYS2 UCRT" + } } \ No newline at end of file diff --git a/src/spider/SpiderRuntime.cpp b/src/spider/SpiderRuntime.cpp index cffd95a..7c119f8 100644 --- a/src/spider/SpiderRuntime.cpp +++ b/src/spider/SpiderRuntime.cpp @@ -1,16 +1,16 @@ -#include "SpiderRuntime.hpp" - -#include - -#include - -namespace spider { - - - -} - -int main() { - spider::liveDebugMain(); - return 0; -} +#include "SpiderRuntime.hpp" + +#include + +#include + +namespace spider { + + + +} + +int main() { + spider::liveDebugMain(); + return 0; +} diff --git a/src/spider/SpiderRuntime.hpp b/src/spider/SpiderRuntime.hpp index 6f87fd0..2ae56f5 100644 --- a/src/spider/SpiderRuntime.hpp +++ b/src/spider/SpiderRuntime.hpp @@ -1,12 +1,12 @@ -#pragma once - -#include - -namespace spider { - - class Runtime; - class CPU; - class RAM; - class InstrReel; - -} +#pragma once + +#include + +namespace spider { + + class Runtime; + class CPU; + class RAM; + class InstrReel; + +} diff --git a/src/spider/main_esp32.cpp b/src/spider/main_esp32.cpp new file mode 100644 index 0000000..024b35f --- /dev/null +++ b/src/spider/main_esp32.cpp @@ -0,0 +1,8 @@ +// ESP32 entry point for Spider Runtime +// This replaces SpiderRuntime.cpp for microcontroller builds +#include "SpiderRuntime.hpp" + +int main() { + // TODO: initialize Spider runtime for ESP32 + return 0; +} diff --git a/src/spider/runtime/Runtime.cpp b/src/spider/runtime/Runtime.cpp index 461f093..f51e675 100644 --- a/src/spider/runtime/Runtime.cpp +++ b/src/spider/runtime/Runtime.cpp @@ -1,29 +1,29 @@ -#include "Runtime.hpp" - -namespace spider { - - // Constructors & Destructors // - - Runtime::Runtime() : ram(0) {} - - Runtime::Runtime(u64 ramSize) : ram(ramSize) {} - - Runtime::~Runtime() {} - - // Stepping/Running the Machine // - - void Runtime::step() {} - - void Runtime::step(u64 n) {} - - void Runtime::run() {} - - void Runtime::run(u64 n) {} - - // Misc // - - void Runtime::resizeRAM(u64 length) { - ram.resize(length); - } - -} +#include "Runtime.hpp" + +namespace spider { + + // Constructors & Destructors // + + Runtime::Runtime() : ram(0) {} + + Runtime::Runtime(u64 ramSize) : ram(ramSize) {} + + Runtime::~Runtime() {} + + // Stepping/Running the Machine // + + void Runtime::step() {} + + void Runtime::step(u64 n) {} + + void Runtime::run() {} + + void Runtime::run(u64 n) {} + + // Misc // + + void Runtime::resizeRAM(u64 length) { + ram.resize(length); + } + +} diff --git a/src/spider/runtime/Runtime.hpp b/src/spider/runtime/Runtime.hpp index 6541690..b76a1a5 100644 --- a/src/spider/runtime/Runtime.hpp +++ b/src/spider/runtime/Runtime.hpp @@ -1,73 +1,73 @@ -#pragma once - -#include -#include - -namespace spider { - - /** - * The main runtime class. - * This is where the Spider VM (Runtime) lives - */ - class Runtime { - public: - - CPU cpu; - RAM ram; - - public: - - /** - * Creates a new runtime, with no memory. - */ - Runtime(); - - /** - * Creates a new runtime, with a specific - * amount of memory. - */ - Runtime(u64 ramSize); - - /** - * Runtime Destructor. - */ - ~Runtime(); - - public: - - /** - * Steps the clock of the VM once. - */ - void step(); - - /** - * Steps n-times the clock of the VM. - */ - void step(u64 n); - - public: - - /** - * Sets the machine to run continously. - * If interrupts occur, they will be handled - * automatically. - */ - void run(); - - /** - * Runs this machine for a set amount of - * milliseconds. - */ - void run(u64 ms); - - public: - - /** - * Resizes the ram, which will preserve - * data inside the next length. - */ - void resizeRAM(u64 length); - - }; - -} +#pragma once + +#include +#include + +namespace spider { + + /** + * The main runtime class. + * This is where the Spider VM (Runtime) lives + */ + class Runtime { + public: + + CPU cpu; + RAM ram; + + public: + + /** + * Creates a new runtime, with no memory. + */ + Runtime(); + + /** + * Creates a new runtime, with a specific + * amount of memory. + */ + Runtime(u64 ramSize); + + /** + * Runtime Destructor. + */ + ~Runtime(); + + public: + + /** + * Steps the clock of the VM once. + */ + void step(); + + /** + * Steps n-times the clock of the VM. + */ + void step(u64 n); + + public: + + /** + * Sets the machine to run continously. + * If interrupts occur, they will be handled + * automatically. + */ + void run(); + + /** + * Runs this machine for a set amount of + * milliseconds. + */ + void run(u64 ms); + + public: + + /** + * Resizes the ram, which will preserve + * data inside the next length. + */ + void resizeRAM(u64 length); + + }; + +} diff --git a/src/spider/runtime/common.hpp b/src/spider/runtime/common.hpp index 3507fc0..a1b536f 100644 --- a/src/spider/runtime/common.hpp +++ b/src/spider/runtime/common.hpp @@ -1,38 +1,38 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace spider { - - // Absolute Types - using u8 = std::uint8_t; - using u16 = std::uint16_t; - using u32 = std::uint32_t; - using u64 = std::uint64_t; - - using i8 = std::int8_t; - using i16 = std::int16_t; - using i32 = std::int32_t; - using i64 = std::int64_t; - - using f32 = float; // TODO: SPIDER_EMULATE_FLOAT will control this - using f64 = double; - - // TODO: Check if we're on C++23, there is already stdfloat - static_assert(sizeof(f32) == 4, "The f32 type must be exactly 4 bytes."); - static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes."); - - // Utility types - using isize = std::size_t; - - // Utility imports - using std::vector; - using std::deque; - using std::map; - using std::optional; - -} +#pragma once + +#include +#include +#include +#include +#include + +namespace spider { + + // Absolute Types + using u8 = std::uint8_t; + using u16 = std::uint16_t; + using u32 = std::uint32_t; + using u64 = std::uint64_t; + + using i8 = std::int8_t; + using i16 = std::int16_t; + using i32 = std::int32_t; + using i64 = std::int64_t; + + using f32 = float; // TODO: SPIDER_EMULATE_FLOAT will control this + using f64 = double; + + // TODO: Check if we're on C++23, there is already stdfloat + static_assert(sizeof(f32) == 4, "The f32 type must be exactly 4 bytes."); + static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes."); + + // Utility types + using isize = std::size_t; + + // Utility imports + using std::vector; + using std::deque; + using std::map; + using std::optional; + +} diff --git a/src/spider/runtime/cpu/CPU.cpp b/src/spider/runtime/cpu/CPU.cpp index 843e7a9..65a2dd8 100644 --- a/src/spider/runtime/cpu/CPU.cpp +++ b/src/spider/runtime/cpu/CPU.cpp @@ -1,111 +1,111 @@ -#include "CPU.hpp" - -#include - -#include - -#include - -#if __cplusplus >= 202002L -#include -#endif - -namespace spider { - - CPU::CPU() - : RA{}, RB{}, RC{}, RD{}, - RX{}, RY{}, R0{}, R1{}, - R2{}, R3{}, R4{}, R5{}, - R6{}, R7{}, R8{}, R9{}, - RF{}, RI{}, RS{}, RZ{}, - RE{}, RN{}, RV{}, RM{}, - ALU0{}, ALU1{}, - _ram(nullptr), _reel(nullptr) { - } - - CPU::~CPU() {} - - // Setup & Configuration // - - void CPU::hookRAM(RAM* ram) { - this->_ram = ram; - } - - void CPU::hookInstrReel(InstrReel* reel) { - this->_reel = reel; - } - - constexpr u64 CPU::getFlag(u64 mask) { - if (!mask) return 0; -#if __cplusplus >= 202002L - return (RF & mask) >> std::countr_zero(mask); -#elif defined(SPIDER_COMPILER_GCC_LIKE) - return (RF & mask) >> __builtin_ctzll(mask); -#elif defined(SPIDER_COMPILER_MSVC) - return (RF & mask) >> _BitScanForward64(mask); -#else - // If you have reached this part, - // please come up with a better alternative. - u64 bits = RF & mask; - while (mask && (mask >>= 1)) bits >>= 1; - return bits; -#endif - } - - // Addressing Modes // - - /** - * Implied Addressing Mode - */ - void CPU::imp() { - // Nothing // - } - - /** - * Immediate Addressing Mode - */ - void CPU::imm() { - u8 size = 2 << _size; - _next = &ALU0; - } - - /** - * Absolute Addressing Mode - */ - void CPU::abs() { - u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE); - } - - /** - * Register Addressing Mode - */ - void CPU::reg() { - sizeof(CPU); - } - - /** - * Indrect Addressing Mode - */ - void CPU::ind() {} - - /** - * Pointer Addressing Mode - */ - void CPU::ptr() {} - - /** - * Indexed Addressing Mode - */ - void CPU::idx() {} - - /** - * Scaled Addressing Mode - */ - void CPU::sca() {} - - /** - * Displaced Addressing Mode - */ - void CPU::dis() {} - -} +#include "CPU.hpp" + +#include + +#include + +#include + +#if __cplusplus >= 202002L +#include +#endif + +namespace spider { + + CPU::CPU() + : RA{}, RB{}, RC{}, RD{}, + RX{}, RY{}, R0{}, R1{}, + R2{}, R3{}, R4{}, R5{}, + R6{}, R7{}, R8{}, R9{}, + RF{}, RI{}, RS{}, RZ{}, + RE{}, RN{}, RV{}, RM{}, + ALU0{}, ALU1{}, + _ram(nullptr), _reel(nullptr) { + } + + CPU::~CPU() {} + + // Setup & Configuration // + + void CPU::hookRAM(RAM* ram) { + this->_ram = ram; + } + + void CPU::hookInstrReel(InstrReel* reel) { + this->_reel = reel; + } + + constexpr u64 CPU::getFlag(u64 mask) { + if (!mask) return 0; +#if __cplusplus >= 202002L + return (RF & mask) >> std::countr_zero(mask); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + return (RF & mask) >> __builtin_ctzll(mask); +#elif defined(SPIDER_COMPILER_MSVC) + return (RF & mask) >> _BitScanForward64(mask); +#else + // If you have reached this part, + // please come up with a better alternative. + u64 bits = RF & mask; + while (mask && (mask >>= 1)) bits >>= 1; + return bits; +#endif + } + + // Addressing Modes // + + /** + * Implied Addressing Mode + */ + void CPU::imp() { + // Nothing // + } + + /** + * Immediate Addressing Mode + */ + void CPU::imm() { + u8 size = 2 << _size; + _next = &ALU0; + } + + /** + * Absolute Addressing Mode + */ + void CPU::abs() { + u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE); + } + + /** + * Register Addressing Mode + */ + void CPU::reg() { + sizeof(CPU); + } + + /** + * Indrect Addressing Mode + */ + void CPU::ind() {} + + /** + * Pointer Addressing Mode + */ + void CPU::ptr() {} + + /** + * Indexed Addressing Mode + */ + void CPU::idx() {} + + /** + * Scaled Addressing Mode + */ + void CPU::sca() {} + + /** + * Displaced Addressing Mode + */ + void CPU::dis() {} + +} diff --git a/src/spider/runtime/cpu/CPU.hpp b/src/spider/runtime/cpu/CPU.hpp index 7bba16f..df4ac1e 100644 --- a/src/spider/runtime/cpu/CPU.hpp +++ b/src/spider/runtime/cpu/CPU.hpp @@ -1,782 +1,782 @@ -#pragma once - -#include -#include - -namespace spider { - - class CPU { - public: // Flag Register Constants // - static constexpr const u64 FLAG_ENABLE = 0b0000000000000000000000000000000000000000000000000000000000000001; - static constexpr const u64 FLAG_INTERRUPT_SIGNAL = 0b0000000000000000000000000000000000000000000000000000000000000010; - static constexpr const u64 FLAG_INTERRUPT_REQUEST = 0b0000000000000000000000000000000000000000000000000000000000000100; - static constexpr const u64 FLAG_EXCEPTION = 0b0000000000000000000000000000000000000000000000000000000000001000; - static constexpr const u64 FLAG_MEMORY_MODE = 0b0000000000000000000000000000000000000000000000000000000000110000; - - public: // General Purpose Registers - union { - register_t GPR[16]; - struct { - register_t RA, RB, RC, RD, - RX, RY, R0, R1, - R2, R3, R4, R5, - R6, R7, R8, R9; - }; - }; - - public: // System Registers - u64 RF; - u64 RI; - u64 RS; - u64 RZ; - u64 RE; - u64 RN; // Epsilo(n) - u64 RV; - u64 RM; - - public: - - /** - * These are private registers, which are only used - * whenever constant things are used. - * This way we don't "write" into constant values, rather - * we write into a writeable var which is "hidden" - */ - register_t ALU0, ALU1; - - private: - - /** - * Pointer to the current RAM hooked into - * the CPU. - * - * It is unproved whether having the RAM directly - * into the CPU is better than not, or whether a - * virtual BUS is better. - * - * Alas, this way we can have a CPU state switch - * between memory and instruction banks. - */ - RAM* _ram; - - /** - * Pointer to the current Instruction Reel - * hooked into the CPU. - * - * Ditto as RAM. - */ - InstrReel* _reel; - - register_t* _next; - u8 _addrm : 6; - u8 _size : 2; - - public: - - CPU(); - - CPU(const CPU& other) = default; - - CPU(CPU&& other) noexcept = default; - - ~CPU(); - - public: - - CPU& operator=(const CPU& other) = default; - - CPU& operator=(CPU&& other) noexcept = default; - - public: - - void hookRAM(RAM* ram); - - void hookInstrReel(InstrReel* reel); - - constexpr u64 getFlag(u64 mask); - - public: // Addressing Modes - - /** - * Implied Addressing Mode - */ - void imp(); - - /** - * Immediate Addressing Mode - */ - void imm(); - - /** - * Absolute Addressing Mode - */ - void abs(); - - /** - * Register Addressing Mode - */ - void reg(); - - /** - * Indrect Addressing Mode - */ - void ind(); - - /** - * Pointer Addressing Mode - */ - void ptr(); - - /** - * Indexed Addressing Mode - */ - void idx(); - - /** - * Scaled Addressing Mode - */ - void sca(); - - /** - * Displaced Addressing Mode - */ - void dis(); - - public: - - // // - // [System] 0x000 — NOP: No Operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Nothing - void NOP(); - - // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (Spider Version) -> RA - void SPDR(); - - // [System] 0x002 — MMODE: Set Memory Mode - // Params: 1 | AddrMask1: 05 AddrMask2: 00 | TypeMask: 01 - // Operation: Dst -> Memory Mode Bits - void MMODE(); - - // [System] 0x003 — INT: Interrupt - // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0F - // Operation: Performs system interrupt no. (Dst) (See table) - void INT(); - - // [System] 0x004 — LRV: Load Interrupt Vector Register - // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0C - // Operation: Dst -> RV - void LRV(); - - // [System] 0x005 — FSR: Fetch System Register - // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F - // Operation: System Register at Dst -> Dst - void FSR(); - - // [System] 0x006 — FIR: Fetch Instruction Register - // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F - // Operation: Instruction Register -> Dst - void FIR(); - - // [System] 0x007 — FZR: Fetch Stack Base Register - // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F - // Operation: Stack Base Register -> Dst - void FZR(); - - // [System] 0x008 — LSR: Load System Register - // Params: 2 | AddrMask1: 1E AddrMask2: 1F | TypeMask: 0F - // Operation: Src -> System Register at Dst - void LSR(); - - // [System] 0x009 — FVR: Fetch Interrupt Vector Register - // Params: 1 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Interrupt Vector Register -> Dst - void FVR(); - - // [Memory] 0x00A — MOV: Moves values - // Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Src -> Dst - void MOV(); - - // [Memory] 0x00B — MOR: Moves registers - // Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: R Scr -> R Dst - void MOR(); - - // [Memory] 0x00C — AMOV: Array Move, uses X and Y as ptrs, A as amount - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Array from X to Y, by A amount - void AMOV(); - - // [Memory] 0x00D — SWP: Swap registers - // Params: 2 | AddrMask1: 04 AddrMask2: 04 | TypeMask: 00 - // Operation: Src <-> Dst - void SWP(); - - // [Memory] 0x00E — AHM: Ask Host for Memory - // Params: 1 | AddrMask1: 04 AddrMask2: 00 | TypeMask: 0F - // Operation: Asks the host for a specific size of memory. Responds with 0 or 1 - void AHM(); - - // [Integer] 0x010 — COM: One's complement - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: ~ Dst -> Dst - void COM(); - - // [Integer] 0x011 — NEG: Two's complement - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: - Dst -> Dst - void NEG(); - - // [Integer] 0x012 — EXS: Extend Sign - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Last bit is copied and expanded for the next int size - void EXS(); - - // [Integer] 0x013 — INC: Increment - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst + 1 -> Dst - void INC(); - - // [Integer] 0x014 — DEC: Decrement - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst - 1 -> Dst - void DEC(); - - // [Integer] 0x015 — ADD: Addition - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst + Src -> Dst - void ADD(); - - // [Integer] 0x016 — SUB: Subtraction - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst - Src-> Dst - void SUB(); - - // [Integer] 0x017 — MUL: Multiplication - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Signed Dst * Src -> Dst - void MUL(); - - // [Integer] 0x018 — UMUL: Unsigned Multiplication - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Unsigned Dst * Src -> Dst - void UMUL(); - - // [Integer] 0x019 — DIV: Division - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Signed Dst / Src -> Dst - void DIV(); - - // [Integer] 0x01A — UDIV: Unsigned Division - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Unsigned Dst / Src -> Dst - void UDIV(); - - // [Integer] 0x01B — MOD: Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Signed Dst % Src -> Dst - void MOD(); - - // [Integer] 0x01C — UMOD: Unsigned Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Unsigned Dst % Src -> Dst - void UMOD(); - - // [Integer] 0x01D — DMOD: Division and Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Signed Dst / Src -> X, Dst % Src -> Y - void DMOD(); - - // [Integer] 0x01E — UDMD: Unsigned Division and Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Unsigned Dst / Src -> X, Dst % Src -> Y - void UDMD(); - - // [System] 0x01F — FBT: Test and update Flag Register (Integer) Bits - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Flags of Dst - - void FBT(); - - // [Bit Wise] 0x020 — STB: Set Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Src# bit is set on Dst - void STB(); - - // [Bit Wise] 0x021 — CRB: Clear Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Src# bit is cleared on Dst - void CRB(); - - // [Bit Wise] 0x022 — TSB: Test Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Src# bit is tested against Dst, updates Equal Flag - void TSB(); - - // [Bit Wise] 0x023 — BOOL: Sets the booleaness of a value - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Tests Dst != 0, updates Equal Flag - void BOOL(); - - // [Bit Wise] 0x024 — NOT: Sets the inverse booleaness of a value (! BOOL) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Tests Dst == 0, updates Equal Flag - void NOT(); - - // [Bit Wise] 0x025 — AND: Boolean AND operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst AND Src into Dst - void AND(); - - // [Bit Wise] 0x026 — OR: Boolean OR operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst OR Src into Dst - void OR(); - - // [Bit Wise] 0x027 — XOR: Boolean XOR operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst XOR Src into Dst - void XOR(); - - // [Bit Wise] 0x028 — SHL: Arithmetic Shift Left - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst << Src into Dst - void SHL(); - - // [Bit Wise] 0x029 — SHR: Arithmetic Shift Right - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst >> Src into Dst - void SHR(); - - // [Bit Wise] 0x02A — SSR: Signed Shift Right - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst >>> Src into Dst - void SSR(); - - // [Bit Wise] 0x02B — ROL: Rotate Left - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst ROL Src into Dst - void ROL(); - - // [Bit Wise] 0x02C — ROR: Rotate Right - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst ROR Src into Dst - void ROR(); - - // [Bit Wise] 0x02D — CNT: Counts bits - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: # of 1's into Dst - void CNT(); - - // [Boolean] 0x030 — EQ: Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst == Src into Dst - void EQ(); - - // [Boolean] 0x031 — NE: Not Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst != Src into Dst - void NE(); - - // [Boolean] 0x032 — GT: Greater Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst > Src into Dst - void GT(); - - // [Boolean] 0x033 — GE: Greater or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst >= Src into Dst - void GE(); - - // [Boolean] 0x034 — LT: Lower Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst < Src into Dst - void LT(); - - // [Boolean] 0x035 — LE: Lower or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst <= Src into Dst - void LE(); - - // [Branch] 0x038 — JMP: Jump to absolute position - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst -> Instruction Register - void JMP(); - - // [Branch] 0x039 — JEQ: Jumps to position if EQ flag is set - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst -> Instruction Register IF Flags.EQ - void JEQ(); - - // [Branch] 0x03A — JNE: Jumps to position if EQ flag is cleared - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst -> Instruction Register IF NOT Flags.EQ - void JNE(); - - // [Branch] 0x03B — JIF: Jumps if value provided is booleanly true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst -> Instruction Register IF Src - void JIF(); - - // [Branch] 0x03C — JMR: Jump Relative - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst + Instruction Register -> Instruction Register - void JMR(); - - // [Branch] 0x03D — JER: Jumps to relative position if EQ flag is set - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst + Instruction Register -> Instruction Register IF Flags.EQ - void JER(); - - // [Branch] 0x03E — JNR: Jumps to relative position if EQ flag is cleared - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst + Instruction Register -> Instruction Register IF NOT Flags.EQ - void JNR(); - - // [Branch] 0x03F — JIR: Jumps to relative position if value provided is booleanly true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst + Instruction Register -> Instruction Register IF Src - void JIR(); - - // [System] 0x040 — SFB: Store (User) Flag Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: - void SFB(); - - // [System] 0x041 — LFB: Load (User) Flag Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: - void LFB(); - - // [Branch] 0x042 — JUF: Jump to absolute position, if user flag is true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: - void JUF(); - - // [Branch] 0x043 — JUR: Jump to relative position, if user flag is true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: - void JUR(); - - // [Memory] 0x044 — PUSH: Push to stack - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst -> pushed into stack - void PUSH(); - - // [Memory] 0x045 — POP: Pop from stack - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: popped from stack -> Dst - void POP(); - - // [Memory] 0x046 — ALLOC: Allocate to heap - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Dst -> heap ptr of size Dst - void ALLOC(); - - // [Memory] 0x047 — HFREE: Delete from heap - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Frees heap ptr in Dst - void HFREE(); - - // [Branch] 0x04A — CALL: Call function at instruction index - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Performs a function call, step XX - void CALL(); - - // [Branch] 0x04B — RET: Return from a function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: Undoes a function call, step XX - void RET(); - - // [System] 0x04C — EDI: Enable/Disable External Interrupts - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: bool( Dst ) -> Enable External Interrupts Bit - void EDI(); - - // [System] 0x04D — SHSS: Set Hotswap Signal Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F - // Operation: bool( Dst ) -> Hot Swap Signal Bit - void SHSS(); - - // [Floating Point] 0x050 — FLI: Float Load Immediate - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void FLI(); - - // [Floating Point] 0x051 — FNEG: Float negate - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - Dst -> Dst - void FNEG(); - - // [Floating Point] 0x052 — FADD: Float add - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst + Src -> Dst - void FADD(); - - // [Floating Point] 0x053 — FSUB: Float subtract - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst - Src-> Dst - void FSUB(); - - // [Floating Point] 0x054 — FMUL: Float multiplication - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst * Src -> Dst - void FMUL(); - - // [Floating Point] 0x055 — FDIV: Float division - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst / Src -> Dst - void FDIV(); - - // [Floating Point] 0x056 — FMOD: Float modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst % Src -> Dst - void FMOD(); - - // [Floating Point] 0x057 — FDMOD: Float division and modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst / Src -> X, Dst % Src -> Y - void FDMOD(); - - // [Floating Point] 0x058 — FEPS: Sets the float epsilon value, for comparison - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst -> Epsilon Register - void FEPS(); - - // [Floating Point] 0x059 — FEEP: Float Enable/Disable Epsilon - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: bool( Dst ) -> Epsilon Enable Bit - void FEEP(); - - // [Boolean] 0x05A — FEQ: Float Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst == Src into Dst - void FEQ(); - - // [Boolean] 0x05B — FNE: Float Not Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst != Src into Dst - void FNE(); - - // [Boolean] 0x05C — FGT: Float Greater Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst > Src into Dst - void FGT(); - - // [Boolean] 0x05D — FGE: Float Greater or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst >= Src into Dst - void FGE(); - - // [Boolean] 0x05E — FLT: Float Lower Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst < Src into Dst - void FLT(); - - // [Boolean] 0x05F — FLE: Float Lower or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst <= Src into Dst - void FLE(); - - // [Casts] 0x060 — F2D: F32 (Float) to F64 (Double) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void F2D(); - - // [Casts] 0x061 — D2F: F64 (Double) to F32 (Float) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void D2F(); - - // [Casts] 0x062 — I2F: I32 (Integer) to F32 (Float) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void I2F(); - - // [Casts] 0x063 — I2D: I32 (Integer) to F64 (Double) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void I2D(); - - // [Casts] 0x064 — L2F: I64 (Long) to F32 (Float) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void L2F(); - - // [Casts] 0x065 — L2D: I64 (Long) to F64 (Double) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void L2D(); - - // [Casts] 0x066 — F2I: F32 (Float) to I32 (Integer) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void F2I(); - - // [Casts] 0x067 — F2L: F32 (Float) to I64 (Long) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void F2L(); - - // [Casts] 0x068 — D2I: F64 (Double) to I32 (Integer) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void D2I(); - - // [Casts] 0x069 — D2L: F64 (Double) to I64 (Long) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: (cast) Dst -> Dst - void D2L(); - - // [Trigonometric] 0x06C — SIN: Sine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: sin( Dst ) -> Dst - void SIN(); - - // [Trigonometric] 0x06D — COS: Cosine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: cos( Dst ) -> Dst - void COS(); - - // [Trigonometric] 0x06E — TAN: Tangent Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: tan( Dst ) -> Dst - void TAN(); - - // [Trigonometric] 0x06F — ASIN: Arc Sine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: asin( Dst ) -> Dst - void ASIN(); - - // [Trigonometric] 0x070 — ACOS: Arc Cosine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: acos( Dst ) -> Dst - void ACOS(); - - // [Trigonometric] 0x071 — ATAN: Arc Tangent Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: atan( Dst ) -> Dst - void ATAN(); - - // [Trigonometric] 0x072 — ATAN2: Arc Tangent Function with 2 Arguments - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: atan( Dst, Src ) -> Dst - void ATAN2(); - - // [Exponential] 0x074 — EXP: Exponential Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: exp( Dst ) -> Dst - void EXP(); - - // [Exponential] 0x075 — LOG: Natural Logarithm - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: ln( Dst ) -> Dst - void LOG(); - - // [Exponential] 0x076 — LOGAB: Logarithm A of B - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: log( Dst, Src ) -> Dst - void LOGAB(); - - // [Exponential] 0x077 — POW: Power Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: pow( Dst, Src ) -> Dst - void POW(); - - // [Exponential] 0x078 — SQRT: Square Root - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: sqrt( Dst ) -> Dst - void SQRT(); - - // [Exponential] 0x079 — ROOT: General Root - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: pow( Dst, 1 / Src ) -> Dst - void ROOT(); - - // [Integer] 0x07C — ADC: Add with Carry - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst + Src + Flags.Carry -> Dst, Flags.Carry - void ADC(); - - // [Integer] 0x07D — SWC: Subtract with Carry (Borrow) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Dst - Src - Flags.Carry -> Dst, Flags.Carry - void SWC(); - - // [Integer] 0x07E — MWO: Multiply with Overflow - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Signed Dst * Src -> Dst, Flags.Carry - void MWO(); - - // [Integer] 0x07F — UMO: Unsigned Multiply with Overflow - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: Unsigned Dst * Src -> Dst, Flags.Carry - void UMO(); - - // [Matrix] 0x080 — MADD: Matrix Addition - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void MADD(); - - // [Matrix] 0x081 — MSUB: Matrix Subtraction - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void MSUB(); - - // [Matrix] 0x082 — MMUL: Matrix Multiply - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void MMUL(); - - // [Matrix] 0x083 — MINV: Matrix Inverse - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void MINV(); - - // [Matrix] 0x084 — MTRA: Matrix Transpose - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void MTRA(); - - // [Matrix] 0x085 — MDET: Matrix Determinant - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void MDET(); - - // [SIMD] 0x08A — XADD: SIMD Addition - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void XADD(); - - // [SIMD] 0x08B — XSUB: SIMD Subtract - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void XSUB(); - - // [SIMD] 0x08C — XAMA: SIMD Alternate Multiply-Add - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void XAMA(); - - // [SIMD] 0x08D — XMUL: SIMD Multiply - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void XMUL(); - - // [SIMD] 0x08E — XDIV: SIMD Divide - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void XDIV(); - - // [Easter Eggs] 0x0F0 — UPY: Will place "YUPI" in memory - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 - // Operation: - void UPY(); - - // // - - }; - +#pragma once + +#include +#include + +namespace spider { + + class CPU { + public: // Flag Register Constants // + static constexpr const u64 FLAG_ENABLE = 0b0000000000000000000000000000000000000000000000000000000000000001; + static constexpr const u64 FLAG_INTERRUPT_SIGNAL = 0b0000000000000000000000000000000000000000000000000000000000000010; + static constexpr const u64 FLAG_INTERRUPT_REQUEST = 0b0000000000000000000000000000000000000000000000000000000000000100; + static constexpr const u64 FLAG_EXCEPTION = 0b0000000000000000000000000000000000000000000000000000000000001000; + static constexpr const u64 FLAG_MEMORY_MODE = 0b0000000000000000000000000000000000000000000000000000000000110000; + + public: // General Purpose Registers + union { + register_t GPR[16]; + struct { + register_t RA, RB, RC, RD, + RX, RY, R0, R1, + R2, R3, R4, R5, + R6, R7, R8, R9; + }; + }; + + public: // System Registers + u64 RF; + u64 RI; + u64 RS; + u64 RZ; + u64 RE; + u64 RN; // Epsilo(n) + u64 RV; + u64 RM; + + public: + + /** + * These are private registers, which are only used + * whenever constant things are used. + * This way we don't "write" into constant values, rather + * we write into a writeable var which is "hidden" + */ + register_t ALU0, ALU1; + + private: + + /** + * Pointer to the current RAM hooked into + * the CPU. + * + * It is unproved whether having the RAM directly + * into the CPU is better than not, or whether a + * virtual BUS is better. + * + * Alas, this way we can have a CPU state switch + * between memory and instruction banks. + */ + RAM* _ram; + + /** + * Pointer to the current Instruction Reel + * hooked into the CPU. + * + * Ditto as RAM. + */ + InstrReel* _reel; + + register_t* _next; + u8 _addrm : 6; + u8 _size : 2; + + public: + + CPU(); + + CPU(const CPU& other) = default; + + CPU(CPU&& other) noexcept = default; + + ~CPU(); + + public: + + CPU& operator=(const CPU& other) = default; + + CPU& operator=(CPU&& other) noexcept = default; + + public: + + void hookRAM(RAM* ram); + + void hookInstrReel(InstrReel* reel); + + constexpr u64 getFlag(u64 mask); + + public: // Addressing Modes + + /** + * Implied Addressing Mode + */ + void imp(); + + /** + * Immediate Addressing Mode + */ + void imm(); + + /** + * Absolute Addressing Mode + */ + void abs(); + + /** + * Register Addressing Mode + */ + void reg(); + + /** + * Indrect Addressing Mode + */ + void ind(); + + /** + * Pointer Addressing Mode + */ + void ptr(); + + /** + * Indexed Addressing Mode + */ + void idx(); + + /** + * Scaled Addressing Mode + */ + void sca(); + + /** + * Displaced Addressing Mode + */ + void dis(); + + public: + + // // + // [System] 0x000 — NOP: No Operation + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Nothing + void NOP(); + + // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (Spider Version) -> RA + void SPDR(); + + // [System] 0x002 — MMODE: Set Memory Mode + // Params: 1 | AddrMask1: 05 AddrMask2: 00 | TypeMask: 01 + // Operation: Dst -> Memory Mode Bits + void MMODE(); + + // [System] 0x003 — INT: Interrupt + // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0F + // Operation: Performs system interrupt no. (Dst) (See table) + void INT(); + + // [System] 0x004 — LRV: Load Interrupt Vector Register + // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0C + // Operation: Dst -> RV + void LRV(); + + // [System] 0x005 — FSR: Fetch System Register + // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F + // Operation: System Register at Dst -> Dst + void FSR(); + + // [System] 0x006 — FIR: Fetch Instruction Register + // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F + // Operation: Instruction Register -> Dst + void FIR(); + + // [System] 0x007 — FZR: Fetch Stack Base Register + // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F + // Operation: Stack Base Register -> Dst + void FZR(); + + // [System] 0x008 — LSR: Load System Register + // Params: 2 | AddrMask1: 1E AddrMask2: 1F | TypeMask: 0F + // Operation: Src -> System Register at Dst + void LSR(); + + // [System] 0x009 — FVR: Fetch Interrupt Vector Register + // Params: 1 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Interrupt Vector Register -> Dst + void FVR(); + + // [Memory] 0x00A — MOV: Moves values + // Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Src -> Dst + void MOV(); + + // [Memory] 0x00B — MOR: Moves registers + // Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: R Scr -> R Dst + void MOR(); + + // [Memory] 0x00C — AMOV: Array Move, uses X and Y as ptrs, A as amount + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Array from X to Y, by A amount + void AMOV(); + + // [Memory] 0x00D — SWP: Swap registers + // Params: 2 | AddrMask1: 04 AddrMask2: 04 | TypeMask: 00 + // Operation: Src <-> Dst + void SWP(); + + // [Memory] 0x00E — AHM: Ask Host for Memory + // Params: 1 | AddrMask1: 04 AddrMask2: 00 | TypeMask: 0F + // Operation: Asks the host for a specific size of memory. Responds with 0 or 1 + void AHM(); + + // [Integer] 0x010 — COM: One's complement + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: ~ Dst -> Dst + void COM(); + + // [Integer] 0x011 — NEG: Two's complement + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: - Dst -> Dst + void NEG(); + + // [Integer] 0x012 — EXS: Extend Sign + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Last bit is copied and expanded for the next int size + void EXS(); + + // [Integer] 0x013 — INC: Increment + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst + 1 -> Dst + void INC(); + + // [Integer] 0x014 — DEC: Decrement + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst - 1 -> Dst + void DEC(); + + // [Integer] 0x015 — ADD: Addition + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst + Src -> Dst + void ADD(); + + // [Integer] 0x016 — SUB: Subtraction + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst - Src-> Dst + void SUB(); + + // [Integer] 0x017 — MUL: Multiplication + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Signed Dst * Src -> Dst + void MUL(); + + // [Integer] 0x018 — UMUL: Unsigned Multiplication + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Unsigned Dst * Src -> Dst + void UMUL(); + + // [Integer] 0x019 — DIV: Division + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Signed Dst / Src -> Dst + void DIV(); + + // [Integer] 0x01A — UDIV: Unsigned Division + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Unsigned Dst / Src -> Dst + void UDIV(); + + // [Integer] 0x01B — MOD: Modulus + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Signed Dst % Src -> Dst + void MOD(); + + // [Integer] 0x01C — UMOD: Unsigned Modulus + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Unsigned Dst % Src -> Dst + void UMOD(); + + // [Integer] 0x01D — DMOD: Division and Modulus + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Signed Dst / Src -> X, Dst % Src -> Y + void DMOD(); + + // [Integer] 0x01E — UDMD: Unsigned Division and Modulus + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Unsigned Dst / Src -> X, Dst % Src -> Y + void UDMD(); + + // [System] 0x01F — FBT: Test and update Flag Register (Integer) Bits + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Flags of Dst - + void FBT(); + + // [Bit Wise] 0x020 — STB: Set Bit + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Src# bit is set on Dst + void STB(); + + // [Bit Wise] 0x021 — CRB: Clear Bit + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Src# bit is cleared on Dst + void CRB(); + + // [Bit Wise] 0x022 — TSB: Test Bit + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Src# bit is tested against Dst, updates Equal Flag + void TSB(); + + // [Bit Wise] 0x023 — BOOL: Sets the booleaness of a value + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Tests Dst != 0, updates Equal Flag + void BOOL(); + + // [Bit Wise] 0x024 — NOT: Sets the inverse booleaness of a value (! BOOL) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Tests Dst == 0, updates Equal Flag + void NOT(); + + // [Bit Wise] 0x025 — AND: Boolean AND operation + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst AND Src into Dst + void AND(); + + // [Bit Wise] 0x026 — OR: Boolean OR operation + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst OR Src into Dst + void OR(); + + // [Bit Wise] 0x027 — XOR: Boolean XOR operation + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst XOR Src into Dst + void XOR(); + + // [Bit Wise] 0x028 — SHL: Arithmetic Shift Left + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst << Src into Dst + void SHL(); + + // [Bit Wise] 0x029 — SHR: Arithmetic Shift Right + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst >> Src into Dst + void SHR(); + + // [Bit Wise] 0x02A — SSR: Signed Shift Right + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst >>> Src into Dst + void SSR(); + + // [Bit Wise] 0x02B — ROL: Rotate Left + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst ROL Src into Dst + void ROL(); + + // [Bit Wise] 0x02C — ROR: Rotate Right + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst ROR Src into Dst + void ROR(); + + // [Bit Wise] 0x02D — CNT: Counts bits + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: # of 1's into Dst + void CNT(); + + // [Boolean] 0x030 — EQ: Equal + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst == Src into Dst + void EQ(); + + // [Boolean] 0x031 — NE: Not Equal + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst != Src into Dst + void NE(); + + // [Boolean] 0x032 — GT: Greater Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst > Src into Dst + void GT(); + + // [Boolean] 0x033 — GE: Greater or Equal Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst >= Src into Dst + void GE(); + + // [Boolean] 0x034 — LT: Lower Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst < Src into Dst + void LT(); + + // [Boolean] 0x035 — LE: Lower or Equal Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst <= Src into Dst + void LE(); + + // [Branch] 0x038 — JMP: Jump to absolute position + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst -> Instruction Register + void JMP(); + + // [Branch] 0x039 — JEQ: Jumps to position if EQ flag is set + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst -> Instruction Register IF Flags.EQ + void JEQ(); + + // [Branch] 0x03A — JNE: Jumps to position if EQ flag is cleared + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst -> Instruction Register IF NOT Flags.EQ + void JNE(); + + // [Branch] 0x03B — JIF: Jumps if value provided is booleanly true + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst -> Instruction Register IF Src + void JIF(); + + // [Branch] 0x03C — JMR: Jump Relative + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst + Instruction Register -> Instruction Register + void JMR(); + + // [Branch] 0x03D — JER: Jumps to relative position if EQ flag is set + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst + Instruction Register -> Instruction Register IF Flags.EQ + void JER(); + + // [Branch] 0x03E — JNR: Jumps to relative position if EQ flag is cleared + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst + Instruction Register -> Instruction Register IF NOT Flags.EQ + void JNR(); + + // [Branch] 0x03F — JIR: Jumps to relative position if value provided is booleanly true + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst + Instruction Register -> Instruction Register IF Src + void JIR(); + + // [System] 0x040 — SFB: Store (User) Flag Bit + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: + void SFB(); + + // [System] 0x041 — LFB: Load (User) Flag Bit + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: + void LFB(); + + // [Branch] 0x042 — JUF: Jump to absolute position, if user flag is true + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: + void JUF(); + + // [Branch] 0x043 — JUR: Jump to relative position, if user flag is true + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: + void JUR(); + + // [Memory] 0x044 — PUSH: Push to stack + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst -> pushed into stack + void PUSH(); + + // [Memory] 0x045 — POP: Pop from stack + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: popped from stack -> Dst + void POP(); + + // [Memory] 0x046 — ALLOC: Allocate to heap + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Dst -> heap ptr of size Dst + void ALLOC(); + + // [Memory] 0x047 — HFREE: Delete from heap + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Frees heap ptr in Dst + void HFREE(); + + // [Branch] 0x04A — CALL: Call function at instruction index + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Performs a function call, step XX + void CALL(); + + // [Branch] 0x04B — RET: Return from a function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: Undoes a function call, step XX + void RET(); + + // [System] 0x04C — EDI: Enable/Disable External Interrupts + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: bool( Dst ) -> Enable External Interrupts Bit + void EDI(); + + // [System] 0x04D — SHSS: Set Hotswap Signal Bit + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Operation: bool( Dst ) -> Hot Swap Signal Bit + void SHSS(); + + // [Floating Point] 0x050 — FLI: Float Load Immediate + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void FLI(); + + // [Floating Point] 0x051 — FNEG: Float negate + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: - Dst -> Dst + void FNEG(); + + // [Floating Point] 0x052 — FADD: Float add + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst + Src -> Dst + void FADD(); + + // [Floating Point] 0x053 — FSUB: Float subtract + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst - Src-> Dst + void FSUB(); + + // [Floating Point] 0x054 — FMUL: Float multiplication + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst * Src -> Dst + void FMUL(); + + // [Floating Point] 0x055 — FDIV: Float division + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst / Src -> Dst + void FDIV(); + + // [Floating Point] 0x056 — FMOD: Float modulus + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst % Src -> Dst + void FMOD(); + + // [Floating Point] 0x057 — FDMOD: Float division and modulus + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst / Src -> X, Dst % Src -> Y + void FDMOD(); + + // [Floating Point] 0x058 — FEPS: Sets the float epsilon value, for comparison + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst -> Epsilon Register + void FEPS(); + + // [Floating Point] 0x059 — FEEP: Float Enable/Disable Epsilon + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: bool( Dst ) -> Epsilon Enable Bit + void FEEP(); + + // [Boolean] 0x05A — FEQ: Float Equal + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst == Src into Dst + void FEQ(); + + // [Boolean] 0x05B — FNE: Float Not Equal + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst != Src into Dst + void FNE(); + + // [Boolean] 0x05C — FGT: Float Greater Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst > Src into Dst + void FGT(); + + // [Boolean] 0x05D — FGE: Float Greater or Equal Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst >= Src into Dst + void FGE(); + + // [Boolean] 0x05E — FLT: Float Lower Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst < Src into Dst + void FLT(); + + // [Boolean] 0x05F — FLE: Float Lower or Equal Than + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst <= Src into Dst + void FLE(); + + // [Casts] 0x060 — F2D: F32 (Float) to F64 (Double) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void F2D(); + + // [Casts] 0x061 — D2F: F64 (Double) to F32 (Float) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void D2F(); + + // [Casts] 0x062 — I2F: I32 (Integer) to F32 (Float) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void I2F(); + + // [Casts] 0x063 — I2D: I32 (Integer) to F64 (Double) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void I2D(); + + // [Casts] 0x064 — L2F: I64 (Long) to F32 (Float) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void L2F(); + + // [Casts] 0x065 — L2D: I64 (Long) to F64 (Double) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void L2D(); + + // [Casts] 0x066 — F2I: F32 (Float) to I32 (Integer) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void F2I(); + + // [Casts] 0x067 — F2L: F32 (Float) to I64 (Long) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void F2L(); + + // [Casts] 0x068 — D2I: F64 (Double) to I32 (Integer) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void D2I(); + + // [Casts] 0x069 — D2L: F64 (Double) to I64 (Long) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: (cast) Dst -> Dst + void D2L(); + + // [Trigonometric] 0x06C — SIN: Sine Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: sin( Dst ) -> Dst + void SIN(); + + // [Trigonometric] 0x06D — COS: Cosine Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: cos( Dst ) -> Dst + void COS(); + + // [Trigonometric] 0x06E — TAN: Tangent Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: tan( Dst ) -> Dst + void TAN(); + + // [Trigonometric] 0x06F — ASIN: Arc Sine Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: asin( Dst ) -> Dst + void ASIN(); + + // [Trigonometric] 0x070 — ACOS: Arc Cosine Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: acos( Dst ) -> Dst + void ACOS(); + + // [Trigonometric] 0x071 — ATAN: Arc Tangent Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: atan( Dst ) -> Dst + void ATAN(); + + // [Trigonometric] 0x072 — ATAN2: Arc Tangent Function with 2 Arguments + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: atan( Dst, Src ) -> Dst + void ATAN2(); + + // [Exponential] 0x074 — EXP: Exponential Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: exp( Dst ) -> Dst + void EXP(); + + // [Exponential] 0x075 — LOG: Natural Logarithm + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: ln( Dst ) -> Dst + void LOG(); + + // [Exponential] 0x076 — LOGAB: Logarithm A of B + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: log( Dst, Src ) -> Dst + void LOGAB(); + + // [Exponential] 0x077 — POW: Power Function + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: pow( Dst, Src ) -> Dst + void POW(); + + // [Exponential] 0x078 — SQRT: Square Root + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: sqrt( Dst ) -> Dst + void SQRT(); + + // [Exponential] 0x079 — ROOT: General Root + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: pow( Dst, 1 / Src ) -> Dst + void ROOT(); + + // [Integer] 0x07C — ADC: Add with Carry + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst + Src + Flags.Carry -> Dst, Flags.Carry + void ADC(); + + // [Integer] 0x07D — SWC: Subtract with Carry (Borrow) + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Dst - Src - Flags.Carry -> Dst, Flags.Carry + void SWC(); + + // [Integer] 0x07E — MWO: Multiply with Overflow + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Signed Dst * Src -> Dst, Flags.Carry + void MWO(); + + // [Integer] 0x07F — UMO: Unsigned Multiply with Overflow + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: Unsigned Dst * Src -> Dst, Flags.Carry + void UMO(); + + // [Matrix] 0x080 — MADD: Matrix Addition + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void MADD(); + + // [Matrix] 0x081 — MSUB: Matrix Subtraction + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void MSUB(); + + // [Matrix] 0x082 — MMUL: Matrix Multiply + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void MMUL(); + + // [Matrix] 0x083 — MINV: Matrix Inverse + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void MINV(); + + // [Matrix] 0x084 — MTRA: Matrix Transpose + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void MTRA(); + + // [Matrix] 0x085 — MDET: Matrix Determinant + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void MDET(); + + // [SIMD] 0x08A — XADD: SIMD Addition + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void XADD(); + + // [SIMD] 0x08B — XSUB: SIMD Subtract + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void XSUB(); + + // [SIMD] 0x08C — XAMA: SIMD Alternate Multiply-Add + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void XAMA(); + + // [SIMD] 0x08D — XMUL: SIMD Multiply + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void XMUL(); + + // [SIMD] 0x08E — XDIV: SIMD Divide + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void XDIV(); + + // [Easter Eggs] 0x0F0 — UPY: Will place "YUPI" in memory + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void UPY(); + + // // + + }; + } \ No newline at end of file diff --git a/src/spider/runtime/cpu/Register.hpp b/src/spider/runtime/cpu/Register.hpp index 2948e22..959b8ed 100644 --- a/src/spider/runtime/cpu/Register.hpp +++ b/src/spider/runtime/cpu/Register.hpp @@ -1,81 +1,81 @@ -#pragma once - -#include -#include - -namespace spider { - - /** - * A register is a tiny piece of memory. - * I hate adding a _t suffix but for some idiotic - * reason "register" is a keyword in C++. - * - * Note that we have to check the endianness of the system - * at compile time to order the structure so that smaller - * types are actually the bottom part of the memory. - * - * Also, this has to be done with a compiler that allows - * type-punning which is the "standard" right now. - */ - union register_t { - u64 _u64; - i64 _i64; - f64 _f64; - u8 _bytes[8]; - - struct { - #if SPIDER_LITTLE_ENDIAN - u8 _u8; // This looks like a cruel joke - u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; - #else - u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; - u8 _u8; - #endif - }; - - struct { - #if SPIDER_LITTLE_ENDIAN - u16 _u16; - u16 : 16; u16 : 16; u16 : 16; - #else - u16 : 16; u16 : 16; u16 : 16; - u16 _u16; - #endif - }; - - struct { - #if SPIDER_LITTLE_ENDIAN - u32 _u32; u32 : 32; - #else - u32 : 32; u32 _u32; - #endif - }; - - struct { - #if SPIDER_LITTLE_ENDIAN - f32 _f32; u32 : 32; - #else - u32 : 32; f32 _f32; - #endif - }; - - u8& operator[](size_t i) { // 0 is always LSB - #if SPIDER_LITTLE_ENDIAN - return _bytes[i]; - #else - return _bytes[7 - i]; - #endif - } - - // ngl I could get executed for not having a const version - const u8& operator[](size_t i) const { // 0 is always LSB - #if SPIDER_LITTLE_ENDIAN - return _bytes[i]; - #else - return _bytes[7 - i]; - #endif - } - }; - static_assert(sizeof(register_t) == 8, "The register type must be exactly 8 bytes."); - +#pragma once + +#include +#include + +namespace spider { + + /** + * A register is a tiny piece of memory. + * I hate adding a _t suffix but for some idiotic + * reason "register" is a keyword in C++. + * + * Note that we have to check the endianness of the system + * at compile time to order the structure so that smaller + * types are actually the bottom part of the memory. + * + * Also, this has to be done with a compiler that allows + * type-punning which is the "standard" right now. + */ + union register_t { + u64 _u64; + i64 _i64; + f64 _f64; + u8 _bytes[8]; + + struct { + #if SPIDER_LITTLE_ENDIAN + u8 _u8; // This looks like a cruel joke + u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; + #else + u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; + u8 _u8; + #endif + }; + + struct { + #if SPIDER_LITTLE_ENDIAN + u16 _u16; + u16 : 16; u16 : 16; u16 : 16; + #else + u16 : 16; u16 : 16; u16 : 16; + u16 _u16; + #endif + }; + + struct { + #if SPIDER_LITTLE_ENDIAN + u32 _u32; u32 : 32; + #else + u32 : 32; u32 _u32; + #endif + }; + + struct { + #if SPIDER_LITTLE_ENDIAN + f32 _f32; u32 : 32; + #else + u32 : 32; f32 _f32; + #endif + }; + + u8& operator[](size_t i) { // 0 is always LSB + #if SPIDER_LITTLE_ENDIAN + return _bytes[i]; + #else + return _bytes[7 - i]; + #endif + } + + // ngl I could get executed for not having a const version + const u8& operator[](size_t i) const { // 0 is always LSB + #if SPIDER_LITTLE_ENDIAN + return _bytes[i]; + #else + return _bytes[7 - i]; + #endif + } + }; + static_assert(sizeof(register_t) == 8, "The register type must be exactly 8 bytes."); + } \ No newline at end of file diff --git a/src/spider/runtime/debug/LiveDebug.cpp b/src/spider/runtime/debug/LiveDebug.cpp index f1301d4..e61cce1 100644 --- a/src/spider/runtime/debug/LiveDebug.cpp +++ b/src/spider/runtime/debug/LiveDebug.cpp @@ -1,386 +1,386 @@ -#include "LiveDebug.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -namespace spider { - - void drawHead(Terminal& t) { - t.move(1, 1) - .style(Terminal::FG_YELLOW) - .print(" Spider Runtime Live Debug ") - .style(Terminal::RESET).print(" | ") - .style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ") - .style(Terminal::RESET).print(" | ") - .style(Terminal::FG_B_BLACK).print("Press ESC to exit") - .style(Terminal::FG_BLACK) - .style(Terminal::BG_YELLOW) - .move(3, 1).print(" // __ \\\\").print(" ") // 27 - .move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ") - .move(5, 1).print(" //()\\\\ ").print(" alpha ") - .move(6, 1).print(" \\\\ // ").print(" ") - .style(Terminal::RESET) - .style(Terminal::FG_B_BLACK) // 4x8 for the menu - .move(3, 28).print("[ STEP ]") - .move(4, 28).print("[ STOP ]") - .move(5, 28).print("[ RUN ]") - .move(6, 28).print("[ MENU ]") - .style(Terminal::RESET) - ; - } - - void drawCPUTempl(Terminal& t, CPU& cpu) { - i32 r = 8, c = 1; - i32 w = 35, h = 31; - t.drawBox(r, c, w, h, "CPU"); - - const std::string regs[] = { - "RA", "RB", "RC", "RD", - "RX", "RY", "R0", "R1", - "R2", "R3", "R4", "R5", - "R6", "R7", "R8", "R9", - "RF", "RI", "RS", "RZ", - "RE", "RN", "RV", "RM", - "ALU0", "ALU1" - }; - const std::string alt[] = { - Terminal::FG_WHITE, - Terminal::FG_B_BLACK, - }; - - r++; - c++; - - t.move(r++, c); - t.style(Terminal::FG_B_YELLOW); - t.print_center(w - 2, "GP Registers"); - t.style(Terminal::RESET); - for (i32 i = 0; i < 8; i++) { - t.style(alt[i & 1]); - t.move(r + i * 2, c); - t.print(regs[i * 2]); - t.move(r + i * 2, c + 17); - t.print(regs[i * 2 + 1]); - } - - t.move(r += 16, c); - t.style(Terminal::FG_B_CYAN); - t.print_center(w - 2, "System Registers"); - t.style(Terminal::RESET); - r++; - for (i32 j = 0, i = 8; i < 12; j++, i++) { - t.style(alt[j & 1]); - t.move(r + j * 2, c); - t.print(regs[i * 2]); - t.move(r + j * 2, c + 17); - t.print(regs[i * 2 + 1]); - } - - t.move(r += 8, c); - t.style(Terminal::FG_GREEN); - t.print_center(w - 2, "Extra Registers"); - t.style(Terminal::RESET); - r++; - for (i32 j = 0, i = 12; i < 13; j++, i++) { - t.style(alt[j & 1]); - t.move(r + j * 2, c); - t.print(regs[i * 2]); - t.move(r + j * 2, c + 17); - t.print(regs[i * 2 + 1]); - } - - t.flush(); - } - - void printU64Hex(u64 n) { - std::ios state(nullptr); - state.copyfmt(std::cout); - std::cout - << std::hex - << std::uppercase - << std::setfill('0') - << std::setw(16) - << n; - std::cout.copyfmt(state); - } - - void drawCPU(Terminal& t, CPU& cpu) { - i32 r = 8, c = 1; - - const register_t* regs[] = { - &cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD, - &cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1, - &cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5, - &cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9, - //&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ, - //&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM, - &cpu.ALU0, &cpu.ALU1 - }; - const u64* sys_regs[] = { - &cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ, - &cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM, - }; - const std::string alt[] = { - Terminal::FG_WHITE, - Terminal::FG_B_BLACK, - }; - - r++; - c++; - t.move(r++, c); - t.style(Terminal::RESET); - r++; - for (i32 i = 0; i < 8; i++) { - t.style(alt[i & 1]); - t.move(r + i * 2, c); - printU64Hex(regs[i * 2]->_u64); - t.move(r + i * 2, c + 17); - printU64Hex(regs[i * 2 + 1]->_u64); - } - - t.move(r += 16, c); - r++; - for (i32 j = 0, i = 8; i < 12; j++, i++) { - t.style(alt[j & 1]); - t.move(r + j * 2, c); - printU64Hex(*sys_regs[i * 2]); - t.move(r + j * 2, c + 17); - printU64Hex(*sys_regs[i * 2 + 1]); - } - - t.move(r += 8, c); - r++; - for (i32 j = 0; j < 1; j++) { - t.style(alt[j & 1]); - t.move(r + j * 2, c); - printU64Hex(regs[16 + j * 2]->_u64); - t.move(r + j * 2, c + 17); - printU64Hex(regs[16 + j * 2 + 1]->_u64); - } - - t.flush(); - } - - i32 addressWidth(isize ramSize) { - if (ramSize == 0) return 1; - isize maxAddr = ramSize - 1; - i32 digits = 0; - // Shift by increments of 4 (one hex nibble) - // We use a do-while to ensure at least 1 digit is returned for small RAMs - do { - digits++; - maxAddr >>= 4; - } while (maxAddr > 0); - - return digits; - } - - /** - * Draws a vertical scrollbar - * @param x The column where the bar should be placed (usually box_x + width - 1) - * @param y The starting row of the track (usually box_y + 1) - * @param trackHeight The internal height of the box (box_height - 2) - * @param progress The current progress - * @param total The total - */ - void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) { - if (total == 0 || trackHeight <= 0) return; - - // 1. Draw the background track (Light Shade: ░) - term.style(Terminal::FG_B_BLACK); // Dim the track - for (int i = 0; i < trackHeight; ++i) { - term.move(y + i, x).print("░"); - } - - // 2. Calculate Thumb Position - // Cap progress to total to avoid overflow - if (progress > total) progress = total; - - // Calculate ratio (0.0 to 1.0) - f64 ratio = f64(progress) / f64(total); - - // Map to track coordinates - i32 thumbOffset = i32(ratio * (trackHeight - 1)); - - // 3. Draw the Thumb (Full Block: █) - term.move(y + thumbOffset, x); - term.style(Terminal::FG_WHITE).print("█"); - term.style(Terminal::RESET); - } - - /** - * Draws a hex dump of memory within a styled terminal box. - * @param term Reference to your Terminal instance - * @param ram The RAM - * @param scrollPos The starting address to display - * @param x Starting column - * @param y Starting row - * @param width Width of the box - * @param height Height of the box - */ - void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) { - // 1. Draw the container box - i32 y = 3; - i32 height = 36; - - // 2. Configuration for the hex layout - int addrWidth = addressWidth(ram.size()); - int bytesPerRow = 8; - int displayRows = height - 2; // Subtract top/bottom borders - i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth; - i32 x = 37; - - // create box - term.drawBox(y, x, width, height, "RAM"); - drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size()); - - // Ensure scrollPos is within bounds and aligned - if (scrollPos < 0) scrollPos = 0; - if (scrollPos > ram.size()) scrollPos = ram.size(); - - for (int i = 0; i < displayRows; ++i) { - isize currentRowAddr = scrollPos + (i * bytesPerRow); - - // address lock - if (currentRowAddr >= ram.size()) { - term.move(y + 1 + i, x + 1); - term.print(std::string(width - 3, ' ')); - continue; - } - - std::stringstream ssaddr; - std::stringstream ss; - - // setup ss - ssaddr << std::setfill('0') << std::uppercase << std::hex; - ss << std::setfill('0') << std::uppercase << std::hex; - - // address - ssaddr << std::setw(addrWidth) << currentRowAddr << " "; - - // Hex Bytes - std::string asciiPart = ""; - for (int j = 0; j < bytesPerRow; ++j) { - isize targetAddr = currentRowAddr + j; - if (targetAddr >= ram.size()) { - ss << ""; // Padding for end of memory - asciiPart += ""; - continue; - } - - u8 byte = ram[targetAddr]; - ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " "; - asciiPart += (std::isprint(byte) ? (char)byte : '.'); - } - - // --- Combine and Print --- - term.move(y + 1 + i, x + 2); // Move inside the box - term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan - term.style(Terminal::FG_WHITE).print(ss.str()); - term.style(Terminal::FG_B_YELLOW).print(" | "); - term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White - } - - term.style(Terminal::RESET); - term.flush(); - } - - std::string getTimestamp() { - std::time_t t = std::time(nullptr); - std::tm lt; -#if defined(SPIDER_OS_WINDOWS) - localtime_s(<, &t); -#endif -#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) - localtime_r(&t, <); -#endif - return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}", - lt.tm_hour, lt.tm_min, lt.tm_sec, - lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900); - } - - void drawTime(Terminal& t) { - //auto now = std::chrono::system_clock::now(); - //auto now_l = std::chrono::current_zone()->to_local(now); - //auto now_s = std::chrono::floor(now_l); - //std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss - //std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY - - t.move(1, 76); - t.style(Terminal::RESET); - t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp()); - } - - void redraw(Terminal& t, Runtime& r, u64 scroll) { - // draw CPU, RAM - drawCPU(t, r.cpu); - drawRAM(t, r.ram, scroll); - } - - int liveDebugMain() { - Terminal t; - Runtime runtime(1024); - - bool running = true, update = true; - u64 ramScroll = 0; - u8 key = Terminal::UNKNOWN; - - t.println("Starting Spider live debug..."); - t.altbuff(true).cursor(false); - - drawTime(t); - drawHead(t); - drawCPUTempl(t, runtime.cpu); - - // delay for time - auto last_exec = std::chrono::steady_clock::now(); - auto delay = std::chrono::milliseconds(1000); - - while (running) { - // draw time - auto now = std::chrono::steady_clock::now(); - if (now - last_exec >= delay) { - drawTime(t); - last_exec = now; - } - - // redraw something if it updated - if (update) { - redraw(t, runtime, ramScroll); - update = false; - } - - // Handle Input - key = t.getKeyNb(); - switch (key) { - case Terminal::ESC: - running = false; - break; - case Terminal::UP: - if (ramScroll >= 16) ramScroll -= 16; - update = true; - break; - case Terminal::DOWN: - if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16; - update = true; - break; - default: - break; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - t.altbuff(false).println("Stopped Spider live debug.").flush(); - return 0; - } - -} +#include "LiveDebug.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +namespace spider { + + void drawHead(Terminal& t) { + t.move(1, 1) + .style(Terminal::FG_YELLOW) + .print(" Spider Runtime Live Debug ") + .style(Terminal::RESET).print(" | ") + .style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ") + .style(Terminal::RESET).print(" | ") + .style(Terminal::FG_B_BLACK).print("Press ESC to exit") + .style(Terminal::FG_BLACK) + .style(Terminal::BG_YELLOW) + .move(3, 1).print(" // __ \\\\").print(" ") // 27 + .move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ") + .move(5, 1).print(" //()\\\\ ").print(" alpha ") + .move(6, 1).print(" \\\\ // ").print(" ") + .style(Terminal::RESET) + .style(Terminal::FG_B_BLACK) // 4x8 for the menu + .move(3, 28).print("[ STEP ]") + .move(4, 28).print("[ STOP ]") + .move(5, 28).print("[ RUN ]") + .move(6, 28).print("[ MENU ]") + .style(Terminal::RESET) + ; + } + + void drawCPUTempl(Terminal& t, CPU& cpu) { + i32 r = 8, c = 1; + i32 w = 35, h = 31; + t.drawBox(r, c, w, h, "CPU"); + + const std::string regs[] = { + "RA", "RB", "RC", "RD", + "RX", "RY", "R0", "R1", + "R2", "R3", "R4", "R5", + "R6", "R7", "R8", "R9", + "RF", "RI", "RS", "RZ", + "RE", "RN", "RV", "RM", + "ALU0", "ALU1" + }; + const std::string alt[] = { + Terminal::FG_WHITE, + Terminal::FG_B_BLACK, + }; + + r++; + c++; + + t.move(r++, c); + t.style(Terminal::FG_B_YELLOW); + t.print_center(w - 2, "GP Registers"); + t.style(Terminal::RESET); + for (i32 i = 0; i < 8; i++) { + t.style(alt[i & 1]); + t.move(r + i * 2, c); + t.print(regs[i * 2]); + t.move(r + i * 2, c + 17); + t.print(regs[i * 2 + 1]); + } + + t.move(r += 16, c); + t.style(Terminal::FG_B_CYAN); + t.print_center(w - 2, "System Registers"); + t.style(Terminal::RESET); + r++; + for (i32 j = 0, i = 8; i < 12; j++, i++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + t.print(regs[i * 2]); + t.move(r + j * 2, c + 17); + t.print(regs[i * 2 + 1]); + } + + t.move(r += 8, c); + t.style(Terminal::FG_GREEN); + t.print_center(w - 2, "Extra Registers"); + t.style(Terminal::RESET); + r++; + for (i32 j = 0, i = 12; i < 13; j++, i++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + t.print(regs[i * 2]); + t.move(r + j * 2, c + 17); + t.print(regs[i * 2 + 1]); + } + + t.flush(); + } + + void printU64Hex(u64 n) { + std::ios state(nullptr); + state.copyfmt(std::cout); + std::cout + << std::hex + << std::uppercase + << std::setfill('0') + << std::setw(16) + << n; + std::cout.copyfmt(state); + } + + void drawCPU(Terminal& t, CPU& cpu) { + i32 r = 8, c = 1; + + const register_t* regs[] = { + &cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD, + &cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1, + &cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5, + &cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9, + //&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ, + //&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM, + &cpu.ALU0, &cpu.ALU1 + }; + const u64* sys_regs[] = { + &cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ, + &cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM, + }; + const std::string alt[] = { + Terminal::FG_WHITE, + Terminal::FG_B_BLACK, + }; + + r++; + c++; + t.move(r++, c); + t.style(Terminal::RESET); + r++; + for (i32 i = 0; i < 8; i++) { + t.style(alt[i & 1]); + t.move(r + i * 2, c); + printU64Hex(regs[i * 2]->_u64); + t.move(r + i * 2, c + 17); + printU64Hex(regs[i * 2 + 1]->_u64); + } + + t.move(r += 16, c); + r++; + for (i32 j = 0, i = 8; i < 12; j++, i++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + printU64Hex(*sys_regs[i * 2]); + t.move(r + j * 2, c + 17); + printU64Hex(*sys_regs[i * 2 + 1]); + } + + t.move(r += 8, c); + r++; + for (i32 j = 0; j < 1; j++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + printU64Hex(regs[16 + j * 2]->_u64); + t.move(r + j * 2, c + 17); + printU64Hex(regs[16 + j * 2 + 1]->_u64); + } + + t.flush(); + } + + i32 addressWidth(isize ramSize) { + if (ramSize == 0) return 1; + isize maxAddr = ramSize - 1; + i32 digits = 0; + // Shift by increments of 4 (one hex nibble) + // We use a do-while to ensure at least 1 digit is returned for small RAMs + do { + digits++; + maxAddr >>= 4; + } while (maxAddr > 0); + + return digits; + } + + /** + * Draws a vertical scrollbar + * @param x The column where the bar should be placed (usually box_x + width - 1) + * @param y The starting row of the track (usually box_y + 1) + * @param trackHeight The internal height of the box (box_height - 2) + * @param progress The current progress + * @param total The total + */ + void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) { + if (total == 0 || trackHeight <= 0) return; + + // 1. Draw the background track (Light Shade: ░) + term.style(Terminal::FG_B_BLACK); // Dim the track + for (int i = 0; i < trackHeight; ++i) { + term.move(y + i, x).print("░"); + } + + // 2. Calculate Thumb Position + // Cap progress to total to avoid overflow + if (progress > total) progress = total; + + // Calculate ratio (0.0 to 1.0) + f64 ratio = f64(progress) / f64(total); + + // Map to track coordinates + i32 thumbOffset = i32(ratio * (trackHeight - 1)); + + // 3. Draw the Thumb (Full Block: █) + term.move(y + thumbOffset, x); + term.style(Terminal::FG_WHITE).print("█"); + term.style(Terminal::RESET); + } + + /** + * Draws a hex dump of memory within a styled terminal box. + * @param term Reference to your Terminal instance + * @param ram The RAM + * @param scrollPos The starting address to display + * @param x Starting column + * @param y Starting row + * @param width Width of the box + * @param height Height of the box + */ + void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) { + // 1. Draw the container box + i32 y = 3; + i32 height = 36; + + // 2. Configuration for the hex layout + int addrWidth = addressWidth(ram.size()); + int bytesPerRow = 8; + int displayRows = height - 2; // Subtract top/bottom borders + i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth; + i32 x = 37; + + // create box + term.drawBox(y, x, width, height, "RAM"); + drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size()); + + // Ensure scrollPos is within bounds and aligned + if (scrollPos < 0) scrollPos = 0; + if (scrollPos > ram.size()) scrollPos = ram.size(); + + for (int i = 0; i < displayRows; ++i) { + isize currentRowAddr = scrollPos + (i * bytesPerRow); + + // address lock + if (currentRowAddr >= ram.size()) { + term.move(y + 1 + i, x + 1); + term.print(std::string(width - 3, ' ')); + continue; + } + + std::stringstream ssaddr; + std::stringstream ss; + + // setup ss + ssaddr << std::setfill('0') << std::uppercase << std::hex; + ss << std::setfill('0') << std::uppercase << std::hex; + + // address + ssaddr << std::setw(addrWidth) << currentRowAddr << " "; + + // Hex Bytes + std::string asciiPart = ""; + for (int j = 0; j < bytesPerRow; ++j) { + isize targetAddr = currentRowAddr + j; + if (targetAddr >= ram.size()) { + ss << ""; // Padding for end of memory + asciiPart += ""; + continue; + } + + u8 byte = ram[targetAddr]; + ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " "; + asciiPart += (std::isprint(byte) ? (char)byte : '.'); + } + + // --- Combine and Print --- + term.move(y + 1 + i, x + 2); // Move inside the box + term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan + term.style(Terminal::FG_WHITE).print(ss.str()); + term.style(Terminal::FG_B_YELLOW).print(" | "); + term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White + } + + term.style(Terminal::RESET); + term.flush(); + } + + std::string getTimestamp() { + std::time_t t = std::time(nullptr); + std::tm lt; +#if defined(SPIDER_OS_WINDOWS) + localtime_s(<, &t); +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + localtime_r(&t, <); +#endif + return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}", + lt.tm_hour, lt.tm_min, lt.tm_sec, + lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900); + } + + void drawTime(Terminal& t) { + //auto now = std::chrono::system_clock::now(); + //auto now_l = std::chrono::current_zone()->to_local(now); + //auto now_s = std::chrono::floor(now_l); + //std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss + //std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY + + t.move(1, 76); + t.style(Terminal::RESET); + t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp()); + } + + void redraw(Terminal& t, Runtime& r, u64 scroll) { + // draw CPU, RAM + drawCPU(t, r.cpu); + drawRAM(t, r.ram, scroll); + } + + int liveDebugMain() { + Terminal t; + Runtime runtime(1024); + + bool running = true, update = true; + u64 ramScroll = 0; + u8 key = Terminal::UNKNOWN; + + t.println("Starting Spider live debug..."); + t.altbuff(true).cursor(false); + + drawTime(t); + drawHead(t); + drawCPUTempl(t, runtime.cpu); + + // delay for time + auto last_exec = std::chrono::steady_clock::now(); + auto delay = std::chrono::milliseconds(1000); + + while (running) { + // draw time + auto now = std::chrono::steady_clock::now(); + if (now - last_exec >= delay) { + drawTime(t); + last_exec = now; + } + + // redraw something if it updated + if (update) { + redraw(t, runtime, ramScroll); + update = false; + } + + // Handle Input + key = t.getKeyNb(); + switch (key) { + case Terminal::ESC: + running = false; + break; + case Terminal::UP: + if (ramScroll >= 16) ramScroll -= 16; + update = true; + break; + case Terminal::DOWN: + if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16; + update = true; + break; + default: + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + t.altbuff(false).println("Stopped Spider live debug.").flush(); + return 0; + } + +} diff --git a/src/spider/runtime/debug/LiveDebug.hpp b/src/spider/runtime/debug/LiveDebug.hpp index 69140cb..99995f8 100644 --- a/src/spider/runtime/debug/LiveDebug.hpp +++ b/src/spider/runtime/debug/LiveDebug.hpp @@ -1,7 +1,7 @@ -#pragma once - -namespace spider { - - int liveDebugMain(); - -} +#pragma once + +namespace spider { + + int liveDebugMain(); + +} diff --git a/src/spider/runtime/instr/Instr_00-1F.cpp b/src/spider/runtime/instr/Instr_00-1F.cpp index 0d40cc9..6dacdf9 100644 --- a/src/spider/runtime/instr/Instr_00-1F.cpp +++ b/src/spider/runtime/instr/Instr_00-1F.cpp @@ -1,9 +1,9 @@ -#include - -namespace spider { - - void CPU::NOP() { - // No Operation // - } - -} +#include + +namespace spider { + + void CPU::NOP() { + // No Operation // + } + +} diff --git a/src/spider/runtime/math/Quat.cpp b/src/spider/runtime/math/Quat.cpp index ae40493..008423a 100644 --- a/src/spider/runtime/math/Quat.cpp +++ b/src/spider/runtime/math/Quat.cpp @@ -1,22 +1,22 @@ -#include "Quat.hpp" - -#include - -namespace spider { - - int quatMain() { - Quat q1 = { 1.0f, 0.0f, 0.0f, 0.0f }; - Quat q2 = { 0.5f, 0.5f, 0.5f, 0.5f }; - - Quat result = quat_multiply(q1, q2); // Returns the result! - - std::cout << "Result: (" - << result.w << ", " - << result.x << ", " - << result.y << ", " - << result.z << ")" << std::endl; - - return 0; - } - -} +#include "Quat.hpp" + +#include + +namespace spider { + + int quatMain() { + Quat q1 = { 1.0f, 0.0f, 0.0f, 0.0f }; + Quat q2 = { 0.5f, 0.5f, 0.5f, 0.5f }; + + Quat result = quat_multiply(q1, q2); // Returns the result! + + std::cout << "Result: (" + << result.w << ", " + << result.x << ", " + << result.y << ", " + << result.z << ")" << std::endl; + + return 0; + } + +} diff --git a/src/spider/runtime/math/Quat.hpp b/src/spider/runtime/math/Quat.hpp index 676778c..11b8522 100644 --- a/src/spider/runtime/math/Quat.hpp +++ b/src/spider/runtime/math/Quat.hpp @@ -1,24 +1,24 @@ -#pragma once - -#include - -namespace spider { - - template - struct Quat { - T w, x, y, z; - }; - - /** - * Multiplies two quaternions together. - */ - template inline Quat quat_multiply(Quat A, Quat B) { - return { - B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z, - B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y, - B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x, - B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w - }; - } - -} +#pragma once + +#include + +namespace spider { + + template + struct Quat { + T w, x, y, z; + }; + + /** + * Multiplies two quaternions together. + */ + template inline Quat quat_multiply(Quat A, Quat B) { + return { + B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z, + B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y, + B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x, + B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w + }; + } + +} diff --git a/src/spider/runtime/memory/ByteArray.cpp b/src/spider/runtime/memory/ByteArray.cpp index 507fa67..49632b9 100644 --- a/src/spider/runtime/memory/ByteArray.cpp +++ b/src/spider/runtime/memory/ByteArray.cpp @@ -1,74 +1,74 @@ -#include "ByteArray.hpp" - -#include - -namespace spider { - - ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) { - if (_size > 0) { - _mem = new u8[_size]; - std::memset(_mem, 0, _size); - } - } - - ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) { - std::copy(other._mem, other._mem + _size, _mem); - } - - ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) { - other._mem = nullptr; - other._size = 0; - } - - ByteArray::~ByteArray() { - delete[] _mem; - } - - ByteArray& ByteArray::operator=(const ByteArray& other) { - if (this == &other) return *this; // lock self - - u8* new_mem = new u8[other._size]; - std::copy(other._mem, other._mem + other._size, new_mem); - - delete[] _mem; - _mem = new_mem; - _size = other._size; - - return *this; - } - - ByteArray& ByteArray::operator=(ByteArray&& other) noexcept { - if (this == &other) return *this; // lock self - - delete[] _mem; - - _mem = other._mem; // time to steal! - _size = other._size; - - other._mem = nullptr; // leave as a husk - other._size = 0; - - return *this; - } - - u8& ByteArray::operator[](isize index) { - return _mem[index]; - } - - u8 ByteArray::operator[](isize index) const { - return _mem[index]; - } - - u8* ByteArray::data() { - return _mem; - } - - const u8* ByteArray::data() const { - return _mem; - } - - isize ByteArray::size() const { - return _size; - } - -} +#include "ByteArray.hpp" + +#include + +namespace spider { + + ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) { + if (_size > 0) { + _mem = new u8[_size]; + std::memset(_mem, 0, _size); + } + } + + ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) { + std::copy(other._mem, other._mem + _size, _mem); + } + + ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) { + other._mem = nullptr; + other._size = 0; + } + + ByteArray::~ByteArray() { + delete[] _mem; + } + + ByteArray& ByteArray::operator=(const ByteArray& other) { + if (this == &other) return *this; // lock self + + u8* new_mem = new u8[other._size]; + std::copy(other._mem, other._mem + other._size, new_mem); + + delete[] _mem; + _mem = new_mem; + _size = other._size; + + return *this; + } + + ByteArray& ByteArray::operator=(ByteArray&& other) noexcept { + if (this == &other) return *this; // lock self + + delete[] _mem; + + _mem = other._mem; // time to steal! + _size = other._size; + + other._mem = nullptr; // leave as a husk + other._size = 0; + + return *this; + } + + u8& ByteArray::operator[](isize index) { + return _mem[index]; + } + + u8 ByteArray::operator[](isize index) const { + return _mem[index]; + } + + u8* ByteArray::data() { + return _mem; + } + + const u8* ByteArray::data() const { + return _mem; + } + + isize ByteArray::size() const { + return _size; + } + +} diff --git a/src/spider/runtime/memory/ByteArray.hpp b/src/spider/runtime/memory/ByteArray.hpp index 69ca2e7..0394d58 100644 --- a/src/spider/runtime/memory/ByteArray.hpp +++ b/src/spider/runtime/memory/ByteArray.hpp @@ -1,49 +1,49 @@ -#pragma once - -#include - -namespace spider { - - /** - * A general purpose byte array - * with RAII semantics. - */ - class ByteArray { - private: - - u8* _mem; - isize _size; - - public: - - ByteArray(isize length); - - ByteArray(const ByteArray& other); - - ByteArray(ByteArray&& other) noexcept; - - ~ByteArray(); - - public: - - ByteArray& operator=(const ByteArray& other); - - ByteArray& operator=(ByteArray&& other) noexcept; - - public: - - u8& operator[](isize index); - - u8 operator[](isize index) const; - - public: - - u8* data(); - - const u8* data() const; - - isize size() const; - - }; - -} +#pragma once + +#include + +namespace spider { + + /** + * A general purpose byte array + * with RAII semantics. + */ + class ByteArray { + private: + + u8* _mem; + isize _size; + + public: + + ByteArray(isize length); + + ByteArray(const ByteArray& other); + + ByteArray(ByteArray&& other) noexcept; + + ~ByteArray(); + + public: + + ByteArray& operator=(const ByteArray& other); + + ByteArray& operator=(ByteArray&& other) noexcept; + + public: + + u8& operator[](isize index); + + u8 operator[](isize index) const; + + public: + + u8* data(); + + const u8* data() const; + + isize size() const; + + }; + +} diff --git a/src/spider/runtime/memory/RAM.cpp b/src/spider/runtime/memory/RAM.cpp index 5c65303..f690bed 100644 --- a/src/spider/runtime/memory/RAM.cpp +++ b/src/spider/runtime/memory/RAM.cpp @@ -1,130 +1,130 @@ -#include "RAM.hpp" - -#include - -namespace spider { - - // Constructors & Destructors // - - RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) { - if (_size > 0) { - _mem = new u8[_size]; - std::memset(_mem, 0, _size); - } - } - - RAM::RAM(const RAM& other) : _size(other._size), _oob(0) { - _mem = new u8[_size]; - std::copy(other._mem, other._mem + _size, _mem); - } - - RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) { - other._mem = nullptr; - other._size = 0; - } - - RAM::~RAM() { - delete[] _mem; - } - - // Assign Operators // - - RAM& RAM::operator=(const RAM& other) { - if (this == &other) return *this; // lock self - - u8* new_mem = new u8[other._size]; - std::copy(other._mem, other._mem + other._size, new_mem); - - delete[] _mem; - _mem = new_mem; - _size = other._size; - - return *this; - } - - RAM& RAM::operator=(RAM&& other) noexcept { - if (this == &other) return *this; // lock self - - delete[] _mem; - - _mem = other._mem; // time to steal! - _size = other._size; - - other._mem = nullptr; // leave as a husk - other._size = 0; - - return *this; - } - - // Unsafe Access // - - u8& RAM::operator[](u64 i) { return _mem[i]; } - - u8 RAM::operator[](u64 i) const { return _mem[i]; } - - // Managed Access // - - u8& RAM::at(u64 i) { - return (i < _size) ? _mem[i] : _oob; - } - - u8 RAM::at(u64 i) const { - return (i < _size) ? _mem[i] : _oob; - } - - // Misc // - - void RAM::resize(u64 new_size) { - // Special case 1 - if (new_size == _size) return; - - // Special case 2 - if (new_size == 0) { - delete[] _mem; - _mem = nullptr; - _size = 0; - return; - } - - // 1. Allocate the new block - u8* new_mem = new u8[new_size]; - - // 2. Zero-initialize - std::memset(new_mem, 0, new_size); - - // 3. Preserve data - // If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes. - u64 bytes_to_copy = (new_size < _size) ? new_size : _size; - - // 3.1 Previous size could be zero, where _mem would be null - if (_mem != nullptr) { - std::copy(_mem, _mem + bytes_to_copy, new_mem); - } - - // 4. Swap and Clean up - delete[] _mem; - _mem = new_mem; - _size = new_size; - } - - u64 RAM::size() const { - return _size; - } - - u8* RAM::begin() { - return this->_mem; - } - - u8* RAM::end() { - return this->_mem + this->_size; - } - - const u8* RAM::begin() const { - return this->_mem; - } - - const u8* RAM::end() const { - return this->_mem + this->_size; - } - -} +#include "RAM.hpp" + +#include + +namespace spider { + + // Constructors & Destructors // + + RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) { + if (_size > 0) { + _mem = new u8[_size]; + std::memset(_mem, 0, _size); + } + } + + RAM::RAM(const RAM& other) : _size(other._size), _oob(0) { + _mem = new u8[_size]; + std::copy(other._mem, other._mem + _size, _mem); + } + + RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) { + other._mem = nullptr; + other._size = 0; + } + + RAM::~RAM() { + delete[] _mem; + } + + // Assign Operators // + + RAM& RAM::operator=(const RAM& other) { + if (this == &other) return *this; // lock self + + u8* new_mem = new u8[other._size]; + std::copy(other._mem, other._mem + other._size, new_mem); + + delete[] _mem; + _mem = new_mem; + _size = other._size; + + return *this; + } + + RAM& RAM::operator=(RAM&& other) noexcept { + if (this == &other) return *this; // lock self + + delete[] _mem; + + _mem = other._mem; // time to steal! + _size = other._size; + + other._mem = nullptr; // leave as a husk + other._size = 0; + + return *this; + } + + // Unsafe Access // + + u8& RAM::operator[](u64 i) { return _mem[i]; } + + u8 RAM::operator[](u64 i) const { return _mem[i]; } + + // Managed Access // + + u8& RAM::at(u64 i) { + return (i < _size) ? _mem[i] : _oob; + } + + u8 RAM::at(u64 i) const { + return (i < _size) ? _mem[i] : _oob; + } + + // Misc // + + void RAM::resize(u64 new_size) { + // Special case 1 + if (new_size == _size) return; + + // Special case 2 + if (new_size == 0) { + delete[] _mem; + _mem = nullptr; + _size = 0; + return; + } + + // 1. Allocate the new block + u8* new_mem = new u8[new_size]; + + // 2. Zero-initialize + std::memset(new_mem, 0, new_size); + + // 3. Preserve data + // If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes. + u64 bytes_to_copy = (new_size < _size) ? new_size : _size; + + // 3.1 Previous size could be zero, where _mem would be null + if (_mem != nullptr) { + std::copy(_mem, _mem + bytes_to_copy, new_mem); + } + + // 4. Swap and Clean up + delete[] _mem; + _mem = new_mem; + _size = new_size; + } + + u64 RAM::size() const { + return _size; + } + + u8* RAM::begin() { + return this->_mem; + } + + u8* RAM::end() { + return this->_mem + this->_size; + } + + const u8* RAM::begin() const { + return this->_mem; + } + + const u8* RAM::end() const { + return this->_mem + this->_size; + } + +} diff --git a/src/spider/runtime/memory/RAM.hpp b/src/spider/runtime/memory/RAM.hpp index c62cd46..ac7da5d 100644 --- a/src/spider/runtime/memory/RAM.hpp +++ b/src/spider/runtime/memory/RAM.hpp @@ -1,64 +1,64 @@ -#pragma once - -#include - -namespace spider { - - /** - * A memory container. - * As a reminder, the amount of RAM - * is designed by the host. - */ - class RAM { - private: - u8* _mem; - u64 _size; - u8 _oob; // Out of bounds reference - - public: - - RAM(u64 length); - - RAM(const RAM& other); - - RAM(RAM&& other) noexcept; - - ~RAM(); - - public: - - RAM& operator=(const RAM& other); - - RAM& operator=(RAM&& other) noexcept; - - public: // Unsafe access - - u8& operator[](u64 i); - - u8 operator[](u64 i) const; - - public: // managed access (oob = 0) - - u8& at(u64 i); - - u8 at(u64 i) const; - - public: - - void resize(u64 new_size); - - u64 size() const; - - public: - - u8* begin(); - - u8* end(); - - const u8* begin() const; - - const u8* end() const; - - }; - +#pragma once + +#include + +namespace spider { + + /** + * A memory container. + * As a reminder, the amount of RAM + * is designed by the host. + */ + class RAM { + private: + u8* _mem; + u64 _size; + u8 _oob; // Out of bounds reference + + public: + + RAM(u64 length); + + RAM(const RAM& other); + + RAM(RAM&& other) noexcept; + + ~RAM(); + + public: + + RAM& operator=(const RAM& other); + + RAM& operator=(RAM&& other) noexcept; + + public: // Unsafe access + + u8& operator[](u64 i); + + u8 operator[](u64 i) const; + + public: // managed access (oob = 0) + + u8& at(u64 i); + + u8 at(u64 i) const; + + public: + + void resize(u64 new_size); + + u64 size() const; + + public: + + u8* begin(); + + u8* end(); + + const u8* begin() const; + + const u8* end() const; + + }; + } \ No newline at end of file diff --git a/src/spider/runtime/memory/Types.hpp b/src/spider/runtime/memory/Types.hpp index 6c80507..1b36035 100644 --- a/src/spider/runtime/memory/Types.hpp +++ b/src/spider/runtime/memory/Types.hpp @@ -1,250 +1,250 @@ -#pragma once - -#include -#include - -#if __cplusplus >= 202002L - #include -#endif - -#if defined(SPIDER_COMPILER_MSVC) - #include -#endif - -#include - -namespace spider { - - /* - * This file contains cross platform type juggling. - * Optimized for each case. - * - * General assumtions is that unsigned and signed - * integers are the exact same bit representation. - * - * Floats to and from integers is the focus when - * juggling. - * - * Additionally, provides help selecting a specific - * type from raw bytes. - */ - - // Utilities // - -#if __cplusplus >= 202002L - using std::bit_cast; -#else - template - inline To bit_cast(const From& src) { - static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch"); - To dst; - std::memcpy(&dst, &src, sizeof(To)); - return dst; - } -#endif - - template - inline T byteswap(T v) { - static_assert(std::is_integral::value, "byteswap requires integral type"); - - using U = std::make_unsigned_t; - U u = static_cast(v); - - if constexpr (sizeof(T) == 1) { - return v; - } else if constexpr (sizeof(T) == 2) { - -#if defined(SPIDER_COMPILER_MSVC) - u = _byteswap_ushort(u); -#elif defined(SPIDER_COMPILER_GCC_LIKE) - u = __builtin_bswap16(u); -#else - u = (u >> 8) | (u << 8); -#endif - - } else if constexpr (sizeof(T) == 4) { - -#if defined(SPIDER_COMPILER_MSVC) - u = _byteswap_ulong(u); -#elif defined(SPIDER_COMPILER_GCC_LIKE) - u = __builtin_bswap32(u); -#else - u = - ((u & 0x000000FFu) << 24) | - ((u & 0x0000FF00u) << 8) | - ((u & 0x00FF0000u) >> 8) | - ((u & 0xFF000000u) >> 24); -#endif - - } else if constexpr (sizeof(T) == 8) { - -#if defined(SPIDER_COMPILER_MSVC) - u = _byteswap_uint64(u); -#elif defined(SPIDER_COMPILER_GCC_LIKE) - u = __builtin_bswap64(u); -#else - u = - ((u & 0x00000000000000FFull) << 56) | - ((u & 0x000000000000FF00ull) << 40) | - ((u & 0x0000000000FF0000ull) << 24) | - ((u & 0x00000000FF000000ull) << 8) | - ((u & 0x000000FF00000000ull) >> 8) | - ((u & 0x0000FF0000000000ull) >> 24) | - ((u & 0x00FF000000000000ull) >> 40) | - ((u & 0xFF00000000000000ull) >> 56); -#endif - - } else { - // Generic fallback (rare: non 1/2/4/8-byte types) - U result = 0; - for (size_t i = 0; i < sizeof(T); ++i) { - result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8); - } - u = result; - } - - return static_cast(u); - } - - // Store Big Endian // - - template - inline void storeBE(T n, u8* bytes) { - static_assert(std::is_trivially_copyable::value); -#if SPIDER_BIG_ENDIAN - std::memcpy(bytes, &n, sizeof(T)); -#endif -#if SPIDER_LITTLE_ENDIAN - T tmp = byteswap(n); - std::memcpy(bytes, &tmp, sizeof(T)); -#endif -#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN - for (size_t i = 0; i < sizeof(T); ++i) { - bytes[i] = static_cast( - (static_cast>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF - ); - } -#endif - } - - template<> - inline void storeBE(f32 n, u8* bytes) { - u32 tmp = bit_cast(n); - storeBE(tmp, bytes); - } - - template<> - inline void storeBE(f64 n, u8* bytes) { - u64 tmp = bit_cast(n); - storeBE(tmp, bytes); - } - - // Load Big Endian // - - template - inline void loadBE(T* n, const u8* bytes) { - static_assert(std::is_trivially_copyable::value); -#if SPIDER_BIG_ENDIAN - std::memcpy(n, bytes, sizeof(T)); -#endif -#if SPIDER_LITTLE_ENDIAN - T tmp; - std::memcpy(&tmp, bytes, sizeof(T)); - *n = byteswap(tmp); -#endif -#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN - using U = std::make_unsigned_t; - U result = 0; - for (size_t i = 0; i < sizeof(T); ++i) { - result |= static_cast(bytes[i]) << ((sizeof(T) - 1 - i) * 8); - } - *n = static_cast(result); -#endif - } - - template<> - inline void loadBE(f32* n, const u8* bytes) { - u32 tmp; - loadBE(&tmp, bytes); - *n = bit_cast(tmp); - } - - template<> - inline void loadBE(f64* n, const u8* bytes) { - u64 tmp; - loadBE(&tmp, bytes); - *n = bit_cast(tmp); - } - - // Store Little Endian // - - template - inline void storeLE(T n, u8* bytes) { - static_assert(std::is_trivially_copyable::value); -#if SPIDER_BIG_ENDIAN - T tmp = byteswap(n); - std::memcpy(bytes, &tmp, sizeof(T)); -#endif -#if SPIDER_LITTLE_ENDIAN - std::memcpy(bytes, &n, sizeof(T)); -#endif -#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN - for (size_t i = 0; i < sizeof(T); ++i) { - bytes[i] = static_cast( - (static_cast>(n) >> (i * 8)) & 0xFF - ); - } -#endif - } - - template<> - inline void storeLE(f32 n, u8* bytes) { - u32 tmp = bit_cast(n); - storeLE(tmp, bytes); - } - - template<> - inline void storeLE(f64 n, u8* bytes) { - u64 tmp = bit_cast(n); - storeLE(tmp, bytes); - } - - // Load Little Endian // - - template - inline void loadLE(T* n, const u8* bytes) { - static_assert(std::is_trivially_copyable::value); -#if SPIDER_BIG_ENDIAN - T tmp; - std::memcpy(&tmp, bytes, sizeof(T)); - *n = byteswap(tmp); -#endif -#if SPIDER_LITTLE_ENDIAN - std::memcpy(n, bytes, sizeof(T)); -#endif -#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN - using U = std::make_unsigned_t; - U result = 0; - for (size_t i = 0; i < sizeof(T); ++i) { - result |= static_cast(bytes[i]) << (i * 8); - } - *n = static_cast(result); -#endif - } - - template<> - inline void loadLE(f32* n, const u8* bytes) { - u32 tmp; - loadLE(&tmp, bytes); - *n = bit_cast(tmp); - } - - template<> - inline void loadLE(f64* n, const u8* bytes) { - u64 tmp; - loadLE(&tmp, bytes); - *n = bit_cast(tmp); - } - -} - +#pragma once + +#include +#include + +#if __cplusplus >= 202002L + #include +#endif + +#if defined(SPIDER_COMPILER_MSVC) + #include +#endif + +#include + +namespace spider { + + /* + * This file contains cross platform type juggling. + * Optimized for each case. + * + * General assumtions is that unsigned and signed + * integers are the exact same bit representation. + * + * Floats to and from integers is the focus when + * juggling. + * + * Additionally, provides help selecting a specific + * type from raw bytes. + */ + + // Utilities // + +#if __cplusplus >= 202002L + using std::bit_cast; +#else + template + inline To bit_cast(const From& src) { + static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch"); + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; + } +#endif + + template + inline T byteswap(T v) { + static_assert(std::is_integral::value, "byteswap requires integral type"); + + using U = std::make_unsigned_t; + U u = static_cast(v); + + if constexpr (sizeof(T) == 1) { + return v; + } else if constexpr (sizeof(T) == 2) { + +#if defined(SPIDER_COMPILER_MSVC) + u = _byteswap_ushort(u); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + u = __builtin_bswap16(u); +#else + u = (u >> 8) | (u << 8); +#endif + + } else if constexpr (sizeof(T) == 4) { + +#if defined(SPIDER_COMPILER_MSVC) + u = _byteswap_ulong(u); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + u = __builtin_bswap32(u); +#else + u = + ((u & 0x000000FFu) << 24) | + ((u & 0x0000FF00u) << 8) | + ((u & 0x00FF0000u) >> 8) | + ((u & 0xFF000000u) >> 24); +#endif + + } else if constexpr (sizeof(T) == 8) { + +#if defined(SPIDER_COMPILER_MSVC) + u = _byteswap_uint64(u); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + u = __builtin_bswap64(u); +#else + u = + ((u & 0x00000000000000FFull) << 56) | + ((u & 0x000000000000FF00ull) << 40) | + ((u & 0x0000000000FF0000ull) << 24) | + ((u & 0x00000000FF000000ull) << 8) | + ((u & 0x000000FF00000000ull) >> 8) | + ((u & 0x0000FF0000000000ull) >> 24) | + ((u & 0x00FF000000000000ull) >> 40) | + ((u & 0xFF00000000000000ull) >> 56); +#endif + + } else { + // Generic fallback (rare: non 1/2/4/8-byte types) + U result = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8); + } + u = result; + } + + return static_cast(u); + } + + // Store Big Endian // + + template + inline void storeBE(T n, u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + std::memcpy(bytes, &n, sizeof(T)); +#endif +#if SPIDER_LITTLE_ENDIAN + T tmp = byteswap(n); + std::memcpy(bytes, &tmp, sizeof(T)); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + for (size_t i = 0; i < sizeof(T); ++i) { + bytes[i] = static_cast( + (static_cast>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF + ); + } +#endif + } + + template<> + inline void storeBE(f32 n, u8* bytes) { + u32 tmp = bit_cast(n); + storeBE(tmp, bytes); + } + + template<> + inline void storeBE(f64 n, u8* bytes) { + u64 tmp = bit_cast(n); + storeBE(tmp, bytes); + } + + // Load Big Endian // + + template + inline void loadBE(T* n, const u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + std::memcpy(n, bytes, sizeof(T)); +#endif +#if SPIDER_LITTLE_ENDIAN + T tmp; + std::memcpy(&tmp, bytes, sizeof(T)); + *n = byteswap(tmp); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + using U = std::make_unsigned_t; + U result = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + result |= static_cast(bytes[i]) << ((sizeof(T) - 1 - i) * 8); + } + *n = static_cast(result); +#endif + } + + template<> + inline void loadBE(f32* n, const u8* bytes) { + u32 tmp; + loadBE(&tmp, bytes); + *n = bit_cast(tmp); + } + + template<> + inline void loadBE(f64* n, const u8* bytes) { + u64 tmp; + loadBE(&tmp, bytes); + *n = bit_cast(tmp); + } + + // Store Little Endian // + + template + inline void storeLE(T n, u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + T tmp = byteswap(n); + std::memcpy(bytes, &tmp, sizeof(T)); +#endif +#if SPIDER_LITTLE_ENDIAN + std::memcpy(bytes, &n, sizeof(T)); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + for (size_t i = 0; i < sizeof(T); ++i) { + bytes[i] = static_cast( + (static_cast>(n) >> (i * 8)) & 0xFF + ); + } +#endif + } + + template<> + inline void storeLE(f32 n, u8* bytes) { + u32 tmp = bit_cast(n); + storeLE(tmp, bytes); + } + + template<> + inline void storeLE(f64 n, u8* bytes) { + u64 tmp = bit_cast(n); + storeLE(tmp, bytes); + } + + // Load Little Endian // + + template + inline void loadLE(T* n, const u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + T tmp; + std::memcpy(&tmp, bytes, sizeof(T)); + *n = byteswap(tmp); +#endif +#if SPIDER_LITTLE_ENDIAN + std::memcpy(n, bytes, sizeof(T)); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + using U = std::make_unsigned_t; + U result = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + result |= static_cast(bytes[i]) << (i * 8); + } + *n = static_cast(result); +#endif + } + + template<> + inline void loadLE(f32* n, const u8* bytes) { + u32 tmp; + loadLE(&tmp, bytes); + *n = bit_cast(tmp); + } + + template<> + inline void loadLE(f64* n, const u8* bytes) { + u64 tmp; + loadLE(&tmp, bytes); + *n = bit_cast(tmp); + } + +} + diff --git a/src/spider/runtime/native/distro.hpp b/src/spider/runtime/native/distro.hpp index 1e691a2..45664c4 100644 --- a/src/spider/runtime/native/distro.hpp +++ b/src/spider/runtime/native/distro.hpp @@ -99,7 +99,7 @@ #define SPIDER_NO_ICU #endif - #if define(SPIDER_OS_NONE) + #if defined(SPIDER_OS_NONE) #define SPIDER_OS_NAME "None" #elif !defined(SPIDER_OS_MCU) #error "[Spider Distro] Unsupported MCU OS" diff --git a/src/spider/runtime/native/distro_defs.hpp b/src/spider/runtime/native/distro_defs.hpp index 8e7544d..a12f64a 100644 --- a/src/spider/runtime/native/distro_defs.hpp +++ b/src/spider/runtime/native/distro_defs.hpp @@ -1,40 +1,40 @@ -#pragma once - -// ========================================================== // -// SPIDER DEFAULT SETTINGS, PER DISTRO // -// ========================================================== // - - -// ================== MEMORY FOOTPRINT ================== // - -/** - * Use a normal amount of memory, assuming there - * is like 100KB free of it. - */ -#define SPIDER_MEMFOOTPRINT_NORMAL 0 -/** - * Attempt to reduce the memory footprint - * where possible, but without doing - * extreme adaptations. - */ -#define SPIDER_MEMFOOTPRINT_REDUCED 1 -/** - * Will deliverately convert things from memory - * to functions in order to free as much memory - * as possible, even if it slows things down. - */ -#define SPIDER_MEMFOOTPRINT_MINIMAL 2 - -#ifndef SPIDER_MEMFOOTPRINT - #if defined(SPIDER_DISTRO_MOBILE) || defined(SPIDER_DISTRO_BROWSER) - #define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_REDUCED - #elif defined(SPIDER_DISTRO_MICRO) - #define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_MINIMAL - #else - #define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_NORMAL - #endif -#endif - -// ================== MISC ================== // - - +#pragma once + +// ========================================================== // +// SPIDER DEFAULT SETTINGS, PER DISTRO // +// ========================================================== // + + +// ================== MEMORY FOOTPRINT ================== // + +/** + * Use a normal amount of memory, assuming there + * is like 100KB free of it. + */ +#define SPIDER_MEMFOOTPRINT_NORMAL 0 +/** + * Attempt to reduce the memory footprint + * where possible, but without doing + * extreme adaptations. + */ +#define SPIDER_MEMFOOTPRINT_REDUCED 1 +/** + * Will deliverately convert things from memory + * to functions in order to free as much memory + * as possible, even if it slows things down. + */ +#define SPIDER_MEMFOOTPRINT_MINIMAL 2 + +#ifndef SPIDER_MEMFOOTPRINT + #if defined(SPIDER_DISTRO_MOBILE) || defined(SPIDER_DISTRO_BROWSER) + #define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_REDUCED + #elif defined(SPIDER_DISTRO_MICRO) + #define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_MINIMAL + #else + #define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_NORMAL + #endif +#endif + +// ================== MISC ================== // + + diff --git a/src/spider/runtime/native/distro_mcu.hpp b/src/spider/runtime/native/distro_mcu.hpp index ffb3362..d81eca6 100644 --- a/src/spider/runtime/native/distro_mcu.hpp +++ b/src/spider/runtime/native/distro_mcu.hpp @@ -1,112 +1,112 @@ -#pragma once - -// ========================================================== // -// SPIDER MICROCONTROLLER AUTODETECT // -// ========================================================== // - -// Automatically enable configurations for the microcontroller // -// so long as we can detect it or the user has already configured // -// the corresponding macros. // - -#define SPIDER_MCU_FAM_GENERIC 0 -#define SPIDER_MCU_FAM_AVR 1 -#define SPIDER_MCU_FAM_ARM_CM 2 -#define SPIDER_MCU_FAM_ARM_MBED 3 -#define SPIDER_MCU_FAM_PIC 4 -#define SPIDER_MCU_FAM_PIC32 5 -#define SPIDER_MCU_FAM_ESP8266 6 -#define SPIDER_MCU_FAM_ESP32 7 -#define SPIDER_MCU_FAM_RISCV 8 -#define SPIDER_MCU_FAM_RP2040 9 - -#if defined(SPIDER_MCU_AVR) || defined(__avr__) || defined(__AVR__) -// ========================================================== // -// AVR (Atmel / Microchip) // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_AVR - #define SPIDER_MCU_NAME "AVR" - -#elif defined(SPIDER_MCU_ARM) || defined(__arm__) || defined(__ARM_ARCH) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6M__) -// ========================================================== // -// ARM Cortex-M (most STM32, nRF, etc.) // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_CM - #define SPIDER_MCU_NAME "ARM Cortex-M" - -#elif defined(SPIDER_MCU_MBED) || defined(TARGET_LIKE_MBED) -// ========================================================== // -// Mbed OS special detection // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_MBED - #define SPIDER_MCU_NAME "ARM MBED" - #define SPIDER_OS_NAME "MBED OS" - -#elif defined(SPIDER_MCU_PIC8) || defined(__XC) && (defined(_PIC14) || defined(_PIC16)) -// ========================================================== // -// PIC (8-bit) // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC - #define SPIDER_MCU_NAME "PIC (8-bit)" - -#elif defined(SPIDER_MCU_PIC32) || defined(__XC32__) -// ========================================================== // -// PIC32 (MIPS) // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC32 - #define SPIDER_MCU_NAME "PIC (32-bit)" - -#elif defined(SPIDER_MCU_ESP8266) || defined(ESP8266) -// ========================================================== // -// ESP8266 // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP8266 - #define SPIDER_MCU_NAME "ESP-8266" - -#elif defined(SPIDER_MCU_ESP32) || defined(ESP32) -// ========================================================== // -// ESP32 // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP32 - #define SPIDER_MCU_NAME "ESP-32" - -#elif defined(SPIDER_MCU_PICO) || defined(PICO_PLATFORM) || defined(PICO_BOARD) || defined(RP2040) || defined(__RP2040__) -// ========================================================== // -// Raspberry Pi Pico (RP2040) // -// ========================================================== // - #define SPIDER_MCU_FAM_FAMILY SPIDER_MCU_FAM_RP2040 - #define SPIDER_MCU_NAME "ESP-32" - -#elif defined(SPIDER_MCU_RISCV) || defined(__riscv) || defined(__riscv__) -// ========================================================== // -// RISC-V MCUs // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_RISCV - #define SPIDER_MCU_NAME "RISC-V MCU" - -#elif defined(SPIDER_MCU_GENERIC) -// ========================================================== // -// GENERIC MICRO // -// ========================================================== // - #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_GENERIC - #define SPIDER_MCU_NAME "Generic MCU" -#endif - -#ifdef SPIDER_MCU_FAMILY - - #ifndef SPIDER_DISTRO_MICRO - #define SPIDER_DISTRO_MICRO - #endif - - // If SPIDER_OS_NAME was already defined, implies the SPIDER_MCU_FAM has an OS - #if defined(SPIDER_OS_NAME) && !defined(SPIDER_OS_MCU) - #define SPIDER_OS_MCU - #endif - - // If no SPIDER_MCU_FAM OS defined, then it is NONE - #ifndef SPIDER_OS_MCU - #define SPIDER_OS_NONE - #endif - -#elif defined(SPIDER_DISTRO_MICRO) - #error "[Spider Distro] Unsupported SPIDER_MCU_FAM. Define SPIDER_MCU_GENERIC and see if works." -#endif +#pragma once + +// ========================================================== // +// SPIDER MICROCONTROLLER AUTODETECT // +// ========================================================== // + +// Automatically enable configurations for the microcontroller // +// so long as we can detect it or the user has already configured // +// the corresponding macros. // + +#define SPIDER_MCU_FAM_GENERIC 0 +#define SPIDER_MCU_FAM_AVR 1 +#define SPIDER_MCU_FAM_ARM_CM 2 +#define SPIDER_MCU_FAM_ARM_MBED 3 +#define SPIDER_MCU_FAM_PIC 4 +#define SPIDER_MCU_FAM_PIC32 5 +#define SPIDER_MCU_FAM_ESP8266 6 +#define SPIDER_MCU_FAM_ESP32 7 +#define SPIDER_MCU_FAM_RISCV 8 +#define SPIDER_MCU_FAM_RP2040 9 + +#if defined(SPIDER_MCU_AVR) || defined(__avr__) || defined(__AVR__) +// ========================================================== // +// AVR (Atmel / Microchip) // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_AVR + #define SPIDER_MCU_NAME "AVR" + +#elif defined(SPIDER_MCU_ARM) || defined(__arm__) || defined(__ARM_ARCH) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6M__) +// ========================================================== // +// ARM Cortex-M (most STM32, nRF, etc.) // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_CM + #define SPIDER_MCU_NAME "ARM Cortex-M" + +#elif defined(SPIDER_MCU_MBED) || defined(TARGET_LIKE_MBED) +// ========================================================== // +// Mbed OS special detection // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_MBED + #define SPIDER_MCU_NAME "ARM MBED" + #define SPIDER_OS_NAME "MBED OS" + +#elif defined(SPIDER_MCU_PIC8) || defined(__XC) && (defined(_PIC14) || defined(_PIC16)) +// ========================================================== // +// PIC (8-bit) // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC + #define SPIDER_MCU_NAME "PIC (8-bit)" + +#elif defined(SPIDER_MCU_PIC32) || defined(__XC32__) +// ========================================================== // +// PIC32 (MIPS) // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC32 + #define SPIDER_MCU_NAME "PIC (32-bit)" + +#elif defined(SPIDER_MCU_ESP8266) || defined(ESP8266) +// ========================================================== // +// ESP8266 // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP8266 + #define SPIDER_MCU_NAME "ESP-8266" + +#elif defined(SPIDER_MCU_ESP32) || defined(ESP32) +// ========================================================== // +// ESP32 // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP32 + #define SPIDER_MCU_NAME "ESP-32" + +#elif defined(SPIDER_MCU_PICO) || defined(PICO_PLATFORM) || defined(PICO_BOARD) || defined(RP2040) || defined(__RP2040__) +// ========================================================== // +// Raspberry Pi Pico (RP2040) // +// ========================================================== // + #define SPIDER_MCU_FAM_FAMILY SPIDER_MCU_FAM_RP2040 + #define SPIDER_MCU_NAME "ESP-32" + +#elif defined(SPIDER_MCU_RISCV) || defined(__riscv) || defined(__riscv__) +// ========================================================== // +// RISC-V MCUs // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_RISCV + #define SPIDER_MCU_NAME "RISC-V MCU" + +#elif defined(SPIDER_MCU_GENERIC) +// ========================================================== // +// GENERIC MICRO // +// ========================================================== // + #define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_GENERIC + #define SPIDER_MCU_NAME "Generic MCU" +#endif + +#ifdef SPIDER_MCU_FAMILY + + #ifndef SPIDER_DISTRO_MICRO + #define SPIDER_DISTRO_MICRO + #endif + + // If SPIDER_OS_NAME was already defined, implies the SPIDER_MCU_FAM has an OS + #if defined(SPIDER_OS_NAME) && !defined(SPIDER_OS_MCU) + #define SPIDER_OS_MCU + #endif + + // If no SPIDER_MCU_FAM OS defined, then it is NONE + #ifndef SPIDER_OS_MCU + #define SPIDER_OS_NONE + #endif + +#elif defined(SPIDER_DISTRO_MICRO) + #error "[Spider Distro] Unsupported SPIDER_MCU_FAM. Define SPIDER_MCU_GENERIC and see if works." +#endif diff --git a/src/spider/runtime/native/machine.hpp b/src/spider/runtime/native/machine.hpp index d48186c..7136158 100644 --- a/src/spider/runtime/native/machine.hpp +++ b/src/spider/runtime/native/machine.hpp @@ -1,93 +1,93 @@ -#pragma once - -/* - * This file contains macros related to machine dependent - * things like alignment and type juggling -*/ - -// ========================================================== // -// ENDIANNESS // -// ========================================================== // - -// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) - #define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - #define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - -// Fallbacks (For older/constrained compilers) -#else - #if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega - #define SPIDER_LITTLE_ENDIAN 1 - #define SPIDER_BIG_ENDIAN 0 - #elif defined(__wasm__) || defined(__wasm32__) // WebAssembly - #define SPIDER_LITTLE_ENDIAN 1 - #define SPIDER_BIG_ENDIAN 0 - #elif defined(__arm__) || defined(__thumb__) // RP2040, STM32, etc. - #if defined(__ARMEB__) - #define SPIDER_LITTLE_ENDIAN 0 - #define SPIDER_BIG_ENDIAN 1 - #else - #define SPIDER_LITTLE_ENDIAN 1 - #define SPIDER_BIG_ENDIAN 0 - #endif - #elif defined(__xtensa__) || defined(__ESP32__) // ESP32 - #define SPIDER_LITTLE_ENDIAN 1 - #define SPIDER_BIG_ENDIAN 0 - // Likely will never use this clause - // ...but keeps compatibility with the one (1) - // guy who uses MSVC. - #elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64) - #define SPIDER_LITTLE_ENDIAN 1 - #define SPIDER_BIG_ENDIAN 0 - #else - #error "[Spider Machine] Unsupported or unknown architecture endianness!" - #endif -#endif - -// Safety checks -#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN) - #error "[Spider Machine] Missed at least one little/big endian macros" -#endif -#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1 - #warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!" -#endif - - -// ========================================================== // -// PACKING // -// (not used now) // -// ========================================================== // - -// Find out what compiler the user is using -#if defined(__clang__) - #define SPIDER_COMPILER_CLANG - #define SPIDER_COMPILER_GCC_LIKE -#elif defined(__GNUC__) - #define SPIDER_COMPILER_GCC - #define SPIDER_COMPILER_GCC_LIKE -#elif defined(_MSC_VER) - #define SPIDER_COMPILER_MSVC -#else - #define SPIDER_COMPILER_UNKNOWN -#endif - -// Macros... -#if defined(SPIDER_COMPILER_GCC_LIKE) - #define SPIDER_PACK_BEGIN - #define SPIDER_PACK_END - #define SPIDER_PACK_STRUCT __attribute__((packed)) - -#elif defined(SPIDER_COMPILER_MSVC) - #define SPIDER_BEGIN_PACKED __pragma(pack(push, 1)) - #define SPIDER_END_PACKED __pragma(pack(pop)) - #define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED - -#else - #define SPIDER_ATTRIBUTE_PACKED - #define SPIDER_BEGIN_PACKED - #define SPIDER_END_PACKED - #define SPIDER_PACKED_STRUCT(decl) decl - #warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!" -#endif - -namespace spider {} +#pragma once + +/* + * This file contains macros related to machine dependent + * things like alignment and type juggling +*/ + +// ========================================================== // +// ENDIANNESS // +// ========================================================== // + +// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) + #define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + +// Fallbacks (For older/constrained compilers) +#else + #if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega + #define SPIDER_LITTLE_ENDIAN 1 + #define SPIDER_BIG_ENDIAN 0 + #elif defined(__wasm__) || defined(__wasm32__) // WebAssembly + #define SPIDER_LITTLE_ENDIAN 1 + #define SPIDER_BIG_ENDIAN 0 + #elif defined(__arm__) || defined(__thumb__) // RP2040, STM32, etc. + #if defined(__ARMEB__) + #define SPIDER_LITTLE_ENDIAN 0 + #define SPIDER_BIG_ENDIAN 1 + #else + #define SPIDER_LITTLE_ENDIAN 1 + #define SPIDER_BIG_ENDIAN 0 + #endif + #elif defined(__xtensa__) || defined(__ESP32__) // ESP32 + #define SPIDER_LITTLE_ENDIAN 1 + #define SPIDER_BIG_ENDIAN 0 + // Likely will never use this clause + // ...but keeps compatibility with the one (1) + // guy who uses MSVC. + #elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64) + #define SPIDER_LITTLE_ENDIAN 1 + #define SPIDER_BIG_ENDIAN 0 + #else + #error "[Spider Machine] Unsupported or unknown architecture endianness!" + #endif +#endif + +// Safety checks +#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN) + #error "[Spider Machine] Missed at least one little/big endian macros" +#endif +#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1 + #warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!" +#endif + + +// ========================================================== // +// PACKING // +// (not used now) // +// ========================================================== // + +// Find out what compiler the user is using +#if defined(__clang__) + #define SPIDER_COMPILER_CLANG + #define SPIDER_COMPILER_GCC_LIKE +#elif defined(__GNUC__) + #define SPIDER_COMPILER_GCC + #define SPIDER_COMPILER_GCC_LIKE +#elif defined(_MSC_VER) + #define SPIDER_COMPILER_MSVC +#else + #define SPIDER_COMPILER_UNKNOWN +#endif + +// Macros... +#if defined(SPIDER_COMPILER_GCC_LIKE) + #define SPIDER_PACK_BEGIN + #define SPIDER_PACK_END + #define SPIDER_PACK_STRUCT __attribute__((packed)) + +#elif defined(SPIDER_COMPILER_MSVC) + #define SPIDER_BEGIN_PACKED __pragma(pack(push, 1)) + #define SPIDER_END_PACKED __pragma(pack(pop)) + #define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED + +#else + #define SPIDER_ATTRIBUTE_PACKED + #define SPIDER_BEGIN_PACKED + #define SPIDER_END_PACKED + #define SPIDER_PACKED_STRUCT(decl) decl + #warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!" +#endif + +namespace spider {} diff --git a/src/spider/runtime/reel/InstrReel.cpp b/src/spider/runtime/reel/InstrReel.cpp index 88df155..4837c66 100644 --- a/src/spider/runtime/reel/InstrReel.cpp +++ b/src/spider/runtime/reel/InstrReel.cpp @@ -1,77 +1,77 @@ -#include "InstrReel.hpp" - -#include - -#include - -namespace spider { - - // Public Interface // - - InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {} - - InstrReel::~InstrReel() {} - - // Instruction abstraction // - - u8 InstrReel::atU8(u64 ip) { - // guard against access - u64 ip_p = ip - _offset; - if(ip_p + 1 > _size) return 0; - - // send byte - return _mem[ip]; - } - - u16 InstrReel::atU16(u64 ip) { - // guard against access - u64 ip_p = ip - _offset; - if(ip_p + 2 > _size) return 0; - - // build a 16-bit big endian number - u16 dat; - spider::loadLE(&dat, _mem + ip_p); - return dat; - } - - u32 InstrReel::atU32(u64 ip) { - // guard against access - u64 ip_p = ip - _offset; - if(ip_p + 4 > _size) return 0; - - // build a 32-bit big endian number - u32 dat; - spider::loadLE(&dat, _mem + ip_p); - return dat; - } - - u64 InstrReel::atU64(u64 ip) { - // guard against access - u64 ip_p = ip - _offset; - if(ip_p + 8 > _size) return 0; - - // build a 64-bit big endian number - u64 dat; - spider::loadLE(&dat, _mem + ip_p); - return dat; - } - - u64 InstrReel::size() { - return _total_size; - } - - // Static Utils // - - u16 InstrReel::unpackInstr(u16 bcode) { - return (bcode >> 5) & 0x1FF; - } - - u8 InstrReel::unpackAddrMode(u16 bcode) { - return (bcode >> 2) & 0x1F; - } - - u8 InstrReel::unpackTypeSize(u16 bcode) { - return bcode & 0x3; - } - -} +#include "InstrReel.hpp" + +#include + +#include + +namespace spider { + + // Public Interface // + + InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {} + + InstrReel::~InstrReel() {} + + // Instruction abstraction // + + u8 InstrReel::atU8(u64 ip) { + // guard against access + u64 ip_p = ip - _offset; + if(ip_p + 1 > _size) return 0; + + // send byte + return _mem[ip]; + } + + u16 InstrReel::atU16(u64 ip) { + // guard against access + u64 ip_p = ip - _offset; + if(ip_p + 2 > _size) return 0; + + // build a 16-bit big endian number + u16 dat; + spider::loadLE(&dat, _mem + ip_p); + return dat; + } + + u32 InstrReel::atU32(u64 ip) { + // guard against access + u64 ip_p = ip - _offset; + if(ip_p + 4 > _size) return 0; + + // build a 32-bit big endian number + u32 dat; + spider::loadLE(&dat, _mem + ip_p); + return dat; + } + + u64 InstrReel::atU64(u64 ip) { + // guard against access + u64 ip_p = ip - _offset; + if(ip_p + 8 > _size) return 0; + + // build a 64-bit big endian number + u64 dat; + spider::loadLE(&dat, _mem + ip_p); + return dat; + } + + u64 InstrReel::size() { + return _total_size; + } + + // Static Utils // + + u16 InstrReel::unpackInstr(u16 bcode) { + return (bcode >> 5) & 0x1FF; + } + + u8 InstrReel::unpackAddrMode(u16 bcode) { + return (bcode >> 2) & 0x1F; + } + + u8 InstrReel::unpackTypeSize(u16 bcode) { + return bcode & 0x3; + } + +} diff --git a/src/spider/runtime/reel/InstrReel.hpp b/src/spider/runtime/reel/InstrReel.hpp index 06a3d14..e96a6d9 100644 --- a/src/spider/runtime/reel/InstrReel.hpp +++ b/src/spider/runtime/reel/InstrReel.hpp @@ -1,74 +1,74 @@ -#pragma once - -#include -#include - -namespace spider { - - /** - * Implements an instruction reel. - */ - class InstrReel { - protected: // Current accessing range // - - u8* _mem; - isize _size; - isize _offset; - isize _total_size; - - public: - - InstrReel(); - - virtual ~InstrReel(); - - public: - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u8 atU8(u64 ip); - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u16 atU16(u64 ip); - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u32 atU32(u64 ip); - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u64 atU64(u64 ip); - - /** - * Current size of the instructions. - */ - virtual u64 size(); - - public: // Static Utils // - - static u16 unpackInstr(u16 bcode); - - static u8 unpackAddrMode(u16 bcode); - - static u8 unpackTypeSize(u16 bcode); - - }; - -} +#pragma once + +#include +#include + +namespace spider { + + /** + * Implements an instruction reel. + */ + class InstrReel { + protected: // Current accessing range // + + u8* _mem; + isize _size; + isize _offset; + isize _total_size; + + public: + + InstrReel(); + + virtual ~InstrReel(); + + public: + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u8 atU8(u64 ip); + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u16 atU16(u64 ip); + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u32 atU32(u64 ip); + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u64 atU64(u64 ip); + + /** + * Current size of the instructions. + */ + virtual u64 size(); + + public: // Static Utils // + + static u16 unpackInstr(u16 bcode); + + static u8 unpackAddrMode(u16 bcode); + + static u8 unpackTypeSize(u16 bcode); + + }; + +} diff --git a/src/spider/runtime/reel/InstrReelDyn.cpp b/src/spider/runtime/reel/InstrReelDyn.cpp index 2e66a25..0c64008 100644 --- a/src/spider/runtime/reel/InstrReelDyn.cpp +++ b/src/spider/runtime/reel/InstrReelDyn.cpp @@ -1,194 +1,194 @@ -#include "InstrReelDyn.hpp" - -#include - -namespace spider { - - InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) { - _total_size = length; - growToFit(length > 0 ? length - 1 : 0); - selectBlock(0); - } - - InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {} - - InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) : _use_count(copy._use_count), _block_index(copy._block_index), _blocks(copy._blocks) { - if (_block_index < _blocks.size()) selectBlock(_block_index); - } - - InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept : _use_count(move._use_count), _block_index(move._block_index), _blocks(std::move(move._blocks)) { - if (_block_index < _blocks.size()) selectBlock(_block_index); - } - - InstrReelDyn::~InstrReelDyn() { - // .. // - } - - InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) { - _use_count = copy._use_count; - _block_index = copy._block_index; - _blocks = copy._blocks; - if (_block_index < _blocks.size()) selectBlock(_block_index); - return *this; - } - - InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept { - _use_count = move._use_count; - _block_index = move._block_index; - _blocks = std::move(move._blocks); - if (_block_index < _blocks.size()) selectBlock(_block_index); - - move._use_count = 0; - move._block_index = 0; - move._mem = nullptr; - move._offset = 0; - move._size = 0; - move._total_size = 0; - return *this; - } - - void InstrReelDyn::growToFit(isize index) { - while (_blocks.size() < (index + 1)) { - _blocks.emplace_back(); - } - } - - isize InstrReelDyn::selectIndex(u64 ip) { - return ip / 256; - } - - InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) { - // Update base class cache - auto ptr = &_blocks[index]; - _offset = index * 256; - _mem = ptr->data; - _size = 256; - _block_index = index; - - //_blocks[block_idx].access_count++; - return ptr; - } - - u8 InstrReelDyn::atU8(u64 ip) { - isize j = selectIndex(ip); - if (j >= _blocks.size()) return 0; - if (j != _block_index) { - this->selectBlock(j); - } - return _mem[ip - _offset]; - } - - u16 InstrReelDyn::atU16(u64 ip) { - isize j0 = selectIndex(ip); - isize j1 = selectIndex(ip + 1); - if (j1 >= _blocks.size()) return 0; - if (j0 == j1 && j0 != _block_index) { - selectBlock(j0); - } - if (j0 == j1 && j0 == _block_index) { - u16 dat; - spider::loadLE(&dat, _mem); - return dat; - } - - // general case, first part - u16 dat = 0; - const u8 size = sizeof(u16); - - // select first block and offset - selectBlock(j0); - u8 rem = ip % 256; - - for (u8 n = 0; n < size; n++) { - dat |= _mem[rem++] << (n * 8); - ip++; - if (!rem) selectBlock(++j0); - } - - return dat; - } - - u32 InstrReelDyn::atU32(u64 ip) { - isize j0 = selectIndex(ip); - isize j1 = selectIndex(ip + 3); - if (j1 >= _blocks.size()) return 0; - if (j0 == j1 && j0 != _block_index) { - selectBlock(j0); - } - if (j0 == j1 && j0 == _block_index) { - u32 dat; - spider::loadLE(&dat, _mem); - return dat; - } - - // general case, first part - u32 dat = 0; - const u8 size = sizeof(u32); - - // select first block and offset - selectBlock(j0); - u8 rem = ip % 256; - - for (u8 n = 0; n < size; n++) { - dat |= _mem[rem++] << (n * 8); - ip++; - if (!rem) selectBlock(++j0); - } - - return dat; - } - - u64 InstrReelDyn::atU64(u64 ip) { - isize j0 = selectIndex(ip); - isize j1 = selectIndex(ip + 3); - if (j1 >= _blocks.size()) return 0; - if (j0 == j1 && j0 != _block_index) { - selectBlock(j0); - } - if (j0 == j1 && j0 == _block_index) { - u64 dat; - spider::loadLE(&dat, _mem); - return dat; - } - - // general case, first part - u64 dat = 0; - const u8 size = sizeof(u64); - - // select first block and offset - selectBlock(j0); - u8 rem = ip % 256; - - for (u8 n = 0; n < size; n++) { - dat |= _mem[rem++] << (n * 8); - ip++; - if (!rem) selectBlock(++j0); - } - - return dat; - } - - void InstrReelDyn::at(u64 ip, u8 dat) {} - - void InstrReelDyn::at(u64 ip, u16 dat) {} - - void InstrReelDyn::at(u64 ip, u32 dat) {} - - void InstrReelDyn::at(u64 ip, u64 dat) {} - - /** - * Appends instruction at location. - */ - void InstrReelDyn::append(u64 ip, u16 bc) {} - - /** - * Appends instruction at the end. - */ - void InstrReelDyn::append(u16 bc) {} - - /** - * Removes instruction at location. - */ - void InstrReelDyn::remove(u64 ip) {} - -} +#include "InstrReelDyn.hpp" + +#include + +namespace spider { + + InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) { + _total_size = length; + growToFit(length > 0 ? length - 1 : 0); + selectBlock(0); + } + + InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {} + + InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) : _use_count(copy._use_count), _block_index(copy._block_index), _blocks(copy._blocks) { + if (_block_index < _blocks.size()) selectBlock(_block_index); + } + + InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept : _use_count(move._use_count), _block_index(move._block_index), _blocks(std::move(move._blocks)) { + if (_block_index < _blocks.size()) selectBlock(_block_index); + } + + InstrReelDyn::~InstrReelDyn() { + // .. // + } + + InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) { + _use_count = copy._use_count; + _block_index = copy._block_index; + _blocks = copy._blocks; + if (_block_index < _blocks.size()) selectBlock(_block_index); + return *this; + } + + InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept { + _use_count = move._use_count; + _block_index = move._block_index; + _blocks = std::move(move._blocks); + if (_block_index < _blocks.size()) selectBlock(_block_index); + + move._use_count = 0; + move._block_index = 0; + move._mem = nullptr; + move._offset = 0; + move._size = 0; + move._total_size = 0; + return *this; + } + + void InstrReelDyn::growToFit(isize index) { + while (_blocks.size() < (index + 1)) { + _blocks.emplace_back(); + } + } + + isize InstrReelDyn::selectIndex(u64 ip) { + return ip / 256; + } + + InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) { + // Update base class cache + auto ptr = &_blocks[index]; + _offset = index * 256; + _mem = ptr->data; + _size = 256; + _block_index = index; + + //_blocks[block_idx].access_count++; + return ptr; + } + + u8 InstrReelDyn::atU8(u64 ip) { + isize j = selectIndex(ip); + if (j >= _blocks.size()) return 0; + if (j != _block_index) { + this->selectBlock(j); + } + return _mem[ip - _offset]; + } + + u16 InstrReelDyn::atU16(u64 ip) { + isize j0 = selectIndex(ip); + isize j1 = selectIndex(ip + 1); + if (j1 >= _blocks.size()) return 0; + if (j0 == j1 && j0 != _block_index) { + selectBlock(j0); + } + if (j0 == j1 && j0 == _block_index) { + u16 dat; + spider::loadLE(&dat, _mem); + return dat; + } + + // general case, first part + u16 dat = 0; + const u8 size = sizeof(u16); + + // select first block and offset + selectBlock(j0); + u8 rem = ip % 256; + + for (u8 n = 0; n < size; n++) { + dat |= _mem[rem++] << (n * 8); + ip++; + if (!rem) selectBlock(++j0); + } + + return dat; + } + + u32 InstrReelDyn::atU32(u64 ip) { + isize j0 = selectIndex(ip); + isize j1 = selectIndex(ip + 3); + if (j1 >= _blocks.size()) return 0; + if (j0 == j1 && j0 != _block_index) { + selectBlock(j0); + } + if (j0 == j1 && j0 == _block_index) { + u32 dat; + spider::loadLE(&dat, _mem); + return dat; + } + + // general case, first part + u32 dat = 0; + const u8 size = sizeof(u32); + + // select first block and offset + selectBlock(j0); + u8 rem = ip % 256; + + for (u8 n = 0; n < size; n++) { + dat |= _mem[rem++] << (n * 8); + ip++; + if (!rem) selectBlock(++j0); + } + + return dat; + } + + u64 InstrReelDyn::atU64(u64 ip) { + isize j0 = selectIndex(ip); + isize j1 = selectIndex(ip + 3); + if (j1 >= _blocks.size()) return 0; + if (j0 == j1 && j0 != _block_index) { + selectBlock(j0); + } + if (j0 == j1 && j0 == _block_index) { + u64 dat; + spider::loadLE(&dat, _mem); + return dat; + } + + // general case, first part + u64 dat = 0; + const u8 size = sizeof(u64); + + // select first block and offset + selectBlock(j0); + u8 rem = ip % 256; + + for (u8 n = 0; n < size; n++) { + dat |= _mem[rem++] << (n * 8); + ip++; + if (!rem) selectBlock(++j0); + } + + return dat; + } + + void InstrReelDyn::at(u64 ip, u8 dat) {} + + void InstrReelDyn::at(u64 ip, u16 dat) {} + + void InstrReelDyn::at(u64 ip, u32 dat) {} + + void InstrReelDyn::at(u64 ip, u64 dat) {} + + /** + * Appends instruction at location. + */ + void InstrReelDyn::append(u64 ip, u16 bc) {} + + /** + * Appends instruction at the end. + */ + void InstrReelDyn::append(u16 bc) {} + + /** + * Removes instruction at location. + */ + void InstrReelDyn::remove(u64 ip) {} + +} diff --git a/src/spider/runtime/reel/InstrReelDyn.hpp b/src/spider/runtime/reel/InstrReelDyn.hpp index 1b5a4c7..6b8cc3e 100644 --- a/src/spider/runtime/reel/InstrReelDyn.hpp +++ b/src/spider/runtime/reel/InstrReelDyn.hpp @@ -1,110 +1,110 @@ -#pragma once - -#include - -namespace spider { - - /** - * Implements an instruction reel. - */ - class InstrReelDyn : public InstrReel { - private: - - struct ReelBlock { - u8 data[256] = {}; - }; - - private: - - u64 _use_count; - isize _block_index; - std::deque _blocks; - - public: - - InstrReelDyn(u64 length); - - InstrReelDyn(const u8* data, u64 length); - - InstrReelDyn(const InstrReelDyn& copy); - - InstrReelDyn(InstrReelDyn&& move) noexcept; - - virtual ~InstrReelDyn(); - - public: - - InstrReelDyn& operator=(const InstrReelDyn& copy); - - InstrReelDyn& operator=(InstrReelDyn&& move) noexcept; - - private: - - isize selectIndex(u64 ip); - - void growToFit(isize index); - - ReelBlock* selectBlock(isize index); - - public: - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u8 atU8(u64 ip) override; - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u16 atU16(u64 ip) override; - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u32 atU32(u64 ip) override; - - /** - * Obtains a byte of data at - * the specific location. - * Reindexing may occur, continous access - * may incurr in less penalties. - */ - virtual u64 atU64(u64 ip) override; - - public: - - void at(u64 ip, u8 dat); - - void at(u64 ip, u16 dat); - - void at(u64 ip, u32 dat); - - void at(u64 ip, u64 dat); - - /** - * Appends instruction at location. - */ - void append(u64 ip, u16 bc); - - /** - * Appends instruction at the end. - */ - void append(u16 bc); - - /** - * Removes instruction at location. - */ - void remove(u64 ip); - - }; - -} +#pragma once + +#include + +namespace spider { + + /** + * Implements an instruction reel. + */ + class InstrReelDyn : public InstrReel { + private: + + struct ReelBlock { + u8 data[256] = {}; + }; + + private: + + u64 _use_count; + isize _block_index; + std::deque _blocks; + + public: + + InstrReelDyn(u64 length); + + InstrReelDyn(const u8* data, u64 length); + + InstrReelDyn(const InstrReelDyn& copy); + + InstrReelDyn(InstrReelDyn&& move) noexcept; + + virtual ~InstrReelDyn(); + + public: + + InstrReelDyn& operator=(const InstrReelDyn& copy); + + InstrReelDyn& operator=(InstrReelDyn&& move) noexcept; + + private: + + isize selectIndex(u64 ip); + + void growToFit(isize index); + + ReelBlock* selectBlock(isize index); + + public: + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u8 atU8(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u16 atU16(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u32 atU32(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u64 atU64(u64 ip) override; + + public: + + void at(u64 ip, u8 dat); + + void at(u64 ip, u16 dat); + + void at(u64 ip, u32 dat); + + void at(u64 ip, u64 dat); + + /** + * Appends instruction at location. + */ + void append(u64 ip, u16 bc); + + /** + * Appends instruction at the end. + */ + void append(u16 bc); + + /** + * Removes instruction at location. + */ + void remove(u64 ip); + + }; + +} diff --git a/src/spider/runtime/reel/InstrReelFixed.cpp b/src/spider/runtime/reel/InstrReelFixed.cpp index 0c41e7f..49373b8 100644 --- a/src/spider/runtime/reel/InstrReelFixed.cpp +++ b/src/spider/runtime/reel/InstrReelFixed.cpp @@ -1,149 +1,149 @@ -#include "InstrReelFixed.hpp" - -#include - -#include - -namespace spider { - - // Constructors & Destructors // - - InstrReelFixed::InstrReelFixed(u64 length) { - this->_offset = 0; - this->_size = length; - this->_total_size = length; - - if (_size > 0) { - _mem = new u8[_size]; - std::memset(_mem, 0, _size); - } - } - - InstrReelFixed::InstrReelFixed(const u8* data, u64 length) { - this->_offset = 0; - this->_size = length; - this->_total_size = length; - - if (_size > 0) { - _mem = new u8[_size]; - std::copy(data, data + _size, _mem); - } - } - - InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) { - _offset = other._offset; - _size = other._size; - _total_size = other._total_size; - _mem = new u8[_size]; - std::copy(other._mem, other._mem + _size, _mem); - } - - InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept { - _mem = other._mem; - _offset = other._offset; - _size = other._size; - _total_size = other._total_size; - - other._mem = nullptr; - other._offset = 0; - other._size = 0; - other._total_size = 0; - } - - InstrReelFixed::~InstrReelFixed() { - delete[] _mem; - } - - // Assign Operators // - - InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& other) { - if (this == &other) return *this; // lock self - - u8* new_mem = new u8[other._size]; - std::copy(other._mem, other._mem + other._size, new_mem); - - delete[] _mem; - _mem = new_mem; - _offset = other._offset; - _size = other._size; - _total_size = other._total_size; - - return *this; - } - - InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept { - if (this == &other) return *this; // lock self - - delete[] _mem; - - _mem = other._mem; // steal - _offset = other._offset; - _size = other._size; - _total_size = other._total_size; - - other._mem = nullptr; // leave as husk - other._offset = 0; - other._size = 0; - other._total_size = 0; - - return *this; - } - - // Misc // - - void InstrReelFixed::at(u64 ip, u8 dat) { - if(ip + 1 > _size) return; - _mem[ip] = dat; - } - - void InstrReelFixed::at(u64 ip, u16 dat) { - if(ip + 2 > _size) return; - spider::storeLE(dat, _mem + ip); - } - - void InstrReelFixed::at(u64 ip, u32 dat) { - if(ip + 4 > _size) return; - spider::storeLE(dat, _mem + ip); - } - - void InstrReelFixed::at(u64 ip, u64 dat) { - if(ip + 8 > _size) return; - spider::storeLE(dat, _mem + ip); - } - - void InstrReelFixed::resize(u64 new_size) { - // Special case 1 - if (new_size == _size) return; - - // Special case 2 - if (new_size == 0) { - delete[] _mem; - _mem = nullptr; - _size = 0; - _total_size = 0; - return; - } - - // 1. Allocate the new block - u8* new_mem = new u8[new_size]; - - // 2. Zero-initialize - std::memset(new_mem, 0, new_size); - - // 3. Preserve data - // If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes. - u64 bytes_to_copy = (new_size < _size) ? new_size : _size; - - // 3.1 Previous size could be zero, where _mem would be null - if (_mem != nullptr) { - std::copy(_mem, _mem + bytes_to_copy, new_mem); - } - - // 4. Swap and Clean up - delete[] _mem; - _mem = new_mem; - _size = new_size; - _total_size = new_size; - } - -} +#include "InstrReelFixed.hpp" + +#include + +#include + +namespace spider { + + // Constructors & Destructors // + + InstrReelFixed::InstrReelFixed(u64 length) { + this->_offset = 0; + this->_size = length; + this->_total_size = length; + + if (_size > 0) { + _mem = new u8[_size]; + std::memset(_mem, 0, _size); + } + } + + InstrReelFixed::InstrReelFixed(const u8* data, u64 length) { + this->_offset = 0; + this->_size = length; + this->_total_size = length; + + if (_size > 0) { + _mem = new u8[_size]; + std::copy(data, data + _size, _mem); + } + } + + InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) { + _offset = other._offset; + _size = other._size; + _total_size = other._total_size; + _mem = new u8[_size]; + std::copy(other._mem, other._mem + _size, _mem); + } + + InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept { + _mem = other._mem; + _offset = other._offset; + _size = other._size; + _total_size = other._total_size; + + other._mem = nullptr; + other._offset = 0; + other._size = 0; + other._total_size = 0; + } + + InstrReelFixed::~InstrReelFixed() { + delete[] _mem; + } + + // Assign Operators // + + InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& other) { + if (this == &other) return *this; // lock self + + u8* new_mem = new u8[other._size]; + std::copy(other._mem, other._mem + other._size, new_mem); + + delete[] _mem; + _mem = new_mem; + _offset = other._offset; + _size = other._size; + _total_size = other._total_size; + + return *this; + } + + InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept { + if (this == &other) return *this; // lock self + + delete[] _mem; + + _mem = other._mem; // steal + _offset = other._offset; + _size = other._size; + _total_size = other._total_size; + + other._mem = nullptr; // leave as husk + other._offset = 0; + other._size = 0; + other._total_size = 0; + + return *this; + } + + // Misc // + + void InstrReelFixed::at(u64 ip, u8 dat) { + if(ip + 1 > _size) return; + _mem[ip] = dat; + } + + void InstrReelFixed::at(u64 ip, u16 dat) { + if(ip + 2 > _size) return; + spider::storeLE(dat, _mem + ip); + } + + void InstrReelFixed::at(u64 ip, u32 dat) { + if(ip + 4 > _size) return; + spider::storeLE(dat, _mem + ip); + } + + void InstrReelFixed::at(u64 ip, u64 dat) { + if(ip + 8 > _size) return; + spider::storeLE(dat, _mem + ip); + } + + void InstrReelFixed::resize(u64 new_size) { + // Special case 1 + if (new_size == _size) return; + + // Special case 2 + if (new_size == 0) { + delete[] _mem; + _mem = nullptr; + _size = 0; + _total_size = 0; + return; + } + + // 1. Allocate the new block + u8* new_mem = new u8[new_size]; + + // 2. Zero-initialize + std::memset(new_mem, 0, new_size); + + // 3. Preserve data + // If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes. + u64 bytes_to_copy = (new_size < _size) ? new_size : _size; + + // 3.1 Previous size could be zero, where _mem would be null + if (_mem != nullptr) { + std::copy(_mem, _mem + bytes_to_copy, new_mem); + } + + // 4. Swap and Clean up + delete[] _mem; + _mem = new_mem; + _size = new_size; + _total_size = new_size; + } + +} diff --git a/src/spider/runtime/reel/InstrReelFixed.hpp b/src/spider/runtime/reel/InstrReelFixed.hpp index 505c0be..f756a15 100644 --- a/src/spider/runtime/reel/InstrReelFixed.hpp +++ b/src/spider/runtime/reel/InstrReelFixed.hpp @@ -1,43 +1,43 @@ -#pragma once - -#include - -namespace spider { - - /** - * Implements an instruction reel. - */ - class InstrReelFixed : public InstrReel { - public: - - InstrReelFixed(u64 length); - - InstrReelFixed(const u8* data, u64 length); - - InstrReelFixed(const InstrReelFixed& copy); - - InstrReelFixed(InstrReelFixed&& move) noexcept; - - virtual ~InstrReelFixed(); - - public: - - InstrReelFixed& operator=(const InstrReelFixed& copy); - - InstrReelFixed& operator=(InstrReelFixed&& move) noexcept; - - public: - - void at(u64 ip, u8 dat); - - void at(u64 ip, u16 dat); - - void at(u64 ip, u32 dat); - - void at(u64 ip, u64 dat); - - void resize(u64 new_size); - - }; - -} +#pragma once + +#include + +namespace spider { + + /** + * Implements an instruction reel. + */ + class InstrReelFixed : public InstrReel { + public: + + InstrReelFixed(u64 length); + + InstrReelFixed(const u8* data, u64 length); + + InstrReelFixed(const InstrReelFixed& copy); + + InstrReelFixed(InstrReelFixed&& move) noexcept; + + virtual ~InstrReelFixed(); + + public: + + InstrReelFixed& operator=(const InstrReelFixed& copy); + + InstrReelFixed& operator=(InstrReelFixed&& move) noexcept; + + public: + + void at(u64 ip, u8 dat); + + void at(u64 ip, u16 dat); + + void at(u64 ip, u32 dat); + + void at(u64 ip, u64 dat); + + void resize(u64 new_size); + + }; + +} diff --git a/src/spider/runtime/util/Terminal.cpp b/src/spider/runtime/util/Terminal.cpp index 52eb4c8..fbb9cc2 100644 --- a/src/spider/runtime/util/Terminal.cpp +++ b/src/spider/runtime/util/Terminal.cpp @@ -1,277 +1,277 @@ -#include "Terminal.hpp" - -#include - -#if defined(SPIDER_OS_WINDOWS) -#include -#include -#endif - -#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) -#include -#include -#include -#endif - -#if defined(SPIDER_DISTRO_DESKTOP) - -namespace spider { - - // Style // - const char* Terminal::RESET = "\033[0m"; - const char* Terminal::BOLD = "\033[1m"; - const char* Terminal::ITALIC = "\033[3m"; - const char* Terminal::FAINT = "\033[2m"; - const char* Terminal::STRIKE = "\033[9m"; - - // Foreground // - const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m"; - const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m"; - const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m"; - const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m"; - const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m"; - const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m"; - const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m"; - const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m"; - - // Background // - const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m"; - const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m"; - const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m"; - const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m"; - const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m"; - const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m"; - const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m"; - const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m"; - - Terminal::Terminal() { -#if defined(SPIDER_OS_WINDOWS) - // Enable UTF-8 - SetConsoleOutputCP(CP_UTF8); - SetConsoleCP(CP_UTF8); - - // enable vtp - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD dwMode = 0; - GetConsoleMode(hOut, &dwMode); - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(hOut, dwMode); -#endif - } - - Terminal::~Terminal() { - altbuff(false).style(RESET).cursor(true).flush(); - } - - Terminal& Terminal::style(const std::string_view code) { - std::cout << code; - return *this; - } - - Terminal& Terminal::move(i32 row, i32 col) { - std::cout << "\033[" << row << ";" << col << "H"; - return *this; - } - - Terminal& Terminal::altbuff(bool enable) { - std::cout << (enable ? "\033[?1049h" : "\033[?1049l"); - return *this; - } - - Terminal& Terminal::cls() { - std::cout << "\033[2J"; - return *this; - } - - Terminal& Terminal::scrollRange(i32 start, i32 end) { - std::cout << "\033[" << start << ";" << end << "r\033[?6h"; - return *this; - } - - Terminal& Terminal::undoSRange() { - std::cout << "\033[r\033[?6l\033[H"; - return *this; - } - - Terminal& Terminal::fill(const std::string_view color) { - this->style(color); - this->cls(); - return *this; - } - - Terminal& Terminal::clearRow(i32 row) { - // Move to row, column 1 - this->move(row, 1); - // \033[2K clears the entire line - std::cout << "\033[2K"; - return *this; - } - - Terminal& Terminal::clearRows(i32 start, i32 end) { - // Ensure we don't loop infinitely if start > end - if (start > end) std::swap(start, end); - - for (i32 i = start; i <= end; ++i) { - this->clearRow(i); - } - - // Optional: Move cursor back to the start of the cleared block - this->move(start, 1); - return *this; - } - - Terminal& Terminal::cursor(bool show) { - std::cout << (show ? "\033[?25h" : "\033[?25l"); - return *this; - } - - Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) { - // 1. Draw the top border - move(startRow, startCol); - std::cout << "┌"; - for (i32 i = 0; i < width - 2; ++i) std::cout << "─"; - std::cout << "┐"; - - // 2. Draw the sides - for (i32 i = 1; i < height - 1; ++i) { - move(startRow + i, startCol); - std::cout << "│"; - move(startRow + i, startCol + width - 1); - std::cout << "│"; - } - - // 3. Draw the bottom border - move(startRow + height - 1, startCol); - std::cout << "└"; - for (i32 i = 0; i < width - 2; ++i) std::cout << "─"; - std::cout << "┘"; - - // 4. Overlay the title if provided - if (!title.empty()) { - move(startRow, startCol + (width - title.size() - 2) / 2); - std::cout << " " << title << " "; - } - - std::cout.flush(); - return *this; - } - - Terminal& Terminal::flush() { - std::cout << std::flush; - return *this; - } - - Terminal& Terminal::sink() { - std::cin.clear(); -#if defined(SPIDER_OS_WINDOWS) - while (_kbhit()) _getch(); -#endif -#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) - tcflush(STDIN_FILENO, TCIFLUSH); -#endif - return *this; - } - - std::pair Terminal::getSize() { - std::pair pair; -#if defined(SPIDER_OS_WINDOWS) - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { - pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1; - pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - } -#endif -#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) - struct winsize w; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) { - pair.first = w.ws_col; - pair.second = w.ws_row; - } -#endif - return pair; - } - - Terminal& Terminal::wait() { - sink(); - std::cin.get(); - return *this; - } - - u8 Terminal::getKey() { -#if defined(SPIDER_OS_WINDOWS) - i32 ch = _getch(); - if (ch == 0 || ch == 224) { - switch (_getch()) { - case 72: return Terminal::UP; - case 80: return Terminal::DOWN; - case 75: return Terminal::LEFT; - case 77: return Terminal::RIGHT; - default: return Terminal::UNKNOWN; - } - } - if (ch == 13) return Terminal::ENTER; - if (ch == 27) return Terminal::ESC; - if (ch == 8) return Terminal::BACKSPACE; - return Terminal::UNKNOWN; -#endif -#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) - struct termios oldt, newt; - tcgetattr(STDIN_FILENO, &oldt); - newt = oldt; - newt.c_lflag &= ~(ICANON | ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - - u8 result = Terminal::UNKNOWN; - int ch = getchar(); - - if (ch == 27) { // Potential Escape Sequence - // Use a small timeout or check if more chars are in buffer - // to distinguish between 'Esc' key and 'Arrow' sequence - // Another Win for the Win API - struct timeval tv = { 0, 10000 }; // 10ms wait - fd_set fds; - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - - if (select(1, &fds, NULL, NULL, &tv) > 0) { - if (getchar() == '[') { - switch (getchar()) { - case 'A': result = Terminal::UP; break; - case 'B': result = Terminal::DOWN; break; - case 'D': result = Terminal::LEFT; break; - case 'C': result = Terminal::RIGHT; break; - } - } - } else { - result = Terminal::ESC; - } - } else if (ch == 10) result = Terminal::ENTER; - else if (ch == 127) result = Terminal::BACKSPACE; - else result = (u8)ch; - - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - return result; -#endif - } - - u8 Terminal::getKeyNb() { -#if defined(SPIDER_OS_WINDOWS) - if (_kbhit()) return getKey(); - return Terminal::UNKNOWN; -#endif -#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) - struct timeval tv = { 0, 0 }; - fd_set fds; - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - // select() returns > 0 if there is data to read - if (select(1, &fds, NULL, NULL, &tv) > 0) { - return getKey(); - } - return Terminal::UNKNOWN; -#endif - } - -} - -#endif +#include "Terminal.hpp" + +#include + +#if defined(SPIDER_OS_WINDOWS) +#include +#include +#endif + +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) +#include +#include +#include +#endif + +#if defined(SPIDER_DISTRO_DESKTOP) + +namespace spider { + + // Style // + const char* Terminal::RESET = "\033[0m"; + const char* Terminal::BOLD = "\033[1m"; + const char* Terminal::ITALIC = "\033[3m"; + const char* Terminal::FAINT = "\033[2m"; + const char* Terminal::STRIKE = "\033[9m"; + + // Foreground // + const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m"; + const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m"; + const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m"; + const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m"; + const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m"; + const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m"; + const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m"; + const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m"; + + // Background // + const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m"; + const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m"; + const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m"; + const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m"; + const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m"; + const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m"; + const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m"; + const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m"; + + Terminal::Terminal() { +#if defined(SPIDER_OS_WINDOWS) + // Enable UTF-8 + SetConsoleOutputCP(CP_UTF8); + SetConsoleCP(CP_UTF8); + + // enable vtp + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + GetConsoleMode(hOut, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hOut, dwMode); +#endif + } + + Terminal::~Terminal() { + altbuff(false).style(RESET).cursor(true).flush(); + } + + Terminal& Terminal::style(const std::string_view code) { + std::cout << code; + return *this; + } + + Terminal& Terminal::move(i32 row, i32 col) { + std::cout << "\033[" << row << ";" << col << "H"; + return *this; + } + + Terminal& Terminal::altbuff(bool enable) { + std::cout << (enable ? "\033[?1049h" : "\033[?1049l"); + return *this; + } + + Terminal& Terminal::cls() { + std::cout << "\033[2J"; + return *this; + } + + Terminal& Terminal::scrollRange(i32 start, i32 end) { + std::cout << "\033[" << start << ";" << end << "r\033[?6h"; + return *this; + } + + Terminal& Terminal::undoSRange() { + std::cout << "\033[r\033[?6l\033[H"; + return *this; + } + + Terminal& Terminal::fill(const std::string_view color) { + this->style(color); + this->cls(); + return *this; + } + + Terminal& Terminal::clearRow(i32 row) { + // Move to row, column 1 + this->move(row, 1); + // \033[2K clears the entire line + std::cout << "\033[2K"; + return *this; + } + + Terminal& Terminal::clearRows(i32 start, i32 end) { + // Ensure we don't loop infinitely if start > end + if (start > end) std::swap(start, end); + + for (i32 i = start; i <= end; ++i) { + this->clearRow(i); + } + + // Optional: Move cursor back to the start of the cleared block + this->move(start, 1); + return *this; + } + + Terminal& Terminal::cursor(bool show) { + std::cout << (show ? "\033[?25h" : "\033[?25l"); + return *this; + } + + Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) { + // 1. Draw the top border + move(startRow, startCol); + std::cout << "┌"; + for (i32 i = 0; i < width - 2; ++i) std::cout << "─"; + std::cout << "┐"; + + // 2. Draw the sides + for (i32 i = 1; i < height - 1; ++i) { + move(startRow + i, startCol); + std::cout << "│"; + move(startRow + i, startCol + width - 1); + std::cout << "│"; + } + + // 3. Draw the bottom border + move(startRow + height - 1, startCol); + std::cout << "└"; + for (i32 i = 0; i < width - 2; ++i) std::cout << "─"; + std::cout << "┘"; + + // 4. Overlay the title if provided + if (!title.empty()) { + move(startRow, startCol + (width - title.size() - 2) / 2); + std::cout << " " << title << " "; + } + + std::cout.flush(); + return *this; + } + + Terminal& Terminal::flush() { + std::cout << std::flush; + return *this; + } + + Terminal& Terminal::sink() { + std::cin.clear(); +#if defined(SPIDER_OS_WINDOWS) + while (_kbhit()) _getch(); +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + tcflush(STDIN_FILENO, TCIFLUSH); +#endif + return *this; + } + + std::pair Terminal::getSize() { + std::pair pair; +#if defined(SPIDER_OS_WINDOWS) + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { + pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1; + pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + } +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) { + pair.first = w.ws_col; + pair.second = w.ws_row; + } +#endif + return pair; + } + + Terminal& Terminal::wait() { + sink(); + std::cin.get(); + return *this; + } + + u8 Terminal::getKey() { +#if defined(SPIDER_OS_WINDOWS) + i32 ch = _getch(); + if (ch == 0 || ch == 224) { + switch (_getch()) { + case 72: return Terminal::UP; + case 80: return Terminal::DOWN; + case 75: return Terminal::LEFT; + case 77: return Terminal::RIGHT; + default: return Terminal::UNKNOWN; + } + } + if (ch == 13) return Terminal::ENTER; + if (ch == 27) return Terminal::ESC; + if (ch == 8) return Terminal::BACKSPACE; + return Terminal::UNKNOWN; +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + struct termios oldt, newt; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + u8 result = Terminal::UNKNOWN; + int ch = getchar(); + + if (ch == 27) { // Potential Escape Sequence + // Use a small timeout or check if more chars are in buffer + // to distinguish between 'Esc' key and 'Arrow' sequence + // Another Win for the Win API + struct timeval tv = { 0, 10000 }; // 10ms wait + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + + if (select(1, &fds, NULL, NULL, &tv) > 0) { + if (getchar() == '[') { + switch (getchar()) { + case 'A': result = Terminal::UP; break; + case 'B': result = Terminal::DOWN; break; + case 'D': result = Terminal::LEFT; break; + case 'C': result = Terminal::RIGHT; break; + } + } + } else { + result = Terminal::ESC; + } + } else if (ch == 10) result = Terminal::ENTER; + else if (ch == 127) result = Terminal::BACKSPACE; + else result = (u8)ch; + + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return result; +#endif + } + + u8 Terminal::getKeyNb() { +#if defined(SPIDER_OS_WINDOWS) + if (_kbhit()) return getKey(); + return Terminal::UNKNOWN; +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + struct timeval tv = { 0, 0 }; + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + // select() returns > 0 if there is data to read + if (select(1, &fds, NULL, NULL, &tv) > 0) { + return getKey(); + } + return Terminal::UNKNOWN; +#endif + } + +} + +#endif diff --git a/src/spider/runtime/util/Terminal.hpp b/src/spider/runtime/util/Terminal.hpp index 3f183f1..5137007 100644 --- a/src/spider/runtime/util/Terminal.hpp +++ b/src/spider/runtime/util/Terminal.hpp @@ -1,176 +1,176 @@ -#pragma once - -#include - -#include -#include -#include -#include - -namespace spider { - - class Terminal { - public: - - static const char* RESET; - static const char* BOLD; - static const char* ITALIC; - static const char* FAINT; - static const char* STRIKE; - - static const char* FG_BLACK; static const char* FG_B_BLACK; - static const char* FG_RED; static const char* FG_B_RED; - static const char* FG_GREEN; static const char* FG_B_GREEN; - static const char* FG_YELLOW; static const char* FG_B_YELLOW; - static const char* FG_BLUE; static const char* FG_B_BLUE; - static const char* FG_MAGENTA; static const char* FG_B_MAGENTA; - static const char* FG_CYAN; static const char* FG_B_CYAN; - static const char* FG_WHITE; static const char* FG_B_WHITE; - - static const char* BG_BLACK; static const char* BG_B_BLACK; - static const char* BG_RED; static const char* BG_B_RED; - static const char* BG_GREEN; static const char* BG_B_GREEN; - static const char* BG_YELLOW; static const char* BG_B_YELLOW; - static const char* BG_BLUE; static const char* BG_B_BLUE; - static const char* BG_MAGENTA; static const char* BG_B_MAGENTA; - static const char* BG_CYAN; static const char* BG_B_CYAN; - static const char* BG_WHITE; static const char* BG_B_WHITE; - - public: - - // Key Definitions (ASCII OK) // - static constexpr const u8 UP = 0x80; - static constexpr const u8 DOWN = 0x81; - static constexpr const u8 LEFT = 0x82; - static constexpr const u8 RIGHT = 0x83; - static constexpr const u8 ENTER = 0x84; - static constexpr const u8 ESC = 0x85; - static constexpr const u8 BACKSPACE = 0x86; - static constexpr const u8 UNKNOWN = 0xFF; - - public: - - Terminal(); - - ~Terminal(); - - public: - - /** - * Sets a style - */ - Terminal& style(const std::string_view code); - - /** - * Fills the screen with a specific background color. - * @param color The background color constant (e.g., Terminal::BG_BLUE) - */ - Terminal& fill(const std::string_view color); - - /** - * Moves the cursor. - */ - Terminal& move(i32 row, i32 col); - - /** - * Clears the screen - */ - Terminal& cls(); - - Terminal& altbuff(bool enable); - - Terminal& scrollRange(i32 start, i32 end); - - Terminal& undoSRange(); - - /** - * Clears a specific row. - * @param row The 1-based index of the row to clear. - */ - Terminal& clearRow(i32 row); - - /** - * Clears a range of rows (inclusive). - * @param start The first row. - * @param end The last row. - */ - Terminal& clearRows(i32 start, i32 end); - - /** - * Shows / Hides the cursor. - */ - Terminal& cursor(bool show); - - public: - - Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title); - - public: - - /** - * Flushes the output buffer - */ - Terminal& flush(); - - /** - * Clears the input buffer. - * Useful for some specific input cases - */ - Terminal& sink(); - - public: - - Terminal& wait(); - - u8 getKey(); - - /** - * Get key non blocking - */ - u8 getKeyNb(); - - std::pair getSize(); - - public: - - template - Terminal& print(const T& msg) { - std::cout << msg; - return *this; - } - - template - Terminal& println(const T& msg) { - std::cout << msg << "\n"; - return *this; - } - - template - Terminal& print_center(i32 width, const T& msg) { - // to string - std::ostringstream oss; - oss << msg; - std::string s = oss.str(); - - // then print - if (s.length() >= isize(width)) { - std::cout << s; - } else { - i32 total_padding = width - s.length(); - i32 left_padding = total_padding / 2; - std::cout << std::string(left_padding, ' '); - std::cout << s; - std::cout << std::string(total_padding - left_padding, ' '); - } - return *this; - } - - template - Terminal& read(T& var) { - std::cin >> var; - return *this; - } - - }; - +#pragma once + +#include + +#include +#include +#include +#include + +namespace spider { + + class Terminal { + public: + + static const char* RESET; + static const char* BOLD; + static const char* ITALIC; + static const char* FAINT; + static const char* STRIKE; + + static const char* FG_BLACK; static const char* FG_B_BLACK; + static const char* FG_RED; static const char* FG_B_RED; + static const char* FG_GREEN; static const char* FG_B_GREEN; + static const char* FG_YELLOW; static const char* FG_B_YELLOW; + static const char* FG_BLUE; static const char* FG_B_BLUE; + static const char* FG_MAGENTA; static const char* FG_B_MAGENTA; + static const char* FG_CYAN; static const char* FG_B_CYAN; + static const char* FG_WHITE; static const char* FG_B_WHITE; + + static const char* BG_BLACK; static const char* BG_B_BLACK; + static const char* BG_RED; static const char* BG_B_RED; + static const char* BG_GREEN; static const char* BG_B_GREEN; + static const char* BG_YELLOW; static const char* BG_B_YELLOW; + static const char* BG_BLUE; static const char* BG_B_BLUE; + static const char* BG_MAGENTA; static const char* BG_B_MAGENTA; + static const char* BG_CYAN; static const char* BG_B_CYAN; + static const char* BG_WHITE; static const char* BG_B_WHITE; + + public: + + // Key Definitions (ASCII OK) // + static constexpr const u8 UP = 0x80; + static constexpr const u8 DOWN = 0x81; + static constexpr const u8 LEFT = 0x82; + static constexpr const u8 RIGHT = 0x83; + static constexpr const u8 ENTER = 0x84; + static constexpr const u8 ESC = 0x85; + static constexpr const u8 BACKSPACE = 0x86; + static constexpr const u8 UNKNOWN = 0xFF; + + public: + + Terminal(); + + ~Terminal(); + + public: + + /** + * Sets a style + */ + Terminal& style(const std::string_view code); + + /** + * Fills the screen with a specific background color. + * @param color The background color constant (e.g., Terminal::BG_BLUE) + */ + Terminal& fill(const std::string_view color); + + /** + * Moves the cursor. + */ + Terminal& move(i32 row, i32 col); + + /** + * Clears the screen + */ + Terminal& cls(); + + Terminal& altbuff(bool enable); + + Terminal& scrollRange(i32 start, i32 end); + + Terminal& undoSRange(); + + /** + * Clears a specific row. + * @param row The 1-based index of the row to clear. + */ + Terminal& clearRow(i32 row); + + /** + * Clears a range of rows (inclusive). + * @param start The first row. + * @param end The last row. + */ + Terminal& clearRows(i32 start, i32 end); + + /** + * Shows / Hides the cursor. + */ + Terminal& cursor(bool show); + + public: + + Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title); + + public: + + /** + * Flushes the output buffer + */ + Terminal& flush(); + + /** + * Clears the input buffer. + * Useful for some specific input cases + */ + Terminal& sink(); + + public: + + Terminal& wait(); + + u8 getKey(); + + /** + * Get key non blocking + */ + u8 getKeyNb(); + + std::pair getSize(); + + public: + + template + Terminal& print(const T& msg) { + std::cout << msg; + return *this; + } + + template + Terminal& println(const T& msg) { + std::cout << msg << "\n"; + return *this; + } + + template + Terminal& print_center(i32 width, const T& msg) { + // to string + std::ostringstream oss; + oss << msg; + std::string s = oss.str(); + + // then print + if (s.length() >= isize(width)) { + std::cout << s; + } else { + i32 total_padding = width - s.length(); + i32 left_padding = total_padding / 2; + std::cout << std::string(left_padding, ' '); + std::cout << s; + std::cout << std::string(total_padding - left_padding, ' '); + } + return *this; + } + + template + Terminal& read(T& var) { + std::cin >> var; + return *this; + } + + }; + } \ No newline at end of file