add ESP32 build system with xtensa-esp-elf toolchain

This commit is contained in:
2026-03-25 15:23:41 -06:00
parent 4a659b5f0d
commit 680a2fdb06
50 changed files with 4219 additions and 4091 deletions

View File

@@ -1,16 +1,16 @@
#include "SpiderRuntime.hpp"
#include <spider/runtime/debug/LiveDebug.hpp>
#include <iostream>
namespace spider {
}
int main() {
spider::liveDebugMain();
return 0;
}
#include "SpiderRuntime.hpp"
#include <spider/runtime/debug/LiveDebug.hpp>
#include <iostream>
namespace spider {
}
int main() {
spider::liveDebugMain();
return 0;
}

View File

@@ -1,12 +1,12 @@
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
class Runtime;
class CPU;
class RAM;
class InstrReel;
}
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
class Runtime;
class CPU;
class RAM;
class InstrReel;
}

View File

@@ -0,0 +1,8 @@
// ESP32 entry point for Spider Runtime
// This replaces SpiderRuntime.cpp for microcontroller builds
#include "SpiderRuntime.hpp"
int main() {
// TODO: initialize Spider runtime for ESP32
return 0;
}

View File

@@ -1,29 +1,29 @@
#include "Runtime.hpp"
namespace spider {
// Constructors & Destructors //
Runtime::Runtime() : ram(0) {}
Runtime::Runtime(u64 ramSize) : ram(ramSize) {}
Runtime::~Runtime() {}
// Stepping/Running the Machine //
void Runtime::step() {}
void Runtime::step(u64 n) {}
void Runtime::run() {}
void Runtime::run(u64 n) {}
// Misc //
void Runtime::resizeRAM(u64 length) {
ram.resize(length);
}
}
#include "Runtime.hpp"
namespace spider {
// Constructors & Destructors //
Runtime::Runtime() : ram(0) {}
Runtime::Runtime(u64 ramSize) : ram(ramSize) {}
Runtime::~Runtime() {}
// Stepping/Running the Machine //
void Runtime::step() {}
void Runtime::step(u64 n) {}
void Runtime::run() {}
void Runtime::run(u64 n) {}
// Misc //
void Runtime::resizeRAM(u64 length) {
ram.resize(length);
}
}

View File

@@ -1,73 +1,73 @@
#pragma once
#include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/RAM.hpp>
namespace spider {
/**
* The main runtime class.
* This is where the Spider VM (Runtime) lives
*/
class Runtime {
public:
CPU cpu;
RAM ram;
public:
/**
* Creates a new runtime, with no memory.
*/
Runtime();
/**
* Creates a new runtime, with a specific
* amount of memory.
*/
Runtime(u64 ramSize);
/**
* Runtime Destructor.
*/
~Runtime();
public:
/**
* Steps the clock of the VM once.
*/
void step();
/**
* Steps n-times the clock of the VM.
*/
void step(u64 n);
public:
/**
* Sets the machine to run continously.
* If interrupts occur, they will be handled
* automatically.
*/
void run();
/**
* Runs this machine for a set amount of
* milliseconds.
*/
void run(u64 ms);
public:
/**
* Resizes the ram, which will preserve
* data inside the next length.
*/
void resizeRAM(u64 length);
};
}
#pragma once
#include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/RAM.hpp>
namespace spider {
/**
* The main runtime class.
* This is where the Spider VM (Runtime) lives
*/
class Runtime {
public:
CPU cpu;
RAM ram;
public:
/**
* Creates a new runtime, with no memory.
*/
Runtime();
/**
* Creates a new runtime, with a specific
* amount of memory.
*/
Runtime(u64 ramSize);
/**
* Runtime Destructor.
*/
~Runtime();
public:
/**
* Steps the clock of the VM once.
*/
void step();
/**
* Steps n-times the clock of the VM.
*/
void step(u64 n);
public:
/**
* Sets the machine to run continously.
* If interrupts occur, they will be handled
* automatically.
*/
void run();
/**
* Runs this machine for a set amount of
* milliseconds.
*/
void run(u64 ms);
public:
/**
* Resizes the ram, which will preserve
* data inside the next length.
*/
void resizeRAM(u64 length);
};
}

View File

@@ -1,38 +1,38 @@
#pragma once
#include <cstdint>
#include <vector>
#include <deque>
#include <map>
#include <optional>
namespace spider {
// Absolute Types
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using f32 = float; // TODO: SPIDER_EMULATE_FLOAT will control this
using f64 = double;
// TODO: Check if we're on C++23, there is already stdfloat
static_assert(sizeof(f32) == 4, "The f32 type must be exactly 4 bytes.");
static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes.");
// Utility types
using isize = std::size_t;
// Utility imports
using std::vector;
using std::deque;
using std::map;
using std::optional;
}
#pragma once
#include <cstdint>
#include <vector>
#include <deque>
#include <map>
#include <optional>
namespace spider {
// Absolute Types
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using f32 = float; // TODO: SPIDER_EMULATE_FLOAT will control this
using f64 = double;
// TODO: Check if we're on C++23, there is already stdfloat
static_assert(sizeof(f32) == 4, "The f32 type must be exactly 4 bytes.");
static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes.");
// Utility types
using isize = std::size_t;
// Utility imports
using std::vector;
using std::deque;
using std::map;
using std::optional;
}

View File

@@ -1,111 +1,111 @@
#include "CPU.hpp"
#include <spider/runtime/native/machine.hpp>
#include <spider/runtime/memory/RAM.hpp>
#include <spider/runtime/reel/InstrReel.hpp>
#if __cplusplus >= 202002L
#include <bit>
#endif
namespace spider {
CPU::CPU()
: RA{}, RB{}, RC{}, RD{},
RX{}, RY{}, R0{}, R1{},
R2{}, R3{}, R4{}, R5{},
R6{}, R7{}, R8{}, R9{},
RF{}, RI{}, RS{}, RZ{},
RE{}, RN{}, RV{}, RM{},
ALU0{}, ALU1{},
_ram(nullptr), _reel(nullptr) {
}
CPU::~CPU() {}
// Setup & Configuration //
void CPU::hookRAM(RAM* ram) {
this->_ram = ram;
}
void CPU::hookInstrReel(InstrReel* reel) {
this->_reel = reel;
}
constexpr u64 CPU::getFlag(u64 mask) {
if (!mask) return 0;
#if __cplusplus >= 202002L
return (RF & mask) >> std::countr_zero(mask);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
return (RF & mask) >> __builtin_ctzll(mask);
#elif defined(SPIDER_COMPILER_MSVC)
return (RF & mask) >> _BitScanForward64(mask);
#else
// If you have reached this part,
// please come up with a better alternative.
u64 bits = RF & mask;
while (mask && (mask >>= 1)) bits >>= 1;
return bits;
#endif
}
// Addressing Modes //
/**
* Implied Addressing Mode
*/
void CPU::imp() {
// Nothing //
}
/**
* Immediate Addressing Mode
*/
void CPU::imm() {
u8 size = 2 << _size;
_next = &ALU0;
}
/**
* Absolute Addressing Mode
*/
void CPU::abs() {
u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE);
}
/**
* Register Addressing Mode
*/
void CPU::reg() {
sizeof(CPU);
}
/**
* Indrect Addressing Mode
*/
void CPU::ind() {}
/**
* Pointer Addressing Mode
*/
void CPU::ptr() {}
/**
* Indexed Addressing Mode
*/
void CPU::idx() {}
/**
* Scaled Addressing Mode
*/
void CPU::sca() {}
/**
* Displaced Addressing Mode
*/
void CPU::dis() {}
}
#include "CPU.hpp"
#include <spider/runtime/native/machine.hpp>
#include <spider/runtime/memory/RAM.hpp>
#include <spider/runtime/reel/InstrReel.hpp>
#if __cplusplus >= 202002L
#include <bit>
#endif
namespace spider {
CPU::CPU()
: RA{}, RB{}, RC{}, RD{},
RX{}, RY{}, R0{}, R1{},
R2{}, R3{}, R4{}, R5{},
R6{}, R7{}, R8{}, R9{},
RF{}, RI{}, RS{}, RZ{},
RE{}, RN{}, RV{}, RM{},
ALU0{}, ALU1{},
_ram(nullptr), _reel(nullptr) {
}
CPU::~CPU() {}
// Setup & Configuration //
void CPU::hookRAM(RAM* ram) {
this->_ram = ram;
}
void CPU::hookInstrReel(InstrReel* reel) {
this->_reel = reel;
}
constexpr u64 CPU::getFlag(u64 mask) {
if (!mask) return 0;
#if __cplusplus >= 202002L
return (RF & mask) >> std::countr_zero(mask);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
return (RF & mask) >> __builtin_ctzll(mask);
#elif defined(SPIDER_COMPILER_MSVC)
return (RF & mask) >> _BitScanForward64(mask);
#else
// If you have reached this part,
// please come up with a better alternative.
u64 bits = RF & mask;
while (mask && (mask >>= 1)) bits >>= 1;
return bits;
#endif
}
// Addressing Modes //
/**
* Implied Addressing Mode
*/
void CPU::imp() {
// Nothing //
}
/**
* Immediate Addressing Mode
*/
void CPU::imm() {
u8 size = 2 << _size;
_next = &ALU0;
}
/**
* Absolute Addressing Mode
*/
void CPU::abs() {
u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE);
}
/**
* Register Addressing Mode
*/
void CPU::reg() {
sizeof(CPU);
}
/**
* Indrect Addressing Mode
*/
void CPU::ind() {}
/**
* Pointer Addressing Mode
*/
void CPU::ptr() {}
/**
* Indexed Addressing Mode
*/
void CPU::idx() {}
/**
* Scaled Addressing Mode
*/
void CPU::sca() {}
/**
* Displaced Addressing Mode
*/
void CPU::dis() {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,81 +1,81 @@
#pragma once
#include <spider/runtime/common.hpp>
#include <spider/runtime/native/machine.hpp>
namespace spider {
/**
* A register is a tiny piece of memory.
* I hate adding a _t suffix but for some idiotic
* reason "register" is a keyword in C++.
*
* Note that we have to check the endianness of the system
* at compile time to order the structure so that smaller
* types are actually the bottom part of the memory.
*
* Also, this has to be done with a compiler that allows
* type-punning which is the "standard" right now.
*/
union register_t {
u64 _u64;
i64 _i64;
f64 _f64;
u8 _bytes[8];
struct {
#if SPIDER_LITTLE_ENDIAN
u8 _u8; // This looks like a cruel joke
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
#else
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
u8 _u8;
#endif
};
struct {
#if SPIDER_LITTLE_ENDIAN
u16 _u16;
u16 : 16; u16 : 16; u16 : 16;
#else
u16 : 16; u16 : 16; u16 : 16;
u16 _u16;
#endif
};
struct {
#if SPIDER_LITTLE_ENDIAN
u32 _u32; u32 : 32;
#else
u32 : 32; u32 _u32;
#endif
};
struct {
#if SPIDER_LITTLE_ENDIAN
f32 _f32; u32 : 32;
#else
u32 : 32; f32 _f32;
#endif
};
u8& operator[](size_t i) { // 0 is always LSB
#if SPIDER_LITTLE_ENDIAN
return _bytes[i];
#else
return _bytes[7 - i];
#endif
}
// ngl I could get executed for not having a const version
const u8& operator[](size_t i) const { // 0 is always LSB
#if SPIDER_LITTLE_ENDIAN
return _bytes[i];
#else
return _bytes[7 - i];
#endif
}
};
static_assert(sizeof(register_t) == 8, "The register type must be exactly 8 bytes.");
#pragma once
#include <spider/runtime/common.hpp>
#include <spider/runtime/native/machine.hpp>
namespace spider {
/**
* A register is a tiny piece of memory.
* I hate adding a _t suffix but for some idiotic
* reason "register" is a keyword in C++.
*
* Note that we have to check the endianness of the system
* at compile time to order the structure so that smaller
* types are actually the bottom part of the memory.
*
* Also, this has to be done with a compiler that allows
* type-punning which is the "standard" right now.
*/
union register_t {
u64 _u64;
i64 _i64;
f64 _f64;
u8 _bytes[8];
struct {
#if SPIDER_LITTLE_ENDIAN
u8 _u8; // This looks like a cruel joke
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
#else
u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8;
u8 _u8;
#endif
};
struct {
#if SPIDER_LITTLE_ENDIAN
u16 _u16;
u16 : 16; u16 : 16; u16 : 16;
#else
u16 : 16; u16 : 16; u16 : 16;
u16 _u16;
#endif
};
struct {
#if SPIDER_LITTLE_ENDIAN
u32 _u32; u32 : 32;
#else
u32 : 32; u32 _u32;
#endif
};
struct {
#if SPIDER_LITTLE_ENDIAN
f32 _f32; u32 : 32;
#else
u32 : 32; f32 _f32;
#endif
};
u8& operator[](size_t i) { // 0 is always LSB
#if SPIDER_LITTLE_ENDIAN
return _bytes[i];
#else
return _bytes[7 - i];
#endif
}
// ngl I could get executed for not having a const version
const u8& operator[](size_t i) const { // 0 is always LSB
#if SPIDER_LITTLE_ENDIAN
return _bytes[i];
#else
return _bytes[7 - i];
#endif
}
};
static_assert(sizeof(register_t) == 8, "The register type must be exactly 8 bytes.");
}

View File

@@ -1,386 +1,386 @@
#include "LiveDebug.hpp"
#include <spider/runtime/Runtime.hpp>
#include <spider/runtime/util/Terminal.hpp>
#include <spider/runtime/native/distro.hpp>
#include <vector>
#include <string>
#include <iomanip>
#include <iostream>
#include <chrono>
#include <format>
#include <thread>
namespace spider {
void drawHead(Terminal& t) {
t.move(1, 1)
.style(Terminal::FG_YELLOW)
.print(" Spider Runtime Live Debug ")
.style(Terminal::RESET).print(" | ")
.style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ")
.style(Terminal::RESET).print(" | ")
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
.style(Terminal::FG_BLACK)
.style(Terminal::BG_YELLOW)
.move(3, 1).print(" // __ \\\\").print(" ") // 27
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
.move(6, 1).print(" \\\\ // ").print(" ")
.style(Terminal::RESET)
.style(Terminal::FG_B_BLACK) // 4x8 for the menu
.move(3, 28).print("[ STEP ]")
.move(4, 28).print("[ STOP ]")
.move(5, 28).print("[ RUN ]")
.move(6, 28).print("[ MENU ]")
.style(Terminal::RESET)
;
}
void drawCPUTempl(Terminal& t, CPU& cpu) {
i32 r = 8, c = 1;
i32 w = 35, h = 31;
t.drawBox(r, c, w, h, "CPU");
const std::string regs[] = {
"RA", "RB", "RC", "RD",
"RX", "RY", "R0", "R1",
"R2", "R3", "R4", "R5",
"R6", "R7", "R8", "R9",
"RF", "RI", "RS", "RZ",
"RE", "RN", "RV", "RM",
"ALU0", "ALU1"
};
const std::string alt[] = {
Terminal::FG_WHITE,
Terminal::FG_B_BLACK,
};
r++;
c++;
t.move(r++, c);
t.style(Terminal::FG_B_YELLOW);
t.print_center(w - 2, "GP Registers");
t.style(Terminal::RESET);
for (i32 i = 0; i < 8; i++) {
t.style(alt[i & 1]);
t.move(r + i * 2, c);
t.print(regs[i * 2]);
t.move(r + i * 2, c + 17);
t.print(regs[i * 2 + 1]);
}
t.move(r += 16, c);
t.style(Terminal::FG_B_CYAN);
t.print_center(w - 2, "System Registers");
t.style(Terminal::RESET);
r++;
for (i32 j = 0, i = 8; i < 12; j++, i++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
t.print(regs[i * 2]);
t.move(r + j * 2, c + 17);
t.print(regs[i * 2 + 1]);
}
t.move(r += 8, c);
t.style(Terminal::FG_GREEN);
t.print_center(w - 2, "Extra Registers");
t.style(Terminal::RESET);
r++;
for (i32 j = 0, i = 12; i < 13; j++, i++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
t.print(regs[i * 2]);
t.move(r + j * 2, c + 17);
t.print(regs[i * 2 + 1]);
}
t.flush();
}
void printU64Hex(u64 n) {
std::ios state(nullptr);
state.copyfmt(std::cout);
std::cout
<< std::hex
<< std::uppercase
<< std::setfill('0')
<< std::setw(16)
<< n;
std::cout.copyfmt(state);
}
void drawCPU(Terminal& t, CPU& cpu) {
i32 r = 8, c = 1;
const register_t* regs[] = {
&cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD,
&cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1,
&cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5,
&cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9,
//&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
//&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
&cpu.ALU0, &cpu.ALU1
};
const u64* sys_regs[] = {
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
};
const std::string alt[] = {
Terminal::FG_WHITE,
Terminal::FG_B_BLACK,
};
r++;
c++;
t.move(r++, c);
t.style(Terminal::RESET);
r++;
for (i32 i = 0; i < 8; i++) {
t.style(alt[i & 1]);
t.move(r + i * 2, c);
printU64Hex(regs[i * 2]->_u64);
t.move(r + i * 2, c + 17);
printU64Hex(regs[i * 2 + 1]->_u64);
}
t.move(r += 16, c);
r++;
for (i32 j = 0, i = 8; i < 12; j++, i++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
printU64Hex(*sys_regs[i * 2]);
t.move(r + j * 2, c + 17);
printU64Hex(*sys_regs[i * 2 + 1]);
}
t.move(r += 8, c);
r++;
for (i32 j = 0; j < 1; j++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
printU64Hex(regs[16 + j * 2]->_u64);
t.move(r + j * 2, c + 17);
printU64Hex(regs[16 + j * 2 + 1]->_u64);
}
t.flush();
}
i32 addressWidth(isize ramSize) {
if (ramSize == 0) return 1;
isize maxAddr = ramSize - 1;
i32 digits = 0;
// Shift by increments of 4 (one hex nibble)
// We use a do-while to ensure at least 1 digit is returned for small RAMs
do {
digits++;
maxAddr >>= 4;
} while (maxAddr > 0);
return digits;
}
/**
* Draws a vertical scrollbar
* @param x The column where the bar should be placed (usually box_x + width - 1)
* @param y The starting row of the track (usually box_y + 1)
* @param trackHeight The internal height of the box (box_height - 2)
* @param progress The current progress
* @param total The total
*/
void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) {
if (total == 0 || trackHeight <= 0) return;
// 1. Draw the background track (Light Shade: ░)
term.style(Terminal::FG_B_BLACK); // Dim the track
for (int i = 0; i < trackHeight; ++i) {
term.move(y + i, x).print("");
}
// 2. Calculate Thumb Position
// Cap progress to total to avoid overflow
if (progress > total) progress = total;
// Calculate ratio (0.0 to 1.0)
f64 ratio = f64(progress) / f64(total);
// Map to track coordinates
i32 thumbOffset = i32(ratio * (trackHeight - 1));
// 3. Draw the Thumb (Full Block: █)
term.move(y + thumbOffset, x);
term.style(Terminal::FG_WHITE).print("");
term.style(Terminal::RESET);
}
/**
* Draws a hex dump of memory within a styled terminal box.
* @param term Reference to your Terminal instance
* @param ram The RAM
* @param scrollPos The starting address to display
* @param x Starting column
* @param y Starting row
* @param width Width of the box
* @param height Height of the box
*/
void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) {
// 1. Draw the container box
i32 y = 3;
i32 height = 36;
// 2. Configuration for the hex layout
int addrWidth = addressWidth(ram.size());
int bytesPerRow = 8;
int displayRows = height - 2; // Subtract top/bottom borders
i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth;
i32 x = 37;
// create box
term.drawBox(y, x, width, height, "RAM");
drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size());
// Ensure scrollPos is within bounds and aligned
if (scrollPos < 0) scrollPos = 0;
if (scrollPos > ram.size()) scrollPos = ram.size();
for (int i = 0; i < displayRows; ++i) {
isize currentRowAddr = scrollPos + (i * bytesPerRow);
// address lock
if (currentRowAddr >= ram.size()) {
term.move(y + 1 + i, x + 1);
term.print(std::string(width - 3, ' '));
continue;
}
std::stringstream ssaddr;
std::stringstream ss;
// setup ss
ssaddr << std::setfill('0') << std::uppercase << std::hex;
ss << std::setfill('0') << std::uppercase << std::hex;
// address
ssaddr << std::setw(addrWidth) << currentRowAddr << " ";
// Hex Bytes
std::string asciiPart = "";
for (int j = 0; j < bytesPerRow; ++j) {
isize targetAddr = currentRowAddr + j;
if (targetAddr >= ram.size()) {
ss << ""; // Padding for end of memory
asciiPart += "";
continue;
}
u8 byte = ram[targetAddr];
ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " ";
asciiPart += (std::isprint(byte) ? (char)byte : '.');
}
// --- Combine and Print ---
term.move(y + 1 + i, x + 2); // Move inside the box
term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan
term.style(Terminal::FG_WHITE).print(ss.str());
term.style(Terminal::FG_B_YELLOW).print(" | ");
term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White
}
term.style(Terminal::RESET);
term.flush();
}
std::string getTimestamp() {
std::time_t t = std::time(nullptr);
std::tm lt;
#if defined(SPIDER_OS_WINDOWS)
localtime_s(&lt, &t);
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
localtime_r(&t, &lt);
#endif
return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}",
lt.tm_hour, lt.tm_min, lt.tm_sec,
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
}
void drawTime(Terminal& t) {
//auto now = std::chrono::system_clock::now();
//auto now_l = std::chrono::current_zone()->to_local(now);
//auto now_s = std::chrono::floor<std::chrono::seconds>(now_l);
//std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss
//std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY
t.move(1, 76);
t.style(Terminal::RESET);
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
}
void redraw(Terminal& t, Runtime& r, u64 scroll) {
// draw CPU, RAM
drawCPU(t, r.cpu);
drawRAM(t, r.ram, scroll);
}
int liveDebugMain() {
Terminal t;
Runtime runtime(1024);
bool running = true, update = true;
u64 ramScroll = 0;
u8 key = Terminal::UNKNOWN;
t.println("Starting Spider live debug...");
t.altbuff(true).cursor(false);
drawTime(t);
drawHead(t);
drawCPUTempl(t, runtime.cpu);
// delay for time
auto last_exec = std::chrono::steady_clock::now();
auto delay = std::chrono::milliseconds(1000);
while (running) {
// draw time
auto now = std::chrono::steady_clock::now();
if (now - last_exec >= delay) {
drawTime(t);
last_exec = now;
}
// redraw something if it updated
if (update) {
redraw(t, runtime, ramScroll);
update = false;
}
// Handle Input
key = t.getKeyNb();
switch (key) {
case Terminal::ESC:
running = false;
break;
case Terminal::UP:
if (ramScroll >= 16) ramScroll -= 16;
update = true;
break;
case Terminal::DOWN:
if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16;
update = true;
break;
default:
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
t.altbuff(false).println("Stopped Spider live debug.").flush();
return 0;
}
}
#include "LiveDebug.hpp"
#include <spider/runtime/Runtime.hpp>
#include <spider/runtime/util/Terminal.hpp>
#include <spider/runtime/native/distro.hpp>
#include <vector>
#include <string>
#include <iomanip>
#include <iostream>
#include <chrono>
#include <format>
#include <thread>
namespace spider {
void drawHead(Terminal& t) {
t.move(1, 1)
.style(Terminal::FG_YELLOW)
.print(" Spider Runtime Live Debug ")
.style(Terminal::RESET).print(" | ")
.style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ")
.style(Terminal::RESET).print(" | ")
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
.style(Terminal::FG_BLACK)
.style(Terminal::BG_YELLOW)
.move(3, 1).print(" // __ \\\\").print(" ") // 27
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
.move(6, 1).print(" \\\\ // ").print(" ")
.style(Terminal::RESET)
.style(Terminal::FG_B_BLACK) // 4x8 for the menu
.move(3, 28).print("[ STEP ]")
.move(4, 28).print("[ STOP ]")
.move(5, 28).print("[ RUN ]")
.move(6, 28).print("[ MENU ]")
.style(Terminal::RESET)
;
}
void drawCPUTempl(Terminal& t, CPU& cpu) {
i32 r = 8, c = 1;
i32 w = 35, h = 31;
t.drawBox(r, c, w, h, "CPU");
const std::string regs[] = {
"RA", "RB", "RC", "RD",
"RX", "RY", "R0", "R1",
"R2", "R3", "R4", "R5",
"R6", "R7", "R8", "R9",
"RF", "RI", "RS", "RZ",
"RE", "RN", "RV", "RM",
"ALU0", "ALU1"
};
const std::string alt[] = {
Terminal::FG_WHITE,
Terminal::FG_B_BLACK,
};
r++;
c++;
t.move(r++, c);
t.style(Terminal::FG_B_YELLOW);
t.print_center(w - 2, "GP Registers");
t.style(Terminal::RESET);
for (i32 i = 0; i < 8; i++) {
t.style(alt[i & 1]);
t.move(r + i * 2, c);
t.print(regs[i * 2]);
t.move(r + i * 2, c + 17);
t.print(regs[i * 2 + 1]);
}
t.move(r += 16, c);
t.style(Terminal::FG_B_CYAN);
t.print_center(w - 2, "System Registers");
t.style(Terminal::RESET);
r++;
for (i32 j = 0, i = 8; i < 12; j++, i++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
t.print(regs[i * 2]);
t.move(r + j * 2, c + 17);
t.print(regs[i * 2 + 1]);
}
t.move(r += 8, c);
t.style(Terminal::FG_GREEN);
t.print_center(w - 2, "Extra Registers");
t.style(Terminal::RESET);
r++;
for (i32 j = 0, i = 12; i < 13; j++, i++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
t.print(regs[i * 2]);
t.move(r + j * 2, c + 17);
t.print(regs[i * 2 + 1]);
}
t.flush();
}
void printU64Hex(u64 n) {
std::ios state(nullptr);
state.copyfmt(std::cout);
std::cout
<< std::hex
<< std::uppercase
<< std::setfill('0')
<< std::setw(16)
<< n;
std::cout.copyfmt(state);
}
void drawCPU(Terminal& t, CPU& cpu) {
i32 r = 8, c = 1;
const register_t* regs[] = {
&cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD,
&cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1,
&cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5,
&cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9,
//&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
//&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
&cpu.ALU0, &cpu.ALU1
};
const u64* sys_regs[] = {
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
};
const std::string alt[] = {
Terminal::FG_WHITE,
Terminal::FG_B_BLACK,
};
r++;
c++;
t.move(r++, c);
t.style(Terminal::RESET);
r++;
for (i32 i = 0; i < 8; i++) {
t.style(alt[i & 1]);
t.move(r + i * 2, c);
printU64Hex(regs[i * 2]->_u64);
t.move(r + i * 2, c + 17);
printU64Hex(regs[i * 2 + 1]->_u64);
}
t.move(r += 16, c);
r++;
for (i32 j = 0, i = 8; i < 12; j++, i++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
printU64Hex(*sys_regs[i * 2]);
t.move(r + j * 2, c + 17);
printU64Hex(*sys_regs[i * 2 + 1]);
}
t.move(r += 8, c);
r++;
for (i32 j = 0; j < 1; j++) {
t.style(alt[j & 1]);
t.move(r + j * 2, c);
printU64Hex(regs[16 + j * 2]->_u64);
t.move(r + j * 2, c + 17);
printU64Hex(regs[16 + j * 2 + 1]->_u64);
}
t.flush();
}
i32 addressWidth(isize ramSize) {
if (ramSize == 0) return 1;
isize maxAddr = ramSize - 1;
i32 digits = 0;
// Shift by increments of 4 (one hex nibble)
// We use a do-while to ensure at least 1 digit is returned for small RAMs
do {
digits++;
maxAddr >>= 4;
} while (maxAddr > 0);
return digits;
}
/**
* Draws a vertical scrollbar
* @param x The column where the bar should be placed (usually box_x + width - 1)
* @param y The starting row of the track (usually box_y + 1)
* @param trackHeight The internal height of the box (box_height - 2)
* @param progress The current progress
* @param total The total
*/
void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) {
if (total == 0 || trackHeight <= 0) return;
// 1. Draw the background track (Light Shade: ░)
term.style(Terminal::FG_B_BLACK); // Dim the track
for (int i = 0; i < trackHeight; ++i) {
term.move(y + i, x).print("");
}
// 2. Calculate Thumb Position
// Cap progress to total to avoid overflow
if (progress > total) progress = total;
// Calculate ratio (0.0 to 1.0)
f64 ratio = f64(progress) / f64(total);
// Map to track coordinates
i32 thumbOffset = i32(ratio * (trackHeight - 1));
// 3. Draw the Thumb (Full Block: █)
term.move(y + thumbOffset, x);
term.style(Terminal::FG_WHITE).print("");
term.style(Terminal::RESET);
}
/**
* Draws a hex dump of memory within a styled terminal box.
* @param term Reference to your Terminal instance
* @param ram The RAM
* @param scrollPos The starting address to display
* @param x Starting column
* @param y Starting row
* @param width Width of the box
* @param height Height of the box
*/
void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) {
// 1. Draw the container box
i32 y = 3;
i32 height = 36;
// 2. Configuration for the hex layout
int addrWidth = addressWidth(ram.size());
int bytesPerRow = 8;
int displayRows = height - 2; // Subtract top/bottom borders
i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth;
i32 x = 37;
// create box
term.drawBox(y, x, width, height, "RAM");
drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size());
// Ensure scrollPos is within bounds and aligned
if (scrollPos < 0) scrollPos = 0;
if (scrollPos > ram.size()) scrollPos = ram.size();
for (int i = 0; i < displayRows; ++i) {
isize currentRowAddr = scrollPos + (i * bytesPerRow);
// address lock
if (currentRowAddr >= ram.size()) {
term.move(y + 1 + i, x + 1);
term.print(std::string(width - 3, ' '));
continue;
}
std::stringstream ssaddr;
std::stringstream ss;
// setup ss
ssaddr << std::setfill('0') << std::uppercase << std::hex;
ss << std::setfill('0') << std::uppercase << std::hex;
// address
ssaddr << std::setw(addrWidth) << currentRowAddr << " ";
// Hex Bytes
std::string asciiPart = "";
for (int j = 0; j < bytesPerRow; ++j) {
isize targetAddr = currentRowAddr + j;
if (targetAddr >= ram.size()) {
ss << ""; // Padding for end of memory
asciiPart += "";
continue;
}
u8 byte = ram[targetAddr];
ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " ";
asciiPart += (std::isprint(byte) ? (char)byte : '.');
}
// --- Combine and Print ---
term.move(y + 1 + i, x + 2); // Move inside the box
term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan
term.style(Terminal::FG_WHITE).print(ss.str());
term.style(Terminal::FG_B_YELLOW).print(" | ");
term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White
}
term.style(Terminal::RESET);
term.flush();
}
std::string getTimestamp() {
std::time_t t = std::time(nullptr);
std::tm lt;
#if defined(SPIDER_OS_WINDOWS)
localtime_s(&lt, &t);
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
localtime_r(&t, &lt);
#endif
return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}",
lt.tm_hour, lt.tm_min, lt.tm_sec,
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
}
void drawTime(Terminal& t) {
//auto now = std::chrono::system_clock::now();
//auto now_l = std::chrono::current_zone()->to_local(now);
//auto now_s = std::chrono::floor<std::chrono::seconds>(now_l);
//std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss
//std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY
t.move(1, 76);
t.style(Terminal::RESET);
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
}
void redraw(Terminal& t, Runtime& r, u64 scroll) {
// draw CPU, RAM
drawCPU(t, r.cpu);
drawRAM(t, r.ram, scroll);
}
int liveDebugMain() {
Terminal t;
Runtime runtime(1024);
bool running = true, update = true;
u64 ramScroll = 0;
u8 key = Terminal::UNKNOWN;
t.println("Starting Spider live debug...");
t.altbuff(true).cursor(false);
drawTime(t);
drawHead(t);
drawCPUTempl(t, runtime.cpu);
// delay for time
auto last_exec = std::chrono::steady_clock::now();
auto delay = std::chrono::milliseconds(1000);
while (running) {
// draw time
auto now = std::chrono::steady_clock::now();
if (now - last_exec >= delay) {
drawTime(t);
last_exec = now;
}
// redraw something if it updated
if (update) {
redraw(t, runtime, ramScroll);
update = false;
}
// Handle Input
key = t.getKeyNb();
switch (key) {
case Terminal::ESC:
running = false;
break;
case Terminal::UP:
if (ramScroll >= 16) ramScroll -= 16;
update = true;
break;
case Terminal::DOWN:
if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16;
update = true;
break;
default:
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
t.altbuff(false).println("Stopped Spider live debug.").flush();
return 0;
}
}

View File

@@ -1,7 +1,7 @@
#pragma once
namespace spider {
int liveDebugMain();
}
#pragma once
namespace spider {
int liveDebugMain();
}

View File

@@ -1,9 +1,9 @@
#include <spider/runtime/cpu/CPU.hpp>
namespace spider {
void CPU::NOP() {
// No Operation //
}
}
#include <spider/runtime/cpu/CPU.hpp>
namespace spider {
void CPU::NOP() {
// No Operation //
}
}

View File

@@ -1,22 +1,22 @@
#include "Quat.hpp"
#include <iostream>
namespace spider {
int quatMain() {
Quat<double> q1 = { 1.0f, 0.0f, 0.0f, 0.0f };
Quat<double> q2 = { 0.5f, 0.5f, 0.5f, 0.5f };
Quat<double> result = quat_multiply(q1, q2); // Returns the result!
std::cout << "Result: ("
<< result.w << ", "
<< result.x << ", "
<< result.y << ", "
<< result.z << ")" << std::endl;
return 0;
}
}
#include "Quat.hpp"
#include <iostream>
namespace spider {
int quatMain() {
Quat<double> q1 = { 1.0f, 0.0f, 0.0f, 0.0f };
Quat<double> q2 = { 0.5f, 0.5f, 0.5f, 0.5f };
Quat<double> result = quat_multiply(q1, q2); // Returns the result!
std::cout << "Result: ("
<< result.w << ", "
<< result.x << ", "
<< result.y << ", "
<< result.z << ")" << std::endl;
return 0;
}
}

View File

@@ -1,24 +1,24 @@
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
template<typename T>
struct Quat {
T w, x, y, z;
};
/**
* Multiplies two quaternions together.
*/
template<typename T> inline Quat<T> quat_multiply(Quat<T> A, Quat<T> B) {
return {
B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z,
B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y,
B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x,
B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w
};
}
}
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
template<typename T>
struct Quat {
T w, x, y, z;
};
/**
* Multiplies two quaternions together.
*/
template<typename T> inline Quat<T> quat_multiply(Quat<T> A, Quat<T> B) {
return {
B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z,
B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y,
B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x,
B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w
};
}
}

View File

@@ -1,74 +1,74 @@
#include "ByteArray.hpp"
#include <cstring>
namespace spider {
ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) {
if (_size > 0) {
_mem = new u8[_size];
std::memset(_mem, 0, _size);
}
}
ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) {
std::copy(other._mem, other._mem + _size, _mem);
}
ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) {
other._mem = nullptr;
other._size = 0;
}
ByteArray::~ByteArray() {
delete[] _mem;
}
ByteArray& ByteArray::operator=(const ByteArray& other) {
if (this == &other) return *this; // lock self
u8* new_mem = new u8[other._size];
std::copy(other._mem, other._mem + other._size, new_mem);
delete[] _mem;
_mem = new_mem;
_size = other._size;
return *this;
}
ByteArray& ByteArray::operator=(ByteArray&& other) noexcept {
if (this == &other) return *this; // lock self
delete[] _mem;
_mem = other._mem; // time to steal!
_size = other._size;
other._mem = nullptr; // leave as a husk
other._size = 0;
return *this;
}
u8& ByteArray::operator[](isize index) {
return _mem[index];
}
u8 ByteArray::operator[](isize index) const {
return _mem[index];
}
u8* ByteArray::data() {
return _mem;
}
const u8* ByteArray::data() const {
return _mem;
}
isize ByteArray::size() const {
return _size;
}
}
#include "ByteArray.hpp"
#include <cstring>
namespace spider {
ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) {
if (_size > 0) {
_mem = new u8[_size];
std::memset(_mem, 0, _size);
}
}
ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) {
std::copy(other._mem, other._mem + _size, _mem);
}
ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) {
other._mem = nullptr;
other._size = 0;
}
ByteArray::~ByteArray() {
delete[] _mem;
}
ByteArray& ByteArray::operator=(const ByteArray& other) {
if (this == &other) return *this; // lock self
u8* new_mem = new u8[other._size];
std::copy(other._mem, other._mem + other._size, new_mem);
delete[] _mem;
_mem = new_mem;
_size = other._size;
return *this;
}
ByteArray& ByteArray::operator=(ByteArray&& other) noexcept {
if (this == &other) return *this; // lock self
delete[] _mem;
_mem = other._mem; // time to steal!
_size = other._size;
other._mem = nullptr; // leave as a husk
other._size = 0;
return *this;
}
u8& ByteArray::operator[](isize index) {
return _mem[index];
}
u8 ByteArray::operator[](isize index) const {
return _mem[index];
}
u8* ByteArray::data() {
return _mem;
}
const u8* ByteArray::data() const {
return _mem;
}
isize ByteArray::size() const {
return _size;
}
}

View File

@@ -1,49 +1,49 @@
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
/**
* A general purpose byte array
* with RAII semantics.
*/
class ByteArray {
private:
u8* _mem;
isize _size;
public:
ByteArray(isize length);
ByteArray(const ByteArray& other);
ByteArray(ByteArray&& other) noexcept;
~ByteArray();
public:
ByteArray& operator=(const ByteArray& other);
ByteArray& operator=(ByteArray&& other) noexcept;
public:
u8& operator[](isize index);
u8 operator[](isize index) const;
public:
u8* data();
const u8* data() const;
isize size() const;
};
}
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
/**
* A general purpose byte array
* with RAII semantics.
*/
class ByteArray {
private:
u8* _mem;
isize _size;
public:
ByteArray(isize length);
ByteArray(const ByteArray& other);
ByteArray(ByteArray&& other) noexcept;
~ByteArray();
public:
ByteArray& operator=(const ByteArray& other);
ByteArray& operator=(ByteArray&& other) noexcept;
public:
u8& operator[](isize index);
u8 operator[](isize index) const;
public:
u8* data();
const u8* data() const;
isize size() const;
};
}

View File

@@ -1,130 +1,130 @@
#include "RAM.hpp"
#include <cstring>
namespace spider {
// Constructors & Destructors //
RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) {
if (_size > 0) {
_mem = new u8[_size];
std::memset(_mem, 0, _size);
}
}
RAM::RAM(const RAM& other) : _size(other._size), _oob(0) {
_mem = new u8[_size];
std::copy(other._mem, other._mem + _size, _mem);
}
RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) {
other._mem = nullptr;
other._size = 0;
}
RAM::~RAM() {
delete[] _mem;
}
// Assign Operators //
RAM& RAM::operator=(const RAM& other) {
if (this == &other) return *this; // lock self
u8* new_mem = new u8[other._size];
std::copy(other._mem, other._mem + other._size, new_mem);
delete[] _mem;
_mem = new_mem;
_size = other._size;
return *this;
}
RAM& RAM::operator=(RAM&& other) noexcept {
if (this == &other) return *this; // lock self
delete[] _mem;
_mem = other._mem; // time to steal!
_size = other._size;
other._mem = nullptr; // leave as a husk
other._size = 0;
return *this;
}
// Unsafe Access //
u8& RAM::operator[](u64 i) { return _mem[i]; }
u8 RAM::operator[](u64 i) const { return _mem[i]; }
// Managed Access //
u8& RAM::at(u64 i) {
return (i < _size) ? _mem[i] : _oob;
}
u8 RAM::at(u64 i) const {
return (i < _size) ? _mem[i] : _oob;
}
// Misc //
void RAM::resize(u64 new_size) {
// Special case 1
if (new_size == _size) return;
// Special case 2
if (new_size == 0) {
delete[] _mem;
_mem = nullptr;
_size = 0;
return;
}
// 1. Allocate the new block
u8* new_mem = new u8[new_size];
// 2. Zero-initialize
std::memset(new_mem, 0, new_size);
// 3. Preserve data
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
// 3.1 Previous size could be zero, where _mem would be null
if (_mem != nullptr) {
std::copy(_mem, _mem + bytes_to_copy, new_mem);
}
// 4. Swap and Clean up
delete[] _mem;
_mem = new_mem;
_size = new_size;
}
u64 RAM::size() const {
return _size;
}
u8* RAM::begin() {
return this->_mem;
}
u8* RAM::end() {
return this->_mem + this->_size;
}
const u8* RAM::begin() const {
return this->_mem;
}
const u8* RAM::end() const {
return this->_mem + this->_size;
}
}
#include "RAM.hpp"
#include <cstring>
namespace spider {
// Constructors & Destructors //
RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) {
if (_size > 0) {
_mem = new u8[_size];
std::memset(_mem, 0, _size);
}
}
RAM::RAM(const RAM& other) : _size(other._size), _oob(0) {
_mem = new u8[_size];
std::copy(other._mem, other._mem + _size, _mem);
}
RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) {
other._mem = nullptr;
other._size = 0;
}
RAM::~RAM() {
delete[] _mem;
}
// Assign Operators //
RAM& RAM::operator=(const RAM& other) {
if (this == &other) return *this; // lock self
u8* new_mem = new u8[other._size];
std::copy(other._mem, other._mem + other._size, new_mem);
delete[] _mem;
_mem = new_mem;
_size = other._size;
return *this;
}
RAM& RAM::operator=(RAM&& other) noexcept {
if (this == &other) return *this; // lock self
delete[] _mem;
_mem = other._mem; // time to steal!
_size = other._size;
other._mem = nullptr; // leave as a husk
other._size = 0;
return *this;
}
// Unsafe Access //
u8& RAM::operator[](u64 i) { return _mem[i]; }
u8 RAM::operator[](u64 i) const { return _mem[i]; }
// Managed Access //
u8& RAM::at(u64 i) {
return (i < _size) ? _mem[i] : _oob;
}
u8 RAM::at(u64 i) const {
return (i < _size) ? _mem[i] : _oob;
}
// Misc //
void RAM::resize(u64 new_size) {
// Special case 1
if (new_size == _size) return;
// Special case 2
if (new_size == 0) {
delete[] _mem;
_mem = nullptr;
_size = 0;
return;
}
// 1. Allocate the new block
u8* new_mem = new u8[new_size];
// 2. Zero-initialize
std::memset(new_mem, 0, new_size);
// 3. Preserve data
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
// 3.1 Previous size could be zero, where _mem would be null
if (_mem != nullptr) {
std::copy(_mem, _mem + bytes_to_copy, new_mem);
}
// 4. Swap and Clean up
delete[] _mem;
_mem = new_mem;
_size = new_size;
}
u64 RAM::size() const {
return _size;
}
u8* RAM::begin() {
return this->_mem;
}
u8* RAM::end() {
return this->_mem + this->_size;
}
const u8* RAM::begin() const {
return this->_mem;
}
const u8* RAM::end() const {
return this->_mem + this->_size;
}
}

View File

@@ -1,64 +1,64 @@
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
/**
* A memory container.
* As a reminder, the amount of RAM
* is designed by the host.
*/
class RAM {
private:
u8* _mem;
u64 _size;
u8 _oob; // Out of bounds reference
public:
RAM(u64 length);
RAM(const RAM& other);
RAM(RAM&& other) noexcept;
~RAM();
public:
RAM& operator=(const RAM& other);
RAM& operator=(RAM&& other) noexcept;
public: // Unsafe access
u8& operator[](u64 i);
u8 operator[](u64 i) const;
public: // managed access (oob = 0)
u8& at(u64 i);
u8 at(u64 i) const;
public:
void resize(u64 new_size);
u64 size() const;
public:
u8* begin();
u8* end();
const u8* begin() const;
const u8* end() const;
};
#pragma once
#include <spider/runtime/common.hpp>
namespace spider {
/**
* A memory container.
* As a reminder, the amount of RAM
* is designed by the host.
*/
class RAM {
private:
u8* _mem;
u64 _size;
u8 _oob; // Out of bounds reference
public:
RAM(u64 length);
RAM(const RAM& other);
RAM(RAM&& other) noexcept;
~RAM();
public:
RAM& operator=(const RAM& other);
RAM& operator=(RAM&& other) noexcept;
public: // Unsafe access
u8& operator[](u64 i);
u8 operator[](u64 i) const;
public: // managed access (oob = 0)
u8& at(u64 i);
u8 at(u64 i) const;
public:
void resize(u64 new_size);
u64 size() const;
public:
u8* begin();
u8* end();
const u8* begin() const;
const u8* end() const;
};
}

View File

@@ -1,250 +1,250 @@
#pragma once
#include <spider/runtime/common.hpp>
#include <spider/runtime/native/machine.hpp>
#if __cplusplus >= 202002L
#include <bit>
#endif
#if defined(SPIDER_COMPILER_MSVC)
#include <cstdlib>
#endif
#include <cstring>
namespace spider {
/*
* This file contains cross platform type juggling.
* Optimized for each case.
*
* General assumtions is that unsigned and signed
* integers are the exact same bit representation.
*
* Floats to and from integers is the focus when
* juggling.
*
* Additionally, provides help selecting a specific
* type from raw bytes.
*/
// Utilities //
#if __cplusplus >= 202002L
using std::bit_cast;
#else
template<typename To, typename From>
inline To bit_cast(const From& src) {
static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch");
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
#endif
template<typename T>
inline T byteswap(T v) {
static_assert(std::is_integral<T>::value, "byteswap requires integral type");
using U = std::make_unsigned_t<T>;
U u = static_cast<U>(v);
if constexpr (sizeof(T) == 1) {
return v;
} else if constexpr (sizeof(T) == 2) {
#if defined(SPIDER_COMPILER_MSVC)
u = _byteswap_ushort(u);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
u = __builtin_bswap16(u);
#else
u = (u >> 8) | (u << 8);
#endif
} else if constexpr (sizeof(T) == 4) {
#if defined(SPIDER_COMPILER_MSVC)
u = _byteswap_ulong(u);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
u = __builtin_bswap32(u);
#else
u =
((u & 0x000000FFu) << 24) |
((u & 0x0000FF00u) << 8) |
((u & 0x00FF0000u) >> 8) |
((u & 0xFF000000u) >> 24);
#endif
} else if constexpr (sizeof(T) == 8) {
#if defined(SPIDER_COMPILER_MSVC)
u = _byteswap_uint64(u);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
u = __builtin_bswap64(u);
#else
u =
((u & 0x00000000000000FFull) << 56) |
((u & 0x000000000000FF00ull) << 40) |
((u & 0x0000000000FF0000ull) << 24) |
((u & 0x00000000FF000000ull) << 8) |
((u & 0x000000FF00000000ull) >> 8) |
((u & 0x0000FF0000000000ull) >> 24) |
((u & 0x00FF000000000000ull) >> 40) |
((u & 0xFF00000000000000ull) >> 56);
#endif
} else {
// Generic fallback (rare: non 1/2/4/8-byte types)
U result = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8);
}
u = result;
}
return static_cast<T>(u);
}
// Store Big Endian //
template<typename T>
inline void storeBE(T n, u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
std::memcpy(bytes, &n, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
T tmp = byteswap(n);
std::memcpy(bytes, &tmp, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
for (size_t i = 0; i < sizeof(T); ++i) {
bytes[i] = static_cast<u8>(
(static_cast<std::make_unsigned_t<T>>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF
);
}
#endif
}
template<>
inline void storeBE<f32>(f32 n, u8* bytes) {
u32 tmp = bit_cast<u32>(n);
storeBE(tmp, bytes);
}
template<>
inline void storeBE<f64>(f64 n, u8* bytes) {
u64 tmp = bit_cast<u64>(n);
storeBE(tmp, bytes);
}
// Load Big Endian //
template<typename T>
inline void loadBE(T* n, const u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
std::memcpy(n, bytes, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
T tmp;
std::memcpy(&tmp, bytes, sizeof(T));
*n = byteswap(tmp);
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
using U = std::make_unsigned_t<T>;
U result = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= static_cast<U>(bytes[i]) << ((sizeof(T) - 1 - i) * 8);
}
*n = static_cast<T>(result);
#endif
}
template<>
inline void loadBE<f32>(f32* n, const u8* bytes) {
u32 tmp;
loadBE(&tmp, bytes);
*n = bit_cast<f32>(tmp);
}
template<>
inline void loadBE<f64>(f64* n, const u8* bytes) {
u64 tmp;
loadBE(&tmp, bytes);
*n = bit_cast<f64>(tmp);
}
// Store Little Endian //
template<typename T>
inline void storeLE(T n, u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
T tmp = byteswap(n);
std::memcpy(bytes, &tmp, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(bytes, &n, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
for (size_t i = 0; i < sizeof(T); ++i) {
bytes[i] = static_cast<u8>(
(static_cast<std::make_unsigned_t<T>>(n) >> (i * 8)) & 0xFF
);
}
#endif
}
template<>
inline void storeLE<f32>(f32 n, u8* bytes) {
u32 tmp = bit_cast<u32>(n);
storeLE(tmp, bytes);
}
template<>
inline void storeLE<f64>(f64 n, u8* bytes) {
u64 tmp = bit_cast<u64>(n);
storeLE(tmp, bytes);
}
// Load Little Endian //
template<typename T>
inline void loadLE(T* n, const u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
T tmp;
std::memcpy(&tmp, bytes, sizeof(T));
*n = byteswap(tmp);
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(n, bytes, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
using U = std::make_unsigned_t<T>;
U result = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= static_cast<U>(bytes[i]) << (i * 8);
}
*n = static_cast<T>(result);
#endif
}
template<>
inline void loadLE<f32>(f32* n, const u8* bytes) {
u32 tmp;
loadLE(&tmp, bytes);
*n = bit_cast<f32>(tmp);
}
template<>
inline void loadLE<f64>(f64* n, const u8* bytes) {
u64 tmp;
loadLE(&tmp, bytes);
*n = bit_cast<f64>(tmp);
}
}
#pragma once
#include <spider/runtime/common.hpp>
#include <spider/runtime/native/machine.hpp>
#if __cplusplus >= 202002L
#include <bit>
#endif
#if defined(SPIDER_COMPILER_MSVC)
#include <cstdlib>
#endif
#include <cstring>
namespace spider {
/*
* This file contains cross platform type juggling.
* Optimized for each case.
*
* General assumtions is that unsigned and signed
* integers are the exact same bit representation.
*
* Floats to and from integers is the focus when
* juggling.
*
* Additionally, provides help selecting a specific
* type from raw bytes.
*/
// Utilities //
#if __cplusplus >= 202002L
using std::bit_cast;
#else
template<typename To, typename From>
inline To bit_cast(const From& src) {
static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch");
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
#endif
template<typename T>
inline T byteswap(T v) {
static_assert(std::is_integral<T>::value, "byteswap requires integral type");
using U = std::make_unsigned_t<T>;
U u = static_cast<U>(v);
if constexpr (sizeof(T) == 1) {
return v;
} else if constexpr (sizeof(T) == 2) {
#if defined(SPIDER_COMPILER_MSVC)
u = _byteswap_ushort(u);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
u = __builtin_bswap16(u);
#else
u = (u >> 8) | (u << 8);
#endif
} else if constexpr (sizeof(T) == 4) {
#if defined(SPIDER_COMPILER_MSVC)
u = _byteswap_ulong(u);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
u = __builtin_bswap32(u);
#else
u =
((u & 0x000000FFu) << 24) |
((u & 0x0000FF00u) << 8) |
((u & 0x00FF0000u) >> 8) |
((u & 0xFF000000u) >> 24);
#endif
} else if constexpr (sizeof(T) == 8) {
#if defined(SPIDER_COMPILER_MSVC)
u = _byteswap_uint64(u);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
u = __builtin_bswap64(u);
#else
u =
((u & 0x00000000000000FFull) << 56) |
((u & 0x000000000000FF00ull) << 40) |
((u & 0x0000000000FF0000ull) << 24) |
((u & 0x00000000FF000000ull) << 8) |
((u & 0x000000FF00000000ull) >> 8) |
((u & 0x0000FF0000000000ull) >> 24) |
((u & 0x00FF000000000000ull) >> 40) |
((u & 0xFF00000000000000ull) >> 56);
#endif
} else {
// Generic fallback (rare: non 1/2/4/8-byte types)
U result = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8);
}
u = result;
}
return static_cast<T>(u);
}
// Store Big Endian //
template<typename T>
inline void storeBE(T n, u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
std::memcpy(bytes, &n, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
T tmp = byteswap(n);
std::memcpy(bytes, &tmp, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
for (size_t i = 0; i < sizeof(T); ++i) {
bytes[i] = static_cast<u8>(
(static_cast<std::make_unsigned_t<T>>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF
);
}
#endif
}
template<>
inline void storeBE<f32>(f32 n, u8* bytes) {
u32 tmp = bit_cast<u32>(n);
storeBE(tmp, bytes);
}
template<>
inline void storeBE<f64>(f64 n, u8* bytes) {
u64 tmp = bit_cast<u64>(n);
storeBE(tmp, bytes);
}
// Load Big Endian //
template<typename T>
inline void loadBE(T* n, const u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
std::memcpy(n, bytes, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
T tmp;
std::memcpy(&tmp, bytes, sizeof(T));
*n = byteswap(tmp);
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
using U = std::make_unsigned_t<T>;
U result = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= static_cast<U>(bytes[i]) << ((sizeof(T) - 1 - i) * 8);
}
*n = static_cast<T>(result);
#endif
}
template<>
inline void loadBE<f32>(f32* n, const u8* bytes) {
u32 tmp;
loadBE(&tmp, bytes);
*n = bit_cast<f32>(tmp);
}
template<>
inline void loadBE<f64>(f64* n, const u8* bytes) {
u64 tmp;
loadBE(&tmp, bytes);
*n = bit_cast<f64>(tmp);
}
// Store Little Endian //
template<typename T>
inline void storeLE(T n, u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
T tmp = byteswap(n);
std::memcpy(bytes, &tmp, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(bytes, &n, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
for (size_t i = 0; i < sizeof(T); ++i) {
bytes[i] = static_cast<u8>(
(static_cast<std::make_unsigned_t<T>>(n) >> (i * 8)) & 0xFF
);
}
#endif
}
template<>
inline void storeLE<f32>(f32 n, u8* bytes) {
u32 tmp = bit_cast<u32>(n);
storeLE(tmp, bytes);
}
template<>
inline void storeLE<f64>(f64 n, u8* bytes) {
u64 tmp = bit_cast<u64>(n);
storeLE(tmp, bytes);
}
// Load Little Endian //
template<typename T>
inline void loadLE(T* n, const u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
T tmp;
std::memcpy(&tmp, bytes, sizeof(T));
*n = byteswap(tmp);
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(n, bytes, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
using U = std::make_unsigned_t<T>;
U result = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= static_cast<U>(bytes[i]) << (i * 8);
}
*n = static_cast<T>(result);
#endif
}
template<>
inline void loadLE<f32>(f32* n, const u8* bytes) {
u32 tmp;
loadLE(&tmp, bytes);
*n = bit_cast<f32>(tmp);
}
template<>
inline void loadLE<f64>(f64* n, const u8* bytes) {
u64 tmp;
loadLE(&tmp, bytes);
*n = bit_cast<f64>(tmp);
}
}

View File

@@ -99,7 +99,7 @@
#define SPIDER_NO_ICU
#endif
#if define(SPIDER_OS_NONE)
#if defined(SPIDER_OS_NONE)
#define SPIDER_OS_NAME "None"
#elif !defined(SPIDER_OS_MCU)
#error "[Spider Distro] Unsupported MCU OS"

View File

@@ -1,40 +1,40 @@
#pragma once
// ========================================================== //
// SPIDER DEFAULT SETTINGS, PER DISTRO //
// ========================================================== //
// ================== MEMORY FOOTPRINT ================== //
/**
* Use a normal amount of memory, assuming there
* is like 100KB free of it.
*/
#define SPIDER_MEMFOOTPRINT_NORMAL 0
/**
* Attempt to reduce the memory footprint
* where possible, but without doing
* extreme adaptations.
*/
#define SPIDER_MEMFOOTPRINT_REDUCED 1
/**
* Will deliverately convert things from memory
* to functions in order to free as much memory
* as possible, even if it slows things down.
*/
#define SPIDER_MEMFOOTPRINT_MINIMAL 2
#ifndef SPIDER_MEMFOOTPRINT
#if defined(SPIDER_DISTRO_MOBILE) || defined(SPIDER_DISTRO_BROWSER)
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_REDUCED
#elif defined(SPIDER_DISTRO_MICRO)
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_MINIMAL
#else
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_NORMAL
#endif
#endif
// ================== MISC ================== //
#pragma once
// ========================================================== //
// SPIDER DEFAULT SETTINGS, PER DISTRO //
// ========================================================== //
// ================== MEMORY FOOTPRINT ================== //
/**
* Use a normal amount of memory, assuming there
* is like 100KB free of it.
*/
#define SPIDER_MEMFOOTPRINT_NORMAL 0
/**
* Attempt to reduce the memory footprint
* where possible, but without doing
* extreme adaptations.
*/
#define SPIDER_MEMFOOTPRINT_REDUCED 1
/**
* Will deliverately convert things from memory
* to functions in order to free as much memory
* as possible, even if it slows things down.
*/
#define SPIDER_MEMFOOTPRINT_MINIMAL 2
#ifndef SPIDER_MEMFOOTPRINT
#if defined(SPIDER_DISTRO_MOBILE) || defined(SPIDER_DISTRO_BROWSER)
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_REDUCED
#elif defined(SPIDER_DISTRO_MICRO)
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_MINIMAL
#else
#define SPIDER_MEMFOOTPRINT SPIDER_MEMFOOTPRINT_NORMAL
#endif
#endif
// ================== MISC ================== //

View File

@@ -1,112 +1,112 @@
#pragma once
// ========================================================== //
// SPIDER MICROCONTROLLER AUTODETECT //
// ========================================================== //
// Automatically enable configurations for the microcontroller //
// so long as we can detect it or the user has already configured //
// the corresponding macros. //
#define SPIDER_MCU_FAM_GENERIC 0
#define SPIDER_MCU_FAM_AVR 1
#define SPIDER_MCU_FAM_ARM_CM 2
#define SPIDER_MCU_FAM_ARM_MBED 3
#define SPIDER_MCU_FAM_PIC 4
#define SPIDER_MCU_FAM_PIC32 5
#define SPIDER_MCU_FAM_ESP8266 6
#define SPIDER_MCU_FAM_ESP32 7
#define SPIDER_MCU_FAM_RISCV 8
#define SPIDER_MCU_FAM_RP2040 9
#if defined(SPIDER_MCU_AVR) || defined(__avr__) || defined(__AVR__)
// ========================================================== //
// AVR (Atmel / Microchip) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_AVR
#define SPIDER_MCU_NAME "AVR"
#elif defined(SPIDER_MCU_ARM) || defined(__arm__) || defined(__ARM_ARCH) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6M__)
// ========================================================== //
// ARM Cortex-M (most STM32, nRF, etc.) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_CM
#define SPIDER_MCU_NAME "ARM Cortex-M"
#elif defined(SPIDER_MCU_MBED) || defined(TARGET_LIKE_MBED)
// ========================================================== //
// Mbed OS special detection //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_MBED
#define SPIDER_MCU_NAME "ARM MBED"
#define SPIDER_OS_NAME "MBED OS"
#elif defined(SPIDER_MCU_PIC8) || defined(__XC) && (defined(_PIC14) || defined(_PIC16))
// ========================================================== //
// PIC (8-bit) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC
#define SPIDER_MCU_NAME "PIC (8-bit)"
#elif defined(SPIDER_MCU_PIC32) || defined(__XC32__)
// ========================================================== //
// PIC32 (MIPS) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC32
#define SPIDER_MCU_NAME "PIC (32-bit)"
#elif defined(SPIDER_MCU_ESP8266) || defined(ESP8266)
// ========================================================== //
// ESP8266 //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP8266
#define SPIDER_MCU_NAME "ESP-8266"
#elif defined(SPIDER_MCU_ESP32) || defined(ESP32)
// ========================================================== //
// ESP32 //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP32
#define SPIDER_MCU_NAME "ESP-32"
#elif defined(SPIDER_MCU_PICO) || defined(PICO_PLATFORM) || defined(PICO_BOARD) || defined(RP2040) || defined(__RP2040__)
// ========================================================== //
// Raspberry Pi Pico (RP2040) //
// ========================================================== //
#define SPIDER_MCU_FAM_FAMILY SPIDER_MCU_FAM_RP2040
#define SPIDER_MCU_NAME "ESP-32"
#elif defined(SPIDER_MCU_RISCV) || defined(__riscv) || defined(__riscv__)
// ========================================================== //
// RISC-V MCUs //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_RISCV
#define SPIDER_MCU_NAME "RISC-V MCU"
#elif defined(SPIDER_MCU_GENERIC)
// ========================================================== //
// GENERIC MICRO //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_GENERIC
#define SPIDER_MCU_NAME "Generic MCU"
#endif
#ifdef SPIDER_MCU_FAMILY
#ifndef SPIDER_DISTRO_MICRO
#define SPIDER_DISTRO_MICRO
#endif
// If SPIDER_OS_NAME was already defined, implies the SPIDER_MCU_FAM has an OS
#if defined(SPIDER_OS_NAME) && !defined(SPIDER_OS_MCU)
#define SPIDER_OS_MCU
#endif
// If no SPIDER_MCU_FAM OS defined, then it is NONE
#ifndef SPIDER_OS_MCU
#define SPIDER_OS_NONE
#endif
#elif defined(SPIDER_DISTRO_MICRO)
#error "[Spider Distro] Unsupported SPIDER_MCU_FAM. Define SPIDER_MCU_GENERIC and see if works."
#endif
#pragma once
// ========================================================== //
// SPIDER MICROCONTROLLER AUTODETECT //
// ========================================================== //
// Automatically enable configurations for the microcontroller //
// so long as we can detect it or the user has already configured //
// the corresponding macros. //
#define SPIDER_MCU_FAM_GENERIC 0
#define SPIDER_MCU_FAM_AVR 1
#define SPIDER_MCU_FAM_ARM_CM 2
#define SPIDER_MCU_FAM_ARM_MBED 3
#define SPIDER_MCU_FAM_PIC 4
#define SPIDER_MCU_FAM_PIC32 5
#define SPIDER_MCU_FAM_ESP8266 6
#define SPIDER_MCU_FAM_ESP32 7
#define SPIDER_MCU_FAM_RISCV 8
#define SPIDER_MCU_FAM_RP2040 9
#if defined(SPIDER_MCU_AVR) || defined(__avr__) || defined(__AVR__)
// ========================================================== //
// AVR (Atmel / Microchip) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_AVR
#define SPIDER_MCU_NAME "AVR"
#elif defined(SPIDER_MCU_ARM) || defined(__arm__) || defined(__ARM_ARCH) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6M__)
// ========================================================== //
// ARM Cortex-M (most STM32, nRF, etc.) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_CM
#define SPIDER_MCU_NAME "ARM Cortex-M"
#elif defined(SPIDER_MCU_MBED) || defined(TARGET_LIKE_MBED)
// ========================================================== //
// Mbed OS special detection //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ARM_MBED
#define SPIDER_MCU_NAME "ARM MBED"
#define SPIDER_OS_NAME "MBED OS"
#elif defined(SPIDER_MCU_PIC8) || defined(__XC) && (defined(_PIC14) || defined(_PIC16))
// ========================================================== //
// PIC (8-bit) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC
#define SPIDER_MCU_NAME "PIC (8-bit)"
#elif defined(SPIDER_MCU_PIC32) || defined(__XC32__)
// ========================================================== //
// PIC32 (MIPS) //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_PIC32
#define SPIDER_MCU_NAME "PIC (32-bit)"
#elif defined(SPIDER_MCU_ESP8266) || defined(ESP8266)
// ========================================================== //
// ESP8266 //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP8266
#define SPIDER_MCU_NAME "ESP-8266"
#elif defined(SPIDER_MCU_ESP32) || defined(ESP32)
// ========================================================== //
// ESP32 //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_ESP32
#define SPIDER_MCU_NAME "ESP-32"
#elif defined(SPIDER_MCU_PICO) || defined(PICO_PLATFORM) || defined(PICO_BOARD) || defined(RP2040) || defined(__RP2040__)
// ========================================================== //
// Raspberry Pi Pico (RP2040) //
// ========================================================== //
#define SPIDER_MCU_FAM_FAMILY SPIDER_MCU_FAM_RP2040
#define SPIDER_MCU_NAME "ESP-32"
#elif defined(SPIDER_MCU_RISCV) || defined(__riscv) || defined(__riscv__)
// ========================================================== //
// RISC-V MCUs //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_RISCV
#define SPIDER_MCU_NAME "RISC-V MCU"
#elif defined(SPIDER_MCU_GENERIC)
// ========================================================== //
// GENERIC MICRO //
// ========================================================== //
#define SPIDER_MCU_FAMILY SPIDER_MCU_FAM_GENERIC
#define SPIDER_MCU_NAME "Generic MCU"
#endif
#ifdef SPIDER_MCU_FAMILY
#ifndef SPIDER_DISTRO_MICRO
#define SPIDER_DISTRO_MICRO
#endif
// If SPIDER_OS_NAME was already defined, implies the SPIDER_MCU_FAM has an OS
#if defined(SPIDER_OS_NAME) && !defined(SPIDER_OS_MCU)
#define SPIDER_OS_MCU
#endif
// If no SPIDER_MCU_FAM OS defined, then it is NONE
#ifndef SPIDER_OS_MCU
#define SPIDER_OS_NONE
#endif
#elif defined(SPIDER_DISTRO_MICRO)
#error "[Spider Distro] Unsupported SPIDER_MCU_FAM. Define SPIDER_MCU_GENERIC and see if works."
#endif

View File

@@ -1,93 +1,93 @@
#pragma once
/*
* This file contains macros related to machine dependent
* things like alignment and type juggling
*/
// ========================================================== //
// ENDIANNESS //
// ========================================================== //
// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
#define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
// Fallbacks (For older/constrained compilers)
#else
#if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#elif defined(__wasm__) || defined(__wasm32__) // WebAssembly
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#elif defined(__arm__) || defined(__thumb__) // RP2040, STM32, etc.
#if defined(__ARMEB__)
#define SPIDER_LITTLE_ENDIAN 0
#define SPIDER_BIG_ENDIAN 1
#else
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#endif
#elif defined(__xtensa__) || defined(__ESP32__) // ESP32
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
// Likely will never use this clause
// ...but keeps compatibility with the one (1)
// guy who uses MSVC.
#elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64)
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#else
#error "[Spider Machine] Unsupported or unknown architecture endianness!"
#endif
#endif
// Safety checks
#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN)
#error "[Spider Machine] Missed at least one little/big endian macros"
#endif
#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1
#warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!"
#endif
// ========================================================== //
// PACKING //
// (not used now) //
// ========================================================== //
// Find out what compiler the user is using
#if defined(__clang__)
#define SPIDER_COMPILER_CLANG
#define SPIDER_COMPILER_GCC_LIKE
#elif defined(__GNUC__)
#define SPIDER_COMPILER_GCC
#define SPIDER_COMPILER_GCC_LIKE
#elif defined(_MSC_VER)
#define SPIDER_COMPILER_MSVC
#else
#define SPIDER_COMPILER_UNKNOWN
#endif
// Macros...
#if defined(SPIDER_COMPILER_GCC_LIKE)
#define SPIDER_PACK_BEGIN
#define SPIDER_PACK_END
#define SPIDER_PACK_STRUCT __attribute__((packed))
#elif defined(SPIDER_COMPILER_MSVC)
#define SPIDER_BEGIN_PACKED __pragma(pack(push, 1))
#define SPIDER_END_PACKED __pragma(pack(pop))
#define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED
#else
#define SPIDER_ATTRIBUTE_PACKED
#define SPIDER_BEGIN_PACKED
#define SPIDER_END_PACKED
#define SPIDER_PACKED_STRUCT(decl) decl
#warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!"
#endif
namespace spider {}
#pragma once
/*
* This file contains macros related to machine dependent
* things like alignment and type juggling
*/
// ========================================================== //
// ENDIANNESS //
// ========================================================== //
// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
#define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
// Fallbacks (For older/constrained compilers)
#else
#if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#elif defined(__wasm__) || defined(__wasm32__) // WebAssembly
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#elif defined(__arm__) || defined(__thumb__) // RP2040, STM32, etc.
#if defined(__ARMEB__)
#define SPIDER_LITTLE_ENDIAN 0
#define SPIDER_BIG_ENDIAN 1
#else
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#endif
#elif defined(__xtensa__) || defined(__ESP32__) // ESP32
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
// Likely will never use this clause
// ...but keeps compatibility with the one (1)
// guy who uses MSVC.
#elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64)
#define SPIDER_LITTLE_ENDIAN 1
#define SPIDER_BIG_ENDIAN 0
#else
#error "[Spider Machine] Unsupported or unknown architecture endianness!"
#endif
#endif
// Safety checks
#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN)
#error "[Spider Machine] Missed at least one little/big endian macros"
#endif
#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1
#warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!"
#endif
// ========================================================== //
// PACKING //
// (not used now) //
// ========================================================== //
// Find out what compiler the user is using
#if defined(__clang__)
#define SPIDER_COMPILER_CLANG
#define SPIDER_COMPILER_GCC_LIKE
#elif defined(__GNUC__)
#define SPIDER_COMPILER_GCC
#define SPIDER_COMPILER_GCC_LIKE
#elif defined(_MSC_VER)
#define SPIDER_COMPILER_MSVC
#else
#define SPIDER_COMPILER_UNKNOWN
#endif
// Macros...
#if defined(SPIDER_COMPILER_GCC_LIKE)
#define SPIDER_PACK_BEGIN
#define SPIDER_PACK_END
#define SPIDER_PACK_STRUCT __attribute__((packed))
#elif defined(SPIDER_COMPILER_MSVC)
#define SPIDER_BEGIN_PACKED __pragma(pack(push, 1))
#define SPIDER_END_PACKED __pragma(pack(pop))
#define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED
#else
#define SPIDER_ATTRIBUTE_PACKED
#define SPIDER_BEGIN_PACKED
#define SPIDER_END_PACKED
#define SPIDER_PACKED_STRUCT(decl) decl
#warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!"
#endif
namespace spider {}

View File

@@ -1,77 +1,77 @@
#include "InstrReel.hpp"
#include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/Types.hpp>
namespace spider {
// Public Interface //
InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {}
InstrReel::~InstrReel() {}
// Instruction abstraction //
u8 InstrReel::atU8(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 1 > _size) return 0;
// send byte
return _mem[ip];
}
u16 InstrReel::atU16(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 2 > _size) return 0;
// build a 16-bit big endian number
u16 dat;
spider::loadLE(&dat, _mem + ip_p);
return dat;
}
u32 InstrReel::atU32(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 4 > _size) return 0;
// build a 32-bit big endian number
u32 dat;
spider::loadLE(&dat, _mem + ip_p);
return dat;
}
u64 InstrReel::atU64(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 8 > _size) return 0;
// build a 64-bit big endian number
u64 dat;
spider::loadLE(&dat, _mem + ip_p);
return dat;
}
u64 InstrReel::size() {
return _total_size;
}
// Static Utils //
u16 InstrReel::unpackInstr(u16 bcode) {
return (bcode >> 5) & 0x1FF;
}
u8 InstrReel::unpackAddrMode(u16 bcode) {
return (bcode >> 2) & 0x1F;
}
u8 InstrReel::unpackTypeSize(u16 bcode) {
return bcode & 0x3;
}
}
#include "InstrReel.hpp"
#include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/Types.hpp>
namespace spider {
// Public Interface //
InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {}
InstrReel::~InstrReel() {}
// Instruction abstraction //
u8 InstrReel::atU8(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 1 > _size) return 0;
// send byte
return _mem[ip];
}
u16 InstrReel::atU16(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 2 > _size) return 0;
// build a 16-bit big endian number
u16 dat;
spider::loadLE(&dat, _mem + ip_p);
return dat;
}
u32 InstrReel::atU32(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 4 > _size) return 0;
// build a 32-bit big endian number
u32 dat;
spider::loadLE(&dat, _mem + ip_p);
return dat;
}
u64 InstrReel::atU64(u64 ip) {
// guard against access
u64 ip_p = ip - _offset;
if(ip_p + 8 > _size) return 0;
// build a 64-bit big endian number
u64 dat;
spider::loadLE(&dat, _mem + ip_p);
return dat;
}
u64 InstrReel::size() {
return _total_size;
}
// Static Utils //
u16 InstrReel::unpackInstr(u16 bcode) {
return (bcode >> 5) & 0x1FF;
}
u8 InstrReel::unpackAddrMode(u16 bcode) {
return (bcode >> 2) & 0x1F;
}
u8 InstrReel::unpackTypeSize(u16 bcode) {
return bcode & 0x3;
}
}

View File

@@ -1,74 +1,74 @@
#pragma once
#include <spider/SpiderRuntime.hpp>
#include <spider/runtime/memory/ByteArray.hpp>
namespace spider {
/**
* Implements an instruction reel.
*/
class InstrReel {
protected: // Current accessing range //
u8* _mem;
isize _size;
isize _offset;
isize _total_size;
public:
InstrReel();
virtual ~InstrReel();
public:
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u8 atU8(u64 ip);
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u16 atU16(u64 ip);
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u32 atU32(u64 ip);
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u64 atU64(u64 ip);
/**
* Current size of the instructions.
*/
virtual u64 size();
public: // Static Utils //
static u16 unpackInstr(u16 bcode);
static u8 unpackAddrMode(u16 bcode);
static u8 unpackTypeSize(u16 bcode);
};
}
#pragma once
#include <spider/SpiderRuntime.hpp>
#include <spider/runtime/memory/ByteArray.hpp>
namespace spider {
/**
* Implements an instruction reel.
*/
class InstrReel {
protected: // Current accessing range //
u8* _mem;
isize _size;
isize _offset;
isize _total_size;
public:
InstrReel();
virtual ~InstrReel();
public:
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u8 atU8(u64 ip);
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u16 atU16(u64 ip);
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u32 atU32(u64 ip);
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u64 atU64(u64 ip);
/**
* Current size of the instructions.
*/
virtual u64 size();
public: // Static Utils //
static u16 unpackInstr(u16 bcode);
static u8 unpackAddrMode(u16 bcode);
static u8 unpackTypeSize(u16 bcode);
};
}

View File

@@ -1,194 +1,194 @@
#include "InstrReelDyn.hpp"
#include <spider/runtime/memory/Types.hpp>
namespace spider {
InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) {
_total_size = length;
growToFit(length > 0 ? length - 1 : 0);
selectBlock(0);
}
InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {}
InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) : _use_count(copy._use_count), _block_index(copy._block_index), _blocks(copy._blocks) {
if (_block_index < _blocks.size()) selectBlock(_block_index);
}
InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept : _use_count(move._use_count), _block_index(move._block_index), _blocks(std::move(move._blocks)) {
if (_block_index < _blocks.size()) selectBlock(_block_index);
}
InstrReelDyn::~InstrReelDyn() {
// .. //
}
InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) {
_use_count = copy._use_count;
_block_index = copy._block_index;
_blocks = copy._blocks;
if (_block_index < _blocks.size()) selectBlock(_block_index);
return *this;
}
InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept {
_use_count = move._use_count;
_block_index = move._block_index;
_blocks = std::move(move._blocks);
if (_block_index < _blocks.size()) selectBlock(_block_index);
move._use_count = 0;
move._block_index = 0;
move._mem = nullptr;
move._offset = 0;
move._size = 0;
move._total_size = 0;
return *this;
}
void InstrReelDyn::growToFit(isize index) {
while (_blocks.size() < (index + 1)) {
_blocks.emplace_back();
}
}
isize InstrReelDyn::selectIndex(u64 ip) {
return ip / 256;
}
InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) {
// Update base class cache
auto ptr = &_blocks[index];
_offset = index * 256;
_mem = ptr->data;
_size = 256;
_block_index = index;
//_blocks[block_idx].access_count++;
return ptr;
}
u8 InstrReelDyn::atU8(u64 ip) {
isize j = selectIndex(ip);
if (j >= _blocks.size()) return 0;
if (j != _block_index) {
this->selectBlock(j);
}
return _mem[ip - _offset];
}
u16 InstrReelDyn::atU16(u64 ip) {
isize j0 = selectIndex(ip);
isize j1 = selectIndex(ip + 1);
if (j1 >= _blocks.size()) return 0;
if (j0 == j1 && j0 != _block_index) {
selectBlock(j0);
}
if (j0 == j1 && j0 == _block_index) {
u16 dat;
spider::loadLE(&dat, _mem);
return dat;
}
// general case, first part
u16 dat = 0;
const u8 size = sizeof(u16);
// select first block and offset
selectBlock(j0);
u8 rem = ip % 256;
for (u8 n = 0; n < size; n++) {
dat |= _mem[rem++] << (n * 8);
ip++;
if (!rem) selectBlock(++j0);
}
return dat;
}
u32 InstrReelDyn::atU32(u64 ip) {
isize j0 = selectIndex(ip);
isize j1 = selectIndex(ip + 3);
if (j1 >= _blocks.size()) return 0;
if (j0 == j1 && j0 != _block_index) {
selectBlock(j0);
}
if (j0 == j1 && j0 == _block_index) {
u32 dat;
spider::loadLE(&dat, _mem);
return dat;
}
// general case, first part
u32 dat = 0;
const u8 size = sizeof(u32);
// select first block and offset
selectBlock(j0);
u8 rem = ip % 256;
for (u8 n = 0; n < size; n++) {
dat |= _mem[rem++] << (n * 8);
ip++;
if (!rem) selectBlock(++j0);
}
return dat;
}
u64 InstrReelDyn::atU64(u64 ip) {
isize j0 = selectIndex(ip);
isize j1 = selectIndex(ip + 3);
if (j1 >= _blocks.size()) return 0;
if (j0 == j1 && j0 != _block_index) {
selectBlock(j0);
}
if (j0 == j1 && j0 == _block_index) {
u64 dat;
spider::loadLE(&dat, _mem);
return dat;
}
// general case, first part
u64 dat = 0;
const u8 size = sizeof(u64);
// select first block and offset
selectBlock(j0);
u8 rem = ip % 256;
for (u8 n = 0; n < size; n++) {
dat |= _mem[rem++] << (n * 8);
ip++;
if (!rem) selectBlock(++j0);
}
return dat;
}
void InstrReelDyn::at(u64 ip, u8 dat) {}
void InstrReelDyn::at(u64 ip, u16 dat) {}
void InstrReelDyn::at(u64 ip, u32 dat) {}
void InstrReelDyn::at(u64 ip, u64 dat) {}
/**
* Appends instruction at location.
*/
void InstrReelDyn::append(u64 ip, u16 bc) {}
/**
* Appends instruction at the end.
*/
void InstrReelDyn::append(u16 bc) {}
/**
* Removes instruction at location.
*/
void InstrReelDyn::remove(u64 ip) {}
}
#include "InstrReelDyn.hpp"
#include <spider/runtime/memory/Types.hpp>
namespace spider {
InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) {
_total_size = length;
growToFit(length > 0 ? length - 1 : 0);
selectBlock(0);
}
InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {}
InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) : _use_count(copy._use_count), _block_index(copy._block_index), _blocks(copy._blocks) {
if (_block_index < _blocks.size()) selectBlock(_block_index);
}
InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept : _use_count(move._use_count), _block_index(move._block_index), _blocks(std::move(move._blocks)) {
if (_block_index < _blocks.size()) selectBlock(_block_index);
}
InstrReelDyn::~InstrReelDyn() {
// .. //
}
InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) {
_use_count = copy._use_count;
_block_index = copy._block_index;
_blocks = copy._blocks;
if (_block_index < _blocks.size()) selectBlock(_block_index);
return *this;
}
InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept {
_use_count = move._use_count;
_block_index = move._block_index;
_blocks = std::move(move._blocks);
if (_block_index < _blocks.size()) selectBlock(_block_index);
move._use_count = 0;
move._block_index = 0;
move._mem = nullptr;
move._offset = 0;
move._size = 0;
move._total_size = 0;
return *this;
}
void InstrReelDyn::growToFit(isize index) {
while (_blocks.size() < (index + 1)) {
_blocks.emplace_back();
}
}
isize InstrReelDyn::selectIndex(u64 ip) {
return ip / 256;
}
InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) {
// Update base class cache
auto ptr = &_blocks[index];
_offset = index * 256;
_mem = ptr->data;
_size = 256;
_block_index = index;
//_blocks[block_idx].access_count++;
return ptr;
}
u8 InstrReelDyn::atU8(u64 ip) {
isize j = selectIndex(ip);
if (j >= _blocks.size()) return 0;
if (j != _block_index) {
this->selectBlock(j);
}
return _mem[ip - _offset];
}
u16 InstrReelDyn::atU16(u64 ip) {
isize j0 = selectIndex(ip);
isize j1 = selectIndex(ip + 1);
if (j1 >= _blocks.size()) return 0;
if (j0 == j1 && j0 != _block_index) {
selectBlock(j0);
}
if (j0 == j1 && j0 == _block_index) {
u16 dat;
spider::loadLE(&dat, _mem);
return dat;
}
// general case, first part
u16 dat = 0;
const u8 size = sizeof(u16);
// select first block and offset
selectBlock(j0);
u8 rem = ip % 256;
for (u8 n = 0; n < size; n++) {
dat |= _mem[rem++] << (n * 8);
ip++;
if (!rem) selectBlock(++j0);
}
return dat;
}
u32 InstrReelDyn::atU32(u64 ip) {
isize j0 = selectIndex(ip);
isize j1 = selectIndex(ip + 3);
if (j1 >= _blocks.size()) return 0;
if (j0 == j1 && j0 != _block_index) {
selectBlock(j0);
}
if (j0 == j1 && j0 == _block_index) {
u32 dat;
spider::loadLE(&dat, _mem);
return dat;
}
// general case, first part
u32 dat = 0;
const u8 size = sizeof(u32);
// select first block and offset
selectBlock(j0);
u8 rem = ip % 256;
for (u8 n = 0; n < size; n++) {
dat |= _mem[rem++] << (n * 8);
ip++;
if (!rem) selectBlock(++j0);
}
return dat;
}
u64 InstrReelDyn::atU64(u64 ip) {
isize j0 = selectIndex(ip);
isize j1 = selectIndex(ip + 3);
if (j1 >= _blocks.size()) return 0;
if (j0 == j1 && j0 != _block_index) {
selectBlock(j0);
}
if (j0 == j1 && j0 == _block_index) {
u64 dat;
spider::loadLE(&dat, _mem);
return dat;
}
// general case, first part
u64 dat = 0;
const u8 size = sizeof(u64);
// select first block and offset
selectBlock(j0);
u8 rem = ip % 256;
for (u8 n = 0; n < size; n++) {
dat |= _mem[rem++] << (n * 8);
ip++;
if (!rem) selectBlock(++j0);
}
return dat;
}
void InstrReelDyn::at(u64 ip, u8 dat) {}
void InstrReelDyn::at(u64 ip, u16 dat) {}
void InstrReelDyn::at(u64 ip, u32 dat) {}
void InstrReelDyn::at(u64 ip, u64 dat) {}
/**
* Appends instruction at location.
*/
void InstrReelDyn::append(u64 ip, u16 bc) {}
/**
* Appends instruction at the end.
*/
void InstrReelDyn::append(u16 bc) {}
/**
* Removes instruction at location.
*/
void InstrReelDyn::remove(u64 ip) {}
}

View File

@@ -1,110 +1,110 @@
#pragma once
#include <spider/runtime/reel/InstrReel.hpp>
namespace spider {
/**
* Implements an instruction reel.
*/
class InstrReelDyn : public InstrReel {
private:
struct ReelBlock {
u8 data[256] = {};
};
private:
u64 _use_count;
isize _block_index;
std::deque<ReelBlock> _blocks;
public:
InstrReelDyn(u64 length);
InstrReelDyn(const u8* data, u64 length);
InstrReelDyn(const InstrReelDyn& copy);
InstrReelDyn(InstrReelDyn&& move) noexcept;
virtual ~InstrReelDyn();
public:
InstrReelDyn& operator=(const InstrReelDyn& copy);
InstrReelDyn& operator=(InstrReelDyn&& move) noexcept;
private:
isize selectIndex(u64 ip);
void growToFit(isize index);
ReelBlock* selectBlock(isize index);
public:
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u8 atU8(u64 ip) override;
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u16 atU16(u64 ip) override;
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u32 atU32(u64 ip) override;
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u64 atU64(u64 ip) override;
public:
void at(u64 ip, u8 dat);
void at(u64 ip, u16 dat);
void at(u64 ip, u32 dat);
void at(u64 ip, u64 dat);
/**
* Appends instruction at location.
*/
void append(u64 ip, u16 bc);
/**
* Appends instruction at the end.
*/
void append(u16 bc);
/**
* Removes instruction at location.
*/
void remove(u64 ip);
};
}
#pragma once
#include <spider/runtime/reel/InstrReel.hpp>
namespace spider {
/**
* Implements an instruction reel.
*/
class InstrReelDyn : public InstrReel {
private:
struct ReelBlock {
u8 data[256] = {};
};
private:
u64 _use_count;
isize _block_index;
std::deque<ReelBlock> _blocks;
public:
InstrReelDyn(u64 length);
InstrReelDyn(const u8* data, u64 length);
InstrReelDyn(const InstrReelDyn& copy);
InstrReelDyn(InstrReelDyn&& move) noexcept;
virtual ~InstrReelDyn();
public:
InstrReelDyn& operator=(const InstrReelDyn& copy);
InstrReelDyn& operator=(InstrReelDyn&& move) noexcept;
private:
isize selectIndex(u64 ip);
void growToFit(isize index);
ReelBlock* selectBlock(isize index);
public:
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u8 atU8(u64 ip) override;
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u16 atU16(u64 ip) override;
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u32 atU32(u64 ip) override;
/**
* Obtains a byte of data at
* the specific location.
* Reindexing may occur, continous access
* may incurr in less penalties.
*/
virtual u64 atU64(u64 ip) override;
public:
void at(u64 ip, u8 dat);
void at(u64 ip, u16 dat);
void at(u64 ip, u32 dat);
void at(u64 ip, u64 dat);
/**
* Appends instruction at location.
*/
void append(u64 ip, u16 bc);
/**
* Appends instruction at the end.
*/
void append(u16 bc);
/**
* Removes instruction at location.
*/
void remove(u64 ip);
};
}

View File

@@ -1,149 +1,149 @@
#include "InstrReelFixed.hpp"
#include <spider/runtime/memory/Types.hpp>
#include <cstring>
namespace spider {
// Constructors & Destructors //
InstrReelFixed::InstrReelFixed(u64 length) {
this->_offset = 0;
this->_size = length;
this->_total_size = length;
if (_size > 0) {
_mem = new u8[_size];
std::memset(_mem, 0, _size);
}
}
InstrReelFixed::InstrReelFixed(const u8* data, u64 length) {
this->_offset = 0;
this->_size = length;
this->_total_size = length;
if (_size > 0) {
_mem = new u8[_size];
std::copy(data, data + _size, _mem);
}
}
InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) {
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
_mem = new u8[_size];
std::copy(other._mem, other._mem + _size, _mem);
}
InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept {
_mem = other._mem;
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
other._mem = nullptr;
other._offset = 0;
other._size = 0;
other._total_size = 0;
}
InstrReelFixed::~InstrReelFixed() {
delete[] _mem;
}
// Assign Operators //
InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& other) {
if (this == &other) return *this; // lock self
u8* new_mem = new u8[other._size];
std::copy(other._mem, other._mem + other._size, new_mem);
delete[] _mem;
_mem = new_mem;
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
return *this;
}
InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept {
if (this == &other) return *this; // lock self
delete[] _mem;
_mem = other._mem; // steal
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
other._mem = nullptr; // leave as husk
other._offset = 0;
other._size = 0;
other._total_size = 0;
return *this;
}
// Misc //
void InstrReelFixed::at(u64 ip, u8 dat) {
if(ip + 1 > _size) return;
_mem[ip] = dat;
}
void InstrReelFixed::at(u64 ip, u16 dat) {
if(ip + 2 > _size) return;
spider::storeLE(dat, _mem + ip);
}
void InstrReelFixed::at(u64 ip, u32 dat) {
if(ip + 4 > _size) return;
spider::storeLE(dat, _mem + ip);
}
void InstrReelFixed::at(u64 ip, u64 dat) {
if(ip + 8 > _size) return;
spider::storeLE(dat, _mem + ip);
}
void InstrReelFixed::resize(u64 new_size) {
// Special case 1
if (new_size == _size) return;
// Special case 2
if (new_size == 0) {
delete[] _mem;
_mem = nullptr;
_size = 0;
_total_size = 0;
return;
}
// 1. Allocate the new block
u8* new_mem = new u8[new_size];
// 2. Zero-initialize
std::memset(new_mem, 0, new_size);
// 3. Preserve data
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
// 3.1 Previous size could be zero, where _mem would be null
if (_mem != nullptr) {
std::copy(_mem, _mem + bytes_to_copy, new_mem);
}
// 4. Swap and Clean up
delete[] _mem;
_mem = new_mem;
_size = new_size;
_total_size = new_size;
}
}
#include "InstrReelFixed.hpp"
#include <spider/runtime/memory/Types.hpp>
#include <cstring>
namespace spider {
// Constructors & Destructors //
InstrReelFixed::InstrReelFixed(u64 length) {
this->_offset = 0;
this->_size = length;
this->_total_size = length;
if (_size > 0) {
_mem = new u8[_size];
std::memset(_mem, 0, _size);
}
}
InstrReelFixed::InstrReelFixed(const u8* data, u64 length) {
this->_offset = 0;
this->_size = length;
this->_total_size = length;
if (_size > 0) {
_mem = new u8[_size];
std::copy(data, data + _size, _mem);
}
}
InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) {
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
_mem = new u8[_size];
std::copy(other._mem, other._mem + _size, _mem);
}
InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept {
_mem = other._mem;
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
other._mem = nullptr;
other._offset = 0;
other._size = 0;
other._total_size = 0;
}
InstrReelFixed::~InstrReelFixed() {
delete[] _mem;
}
// Assign Operators //
InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& other) {
if (this == &other) return *this; // lock self
u8* new_mem = new u8[other._size];
std::copy(other._mem, other._mem + other._size, new_mem);
delete[] _mem;
_mem = new_mem;
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
return *this;
}
InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept {
if (this == &other) return *this; // lock self
delete[] _mem;
_mem = other._mem; // steal
_offset = other._offset;
_size = other._size;
_total_size = other._total_size;
other._mem = nullptr; // leave as husk
other._offset = 0;
other._size = 0;
other._total_size = 0;
return *this;
}
// Misc //
void InstrReelFixed::at(u64 ip, u8 dat) {
if(ip + 1 > _size) return;
_mem[ip] = dat;
}
void InstrReelFixed::at(u64 ip, u16 dat) {
if(ip + 2 > _size) return;
spider::storeLE(dat, _mem + ip);
}
void InstrReelFixed::at(u64 ip, u32 dat) {
if(ip + 4 > _size) return;
spider::storeLE(dat, _mem + ip);
}
void InstrReelFixed::at(u64 ip, u64 dat) {
if(ip + 8 > _size) return;
spider::storeLE(dat, _mem + ip);
}
void InstrReelFixed::resize(u64 new_size) {
// Special case 1
if (new_size == _size) return;
// Special case 2
if (new_size == 0) {
delete[] _mem;
_mem = nullptr;
_size = 0;
_total_size = 0;
return;
}
// 1. Allocate the new block
u8* new_mem = new u8[new_size];
// 2. Zero-initialize
std::memset(new_mem, 0, new_size);
// 3. Preserve data
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
// 3.1 Previous size could be zero, where _mem would be null
if (_mem != nullptr) {
std::copy(_mem, _mem + bytes_to_copy, new_mem);
}
// 4. Swap and Clean up
delete[] _mem;
_mem = new_mem;
_size = new_size;
_total_size = new_size;
}
}

View File

@@ -1,43 +1,43 @@
#pragma once
#include <spider/runtime/reel/InstrReel.hpp>
namespace spider {
/**
* Implements an instruction reel.
*/
class InstrReelFixed : public InstrReel {
public:
InstrReelFixed(u64 length);
InstrReelFixed(const u8* data, u64 length);
InstrReelFixed(const InstrReelFixed& copy);
InstrReelFixed(InstrReelFixed&& move) noexcept;
virtual ~InstrReelFixed();
public:
InstrReelFixed& operator=(const InstrReelFixed& copy);
InstrReelFixed& operator=(InstrReelFixed&& move) noexcept;
public:
void at(u64 ip, u8 dat);
void at(u64 ip, u16 dat);
void at(u64 ip, u32 dat);
void at(u64 ip, u64 dat);
void resize(u64 new_size);
};
}
#pragma once
#include <spider/runtime/reel/InstrReel.hpp>
namespace spider {
/**
* Implements an instruction reel.
*/
class InstrReelFixed : public InstrReel {
public:
InstrReelFixed(u64 length);
InstrReelFixed(const u8* data, u64 length);
InstrReelFixed(const InstrReelFixed& copy);
InstrReelFixed(InstrReelFixed&& move) noexcept;
virtual ~InstrReelFixed();
public:
InstrReelFixed& operator=(const InstrReelFixed& copy);
InstrReelFixed& operator=(InstrReelFixed&& move) noexcept;
public:
void at(u64 ip, u8 dat);
void at(u64 ip, u16 dat);
void at(u64 ip, u32 dat);
void at(u64 ip, u64 dat);
void resize(u64 new_size);
};
}

View File

@@ -1,277 +1,277 @@
#include "Terminal.hpp"
#include <spider/runtime/native/distro.hpp>
#if defined(SPIDER_OS_WINDOWS)
#include <conio.h>
#include <windows.h>
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#endif
#if defined(SPIDER_DISTRO_DESKTOP)
namespace spider {
// Style //
const char* Terminal::RESET = "\033[0m";
const char* Terminal::BOLD = "\033[1m";
const char* Terminal::ITALIC = "\033[3m";
const char* Terminal::FAINT = "\033[2m";
const char* Terminal::STRIKE = "\033[9m";
// Foreground //
const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m";
const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m";
const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m";
const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m";
const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m";
const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m";
const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m";
const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m";
// Background //
const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m";
const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m";
const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m";
const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m";
const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m";
const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m";
const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m";
const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m";
Terminal::Terminal() {
#if defined(SPIDER_OS_WINDOWS)
// Enable UTF-8
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
// enable vtp
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
#endif
}
Terminal::~Terminal() {
altbuff(false).style(RESET).cursor(true).flush();
}
Terminal& Terminal::style(const std::string_view code) {
std::cout << code;
return *this;
}
Terminal& Terminal::move(i32 row, i32 col) {
std::cout << "\033[" << row << ";" << col << "H";
return *this;
}
Terminal& Terminal::altbuff(bool enable) {
std::cout << (enable ? "\033[?1049h" : "\033[?1049l");
return *this;
}
Terminal& Terminal::cls() {
std::cout << "\033[2J";
return *this;
}
Terminal& Terminal::scrollRange(i32 start, i32 end) {
std::cout << "\033[" << start << ";" << end << "r\033[?6h";
return *this;
}
Terminal& Terminal::undoSRange() {
std::cout << "\033[r\033[?6l\033[H";
return *this;
}
Terminal& Terminal::fill(const std::string_view color) {
this->style(color);
this->cls();
return *this;
}
Terminal& Terminal::clearRow(i32 row) {
// Move to row, column 1
this->move(row, 1);
// \033[2K clears the entire line
std::cout << "\033[2K";
return *this;
}
Terminal& Terminal::clearRows(i32 start, i32 end) {
// Ensure we don't loop infinitely if start > end
if (start > end) std::swap(start, end);
for (i32 i = start; i <= end; ++i) {
this->clearRow(i);
}
// Optional: Move cursor back to the start of the cleared block
this->move(start, 1);
return *this;
}
Terminal& Terminal::cursor(bool show) {
std::cout << (show ? "\033[?25h" : "\033[?25l");
return *this;
}
Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) {
// 1. Draw the top border
move(startRow, startCol);
std::cout << "";
for (i32 i = 0; i < width - 2; ++i) std::cout << "";
std::cout << "";
// 2. Draw the sides
for (i32 i = 1; i < height - 1; ++i) {
move(startRow + i, startCol);
std::cout << "";
move(startRow + i, startCol + width - 1);
std::cout << "";
}
// 3. Draw the bottom border
move(startRow + height - 1, startCol);
std::cout << "";
for (i32 i = 0; i < width - 2; ++i) std::cout << "";
std::cout << "";
// 4. Overlay the title if provided
if (!title.empty()) {
move(startRow, startCol + (width - title.size() - 2) / 2);
std::cout << " " << title << " ";
}
std::cout.flush();
return *this;
}
Terminal& Terminal::flush() {
std::cout << std::flush;
return *this;
}
Terminal& Terminal::sink() {
std::cin.clear();
#if defined(SPIDER_OS_WINDOWS)
while (_kbhit()) _getch();
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
tcflush(STDIN_FILENO, TCIFLUSH);
#endif
return *this;
}
std::pair<i32, i32> Terminal::getSize() {
std::pair<i32, i32> pair;
#if defined(SPIDER_OS_WINDOWS)
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1;
pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
pair.first = w.ws_col;
pair.second = w.ws_row;
}
#endif
return pair;
}
Terminal& Terminal::wait() {
sink();
std::cin.get();
return *this;
}
u8 Terminal::getKey() {
#if defined(SPIDER_OS_WINDOWS)
i32 ch = _getch();
if (ch == 0 || ch == 224) {
switch (_getch()) {
case 72: return Terminal::UP;
case 80: return Terminal::DOWN;
case 75: return Terminal::LEFT;
case 77: return Terminal::RIGHT;
default: return Terminal::UNKNOWN;
}
}
if (ch == 13) return Terminal::ENTER;
if (ch == 27) return Terminal::ESC;
if (ch == 8) return Terminal::BACKSPACE;
return Terminal::UNKNOWN;
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
u8 result = Terminal::UNKNOWN;
int ch = getchar();
if (ch == 27) { // Potential Escape Sequence
// Use a small timeout or check if more chars are in buffer
// to distinguish between 'Esc' key and 'Arrow' sequence
// Another Win for the Win API
struct timeval tv = { 0, 10000 }; // 10ms wait
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
if (select(1, &fds, NULL, NULL, &tv) > 0) {
if (getchar() == '[') {
switch (getchar()) {
case 'A': result = Terminal::UP; break;
case 'B': result = Terminal::DOWN; break;
case 'D': result = Terminal::LEFT; break;
case 'C': result = Terminal::RIGHT; break;
}
}
} else {
result = Terminal::ESC;
}
} else if (ch == 10) result = Terminal::ENTER;
else if (ch == 127) result = Terminal::BACKSPACE;
else result = (u8)ch;
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return result;
#endif
}
u8 Terminal::getKeyNb() {
#if defined(SPIDER_OS_WINDOWS)
if (_kbhit()) return getKey();
return Terminal::UNKNOWN;
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
struct timeval tv = { 0, 0 };
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
// select() returns > 0 if there is data to read
if (select(1, &fds, NULL, NULL, &tv) > 0) {
return getKey();
}
return Terminal::UNKNOWN;
#endif
}
}
#endif
#include "Terminal.hpp"
#include <spider/runtime/native/distro.hpp>
#if defined(SPIDER_OS_WINDOWS)
#include <conio.h>
#include <windows.h>
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#endif
#if defined(SPIDER_DISTRO_DESKTOP)
namespace spider {
// Style //
const char* Terminal::RESET = "\033[0m";
const char* Terminal::BOLD = "\033[1m";
const char* Terminal::ITALIC = "\033[3m";
const char* Terminal::FAINT = "\033[2m";
const char* Terminal::STRIKE = "\033[9m";
// Foreground //
const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m";
const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m";
const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m";
const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m";
const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m";
const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m";
const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m";
const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m";
// Background //
const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m";
const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m";
const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m";
const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m";
const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m";
const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m";
const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m";
const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m";
Terminal::Terminal() {
#if defined(SPIDER_OS_WINDOWS)
// Enable UTF-8
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
// enable vtp
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
#endif
}
Terminal::~Terminal() {
altbuff(false).style(RESET).cursor(true).flush();
}
Terminal& Terminal::style(const std::string_view code) {
std::cout << code;
return *this;
}
Terminal& Terminal::move(i32 row, i32 col) {
std::cout << "\033[" << row << ";" << col << "H";
return *this;
}
Terminal& Terminal::altbuff(bool enable) {
std::cout << (enable ? "\033[?1049h" : "\033[?1049l");
return *this;
}
Terminal& Terminal::cls() {
std::cout << "\033[2J";
return *this;
}
Terminal& Terminal::scrollRange(i32 start, i32 end) {
std::cout << "\033[" << start << ";" << end << "r\033[?6h";
return *this;
}
Terminal& Terminal::undoSRange() {
std::cout << "\033[r\033[?6l\033[H";
return *this;
}
Terminal& Terminal::fill(const std::string_view color) {
this->style(color);
this->cls();
return *this;
}
Terminal& Terminal::clearRow(i32 row) {
// Move to row, column 1
this->move(row, 1);
// \033[2K clears the entire line
std::cout << "\033[2K";
return *this;
}
Terminal& Terminal::clearRows(i32 start, i32 end) {
// Ensure we don't loop infinitely if start > end
if (start > end) std::swap(start, end);
for (i32 i = start; i <= end; ++i) {
this->clearRow(i);
}
// Optional: Move cursor back to the start of the cleared block
this->move(start, 1);
return *this;
}
Terminal& Terminal::cursor(bool show) {
std::cout << (show ? "\033[?25h" : "\033[?25l");
return *this;
}
Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) {
// 1. Draw the top border
move(startRow, startCol);
std::cout << "";
for (i32 i = 0; i < width - 2; ++i) std::cout << "";
std::cout << "";
// 2. Draw the sides
for (i32 i = 1; i < height - 1; ++i) {
move(startRow + i, startCol);
std::cout << "";
move(startRow + i, startCol + width - 1);
std::cout << "";
}
// 3. Draw the bottom border
move(startRow + height - 1, startCol);
std::cout << "";
for (i32 i = 0; i < width - 2; ++i) std::cout << "";
std::cout << "";
// 4. Overlay the title if provided
if (!title.empty()) {
move(startRow, startCol + (width - title.size() - 2) / 2);
std::cout << " " << title << " ";
}
std::cout.flush();
return *this;
}
Terminal& Terminal::flush() {
std::cout << std::flush;
return *this;
}
Terminal& Terminal::sink() {
std::cin.clear();
#if defined(SPIDER_OS_WINDOWS)
while (_kbhit()) _getch();
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
tcflush(STDIN_FILENO, TCIFLUSH);
#endif
return *this;
}
std::pair<i32, i32> Terminal::getSize() {
std::pair<i32, i32> pair;
#if defined(SPIDER_OS_WINDOWS)
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1;
pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
pair.first = w.ws_col;
pair.second = w.ws_row;
}
#endif
return pair;
}
Terminal& Terminal::wait() {
sink();
std::cin.get();
return *this;
}
u8 Terminal::getKey() {
#if defined(SPIDER_OS_WINDOWS)
i32 ch = _getch();
if (ch == 0 || ch == 224) {
switch (_getch()) {
case 72: return Terminal::UP;
case 80: return Terminal::DOWN;
case 75: return Terminal::LEFT;
case 77: return Terminal::RIGHT;
default: return Terminal::UNKNOWN;
}
}
if (ch == 13) return Terminal::ENTER;
if (ch == 27) return Terminal::ESC;
if (ch == 8) return Terminal::BACKSPACE;
return Terminal::UNKNOWN;
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
u8 result = Terminal::UNKNOWN;
int ch = getchar();
if (ch == 27) { // Potential Escape Sequence
// Use a small timeout or check if more chars are in buffer
// to distinguish between 'Esc' key and 'Arrow' sequence
// Another Win for the Win API
struct timeval tv = { 0, 10000 }; // 10ms wait
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
if (select(1, &fds, NULL, NULL, &tv) > 0) {
if (getchar() == '[') {
switch (getchar()) {
case 'A': result = Terminal::UP; break;
case 'B': result = Terminal::DOWN; break;
case 'D': result = Terminal::LEFT; break;
case 'C': result = Terminal::RIGHT; break;
}
}
} else {
result = Terminal::ESC;
}
} else if (ch == 10) result = Terminal::ENTER;
else if (ch == 127) result = Terminal::BACKSPACE;
else result = (u8)ch;
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return result;
#endif
}
u8 Terminal::getKeyNb() {
#if defined(SPIDER_OS_WINDOWS)
if (_kbhit()) return getKey();
return Terminal::UNKNOWN;
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
struct timeval tv = { 0, 0 };
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
// select() returns > 0 if there is data to read
if (select(1, &fds, NULL, NULL, &tv) > 0) {
return getKey();
}
return Terminal::UNKNOWN;
#endif
}
}
#endif

View File

@@ -1,176 +1,176 @@
#pragma once
#include <spider/runtime/common.hpp>
#include <iostream>
#include <string>
#include <string_view>
#include <sstream>
namespace spider {
class Terminal {
public:
static const char* RESET;
static const char* BOLD;
static const char* ITALIC;
static const char* FAINT;
static const char* STRIKE;
static const char* FG_BLACK; static const char* FG_B_BLACK;
static const char* FG_RED; static const char* FG_B_RED;
static const char* FG_GREEN; static const char* FG_B_GREEN;
static const char* FG_YELLOW; static const char* FG_B_YELLOW;
static const char* FG_BLUE; static const char* FG_B_BLUE;
static const char* FG_MAGENTA; static const char* FG_B_MAGENTA;
static const char* FG_CYAN; static const char* FG_B_CYAN;
static const char* FG_WHITE; static const char* FG_B_WHITE;
static const char* BG_BLACK; static const char* BG_B_BLACK;
static const char* BG_RED; static const char* BG_B_RED;
static const char* BG_GREEN; static const char* BG_B_GREEN;
static const char* BG_YELLOW; static const char* BG_B_YELLOW;
static const char* BG_BLUE; static const char* BG_B_BLUE;
static const char* BG_MAGENTA; static const char* BG_B_MAGENTA;
static const char* BG_CYAN; static const char* BG_B_CYAN;
static const char* BG_WHITE; static const char* BG_B_WHITE;
public:
// Key Definitions (ASCII OK) //
static constexpr const u8 UP = 0x80;
static constexpr const u8 DOWN = 0x81;
static constexpr const u8 LEFT = 0x82;
static constexpr const u8 RIGHT = 0x83;
static constexpr const u8 ENTER = 0x84;
static constexpr const u8 ESC = 0x85;
static constexpr const u8 BACKSPACE = 0x86;
static constexpr const u8 UNKNOWN = 0xFF;
public:
Terminal();
~Terminal();
public:
/**
* Sets a style
*/
Terminal& style(const std::string_view code);
/**
* Fills the screen with a specific background color.
* @param color The background color constant (e.g., Terminal::BG_BLUE)
*/
Terminal& fill(const std::string_view color);
/**
* Moves the cursor.
*/
Terminal& move(i32 row, i32 col);
/**
* Clears the screen
*/
Terminal& cls();
Terminal& altbuff(bool enable);
Terminal& scrollRange(i32 start, i32 end);
Terminal& undoSRange();
/**
* Clears a specific row.
* @param row The 1-based index of the row to clear.
*/
Terminal& clearRow(i32 row);
/**
* Clears a range of rows (inclusive).
* @param start The first row.
* @param end The last row.
*/
Terminal& clearRows(i32 start, i32 end);
/**
* Shows / Hides the cursor.
*/
Terminal& cursor(bool show);
public:
Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title);
public:
/**
* Flushes the output buffer
*/
Terminal& flush();
/**
* Clears the input buffer.
* Useful for some specific input cases
*/
Terminal& sink();
public:
Terminal& wait();
u8 getKey();
/**
* Get key non blocking
*/
u8 getKeyNb();
std::pair<i32, i32> getSize();
public:
template <typename T>
Terminal& print(const T& msg) {
std::cout << msg;
return *this;
}
template <typename T>
Terminal& println(const T& msg) {
std::cout << msg << "\n";
return *this;
}
template <typename T>
Terminal& print_center(i32 width, const T& msg) {
// to string
std::ostringstream oss;
oss << msg;
std::string s = oss.str();
// then print
if (s.length() >= isize(width)) {
std::cout << s;
} else {
i32 total_padding = width - s.length();
i32 left_padding = total_padding / 2;
std::cout << std::string(left_padding, ' ');
std::cout << s;
std::cout << std::string(total_padding - left_padding, ' ');
}
return *this;
}
template <typename T>
Terminal& read(T& var) {
std::cin >> var;
return *this;
}
};
#pragma once
#include <spider/runtime/common.hpp>
#include <iostream>
#include <string>
#include <string_view>
#include <sstream>
namespace spider {
class Terminal {
public:
static const char* RESET;
static const char* BOLD;
static const char* ITALIC;
static const char* FAINT;
static const char* STRIKE;
static const char* FG_BLACK; static const char* FG_B_BLACK;
static const char* FG_RED; static const char* FG_B_RED;
static const char* FG_GREEN; static const char* FG_B_GREEN;
static const char* FG_YELLOW; static const char* FG_B_YELLOW;
static const char* FG_BLUE; static const char* FG_B_BLUE;
static const char* FG_MAGENTA; static const char* FG_B_MAGENTA;
static const char* FG_CYAN; static const char* FG_B_CYAN;
static const char* FG_WHITE; static const char* FG_B_WHITE;
static const char* BG_BLACK; static const char* BG_B_BLACK;
static const char* BG_RED; static const char* BG_B_RED;
static const char* BG_GREEN; static const char* BG_B_GREEN;
static const char* BG_YELLOW; static const char* BG_B_YELLOW;
static const char* BG_BLUE; static const char* BG_B_BLUE;
static const char* BG_MAGENTA; static const char* BG_B_MAGENTA;
static const char* BG_CYAN; static const char* BG_B_CYAN;
static const char* BG_WHITE; static const char* BG_B_WHITE;
public:
// Key Definitions (ASCII OK) //
static constexpr const u8 UP = 0x80;
static constexpr const u8 DOWN = 0x81;
static constexpr const u8 LEFT = 0x82;
static constexpr const u8 RIGHT = 0x83;
static constexpr const u8 ENTER = 0x84;
static constexpr const u8 ESC = 0x85;
static constexpr const u8 BACKSPACE = 0x86;
static constexpr const u8 UNKNOWN = 0xFF;
public:
Terminal();
~Terminal();
public:
/**
* Sets a style
*/
Terminal& style(const std::string_view code);
/**
* Fills the screen with a specific background color.
* @param color The background color constant (e.g., Terminal::BG_BLUE)
*/
Terminal& fill(const std::string_view color);
/**
* Moves the cursor.
*/
Terminal& move(i32 row, i32 col);
/**
* Clears the screen
*/
Terminal& cls();
Terminal& altbuff(bool enable);
Terminal& scrollRange(i32 start, i32 end);
Terminal& undoSRange();
/**
* Clears a specific row.
* @param row The 1-based index of the row to clear.
*/
Terminal& clearRow(i32 row);
/**
* Clears a range of rows (inclusive).
* @param start The first row.
* @param end The last row.
*/
Terminal& clearRows(i32 start, i32 end);
/**
* Shows / Hides the cursor.
*/
Terminal& cursor(bool show);
public:
Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title);
public:
/**
* Flushes the output buffer
*/
Terminal& flush();
/**
* Clears the input buffer.
* Useful for some specific input cases
*/
Terminal& sink();
public:
Terminal& wait();
u8 getKey();
/**
* Get key non blocking
*/
u8 getKeyNb();
std::pair<i32, i32> getSize();
public:
template <typename T>
Terminal& print(const T& msg) {
std::cout << msg;
return *this;
}
template <typename T>
Terminal& println(const T& msg) {
std::cout << msg << "\n";
return *this;
}
template <typename T>
Terminal& print_center(i32 width, const T& msg) {
// to string
std::ostringstream oss;
oss << msg;
std::string s = oss.str();
// then print
if (s.length() >= isize(width)) {
std::cout << s;
} else {
i32 total_padding = width - s.length();
i32 left_padding = total_padding / 2;
std::cout << std::string(left_padding, ' ');
std::cout << s;
std::cout << std::string(total_padding - left_padding, ' ');
}
return *this;
}
template <typename T>
Terminal& read(T& var) {
std::cin >> var;
return *this;
}
};
}