add ESP32 build system with xtensa-esp-elf toolchain
This commit is contained in:
12
.gitignore
vendored
12
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
# For now, ignore user builds
|
# For now, ignore user builds
|
||||||
# We will eventually change to a custom
|
# We will eventually change to a custom
|
||||||
# build system.
|
# build system.
|
||||||
# So hold on
|
# So hold on
|
||||||
/bin
|
/bin
|
||||||
/out
|
/out
|
||||||
|
|||||||
36
LICENSE
36
LICENSE
@@ -1,18 +1,18 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 SpiderLang
|
Copyright (c) 2026 SpiderLang
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
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
|
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
|
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
|
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||||
following conditions:
|
following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||||
portions of the Software.
|
portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
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
|
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
|
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
|
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.
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|||||||
26
README.md
26
README.md
@@ -1,13 +1,13 @@
|
|||||||
# spider-runtime
|
# spider-runtime
|
||||||
This is the Spider runtime (aka, the virtual machine) that executes the Spider byte code.
|
This is the Spider runtime (aka, the virtual machine) that executes the Spider byte code.
|
||||||
|
|
||||||
## Code Etiquette
|
## Code Etiquette
|
||||||
- Do not use \r\n
|
- Do not use \r\n
|
||||||
- Do not use any encoding besides UTF-8
|
- Do not use any encoding besides UTF-8
|
||||||
- Always comment global functions, variables, classes, member variables and methods.
|
- Always comment global functions, variables, classes, member variables and methods.
|
||||||
- Do not modify the autogenerated files.
|
- 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 LLM, use private mode and tell it you're working on an old modem.
|
||||||
- If using an AI agent, don't.
|
- 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.
|
- 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.
|
Failure to uphold the code etiquette will result in a slap in the wrist, with a hammer.
|
||||||
|
|||||||
56
build/esp32/Makefile
Normal file
56
build/esp32/Makefile
Normal file
@@ -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
|
||||||
BIN
build/esp32/bin/spider/main_esp32.o
Normal file
BIN
build/esp32/bin/spider/main_esp32.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/Runtime.o
Normal file
BIN
build/esp32/bin/spider/runtime/Runtime.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/cpu/CPU.o
Normal file
BIN
build/esp32/bin/spider/runtime/cpu/CPU.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/instr/Instr_00-1F.o
Normal file
BIN
build/esp32/bin/spider/runtime/instr/Instr_00-1F.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/math/Quat.o
Normal file
BIN
build/esp32/bin/spider/runtime/math/Quat.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/memory/ByteArray.o
Normal file
BIN
build/esp32/bin/spider/runtime/memory/ByteArray.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/memory/RAM.o
Normal file
BIN
build/esp32/bin/spider/runtime/memory/RAM.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/reel/InstrReel.o
Normal file
BIN
build/esp32/bin/spider/runtime/reel/InstrReel.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/reel/InstrReelDyn.o
Normal file
BIN
build/esp32/bin/spider/runtime/reel/InstrReelDyn.o
Normal file
Binary file not shown.
BIN
build/esp32/bin/spider/runtime/reel/InstrReelFixed.o
Normal file
BIN
build/esp32/bin/spider/runtime/reel/InstrReelFixed.o
Normal file
Binary file not shown.
64
build/esp32/gen_makefile.py
Normal file
64
build/esp32/gen_makefile.py
Normal file
@@ -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!")
|
||||||
BIN
build/esp32/out/spider_esp32.elf
Normal file
BIN
build/esp32/out/spider_esp32.elf
Normal file
Binary file not shown.
128
makefile
128
makefile
@@ -1,65 +1,65 @@
|
|||||||
#Compiler and Linker
|
#Compiler and Linker
|
||||||
CC := g++
|
CC := g++
|
||||||
|
|
||||||
#The Target Binary Program
|
#The Target Binary Program
|
||||||
TARGET := out.exe
|
TARGET := out.exe
|
||||||
|
|
||||||
#The Directories, Source, Includes, Objects, Binary and Resources
|
#The Directories, Source, Includes, Objects, Binary and Resources
|
||||||
SRCDIR := src
|
SRCDIR := src
|
||||||
BUILDDIR := bin
|
BUILDDIR := bin
|
||||||
TARGETDIR := out
|
TARGETDIR := out
|
||||||
SRCEXT := cpp
|
SRCEXT := cpp
|
||||||
DEPEXT := d
|
DEPEXT := d
|
||||||
OBJEXT := o
|
OBJEXT := o
|
||||||
|
|
||||||
#Flags, Libraries and Includes
|
#Flags, Libraries and Includes
|
||||||
ROOT := ./
|
ROOT := ./
|
||||||
CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING
|
CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING
|
||||||
LFLAGS := -Wall -std=c++20 -static
|
LFLAGS := -Wall -std=c++20 -static
|
||||||
LIB :=
|
LIB :=
|
||||||
INC := -I./src/
|
INC := -I./src/
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
#DO NOT EDIT BELOW THIS LINE
|
#DO NOT EDIT BELOW THIS LINE
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
|
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
|
||||||
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
|
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
|
||||||
|
|
||||||
#Defauilt Make
|
#Defauilt Make
|
||||||
all: directories $(TARGET)
|
all: directories $(TARGET)
|
||||||
|
|
||||||
#Remake
|
#Remake
|
||||||
remake: cleaner all
|
remake: cleaner all
|
||||||
|
|
||||||
#Make the Directories
|
#Make the Directories
|
||||||
directories:
|
directories:
|
||||||
@mkdir -p $(TARGETDIR)
|
@mkdir -p $(TARGETDIR)
|
||||||
@mkdir -p $(BUILDDIR)
|
@mkdir -p $(BUILDDIR)
|
||||||
|
|
||||||
#Clean only Objecst
|
#Clean only Objecst
|
||||||
clean:
|
clean:
|
||||||
@$(RM) -rf $(BUILDDIR)
|
@$(RM) -rf $(BUILDDIR)
|
||||||
|
|
||||||
#Full Clean, Objects and Binaries
|
#Full Clean, Objects and Binaries
|
||||||
cleaner: clean
|
cleaner: clean
|
||||||
@$(RM) -rf $(TARGETDIR)
|
@$(RM) -rf $(TARGETDIR)
|
||||||
|
|
||||||
#Pull in dependency info for *existing* .o files
|
#Pull in dependency info for *existing* .o files
|
||||||
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
|
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
|
||||||
|
|
||||||
#Link
|
#Link
|
||||||
$(TARGET): $(OBJECTS)
|
$(TARGET): $(OBJECTS)
|
||||||
$(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)
|
$(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)
|
||||||
|
|
||||||
#Compile
|
#Compile
|
||||||
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
|
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
|
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
|
||||||
@$(CC) $(CFLAGS) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
|
@$(CC) $(CFLAGS) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
|
||||||
@cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
|
@cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
|
||||||
@sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
|
@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)
|
@sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
|
||||||
@rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
|
@rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
|
||||||
|
|
||||||
#Non-File Targets
|
#Non-File Targets
|
||||||
.PHONY: all remake clean cleaner resources
|
.PHONY: all remake clean cleaner resources
|
||||||
942
pygen.ipynb
942
pygen.ipynb
@@ -1,471 +1,471 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"id": "21877801",
|
"id": "21877801",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Python Generator\n",
|
"## Python Generator\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This python notebook will serve to generate the necessary code to\n",
|
"This python notebook will serve to generate the necessary code to\n",
|
||||||
"generate some things from Spider.\n",
|
"generate some things from Spider.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Specifically, it will generate the CPU instructions (currently)."
|
"Specifically, it will generate the CPU instructions (currently)."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"id": "b0fcd533",
|
"id": "b0fcd533",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Repo root : ./ -> (True)\n",
|
"Repo root : ./ -> (True)\n",
|
||||||
"CPU.hpp : .//src//spider/runtime/cpu/CPU.hpp -> (True)\n",
|
"CPU.hpp : .//src//spider/runtime/cpu/CPU.hpp -> (True)\n",
|
||||||
"XLSX : .//docs//Spider Instructions.xlsx -> (True)\n",
|
"XLSX : .//docs//Spider Instructions.xlsx -> (True)\n",
|
||||||
"Output dir: .//autogen/ -> (True)\n"
|
"Output dir: .//autogen/ -> (True)\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# setup directories\n",
|
"# setup directories\n",
|
||||||
"import os\n",
|
"import os\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# [CHANGE]\n",
|
"# [CHANGE]\n",
|
||||||
"# Since we're running on a local environment (i hope)\n",
|
"# Since we're running on a local environment (i hope)\n",
|
||||||
"# we can just signal a relative directory.\n",
|
"# we can just signal a relative directory.\n",
|
||||||
"REPO_ROOT = './'\n",
|
"REPO_ROOT = './'\n",
|
||||||
"DOCS_ROOT = f'{REPO_ROOT}/docs/'\n",
|
"DOCS_ROOT = f'{REPO_ROOT}/docs/'\n",
|
||||||
"SRC_ROOT = f'{REPO_ROOT}/src/'\n",
|
"SRC_ROOT = f'{REPO_ROOT}/src/'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Where CPU.hpp lives — this is the file we will inject generated code into.\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",
|
"CPU_HPP_PATH = f'{SRC_ROOT}/spider/runtime/cpu/CPU.hpp'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Where the Excel instruction sheet lives. Allocate the .xlsx file in the project's root folder.\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",
|
"# NOTE: The file I uploaded has a space instead of underscore!\n",
|
||||||
"XLSX_PATH = f'{DOCS_ROOT}/Spider Instructions.xlsx'\n",
|
"XLSX_PATH = f'{DOCS_ROOT}/Spider Instructions.xlsx'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Output folder for any standalone generated files.\n",
|
"# Output folder for any standalone generated files.\n",
|
||||||
"OUT_DIR = f'{REPO_ROOT}/autogen/'\n",
|
"OUT_DIR = f'{REPO_ROOT}/autogen/'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Create the output directory if it does not exist yet.\n",
|
"# Create the output directory if it does not exist yet.\n",
|
||||||
"# exist_ok=True means no error if it already exists.\n",
|
"# exist_ok=True means no error if it already exists.\n",
|
||||||
"os.makedirs(OUT_DIR, exist_ok=True)\n",
|
"os.makedirs(OUT_DIR, exist_ok=True)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"def dir_exists(path:str):\n",
|
"def dir_exists(path:str):\n",
|
||||||
" return os.path.exists(path) and os.path.isdir(path)\n",
|
" return os.path.exists(path) and os.path.isdir(path)\n",
|
||||||
"def file_exists(path:str):\n",
|
"def file_exists(path:str):\n",
|
||||||
" return os.path.exists(path) and os.path.isfile(path)\n",
|
" return os.path.exists(path) and os.path.isfile(path)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f'Repo root : {REPO_ROOT } -> ({ dir_exists(REPO_ROOT )})')\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'CPU.hpp : {CPU_HPP_PATH} -> ({file_exists(CPU_HPP_PATH)})')\n",
|
||||||
"print(f'XLSX : {XLSX_PATH } -> ({file_exists(XLSX_PATH )})')\n",
|
"print(f'XLSX : {XLSX_PATH } -> ({file_exists(XLSX_PATH )})')\n",
|
||||||
"print(f'Output dir: {OUT_DIR } -> ({ dir_exists(OUT_DIR )})')\n"
|
"print(f'Output dir: {OUT_DIR } -> ({ dir_exists(OUT_DIR )})')\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 5,
|
"execution_count": 5,
|
||||||
"id": "b33de8ac",
|
"id": "b33de8ac",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"--- Sample output for NOP ---\n",
|
"--- Sample output for NOP ---\n",
|
||||||
" // [System] 0x000 — NOP: No Operation\n",
|
" // [System] 0x000 — NOP: No Operation\n",
|
||||||
" // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n",
|
" // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n",
|
||||||
" // Operation: Nothing\n",
|
" // Operation: Nothing\n",
|
||||||
" void NOP();\n",
|
" void NOP();\n",
|
||||||
"\n"
|
"\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# Implement here some kind of \"C++\" printer\n",
|
"# Implement here some kind of \"C++\" printer\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Indent used throughout the generated block ──────────────────────────────\n",
|
"# ── Indent used throughout the generated block ──────────────────────────────\n",
|
||||||
"INDENT = ' ' # 8 spaces — matches the indentation inside CPU.hpp\n",
|
"INDENT = ' ' # 8 spaces — matches the indentation inside CPU.hpp\n",
|
||||||
"\n",
|
"\n",
|
||||||
"def format_instruction(byte_code: str, mnemonic: str, name: str,\n",
|
"def format_instruction(byte_code: str, mnemonic: str, name: str,\n",
|
||||||
" group: str, params: int,\n",
|
" group: str, params: int,\n",
|
||||||
" addr_mask_1: str, addr_mask_2: str,\n",
|
" addr_mask_1: str, addr_mask_2: str,\n",
|
||||||
" type_mask: str, operation: str) -> str:\n",
|
" type_mask: str, operation: str) -> str:\n",
|
||||||
" \"\"\"\n",
|
" \"\"\"\n",
|
||||||
" Returns a single C++ instruction declaration as a string.\n",
|
" Returns a single C++ instruction declaration as a string.\n",
|
||||||
"\n",
|
"\n",
|
||||||
" Each instruction becomes a commented constant inside the CPU class.\n",
|
" Each instruction becomes a commented constant inside the CPU class.\n",
|
||||||
" Format:\n",
|
" Format:\n",
|
||||||
" // [GROUP] 0xBYTE — MNEMONIC: Name\n",
|
" // [GROUP] 0xBYTE — MNEMONIC: Name\n",
|
||||||
" // Params: N | AddrMask1: XX AddrMask2: XX | TypeMask: XX\n",
|
" // Params: N | AddrMask1: XX AddrMask2: XX | TypeMask: XX\n",
|
||||||
" // Operation: ...\n",
|
" // Operation: ...\n",
|
||||||
" MNEMONIC\n",
|
" MNEMONIC\n",
|
||||||
" \"\"\"\n",
|
" \"\"\"\n",
|
||||||
" lines = []\n",
|
" lines = []\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # Header comment: group, opcode, mnemonic and human-readable name.\n",
|
" # Header comment: group, opcode, mnemonic and human-readable name.\n",
|
||||||
" lines.append(f'{INDENT}// [{group}] 0x{byte_code} — {mnemonic}: {name}')\n",
|
" lines.append(f'{INDENT}// [{group}] 0x{byte_code} — {mnemonic}: {name}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # Second comment line: parameter count, addressing masks, type size mask.\n",
|
" # Second comment line: parameter count, addressing masks, type size mask.\n",
|
||||||
" lines.append(f'{INDENT}// Params: {params} | '\n",
|
" lines.append(f'{INDENT}// Params: {params} | '\n",
|
||||||
" f'AddrMask1: {addr_mask_1} AddrMask2: {addr_mask_2} | '\n",
|
" f'AddrMask1: {addr_mask_1} AddrMask2: {addr_mask_2} | '\n",
|
||||||
" f'TypeMask: {type_mask}')\n",
|
" f'TypeMask: {type_mask}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # Third comment line: what this instruction actually does.\n",
|
" # Third comment line: what this instruction actually does.\n",
|
||||||
" lines.append(f'{INDENT}// Operation: {operation}')\n",
|
" lines.append(f'{INDENT}// Operation: {operation}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # The declaration itself — just the mnemonic name, matching NOP/SPDR style.\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",
|
" lines.append(f'{INDENT}void {mnemonic}();') # method declaration inside CPU class # enum value: NAME = 0xOPCODE,\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # Empty line between instructions for readability.\n",
|
" # Empty line between instructions for readability.\n",
|
||||||
" lines.append('')\n",
|
" lines.append('')\n",
|
||||||
"\n",
|
"\n",
|
||||||
" return '\\n'.join(lines)\n",
|
" return '\\n'.join(lines)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"def format_block(instructions: list) -> str:\n",
|
"def format_block(instructions: list) -> str:\n",
|
||||||
" \"\"\"\n",
|
" \"\"\"\n",
|
||||||
" Joins all individual instruction strings into one complete block.\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",
|
" This is the text that will be injected between the pygen-target markers.\n",
|
||||||
" \"\"\"\n",
|
" \"\"\"\n",
|
||||||
" # Join every formatted instruction into one big string.\n",
|
" # Join every formatted instruction into one big string.\n",
|
||||||
" return '\\n'.join(instructions)\n",
|
" return '\\n'.join(instructions)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Print what one instruction looks like.\n",
|
"# Print what one instruction looks like.\n",
|
||||||
"sample = format_instruction('000','NOP','No Operation','System',0,'00','00','00','Nothing')\n",
|
"sample = format_instruction('000','NOP','No Operation','System',0,'00','00','00','Nothing')\n",
|
||||||
"print('--- Sample output for NOP ---')\n",
|
"print('--- Sample output for NOP ---')\n",
|
||||||
"print(sample)\n"
|
"print(sample)\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 6,
|
"execution_count": 6,
|
||||||
"id": "58645013",
|
"id": "58645013",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Real instructions : 126\n",
|
"Real instructions : 126\n",
|
||||||
"Reserved slots : 14\n",
|
"Reserved slots : 14\n",
|
||||||
"Duplicate check : PASSED\n",
|
"Duplicate check : PASSED\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Groups found:\n",
|
"Groups found:\n",
|
||||||
"group\n",
|
"group\n",
|
||||||
"Integer 19\n",
|
"Integer 19\n",
|
||||||
"System 15\n",
|
"System 15\n",
|
||||||
"Bit Wise 14\n",
|
"Bit Wise 14\n",
|
||||||
"Boolean 12\n",
|
"Boolean 12\n",
|
||||||
"Branch 12\n",
|
"Branch 12\n",
|
||||||
"Casts 10\n",
|
"Casts 10\n",
|
||||||
"Floating Point 10\n",
|
"Floating Point 10\n",
|
||||||
"Memory 9\n",
|
"Memory 9\n",
|
||||||
"Trigonometric 7\n",
|
"Trigonometric 7\n",
|
||||||
"Exponential 6\n",
|
"Exponential 6\n",
|
||||||
"Matrix 6\n",
|
"Matrix 6\n",
|
||||||
"SIMD 5\n",
|
"SIMD 5\n",
|
||||||
"Easter Eggs 1\n",
|
"Easter Eggs 1\n",
|
||||||
"\n",
|
"\n",
|
||||||
"First 5 instructions:\n",
|
"First 5 instructions:\n",
|
||||||
" byte_code mnemonic group params addr_mask_1 type_mask\n",
|
" byte_code mnemonic group params addr_mask_1 type_mask\n",
|
||||||
"0 000 NOP System 0 00 00\n",
|
"0 000 NOP System 0 00 00\n",
|
||||||
"1 001 SPDR System 0 00 00\n",
|
"1 001 SPDR System 0 00 00\n",
|
||||||
"2 002 MMODE System 1 05 01\n",
|
"2 002 MMODE System 1 05 01\n",
|
||||||
"3 003 INT System 1 1F 0F\n",
|
"3 003 INT System 1 1F 0F\n",
|
||||||
"4 004 LRV System 1 1F 0C\n"
|
"4 004 LRV System 1 1F 0C\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# read the instruction sheet with pandas\n",
|
"# read the instruction sheet with pandas\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"import pandas as pd\n",
|
"import pandas as pd\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# -- Load --------------------------------------------------------------------\n",
|
"# -- Load --------------------------------------------------------------------\n",
|
||||||
"# The data is on the 'Instructions' sheet. Header is on row index 6 (0-based),\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",
|
"# so we skip the first 6 rows of decorative merged cells.\n",
|
||||||
"raw = pd.read_excel(XLSX_PATH, sheet_name='Instructions', header=6)\n",
|
"raw = pd.read_excel(XLSX_PATH, sheet_name='Instructions', header=6)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Rename the two unnamed columns that hold the two addressing mode masks.\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",
|
"# In the sheet they appear after 'Acc. Addr. Mode Mask' with no header label.\n",
|
||||||
"raw.columns = [\n",
|
"raw.columns = [\n",
|
||||||
" 'skip_0', # empty column A\n",
|
" 'skip_0', # empty column A\n",
|
||||||
" 'skip_1', # 'Base Instr.' label column\n",
|
" 'skip_1', # 'Base Instr.' label column\n",
|
||||||
" 'byte_code', # opcode hex string e.g. '000'\n",
|
" 'byte_code', # opcode hex string e.g. '000'\n",
|
||||||
" 'mnemonic', # short name e.g. 'NOP'\n",
|
" 'mnemonic', # short name e.g. 'NOP'\n",
|
||||||
" 'name', # full name e.g. 'No Operation'\n",
|
" 'name', # full name e.g. 'No Operation'\n",
|
||||||
" 'group', # category e.g. 'System'\n",
|
" 'group', # category e.g. 'System'\n",
|
||||||
" 'params', # number of parameters (0, 1, or 2)\n",
|
" 'params', # number of parameters (0, 1, or 2)\n",
|
||||||
" 'imp', # addressing mode: Implied\n",
|
" 'imp', # addressing mode: Implied\n",
|
||||||
" 'imm', # addressing mode: Immediate\n",
|
" 'imm', # addressing mode: Immediate\n",
|
||||||
" 'abs', # addressing mode: Absolute\n",
|
" 'abs', # addressing mode: Absolute\n",
|
||||||
" 'reg', # addressing mode: Register\n",
|
" 'reg', # addressing mode: Register\n",
|
||||||
" 'ind', # addressing mode: Indirect\n",
|
" 'ind', # addressing mode: Indirect\n",
|
||||||
" 'ptr', # addressing mode: Pointer\n",
|
" 'ptr', # addressing mode: Pointer\n",
|
||||||
" 'idx', # addressing mode: Indexed\n",
|
" 'idx', # addressing mode: Indexed\n",
|
||||||
" 'sca', # addressing mode: Scaled\n",
|
" 'sca', # addressing mode: Scaled\n",
|
||||||
" 'dis', # addressing mode: Displaced\n",
|
" 'dis', # addressing mode: Displaced\n",
|
||||||
" 'addr_mask_1', # accepted addressing mode mask for param 1\n",
|
" 'addr_mask_1', # accepted addressing mode mask for param 1\n",
|
||||||
" 'addr_mask_2', # accepted addressing mode mask for param 2\n",
|
" 'addr_mask_2', # accepted addressing mode mask for param 2\n",
|
||||||
" 'B', # type size: Byte (1 byte) supported?\n",
|
" 'B', # type size: Byte (1 byte) supported?\n",
|
||||||
" 'S', # type size: Short (2 bytes) supported?\n",
|
" 'S', # type size: Short (2 bytes) supported?\n",
|
||||||
" 'I', # type size: Int (4 bytes) supported?\n",
|
" 'I', # type size: Int (4 bytes) supported?\n",
|
||||||
" 'L', # type size: Long (8 bytes) supported?\n",
|
" 'L', # type size: Long (8 bytes) supported?\n",
|
||||||
" 'F', # type size: Float supported?\n",
|
" 'F', # type size: Float supported?\n",
|
||||||
" 'D', # type size: Double supported?\n",
|
" 'D', # type size: Double supported?\n",
|
||||||
" 'type_mask', # combined type size mask as hex string\n",
|
" 'type_mask', # combined type size mask as hex string\n",
|
||||||
" 'operation', # human-readable description of what the instruction does\n",
|
" 'operation', # human-readable description of what the instruction does\n",
|
||||||
" 'skip_2', # trailing empty column\n",
|
" 'skip_2', # trailing empty column\n",
|
||||||
"]\n",
|
"]\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Filter ───────────────────────────────────────────────────────────────────\n",
|
"# ── Filter ───────────────────────────────────────────────────────────────────\n",
|
||||||
"# Keep only rows that have a byte_code value (drops empty rows at the bottom).\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",
|
"df = raw[raw['byte_code'].notna()].copy()\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Separate reserved slots from real instructions.\n",
|
"# Separate reserved slots from real instructions.\n",
|
||||||
"# Reserved entries have '(reserved)' in the mnemonic column.\n",
|
"# Reserved entries have '(reserved)' in the mnemonic column.\n",
|
||||||
"is_reserved = df['mnemonic'].astype(str).str.contains('reserved', case=False, na=False)\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",
|
"reserved_df = df[is_reserved].copy() # keep for reference\n",
|
||||||
"instrs_df = df[~is_reserved & df['mnemonic'].notna()].copy() # real instructions only\n",
|
"instrs_df = df[~is_reserved & df['mnemonic'].notna()].copy() # real instructions only\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Skip incomplete entries — rows with no group are placeholder slots (e.g. Int 1-6 Slot)\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",
|
"# that have no defined behaviour yet. Keeping them would generate invalid C++ identifiers.\n",
|
||||||
"instrs_df = instrs_df[instrs_df['group'].notna()].copy()\n",
|
"instrs_df = instrs_df[instrs_df['group'].notna()].copy()\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Clean ────────────────────────────────────────────────────────────────────\n",
|
"# ── Clean ────────────────────────────────────────────────────────────────────\n",
|
||||||
"# Fill NaN masks with '00' (means 'no modes accepted' — safe default).\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_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['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['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['params'] = instrs_df['params'].fillna(0).astype(int)\n",
|
||||||
"instrs_df['name'] = instrs_df['name'].fillna('').astype(str).str.strip()\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['group'] = instrs_df['group'].fillna('Unknown').astype(str).str.strip()\n",
|
||||||
"instrs_df['operation'] = instrs_df['operation'].fillna('').astype(str).str.strip()\n",
|
"instrs_df['operation'] = instrs_df['operation'].fillna('').astype(str).str.strip()\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Sanitize mnemonics ──────────────────────────────────────────────────────\n",
|
"# ── Sanitize mnemonics ──────────────────────────────────────────────────────\n",
|
||||||
"# C++ identifiers cannot contain spaces. Replace spaces with underscores and\n",
|
"# C++ identifiers cannot contain spaces. Replace spaces with underscores and\n",
|
||||||
"# convert to uppercase so 'Int 1 Slot' becomes 'INT_1_SLOT'.\n",
|
"# convert to uppercase so 'Int 1 Slot' becomes 'INT_1_SLOT'.\n",
|
||||||
"instrs_df['mnemonic'] = (\n",
|
"instrs_df['mnemonic'] = (\n",
|
||||||
" instrs_df['mnemonic']\n",
|
" instrs_df['mnemonic']\n",
|
||||||
" .astype(str)\n",
|
" .astype(str)\n",
|
||||||
" .str.strip() # remove leading/trailing whitespace\n",
|
" .str.strip() # remove leading/trailing whitespace\n",
|
||||||
" .str.replace(' ', '_') # replace internal spaces with underscores\n",
|
" .str.replace(' ', '_') # replace internal spaces with underscores\n",
|
||||||
" .str.upper() # uppercase for consistency\n",
|
" .str.upper() # uppercase for consistency\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Validate: duplicate mnemonics ────────────────────────────────────────────\n",
|
"# ── Validate: duplicate mnemonics ────────────────────────────────────────────\n",
|
||||||
"# Duplicates in real instruction names would cause C++ compilation errors.\n",
|
"# Duplicates in real instruction names would cause C++ compilation errors.\n",
|
||||||
"# We abort here rather than generating broken code.\n",
|
"# We abort here rather than generating broken code.\n",
|
||||||
"mnemonic_counts = instrs_df['mnemonic'].value_counts()\n",
|
"mnemonic_counts = instrs_df['mnemonic'].value_counts()\n",
|
||||||
"duplicates = mnemonic_counts[mnemonic_counts > 1]\n",
|
"duplicates = mnemonic_counts[mnemonic_counts > 1]\n",
|
||||||
"if not duplicates.empty:\n",
|
"if not duplicates.empty:\n",
|
||||||
" # Show which mnemonics are duplicated before raising the error.\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",
|
" raise ValueError(f'Duplicate mnemonics found — fix the sheet before generating:\\n{duplicates}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f'Real instructions : {len(instrs_df)}')\n",
|
"print(f'Real instructions : {len(instrs_df)}')\n",
|
||||||
"print(f'Reserved slots : {len(reserved_df)}')\n",
|
"print(f'Reserved slots : {len(reserved_df)}')\n",
|
||||||
"print(f'Duplicate check : PASSED')\n",
|
"print(f'Duplicate check : PASSED')\n",
|
||||||
"print(f'\\nGroups found:')\n",
|
"print(f'\\nGroups found:')\n",
|
||||||
"print(instrs_df['group'].value_counts().to_string())\n",
|
"print(instrs_df['group'].value_counts().to_string())\n",
|
||||||
"print(f'\\nFirst 5 instructions:')\n",
|
"print(f'\\nFirst 5 instructions:')\n",
|
||||||
"print(instrs_df[['byte_code','mnemonic','group','params','addr_mask_1','type_mask']].head().to_string())\n"
|
"print(instrs_df[['byte_code','mnemonic','group','params','addr_mask_1','type_mask']].head().to_string())\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 7,
|
"execution_count": 7,
|
||||||
"id": "452bc76c",
|
"id": "452bc76c",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Masks written to: .//autogen/InstructionMasks.hpp\n",
|
"Masks written to: .//autogen/InstructionMasks.hpp\n",
|
||||||
"Lines generated : 268\n"
|
"Lines generated : 268\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# well, then export the masks (TODO)\n",
|
"# well, then export the masks (TODO)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Build the masks header content ──────────────────────────────────────────\n",
|
"# ── Build the masks header content ──────────────────────────────────────────\n",
|
||||||
"lines = []\n",
|
"lines = []\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Standard C++ header guard — prevents the file from being included more than once.\n",
|
"# Standard C++ header guard — prevents the file from being included more than once.\n",
|
||||||
"lines.append('#pragma once')\n",
|
"lines.append('#pragma once')\n",
|
||||||
"lines.append('// AUTO-GENERATED by pygen.ipynb — DO NOT EDIT MANUALLY')\n",
|
"lines.append('// AUTO-GENERATED by pygen.ipynb — DO NOT EDIT MANUALLY')\n",
|
||||||
"lines.append('#include <spider/runtime/common.hpp>')\n",
|
"lines.append('#include <spider/runtime/common.hpp>')\n",
|
||||||
"lines.append('')\n",
|
"lines.append('')\n",
|
||||||
"lines.append('namespace spider {')\n",
|
"lines.append('namespace spider {')\n",
|
||||||
"lines.append('')\n",
|
"lines.append('')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Addressing mode mask table ───────────────────────────────────────────────\n",
|
"# ── Addressing mode mask table ───────────────────────────────────────────────\n",
|
||||||
"# Each instruction has two masks (one per parameter).\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",
|
"# We write them as a constexpr array so the VM can look them up at runtime\n",
|
||||||
"# using the opcode as the index.\n",
|
"# using the opcode as the index.\n",
|
||||||
"lines.append('// Addressing mode masks — indexed by opcode.')\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('// [opcode][0] = mask for param 1, [opcode][1] = mask for param 2')\n",
|
||||||
"lines.append('constexpr u8 ADDR_MODE_MASKS[][2] = {')\n",
|
"lines.append('constexpr u8 ADDR_MODE_MASKS[][2] = {')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"for _, row in instrs_df.iterrows():\n",
|
"for _, row in instrs_df.iterrows():\n",
|
||||||
" # Convert the hex string mask to an integer for the C++ literal.\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",
|
" m1 = row['addr_mask_1'].replace('.0','').strip() # remove pandas float artefact\n",
|
||||||
" m2 = row['addr_mask_2'].replace('.0','').strip()\n",
|
" m2 = row['addr_mask_2'].replace('.0','').strip()\n",
|
||||||
" m1 = m1 if m1 != 'nan' else '00'\n",
|
" m1 = m1 if m1 != 'nan' else '00'\n",
|
||||||
" m2 = m2 if m2 != 'nan' else '00'\n",
|
" m2 = m2 if m2 != 'nan' else '00'\n",
|
||||||
" # Each row: { 0xMASK1, 0xMASK2 }, // MNEMONIC\n",
|
" # Each row: { 0xMASK1, 0xMASK2 }, // MNEMONIC\n",
|
||||||
" lines.append(f' {{ 0x{m1.upper()}, 0x{m2.upper()} }}, // {row[\"mnemonic\"]}')\n",
|
" lines.append(f' {{ 0x{m1.upper()}, 0x{m2.upper()} }}, // {row[\"mnemonic\"]}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"lines.append('};')\n",
|
"lines.append('};')\n",
|
||||||
"lines.append('')\n",
|
"lines.append('')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Type size mask table ─────────────────────────────────────────────────────\n",
|
"# ── Type size mask table ─────────────────────────────────────────────────────\n",
|
||||||
"# A single byte per instruction encoding which type sizes it accepts.\n",
|
"# A single byte per instruction encoding which type sizes it accepts.\n",
|
||||||
"lines.append('// Type size masks — indexed by opcode.')\n",
|
"lines.append('// Type size masks — indexed by opcode.')\n",
|
||||||
"lines.append('constexpr u8 TYPE_SIZE_MASKS[] = {')\n",
|
"lines.append('constexpr u8 TYPE_SIZE_MASKS[] = {')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"for _, row in instrs_df.iterrows():\n",
|
"for _, row in instrs_df.iterrows():\n",
|
||||||
" tm = str(row['type_mask']).replace('.0','').strip()\n",
|
" tm = str(row['type_mask']).replace('.0','').strip()\n",
|
||||||
" tm = tm if tm != 'nan' else '00'\n",
|
" tm = tm if tm != 'nan' else '00'\n",
|
||||||
" lines.append(f' 0x{tm.upper()}, // {row[\"mnemonic\"]}')\n",
|
" lines.append(f' 0x{tm.upper()}, // {row[\"mnemonic\"]}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"lines.append('};')\n",
|
"lines.append('};')\n",
|
||||||
"lines.append('')\n",
|
"lines.append('')\n",
|
||||||
"lines.append('} // namespace spider')\n",
|
"lines.append('} // namespace spider')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Write to file ────────────────────────────────────────────────────────────\n",
|
"# ── Write to file ────────────────────────────────────────────────────────────\n",
|
||||||
"masks_path = os.path.join(OUT_DIR, 'InstructionMasks.hpp')\n",
|
"masks_path = os.path.join(OUT_DIR, 'InstructionMasks.hpp')\n",
|
||||||
"with open(masks_path, 'w', encoding='utf-8') as f:\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",
|
" # Join with Unix line endings only — repo etiquette says no \\r\\n.\n",
|
||||||
" f.write('\\n'.join(lines))\n",
|
" f.write('\\n'.join(lines))\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f'Masks written to: {masks_path}')\n",
|
"print(f'Masks written to: {masks_path}')\n",
|
||||||
"print(f'Lines generated : {len(lines)}')\n"
|
"print(f'Lines generated : {len(lines)}')\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 8,
|
"execution_count": 8,
|
||||||
"id": "5aaebef0",
|
"id": "5aaebef0",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Instructions formatted: 126\n",
|
"Instructions formatted: 126\n",
|
||||||
"\n",
|
"\n",
|
||||||
"--- Preview (first 2 instructions) ---\n",
|
"--- Preview (first 2 instructions) ---\n",
|
||||||
" // [System] 0x000 — NOP: No Operation\n",
|
" // [System] 0x000 — NOP: No Operation\n",
|
||||||
" // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n",
|
" // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n",
|
||||||
" // Operation: Nothing\n",
|
" // Operation: Nothing\n",
|
||||||
" void NOP();\n",
|
" void NOP();\n",
|
||||||
"\n",
|
"\n",
|
||||||
" // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA\n",
|
" // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA\n",
|
||||||
" // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n",
|
" // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00\n",
|
||||||
" // Operation: (Spider Version) -> RA\n",
|
" // Operation: (Spider Version) -> RA\n",
|
||||||
" void SPDR();\n",
|
" void SPDR();\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n",
|
"CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n",
|
||||||
"Total lines in updated file: 674\n"
|
"Total lines in updated file: 674\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# print the CPU Instructions\n",
|
"# print the CPU Instructions\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Generate all instruction declarations ───────────────────────────────────\n",
|
"# ── Generate all instruction declarations ───────────────────────────────────\n",
|
||||||
"formatted = []\n",
|
"formatted = []\n",
|
||||||
"\n",
|
"\n",
|
||||||
"for _, row in instrs_df.iterrows():\n",
|
"for _, row in instrs_df.iterrows():\n",
|
||||||
" # Clean each field — remove pandas float artefacts like '00.0'\n",
|
" # Clean each field — remove pandas float artefacts like '00.0'\n",
|
||||||
" byte_code = str(row['byte_code']).strip()\n",
|
" byte_code = str(row['byte_code']).strip()\n",
|
||||||
" mnemonic = str(row['mnemonic']).strip()\n",
|
" mnemonic = str(row['mnemonic']).strip()\n",
|
||||||
" name = str(row['name']).strip()\n",
|
" name = str(row['name']).strip()\n",
|
||||||
" group = str(row['group']).strip()\n",
|
" group = str(row['group']).strip()\n",
|
||||||
" params = int(row['params'])\n",
|
" params = int(row['params'])\n",
|
||||||
" addr_mask_1 = str(row['addr_mask_1']).replace('.0', '').strip()\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",
|
" addr_mask_2 = str(row['addr_mask_2']).replace('.0', '').strip()\n",
|
||||||
" type_mask = str(row['type_mask']).replace('.0', '').strip()\n",
|
" type_mask = str(row['type_mask']).replace('.0', '').strip()\n",
|
||||||
" operation = str(row['operation']).strip()\n",
|
" operation = str(row['operation']).strip()\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # Call the C++ printer from Cell 2 to format this instruction.\n",
|
" # Call the C++ printer from Cell 2 to format this instruction.\n",
|
||||||
" formatted.append(format_instruction(\n",
|
" formatted.append(format_instruction(\n",
|
||||||
" byte_code, mnemonic, name, group,\n",
|
" byte_code, mnemonic, name, group,\n",
|
||||||
" params, addr_mask_1, addr_mask_2,\n",
|
" params, addr_mask_1, addr_mask_2,\n",
|
||||||
" type_mask, operation\n",
|
" type_mask, operation\n",
|
||||||
" ))\n",
|
" ))\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Combine all declarations into one block string.\n",
|
"# Combine all declarations into one block string.\n",
|
||||||
"generated_block = format_block(formatted)\n",
|
"generated_block = format_block(formatted)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f'Instructions formatted: {len(formatted)}')\n",
|
"print(f'Instructions formatted: {len(formatted)}')\n",
|
||||||
"print('\\n--- Preview (first 2 instructions) ---')\n",
|
"print('\\n--- Preview (first 2 instructions) ---')\n",
|
||||||
"print('\\n'.join(formatted[:2]))\n",
|
"print('\\n'.join(formatted[:2]))\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# ── Inject into CPU.hpp ──────────────────────────────────────────────────────\n",
|
"# ── Inject into CPU.hpp ──────────────────────────────────────────────────────\n",
|
||||||
"# The markers tell us exactly where to insert the generated block.\n",
|
"# The markers tell us exactly where to insert the generated block.\n",
|
||||||
"MARKER_OPEN = '// <pygen-target name=cpu-instructions> //'\n",
|
"MARKER_OPEN = '// <pygen-target name=cpu-instructions> //'\n",
|
||||||
"MARKER_CLOSE = '// </pygen-target> //'\n",
|
"MARKER_CLOSE = '// </pygen-target> //'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Read the current CPU.hpp content.\n",
|
"# Read the current CPU.hpp content.\n",
|
||||||
"with open(CPU_HPP_PATH, 'r', encoding='utf-8') as f:\n",
|
"with open(CPU_HPP_PATH, 'r', encoding='utf-8') as f:\n",
|
||||||
" original = f.read()\n",
|
" original = f.read()\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Verify both markers exist before modifying anything.\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 either is missing, the file was edited by hand — abort to avoid corruption.\n",
|
||||||
"if MARKER_OPEN not in original:\n",
|
"if MARKER_OPEN not in original:\n",
|
||||||
" raise ValueError(f'Open marker not found in CPU.hpp: {MARKER_OPEN}')\n",
|
" raise ValueError(f'Open marker not found in CPU.hpp: {MARKER_OPEN}')\n",
|
||||||
"if MARKER_CLOSE not in original:\n",
|
"if MARKER_CLOSE not in original:\n",
|
||||||
" raise ValueError(f'Close marker not found in CPU.hpp: {MARKER_CLOSE}')\n",
|
" raise ValueError(f'Close marker not found in CPU.hpp: {MARKER_CLOSE}')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Split the file into 3 parts around the pygen-target markers.\n",
|
"# Split the file into 3 parts around the pygen-target markers.\n",
|
||||||
"# before : everything up to and including the open marker\n",
|
"# before : everything up to and including the open marker\n",
|
||||||
"# after : from the close marker onward (including it)\n",
|
"# after : from the close marker onward (including it)\n",
|
||||||
"before = original[:original.index(MARKER_OPEN) + len(MARKER_OPEN)]\n",
|
"before = original[:original.index(MARKER_OPEN) + len(MARKER_OPEN)]\n",
|
||||||
"after = original[original.index(MARKER_CLOSE):]\n",
|
"after = original[original.index(MARKER_CLOSE):]\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Reassemble: keep before, inject the generated block, then restore after.\n",
|
"# Reassemble: keep before, inject the generated block, then restore after.\n",
|
||||||
"updated = before + '\\n' + generated_block + '\\n' + INDENT + after\n",
|
"updated = before + '\\n' + generated_block + '\\n' + INDENT + after\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Write back using UTF-8 and Unix line endings only (repo etiquette: no \\r\\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",
|
"with open(CPU_HPP_PATH, 'w', encoding='utf-8', newline='\\n') as f:\n",
|
||||||
" f.write(updated)\n",
|
" f.write(updated)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f'\\nCPU.hpp updated successfully at: {CPU_HPP_PATH}')\n",
|
"print(f'\\nCPU.hpp updated successfully at: {CPU_HPP_PATH}')\n",
|
||||||
"print(f'Total lines in updated file: {len(updated.splitlines())}')\n"
|
"print(f'Total lines in updated file: {len(updated.splitlines())}')\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "Python 3",
|
"display_name": "Python 3",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
"name": "python3"
|
"name": "python3"
|
||||||
},
|
},
|
||||||
"language_info": {
|
"language_info": {
|
||||||
"codemirror_mode": {
|
"codemirror_mode": {
|
||||||
"name": "ipython",
|
"name": "ipython",
|
||||||
"version": 3
|
"version": 3
|
||||||
},
|
},
|
||||||
"file_extension": ".py",
|
"file_extension": ".py",
|
||||||
"mimetype": "text/x-python",
|
"mimetype": "text/x-python",
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.13.7"
|
"version": "3.13.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
"nbformat_minor": 5
|
"nbformat_minor": 5
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
{
|
{
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"path": "."
|
"path": "."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"gitlens.remotes": [
|
"gitlens.remotes": [
|
||||||
{
|
{
|
||||||
"domain": "git.sintekanalytics.com",
|
"domain": "git.sintekanalytics.com",
|
||||||
"type": "Gitea",
|
"type": "Gitea",
|
||||||
"name": "Sintek Analytics' Git",
|
"name": "Sintek Analytics' Git",
|
||||||
"protocol": "https",
|
"protocol": "https",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"C_Cpp.default.includePath": [
|
"C_Cpp.default.includePath": [
|
||||||
"./src"
|
"./src"
|
||||||
],
|
],
|
||||||
"terminal.integrated.defaultProfile.windows": "MSYS2 UCRT"
|
"terminal.integrated.defaultProfile.windows": "MSYS2 UCRT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
#include "SpiderRuntime.hpp"
|
#include "SpiderRuntime.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/debug/LiveDebug.hpp>
|
#include <spider/runtime/debug/LiveDebug.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
spider::liveDebugMain();
|
spider::liveDebugMain();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
class Runtime;
|
class Runtime;
|
||||||
class CPU;
|
class CPU;
|
||||||
class RAM;
|
class RAM;
|
||||||
class InstrReel;
|
class InstrReel;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/spider/main_esp32.cpp
Normal file
8
src/spider/main_esp32.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
#include "Runtime.hpp"
|
#include "Runtime.hpp"
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
// Constructors & Destructors //
|
// Constructors & Destructors //
|
||||||
|
|
||||||
Runtime::Runtime() : ram(0) {}
|
Runtime::Runtime() : ram(0) {}
|
||||||
|
|
||||||
Runtime::Runtime(u64 ramSize) : ram(ramSize) {}
|
Runtime::Runtime(u64 ramSize) : ram(ramSize) {}
|
||||||
|
|
||||||
Runtime::~Runtime() {}
|
Runtime::~Runtime() {}
|
||||||
|
|
||||||
// Stepping/Running the Machine //
|
// Stepping/Running the Machine //
|
||||||
|
|
||||||
void Runtime::step() {}
|
void Runtime::step() {}
|
||||||
|
|
||||||
void Runtime::step(u64 n) {}
|
void Runtime::step(u64 n) {}
|
||||||
|
|
||||||
void Runtime::run() {}
|
void Runtime::run() {}
|
||||||
|
|
||||||
void Runtime::run(u64 n) {}
|
void Runtime::run(u64 n) {}
|
||||||
|
|
||||||
// Misc //
|
// Misc //
|
||||||
|
|
||||||
void Runtime::resizeRAM(u64 length) {
|
void Runtime::resizeRAM(u64 length) {
|
||||||
ram.resize(length);
|
ram.resize(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +1,73 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/cpu/CPU.hpp>
|
#include <spider/runtime/cpu/CPU.hpp>
|
||||||
#include <spider/runtime/memory/RAM.hpp>
|
#include <spider/runtime/memory/RAM.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main runtime class.
|
* The main runtime class.
|
||||||
* This is where the Spider VM (Runtime) lives
|
* This is where the Spider VM (Runtime) lives
|
||||||
*/
|
*/
|
||||||
class Runtime {
|
class Runtime {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
RAM ram;
|
RAM ram;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new runtime, with no memory.
|
* Creates a new runtime, with no memory.
|
||||||
*/
|
*/
|
||||||
Runtime();
|
Runtime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new runtime, with a specific
|
* Creates a new runtime, with a specific
|
||||||
* amount of memory.
|
* amount of memory.
|
||||||
*/
|
*/
|
||||||
Runtime(u64 ramSize);
|
Runtime(u64 ramSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runtime Destructor.
|
* Runtime Destructor.
|
||||||
*/
|
*/
|
||||||
~Runtime();
|
~Runtime();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Steps the clock of the VM once.
|
* Steps the clock of the VM once.
|
||||||
*/
|
*/
|
||||||
void step();
|
void step();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Steps n-times the clock of the VM.
|
* Steps n-times the clock of the VM.
|
||||||
*/
|
*/
|
||||||
void step(u64 n);
|
void step(u64 n);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the machine to run continously.
|
* Sets the machine to run continously.
|
||||||
* If interrupts occur, they will be handled
|
* If interrupts occur, they will be handled
|
||||||
* automatically.
|
* automatically.
|
||||||
*/
|
*/
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs this machine for a set amount of
|
* Runs this machine for a set amount of
|
||||||
* milliseconds.
|
* milliseconds.
|
||||||
*/
|
*/
|
||||||
void run(u64 ms);
|
void run(u64 ms);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the ram, which will preserve
|
* Resizes the ram, which will preserve
|
||||||
* data inside the next length.
|
* data inside the next length.
|
||||||
*/
|
*/
|
||||||
void resizeRAM(u64 length);
|
void resizeRAM(u64 length);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
// Absolute Types
|
// Absolute Types
|
||||||
using u8 = std::uint8_t;
|
using u8 = std::uint8_t;
|
||||||
using u16 = std::uint16_t;
|
using u16 = std::uint16_t;
|
||||||
using u32 = std::uint32_t;
|
using u32 = std::uint32_t;
|
||||||
using u64 = std::uint64_t;
|
using u64 = std::uint64_t;
|
||||||
|
|
||||||
using i8 = std::int8_t;
|
using i8 = std::int8_t;
|
||||||
using i16 = std::int16_t;
|
using i16 = std::int16_t;
|
||||||
using i32 = std::int32_t;
|
using i32 = std::int32_t;
|
||||||
using i64 = std::int64_t;
|
using i64 = std::int64_t;
|
||||||
|
|
||||||
using f32 = float; // TODO: SPIDER_EMULATE_FLOAT will control this
|
using f32 = float; // TODO: SPIDER_EMULATE_FLOAT will control this
|
||||||
using f64 = double;
|
using f64 = double;
|
||||||
|
|
||||||
// TODO: Check if we're on C++23, there is already stdfloat
|
// 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(f32) == 4, "The f32 type must be exactly 4 bytes.");
|
||||||
static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes.");
|
static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes.");
|
||||||
|
|
||||||
// Utility types
|
// Utility types
|
||||||
using isize = std::size_t;
|
using isize = std::size_t;
|
||||||
|
|
||||||
// Utility imports
|
// Utility imports
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::deque;
|
using std::deque;
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::optional;
|
using std::optional;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,111 +1,111 @@
|
|||||||
#include "CPU.hpp"
|
#include "CPU.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/native/machine.hpp>
|
#include <spider/runtime/native/machine.hpp>
|
||||||
|
|
||||||
#include <spider/runtime/memory/RAM.hpp>
|
#include <spider/runtime/memory/RAM.hpp>
|
||||||
|
|
||||||
#include <spider/runtime/reel/InstrReel.hpp>
|
#include <spider/runtime/reel/InstrReel.hpp>
|
||||||
|
|
||||||
#if __cplusplus >= 202002L
|
#if __cplusplus >= 202002L
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
CPU::CPU()
|
CPU::CPU()
|
||||||
: RA{}, RB{}, RC{}, RD{},
|
: RA{}, RB{}, RC{}, RD{},
|
||||||
RX{}, RY{}, R0{}, R1{},
|
RX{}, RY{}, R0{}, R1{},
|
||||||
R2{}, R3{}, R4{}, R5{},
|
R2{}, R3{}, R4{}, R5{},
|
||||||
R6{}, R7{}, R8{}, R9{},
|
R6{}, R7{}, R8{}, R9{},
|
||||||
RF{}, RI{}, RS{}, RZ{},
|
RF{}, RI{}, RS{}, RZ{},
|
||||||
RE{}, RN{}, RV{}, RM{},
|
RE{}, RN{}, RV{}, RM{},
|
||||||
ALU0{}, ALU1{},
|
ALU0{}, ALU1{},
|
||||||
_ram(nullptr), _reel(nullptr) {
|
_ram(nullptr), _reel(nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CPU::~CPU() {}
|
CPU::~CPU() {}
|
||||||
|
|
||||||
// Setup & Configuration //
|
// Setup & Configuration //
|
||||||
|
|
||||||
void CPU::hookRAM(RAM* ram) {
|
void CPU::hookRAM(RAM* ram) {
|
||||||
this->_ram = ram;
|
this->_ram = ram;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::hookInstrReel(InstrReel* reel) {
|
void CPU::hookInstrReel(InstrReel* reel) {
|
||||||
this->_reel = reel;
|
this->_reel = reel;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u64 CPU::getFlag(u64 mask) {
|
constexpr u64 CPU::getFlag(u64 mask) {
|
||||||
if (!mask) return 0;
|
if (!mask) return 0;
|
||||||
#if __cplusplus >= 202002L
|
#if __cplusplus >= 202002L
|
||||||
return (RF & mask) >> std::countr_zero(mask);
|
return (RF & mask) >> std::countr_zero(mask);
|
||||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
return (RF & mask) >> __builtin_ctzll(mask);
|
return (RF & mask) >> __builtin_ctzll(mask);
|
||||||
#elif defined(SPIDER_COMPILER_MSVC)
|
#elif defined(SPIDER_COMPILER_MSVC)
|
||||||
return (RF & mask) >> _BitScanForward64(mask);
|
return (RF & mask) >> _BitScanForward64(mask);
|
||||||
#else
|
#else
|
||||||
// If you have reached this part,
|
// If you have reached this part,
|
||||||
// please come up with a better alternative.
|
// please come up with a better alternative.
|
||||||
u64 bits = RF & mask;
|
u64 bits = RF & mask;
|
||||||
while (mask && (mask >>= 1)) bits >>= 1;
|
while (mask && (mask >>= 1)) bits >>= 1;
|
||||||
return bits;
|
return bits;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addressing Modes //
|
// Addressing Modes //
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implied Addressing Mode
|
* Implied Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::imp() {
|
void CPU::imp() {
|
||||||
// Nothing //
|
// Nothing //
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immediate Addressing Mode
|
* Immediate Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::imm() {
|
void CPU::imm() {
|
||||||
u8 size = 2 << _size;
|
u8 size = 2 << _size;
|
||||||
_next = &ALU0;
|
_next = &ALU0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Absolute Addressing Mode
|
* Absolute Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::abs() {
|
void CPU::abs() {
|
||||||
u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE);
|
u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register Addressing Mode
|
* Register Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::reg() {
|
void CPU::reg() {
|
||||||
sizeof(CPU);
|
sizeof(CPU);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indrect Addressing Mode
|
* Indrect Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::ind() {}
|
void CPU::ind() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer Addressing Mode
|
* Pointer Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::ptr() {}
|
void CPU::ptr() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indexed Addressing Mode
|
* Indexed Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::idx() {}
|
void CPU::idx() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scaled Addressing Mode
|
* Scaled Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::sca() {}
|
void CPU::sca() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displaced Addressing Mode
|
* Displaced Addressing Mode
|
||||||
*/
|
*/
|
||||||
void CPU::dis() {}
|
void CPU::dis() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,81 +1,81 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
#include <spider/runtime/native/machine.hpp>
|
#include <spider/runtime/native/machine.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A register is a tiny piece of memory.
|
* A register is a tiny piece of memory.
|
||||||
* I hate adding a _t suffix but for some idiotic
|
* I hate adding a _t suffix but for some idiotic
|
||||||
* reason "register" is a keyword in C++.
|
* reason "register" is a keyword in C++.
|
||||||
*
|
*
|
||||||
* Note that we have to check the endianness of the system
|
* Note that we have to check the endianness of the system
|
||||||
* at compile time to order the structure so that smaller
|
* at compile time to order the structure so that smaller
|
||||||
* types are actually the bottom part of the memory.
|
* types are actually the bottom part of the memory.
|
||||||
*
|
*
|
||||||
* Also, this has to be done with a compiler that allows
|
* Also, this has to be done with a compiler that allows
|
||||||
* type-punning which is the "standard" right now.
|
* type-punning which is the "standard" right now.
|
||||||
*/
|
*/
|
||||||
union register_t {
|
union register_t {
|
||||||
u64 _u64;
|
u64 _u64;
|
||||||
i64 _i64;
|
i64 _i64;
|
||||||
f64 _f64;
|
f64 _f64;
|
||||||
u8 _bytes[8];
|
u8 _bytes[8];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
u8 _u8; // This looks like a cruel joke
|
u8 _u8; // This looks like a cruel joke
|
||||||
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
|
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
|
||||||
#else
|
#else
|
||||||
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
|
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
|
||||||
u8 _u8;
|
u8 _u8;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
u16 _u16;
|
u16 _u16;
|
||||||
u16 : 16; u16 : 16; u16 : 16;
|
u16 : 16; u16 : 16; u16 : 16;
|
||||||
#else
|
#else
|
||||||
u16 : 16; u16 : 16; u16 : 16;
|
u16 : 16; u16 : 16; u16 : 16;
|
||||||
u16 _u16;
|
u16 _u16;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
u32 _u32; u32 : 32;
|
u32 _u32; u32 : 32;
|
||||||
#else
|
#else
|
||||||
u32 : 32; u32 _u32;
|
u32 : 32; u32 _u32;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
f32 _f32; u32 : 32;
|
f32 _f32; u32 : 32;
|
||||||
#else
|
#else
|
||||||
u32 : 32; f32 _f32;
|
u32 : 32; f32 _f32;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
u8& operator[](size_t i) { // 0 is always LSB
|
u8& operator[](size_t i) { // 0 is always LSB
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
return _bytes[i];
|
return _bytes[i];
|
||||||
#else
|
#else
|
||||||
return _bytes[7 - i];
|
return _bytes[7 - i];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ngl I could get executed for not having a const version
|
// ngl I could get executed for not having a const version
|
||||||
const u8& operator[](size_t i) const { // 0 is always LSB
|
const u8& operator[](size_t i) const { // 0 is always LSB
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
return _bytes[i];
|
return _bytes[i];
|
||||||
#else
|
#else
|
||||||
return _bytes[7 - i];
|
return _bytes[7 - i];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(register_t) == 8, "The register type must be exactly 8 bytes.");
|
static_assert(sizeof(register_t) == 8, "The register type must be exactly 8 bytes.");
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,386 +1,386 @@
|
|||||||
#include "LiveDebug.hpp"
|
#include "LiveDebug.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/Runtime.hpp>
|
#include <spider/runtime/Runtime.hpp>
|
||||||
#include <spider/runtime/util/Terminal.hpp>
|
#include <spider/runtime/util/Terminal.hpp>
|
||||||
#include <spider/runtime/native/distro.hpp>
|
#include <spider/runtime/native/distro.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
void drawHead(Terminal& t) {
|
void drawHead(Terminal& t) {
|
||||||
t.move(1, 1)
|
t.move(1, 1)
|
||||||
.style(Terminal::FG_YELLOW)
|
.style(Terminal::FG_YELLOW)
|
||||||
.print(" Spider Runtime Live Debug ")
|
.print(" Spider Runtime Live Debug ")
|
||||||
.style(Terminal::RESET).print(" | ")
|
.style(Terminal::RESET).print(" | ")
|
||||||
.style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ")
|
.style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ")
|
||||||
.style(Terminal::RESET).print(" | ")
|
.style(Terminal::RESET).print(" | ")
|
||||||
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
|
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
|
||||||
.style(Terminal::FG_BLACK)
|
.style(Terminal::FG_BLACK)
|
||||||
.style(Terminal::BG_YELLOW)
|
.style(Terminal::BG_YELLOW)
|
||||||
.move(3, 1).print(" // __ \\\\").print(" ") // 27
|
.move(3, 1).print(" // __ \\\\").print(" ") // 27
|
||||||
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
|
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
|
||||||
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
|
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
|
||||||
.move(6, 1).print(" \\\\ // ").print(" ")
|
.move(6, 1).print(" \\\\ // ").print(" ")
|
||||||
.style(Terminal::RESET)
|
.style(Terminal::RESET)
|
||||||
.style(Terminal::FG_B_BLACK) // 4x8 for the menu
|
.style(Terminal::FG_B_BLACK) // 4x8 for the menu
|
||||||
.move(3, 28).print("[ STEP ]")
|
.move(3, 28).print("[ STEP ]")
|
||||||
.move(4, 28).print("[ STOP ]")
|
.move(4, 28).print("[ STOP ]")
|
||||||
.move(5, 28).print("[ RUN ]")
|
.move(5, 28).print("[ RUN ]")
|
||||||
.move(6, 28).print("[ MENU ]")
|
.move(6, 28).print("[ MENU ]")
|
||||||
.style(Terminal::RESET)
|
.style(Terminal::RESET)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCPUTempl(Terminal& t, CPU& cpu) {
|
void drawCPUTempl(Terminal& t, CPU& cpu) {
|
||||||
i32 r = 8, c = 1;
|
i32 r = 8, c = 1;
|
||||||
i32 w = 35, h = 31;
|
i32 w = 35, h = 31;
|
||||||
t.drawBox(r, c, w, h, "CPU");
|
t.drawBox(r, c, w, h, "CPU");
|
||||||
|
|
||||||
const std::string regs[] = {
|
const std::string regs[] = {
|
||||||
"RA", "RB", "RC", "RD",
|
"RA", "RB", "RC", "RD",
|
||||||
"RX", "RY", "R0", "R1",
|
"RX", "RY", "R0", "R1",
|
||||||
"R2", "R3", "R4", "R5",
|
"R2", "R3", "R4", "R5",
|
||||||
"R6", "R7", "R8", "R9",
|
"R6", "R7", "R8", "R9",
|
||||||
"RF", "RI", "RS", "RZ",
|
"RF", "RI", "RS", "RZ",
|
||||||
"RE", "RN", "RV", "RM",
|
"RE", "RN", "RV", "RM",
|
||||||
"ALU0", "ALU1"
|
"ALU0", "ALU1"
|
||||||
};
|
};
|
||||||
const std::string alt[] = {
|
const std::string alt[] = {
|
||||||
Terminal::FG_WHITE,
|
Terminal::FG_WHITE,
|
||||||
Terminal::FG_B_BLACK,
|
Terminal::FG_B_BLACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
r++;
|
r++;
|
||||||
c++;
|
c++;
|
||||||
|
|
||||||
t.move(r++, c);
|
t.move(r++, c);
|
||||||
t.style(Terminal::FG_B_YELLOW);
|
t.style(Terminal::FG_B_YELLOW);
|
||||||
t.print_center(w - 2, "GP Registers");
|
t.print_center(w - 2, "GP Registers");
|
||||||
t.style(Terminal::RESET);
|
t.style(Terminal::RESET);
|
||||||
for (i32 i = 0; i < 8; i++) {
|
for (i32 i = 0; i < 8; i++) {
|
||||||
t.style(alt[i & 1]);
|
t.style(alt[i & 1]);
|
||||||
t.move(r + i * 2, c);
|
t.move(r + i * 2, c);
|
||||||
t.print(regs[i * 2]);
|
t.print(regs[i * 2]);
|
||||||
t.move(r + i * 2, c + 17);
|
t.move(r + i * 2, c + 17);
|
||||||
t.print(regs[i * 2 + 1]);
|
t.print(regs[i * 2 + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.move(r += 16, c);
|
t.move(r += 16, c);
|
||||||
t.style(Terminal::FG_B_CYAN);
|
t.style(Terminal::FG_B_CYAN);
|
||||||
t.print_center(w - 2, "System Registers");
|
t.print_center(w - 2, "System Registers");
|
||||||
t.style(Terminal::RESET);
|
t.style(Terminal::RESET);
|
||||||
r++;
|
r++;
|
||||||
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
||||||
t.style(alt[j & 1]);
|
t.style(alt[j & 1]);
|
||||||
t.move(r + j * 2, c);
|
t.move(r + j * 2, c);
|
||||||
t.print(regs[i * 2]);
|
t.print(regs[i * 2]);
|
||||||
t.move(r + j * 2, c + 17);
|
t.move(r + j * 2, c + 17);
|
||||||
t.print(regs[i * 2 + 1]);
|
t.print(regs[i * 2 + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.move(r += 8, c);
|
t.move(r += 8, c);
|
||||||
t.style(Terminal::FG_GREEN);
|
t.style(Terminal::FG_GREEN);
|
||||||
t.print_center(w - 2, "Extra Registers");
|
t.print_center(w - 2, "Extra Registers");
|
||||||
t.style(Terminal::RESET);
|
t.style(Terminal::RESET);
|
||||||
r++;
|
r++;
|
||||||
for (i32 j = 0, i = 12; i < 13; j++, i++) {
|
for (i32 j = 0, i = 12; i < 13; j++, i++) {
|
||||||
t.style(alt[j & 1]);
|
t.style(alt[j & 1]);
|
||||||
t.move(r + j * 2, c);
|
t.move(r + j * 2, c);
|
||||||
t.print(regs[i * 2]);
|
t.print(regs[i * 2]);
|
||||||
t.move(r + j * 2, c + 17);
|
t.move(r + j * 2, c + 17);
|
||||||
t.print(regs[i * 2 + 1]);
|
t.print(regs[i * 2 + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.flush();
|
t.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void printU64Hex(u64 n) {
|
void printU64Hex(u64 n) {
|
||||||
std::ios state(nullptr);
|
std::ios state(nullptr);
|
||||||
state.copyfmt(std::cout);
|
state.copyfmt(std::cout);
|
||||||
std::cout
|
std::cout
|
||||||
<< std::hex
|
<< std::hex
|
||||||
<< std::uppercase
|
<< std::uppercase
|
||||||
<< std::setfill('0')
|
<< std::setfill('0')
|
||||||
<< std::setw(16)
|
<< std::setw(16)
|
||||||
<< n;
|
<< n;
|
||||||
std::cout.copyfmt(state);
|
std::cout.copyfmt(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCPU(Terminal& t, CPU& cpu) {
|
void drawCPU(Terminal& t, CPU& cpu) {
|
||||||
i32 r = 8, c = 1;
|
i32 r = 8, c = 1;
|
||||||
|
|
||||||
const register_t* regs[] = {
|
const register_t* regs[] = {
|
||||||
&cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD,
|
&cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD,
|
||||||
&cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1,
|
&cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1,
|
||||||
&cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5,
|
&cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5,
|
||||||
&cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9,
|
&cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9,
|
||||||
//&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
//&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
||||||
//&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
//&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
||||||
&cpu.ALU0, &cpu.ALU1
|
&cpu.ALU0, &cpu.ALU1
|
||||||
};
|
};
|
||||||
const u64* sys_regs[] = {
|
const u64* sys_regs[] = {
|
||||||
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
||||||
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
||||||
};
|
};
|
||||||
const std::string alt[] = {
|
const std::string alt[] = {
|
||||||
Terminal::FG_WHITE,
|
Terminal::FG_WHITE,
|
||||||
Terminal::FG_B_BLACK,
|
Terminal::FG_B_BLACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
r++;
|
r++;
|
||||||
c++;
|
c++;
|
||||||
t.move(r++, c);
|
t.move(r++, c);
|
||||||
t.style(Terminal::RESET);
|
t.style(Terminal::RESET);
|
||||||
r++;
|
r++;
|
||||||
for (i32 i = 0; i < 8; i++) {
|
for (i32 i = 0; i < 8; i++) {
|
||||||
t.style(alt[i & 1]);
|
t.style(alt[i & 1]);
|
||||||
t.move(r + i * 2, c);
|
t.move(r + i * 2, c);
|
||||||
printU64Hex(regs[i * 2]->_u64);
|
printU64Hex(regs[i * 2]->_u64);
|
||||||
t.move(r + i * 2, c + 17);
|
t.move(r + i * 2, c + 17);
|
||||||
printU64Hex(regs[i * 2 + 1]->_u64);
|
printU64Hex(regs[i * 2 + 1]->_u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.move(r += 16, c);
|
t.move(r += 16, c);
|
||||||
r++;
|
r++;
|
||||||
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
||||||
t.style(alt[j & 1]);
|
t.style(alt[j & 1]);
|
||||||
t.move(r + j * 2, c);
|
t.move(r + j * 2, c);
|
||||||
printU64Hex(*sys_regs[i * 2]);
|
printU64Hex(*sys_regs[i * 2]);
|
||||||
t.move(r + j * 2, c + 17);
|
t.move(r + j * 2, c + 17);
|
||||||
printU64Hex(*sys_regs[i * 2 + 1]);
|
printU64Hex(*sys_regs[i * 2 + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.move(r += 8, c);
|
t.move(r += 8, c);
|
||||||
r++;
|
r++;
|
||||||
for (i32 j = 0; j < 1; j++) {
|
for (i32 j = 0; j < 1; j++) {
|
||||||
t.style(alt[j & 1]);
|
t.style(alt[j & 1]);
|
||||||
t.move(r + j * 2, c);
|
t.move(r + j * 2, c);
|
||||||
printU64Hex(regs[16 + j * 2]->_u64);
|
printU64Hex(regs[16 + j * 2]->_u64);
|
||||||
t.move(r + j * 2, c + 17);
|
t.move(r + j * 2, c + 17);
|
||||||
printU64Hex(regs[16 + j * 2 + 1]->_u64);
|
printU64Hex(regs[16 + j * 2 + 1]->_u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
t.flush();
|
t.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 addressWidth(isize ramSize) {
|
i32 addressWidth(isize ramSize) {
|
||||||
if (ramSize == 0) return 1;
|
if (ramSize == 0) return 1;
|
||||||
isize maxAddr = ramSize - 1;
|
isize maxAddr = ramSize - 1;
|
||||||
i32 digits = 0;
|
i32 digits = 0;
|
||||||
// Shift by increments of 4 (one hex nibble)
|
// Shift by increments of 4 (one hex nibble)
|
||||||
// We use a do-while to ensure at least 1 digit is returned for small RAMs
|
// We use a do-while to ensure at least 1 digit is returned for small RAMs
|
||||||
do {
|
do {
|
||||||
digits++;
|
digits++;
|
||||||
maxAddr >>= 4;
|
maxAddr >>= 4;
|
||||||
} while (maxAddr > 0);
|
} while (maxAddr > 0);
|
||||||
|
|
||||||
return digits;
|
return digits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a vertical scrollbar
|
* Draws a vertical scrollbar
|
||||||
* @param x The column where the bar should be placed (usually box_x + width - 1)
|
* @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 y The starting row of the track (usually box_y + 1)
|
||||||
* @param trackHeight The internal height of the box (box_height - 2)
|
* @param trackHeight The internal height of the box (box_height - 2)
|
||||||
* @param progress The current progress
|
* @param progress The current progress
|
||||||
* @param total The total
|
* @param total The total
|
||||||
*/
|
*/
|
||||||
void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) {
|
void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) {
|
||||||
if (total == 0 || trackHeight <= 0) return;
|
if (total == 0 || trackHeight <= 0) return;
|
||||||
|
|
||||||
// 1. Draw the background track (Light Shade: ░)
|
// 1. Draw the background track (Light Shade: ░)
|
||||||
term.style(Terminal::FG_B_BLACK); // Dim the track
|
term.style(Terminal::FG_B_BLACK); // Dim the track
|
||||||
for (int i = 0; i < trackHeight; ++i) {
|
for (int i = 0; i < trackHeight; ++i) {
|
||||||
term.move(y + i, x).print("░");
|
term.move(y + i, x).print("░");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Calculate Thumb Position
|
// 2. Calculate Thumb Position
|
||||||
// Cap progress to total to avoid overflow
|
// Cap progress to total to avoid overflow
|
||||||
if (progress > total) progress = total;
|
if (progress > total) progress = total;
|
||||||
|
|
||||||
// Calculate ratio (0.0 to 1.0)
|
// Calculate ratio (0.0 to 1.0)
|
||||||
f64 ratio = f64(progress) / f64(total);
|
f64 ratio = f64(progress) / f64(total);
|
||||||
|
|
||||||
// Map to track coordinates
|
// Map to track coordinates
|
||||||
i32 thumbOffset = i32(ratio * (trackHeight - 1));
|
i32 thumbOffset = i32(ratio * (trackHeight - 1));
|
||||||
|
|
||||||
// 3. Draw the Thumb (Full Block: █)
|
// 3. Draw the Thumb (Full Block: █)
|
||||||
term.move(y + thumbOffset, x);
|
term.move(y + thumbOffset, x);
|
||||||
term.style(Terminal::FG_WHITE).print("█");
|
term.style(Terminal::FG_WHITE).print("█");
|
||||||
term.style(Terminal::RESET);
|
term.style(Terminal::RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a hex dump of memory within a styled terminal box.
|
* Draws a hex dump of memory within a styled terminal box.
|
||||||
* @param term Reference to your Terminal instance
|
* @param term Reference to your Terminal instance
|
||||||
* @param ram The RAM
|
* @param ram The RAM
|
||||||
* @param scrollPos The starting address to display
|
* @param scrollPos The starting address to display
|
||||||
* @param x Starting column
|
* @param x Starting column
|
||||||
* @param y Starting row
|
* @param y Starting row
|
||||||
* @param width Width of the box
|
* @param width Width of the box
|
||||||
* @param height Height of the box
|
* @param height Height of the box
|
||||||
*/
|
*/
|
||||||
void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) {
|
void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) {
|
||||||
// 1. Draw the container box
|
// 1. Draw the container box
|
||||||
i32 y = 3;
|
i32 y = 3;
|
||||||
i32 height = 36;
|
i32 height = 36;
|
||||||
|
|
||||||
// 2. Configuration for the hex layout
|
// 2. Configuration for the hex layout
|
||||||
int addrWidth = addressWidth(ram.size());
|
int addrWidth = addressWidth(ram.size());
|
||||||
int bytesPerRow = 8;
|
int bytesPerRow = 8;
|
||||||
int displayRows = height - 2; // Subtract top/bottom borders
|
int displayRows = height - 2; // Subtract top/bottom borders
|
||||||
i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth;
|
i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth;
|
||||||
i32 x = 37;
|
i32 x = 37;
|
||||||
|
|
||||||
// create box
|
// create box
|
||||||
term.drawBox(y, x, width, height, "RAM");
|
term.drawBox(y, x, width, height, "RAM");
|
||||||
drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size());
|
drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size());
|
||||||
|
|
||||||
// Ensure scrollPos is within bounds and aligned
|
// Ensure scrollPos is within bounds and aligned
|
||||||
if (scrollPos < 0) scrollPos = 0;
|
if (scrollPos < 0) scrollPos = 0;
|
||||||
if (scrollPos > ram.size()) scrollPos = ram.size();
|
if (scrollPos > ram.size()) scrollPos = ram.size();
|
||||||
|
|
||||||
for (int i = 0; i < displayRows; ++i) {
|
for (int i = 0; i < displayRows; ++i) {
|
||||||
isize currentRowAddr = scrollPos + (i * bytesPerRow);
|
isize currentRowAddr = scrollPos + (i * bytesPerRow);
|
||||||
|
|
||||||
// address lock
|
// address lock
|
||||||
if (currentRowAddr >= ram.size()) {
|
if (currentRowAddr >= ram.size()) {
|
||||||
term.move(y + 1 + i, x + 1);
|
term.move(y + 1 + i, x + 1);
|
||||||
term.print(std::string(width - 3, ' '));
|
term.print(std::string(width - 3, ' '));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ssaddr;
|
std::stringstream ssaddr;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
// setup ss
|
// setup ss
|
||||||
ssaddr << std::setfill('0') << std::uppercase << std::hex;
|
ssaddr << std::setfill('0') << std::uppercase << std::hex;
|
||||||
ss << std::setfill('0') << std::uppercase << std::hex;
|
ss << std::setfill('0') << std::uppercase << std::hex;
|
||||||
|
|
||||||
// address
|
// address
|
||||||
ssaddr << std::setw(addrWidth) << currentRowAddr << " ";
|
ssaddr << std::setw(addrWidth) << currentRowAddr << " ";
|
||||||
|
|
||||||
// Hex Bytes
|
// Hex Bytes
|
||||||
std::string asciiPart = "";
|
std::string asciiPart = "";
|
||||||
for (int j = 0; j < bytesPerRow; ++j) {
|
for (int j = 0; j < bytesPerRow; ++j) {
|
||||||
isize targetAddr = currentRowAddr + j;
|
isize targetAddr = currentRowAddr + j;
|
||||||
if (targetAddr >= ram.size()) {
|
if (targetAddr >= ram.size()) {
|
||||||
ss << ""; // Padding for end of memory
|
ss << ""; // Padding for end of memory
|
||||||
asciiPart += "";
|
asciiPart += "";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 byte = ram[targetAddr];
|
u8 byte = ram[targetAddr];
|
||||||
ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " ";
|
ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " ";
|
||||||
asciiPart += (std::isprint(byte) ? (char)byte : '.');
|
asciiPart += (std::isprint(byte) ? (char)byte : '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Combine and Print ---
|
// --- Combine and Print ---
|
||||||
term.move(y + 1 + i, x + 2); // Move inside the box
|
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_B_CYAN).print(ssaddr.str()); // Hex part in Cyan
|
||||||
term.style(Terminal::FG_WHITE).print(ss.str());
|
term.style(Terminal::FG_WHITE).print(ss.str());
|
||||||
term.style(Terminal::FG_B_YELLOW).print(" | ");
|
term.style(Terminal::FG_B_YELLOW).print(" | ");
|
||||||
term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White
|
term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White
|
||||||
}
|
}
|
||||||
|
|
||||||
term.style(Terminal::RESET);
|
term.style(Terminal::RESET);
|
||||||
term.flush();
|
term.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getTimestamp() {
|
std::string getTimestamp() {
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(nullptr);
|
||||||
std::tm lt;
|
std::tm lt;
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
localtime_s(<, &t);
|
localtime_s(<, &t);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
localtime_r(&t, <);
|
localtime_r(&t, <);
|
||||||
#endif
|
#endif
|
||||||
return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}",
|
return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}",
|
||||||
lt.tm_hour, lt.tm_min, lt.tm_sec,
|
lt.tm_hour, lt.tm_min, lt.tm_sec,
|
||||||
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
|
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawTime(Terminal& t) {
|
void drawTime(Terminal& t) {
|
||||||
//auto now = std::chrono::system_clock::now();
|
//auto now = std::chrono::system_clock::now();
|
||||||
//auto now_l = std::chrono::current_zone()->to_local(now);
|
//auto now_l = std::chrono::current_zone()->to_local(now);
|
||||||
//auto now_s = std::chrono::floor<std::chrono::seconds>(now_l);
|
//auto now_s = std::chrono::floor<std::chrono::seconds>(now_l);
|
||||||
//std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss
|
//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
|
//std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY
|
||||||
|
|
||||||
t.move(1, 76);
|
t.move(1, 76);
|
||||||
t.style(Terminal::RESET);
|
t.style(Terminal::RESET);
|
||||||
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
|
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
void redraw(Terminal& t, Runtime& r, u64 scroll) {
|
void redraw(Terminal& t, Runtime& r, u64 scroll) {
|
||||||
// draw CPU, RAM
|
// draw CPU, RAM
|
||||||
drawCPU(t, r.cpu);
|
drawCPU(t, r.cpu);
|
||||||
drawRAM(t, r.ram, scroll);
|
drawRAM(t, r.ram, scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
int liveDebugMain() {
|
int liveDebugMain() {
|
||||||
Terminal t;
|
Terminal t;
|
||||||
Runtime runtime(1024);
|
Runtime runtime(1024);
|
||||||
|
|
||||||
bool running = true, update = true;
|
bool running = true, update = true;
|
||||||
u64 ramScroll = 0;
|
u64 ramScroll = 0;
|
||||||
u8 key = Terminal::UNKNOWN;
|
u8 key = Terminal::UNKNOWN;
|
||||||
|
|
||||||
t.println("Starting Spider live debug...");
|
t.println("Starting Spider live debug...");
|
||||||
t.altbuff(true).cursor(false);
|
t.altbuff(true).cursor(false);
|
||||||
|
|
||||||
drawTime(t);
|
drawTime(t);
|
||||||
drawHead(t);
|
drawHead(t);
|
||||||
drawCPUTempl(t, runtime.cpu);
|
drawCPUTempl(t, runtime.cpu);
|
||||||
|
|
||||||
// delay for time
|
// delay for time
|
||||||
auto last_exec = std::chrono::steady_clock::now();
|
auto last_exec = std::chrono::steady_clock::now();
|
||||||
auto delay = std::chrono::milliseconds(1000);
|
auto delay = std::chrono::milliseconds(1000);
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
// draw time
|
// draw time
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
if (now - last_exec >= delay) {
|
if (now - last_exec >= delay) {
|
||||||
drawTime(t);
|
drawTime(t);
|
||||||
last_exec = now;
|
last_exec = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// redraw something if it updated
|
// redraw something if it updated
|
||||||
if (update) {
|
if (update) {
|
||||||
redraw(t, runtime, ramScroll);
|
redraw(t, runtime, ramScroll);
|
||||||
update = false;
|
update = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Input
|
// Handle Input
|
||||||
key = t.getKeyNb();
|
key = t.getKeyNb();
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case Terminal::ESC:
|
case Terminal::ESC:
|
||||||
running = false;
|
running = false;
|
||||||
break;
|
break;
|
||||||
case Terminal::UP:
|
case Terminal::UP:
|
||||||
if (ramScroll >= 16) ramScroll -= 16;
|
if (ramScroll >= 16) ramScroll -= 16;
|
||||||
update = true;
|
update = true;
|
||||||
break;
|
break;
|
||||||
case Terminal::DOWN:
|
case Terminal::DOWN:
|
||||||
if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16;
|
if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16;
|
||||||
update = true;
|
update = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
t.altbuff(false).println("Stopped Spider live debug.").flush();
|
t.altbuff(false).println("Stopped Spider live debug.").flush();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
int liveDebugMain();
|
int liveDebugMain();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#include <spider/runtime/cpu/CPU.hpp>
|
#include <spider/runtime/cpu/CPU.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
void CPU::NOP() {
|
void CPU::NOP() {
|
||||||
// No Operation //
|
// No Operation //
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
#include "Quat.hpp"
|
#include "Quat.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
int quatMain() {
|
int quatMain() {
|
||||||
Quat<double> q1 = { 1.0f, 0.0f, 0.0f, 0.0f };
|
Quat<double> q1 = { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||||
Quat<double> q2 = { 0.5f, 0.5f, 0.5f, 0.5f };
|
Quat<double> q2 = { 0.5f, 0.5f, 0.5f, 0.5f };
|
||||||
|
|
||||||
Quat<double> result = quat_multiply(q1, q2); // Returns the result!
|
Quat<double> result = quat_multiply(q1, q2); // Returns the result!
|
||||||
|
|
||||||
std::cout << "Result: ("
|
std::cout << "Result: ("
|
||||||
<< result.w << ", "
|
<< result.w << ", "
|
||||||
<< result.x << ", "
|
<< result.x << ", "
|
||||||
<< result.y << ", "
|
<< result.y << ", "
|
||||||
<< result.z << ")" << std::endl;
|
<< result.z << ")" << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Quat {
|
struct Quat {
|
||||||
T w, x, y, z;
|
T w, x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiplies two quaternions together.
|
* Multiplies two quaternions together.
|
||||||
*/
|
*/
|
||||||
template<typename T> inline Quat<T> quat_multiply(Quat<T> A, Quat<T> B) {
|
template<typename T> inline Quat<T> quat_multiply(Quat<T> A, Quat<T> B) {
|
||||||
return {
|
return {
|
||||||
B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z,
|
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.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.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
|
B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,74 @@
|
|||||||
#include "ByteArray.hpp"
|
#include "ByteArray.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) {
|
ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) {
|
||||||
if (_size > 0) {
|
if (_size > 0) {
|
||||||
_mem = new u8[_size];
|
_mem = new u8[_size];
|
||||||
std::memset(_mem, 0, _size);
|
std::memset(_mem, 0, _size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) {
|
ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) {
|
||||||
std::copy(other._mem, other._mem + _size, _mem);
|
std::copy(other._mem, other._mem + _size, _mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) {
|
ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) {
|
||||||
other._mem = nullptr;
|
other._mem = nullptr;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::~ByteArray() {
|
ByteArray::~ByteArray() {
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray& ByteArray::operator=(const ByteArray& other) {
|
ByteArray& ByteArray::operator=(const ByteArray& other) {
|
||||||
if (this == &other) return *this; // lock self
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
u8* new_mem = new u8[other._size];
|
u8* new_mem = new u8[other._size];
|
||||||
std::copy(other._mem, other._mem + other._size, new_mem);
|
std::copy(other._mem, other._mem + other._size, new_mem);
|
||||||
|
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = new_mem;
|
_mem = new_mem;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray& ByteArray::operator=(ByteArray&& other) noexcept {
|
ByteArray& ByteArray::operator=(ByteArray&& other) noexcept {
|
||||||
if (this == &other) return *this; // lock self
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
|
|
||||||
_mem = other._mem; // time to steal!
|
_mem = other._mem; // time to steal!
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
|
|
||||||
other._mem = nullptr; // leave as a husk
|
other._mem = nullptr; // leave as a husk
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8& ByteArray::operator[](isize index) {
|
u8& ByteArray::operator[](isize index) {
|
||||||
return _mem[index];
|
return _mem[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 ByteArray::operator[](isize index) const {
|
u8 ByteArray::operator[](isize index) const {
|
||||||
return _mem[index];
|
return _mem[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* ByteArray::data() {
|
u8* ByteArray::data() {
|
||||||
return _mem;
|
return _mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* ByteArray::data() const {
|
const u8* ByteArray::data() const {
|
||||||
return _mem;
|
return _mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
isize ByteArray::size() const {
|
isize ByteArray::size() const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A general purpose byte array
|
* A general purpose byte array
|
||||||
* with RAII semantics.
|
* with RAII semantics.
|
||||||
*/
|
*/
|
||||||
class ByteArray {
|
class ByteArray {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
u8* _mem;
|
u8* _mem;
|
||||||
isize _size;
|
isize _size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ByteArray(isize length);
|
ByteArray(isize length);
|
||||||
|
|
||||||
ByteArray(const ByteArray& other);
|
ByteArray(const ByteArray& other);
|
||||||
|
|
||||||
ByteArray(ByteArray&& other) noexcept;
|
ByteArray(ByteArray&& other) noexcept;
|
||||||
|
|
||||||
~ByteArray();
|
~ByteArray();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ByteArray& operator=(const ByteArray& other);
|
ByteArray& operator=(const ByteArray& other);
|
||||||
|
|
||||||
ByteArray& operator=(ByteArray&& other) noexcept;
|
ByteArray& operator=(ByteArray&& other) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
u8& operator[](isize index);
|
u8& operator[](isize index);
|
||||||
|
|
||||||
u8 operator[](isize index) const;
|
u8 operator[](isize index) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
u8* data();
|
u8* data();
|
||||||
|
|
||||||
const u8* data() const;
|
const u8* data() const;
|
||||||
|
|
||||||
isize size() const;
|
isize size() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,130 +1,130 @@
|
|||||||
#include "RAM.hpp"
|
#include "RAM.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
// Constructors & Destructors //
|
// Constructors & Destructors //
|
||||||
|
|
||||||
RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) {
|
RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) {
|
||||||
if (_size > 0) {
|
if (_size > 0) {
|
||||||
_mem = new u8[_size];
|
_mem = new u8[_size];
|
||||||
std::memset(_mem, 0, _size);
|
std::memset(_mem, 0, _size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAM::RAM(const RAM& other) : _size(other._size), _oob(0) {
|
RAM::RAM(const RAM& other) : _size(other._size), _oob(0) {
|
||||||
_mem = new u8[_size];
|
_mem = new u8[_size];
|
||||||
std::copy(other._mem, other._mem + _size, _mem);
|
std::copy(other._mem, other._mem + _size, _mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) {
|
RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) {
|
||||||
other._mem = nullptr;
|
other._mem = nullptr;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RAM::~RAM() {
|
RAM::~RAM() {
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign Operators //
|
// Assign Operators //
|
||||||
|
|
||||||
RAM& RAM::operator=(const RAM& other) {
|
RAM& RAM::operator=(const RAM& other) {
|
||||||
if (this == &other) return *this; // lock self
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
u8* new_mem = new u8[other._size];
|
u8* new_mem = new u8[other._size];
|
||||||
std::copy(other._mem, other._mem + other._size, new_mem);
|
std::copy(other._mem, other._mem + other._size, new_mem);
|
||||||
|
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = new_mem;
|
_mem = new_mem;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RAM& RAM::operator=(RAM&& other) noexcept {
|
RAM& RAM::operator=(RAM&& other) noexcept {
|
||||||
if (this == &other) return *this; // lock self
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
|
|
||||||
_mem = other._mem; // time to steal!
|
_mem = other._mem; // time to steal!
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
|
|
||||||
other._mem = nullptr; // leave as a husk
|
other._mem = nullptr; // leave as a husk
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe Access //
|
// Unsafe Access //
|
||||||
|
|
||||||
u8& RAM::operator[](u64 i) { return _mem[i]; }
|
u8& RAM::operator[](u64 i) { return _mem[i]; }
|
||||||
|
|
||||||
u8 RAM::operator[](u64 i) const { return _mem[i]; }
|
u8 RAM::operator[](u64 i) const { return _mem[i]; }
|
||||||
|
|
||||||
// Managed Access //
|
// Managed Access //
|
||||||
|
|
||||||
u8& RAM::at(u64 i) {
|
u8& RAM::at(u64 i) {
|
||||||
return (i < _size) ? _mem[i] : _oob;
|
return (i < _size) ? _mem[i] : _oob;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 RAM::at(u64 i) const {
|
u8 RAM::at(u64 i) const {
|
||||||
return (i < _size) ? _mem[i] : _oob;
|
return (i < _size) ? _mem[i] : _oob;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Misc //
|
// Misc //
|
||||||
|
|
||||||
void RAM::resize(u64 new_size) {
|
void RAM::resize(u64 new_size) {
|
||||||
// Special case 1
|
// Special case 1
|
||||||
if (new_size == _size) return;
|
if (new_size == _size) return;
|
||||||
|
|
||||||
// Special case 2
|
// Special case 2
|
||||||
if (new_size == 0) {
|
if (new_size == 0) {
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = nullptr;
|
_mem = nullptr;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Allocate the new block
|
// 1. Allocate the new block
|
||||||
u8* new_mem = new u8[new_size];
|
u8* new_mem = new u8[new_size];
|
||||||
|
|
||||||
// 2. Zero-initialize
|
// 2. Zero-initialize
|
||||||
std::memset(new_mem, 0, new_size);
|
std::memset(new_mem, 0, new_size);
|
||||||
|
|
||||||
// 3. Preserve data
|
// 3. Preserve data
|
||||||
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
|
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
|
||||||
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
|
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
|
||||||
|
|
||||||
// 3.1 Previous size could be zero, where _mem would be null
|
// 3.1 Previous size could be zero, where _mem would be null
|
||||||
if (_mem != nullptr) {
|
if (_mem != nullptr) {
|
||||||
std::copy(_mem, _mem + bytes_to_copy, new_mem);
|
std::copy(_mem, _mem + bytes_to_copy, new_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Swap and Clean up
|
// 4. Swap and Clean up
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = new_mem;
|
_mem = new_mem;
|
||||||
_size = new_size;
|
_size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 RAM::size() const {
|
u64 RAM::size() const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* RAM::begin() {
|
u8* RAM::begin() {
|
||||||
return this->_mem;
|
return this->_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* RAM::end() {
|
u8* RAM::end() {
|
||||||
return this->_mem + this->_size;
|
return this->_mem + this->_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* RAM::begin() const {
|
const u8* RAM::begin() const {
|
||||||
return this->_mem;
|
return this->_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* RAM::end() const {
|
const u8* RAM::end() const {
|
||||||
return this->_mem + this->_size;
|
return this->_mem + this->_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,64 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A memory container.
|
* A memory container.
|
||||||
* As a reminder, the amount of RAM
|
* As a reminder, the amount of RAM
|
||||||
* is designed by the host.
|
* is designed by the host.
|
||||||
*/
|
*/
|
||||||
class RAM {
|
class RAM {
|
||||||
private:
|
private:
|
||||||
u8* _mem;
|
u8* _mem;
|
||||||
u64 _size;
|
u64 _size;
|
||||||
u8 _oob; // Out of bounds reference
|
u8 _oob; // Out of bounds reference
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RAM(u64 length);
|
RAM(u64 length);
|
||||||
|
|
||||||
RAM(const RAM& other);
|
RAM(const RAM& other);
|
||||||
|
|
||||||
RAM(RAM&& other) noexcept;
|
RAM(RAM&& other) noexcept;
|
||||||
|
|
||||||
~RAM();
|
~RAM();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RAM& operator=(const RAM& other);
|
RAM& operator=(const RAM& other);
|
||||||
|
|
||||||
RAM& operator=(RAM&& other) noexcept;
|
RAM& operator=(RAM&& other) noexcept;
|
||||||
|
|
||||||
public: // Unsafe access
|
public: // Unsafe access
|
||||||
|
|
||||||
u8& operator[](u64 i);
|
u8& operator[](u64 i);
|
||||||
|
|
||||||
u8 operator[](u64 i) const;
|
u8 operator[](u64 i) const;
|
||||||
|
|
||||||
public: // managed access (oob = 0)
|
public: // managed access (oob = 0)
|
||||||
|
|
||||||
u8& at(u64 i);
|
u8& at(u64 i);
|
||||||
|
|
||||||
u8 at(u64 i) const;
|
u8 at(u64 i) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void resize(u64 new_size);
|
void resize(u64 new_size);
|
||||||
|
|
||||||
u64 size() const;
|
u64 size() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
u8* begin();
|
u8* begin();
|
||||||
|
|
||||||
u8* end();
|
u8* end();
|
||||||
|
|
||||||
const u8* begin() const;
|
const u8* begin() const;
|
||||||
|
|
||||||
const u8* end() const;
|
const u8* end() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,250 +1,250 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
#include <spider/runtime/native/machine.hpp>
|
#include <spider/runtime/native/machine.hpp>
|
||||||
|
|
||||||
#if __cplusplus >= 202002L
|
#if __cplusplus >= 202002L
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SPIDER_COMPILER_MSVC)
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file contains cross platform type juggling.
|
* This file contains cross platform type juggling.
|
||||||
* Optimized for each case.
|
* Optimized for each case.
|
||||||
*
|
*
|
||||||
* General assumtions is that unsigned and signed
|
* General assumtions is that unsigned and signed
|
||||||
* integers are the exact same bit representation.
|
* integers are the exact same bit representation.
|
||||||
*
|
*
|
||||||
* Floats to and from integers is the focus when
|
* Floats to and from integers is the focus when
|
||||||
* juggling.
|
* juggling.
|
||||||
*
|
*
|
||||||
* Additionally, provides help selecting a specific
|
* Additionally, provides help selecting a specific
|
||||||
* type from raw bytes.
|
* type from raw bytes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Utilities //
|
// Utilities //
|
||||||
|
|
||||||
#if __cplusplus >= 202002L
|
#if __cplusplus >= 202002L
|
||||||
using std::bit_cast;
|
using std::bit_cast;
|
||||||
#else
|
#else
|
||||||
template<typename To, typename From>
|
template<typename To, typename From>
|
||||||
inline To bit_cast(const From& src) {
|
inline To bit_cast(const From& src) {
|
||||||
static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch");
|
static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch");
|
||||||
To dst;
|
To dst;
|
||||||
std::memcpy(&dst, &src, sizeof(To));
|
std::memcpy(&dst, &src, sizeof(To));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T byteswap(T v) {
|
inline T byteswap(T v) {
|
||||||
static_assert(std::is_integral<T>::value, "byteswap requires integral type");
|
static_assert(std::is_integral<T>::value, "byteswap requires integral type");
|
||||||
|
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
U u = static_cast<U>(v);
|
U u = static_cast<U>(v);
|
||||||
|
|
||||||
if constexpr (sizeof(T) == 1) {
|
if constexpr (sizeof(T) == 1) {
|
||||||
return v;
|
return v;
|
||||||
} else if constexpr (sizeof(T) == 2) {
|
} else if constexpr (sizeof(T) == 2) {
|
||||||
|
|
||||||
#if defined(SPIDER_COMPILER_MSVC)
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
u = _byteswap_ushort(u);
|
u = _byteswap_ushort(u);
|
||||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
u = __builtin_bswap16(u);
|
u = __builtin_bswap16(u);
|
||||||
#else
|
#else
|
||||||
u = (u >> 8) | (u << 8);
|
u = (u >> 8) | (u << 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else if constexpr (sizeof(T) == 4) {
|
} else if constexpr (sizeof(T) == 4) {
|
||||||
|
|
||||||
#if defined(SPIDER_COMPILER_MSVC)
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
u = _byteswap_ulong(u);
|
u = _byteswap_ulong(u);
|
||||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
u = __builtin_bswap32(u);
|
u = __builtin_bswap32(u);
|
||||||
#else
|
#else
|
||||||
u =
|
u =
|
||||||
((u & 0x000000FFu) << 24) |
|
((u & 0x000000FFu) << 24) |
|
||||||
((u & 0x0000FF00u) << 8) |
|
((u & 0x0000FF00u) << 8) |
|
||||||
((u & 0x00FF0000u) >> 8) |
|
((u & 0x00FF0000u) >> 8) |
|
||||||
((u & 0xFF000000u) >> 24);
|
((u & 0xFF000000u) >> 24);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else if constexpr (sizeof(T) == 8) {
|
} else if constexpr (sizeof(T) == 8) {
|
||||||
|
|
||||||
#if defined(SPIDER_COMPILER_MSVC)
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
u = _byteswap_uint64(u);
|
u = _byteswap_uint64(u);
|
||||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
u = __builtin_bswap64(u);
|
u = __builtin_bswap64(u);
|
||||||
#else
|
#else
|
||||||
u =
|
u =
|
||||||
((u & 0x00000000000000FFull) << 56) |
|
((u & 0x00000000000000FFull) << 56) |
|
||||||
((u & 0x000000000000FF00ull) << 40) |
|
((u & 0x000000000000FF00ull) << 40) |
|
||||||
((u & 0x0000000000FF0000ull) << 24) |
|
((u & 0x0000000000FF0000ull) << 24) |
|
||||||
((u & 0x00000000FF000000ull) << 8) |
|
((u & 0x00000000FF000000ull) << 8) |
|
||||||
((u & 0x000000FF00000000ull) >> 8) |
|
((u & 0x000000FF00000000ull) >> 8) |
|
||||||
((u & 0x0000FF0000000000ull) >> 24) |
|
((u & 0x0000FF0000000000ull) >> 24) |
|
||||||
((u & 0x00FF000000000000ull) >> 40) |
|
((u & 0x00FF000000000000ull) >> 40) |
|
||||||
((u & 0xFF00000000000000ull) >> 56);
|
((u & 0xFF00000000000000ull) >> 56);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Generic fallback (rare: non 1/2/4/8-byte types)
|
// Generic fallback (rare: non 1/2/4/8-byte types)
|
||||||
U result = 0;
|
U result = 0;
|
||||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8);
|
result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8);
|
||||||
}
|
}
|
||||||
u = result;
|
u = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<T>(u);
|
return static_cast<T>(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store Big Endian //
|
// Store Big Endian //
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void storeBE(T n, u8* bytes) {
|
inline void storeBE(T n, u8* bytes) {
|
||||||
static_assert(std::is_trivially_copyable<T>::value);
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
#if SPIDER_BIG_ENDIAN
|
#if SPIDER_BIG_ENDIAN
|
||||||
std::memcpy(bytes, &n, sizeof(T));
|
std::memcpy(bytes, &n, sizeof(T));
|
||||||
#endif
|
#endif
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
T tmp = byteswap(n);
|
T tmp = byteswap(n);
|
||||||
std::memcpy(bytes, &tmp, sizeof(T));
|
std::memcpy(bytes, &tmp, sizeof(T));
|
||||||
#endif
|
#endif
|
||||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
bytes[i] = static_cast<u8>(
|
bytes[i] = static_cast<u8>(
|
||||||
(static_cast<std::make_unsigned_t<T>>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF
|
(static_cast<std::make_unsigned_t<T>>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void storeBE<f32>(f32 n, u8* bytes) {
|
inline void storeBE<f32>(f32 n, u8* bytes) {
|
||||||
u32 tmp = bit_cast<u32>(n);
|
u32 tmp = bit_cast<u32>(n);
|
||||||
storeBE(tmp, bytes);
|
storeBE(tmp, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void storeBE<f64>(f64 n, u8* bytes) {
|
inline void storeBE<f64>(f64 n, u8* bytes) {
|
||||||
u64 tmp = bit_cast<u64>(n);
|
u64 tmp = bit_cast<u64>(n);
|
||||||
storeBE(tmp, bytes);
|
storeBE(tmp, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load Big Endian //
|
// Load Big Endian //
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void loadBE(T* n, const u8* bytes) {
|
inline void loadBE(T* n, const u8* bytes) {
|
||||||
static_assert(std::is_trivially_copyable<T>::value);
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
#if SPIDER_BIG_ENDIAN
|
#if SPIDER_BIG_ENDIAN
|
||||||
std::memcpy(n, bytes, sizeof(T));
|
std::memcpy(n, bytes, sizeof(T));
|
||||||
#endif
|
#endif
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
T tmp;
|
T tmp;
|
||||||
std::memcpy(&tmp, bytes, sizeof(T));
|
std::memcpy(&tmp, bytes, sizeof(T));
|
||||||
*n = byteswap(tmp);
|
*n = byteswap(tmp);
|
||||||
#endif
|
#endif
|
||||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
U result = 0;
|
U result = 0;
|
||||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
result |= static_cast<U>(bytes[i]) << ((sizeof(T) - 1 - i) * 8);
|
result |= static_cast<U>(bytes[i]) << ((sizeof(T) - 1 - i) * 8);
|
||||||
}
|
}
|
||||||
*n = static_cast<T>(result);
|
*n = static_cast<T>(result);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void loadBE<f32>(f32* n, const u8* bytes) {
|
inline void loadBE<f32>(f32* n, const u8* bytes) {
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
loadBE(&tmp, bytes);
|
loadBE(&tmp, bytes);
|
||||||
*n = bit_cast<f32>(tmp);
|
*n = bit_cast<f32>(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void loadBE<f64>(f64* n, const u8* bytes) {
|
inline void loadBE<f64>(f64* n, const u8* bytes) {
|
||||||
u64 tmp;
|
u64 tmp;
|
||||||
loadBE(&tmp, bytes);
|
loadBE(&tmp, bytes);
|
||||||
*n = bit_cast<f64>(tmp);
|
*n = bit_cast<f64>(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store Little Endian //
|
// Store Little Endian //
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void storeLE(T n, u8* bytes) {
|
inline void storeLE(T n, u8* bytes) {
|
||||||
static_assert(std::is_trivially_copyable<T>::value);
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
#if SPIDER_BIG_ENDIAN
|
#if SPIDER_BIG_ENDIAN
|
||||||
T tmp = byteswap(n);
|
T tmp = byteswap(n);
|
||||||
std::memcpy(bytes, &tmp, sizeof(T));
|
std::memcpy(bytes, &tmp, sizeof(T));
|
||||||
#endif
|
#endif
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
std::memcpy(bytes, &n, sizeof(T));
|
std::memcpy(bytes, &n, sizeof(T));
|
||||||
#endif
|
#endif
|
||||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
bytes[i] = static_cast<u8>(
|
bytes[i] = static_cast<u8>(
|
||||||
(static_cast<std::make_unsigned_t<T>>(n) >> (i * 8)) & 0xFF
|
(static_cast<std::make_unsigned_t<T>>(n) >> (i * 8)) & 0xFF
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void storeLE<f32>(f32 n, u8* bytes) {
|
inline void storeLE<f32>(f32 n, u8* bytes) {
|
||||||
u32 tmp = bit_cast<u32>(n);
|
u32 tmp = bit_cast<u32>(n);
|
||||||
storeLE(tmp, bytes);
|
storeLE(tmp, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void storeLE<f64>(f64 n, u8* bytes) {
|
inline void storeLE<f64>(f64 n, u8* bytes) {
|
||||||
u64 tmp = bit_cast<u64>(n);
|
u64 tmp = bit_cast<u64>(n);
|
||||||
storeLE(tmp, bytes);
|
storeLE(tmp, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load Little Endian //
|
// Load Little Endian //
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void loadLE(T* n, const u8* bytes) {
|
inline void loadLE(T* n, const u8* bytes) {
|
||||||
static_assert(std::is_trivially_copyable<T>::value);
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
#if SPIDER_BIG_ENDIAN
|
#if SPIDER_BIG_ENDIAN
|
||||||
T tmp;
|
T tmp;
|
||||||
std::memcpy(&tmp, bytes, sizeof(T));
|
std::memcpy(&tmp, bytes, sizeof(T));
|
||||||
*n = byteswap(tmp);
|
*n = byteswap(tmp);
|
||||||
#endif
|
#endif
|
||||||
#if SPIDER_LITTLE_ENDIAN
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
std::memcpy(n, bytes, sizeof(T));
|
std::memcpy(n, bytes, sizeof(T));
|
||||||
#endif
|
#endif
|
||||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
U result = 0;
|
U result = 0;
|
||||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
result |= static_cast<U>(bytes[i]) << (i * 8);
|
result |= static_cast<U>(bytes[i]) << (i * 8);
|
||||||
}
|
}
|
||||||
*n = static_cast<T>(result);
|
*n = static_cast<T>(result);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void loadLE<f32>(f32* n, const u8* bytes) {
|
inline void loadLE<f32>(f32* n, const u8* bytes) {
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
loadLE(&tmp, bytes);
|
loadLE(&tmp, bytes);
|
||||||
*n = bit_cast<f32>(tmp);
|
*n = bit_cast<f32>(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void loadLE<f64>(f64* n, const u8* bytes) {
|
inline void loadLE<f64>(f64* n, const u8* bytes) {
|
||||||
u64 tmp;
|
u64 tmp;
|
||||||
loadLE(&tmp, bytes);
|
loadLE(&tmp, bytes);
|
||||||
*n = bit_cast<f64>(tmp);
|
*n = bit_cast<f64>(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
#define SPIDER_NO_ICU
|
#define SPIDER_NO_ICU
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if define(SPIDER_OS_NONE)
|
#if defined(SPIDER_OS_NONE)
|
||||||
#define SPIDER_OS_NAME "None"
|
#define SPIDER_OS_NAME "None"
|
||||||
#elif !defined(SPIDER_OS_MCU)
|
#elif !defined(SPIDER_OS_MCU)
|
||||||
#error "[Spider Distro] Unsupported MCU OS"
|
#error "[Spider Distro] Unsupported MCU OS"
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// SPIDER DEFAULT SETTINGS, PER DISTRO //
|
// SPIDER DEFAULT SETTINGS, PER DISTRO //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
|
|
||||||
|
|
||||||
// ================== MEMORY FOOTPRINT ================== //
|
// ================== MEMORY FOOTPRINT ================== //
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use a normal amount of memory, assuming there
|
* Use a normal amount of memory, assuming there
|
||||||
* is like 100KB free of it.
|
* is like 100KB free of it.
|
||||||
*/
|
*/
|
||||||
#define SPIDER_MEMFOOTPRINT_NORMAL 0
|
#define SPIDER_MEMFOOTPRINT_NORMAL 0
|
||||||
/**
|
/**
|
||||||
* Attempt to reduce the memory footprint
|
* Attempt to reduce the memory footprint
|
||||||
* where possible, but without doing
|
* where possible, but without doing
|
||||||
* extreme adaptations.
|
* extreme adaptations.
|
||||||
*/
|
*/
|
||||||
#define SPIDER_MEMFOOTPRINT_REDUCED 1
|
#define SPIDER_MEMFOOTPRINT_REDUCED 1
|
||||||
/**
|
/**
|
||||||
* Will deliverately convert things from memory
|
* Will deliverately convert things from memory
|
||||||
* to functions in order to free as much memory
|
* to functions in order to free as much memory
|
||||||
* as possible, even if it slows things down.
|
* as possible, even if it slows things down.
|
||||||
*/
|
*/
|
||||||
#define SPIDER_MEMFOOTPRINT_MINIMAL 2
|
#define SPIDER_MEMFOOTPRINT_MINIMAL 2
|
||||||
|
|
||||||
#ifndef SPIDER_MEMFOOTPRINT
|
#ifndef SPIDER_MEMFOOTPRINT
|
||||||
#if defined(SPIDER_DISTRO_MOBILE) || defined(SPIDER_DISTRO_BROWSER)
|
#if defined(SPIDER_DISTRO_MOBILE) || defined(SPIDER_DISTRO_BROWSER)
|
||||||
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_REDUCED
|
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_REDUCED
|
||||||
#elif defined(SPIDER_DISTRO_MICRO)
|
#elif defined(SPIDER_DISTRO_MICRO)
|
||||||
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_MINIMAL
|
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_MINIMAL
|
||||||
#else
|
#else
|
||||||
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_NORMAL
|
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_NORMAL
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ================== MISC ================== //
|
// ================== MISC ================== //
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,112 +1,112 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// SPIDER MICROCONTROLLER AUTODETECT //
|
// SPIDER MICROCONTROLLER AUTODETECT //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
|
|
||||||
// Automatically enable configurations for the microcontroller //
|
// Automatically enable configurations for the microcontroller //
|
||||||
// so long as we can detect it or the user has already configured //
|
// so long as we can detect it or the user has already configured //
|
||||||
// the corresponding macros. //
|
// the corresponding macros. //
|
||||||
|
|
||||||
#define SPIDER_MCU_FAM_GENERIC 0
|
#define SPIDER_MCU_FAM_GENERIC 0
|
||||||
#define SPIDER_MCU_FAM_AVR 1
|
#define SPIDER_MCU_FAM_AVR 1
|
||||||
#define SPIDER_MCU_FAM_ARM_CM 2
|
#define SPIDER_MCU_FAM_ARM_CM 2
|
||||||
#define SPIDER_MCU_FAM_ARM_MBED 3
|
#define SPIDER_MCU_FAM_ARM_MBED 3
|
||||||
#define SPIDER_MCU_FAM_PIC 4
|
#define SPIDER_MCU_FAM_PIC 4
|
||||||
#define SPIDER_MCU_FAM_PIC32 5
|
#define SPIDER_MCU_FAM_PIC32 5
|
||||||
#define SPIDER_MCU_FAM_ESP8266 6
|
#define SPIDER_MCU_FAM_ESP8266 6
|
||||||
#define SPIDER_MCU_FAM_ESP32 7
|
#define SPIDER_MCU_FAM_ESP32 7
|
||||||
#define SPIDER_MCU_FAM_RISCV 8
|
#define SPIDER_MCU_FAM_RISCV 8
|
||||||
#define SPIDER_MCU_FAM_RP2040 9
|
#define SPIDER_MCU_FAM_RP2040 9
|
||||||
|
|
||||||
#if defined(SPIDER_MCU_AVR) || defined(__avr__) || defined(__AVR__)
|
#if defined(SPIDER_MCU_AVR) || defined(__avr__) || defined(__AVR__)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// AVR (Atmel / Microchip) //
|
// AVR (Atmel / Microchip) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_AVR
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_AVR
|
||||||
#define SPIDER_MCU_NAME "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__)
|
#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.) //
|
// ARM Cortex-M (most STM32, nRF, etc.) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_CM
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_CM
|
||||||
#define SPIDER_MCU_NAME "ARM Cortex-M"
|
#define SPIDER_MCU_NAME "ARM Cortex-M"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_MBED) || defined(TARGET_LIKE_MBED)
|
#elif defined(SPIDER_MCU_MBED) || defined(TARGET_LIKE_MBED)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// Mbed OS special detection //
|
// Mbed OS special detection //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_MBED
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_MBED
|
||||||
#define SPIDER_MCU_NAME "ARM MBED"
|
#define SPIDER_MCU_NAME "ARM MBED"
|
||||||
#define SPIDER_OS_NAME "MBED OS"
|
#define SPIDER_OS_NAME "MBED OS"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_PIC8) || defined(__XC) && (defined(_PIC14) || defined(_PIC16))
|
#elif defined(SPIDER_MCU_PIC8) || defined(__XC) && (defined(_PIC14) || defined(_PIC16))
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// PIC (8-bit) //
|
// PIC (8-bit) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC
|
||||||
#define SPIDER_MCU_NAME "PIC (8-bit)"
|
#define SPIDER_MCU_NAME "PIC (8-bit)"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_PIC32) || defined(__XC32__)
|
#elif defined(SPIDER_MCU_PIC32) || defined(__XC32__)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// PIC32 (MIPS) //
|
// PIC32 (MIPS) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC32
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC32
|
||||||
#define SPIDER_MCU_NAME "PIC (32-bit)"
|
#define SPIDER_MCU_NAME "PIC (32-bit)"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_ESP8266) || defined(ESP8266)
|
#elif defined(SPIDER_MCU_ESP8266) || defined(ESP8266)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// ESP8266 //
|
// ESP8266 //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP8266
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP8266
|
||||||
#define SPIDER_MCU_NAME "ESP-8266"
|
#define SPIDER_MCU_NAME "ESP-8266"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_ESP32) || defined(ESP32)
|
#elif defined(SPIDER_MCU_ESP32) || defined(ESP32)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// ESP32 //
|
// ESP32 //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP32
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP32
|
||||||
#define SPIDER_MCU_NAME "ESP-32"
|
#define SPIDER_MCU_NAME "ESP-32"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_PICO) || defined(PICO_PLATFORM) || defined(PICO_BOARD) || defined(RP2040) || defined(__RP2040__)
|
#elif defined(SPIDER_MCU_PICO) || defined(PICO_PLATFORM) || defined(PICO_BOARD) || defined(RP2040) || defined(__RP2040__)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// Raspberry Pi Pico (RP2040) //
|
// Raspberry Pi Pico (RP2040) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAM_FAMILY SPIDER_MCU_FAM_RP2040
|
#define SPIDER_MCU_FAM_FAMILY SPIDER_MCU_FAM_RP2040
|
||||||
#define SPIDER_MCU_NAME "ESP-32"
|
#define SPIDER_MCU_NAME "ESP-32"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_RISCV) || defined(__riscv) || defined(__riscv__)
|
#elif defined(SPIDER_MCU_RISCV) || defined(__riscv) || defined(__riscv__)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// RISC-V MCUs //
|
// RISC-V MCUs //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_RISCV
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_RISCV
|
||||||
#define SPIDER_MCU_NAME "RISC-V MCU"
|
#define SPIDER_MCU_NAME "RISC-V MCU"
|
||||||
|
|
||||||
#elif defined(SPIDER_MCU_GENERIC)
|
#elif defined(SPIDER_MCU_GENERIC)
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// GENERIC MICRO //
|
// GENERIC MICRO //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_GENERIC
|
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_GENERIC
|
||||||
#define SPIDER_MCU_NAME "Generic MCU"
|
#define SPIDER_MCU_NAME "Generic MCU"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPIDER_MCU_FAMILY
|
#ifdef SPIDER_MCU_FAMILY
|
||||||
|
|
||||||
#ifndef SPIDER_DISTRO_MICRO
|
#ifndef SPIDER_DISTRO_MICRO
|
||||||
#define SPIDER_DISTRO_MICRO
|
#define SPIDER_DISTRO_MICRO
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If SPIDER_OS_NAME was already defined, implies the SPIDER_MCU_FAM has an OS
|
// If SPIDER_OS_NAME was already defined, implies the SPIDER_MCU_FAM has an OS
|
||||||
#if defined(SPIDER_OS_NAME) && !defined(SPIDER_OS_MCU)
|
#if defined(SPIDER_OS_NAME) && !defined(SPIDER_OS_MCU)
|
||||||
#define SPIDER_OS_MCU
|
#define SPIDER_OS_MCU
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If no SPIDER_MCU_FAM OS defined, then it is NONE
|
// If no SPIDER_MCU_FAM OS defined, then it is NONE
|
||||||
#ifndef SPIDER_OS_MCU
|
#ifndef SPIDER_OS_MCU
|
||||||
#define SPIDER_OS_NONE
|
#define SPIDER_OS_NONE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(SPIDER_DISTRO_MICRO)
|
#elif defined(SPIDER_DISTRO_MICRO)
|
||||||
#error "[Spider Distro] Unsupported SPIDER_MCU_FAM. Define SPIDER_MCU_GENERIC and see if works."
|
#error "[Spider Distro] Unsupported SPIDER_MCU_FAM. Define SPIDER_MCU_GENERIC and see if works."
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,93 +1,93 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file contains macros related to machine dependent
|
* This file contains macros related to machine dependent
|
||||||
* things like alignment and type juggling
|
* things like alignment and type juggling
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// ENDIANNESS //
|
// ENDIANNESS //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
|
|
||||||
// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers
|
// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers
|
||||||
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
|
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
|
||||||
#define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
#define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||||
#define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
#define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||||
|
|
||||||
// Fallbacks (For older/constrained compilers)
|
// Fallbacks (For older/constrained compilers)
|
||||||
#else
|
#else
|
||||||
#if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega
|
#if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega
|
||||||
#define SPIDER_LITTLE_ENDIAN 1
|
#define SPIDER_LITTLE_ENDIAN 1
|
||||||
#define SPIDER_BIG_ENDIAN 0
|
#define SPIDER_BIG_ENDIAN 0
|
||||||
#elif defined(__wasm__) || defined(__wasm32__) // WebAssembly
|
#elif defined(__wasm__) || defined(__wasm32__) // WebAssembly
|
||||||
#define SPIDER_LITTLE_ENDIAN 1
|
#define SPIDER_LITTLE_ENDIAN 1
|
||||||
#define SPIDER_BIG_ENDIAN 0
|
#define SPIDER_BIG_ENDIAN 0
|
||||||
#elif defined(__arm__) || defined(__thumb__) // RP2040, STM32, etc.
|
#elif defined(__arm__) || defined(__thumb__) // RP2040, STM32, etc.
|
||||||
#if defined(__ARMEB__)
|
#if defined(__ARMEB__)
|
||||||
#define SPIDER_LITTLE_ENDIAN 0
|
#define SPIDER_LITTLE_ENDIAN 0
|
||||||
#define SPIDER_BIG_ENDIAN 1
|
#define SPIDER_BIG_ENDIAN 1
|
||||||
#else
|
#else
|
||||||
#define SPIDER_LITTLE_ENDIAN 1
|
#define SPIDER_LITTLE_ENDIAN 1
|
||||||
#define SPIDER_BIG_ENDIAN 0
|
#define SPIDER_BIG_ENDIAN 0
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__xtensa__) || defined(__ESP32__) // ESP32
|
#elif defined(__xtensa__) || defined(__ESP32__) // ESP32
|
||||||
#define SPIDER_LITTLE_ENDIAN 1
|
#define SPIDER_LITTLE_ENDIAN 1
|
||||||
#define SPIDER_BIG_ENDIAN 0
|
#define SPIDER_BIG_ENDIAN 0
|
||||||
// Likely will never use this clause
|
// Likely will never use this clause
|
||||||
// ...but keeps compatibility with the one (1)
|
// ...but keeps compatibility with the one (1)
|
||||||
// guy who uses MSVC.
|
// guy who uses MSVC.
|
||||||
#elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64)
|
#elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64)
|
||||||
#define SPIDER_LITTLE_ENDIAN 1
|
#define SPIDER_LITTLE_ENDIAN 1
|
||||||
#define SPIDER_BIG_ENDIAN 0
|
#define SPIDER_BIG_ENDIAN 0
|
||||||
#else
|
#else
|
||||||
#error "[Spider Machine] Unsupported or unknown architecture endianness!"
|
#error "[Spider Machine] Unsupported or unknown architecture endianness!"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Safety checks
|
// Safety checks
|
||||||
#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN)
|
#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN)
|
||||||
#error "[Spider Machine] Missed at least one little/big endian macros"
|
#error "[Spider Machine] Missed at least one little/big endian macros"
|
||||||
#endif
|
#endif
|
||||||
#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1
|
#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1
|
||||||
#warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!"
|
#warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
// PACKING //
|
// PACKING //
|
||||||
// (not used now) //
|
// (not used now) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
|
|
||||||
// Find out what compiler the user is using
|
// Find out what compiler the user is using
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define SPIDER_COMPILER_CLANG
|
#define SPIDER_COMPILER_CLANG
|
||||||
#define SPIDER_COMPILER_GCC_LIKE
|
#define SPIDER_COMPILER_GCC_LIKE
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#define SPIDER_COMPILER_GCC
|
#define SPIDER_COMPILER_GCC
|
||||||
#define SPIDER_COMPILER_GCC_LIKE
|
#define SPIDER_COMPILER_GCC_LIKE
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#define SPIDER_COMPILER_MSVC
|
#define SPIDER_COMPILER_MSVC
|
||||||
#else
|
#else
|
||||||
#define SPIDER_COMPILER_UNKNOWN
|
#define SPIDER_COMPILER_UNKNOWN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Macros...
|
// Macros...
|
||||||
#if defined(SPIDER_COMPILER_GCC_LIKE)
|
#if defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
#define SPIDER_PACK_BEGIN
|
#define SPIDER_PACK_BEGIN
|
||||||
#define SPIDER_PACK_END
|
#define SPIDER_PACK_END
|
||||||
#define SPIDER_PACK_STRUCT __attribute__((packed))
|
#define SPIDER_PACK_STRUCT __attribute__((packed))
|
||||||
|
|
||||||
#elif defined(SPIDER_COMPILER_MSVC)
|
#elif defined(SPIDER_COMPILER_MSVC)
|
||||||
#define SPIDER_BEGIN_PACKED __pragma(pack(push, 1))
|
#define SPIDER_BEGIN_PACKED __pragma(pack(push, 1))
|
||||||
#define SPIDER_END_PACKED __pragma(pack(pop))
|
#define SPIDER_END_PACKED __pragma(pack(pop))
|
||||||
#define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED
|
#define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define SPIDER_ATTRIBUTE_PACKED
|
#define SPIDER_ATTRIBUTE_PACKED
|
||||||
#define SPIDER_BEGIN_PACKED
|
#define SPIDER_BEGIN_PACKED
|
||||||
#define SPIDER_END_PACKED
|
#define SPIDER_END_PACKED
|
||||||
#define SPIDER_PACKED_STRUCT(decl) decl
|
#define SPIDER_PACKED_STRUCT(decl) decl
|
||||||
#warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!"
|
#warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spider {}
|
namespace spider {}
|
||||||
|
|||||||
@@ -1,77 +1,77 @@
|
|||||||
#include "InstrReel.hpp"
|
#include "InstrReel.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/cpu/CPU.hpp>
|
#include <spider/runtime/cpu/CPU.hpp>
|
||||||
|
|
||||||
#include <spider/runtime/memory/Types.hpp>
|
#include <spider/runtime/memory/Types.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
// Public Interface //
|
// Public Interface //
|
||||||
|
|
||||||
InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {}
|
InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {}
|
||||||
|
|
||||||
InstrReel::~InstrReel() {}
|
InstrReel::~InstrReel() {}
|
||||||
|
|
||||||
// Instruction abstraction //
|
// Instruction abstraction //
|
||||||
|
|
||||||
u8 InstrReel::atU8(u64 ip) {
|
u8 InstrReel::atU8(u64 ip) {
|
||||||
// guard against access
|
// guard against access
|
||||||
u64 ip_p = ip - _offset;
|
u64 ip_p = ip - _offset;
|
||||||
if(ip_p + 1 > _size) return 0;
|
if(ip_p + 1 > _size) return 0;
|
||||||
|
|
||||||
// send byte
|
// send byte
|
||||||
return _mem[ip];
|
return _mem[ip];
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 InstrReel::atU16(u64 ip) {
|
u16 InstrReel::atU16(u64 ip) {
|
||||||
// guard against access
|
// guard against access
|
||||||
u64 ip_p = ip - _offset;
|
u64 ip_p = ip - _offset;
|
||||||
if(ip_p + 2 > _size) return 0;
|
if(ip_p + 2 > _size) return 0;
|
||||||
|
|
||||||
// build a 16-bit big endian number
|
// build a 16-bit big endian number
|
||||||
u16 dat;
|
u16 dat;
|
||||||
spider::loadLE(&dat, _mem + ip_p);
|
spider::loadLE(&dat, _mem + ip_p);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 InstrReel::atU32(u64 ip) {
|
u32 InstrReel::atU32(u64 ip) {
|
||||||
// guard against access
|
// guard against access
|
||||||
u64 ip_p = ip - _offset;
|
u64 ip_p = ip - _offset;
|
||||||
if(ip_p + 4 > _size) return 0;
|
if(ip_p + 4 > _size) return 0;
|
||||||
|
|
||||||
// build a 32-bit big endian number
|
// build a 32-bit big endian number
|
||||||
u32 dat;
|
u32 dat;
|
||||||
spider::loadLE(&dat, _mem + ip_p);
|
spider::loadLE(&dat, _mem + ip_p);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 InstrReel::atU64(u64 ip) {
|
u64 InstrReel::atU64(u64 ip) {
|
||||||
// guard against access
|
// guard against access
|
||||||
u64 ip_p = ip - _offset;
|
u64 ip_p = ip - _offset;
|
||||||
if(ip_p + 8 > _size) return 0;
|
if(ip_p + 8 > _size) return 0;
|
||||||
|
|
||||||
// build a 64-bit big endian number
|
// build a 64-bit big endian number
|
||||||
u64 dat;
|
u64 dat;
|
||||||
spider::loadLE(&dat, _mem + ip_p);
|
spider::loadLE(&dat, _mem + ip_p);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 InstrReel::size() {
|
u64 InstrReel::size() {
|
||||||
return _total_size;
|
return _total_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static Utils //
|
// Static Utils //
|
||||||
|
|
||||||
u16 InstrReel::unpackInstr(u16 bcode) {
|
u16 InstrReel::unpackInstr(u16 bcode) {
|
||||||
return (bcode >> 5) & 0x1FF;
|
return (bcode >> 5) & 0x1FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 InstrReel::unpackAddrMode(u16 bcode) {
|
u8 InstrReel::unpackAddrMode(u16 bcode) {
|
||||||
return (bcode >> 2) & 0x1F;
|
return (bcode >> 2) & 0x1F;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 InstrReel::unpackTypeSize(u16 bcode) {
|
u8 InstrReel::unpackTypeSize(u16 bcode) {
|
||||||
return bcode & 0x3;
|
return bcode & 0x3;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,74 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/SpiderRuntime.hpp>
|
#include <spider/SpiderRuntime.hpp>
|
||||||
#include <spider/runtime/memory/ByteArray.hpp>
|
#include <spider/runtime/memory/ByteArray.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements an instruction reel.
|
* Implements an instruction reel.
|
||||||
*/
|
*/
|
||||||
class InstrReel {
|
class InstrReel {
|
||||||
protected: // Current accessing range //
|
protected: // Current accessing range //
|
||||||
|
|
||||||
u8* _mem;
|
u8* _mem;
|
||||||
isize _size;
|
isize _size;
|
||||||
isize _offset;
|
isize _offset;
|
||||||
isize _total_size;
|
isize _total_size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstrReel();
|
InstrReel();
|
||||||
|
|
||||||
virtual ~InstrReel();
|
virtual ~InstrReel();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u8 atU8(u64 ip);
|
virtual u8 atU8(u64 ip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u16 atU16(u64 ip);
|
virtual u16 atU16(u64 ip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u32 atU32(u64 ip);
|
virtual u32 atU32(u64 ip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u64 atU64(u64 ip);
|
virtual u64 atU64(u64 ip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current size of the instructions.
|
* Current size of the instructions.
|
||||||
*/
|
*/
|
||||||
virtual u64 size();
|
virtual u64 size();
|
||||||
|
|
||||||
public: // Static Utils //
|
public: // Static Utils //
|
||||||
|
|
||||||
static u16 unpackInstr(u16 bcode);
|
static u16 unpackInstr(u16 bcode);
|
||||||
|
|
||||||
static u8 unpackAddrMode(u16 bcode);
|
static u8 unpackAddrMode(u16 bcode);
|
||||||
|
|
||||||
static u8 unpackTypeSize(u16 bcode);
|
static u8 unpackTypeSize(u16 bcode);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,194 +1,194 @@
|
|||||||
#include "InstrReelDyn.hpp"
|
#include "InstrReelDyn.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/memory/Types.hpp>
|
#include <spider/runtime/memory/Types.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) {
|
InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) {
|
||||||
_total_size = length;
|
_total_size = length;
|
||||||
growToFit(length > 0 ? length - 1 : 0);
|
growToFit(length > 0 ? length - 1 : 0);
|
||||||
selectBlock(0);
|
selectBlock(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {}
|
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) {
|
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);
|
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)) {
|
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);
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelDyn::~InstrReelDyn() {
|
InstrReelDyn::~InstrReelDyn() {
|
||||||
// .. //
|
// .. //
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) {
|
InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) {
|
||||||
_use_count = copy._use_count;
|
_use_count = copy._use_count;
|
||||||
_block_index = copy._block_index;
|
_block_index = copy._block_index;
|
||||||
_blocks = copy._blocks;
|
_blocks = copy._blocks;
|
||||||
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept {
|
InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept {
|
||||||
_use_count = move._use_count;
|
_use_count = move._use_count;
|
||||||
_block_index = move._block_index;
|
_block_index = move._block_index;
|
||||||
_blocks = std::move(move._blocks);
|
_blocks = std::move(move._blocks);
|
||||||
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
|
|
||||||
move._use_count = 0;
|
move._use_count = 0;
|
||||||
move._block_index = 0;
|
move._block_index = 0;
|
||||||
move._mem = nullptr;
|
move._mem = nullptr;
|
||||||
move._offset = 0;
|
move._offset = 0;
|
||||||
move._size = 0;
|
move._size = 0;
|
||||||
move._total_size = 0;
|
move._total_size = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrReelDyn::growToFit(isize index) {
|
void InstrReelDyn::growToFit(isize index) {
|
||||||
while (_blocks.size() < (index + 1)) {
|
while (_blocks.size() < (index + 1)) {
|
||||||
_blocks.emplace_back();
|
_blocks.emplace_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isize InstrReelDyn::selectIndex(u64 ip) {
|
isize InstrReelDyn::selectIndex(u64 ip) {
|
||||||
return ip / 256;
|
return ip / 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) {
|
InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) {
|
||||||
// Update base class cache
|
// Update base class cache
|
||||||
auto ptr = &_blocks[index];
|
auto ptr = &_blocks[index];
|
||||||
_offset = index * 256;
|
_offset = index * 256;
|
||||||
_mem = ptr->data;
|
_mem = ptr->data;
|
||||||
_size = 256;
|
_size = 256;
|
||||||
_block_index = index;
|
_block_index = index;
|
||||||
|
|
||||||
//_blocks[block_idx].access_count++;
|
//_blocks[block_idx].access_count++;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 InstrReelDyn::atU8(u64 ip) {
|
u8 InstrReelDyn::atU8(u64 ip) {
|
||||||
isize j = selectIndex(ip);
|
isize j = selectIndex(ip);
|
||||||
if (j >= _blocks.size()) return 0;
|
if (j >= _blocks.size()) return 0;
|
||||||
if (j != _block_index) {
|
if (j != _block_index) {
|
||||||
this->selectBlock(j);
|
this->selectBlock(j);
|
||||||
}
|
}
|
||||||
return _mem[ip - _offset];
|
return _mem[ip - _offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 InstrReelDyn::atU16(u64 ip) {
|
u16 InstrReelDyn::atU16(u64 ip) {
|
||||||
isize j0 = selectIndex(ip);
|
isize j0 = selectIndex(ip);
|
||||||
isize j1 = selectIndex(ip + 1);
|
isize j1 = selectIndex(ip + 1);
|
||||||
if (j1 >= _blocks.size()) return 0;
|
if (j1 >= _blocks.size()) return 0;
|
||||||
if (j0 == j1 && j0 != _block_index) {
|
if (j0 == j1 && j0 != _block_index) {
|
||||||
selectBlock(j0);
|
selectBlock(j0);
|
||||||
}
|
}
|
||||||
if (j0 == j1 && j0 == _block_index) {
|
if (j0 == j1 && j0 == _block_index) {
|
||||||
u16 dat;
|
u16 dat;
|
||||||
spider::loadLE(&dat, _mem);
|
spider::loadLE(&dat, _mem);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// general case, first part
|
// general case, first part
|
||||||
u16 dat = 0;
|
u16 dat = 0;
|
||||||
const u8 size = sizeof(u16);
|
const u8 size = sizeof(u16);
|
||||||
|
|
||||||
// select first block and offset
|
// select first block and offset
|
||||||
selectBlock(j0);
|
selectBlock(j0);
|
||||||
u8 rem = ip % 256;
|
u8 rem = ip % 256;
|
||||||
|
|
||||||
for (u8 n = 0; n < size; n++) {
|
for (u8 n = 0; n < size; n++) {
|
||||||
dat |= _mem[rem++] << (n * 8);
|
dat |= _mem[rem++] << (n * 8);
|
||||||
ip++;
|
ip++;
|
||||||
if (!rem) selectBlock(++j0);
|
if (!rem) selectBlock(++j0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 InstrReelDyn::atU32(u64 ip) {
|
u32 InstrReelDyn::atU32(u64 ip) {
|
||||||
isize j0 = selectIndex(ip);
|
isize j0 = selectIndex(ip);
|
||||||
isize j1 = selectIndex(ip + 3);
|
isize j1 = selectIndex(ip + 3);
|
||||||
if (j1 >= _blocks.size()) return 0;
|
if (j1 >= _blocks.size()) return 0;
|
||||||
if (j0 == j1 && j0 != _block_index) {
|
if (j0 == j1 && j0 != _block_index) {
|
||||||
selectBlock(j0);
|
selectBlock(j0);
|
||||||
}
|
}
|
||||||
if (j0 == j1 && j0 == _block_index) {
|
if (j0 == j1 && j0 == _block_index) {
|
||||||
u32 dat;
|
u32 dat;
|
||||||
spider::loadLE(&dat, _mem);
|
spider::loadLE(&dat, _mem);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// general case, first part
|
// general case, first part
|
||||||
u32 dat = 0;
|
u32 dat = 0;
|
||||||
const u8 size = sizeof(u32);
|
const u8 size = sizeof(u32);
|
||||||
|
|
||||||
// select first block and offset
|
// select first block and offset
|
||||||
selectBlock(j0);
|
selectBlock(j0);
|
||||||
u8 rem = ip % 256;
|
u8 rem = ip % 256;
|
||||||
|
|
||||||
for (u8 n = 0; n < size; n++) {
|
for (u8 n = 0; n < size; n++) {
|
||||||
dat |= _mem[rem++] << (n * 8);
|
dat |= _mem[rem++] << (n * 8);
|
||||||
ip++;
|
ip++;
|
||||||
if (!rem) selectBlock(++j0);
|
if (!rem) selectBlock(++j0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 InstrReelDyn::atU64(u64 ip) {
|
u64 InstrReelDyn::atU64(u64 ip) {
|
||||||
isize j0 = selectIndex(ip);
|
isize j0 = selectIndex(ip);
|
||||||
isize j1 = selectIndex(ip + 3);
|
isize j1 = selectIndex(ip + 3);
|
||||||
if (j1 >= _blocks.size()) return 0;
|
if (j1 >= _blocks.size()) return 0;
|
||||||
if (j0 == j1 && j0 != _block_index) {
|
if (j0 == j1 && j0 != _block_index) {
|
||||||
selectBlock(j0);
|
selectBlock(j0);
|
||||||
}
|
}
|
||||||
if (j0 == j1 && j0 == _block_index) {
|
if (j0 == j1 && j0 == _block_index) {
|
||||||
u64 dat;
|
u64 dat;
|
||||||
spider::loadLE(&dat, _mem);
|
spider::loadLE(&dat, _mem);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// general case, first part
|
// general case, first part
|
||||||
u64 dat = 0;
|
u64 dat = 0;
|
||||||
const u8 size = sizeof(u64);
|
const u8 size = sizeof(u64);
|
||||||
|
|
||||||
// select first block and offset
|
// select first block and offset
|
||||||
selectBlock(j0);
|
selectBlock(j0);
|
||||||
u8 rem = ip % 256;
|
u8 rem = ip % 256;
|
||||||
|
|
||||||
for (u8 n = 0; n < size; n++) {
|
for (u8 n = 0; n < size; n++) {
|
||||||
dat |= _mem[rem++] << (n * 8);
|
dat |= _mem[rem++] << (n * 8);
|
||||||
ip++;
|
ip++;
|
||||||
if (!rem) selectBlock(++j0);
|
if (!rem) selectBlock(++j0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrReelDyn::at(u64 ip, u8 dat) {}
|
void InstrReelDyn::at(u64 ip, u8 dat) {}
|
||||||
|
|
||||||
void InstrReelDyn::at(u64 ip, u16 dat) {}
|
void InstrReelDyn::at(u64 ip, u16 dat) {}
|
||||||
|
|
||||||
void InstrReelDyn::at(u64 ip, u32 dat) {}
|
void InstrReelDyn::at(u64 ip, u32 dat) {}
|
||||||
|
|
||||||
void InstrReelDyn::at(u64 ip, u64 dat) {}
|
void InstrReelDyn::at(u64 ip, u64 dat) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends instruction at location.
|
* Appends instruction at location.
|
||||||
*/
|
*/
|
||||||
void InstrReelDyn::append(u64 ip, u16 bc) {}
|
void InstrReelDyn::append(u64 ip, u16 bc) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends instruction at the end.
|
* Appends instruction at the end.
|
||||||
*/
|
*/
|
||||||
void InstrReelDyn::append(u16 bc) {}
|
void InstrReelDyn::append(u16 bc) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes instruction at location.
|
* Removes instruction at location.
|
||||||
*/
|
*/
|
||||||
void InstrReelDyn::remove(u64 ip) {}
|
void InstrReelDyn::remove(u64 ip) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,110 +1,110 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/reel/InstrReel.hpp>
|
#include <spider/runtime/reel/InstrReel.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements an instruction reel.
|
* Implements an instruction reel.
|
||||||
*/
|
*/
|
||||||
class InstrReelDyn : public InstrReel {
|
class InstrReelDyn : public InstrReel {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct ReelBlock {
|
struct ReelBlock {
|
||||||
u8 data[256] = {};
|
u8 data[256] = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
u64 _use_count;
|
u64 _use_count;
|
||||||
isize _block_index;
|
isize _block_index;
|
||||||
std::deque<ReelBlock> _blocks;
|
std::deque<ReelBlock> _blocks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstrReelDyn(u64 length);
|
InstrReelDyn(u64 length);
|
||||||
|
|
||||||
InstrReelDyn(const u8* data, u64 length);
|
InstrReelDyn(const u8* data, u64 length);
|
||||||
|
|
||||||
InstrReelDyn(const InstrReelDyn& copy);
|
InstrReelDyn(const InstrReelDyn& copy);
|
||||||
|
|
||||||
InstrReelDyn(InstrReelDyn&& move) noexcept;
|
InstrReelDyn(InstrReelDyn&& move) noexcept;
|
||||||
|
|
||||||
virtual ~InstrReelDyn();
|
virtual ~InstrReelDyn();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstrReelDyn& operator=(const InstrReelDyn& copy);
|
InstrReelDyn& operator=(const InstrReelDyn& copy);
|
||||||
|
|
||||||
InstrReelDyn& operator=(InstrReelDyn&& move) noexcept;
|
InstrReelDyn& operator=(InstrReelDyn&& move) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
isize selectIndex(u64 ip);
|
isize selectIndex(u64 ip);
|
||||||
|
|
||||||
void growToFit(isize index);
|
void growToFit(isize index);
|
||||||
|
|
||||||
ReelBlock* selectBlock(isize index);
|
ReelBlock* selectBlock(isize index);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u8 atU8(u64 ip) override;
|
virtual u8 atU8(u64 ip) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u16 atU16(u64 ip) override;
|
virtual u16 atU16(u64 ip) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u32 atU32(u64 ip) override;
|
virtual u32 atU32(u64 ip) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
* Reindexing may occur, continous access
|
* Reindexing may occur, continous access
|
||||||
* may incurr in less penalties.
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
virtual u64 atU64(u64 ip) override;
|
virtual u64 atU64(u64 ip) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void at(u64 ip, u8 dat);
|
void at(u64 ip, u8 dat);
|
||||||
|
|
||||||
void at(u64 ip, u16 dat);
|
void at(u64 ip, u16 dat);
|
||||||
|
|
||||||
void at(u64 ip, u32 dat);
|
void at(u64 ip, u32 dat);
|
||||||
|
|
||||||
void at(u64 ip, u64 dat);
|
void at(u64 ip, u64 dat);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends instruction at location.
|
* Appends instruction at location.
|
||||||
*/
|
*/
|
||||||
void append(u64 ip, u16 bc);
|
void append(u64 ip, u16 bc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends instruction at the end.
|
* Appends instruction at the end.
|
||||||
*/
|
*/
|
||||||
void append(u16 bc);
|
void append(u16 bc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes instruction at location.
|
* Removes instruction at location.
|
||||||
*/
|
*/
|
||||||
void remove(u64 ip);
|
void remove(u64 ip);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,149 +1,149 @@
|
|||||||
#include "InstrReelFixed.hpp"
|
#include "InstrReelFixed.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/memory/Types.hpp>
|
#include <spider/runtime/memory/Types.hpp>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
// Constructors & Destructors //
|
// Constructors & Destructors //
|
||||||
|
|
||||||
InstrReelFixed::InstrReelFixed(u64 length) {
|
InstrReelFixed::InstrReelFixed(u64 length) {
|
||||||
this->_offset = 0;
|
this->_offset = 0;
|
||||||
this->_size = length;
|
this->_size = length;
|
||||||
this->_total_size = length;
|
this->_total_size = length;
|
||||||
|
|
||||||
if (_size > 0) {
|
if (_size > 0) {
|
||||||
_mem = new u8[_size];
|
_mem = new u8[_size];
|
||||||
std::memset(_mem, 0, _size);
|
std::memset(_mem, 0, _size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelFixed::InstrReelFixed(const u8* data, u64 length) {
|
InstrReelFixed::InstrReelFixed(const u8* data, u64 length) {
|
||||||
this->_offset = 0;
|
this->_offset = 0;
|
||||||
this->_size = length;
|
this->_size = length;
|
||||||
this->_total_size = length;
|
this->_total_size = length;
|
||||||
|
|
||||||
if (_size > 0) {
|
if (_size > 0) {
|
||||||
_mem = new u8[_size];
|
_mem = new u8[_size];
|
||||||
std::copy(data, data + _size, _mem);
|
std::copy(data, data + _size, _mem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) {
|
InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) {
|
||||||
_offset = other._offset;
|
_offset = other._offset;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
_total_size = other._total_size;
|
_total_size = other._total_size;
|
||||||
_mem = new u8[_size];
|
_mem = new u8[_size];
|
||||||
std::copy(other._mem, other._mem + _size, _mem);
|
std::copy(other._mem, other._mem + _size, _mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept {
|
InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept {
|
||||||
_mem = other._mem;
|
_mem = other._mem;
|
||||||
_offset = other._offset;
|
_offset = other._offset;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
_total_size = other._total_size;
|
_total_size = other._total_size;
|
||||||
|
|
||||||
other._mem = nullptr;
|
other._mem = nullptr;
|
||||||
other._offset = 0;
|
other._offset = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
other._total_size = 0;
|
other._total_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelFixed::~InstrReelFixed() {
|
InstrReelFixed::~InstrReelFixed() {
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign Operators //
|
// Assign Operators //
|
||||||
|
|
||||||
InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& other) {
|
InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& other) {
|
||||||
if (this == &other) return *this; // lock self
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
u8* new_mem = new u8[other._size];
|
u8* new_mem = new u8[other._size];
|
||||||
std::copy(other._mem, other._mem + other._size, new_mem);
|
std::copy(other._mem, other._mem + other._size, new_mem);
|
||||||
|
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = new_mem;
|
_mem = new_mem;
|
||||||
_offset = other._offset;
|
_offset = other._offset;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
_total_size = other._total_size;
|
_total_size = other._total_size;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept {
|
InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept {
|
||||||
if (this == &other) return *this; // lock self
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
|
|
||||||
_mem = other._mem; // steal
|
_mem = other._mem; // steal
|
||||||
_offset = other._offset;
|
_offset = other._offset;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
_total_size = other._total_size;
|
_total_size = other._total_size;
|
||||||
|
|
||||||
other._mem = nullptr; // leave as husk
|
other._mem = nullptr; // leave as husk
|
||||||
other._offset = 0;
|
other._offset = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
other._total_size = 0;
|
other._total_size = 0;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Misc //
|
// Misc //
|
||||||
|
|
||||||
void InstrReelFixed::at(u64 ip, u8 dat) {
|
void InstrReelFixed::at(u64 ip, u8 dat) {
|
||||||
if(ip + 1 > _size) return;
|
if(ip + 1 > _size) return;
|
||||||
_mem[ip] = dat;
|
_mem[ip] = dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrReelFixed::at(u64 ip, u16 dat) {
|
void InstrReelFixed::at(u64 ip, u16 dat) {
|
||||||
if(ip + 2 > _size) return;
|
if(ip + 2 > _size) return;
|
||||||
spider::storeLE(dat, _mem + ip);
|
spider::storeLE(dat, _mem + ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrReelFixed::at(u64 ip, u32 dat) {
|
void InstrReelFixed::at(u64 ip, u32 dat) {
|
||||||
if(ip + 4 > _size) return;
|
if(ip + 4 > _size) return;
|
||||||
spider::storeLE(dat, _mem + ip);
|
spider::storeLE(dat, _mem + ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrReelFixed::at(u64 ip, u64 dat) {
|
void InstrReelFixed::at(u64 ip, u64 dat) {
|
||||||
if(ip + 8 > _size) return;
|
if(ip + 8 > _size) return;
|
||||||
spider::storeLE(dat, _mem + ip);
|
spider::storeLE(dat, _mem + ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrReelFixed::resize(u64 new_size) {
|
void InstrReelFixed::resize(u64 new_size) {
|
||||||
// Special case 1
|
// Special case 1
|
||||||
if (new_size == _size) return;
|
if (new_size == _size) return;
|
||||||
|
|
||||||
// Special case 2
|
// Special case 2
|
||||||
if (new_size == 0) {
|
if (new_size == 0) {
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = nullptr;
|
_mem = nullptr;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
_total_size = 0;
|
_total_size = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Allocate the new block
|
// 1. Allocate the new block
|
||||||
u8* new_mem = new u8[new_size];
|
u8* new_mem = new u8[new_size];
|
||||||
|
|
||||||
// 2. Zero-initialize
|
// 2. Zero-initialize
|
||||||
std::memset(new_mem, 0, new_size);
|
std::memset(new_mem, 0, new_size);
|
||||||
|
|
||||||
// 3. Preserve data
|
// 3. Preserve data
|
||||||
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
|
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
|
||||||
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
|
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
|
||||||
|
|
||||||
// 3.1 Previous size could be zero, where _mem would be null
|
// 3.1 Previous size could be zero, where _mem would be null
|
||||||
if (_mem != nullptr) {
|
if (_mem != nullptr) {
|
||||||
std::copy(_mem, _mem + bytes_to_copy, new_mem);
|
std::copy(_mem, _mem + bytes_to_copy, new_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Swap and Clean up
|
// 4. Swap and Clean up
|
||||||
delete[] _mem;
|
delete[] _mem;
|
||||||
_mem = new_mem;
|
_mem = new_mem;
|
||||||
_size = new_size;
|
_size = new_size;
|
||||||
_total_size = new_size;
|
_total_size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/reel/InstrReel.hpp>
|
#include <spider/runtime/reel/InstrReel.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements an instruction reel.
|
* Implements an instruction reel.
|
||||||
*/
|
*/
|
||||||
class InstrReelFixed : public InstrReel {
|
class InstrReelFixed : public InstrReel {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstrReelFixed(u64 length);
|
InstrReelFixed(u64 length);
|
||||||
|
|
||||||
InstrReelFixed(const u8* data, u64 length);
|
InstrReelFixed(const u8* data, u64 length);
|
||||||
|
|
||||||
InstrReelFixed(const InstrReelFixed& copy);
|
InstrReelFixed(const InstrReelFixed& copy);
|
||||||
|
|
||||||
InstrReelFixed(InstrReelFixed&& move) noexcept;
|
InstrReelFixed(InstrReelFixed&& move) noexcept;
|
||||||
|
|
||||||
virtual ~InstrReelFixed();
|
virtual ~InstrReelFixed();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstrReelFixed& operator=(const InstrReelFixed& copy);
|
InstrReelFixed& operator=(const InstrReelFixed& copy);
|
||||||
|
|
||||||
InstrReelFixed& operator=(InstrReelFixed&& move) noexcept;
|
InstrReelFixed& operator=(InstrReelFixed&& move) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void at(u64 ip, u8 dat);
|
void at(u64 ip, u8 dat);
|
||||||
|
|
||||||
void at(u64 ip, u16 dat);
|
void at(u64 ip, u16 dat);
|
||||||
|
|
||||||
void at(u64 ip, u32 dat);
|
void at(u64 ip, u32 dat);
|
||||||
|
|
||||||
void at(u64 ip, u64 dat);
|
void at(u64 ip, u64 dat);
|
||||||
|
|
||||||
void resize(u64 new_size);
|
void resize(u64 new_size);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,277 +1,277 @@
|
|||||||
#include "Terminal.hpp"
|
#include "Terminal.hpp"
|
||||||
|
|
||||||
#include <spider/runtime/native/distro.hpp>
|
#include <spider/runtime/native/distro.hpp>
|
||||||
|
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SPIDER_DISTRO_DESKTOP)
|
#if defined(SPIDER_DISTRO_DESKTOP)
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
// Style //
|
// Style //
|
||||||
const char* Terminal::RESET = "\033[0m";
|
const char* Terminal::RESET = "\033[0m";
|
||||||
const char* Terminal::BOLD = "\033[1m";
|
const char* Terminal::BOLD = "\033[1m";
|
||||||
const char* Terminal::ITALIC = "\033[3m";
|
const char* Terminal::ITALIC = "\033[3m";
|
||||||
const char* Terminal::FAINT = "\033[2m";
|
const char* Terminal::FAINT = "\033[2m";
|
||||||
const char* Terminal::STRIKE = "\033[9m";
|
const char* Terminal::STRIKE = "\033[9m";
|
||||||
|
|
||||||
// Foreground //
|
// Foreground //
|
||||||
const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m";
|
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_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_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_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_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_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_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";
|
const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m";
|
||||||
|
|
||||||
// Background //
|
// Background //
|
||||||
const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m";
|
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_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_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_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_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_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_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";
|
const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m";
|
||||||
|
|
||||||
Terminal::Terminal() {
|
Terminal::Terminal() {
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
// Enable UTF-8
|
// Enable UTF-8
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
|
|
||||||
// enable vtp
|
// enable vtp
|
||||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
DWORD dwMode = 0;
|
DWORD dwMode = 0;
|
||||||
GetConsoleMode(hOut, &dwMode);
|
GetConsoleMode(hOut, &dwMode);
|
||||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
SetConsoleMode(hOut, dwMode);
|
SetConsoleMode(hOut, dwMode);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal::~Terminal() {
|
Terminal::~Terminal() {
|
||||||
altbuff(false).style(RESET).cursor(true).flush();
|
altbuff(false).style(RESET).cursor(true).flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::style(const std::string_view code) {
|
Terminal& Terminal::style(const std::string_view code) {
|
||||||
std::cout << code;
|
std::cout << code;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::move(i32 row, i32 col) {
|
Terminal& Terminal::move(i32 row, i32 col) {
|
||||||
std::cout << "\033[" << row << ";" << col << "H";
|
std::cout << "\033[" << row << ";" << col << "H";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::altbuff(bool enable) {
|
Terminal& Terminal::altbuff(bool enable) {
|
||||||
std::cout << (enable ? "\033[?1049h" : "\033[?1049l");
|
std::cout << (enable ? "\033[?1049h" : "\033[?1049l");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::cls() {
|
Terminal& Terminal::cls() {
|
||||||
std::cout << "\033[2J";
|
std::cout << "\033[2J";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::scrollRange(i32 start, i32 end) {
|
Terminal& Terminal::scrollRange(i32 start, i32 end) {
|
||||||
std::cout << "\033[" << start << ";" << end << "r\033[?6h";
|
std::cout << "\033[" << start << ";" << end << "r\033[?6h";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::undoSRange() {
|
Terminal& Terminal::undoSRange() {
|
||||||
std::cout << "\033[r\033[?6l\033[H";
|
std::cout << "\033[r\033[?6l\033[H";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::fill(const std::string_view color) {
|
Terminal& Terminal::fill(const std::string_view color) {
|
||||||
this->style(color);
|
this->style(color);
|
||||||
this->cls();
|
this->cls();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::clearRow(i32 row) {
|
Terminal& Terminal::clearRow(i32 row) {
|
||||||
// Move to row, column 1
|
// Move to row, column 1
|
||||||
this->move(row, 1);
|
this->move(row, 1);
|
||||||
// \033[2K clears the entire line
|
// \033[2K clears the entire line
|
||||||
std::cout << "\033[2K";
|
std::cout << "\033[2K";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::clearRows(i32 start, i32 end) {
|
Terminal& Terminal::clearRows(i32 start, i32 end) {
|
||||||
// Ensure we don't loop infinitely if start > end
|
// Ensure we don't loop infinitely if start > end
|
||||||
if (start > end) std::swap(start, end);
|
if (start > end) std::swap(start, end);
|
||||||
|
|
||||||
for (i32 i = start; i <= end; ++i) {
|
for (i32 i = start; i <= end; ++i) {
|
||||||
this->clearRow(i);
|
this->clearRow(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Move cursor back to the start of the cleared block
|
// Optional: Move cursor back to the start of the cleared block
|
||||||
this->move(start, 1);
|
this->move(start, 1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::cursor(bool show) {
|
Terminal& Terminal::cursor(bool show) {
|
||||||
std::cout << (show ? "\033[?25h" : "\033[?25l");
|
std::cout << (show ? "\033[?25h" : "\033[?25l");
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) {
|
Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) {
|
||||||
// 1. Draw the top border
|
// 1. Draw the top border
|
||||||
move(startRow, startCol);
|
move(startRow, startCol);
|
||||||
std::cout << "┌";
|
std::cout << "┌";
|
||||||
for (i32 i = 0; i < width - 2; ++i) std::cout << "─";
|
for (i32 i = 0; i < width - 2; ++i) std::cout << "─";
|
||||||
std::cout << "┐";
|
std::cout << "┐";
|
||||||
|
|
||||||
// 2. Draw the sides
|
// 2. Draw the sides
|
||||||
for (i32 i = 1; i < height - 1; ++i) {
|
for (i32 i = 1; i < height - 1; ++i) {
|
||||||
move(startRow + i, startCol);
|
move(startRow + i, startCol);
|
||||||
std::cout << "│";
|
std::cout << "│";
|
||||||
move(startRow + i, startCol + width - 1);
|
move(startRow + i, startCol + width - 1);
|
||||||
std::cout << "│";
|
std::cout << "│";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Draw the bottom border
|
// 3. Draw the bottom border
|
||||||
move(startRow + height - 1, startCol);
|
move(startRow + height - 1, startCol);
|
||||||
std::cout << "└";
|
std::cout << "└";
|
||||||
for (i32 i = 0; i < width - 2; ++i) std::cout << "─";
|
for (i32 i = 0; i < width - 2; ++i) std::cout << "─";
|
||||||
std::cout << "┘";
|
std::cout << "┘";
|
||||||
|
|
||||||
// 4. Overlay the title if provided
|
// 4. Overlay the title if provided
|
||||||
if (!title.empty()) {
|
if (!title.empty()) {
|
||||||
move(startRow, startCol + (width - title.size() - 2) / 2);
|
move(startRow, startCol + (width - title.size() - 2) / 2);
|
||||||
std::cout << " " << title << " ";
|
std::cout << " " << title << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout.flush();
|
std::cout.flush();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::flush() {
|
Terminal& Terminal::flush() {
|
||||||
std::cout << std::flush;
|
std::cout << std::flush;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::sink() {
|
Terminal& Terminal::sink() {
|
||||||
std::cin.clear();
|
std::cin.clear();
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
while (_kbhit()) _getch();
|
while (_kbhit()) _getch();
|
||||||
#endif
|
#endif
|
||||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
tcflush(STDIN_FILENO, TCIFLUSH);
|
tcflush(STDIN_FILENO, TCIFLUSH);
|
||||||
#endif
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<i32, i32> Terminal::getSize() {
|
std::pair<i32, i32> Terminal::getSize() {
|
||||||
std::pair<i32, i32> pair;
|
std::pair<i32, i32> pair;
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
|
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
|
||||||
pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||||
pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
|
||||||
pair.first = w.ws_col;
|
pair.first = w.ws_col;
|
||||||
pair.second = w.ws_row;
|
pair.second = w.ws_row;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal& Terminal::wait() {
|
Terminal& Terminal::wait() {
|
||||||
sink();
|
sink();
|
||||||
std::cin.get();
|
std::cin.get();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Terminal::getKey() {
|
u8 Terminal::getKey() {
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
i32 ch = _getch();
|
i32 ch = _getch();
|
||||||
if (ch == 0 || ch == 224) {
|
if (ch == 0 || ch == 224) {
|
||||||
switch (_getch()) {
|
switch (_getch()) {
|
||||||
case 72: return Terminal::UP;
|
case 72: return Terminal::UP;
|
||||||
case 80: return Terminal::DOWN;
|
case 80: return Terminal::DOWN;
|
||||||
case 75: return Terminal::LEFT;
|
case 75: return Terminal::LEFT;
|
||||||
case 77: return Terminal::RIGHT;
|
case 77: return Terminal::RIGHT;
|
||||||
default: return Terminal::UNKNOWN;
|
default: return Terminal::UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ch == 13) return Terminal::ENTER;
|
if (ch == 13) return Terminal::ENTER;
|
||||||
if (ch == 27) return Terminal::ESC;
|
if (ch == 27) return Terminal::ESC;
|
||||||
if (ch == 8) return Terminal::BACKSPACE;
|
if (ch == 8) return Terminal::BACKSPACE;
|
||||||
return Terminal::UNKNOWN;
|
return Terminal::UNKNOWN;
|
||||||
#endif
|
#endif
|
||||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
struct termios oldt, newt;
|
struct termios oldt, newt;
|
||||||
tcgetattr(STDIN_FILENO, &oldt);
|
tcgetattr(STDIN_FILENO, &oldt);
|
||||||
newt = oldt;
|
newt = oldt;
|
||||||
newt.c_lflag &= ~(ICANON | ECHO);
|
newt.c_lflag &= ~(ICANON | ECHO);
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||||
|
|
||||||
u8 result = Terminal::UNKNOWN;
|
u8 result = Terminal::UNKNOWN;
|
||||||
int ch = getchar();
|
int ch = getchar();
|
||||||
|
|
||||||
if (ch == 27) { // Potential Escape Sequence
|
if (ch == 27) { // Potential Escape Sequence
|
||||||
// Use a small timeout or check if more chars are in buffer
|
// Use a small timeout or check if more chars are in buffer
|
||||||
// to distinguish between 'Esc' key and 'Arrow' sequence
|
// to distinguish between 'Esc' key and 'Arrow' sequence
|
||||||
// Another Win for the Win API
|
// Another Win for the Win API
|
||||||
struct timeval tv = { 0, 10000 }; // 10ms wait
|
struct timeval tv = { 0, 10000 }; // 10ms wait
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(STDIN_FILENO, &fds);
|
FD_SET(STDIN_FILENO, &fds);
|
||||||
|
|
||||||
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
||||||
if (getchar() == '[') {
|
if (getchar() == '[') {
|
||||||
switch (getchar()) {
|
switch (getchar()) {
|
||||||
case 'A': result = Terminal::UP; break;
|
case 'A': result = Terminal::UP; break;
|
||||||
case 'B': result = Terminal::DOWN; break;
|
case 'B': result = Terminal::DOWN; break;
|
||||||
case 'D': result = Terminal::LEFT; break;
|
case 'D': result = Terminal::LEFT; break;
|
||||||
case 'C': result = Terminal::RIGHT; break;
|
case 'C': result = Terminal::RIGHT; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = Terminal::ESC;
|
result = Terminal::ESC;
|
||||||
}
|
}
|
||||||
} else if (ch == 10) result = Terminal::ENTER;
|
} else if (ch == 10) result = Terminal::ENTER;
|
||||||
else if (ch == 127) result = Terminal::BACKSPACE;
|
else if (ch == 127) result = Terminal::BACKSPACE;
|
||||||
else result = (u8)ch;
|
else result = (u8)ch;
|
||||||
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||||
return result;
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Terminal::getKeyNb() {
|
u8 Terminal::getKeyNb() {
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
if (_kbhit()) return getKey();
|
if (_kbhit()) return getKey();
|
||||||
return Terminal::UNKNOWN;
|
return Terminal::UNKNOWN;
|
||||||
#endif
|
#endif
|
||||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
struct timeval tv = { 0, 0 };
|
struct timeval tv = { 0, 0 };
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(STDIN_FILENO, &fds);
|
FD_SET(STDIN_FILENO, &fds);
|
||||||
// select() returns > 0 if there is data to read
|
// select() returns > 0 if there is data to read
|
||||||
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
||||||
return getKey();
|
return getKey();
|
||||||
}
|
}
|
||||||
return Terminal::UNKNOWN;
|
return Terminal::UNKNOWN;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,176 +1,176 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/runtime/common.hpp>
|
#include <spider/runtime/common.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
class Terminal {
|
class Terminal {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static const char* RESET;
|
static const char* RESET;
|
||||||
static const char* BOLD;
|
static const char* BOLD;
|
||||||
static const char* ITALIC;
|
static const char* ITALIC;
|
||||||
static const char* FAINT;
|
static const char* FAINT;
|
||||||
static const char* STRIKE;
|
static const char* STRIKE;
|
||||||
|
|
||||||
static const char* FG_BLACK; static const char* FG_B_BLACK;
|
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_RED; static const char* FG_B_RED;
|
||||||
static const char* FG_GREEN; static const char* FG_B_GREEN;
|
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_YELLOW; static const char* FG_B_YELLOW;
|
||||||
static const char* FG_BLUE; static const char* FG_B_BLUE;
|
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_MAGENTA; static const char* FG_B_MAGENTA;
|
||||||
static const char* FG_CYAN; static const char* FG_B_CYAN;
|
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* FG_WHITE; static const char* FG_B_WHITE;
|
||||||
|
|
||||||
static const char* BG_BLACK; static const char* BG_B_BLACK;
|
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_RED; static const char* BG_B_RED;
|
||||||
static const char* BG_GREEN; static const char* BG_B_GREEN;
|
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_YELLOW; static const char* BG_B_YELLOW;
|
||||||
static const char* BG_BLUE; static const char* BG_B_BLUE;
|
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_MAGENTA; static const char* BG_B_MAGENTA;
|
||||||
static const char* BG_CYAN; static const char* BG_B_CYAN;
|
static const char* BG_CYAN; static const char* BG_B_CYAN;
|
||||||
static const char* BG_WHITE; static const char* BG_B_WHITE;
|
static const char* BG_WHITE; static const char* BG_B_WHITE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Key Definitions (ASCII OK) //
|
// Key Definitions (ASCII OK) //
|
||||||
static constexpr const u8 UP = 0x80;
|
static constexpr const u8 UP = 0x80;
|
||||||
static constexpr const u8 DOWN = 0x81;
|
static constexpr const u8 DOWN = 0x81;
|
||||||
static constexpr const u8 LEFT = 0x82;
|
static constexpr const u8 LEFT = 0x82;
|
||||||
static constexpr const u8 RIGHT = 0x83;
|
static constexpr const u8 RIGHT = 0x83;
|
||||||
static constexpr const u8 ENTER = 0x84;
|
static constexpr const u8 ENTER = 0x84;
|
||||||
static constexpr const u8 ESC = 0x85;
|
static constexpr const u8 ESC = 0x85;
|
||||||
static constexpr const u8 BACKSPACE = 0x86;
|
static constexpr const u8 BACKSPACE = 0x86;
|
||||||
static constexpr const u8 UNKNOWN = 0xFF;
|
static constexpr const u8 UNKNOWN = 0xFF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Terminal();
|
Terminal();
|
||||||
|
|
||||||
~Terminal();
|
~Terminal();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a style
|
* Sets a style
|
||||||
*/
|
*/
|
||||||
Terminal& style(const std::string_view code);
|
Terminal& style(const std::string_view code);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills the screen with a specific background color.
|
* Fills the screen with a specific background color.
|
||||||
* @param color The background color constant (e.g., Terminal::BG_BLUE)
|
* @param color The background color constant (e.g., Terminal::BG_BLUE)
|
||||||
*/
|
*/
|
||||||
Terminal& fill(const std::string_view color);
|
Terminal& fill(const std::string_view color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the cursor.
|
* Moves the cursor.
|
||||||
*/
|
*/
|
||||||
Terminal& move(i32 row, i32 col);
|
Terminal& move(i32 row, i32 col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the screen
|
* Clears the screen
|
||||||
*/
|
*/
|
||||||
Terminal& cls();
|
Terminal& cls();
|
||||||
|
|
||||||
Terminal& altbuff(bool enable);
|
Terminal& altbuff(bool enable);
|
||||||
|
|
||||||
Terminal& scrollRange(i32 start, i32 end);
|
Terminal& scrollRange(i32 start, i32 end);
|
||||||
|
|
||||||
Terminal& undoSRange();
|
Terminal& undoSRange();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears a specific row.
|
* Clears a specific row.
|
||||||
* @param row The 1-based index of the row to clear.
|
* @param row The 1-based index of the row to clear.
|
||||||
*/
|
*/
|
||||||
Terminal& clearRow(i32 row);
|
Terminal& clearRow(i32 row);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears a range of rows (inclusive).
|
* Clears a range of rows (inclusive).
|
||||||
* @param start The first row.
|
* @param start The first row.
|
||||||
* @param end The last row.
|
* @param end The last row.
|
||||||
*/
|
*/
|
||||||
Terminal& clearRows(i32 start, i32 end);
|
Terminal& clearRows(i32 start, i32 end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows / Hides the cursor.
|
* Shows / Hides the cursor.
|
||||||
*/
|
*/
|
||||||
Terminal& cursor(bool show);
|
Terminal& cursor(bool show);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title);
|
Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flushes the output buffer
|
* Flushes the output buffer
|
||||||
*/
|
*/
|
||||||
Terminal& flush();
|
Terminal& flush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the input buffer.
|
* Clears the input buffer.
|
||||||
* Useful for some specific input cases
|
* Useful for some specific input cases
|
||||||
*/
|
*/
|
||||||
Terminal& sink();
|
Terminal& sink();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Terminal& wait();
|
Terminal& wait();
|
||||||
|
|
||||||
u8 getKey();
|
u8 getKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get key non blocking
|
* Get key non blocking
|
||||||
*/
|
*/
|
||||||
u8 getKeyNb();
|
u8 getKeyNb();
|
||||||
|
|
||||||
std::pair<i32, i32> getSize();
|
std::pair<i32, i32> getSize();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Terminal& print(const T& msg) {
|
Terminal& print(const T& msg) {
|
||||||
std::cout << msg;
|
std::cout << msg;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Terminal& println(const T& msg) {
|
Terminal& println(const T& msg) {
|
||||||
std::cout << msg << "\n";
|
std::cout << msg << "\n";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Terminal& print_center(i32 width, const T& msg) {
|
Terminal& print_center(i32 width, const T& msg) {
|
||||||
// to string
|
// to string
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << msg;
|
oss << msg;
|
||||||
std::string s = oss.str();
|
std::string s = oss.str();
|
||||||
|
|
||||||
// then print
|
// then print
|
||||||
if (s.length() >= isize(width)) {
|
if (s.length() >= isize(width)) {
|
||||||
std::cout << s;
|
std::cout << s;
|
||||||
} else {
|
} else {
|
||||||
i32 total_padding = width - s.length();
|
i32 total_padding = width - s.length();
|
||||||
i32 left_padding = total_padding / 2;
|
i32 left_padding = total_padding / 2;
|
||||||
std::cout << std::string(left_padding, ' ');
|
std::cout << std::string(left_padding, ' ');
|
||||||
std::cout << s;
|
std::cout << s;
|
||||||
std::cout << std::string(total_padding - left_padding, ' ');
|
std::cout << std::string(total_padding - left_padding, ' ');
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Terminal& read(T& var) {
|
Terminal& read(T& var) {
|
||||||
std::cin >> var;
|
std::cin >> var;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user