add ESP32 build system with xtensa-esp-elf toolchain
This commit is contained in:
+6
-6
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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!")
|
||||||
Binary file not shown.
@@ -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
|
||||||
+471
-471
@@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+111
-111
@@ -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() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+781
-781
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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+130
-130
@@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
+250
-250
@@ -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