diff --git a/autogen/InstructionMasks.hpp b/autogen/InstructionMasks.hpp index 9be8113..34a0909 100644 --- a/autogen/InstructionMasks.hpp +++ b/autogen/InstructionMasks.hpp @@ -16,107 +16,107 @@ constexpr u8 ADDR_MODE_MASKS[][2] = { { 0x1E, 0x00 }, // FIR { 0x1E, 0x00 }, // FZR { 0x1E, 0x1F }, // LSR - { 0x00, 0x00 }, // FVR - { 0x00, 0x00 }, // MOV - { 0x00, 0x00 }, // MOR + { 0x04, 0x00 }, // FVR + { 0x1E, 0xFF }, // MOV + { 0x04, 0x04 }, // MOR { 0x00, 0x00 }, // AMOV { 0x04, 0x04 }, // SWP { 0x04, 0x00 }, // AHM - { 0x00, 0x00 }, // COM - { 0x00, 0x00 }, // NEG - { 0x00, 0x00 }, // EXS - { 0x00, 0x00 }, // INC - { 0x00, 0x00 }, // DEC - { 0x00, 0x00 }, // ADD - { 0x00, 0x00 }, // SUB - { 0x00, 0x00 }, // MUL - { 0x00, 0x00 }, // UMUL - { 0x00, 0x00 }, // DIV - { 0x00, 0x00 }, // UDIV - { 0x00, 0x00 }, // MOD - { 0x00, 0x00 }, // UMOD - { 0x00, 0x00 }, // DMOD - { 0x00, 0x00 }, // UDMD - { 0x00, 0x00 }, // FBT - { 0x00, 0x00 }, // STB - { 0x00, 0x00 }, // CRB - { 0x00, 0x00 }, // TSB - { 0x00, 0x00 }, // BOOL - { 0x00, 0x00 }, // NOT - { 0x00, 0x00 }, // AND - { 0x00, 0x00 }, // OR - { 0x00, 0x00 }, // XOR - { 0x00, 0x00 }, // SHL - { 0x00, 0x00 }, // SHR - { 0x00, 0x00 }, // SSR - { 0x00, 0x00 }, // ROL - { 0x00, 0x00 }, // ROR - { 0x00, 0x00 }, // CNT - { 0x00, 0x00 }, // EQ - { 0x00, 0x00 }, // NE - { 0x00, 0x00 }, // GT - { 0x00, 0x00 }, // GE - { 0x00, 0x00 }, // LT - { 0x00, 0x00 }, // LE - { 0x00, 0x00 }, // JMP - { 0x00, 0x00 }, // JEQ - { 0x00, 0x00 }, // JNE - { 0x00, 0x00 }, // JIF - { 0x00, 0x00 }, // JMR - { 0x00, 0x00 }, // JER - { 0x00, 0x00 }, // JNR - { 0x00, 0x00 }, // JIR - { 0x00, 0x00 }, // SFB - { 0x00, 0x00 }, // LFB - { 0x00, 0x00 }, // JUF - { 0x00, 0x00 }, // JUR - { 0x00, 0x00 }, // PUSH - { 0x00, 0x00 }, // POP - { 0x00, 0x00 }, // ALLOC - { 0x00, 0x00 }, // HFREE - { 0x00, 0x00 }, // CALL + { 0xFF, 0x00 }, // COM + { 0xFF, 0x00 }, // NEG + { 0xFF, 0x00 }, // EXS + { 0xFF, 0x00 }, // INC + { 0xFF, 0x00 }, // DEC + { 0x1E, 0xFF }, // ADD + { 0x1E, 0xFF }, // SUB + { 0x1E, 0xFF }, // MUL + { 0x1E, 0xFF }, // UMUL + { 0x1E, 0xFF }, // DIV + { 0x1E, 0xFF }, // UDIV + { 0x1E, 0xFF }, // MOD + { 0x1E, 0xFF }, // UMOD + { 0x1E, 0xFF }, // DMOD + { 0x1E, 0xFF }, // UDMD + { 0xFF, 0x00 }, // FBT + { 0x1E, 0xFF }, // STB + { 0x1E, 0xFF }, // CRB + { 0x1E, 0xFF }, // TSB + { 0xFF, 0x00 }, // BOOL + { 0xFF, 0x00 }, // NOT + { 0x1E, 0xFF }, // AND + { 0x1E, 0xFF }, // OR + { 0x1E, 0xFF }, // XOR + { 0x1E, 0xFF }, // SHL + { 0x1E, 0xFF }, // SHR + { 0x1E, 0xFF }, // SSR + { 0x1E, 0xFF }, // ROL + { 0x1E, 0xFF }, // ROR + { 0xFF, 0x00 }, // CNT + { 0x1E, 0xFF }, // EQ + { 0x1E, 0xFF }, // NE + { 0x1E, 0xFF }, // GT + { 0x1E, 0xFF }, // GE + { 0x1E, 0xFF }, // LT + { 0x1E, 0xFF }, // LE + { 0xFF, 0x00 }, // JMP + { 0xFF, 0x00 }, // JEQ + { 0xFF, 0x00 }, // JNE + { 0x1E, 0xFF }, // JIF + { 0xFF, 0x00 }, // JMR + { 0xFF, 0x00 }, // JER + { 0xFF, 0x00 }, // JNR + { 0x1E, 0xFF }, // JIR + { 0x1E, 0xFF }, // SFB + { 0x1E, 0xFF }, // LFB + { 0x1E, 0xFF }, // JUF + { 0x1E, 0xFF }, // JUR + { 0xFF, 0x00 }, // PUSH + { 0xFF, 0x00 }, // POP + { 0xFF, 0x00 }, // ALLOC + { 0xFF, 0x00 }, // HFREE + { 0xFF, 0x00 }, // CALL { 0x00, 0x00 }, // RET - { 0x00, 0x00 }, // EDI - { 0x00, 0x00 }, // SHSS - { 0x00, 0x00 }, // FLI - { 0x00, 0x00 }, // FNEG - { 0x00, 0x00 }, // FADD - { 0x00, 0x00 }, // FSUB - { 0x00, 0x00 }, // FMUL - { 0x00, 0x00 }, // FDIV - { 0x00, 0x00 }, // FMOD - { 0x00, 0x00 }, // FDMOD - { 0x00, 0x00 }, // FEPS - { 0x00, 0x00 }, // FEEP - { 0x00, 0x00 }, // FEQ - { 0x00, 0x00 }, // FNE - { 0x00, 0x00 }, // FGT - { 0x00, 0x00 }, // FGE - { 0x00, 0x00 }, // FLT - { 0x00, 0x00 }, // FLE - { 0x00, 0x00 }, // F2D - { 0x00, 0x00 }, // D2F - { 0x00, 0x00 }, // I2F - { 0x00, 0x00 }, // I2D - { 0x00, 0x00 }, // L2F - { 0x00, 0x00 }, // L2D - { 0x00, 0x00 }, // F2I - { 0x00, 0x00 }, // F2L - { 0x00, 0x00 }, // D2I - { 0x00, 0x00 }, // D2L - { 0x00, 0x00 }, // SIN - { 0x00, 0x00 }, // COS - { 0x00, 0x00 }, // TAN - { 0x00, 0x00 }, // ASIN - { 0x00, 0x00 }, // ACOS - { 0x00, 0x00 }, // ATAN - { 0x00, 0x00 }, // ATAN2 - { 0x00, 0x00 }, // EXP - { 0x00, 0x00 }, // LOG - { 0x00, 0x00 }, // LOGAB - { 0x00, 0x00 }, // POW - { 0x00, 0x00 }, // SQRT - { 0x00, 0x00 }, // ROOT + { 0xFF, 0x00 }, // EDI + { 0xFF, 0x00 }, // SHSS + { 0xFF, 0x00 }, // FLI + { 0xFF, 0x00 }, // FNEG + { 0x1E, 0xFF }, // FADD + { 0x1E, 0xFF }, // FSUB + { 0x1E, 0xFF }, // FMUL + { 0x1E, 0xFF }, // FDIV + { 0x1E, 0xFF }, // FMOD + { 0x1E, 0xFF }, // FDMOD + { 0xFF, 0x00 }, // FEPS + { 0xFF, 0x00 }, // FEEP + { 0x1E, 0xFF }, // FEQ + { 0x1E, 0xFF }, // FNE + { 0x1E, 0xFF }, // FGT + { 0x1E, 0xFF }, // FGE + { 0x1E, 0xFF }, // FLT + { 0x1E, 0xFF }, // FLE + { 0xFF, 0x00 }, // F2D + { 0xFF, 0x00 }, // D2F + { 0xFF, 0x00 }, // I2F + { 0xFF, 0x00 }, // I2D + { 0xFF, 0x00 }, // L2F + { 0xFF, 0x00 }, // L2D + { 0xFF, 0x00 }, // F2I + { 0xFF, 0x00 }, // F2L + { 0xFF, 0x00 }, // D2I + { 0xFF, 0x00 }, // D2L + { 0xFF, 0x00 }, // SIN + { 0xFF, 0x00 }, // COS + { 0xFF, 0x00 }, // TAN + { 0xFF, 0x00 }, // ASIN + { 0xFF, 0x00 }, // ACOS + { 0xFF, 0x00 }, // ATAN + { 0x1E, 0xFF }, // ATAN2 + { 0xFF, 0x00 }, // EXP + { 0xFF, 0x00 }, // LOG + { 0x1E, 0xFF }, // LOGAB + { 0x1E, 0xFF }, // POW + { 0xFF, 0x00 }, // SQRT + { 0x1E, 0xFF }, // ROOT { 0x00, 0x00 }, // ADC { 0x00, 0x00 }, // SWC { 0x00, 0x00 }, // MWO @@ -127,6 +127,8 @@ constexpr u8 ADDR_MODE_MASKS[][2] = { { 0x00, 0x00 }, // MINV { 0x00, 0x00 }, // MTRA { 0x00, 0x00 }, // MDET + { 0x00, 0x00 }, // QMKA + { 0x00, 0x00 }, // QMUL { 0x00, 0x00 }, // XADD { 0x00, 0x00 }, // XSUB { 0x00, 0x00 }, // XAMA @@ -140,18 +142,18 @@ constexpr u8 TYPE_SIZE_MASKS[] = { 0x00, // NOP 0x00, // SPDR 0x01, // MMODE - 0x0F, // INT - 0x0C, // LRV - 0x0F, // FSR - 0x0F, // FIR - 0x0F, // FZR - 0x0F, // LSR - 0x0F, // FVR - 0x00, // MOV - 0x00, // MOR - 0x00, // AMOV - 0x00, // SWP - 0x0F, // AHM + 0x08, // INT + 0x08, // LRV + 0x08, // FSR + 0x08, // FIR + 0x08, // FZR + 0x08, // LSR + 0x08, // FVR + 0x0F, // MOV + 0x08, // MOR + 0x08, // AMOV + 0x08, // SWP + 0x08, // AHM 0x0F, // COM 0x0F, // NEG 0x0F, // EXS @@ -208,22 +210,22 @@ constexpr u8 TYPE_SIZE_MASKS[] = { 0x0F, // RET 0x0F, // EDI 0x0F, // SHSS - 0x00, // FLI - 0x00, // FNEG - 0x00, // FADD - 0x00, // FSUB - 0x00, // FMUL - 0x00, // FDIV - 0x00, // FMOD - 0x00, // FDMOD - 0x00, // FEPS - 0x00, // FEEP - 0x00, // FEQ - 0x00, // FNE - 0x00, // FGT - 0x00, // FGE - 0x00, // FLT - 0x00, // FLE + 0x0C, // FLI + 0x0C, // FNEG + 0x0C, // FADD + 0x0C, // FSUB + 0x0C, // FMUL + 0x0C, // FDIV + 0x0C, // FMOD + 0x0C, // FDMOD + 0x0C, // FEPS + 0x0C, // FEEP + 0x0C, // FEQ + 0x0C, // FNE + 0x0C, // FGT + 0x0C, // FGE + 0x0C, // FLT + 0x0C, // FLE 0x00, // F2D 0x00, // D2F 0x00, // I2F @@ -234,19 +236,19 @@ constexpr u8 TYPE_SIZE_MASKS[] = { 0x00, // F2L 0x00, // D2I 0x00, // D2L - 0x00, // SIN - 0x00, // COS - 0x00, // TAN - 0x00, // ASIN - 0x00, // ACOS - 0x00, // ATAN - 0x00, // ATAN2 - 0x00, // EXP - 0x00, // LOG - 0x00, // LOGAB - 0x00, // POW - 0x00, // SQRT - 0x00, // ROOT + 0x0C, // SIN + 0x0C, // COS + 0x0C, // TAN + 0x0C, // ASIN + 0x0C, // ACOS + 0x0C, // ATAN + 0x0C, // ATAN2 + 0x0C, // EXP + 0x0C, // LOG + 0x0C, // LOGAB + 0x0C, // POW + 0x0C, // SQRT + 0x0C, // ROOT 0x00, // ADC 0x00, // SWC 0x00, // MWO @@ -257,6 +259,8 @@ constexpr u8 TYPE_SIZE_MASKS[] = { 0x00, // MINV 0x00, // MTRA 0x00, // MDET + 0x00, // QMKA + 0x00, // QMUL 0x00, // XADD 0x00, // XSUB 0x00, // XAMA diff --git a/docs/Spider Instructions.xlsx b/docs/Spider Instructions.xlsx index e664320..94a7f57 100644 Binary files a/docs/Spider Instructions.xlsx and b/docs/Spider Instructions.xlsx differ diff --git a/makefile b/makefile index 8ec5941..92cedfa 100644 --- a/makefile +++ b/makefile @@ -14,8 +14,16 @@ OBJEXT := o #Flags, Libraries and Includes ROOT := ./ -CFLAGS := -Wall -std=c++20 -DSPIDER_COMPILING -LFLAGS := -Wall -std=c++20 -static +CFLAGS := -std=c++20 -O2 \ + -Wall -Wextra \ + -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align \ + -Wunused -Woverloaded-virtual -Wconversion \ + -Wsign-conversion -Wnull-dereference -Wdouble-promotion \ + -Wformat=2 -Wimplicit-fallthrough -Wsuggest-override \ + -Wextra-semi -Wduplicated-cond -Wduplicated-branches \ + -Wlogical-op -Wuseless-cast +LFLAGS := -std=c++20 -static-libstdc++ -static-libgcc \ + -Wl,--fatal-warnings -Wl,--warn-common LIB := INC := -I./src/ diff --git a/pygen.ipynb b/pygen.ipynb index 4d88ae5..d3d354b 100644 --- a/pygen.ipynb +++ b/pygen.ipynb @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "b0fcd533", "metadata": {}, "outputs": [ @@ -68,7 +68,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "id": "b33de8ac", "metadata": {}, "outputs": [ @@ -144,7 +144,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "58645013", "metadata": {}, "outputs": [ @@ -152,7 +152,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Real instructions : 126\n", + "Real instructions : 128\n", "Reserved slots : 14\n", "Duplicate check : PASSED\n", "\n", @@ -163,13 +163,14 @@ "Bit Wise 14\n", "Boolean 12\n", "Branch 12\n", - "Casts 10\n", "Floating Point 10\n", + "Casts 10\n", "Memory 9\n", "Trigonometric 7\n", "Exponential 6\n", "Matrix 6\n", "SIMD 5\n", + "Quaternion 2\n", "Easter Eggs 1\n", "\n", "First 5 instructions:\n", @@ -177,8 +178,8 @@ "0 000 NOP System 0 00 00\n", "1 001 SPDR System 0 00 00\n", "2 002 MMODE System 1 05 01\n", - "3 003 INT System 1 1F 0F\n", - "4 004 LRV System 1 1F 0C\n" + "3 003 INT System 1 1F 08\n", + "4 004 LRV System 1 1F 08\n" ] } ], @@ -214,6 +215,7 @@ " 'dis', # addressing mode: Displaced\n", " 'addr_mask_1', # accepted addressing mode mask for param 1\n", " 'addr_mask_2', # accepted addressing mode mask for param 2\n", + " 'ignores_addrm',# whether the instruction ignores addressing modes\n", " 'B', # type size: Byte (1 byte) supported?\n", " 'S', # type size: Short (2 bytes) supported?\n", " 'I', # type size: Int (4 bytes) supported?\n", @@ -221,6 +223,7 @@ " 'F', # type size: Float supported?\n", " 'D', # type size: Double supported?\n", " 'type_mask', # combined type size mask as hex string\n", + " 'expensive', # marks computationally expensive instructions\n", " 'operation', # human-readable description of what the instruction does\n", " 'skip_2', # trailing empty column\n", "]\n", @@ -280,7 +283,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "id": "452bc76c", "metadata": {}, "outputs": [ @@ -289,7 +292,7 @@ "output_type": "stream", "text": [ "Masks written to: .//autogen/InstructionMasks.hpp\n", - "Lines generated : 268\n" + "Lines generated : 272\n" ] } ], @@ -354,7 +357,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "id": "5aaebef0", "metadata": {}, "outputs": [ @@ -362,7 +365,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Instructions formatted: 126\n", + "Instructions formatted: 128\n", "\n", "--- Preview (first 2 instructions) ---\n", " // [System] 0x000 — NOP: No Operation\n", @@ -377,7 +380,7 @@ "\n", "\n", "CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n", - "Total lines in updated file: 674\n" + "Total lines in updated file: 883\n" ] } ], @@ -445,6 +448,173 @@ "print(f'\\nCPU.hpp updated successfully at: {CPU_HPP_PATH}')\n", "print(f'Total lines in updated file: {len(updated.splitlines())}')\n" ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "instrmap_gen", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "InstrMap.cpp written to: .//src//spider/runtime/instr/InstrMap.cpp\n", + " Size : 34,157 bytes\n", + " Array entries : 512 (128 populated, 384 nullptr)\n", + " Switch cases : 128\n", + " Line endings : LF-only verified\n" + ] + } + ], + "source": [ + "# ── Generate InstrMap.cpp ────────────────────────────────────────────────────\n", + "# Produces two dispatch implementations in one file:\n", + "# 1. CPUInstr InstrMap[512] — array of member-function pointers\n", + "# 2. void CPU::execute(u16) — switch/case version\n", + "#\n", + "# Both use UPPERCASE method names matching the mnemonic column.\n", + "\n", + "TABLE_SIZE = 512 # 9-bit opcode space\n", + "\n", + "# Build opcode -> mnemonic lookup from the cleaned instruction DataFrame.\n", + "opcode_to_mnem: dict[int, str] = {}\n", + "opcode_to_name: dict[int, str] = {}\n", + "opcode_to_group: dict[int, str] = {}\n", + "\n", + "for _, row in instrs_df.iterrows():\n", + " bc = str(row['byte_code']).strip()\n", + " opc = int(bc, 16)\n", + " opcode_to_mnem[opc] = str(row['mnemonic']).strip()\n", + " opcode_to_name[opc] = str(row['name']).strip()\n", + " opcode_to_group[opc] = str(row['group']).strip()\n", + "\n", + "# Also track reserved slots for annotation.\n", + "reserved_opcodes: set[int] = set()\n", + "for _, row in reserved_df.iterrows():\n", + " bc = str(row['byte_code']).strip()\n", + " if bc and bc != 'nan':\n", + " reserved_opcodes.add(int(bc, 16))\n", + "\n", + "# ── Assemble the file ───────────────────────────────────────────────────────\n", + "L = []\n", + "L.append('/**')\n", + "L.append(' * @file InstrMap.cpp')\n", + "L.append(' * @brief Spider VM instruction dispatch — array and switch implementations.')\n", + "L.append(' *')\n", + "L.append(' * AUTO-GENERATED by pygen.ipynb — DO NOT EDIT BY HAND.')\n", + "L.append(' *')\n", + "L.append(' * This file provides two equivalent dispatch mechanisms:')\n", + "L.append(' *')\n", + "L.append(' * 1. InstrMap[] — A lookup table of member-function pointers indexed by')\n", + "L.append(' * opcode. O(1) dispatch; suitable for platforms where')\n", + "L.append(' * indirect calls through function pointers are efficient.')\n", + "L.append(' *')\n", + "L.append(' * 2. CPU::execute(u16) — A switch/case over every opcode. Lets the')\n", + "L.append(' * compiler emit a jump table or branch tree; may be')\n", + "L.append(' * preferable on microcontrollers or when link-time')\n", + "L.append(' * optimisation can inline the handlers.')\n", + "L.append(' *')\n", + "L.append(' */')\n", + "L.append('') # [CHANGE] Use absolute path to make paths more explicit\n", + "L.append('#include ')\n", + "L.append('')\n", + "L.append('namespace spider {')\n", + "L.append('')\n", + "\n", + "# ── Version 1: Array: ────────────────────────────────────────────────────────\n", + "L.append('// =============================================================')\n", + "L.append('// Version 1 — Lookup table of member-function pointers')\n", + "L.append('// =============================================================')\n", + "L.append('')\n", + "# [CHANGE] Use CPU::Fn Instead\n", + "#L.append('/** Pointer-to-member type for a zero-argument CPU instruction. */')\n", + "#L.append('using CPUInstr = void (CPU::*)();')\n", + "L.append('')\n", + "L.append('/**')\n", + "L.append(f' * Instruction dispatch table ({TABLE_SIZE} entries, 9-bit opcode space).')\n", + "L.append(' *')\n", + "L.append(' * Usage:')\n", + "L.append(' * u16 opcode = fetch();')\n", + "L.append(' * CPU::Fn fn = InstrMap[opcode];')\n", + "L.append(' * if (fn) (cpu.*fn)();')\n", + "L.append(' */') # [CHANGE] Made it part of the CPU & avoided explicit size.\n", + "L.append(f'CPU::Fn CPU::instrMap[] = {{')\n", + "\n", + "for opc in range(TABLE_SIZE):\n", + " mnem = opcode_to_mnem.get(opc)\n", + " if mnem:\n", + " name = opcode_to_name[opc]\n", + " L.append(f' &CPU::{mnem + \",\":<28s}// 0x{opc:03X} — {name}')\n", + " else:\n", + " tag = ''\n", + " if opc in reserved_opcodes:\n", + " tag = ' (reserved)'\n", + " L.append(f' {\"nullptr,\":<28s}// 0x{opc:03X}{tag}')\n", + "\n", + "L.append('};')\n", + "L.append('')\n", + "L.append('')\n", + "\n", + "# ── Version 2: Switch ──────────────────────────────────────────────────────\n", + "L.append('// =============================================================')\n", + "L.append('// Version 2 — Switch dispatch')\n", + "L.append('// =============================================================')\n", + "L.append('')\n", + "L.append('/**')\n", + "L.append(' * Execute the instruction identified by @p opcode.')\n", + "L.append(' *')\n", + "L.append(' * This is functionally equivalent to the InstrMap[] table above')\n", + "L.append(' * but expressed as a switch so the compiler can choose the best')\n", + "L.append(' * lowering strategy (jump table, binary search, etc.).')\n", + "L.append(' *')\n", + "L.append(' * @param opcode 9-bit instruction opcode (0x000 - 0x1FF).')\n", + "L.append(' */')\n", + "L.append('void CPU::executeSwLk() {')\n", + "L.append(' switch (_opcode) {')\n", + "\n", + "last_group = None\n", + "for opc in sorted(opcode_to_mnem.keys()):\n", + " mnem = opcode_to_mnem[opc]\n", + " group = opcode_to_group[opc]\n", + " if group != last_group:\n", + " L.append('')\n", + " L.append(f' // ── {group} ' + '─' * max(1, 44 - len(group)))\n", + " last_group = group\n", + " L.append(f' case 0x{opc:03X}: {mnem}(); break;')\n", + "\n", + "L.append('')\n", + "L.append(' default:')\n", + "L.append(' break;')\n", + "L.append(' }')\n", + "L.append('}')\n", + "L.append('')\n", + "L.append('} // namespace spider')\n", + "L.append('')\n", + "\n", + "INSTRMAP_SRC = '\\n'.join(L)\n", + "\n", + "# ── Write to file ───────────────────────────────────────────────────────────\n", + "# [CHANGE] Write this in the instructions folder to avoid CPU file bloat\n", + "INSTRMAP_PATH = f'{SRC_ROOT}/spider/runtime/instr/InstrMap.cpp'\n", + "\n", + "with open(INSTRMAP_PATH, 'wb') as f:\n", + " f.write(INSTRMAP_SRC.encode('utf-8'))\n", + "\n", + "# Verify LF-only\n", + "with open(INSTRMAP_PATH, 'rb') as f:\n", + " raw_bytes = f.read()\n", + "assert b'\\r' not in raw_bytes, 'CRLF detected in InstrMap.cpp!'\n", + "\n", + "array_count = INSTRMAP_SRC.count('&CPU::')\n", + "switch_count = INSTRMAP_SRC.count('case 0x')\n", + "\n", + "print(f'InstrMap.cpp written to: {INSTRMAP_PATH}')\n", + "print(f' Size : {len(raw_bytes):,} bytes')\n", + "print(f' Array entries : {TABLE_SIZE} ({array_count} populated, {TABLE_SIZE - array_count} nullptr)')\n", + "print(f' Switch cases : {switch_count}')\n", + "print(f' Line endings : LF-only verified')\n" + ] } ], "metadata": { diff --git a/spider-runtime.code-workspace b/spider-runtime.code-workspace index 33de8c3..07b9241 100644 --- a/spider-runtime.code-workspace +++ b/spider-runtime.code-workspace @@ -15,6 +15,7 @@ ], "C_Cpp.default.includePath": [ "./src" - ] + ], + "terminal.integrated.defaultProfile.windows": "MSYS2 UCRT" } } \ No newline at end of file diff --git a/src/spider/SpiderRuntime.cpp b/src/spider/SpiderRuntime.cpp index 5151a6b..8c84608 100644 --- a/src/spider/SpiderRuntime.cpp +++ b/src/spider/SpiderRuntime.cpp @@ -1,14 +1,18 @@ #include "SpiderRuntime.hpp" +#include + #include namespace spider { + const u32 RUNTIME_VERSION_NO = 0x00000000; // v0.1 + const std::string RUNTIME_VERSION = "alpha v0.1"; } int main() { - std::cout << "Hello World" << std::endl; + spider::liveDebugMain(); return 0; } diff --git a/src/spider/SpiderRuntime.hpp b/src/spider/SpiderRuntime.hpp index 6f87fd0..744b6e2 100644 --- a/src/spider/SpiderRuntime.hpp +++ b/src/spider/SpiderRuntime.hpp @@ -4,6 +4,9 @@ namespace spider { + extern const u32 RUNTIME_VERSION_NO; + extern const std::string RUNTIME_VERSION; + class Runtime; class CPU; class RAM; diff --git a/src/spider/runtime/Runtime.cpp b/src/spider/runtime/Runtime.cpp index 461f093..e46bfc4 100644 --- a/src/spider/runtime/Runtime.cpp +++ b/src/spider/runtime/Runtime.cpp @@ -4,17 +4,33 @@ namespace spider { // Constructors & Destructors // - Runtime::Runtime() : ram(0) {} + Runtime::Runtime() : Runtime(0) {} - Runtime::Runtime(u64 ramSize) : ram(ramSize) {} + Runtime::Runtime(u64 ramSize) : ram(ramSize), reel(nullptr) { + cpu.hookRAM(&ram); + } - Runtime::~Runtime() {} + Runtime::~Runtime() { + delete reel; + } // Stepping/Running the Machine // - void Runtime::step() {} + void Runtime::step() { + cpu.fetchInstr(); + // TODO: Call instruction + } - void Runtime::step(u64 n) {} + void Runtime::step(u64 n) { + while(n >= 4) { + step(); + step(); + step(); + step(); + n -= 4; + } + while (n--) step(); + } void Runtime::run() {} @@ -26,4 +42,12 @@ namespace spider { ram.resize(length); } + /** + * Non-owning reel setup. + */ + void Runtime::hookReel(InstrReel* reel, bool own) { + cpu.hookInstrReel(reel); + if(own) this->reel = reel; + } + } diff --git a/src/spider/runtime/Runtime.hpp b/src/spider/runtime/Runtime.hpp index c4dc9c8..dba8bbc 100644 --- a/src/spider/runtime/Runtime.hpp +++ b/src/spider/runtime/Runtime.hpp @@ -1,8 +1,11 @@ #pragma once #include + #include +#include + namespace spider { /** @@ -10,10 +13,11 @@ namespace spider { * This is where the Spider VM (Runtime) lives */ class Runtime { - private: + public: CPU cpu; RAM ram; + InstrReel* reel; public: @@ -68,6 +72,11 @@ namespace spider { */ void resizeRAM(u64 length); + /** + * Non-owning reel setup. + */ + void hookReel(InstrReel* reel, bool own = false); + }; } diff --git a/src/spider/runtime/common.hpp b/src/spider/runtime/common.hpp index 67f8ed8..d8f3d61 100644 --- a/src/spider/runtime/common.hpp +++ b/src/spider/runtime/common.hpp @@ -5,9 +5,11 @@ #include #include #include +#include namespace spider { + // Absolute Types using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; @@ -25,6 +27,9 @@ namespace spider { 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; diff --git a/src/spider/runtime/cpu/CPU.cpp b/src/spider/runtime/cpu/CPU.cpp index e69de29..3308b8f 100644 --- a/src/spider/runtime/cpu/CPU.cpp +++ b/src/spider/runtime/cpu/CPU.cpp @@ -0,0 +1,214 @@ +#include "CPU.hpp" + +#include + +#include +#include + +#include + +#if __cplusplus >= 202002L +#include +#endif + +namespace spider { + + CPU::CPU() + : RA{}, RB{}, RC{}, RD{}, + RX{}, RY{}, R0{}, R1{}, + R2{}, R3{}, R4{}, R5{}, + R6{}, R7{}, R8{}, R9{}, + RF{}, RI{}, RS{}, RZ{}, + RE{}, RN{}, RV{}, RM{}, + ALU0{}, ALU1{}, + _dst(nullptr), _src(nullptr), + _opcode(0), _addrm(0), _size(0), + _store(0), _post(&CPU::imp), + _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 + } + + // Interaction with Reel // + + CPU::Fn CPU::addrModes[] = { + &CPU::imm, &CPU::abs, + &CPU::reg, &CPU::ind, + &CPU::ptr, &CPU::idx, + &CPU::sca, &CPU::dis + }; + + void CPU::fetchInstr() { + u16 i = _reel->readU16(RI); + _opcode = (i >> 7) & 0x1FF; + _addrm = (i >> 2) & 0x1F; + _size = i & 0x3; + RI += 2; + } + + void CPU::fetchOperDst() { + // Move the operand ptrs + _alu = &ALU0; + _opers[1] = _opers[0]; + + // call specific addressing mode + (this->*(CPU::addrModes[_addrm]))(); + } + + void CPU::fetchOperSrc() { + // set ALU + _alu = &ALU1; + + // call specific addressing mode + (this->*(CPU::addrModes[_addrm]))(); + + // modify the _addrm register + _addrm >>= 3; + _addrm++; + } + + void CPU::execute() { + (this->*(CPU::addrModes[_opcode]))(); + } + + // Addressing Modes // + + /** + * Implied Addressing Mode + */ + void CPU::imp() { + // Nothing // + } + + /** + * Immediate Addressing Mode + */ + void CPU::imm() { + switch(_size) { + case 0b00: + _alu->_u8 = _reel->readU8(RI); + break; + case 0b01: + _alu->_u16 = _reel->readU16(RI); + break; + case 0b10: + _alu->_u32 = _reel->readU32(RI); + break; + case 0b11: + _alu->_u64 = _reel->readU64(RI); + break; + } + + _opers[0] = _alu; + _post = &CPU::imp; + RI += 1 << _size; + } + + /** + * Absolute Addressing Mode + */ + void CPU::abs() { // TODO cache ptr size + u8 dat_size = 1 << _size; + u8 ptr_size = 1 << getFlag(CPU::FLAG_MEMORY_MODE); + u64 ptr = 0; + + if(ptr_size + dat_size > _ram->size()) return; // TODO: avoid overflow + + switch(ptr_size) { + case 1: + ptr = _reel->readU8(RI); + break; + case 2: + ptr = _reel->readU16(RI); + break; + case 4: + ptr = _reel->readU32(RI); + break; + case 8: + ptr = _reel->readU64(RI); + break; + } + + switch(_size) { + case 0b00: + spider::loadLE(&_alu->_u8, &(*_ram)[ptr]); + break; + case 0b01: + spider::loadLE(&_alu->_u16, &(*_ram)[ptr]); + break; + case 0b10: + spider::loadLE(&_alu->_u32, &(*_ram)[ptr]); + break; + case 0b11: + spider::loadLE(&_alu->_u64, &(*_ram)[ptr]); + break; + } + + RI += dat_size; + } + + /** + * Register Addressing Mode + */ + void CPU::reg() { + + } + + /** + * 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() {} + + /** + * Post Write Action + */ + void CPU::psw() {} + +} diff --git a/src/spider/runtime/cpu/CPU.hpp b/src/spider/runtime/cpu/CPU.hpp index 0431c1f..a2e8aa5 100644 --- a/src/spider/runtime/cpu/CPU.hpp +++ b/src/spider/runtime/cpu/CPU.hpp @@ -1,15 +1,36 @@ #pragma once +#include #include namespace spider { class CPU { + public: // Helper types + using Fn = void (CPU::*)(); + + public: // Flag Register Constants // + static constexpr const u64 FLAG_ENABLE = 0b0000000000000000000000000000000000000000000000000000000000000001; + static constexpr const u64 FLAG_INTERRUPT_SIGNAL = 0b0000000000000000000000000000000000000000000000000000000000000010; + static constexpr const u64 FLAG_INTERRUPT_REQUEST = 0b0000000000000000000000000000000000000000000000000000000000000100; + static constexpr const u64 FLAG_EXCEPTION = 0b0000000000000000000000000000000000000000000000000000000000001000; + static constexpr const u64 FLAG_MEMORY_MODE = 0b0000000000000000000000000000000000000000000000000000000000110000; + + public: // Map of addressing modes & Instructions + + static CPU::Fn addrModes[]; + static CPU::Fn instrMap[]; + public: // General Purpose Registers - register_t RA, RB, RC, RD, - RX, RY, R0, R1, - R2, R3, R4, R5, - R6, R7, R8, R9; + union { + register_t GPR[16]; + struct { + register_t RA, RB, RC, RD, + RX, RY, R0, R1, + R2, R3, R4, R5, + R6, R7, R8, R9; + }; + }; public: // System Registers u64 RF; @@ -31,6 +52,55 @@ namespace spider { */ register_t ALU0, ALU1; + union { + struct { + register_t* _dst; + register_t* _src; + register_t* _alu; + }; + register_t* _opers[2]; + }; + + // Holds the current instruction opcode + u16 _opcode : 9; + + // Holds the current addressing modes, + // before they were used + u8 _addrm : 5; + + // Holds the current instruction size. + u8 _size : 2; + + // On _post that are not no-ops, it must + // write back DST to this memory location. + u64 _store; + + // Post execution callback + CPU::Fn _post; + + private: + + /** + * Pointer to the current RAM hooked into + * the CPU. + * + * It is unproved whether having the RAM directly + * into the CPU is better than not, or whether a + * virtual BUS is better. + * + * Alas, this way we can have a CPU state switch + * between memory and instruction banks. + */ + RAM* _ram; + + /** + * Pointer to the current Instruction Reel + * hooked into the CPU. + * + * Ditto as RAM. + */ + InstrReel* _reel; + public: CPU(); @@ -47,6 +117,122 @@ namespace spider { CPU& operator=(CPU&& other) noexcept = default; + public: + + void hookRAM(RAM* ram); + + void hookInstrReel(InstrReel* reel); + + constexpr u64 getFlag(u64 mask); + + public: + + /** + * Fetches the instruction from the + * reel, and advances IR by two. + */ + void fetchInstr(); + + /** + * Fetches the destination operand, + * by calling the appropriate addressing + * mode. + * + * Will read the bottom 3 bits. + * For instructions with two operands, + * call Src first. + * + * The internal variable _addrm + * will not be modified. It will + * be important when writing + * back the result. + */ + void fetchOperDst(); + + /** + * Fetches the source operand. + * + * For use in two operand instructions. + * + * Will read the bottom 3 bits. It will + * then shift the _addrm 3 spaces + * to ensure it aligns with the DST + * next. + * + * Additionally, it will add 1 to _addrm + * to account with + */ + void fetchOperSrc(); + + /** + * Executes an opcode, by means of directly + * accessing the instruction map and + * calling that function pointer. + */ + void execute(); + + /** + * Executes an opcode, by means of using + * a large switch statement. Only suitable + * for environments where the instruction + * map is not possible. + * + * This has yet to be proved!!! + */ + void executeSwLk(); + + public: // Addressing Modes + + /** + * Implied Addressing Mode + */ + void imp(); // Kept as it is a no-op + + /** + * Immediate Addressing Mode + */ + void imm(); + + /** + * Absolute Addressing Mode + */ + void abs(); + + /** + * Register Addressing Mode + */ + void reg(); + + /** + * Indrect Addressing Mode + */ + void ind(); + + /** + * Pointer Addressing Mode + */ + void ptr(); + + /** + * Indexed Addressing Mode + */ + void idx(); + + /** + * Scaled Addressing Mode + */ + void sca(); + + /** + * Displaced Addressing Mode + */ + void dis(); + + /** + * Post-Write Action + */ + void psw(); + public: // // @@ -66,327 +252,327 @@ namespace spider { void MMODE(); // [System] 0x003 — INT: Interrupt - // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 08 // Operation: Performs system interrupt no. (Dst) (See table) void INT(); // [System] 0x004 — LRV: Load Interrupt Vector Register - // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0C + // Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 08 // Operation: Dst -> RV void LRV(); // [System] 0x005 — FSR: Fetch System Register - // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 08 // Operation: System Register at Dst -> Dst void FSR(); // [System] 0x006 — FIR: Fetch Instruction Register - // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 08 // Operation: Instruction Register -> Dst void FIR(); // [System] 0x007 — FZR: Fetch Stack Base Register - // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 08 // Operation: Stack Base Register -> Dst void FZR(); // [System] 0x008 — LSR: Load System Register - // Params: 2 | AddrMask1: 1E AddrMask2: 1F | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: 1F | TypeMask: 08 // Operation: Src -> System Register at Dst void LSR(); // [System] 0x009 — FVR: Fetch Interrupt Vector Register - // Params: 1 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: 04 AddrMask2: 00 | TypeMask: 08 // Operation: Interrupt Vector Register -> Dst void FVR(); // [Memory] 0x00A — MOV: Moves values - // Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Src -> Dst void MOV(); // [Memory] 0x00B — MOR: Moves registers - // Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 04 AddrMask2: 04 | TypeMask: 08 // Operation: R Scr -> R Dst void MOR(); // [Memory] 0x00C — AMOV: Array Move, uses X and Y as ptrs, A as amount - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 08 // Operation: Array from X to Y, by A amount void AMOV(); // [Memory] 0x00D — SWP: Swap registers - // Params: 2 | AddrMask1: 04 AddrMask2: 04 | TypeMask: 00 + // Params: 2 | AddrMask1: 04 AddrMask2: 04 | TypeMask: 08 // Operation: Src <-> Dst void SWP(); // [Memory] 0x00E — AHM: Ask Host for Memory - // Params: 1 | AddrMask1: 04 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: 04 AddrMask2: 00 | TypeMask: 08 // Operation: Asks the host for a specific size of memory. Responds with 0 or 1 void AHM(); // [Integer] 0x010 — COM: One's complement - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: ~ Dst -> Dst void COM(); // [Integer] 0x011 — NEG: Two's complement - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: - Dst -> Dst void NEG(); // [Integer] 0x012 — EXS: Extend Sign - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Last bit is copied and expanded for the next int size void EXS(); // [Integer] 0x013 — INC: Increment - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst + 1 -> Dst void INC(); // [Integer] 0x014 — DEC: Decrement - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst - 1 -> Dst void DEC(); // [Integer] 0x015 — ADD: Addition - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst + Src -> Dst void ADD(); // [Integer] 0x016 — SUB: Subtraction - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst - Src-> Dst void SUB(); // [Integer] 0x017 — MUL: Multiplication - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Signed Dst * Src -> Dst void MUL(); // [Integer] 0x018 — UMUL: Unsigned Multiplication - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Unsigned Dst * Src -> Dst void UMUL(); // [Integer] 0x019 — DIV: Division - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Signed Dst / Src -> Dst void DIV(); // [Integer] 0x01A — UDIV: Unsigned Division - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Unsigned Dst / Src -> Dst void UDIV(); // [Integer] 0x01B — MOD: Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Signed Dst % Src -> Dst void MOD(); // [Integer] 0x01C — UMOD: Unsigned Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Unsigned Dst % Src -> Dst void UMOD(); // [Integer] 0x01D — DMOD: Division and Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Signed Dst / Src -> X, Dst % Src -> Y void DMOD(); // [Integer] 0x01E — UDMD: Unsigned Division and Modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Unsigned Dst / Src -> X, Dst % Src -> Y void UDMD(); // [System] 0x01F — FBT: Test and update Flag Register (Integer) Bits - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Flags of Dst - void FBT(); // [Bit Wise] 0x020 — STB: Set Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Src# bit is set on Dst void STB(); // [Bit Wise] 0x021 — CRB: Clear Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Src# bit is cleared on Dst void CRB(); // [Bit Wise] 0x022 — TSB: Test Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Src# bit is tested against Dst, updates Equal Flag void TSB(); // [Bit Wise] 0x023 — BOOL: Sets the booleaness of a value - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Tests Dst != 0, updates Equal Flag void BOOL(); // [Bit Wise] 0x024 — NOT: Sets the inverse booleaness of a value (! BOOL) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Tests Dst == 0, updates Equal Flag void NOT(); // [Bit Wise] 0x025 — AND: Boolean AND operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst AND Src into Dst void AND(); // [Bit Wise] 0x026 — OR: Boolean OR operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst OR Src into Dst void OR(); // [Bit Wise] 0x027 — XOR: Boolean XOR operation - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst XOR Src into Dst void XOR(); // [Bit Wise] 0x028 — SHL: Arithmetic Shift Left - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst << Src into Dst void SHL(); // [Bit Wise] 0x029 — SHR: Arithmetic Shift Right - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst >> Src into Dst void SHR(); // [Bit Wise] 0x02A — SSR: Signed Shift Right - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst >>> Src into Dst void SSR(); // [Bit Wise] 0x02B — ROL: Rotate Left - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst ROL Src into Dst void ROL(); // [Bit Wise] 0x02C — ROR: Rotate Right - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst ROR Src into Dst void ROR(); // [Bit Wise] 0x02D — CNT: Counts bits - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: # of 1's into Dst void CNT(); // [Boolean] 0x030 — EQ: Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst == Src into Dst void EQ(); // [Boolean] 0x031 — NE: Not Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst != Src into Dst void NE(); // [Boolean] 0x032 — GT: Greater Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst > Src into Dst void GT(); // [Boolean] 0x033 — GE: Greater or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst >= Src into Dst void GE(); // [Boolean] 0x034 — LT: Lower Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst < Src into Dst void LT(); // [Boolean] 0x035 — LE: Lower or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst <= Src into Dst void LE(); // [Branch] 0x038 — JMP: Jump to absolute position - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst -> Instruction Register void JMP(); // [Branch] 0x039 — JEQ: Jumps to position if EQ flag is set - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst -> Instruction Register IF Flags.EQ void JEQ(); // [Branch] 0x03A — JNE: Jumps to position if EQ flag is cleared - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst -> Instruction Register IF NOT Flags.EQ void JNE(); // [Branch] 0x03B — JIF: Jumps if value provided is booleanly true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst -> Instruction Register IF Src void JIF(); // [Branch] 0x03C — JMR: Jump Relative - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst + Instruction Register -> Instruction Register void JMR(); // [Branch] 0x03D — JER: Jumps to relative position if EQ flag is set - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst + Instruction Register -> Instruction Register IF Flags.EQ void JER(); // [Branch] 0x03E — JNR: Jumps to relative position if EQ flag is cleared - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst + Instruction Register -> Instruction Register IF NOT Flags.EQ void JNR(); // [Branch] 0x03F — JIR: Jumps to relative position if value provided is booleanly true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: Dst + Instruction Register -> Instruction Register IF Src void JIR(); // [System] 0x040 — SFB: Store (User) Flag Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: void SFB(); // [System] 0x041 — LFB: Load (User) Flag Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: void LFB(); // [Branch] 0x042 — JUF: Jump to absolute position, if user flag is true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: void JUF(); // [Branch] 0x043 — JUR: Jump to relative position, if user flag is true - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Operation: void JUR(); // [Memory] 0x044 — PUSH: Push to stack - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst -> pushed into stack void PUSH(); // [Memory] 0x045 — POP: Pop from stack - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: popped from stack -> Dst void POP(); // [Memory] 0x046 — ALLOC: Allocate to heap - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Dst -> heap ptr of size Dst void ALLOC(); // [Memory] 0x047 — HFREE: Delete from heap - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Frees heap ptr in Dst void HFREE(); // [Branch] 0x04A — CALL: Call function at instruction index - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: Performs a function call, step XX void CALL(); @@ -396,207 +582,207 @@ namespace spider { void RET(); // [System] 0x04C — EDI: Enable/Disable External Interrupts - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: bool( Dst ) -> Enable External Interrupts Bit void EDI(); // [System] 0x04D — SHSS: Set Hotswap Signal Bit - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Operation: bool( Dst ) -> Hot Swap Signal Bit void SHSS(); // [Floating Point] 0x050 — FLI: Float Load Immediate - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: void FLI(); // [Floating Point] 0x051 — FNEG: Float negate - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: - Dst -> Dst void FNEG(); // [Floating Point] 0x052 — FADD: Float add - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst + Src -> Dst void FADD(); // [Floating Point] 0x053 — FSUB: Float subtract - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst - Src-> Dst void FSUB(); // [Floating Point] 0x054 — FMUL: Float multiplication - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst * Src -> Dst void FMUL(); // [Floating Point] 0x055 — FDIV: Float division - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst / Src -> Dst void FDIV(); // [Floating Point] 0x056 — FMOD: Float modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst % Src -> Dst void FMOD(); // [Floating Point] 0x057 — FDMOD: Float division and modulus - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst / Src -> X, Dst % Src -> Y void FDMOD(); // [Floating Point] 0x058 — FEPS: Sets the float epsilon value, for comparison - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: Dst -> Epsilon Register void FEPS(); // [Floating Point] 0x059 — FEEP: Float Enable/Disable Epsilon - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: bool( Dst ) -> Epsilon Enable Bit void FEEP(); // [Boolean] 0x05A — FEQ: Float Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst == Src into Dst void FEQ(); // [Boolean] 0x05B — FNE: Float Not Equal - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst != Src into Dst void FNE(); // [Boolean] 0x05C — FGT: Float Greater Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst > Src into Dst void FGT(); // [Boolean] 0x05D — FGE: Float Greater or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst >= Src into Dst void FGE(); // [Boolean] 0x05E — FLT: Float Lower Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst < Src into Dst void FLT(); // [Boolean] 0x05F — FLE: Float Lower or Equal Than - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: Dst <= Src into Dst void FLE(); // [Casts] 0x060 — F2D: F32 (Float) to F64 (Double) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void F2D(); // [Casts] 0x061 — D2F: F64 (Double) to F32 (Float) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void D2F(); // [Casts] 0x062 — I2F: I32 (Integer) to F32 (Float) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void I2F(); // [Casts] 0x063 — I2D: I32 (Integer) to F64 (Double) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void I2D(); // [Casts] 0x064 — L2F: I64 (Long) to F32 (Float) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void L2F(); // [Casts] 0x065 — L2D: I64 (Long) to F64 (Double) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void L2D(); // [Casts] 0x066 — F2I: F32 (Float) to I32 (Integer) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void F2I(); // [Casts] 0x067 — F2L: F32 (Float) to I64 (Long) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void F2L(); // [Casts] 0x068 — D2I: F64 (Double) to I32 (Integer) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void D2I(); // [Casts] 0x069 — D2L: F64 (Double) to I64 (Long) - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 00 // Operation: (cast) Dst -> Dst void D2L(); // [Trigonometric] 0x06C — SIN: Sine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: sin( Dst ) -> Dst void SIN(); // [Trigonometric] 0x06D — COS: Cosine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: cos( Dst ) -> Dst void COS(); // [Trigonometric] 0x06E — TAN: Tangent Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: tan( Dst ) -> Dst void TAN(); // [Trigonometric] 0x06F — ASIN: Arc Sine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: asin( Dst ) -> Dst void ASIN(); // [Trigonometric] 0x070 — ACOS: Arc Cosine Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: acos( Dst ) -> Dst void ACOS(); // [Trigonometric] 0x071 — ATAN: Arc Tangent Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: atan( Dst ) -> Dst void ATAN(); // [Trigonometric] 0x072 — ATAN2: Arc Tangent Function with 2 Arguments - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: atan( Dst, Src ) -> Dst void ATAN2(); // [Exponential] 0x074 — EXP: Exponential Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: exp( Dst ) -> Dst void EXP(); // [Exponential] 0x075 — LOG: Natural Logarithm - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: ln( Dst ) -> Dst void LOG(); // [Exponential] 0x076 — LOGAB: Logarithm A of B - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: log( Dst, Src ) -> Dst void LOGAB(); // [Exponential] 0x077 — POW: Power Function - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: pow( Dst, Src ) -> Dst void POW(); // [Exponential] 0x078 — SQRT: Square Root - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Operation: sqrt( Dst ) -> Dst void SQRT(); // [Exponential] 0x079 — ROOT: General Root - // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0C // Operation: pow( Dst, 1 / Src ) -> Dst void ROOT(); @@ -650,6 +836,16 @@ namespace spider { // Operation: void MDET(); + // [Quaternion] 0x086 — QMKA: Quaternion Make from Angles + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void QMKA(); + + // [Quaternion] 0x087 — QMUL: Quaternion Multiply + // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 + // Operation: + void QMUL(); + // [SIMD] 0x08A — XADD: SIMD Addition // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Operation: @@ -684,4 +880,4 @@ namespace spider { }; -} \ No newline at end of file +} diff --git a/src/spider/runtime/cpu/InstrReel.hpp b/src/spider/runtime/cpu/InstrReel.hpp deleted file mode 100644 index 5e2175f..0000000 --- a/src/spider/runtime/cpu/InstrReel.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -namespace spider { - - /** - * Implements an instruction reel. - */ - class InstrReel { - private: - - public: - - InstrReel(); - - ~InstrReel(); - - public: - - - - public: - - /** - * Returns the two-byte instruction at the - * specific byte location. - */ - u16 instrAt(u64 ip) const; - - /** - * Obtains a byte of data at - * the specific location. - */ - u8 dataAt(u64 ip) const; - - public: - - /** - * Fetches the data, and then - * feeds the instruction into the - * CPU. - * - * Returns how many steps it should - * move after. - */ - u8 feedNext(CPU& cpu); - - public: // Static Utils // - - static u16 unpackInstr(u16 bcode); - - static u8 unpackAddrMode(u16 bcode); - - static u8 unpackTypeSize(u16 bcode); - - }; - -} diff --git a/src/spider/runtime/cpu/Register.hpp b/src/spider/runtime/cpu/Register.hpp index a2acdd5..2948e22 100644 --- a/src/spider/runtime/cpu/Register.hpp +++ b/src/spider/runtime/cpu/Register.hpp @@ -23,21 +23,25 @@ namespace spider { f64 _f64; u8 _bytes[8]; - SPIDER_PACKED_STRUCT(struct { + struct { #if SPIDER_LITTLE_ENDIAN - u8 _u8; u64 : 56; + u8 _u8; // This looks like a cruel joke + u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; #else - u64 : 56; u8 _u8; + u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; u8 : 8; + u8 _u8; #endif - }); + }; - SPIDER_PACKED_STRUCT(struct { + struct { #if SPIDER_LITTLE_ENDIAN - u16 _u16; u64 : 48; + u16 _u16; + u16 : 16; u16 : 16; u16 : 16; #else - u64 : 48; u16 _u16; + u16 : 16; u16 : 16; u16 : 16; + u16 _u16; #endif - }); + }; struct { #if SPIDER_LITTLE_ENDIAN diff --git a/src/spider/runtime/debug/LiveDebug.cpp b/src/spider/runtime/debug/LiveDebug.cpp new file mode 100644 index 0000000..8e80d5c --- /dev/null +++ b/src/spider/runtime/debug/LiveDebug.cpp @@ -0,0 +1,404 @@ +#include "LiveDebug.hpp" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +namespace spider { + + void drawHead(Terminal& t) { + t.move(1, 1) + .style(Terminal::FG_YELLOW) + .print(" Spider Runtime Live Debug ") + .style(Terminal::RESET).print(" | ") + .style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ") + .style(Terminal::RESET).print(" | ") + .style(Terminal::FG_B_BLACK).print("Press ESC to exit") + .style(Terminal::FG_BLACK) + .style(Terminal::BG_YELLOW) + .move(3, 1).print(" // __ \\\\").print(" ") // 27 + .move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ") + .move(5, 1).print(" //()\\\\ ").print(" alpha ") + .move(6, 1).print(" \\\\ // ").print(" ") + .style(Terminal::RESET) + .style(Terminal::FG_B_BLACK) // 4x8 for the menu + .move(3, 28).print("[ STEP ]") + .move(4, 28).print("[ STOP ]") + .move(5, 28).print("[ RUN ]") + .move(6, 28).print("[ MENU ]") + .style(Terminal::RESET) + ; + } + + void drawCPUTempl(Terminal& t, CPU& cpu) { + i32 r = 8, c = 1; + i32 w = 35, h = 31; + t.drawBox(r, c, w, h, "CPU"); + + const std::string regs[] = { + "RA", "RB", "RC", "RD", + "RX", "RY", "R0", "R1", + "R2", "R3", "R4", "R5", + "R6", "R7", "R8", "R9", + "RF", "RI", "RS", "RZ", + "RE", "RN", "RV", "RM", + "ALU0", "ALU1" + }; + const std::string alt[] = { + Terminal::FG_WHITE, + Terminal::FG_B_BLACK, + }; + + r++; + c++; + + t.move(r++, c); + t.style(Terminal::FG_B_YELLOW); + t.print_center(w - 2, "GP Registers"); + t.style(Terminal::RESET); + for (i32 i = 0; i < 8; i++) { + t.style(alt[i & 1]); + t.move(r + i * 2, c); + t.print(regs[i * 2]); + t.move(r + i * 2, c + 17); + t.print(regs[i * 2 + 1]); + } + + t.move(r += 16, c); + t.style(Terminal::FG_B_CYAN); + t.print_center(w - 2, "System Registers"); + t.style(Terminal::RESET); + r++; + for (i32 j = 0, i = 8; i < 12; j++, i++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + t.print(regs[i * 2]); + t.move(r + j * 2, c + 17); + t.print(regs[i * 2 + 1]); + } + + t.move(r += 8, c); + t.style(Terminal::FG_GREEN); + t.print_center(w - 2, "Extra Registers"); + t.style(Terminal::RESET); + r++; + for (i32 j = 0, i = 12; i < 13; j++, i++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + t.print(regs[i * 2]); + t.move(r + j * 2, c + 17); + t.print(regs[i * 2 + 1]); + } + + t.flush(); + } + + void printU64Hex(u64 n) { + std::ios state(nullptr); + state.copyfmt(std::cout); + std::cout + << std::hex + << std::uppercase + << std::setfill('0') + << std::setw(16) + << n; + std::cout.copyfmt(state); + } + + void drawCPU(Terminal& t, CPU& cpu) { + i32 r = 8, c = 1; + + const register_t* regs[] = { + &cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD, + &cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1, + &cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5, + &cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9, + //&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ, + //&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM, + &cpu.ALU0, &cpu.ALU1 + }; + const u64* sys_regs[] = { + &cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ, + &cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM, + }; + const std::string alt[] = { + Terminal::FG_WHITE, + Terminal::FG_B_BLACK, + }; + + r++; + c++; + t.move(r++, c); + t.style(Terminal::RESET); + r++; + for (i32 i = 0; i < 8; i++) { + t.style(alt[i & 1]); + t.move(r + i * 2, c); + printU64Hex(regs[i * 2]->_u64); + t.move(r + i * 2, c + 17); + printU64Hex(regs[i * 2 + 1]->_u64); + } + + t.move(r += 16, c); + r++; + for (i32 j = 0; j < 4; j++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + printU64Hex(*sys_regs[j * 2]); + t.move(r + j * 2, c + 17); + printU64Hex(*sys_regs[j * 2 + 1]); + } + + t.move(r += 8, c); + r++; + for (i32 j = 0; j < 1; j++) { + t.style(alt[j & 1]); + t.move(r + j * 2, c); + printU64Hex(regs[16 + j * 2]->_u64); + t.move(r + j * 2, c + 17); + printU64Hex(regs[16 + j * 2 + 1]->_u64); + } + + t.flush(); + } + + i32 addressWidth(isize ramSize) { + if (ramSize == 0) return 1; + isize maxAddr = ramSize - 1; + i32 digits = 0; + // Shift by increments of 4 (one hex nibble) + // We use a do-while to ensure at least 1 digit is returned for small RAMs + do { + digits++; + maxAddr >>= 4; + } while (maxAddr > 0); + + return digits; + } + + /** + * Draws a vertical scrollbar + * @param x The column where the bar should be placed (usually box_x + width - 1) + * @param y The starting row of the track (usually box_y + 1) + * @param trackHeight The internal height of the box (box_height - 2) + * @param progress The current progress + * @param total The total + */ + void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) { + if (total == 0 || trackHeight <= 0) return; + + // 1. Draw the background track (Light Shade: ░) + term.style(Terminal::FG_B_BLACK); // Dim the track + for (int i = 0; i < trackHeight; ++i) { + term.move(y + i, x).print("░"); + } + + // 2. Calculate Thumb Position + // Cap progress to total to avoid overflow + if (progress > total) progress = total; + + // Calculate ratio (0.0 to 1.0) + f64 ratio = f64(progress) / f64(total); + + // Map to track coordinates + i32 thumbOffset = i32(ratio * (trackHeight - 1)); + + // 3. Draw the Thumb (Full Block: █) + term.move(y + thumbOffset, x); + term.style(Terminal::FG_WHITE).print("█"); + term.style(Terminal::RESET); + } + + /** + * Draws a hex dump of memory within a styled terminal box. + * @param term Reference to your Terminal instance + * @param ram The RAM + * @param scrollPos The starting address to display + * @param x Starting column + * @param y Starting row + * @param width Width of the box + * @param height Height of the box + */ + void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) { + // 1. Draw the container box + i32 y = 3; + i32 height = 36; + + // 2. Configuration for the hex layout + int addrWidth = addressWidth(ram.size()); + int bytesPerRow = 8; + int displayRows = height - 2; // Subtract top/bottom borders + i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth; + i32 x = 37; + + // create box + term.drawBox(y, x, width, height, "RAM"); + drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size()); + + // Ensure scrollPos is within bounds and aligned + if (scrollPos < 0) scrollPos = 0; + if (scrollPos > ram.size()) scrollPos = ram.size(); + + for (int i = 0; i < displayRows; ++i) { + isize currentRowAddr = scrollPos + (i * bytesPerRow); + + // address lock + if (currentRowAddr >= ram.size()) { + term.move(y + 1 + i, x + 1); + term.print(std::string(width - 3, ' ')); + continue; + } + + std::stringstream ssaddr; + std::stringstream ss; + + // setup ss + ssaddr << std::setfill('0') << std::uppercase << std::hex; + ss << std::setfill('0') << std::uppercase << std::hex; + + // address + ssaddr << std::setw(addrWidth) << currentRowAddr << " "; + + // Hex Bytes + std::string asciiPart = ""; + for (int j = 0; j < bytesPerRow; ++j) { + isize targetAddr = currentRowAddr + j; + if (targetAddr >= ram.size()) { + ss << ""; // Padding for end of memory + asciiPart += ""; + continue; + } + + u8 byte = ram[targetAddr]; + ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " "; + asciiPart += (std::isprint(byte) ? (char)byte : '.'); + } + + // --- Combine and Print --- + term.move(y + 1 + i, x + 2); // Move inside the box + term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan + term.style(Terminal::FG_WHITE).print(ss.str()); + term.style(Terminal::FG_B_YELLOW).print(" | "); + term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White + } + + term.style(Terminal::RESET); + term.flush(); + } + + std::string getTimestamp() { + std::time_t t = std::time(nullptr); + std::tm lt; +#if defined(SPIDER_OS_WINDOWS) + localtime_s(<, &t); +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + localtime_r(&t, <); +#endif + return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}", + lt.tm_hour, lt.tm_min, lt.tm_sec, + lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900); + } + + void drawTime(Terminal& t) { + //auto now = std::chrono::system_clock::now(); + //auto now_l = std::chrono::current_zone()->to_local(now); + //auto now_s = std::chrono::floor(now_l); + //std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss + //std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY + + t.move(1, 76); + t.style(Terminal::RESET); + t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp()); + } + + void redraw(Terminal& t, Runtime& r, u64 scroll) { + // draw CPU, RAM + drawCPU(t, r.cpu); + drawRAM(t, r.ram, scroll); + } + + int liveDebugMain() { + Terminal t; + Runtime runtime(1024); + InstrReelFixed fix(100); + runtime.ram[0] = 0xFF; + runtime.ram[1] = 0xEE; + runtime.ram[2] = 0xDD; + runtime.ram[3] = 0xCC; + runtime.ram[4] = 0xBB; + runtime.ram[5] = 0xAA; + runtime.ram[6] = 0x99; + runtime.ram[7] = 0x88; + fix.writeU16(0, 0b0000111); + runtime.hookReel(&fix, false); + + 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; + case Terminal::ENTER: + update = true; + runtime.cpu.fetchInstr(); + runtime.cpu.fetchOperDst(); + break; + default: + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + t.altbuff(false).println("Stopped Spider live debug.").flush(); + return 0; + } + +} diff --git a/src/spider/runtime/debug/LiveDebug.hpp b/src/spider/runtime/debug/LiveDebug.hpp new file mode 100644 index 0000000..69140cb --- /dev/null +++ b/src/spider/runtime/debug/LiveDebug.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace spider { + + int liveDebugMain(); + +} diff --git a/src/spider/runtime/instr/InstrMap.cpp b/src/spider/runtime/instr/InstrMap.cpp new file mode 100644 index 0000000..6d3e5de --- /dev/null +++ b/src/spider/runtime/instr/InstrMap.cpp @@ -0,0 +1,746 @@ +/** + * @file InstrMap.cpp + * @brief Spider VM instruction dispatch — array and switch implementations. + * + * AUTO-GENERATED by pygen.ipynb — DO NOT EDIT BY HAND. + * + * This file provides two equivalent dispatch mechanisms: + * + * 1. InstrMap[] — A lookup table of member-function pointers indexed by + * opcode. O(1) dispatch; suitable for platforms where + * indirect calls through function pointers are efficient. + * + * 2. CPU::execute(u16) — A switch/case over every opcode. Lets the + * compiler emit a jump table or branch tree; may be + * preferable on microcontrollers or when link-time + * optimisation can inline the handlers. + * + */ + +#include + +namespace spider { + +// ============================================================= +// Version 1 — Lookup table of member-function pointers +// ============================================================= + + +/** + * Instruction dispatch table (512 entries, 9-bit opcode space). + * + * Usage: + * u16 opcode = fetch(); + * CPU::Fn fn = InstrMap[opcode]; + * if (fn) (cpu.*fn)(); + */ +CPU::Fn CPU::instrMap[] = { + &CPU::NOP, // 0x000 — No Operation + &CPU::SPDR, // 0x001 — Will place the Spider version of the interpreter in RA + &CPU::MMODE, // 0x002 — Set Memory Mode + &CPU::INT, // 0x003 — Interrupt + &CPU::LRV, // 0x004 — Load Interrupt Vector Register + &CPU::FSR, // 0x005 — Fetch System Register + &CPU::FIR, // 0x006 — Fetch Instruction Register + &CPU::FZR, // 0x007 — Fetch Stack Base Register + &CPU::LSR, // 0x008 — Load System Register + &CPU::FVR, // 0x009 — Fetch Interrupt Vector Register + &CPU::MOV, // 0x00A — Moves values + &CPU::MOR, // 0x00B — Moves registers + &CPU::AMOV, // 0x00C — Array Move, uses X and Y as ptrs, A as amount + &CPU::SWP, // 0x00D — Swap registers + &CPU::AHM, // 0x00E — Ask Host for Memory + nullptr, // 0x00F (reserved) + &CPU::COM, // 0x010 — One's complement + &CPU::NEG, // 0x011 — Two's complement + &CPU::EXS, // 0x012 — Extend Sign + &CPU::INC, // 0x013 — Increment + &CPU::DEC, // 0x014 — Decrement + &CPU::ADD, // 0x015 — Addition + &CPU::SUB, // 0x016 — Subtraction + &CPU::MUL, // 0x017 — Multiplication + &CPU::UMUL, // 0x018 — Unsigned Multiplication + &CPU::DIV, // 0x019 — Division + &CPU::UDIV, // 0x01A — Unsigned Division + &CPU::MOD, // 0x01B — Modulus + &CPU::UMOD, // 0x01C — Unsigned Modulus + &CPU::DMOD, // 0x01D — Division and Modulus + &CPU::UDMD, // 0x01E — Unsigned Division and Modulus + &CPU::FBT, // 0x01F — Test and update Flag Register (Integer) Bits + &CPU::STB, // 0x020 — Set Bit + &CPU::CRB, // 0x021 — Clear Bit + &CPU::TSB, // 0x022 — Test Bit + &CPU::BOOL, // 0x023 — Sets the booleaness of a value + &CPU::NOT, // 0x024 — Sets the inverse booleaness of a value (! BOOL) + &CPU::AND, // 0x025 — Boolean AND operation + &CPU::OR, // 0x026 — Boolean OR operation + &CPU::XOR, // 0x027 — Boolean XOR operation + &CPU::SHL, // 0x028 — Arithmetic Shift Left + &CPU::SHR, // 0x029 — Arithmetic Shift Right + &CPU::SSR, // 0x02A — Signed Shift Right + &CPU::ROL, // 0x02B — Rotate Left + &CPU::ROR, // 0x02C — Rotate Right + &CPU::CNT, // 0x02D — Counts bits + nullptr, // 0x02E (reserved) + nullptr, // 0x02F (reserved) + &CPU::EQ, // 0x030 — Equal + &CPU::NE, // 0x031 — Not Equal + &CPU::GT, // 0x032 — Greater Than + &CPU::GE, // 0x033 — Greater or Equal Than + &CPU::LT, // 0x034 — Lower Than + &CPU::LE, // 0x035 — Lower or Equal Than + nullptr, // 0x036 (reserved) + nullptr, // 0x037 (reserved) + &CPU::JMP, // 0x038 — Jump to absolute position + &CPU::JEQ, // 0x039 — Jumps to position if EQ flag is set + &CPU::JNE, // 0x03A — Jumps to position if EQ flag is cleared + &CPU::JIF, // 0x03B — Jumps if value provided is booleanly true + &CPU::JMR, // 0x03C — Jump Relative + &CPU::JER, // 0x03D — Jumps to relative position if EQ flag is set + &CPU::JNR, // 0x03E — Jumps to relative position if EQ flag is cleared + &CPU::JIR, // 0x03F — Jumps to relative position if value provided is booleanly true + &CPU::SFB, // 0x040 — Store (User) Flag Bit + &CPU::LFB, // 0x041 — Load (User) Flag Bit + &CPU::JUF, // 0x042 — Jump to absolute position, if user flag is true + &CPU::JUR, // 0x043 — Jump to relative position, if user flag is true + &CPU::PUSH, // 0x044 — Push to stack + &CPU::POP, // 0x045 — Pop from stack + &CPU::ALLOC, // 0x046 — Allocate to heap + &CPU::HFREE, // 0x047 — Delete from heap + nullptr, // 0x048 (reserved) + nullptr, // 0x049 (reserved) + &CPU::CALL, // 0x04A — Call function at instruction index + &CPU::RET, // 0x04B — Return from a function + &CPU::EDI, // 0x04C — Enable/Disable External Interrupts + &CPU::SHSS, // 0x04D — Set Hotswap Signal Bit + nullptr, // 0x04E (reserved) + nullptr, // 0x04F (reserved) + &CPU::FLI, // 0x050 — Float Load Immediate + &CPU::FNEG, // 0x051 — Float negate + &CPU::FADD, // 0x052 — Float add + &CPU::FSUB, // 0x053 — Float subtract + &CPU::FMUL, // 0x054 — Float multiplication + &CPU::FDIV, // 0x055 — Float division + &CPU::FMOD, // 0x056 — Float modulus + &CPU::FDMOD, // 0x057 — Float division and modulus + &CPU::FEPS, // 0x058 — Sets the float epsilon value, for comparison + &CPU::FEEP, // 0x059 — Float Enable/Disable Epsilon + &CPU::FEQ, // 0x05A — Float Equal + &CPU::FNE, // 0x05B — Float Not Equal + &CPU::FGT, // 0x05C — Float Greater Than + &CPU::FGE, // 0x05D — Float Greater or Equal Than + &CPU::FLT, // 0x05E — Float Lower Than + &CPU::FLE, // 0x05F — Float Lower or Equal Than + &CPU::F2D, // 0x060 — F32 (Float) to F64 (Double) + &CPU::D2F, // 0x061 — F64 (Double) to F32 (Float) + &CPU::I2F, // 0x062 — I32 (Integer) to F32 (Float) + &CPU::I2D, // 0x063 — I32 (Integer) to F64 (Double) + &CPU::L2F, // 0x064 — I64 (Long) to F32 (Float) + &CPU::L2D, // 0x065 — I64 (Long) to F64 (Double) + &CPU::F2I, // 0x066 — F32 (Float) to I32 (Integer) + &CPU::F2L, // 0x067 — F32 (Float) to I64 (Long) + &CPU::D2I, // 0x068 — F64 (Double) to I32 (Integer) + &CPU::D2L, // 0x069 — F64 (Double) to I64 (Long) + nullptr, // 0x06A (reserved) + nullptr, // 0x06B (reserved) + &CPU::SIN, // 0x06C — Sine Function + &CPU::COS, // 0x06D — Cosine Function + &CPU::TAN, // 0x06E — Tangent Function + &CPU::ASIN, // 0x06F — Arc Sine Function + &CPU::ACOS, // 0x070 — Arc Cosine Function + &CPU::ATAN, // 0x071 — Arc Tangent Function + &CPU::ATAN2, // 0x072 — Arc Tangent Function with 2 Arguments + nullptr, // 0x073 (reserved) + &CPU::EXP, // 0x074 — Exponential Function + &CPU::LOG, // 0x075 — Natural Logarithm + &CPU::LOGAB, // 0x076 — Logarithm A of B + &CPU::POW, // 0x077 — Power Function + &CPU::SQRT, // 0x078 — Square Root + &CPU::ROOT, // 0x079 — General Root + nullptr, // 0x07A (reserved) + nullptr, // 0x07B (reserved) + &CPU::ADC, // 0x07C — Add with Carry + &CPU::SWC, // 0x07D — Subtract with Carry (Borrow) + &CPU::MWO, // 0x07E — Multiply with Overflow + &CPU::UMO, // 0x07F — Unsigned Multiply with Overflow + &CPU::MADD, // 0x080 — Matrix Addition + &CPU::MSUB, // 0x081 — Matrix Subtraction + &CPU::MMUL, // 0x082 — Matrix Multiply + &CPU::MINV, // 0x083 — Matrix Inverse + &CPU::MTRA, // 0x084 — Matrix Transpose + &CPU::MDET, // 0x085 — Matrix Determinant + &CPU::QMKA, // 0x086 — Quaternion Make from Angles + &CPU::QMUL, // 0x087 — Quaternion Multiply + nullptr, // 0x088 + nullptr, // 0x089 + &CPU::XADD, // 0x08A — SIMD Addition + &CPU::XSUB, // 0x08B — SIMD Subtract + &CPU::XAMA, // 0x08C — SIMD Alternate Multiply-Add + &CPU::XMUL, // 0x08D — SIMD Multiply + &CPU::XDIV, // 0x08E — SIMD Divide + nullptr, // 0x08F + nullptr, // 0x090 + nullptr, // 0x091 + nullptr, // 0x092 + nullptr, // 0x093 + nullptr, // 0x094 + nullptr, // 0x095 + nullptr, // 0x096 + nullptr, // 0x097 + nullptr, // 0x098 + nullptr, // 0x099 + nullptr, // 0x09A + nullptr, // 0x09B + nullptr, // 0x09C + nullptr, // 0x09D + nullptr, // 0x09E + nullptr, // 0x09F + nullptr, // 0x0A0 + nullptr, // 0x0A1 + nullptr, // 0x0A2 + nullptr, // 0x0A3 + nullptr, // 0x0A4 + nullptr, // 0x0A5 + nullptr, // 0x0A6 + nullptr, // 0x0A7 + nullptr, // 0x0A8 + nullptr, // 0x0A9 + nullptr, // 0x0AA + nullptr, // 0x0AB + nullptr, // 0x0AC + nullptr, // 0x0AD + nullptr, // 0x0AE + nullptr, // 0x0AF + nullptr, // 0x0B0 + nullptr, // 0x0B1 + nullptr, // 0x0B2 + nullptr, // 0x0B3 + nullptr, // 0x0B4 + nullptr, // 0x0B5 + nullptr, // 0x0B6 + nullptr, // 0x0B7 + nullptr, // 0x0B8 + nullptr, // 0x0B9 + nullptr, // 0x0BA + nullptr, // 0x0BB + nullptr, // 0x0BC + nullptr, // 0x0BD + nullptr, // 0x0BE + nullptr, // 0x0BF + nullptr, // 0x0C0 + nullptr, // 0x0C1 + nullptr, // 0x0C2 + nullptr, // 0x0C3 + nullptr, // 0x0C4 + nullptr, // 0x0C5 + nullptr, // 0x0C6 + nullptr, // 0x0C7 + nullptr, // 0x0C8 + nullptr, // 0x0C9 + nullptr, // 0x0CA + nullptr, // 0x0CB + nullptr, // 0x0CC + nullptr, // 0x0CD + nullptr, // 0x0CE + nullptr, // 0x0CF + nullptr, // 0x0D0 + nullptr, // 0x0D1 + nullptr, // 0x0D2 + nullptr, // 0x0D3 + nullptr, // 0x0D4 + nullptr, // 0x0D5 + nullptr, // 0x0D6 + nullptr, // 0x0D7 + nullptr, // 0x0D8 + nullptr, // 0x0D9 + nullptr, // 0x0DA + nullptr, // 0x0DB + nullptr, // 0x0DC + nullptr, // 0x0DD + nullptr, // 0x0DE + nullptr, // 0x0DF + nullptr, // 0x0E0 + nullptr, // 0x0E1 + nullptr, // 0x0E2 + nullptr, // 0x0E3 + nullptr, // 0x0E4 + nullptr, // 0x0E5 + nullptr, // 0x0E6 + nullptr, // 0x0E7 + nullptr, // 0x0E8 + nullptr, // 0x0E9 + nullptr, // 0x0EA + nullptr, // 0x0EB + nullptr, // 0x0EC + nullptr, // 0x0ED + nullptr, // 0x0EE + nullptr, // 0x0EF + &CPU::UPY, // 0x0F0 — Will place "YUPI" in memory + nullptr, // 0x0F1 + nullptr, // 0x0F2 + nullptr, // 0x0F3 + nullptr, // 0x0F4 + nullptr, // 0x0F5 + nullptr, // 0x0F6 + nullptr, // 0x0F7 + nullptr, // 0x0F8 + nullptr, // 0x0F9 + nullptr, // 0x0FA + nullptr, // 0x0FB + nullptr, // 0x0FC + nullptr, // 0x0FD + nullptr, // 0x0FE + nullptr, // 0x0FF + nullptr, // 0x100 + nullptr, // 0x101 + nullptr, // 0x102 + nullptr, // 0x103 + nullptr, // 0x104 + nullptr, // 0x105 + nullptr, // 0x106 + nullptr, // 0x107 + nullptr, // 0x108 + nullptr, // 0x109 + nullptr, // 0x10A + nullptr, // 0x10B + nullptr, // 0x10C + nullptr, // 0x10D + nullptr, // 0x10E + nullptr, // 0x10F + nullptr, // 0x110 + nullptr, // 0x111 + nullptr, // 0x112 + nullptr, // 0x113 + nullptr, // 0x114 + nullptr, // 0x115 + nullptr, // 0x116 + nullptr, // 0x117 + nullptr, // 0x118 + nullptr, // 0x119 + nullptr, // 0x11A + nullptr, // 0x11B + nullptr, // 0x11C + nullptr, // 0x11D + nullptr, // 0x11E + nullptr, // 0x11F + nullptr, // 0x120 + nullptr, // 0x121 + nullptr, // 0x122 + nullptr, // 0x123 + nullptr, // 0x124 + nullptr, // 0x125 + nullptr, // 0x126 + nullptr, // 0x127 + nullptr, // 0x128 + nullptr, // 0x129 + nullptr, // 0x12A + nullptr, // 0x12B + nullptr, // 0x12C + nullptr, // 0x12D + nullptr, // 0x12E + nullptr, // 0x12F + nullptr, // 0x130 + nullptr, // 0x131 + nullptr, // 0x132 + nullptr, // 0x133 + nullptr, // 0x134 + nullptr, // 0x135 + nullptr, // 0x136 + nullptr, // 0x137 + nullptr, // 0x138 + nullptr, // 0x139 + nullptr, // 0x13A + nullptr, // 0x13B + nullptr, // 0x13C + nullptr, // 0x13D + nullptr, // 0x13E + nullptr, // 0x13F + nullptr, // 0x140 + nullptr, // 0x141 + nullptr, // 0x142 + nullptr, // 0x143 + nullptr, // 0x144 + nullptr, // 0x145 + nullptr, // 0x146 + nullptr, // 0x147 + nullptr, // 0x148 + nullptr, // 0x149 + nullptr, // 0x14A + nullptr, // 0x14B + nullptr, // 0x14C + nullptr, // 0x14D + nullptr, // 0x14E + nullptr, // 0x14F + nullptr, // 0x150 + nullptr, // 0x151 + nullptr, // 0x152 + nullptr, // 0x153 + nullptr, // 0x154 + nullptr, // 0x155 + nullptr, // 0x156 + nullptr, // 0x157 + nullptr, // 0x158 + nullptr, // 0x159 + nullptr, // 0x15A + nullptr, // 0x15B + nullptr, // 0x15C + nullptr, // 0x15D + nullptr, // 0x15E + nullptr, // 0x15F + nullptr, // 0x160 + nullptr, // 0x161 + nullptr, // 0x162 + nullptr, // 0x163 + nullptr, // 0x164 + nullptr, // 0x165 + nullptr, // 0x166 + nullptr, // 0x167 + nullptr, // 0x168 + nullptr, // 0x169 + nullptr, // 0x16A + nullptr, // 0x16B + nullptr, // 0x16C + nullptr, // 0x16D + nullptr, // 0x16E + nullptr, // 0x16F + nullptr, // 0x170 + nullptr, // 0x171 + nullptr, // 0x172 + nullptr, // 0x173 + nullptr, // 0x174 + nullptr, // 0x175 + nullptr, // 0x176 + nullptr, // 0x177 + nullptr, // 0x178 + nullptr, // 0x179 + nullptr, // 0x17A + nullptr, // 0x17B + nullptr, // 0x17C + nullptr, // 0x17D + nullptr, // 0x17E + nullptr, // 0x17F + nullptr, // 0x180 + nullptr, // 0x181 + nullptr, // 0x182 + nullptr, // 0x183 + nullptr, // 0x184 + nullptr, // 0x185 + nullptr, // 0x186 + nullptr, // 0x187 + nullptr, // 0x188 + nullptr, // 0x189 + nullptr, // 0x18A + nullptr, // 0x18B + nullptr, // 0x18C + nullptr, // 0x18D + nullptr, // 0x18E + nullptr, // 0x18F + nullptr, // 0x190 + nullptr, // 0x191 + nullptr, // 0x192 + nullptr, // 0x193 + nullptr, // 0x194 + nullptr, // 0x195 + nullptr, // 0x196 + nullptr, // 0x197 + nullptr, // 0x198 + nullptr, // 0x199 + nullptr, // 0x19A + nullptr, // 0x19B + nullptr, // 0x19C + nullptr, // 0x19D + nullptr, // 0x19E + nullptr, // 0x19F + nullptr, // 0x1A0 + nullptr, // 0x1A1 + nullptr, // 0x1A2 + nullptr, // 0x1A3 + nullptr, // 0x1A4 + nullptr, // 0x1A5 + nullptr, // 0x1A6 + nullptr, // 0x1A7 + nullptr, // 0x1A8 + nullptr, // 0x1A9 + nullptr, // 0x1AA + nullptr, // 0x1AB + nullptr, // 0x1AC + nullptr, // 0x1AD + nullptr, // 0x1AE + nullptr, // 0x1AF + nullptr, // 0x1B0 + nullptr, // 0x1B1 + nullptr, // 0x1B2 + nullptr, // 0x1B3 + nullptr, // 0x1B4 + nullptr, // 0x1B5 + nullptr, // 0x1B6 + nullptr, // 0x1B7 + nullptr, // 0x1B8 + nullptr, // 0x1B9 + nullptr, // 0x1BA + nullptr, // 0x1BB + nullptr, // 0x1BC + nullptr, // 0x1BD + nullptr, // 0x1BE + nullptr, // 0x1BF + nullptr, // 0x1C0 + nullptr, // 0x1C1 + nullptr, // 0x1C2 + nullptr, // 0x1C3 + nullptr, // 0x1C4 + nullptr, // 0x1C5 + nullptr, // 0x1C6 + nullptr, // 0x1C7 + nullptr, // 0x1C8 + nullptr, // 0x1C9 + nullptr, // 0x1CA + nullptr, // 0x1CB + nullptr, // 0x1CC + nullptr, // 0x1CD + nullptr, // 0x1CE + nullptr, // 0x1CF + nullptr, // 0x1D0 + nullptr, // 0x1D1 + nullptr, // 0x1D2 + nullptr, // 0x1D3 + nullptr, // 0x1D4 + nullptr, // 0x1D5 + nullptr, // 0x1D6 + nullptr, // 0x1D7 + nullptr, // 0x1D8 + nullptr, // 0x1D9 + nullptr, // 0x1DA + nullptr, // 0x1DB + nullptr, // 0x1DC + nullptr, // 0x1DD + nullptr, // 0x1DE + nullptr, // 0x1DF + nullptr, // 0x1E0 + nullptr, // 0x1E1 + nullptr, // 0x1E2 + nullptr, // 0x1E3 + nullptr, // 0x1E4 + nullptr, // 0x1E5 + nullptr, // 0x1E6 + nullptr, // 0x1E7 + nullptr, // 0x1E8 + nullptr, // 0x1E9 + nullptr, // 0x1EA + nullptr, // 0x1EB + nullptr, // 0x1EC + nullptr, // 0x1ED + nullptr, // 0x1EE + nullptr, // 0x1EF + nullptr, // 0x1F0 + nullptr, // 0x1F1 + nullptr, // 0x1F2 + nullptr, // 0x1F3 + nullptr, // 0x1F4 + nullptr, // 0x1F5 + nullptr, // 0x1F6 + nullptr, // 0x1F7 + nullptr, // 0x1F8 + nullptr, // 0x1F9 + nullptr, // 0x1FA + nullptr, // 0x1FB + nullptr, // 0x1FC + nullptr, // 0x1FD + nullptr, // 0x1FE + nullptr, // 0x1FF +}; + + +// ============================================================= +// Version 2 — Switch dispatch +// ============================================================= + +/** + * Execute the instruction identified by @p opcode. + * + * This is functionally equivalent to the InstrMap[] table above + * but expressed as a switch so the compiler can choose the best + * lowering strategy (jump table, binary search, etc.). + * + * @param opcode 9-bit instruction opcode (0x000 - 0x1FF). + */ +void CPU::executeSwLk() { + switch (_opcode) { + + // ── System ────────────────────────────────────── + case 0x000: NOP(); break; + case 0x001: SPDR(); break; + case 0x002: MMODE(); break; + case 0x003: INT(); break; + case 0x004: LRV(); break; + case 0x005: FSR(); break; + case 0x006: FIR(); break; + case 0x007: FZR(); break; + case 0x008: LSR(); break; + case 0x009: FVR(); break; + + // ── Memory ────────────────────────────────────── + case 0x00A: MOV(); break; + case 0x00B: MOR(); break; + case 0x00C: AMOV(); break; + case 0x00D: SWP(); break; + case 0x00E: AHM(); break; + + // ── Integer ───────────────────────────────────── + case 0x010: COM(); break; + case 0x011: NEG(); break; + case 0x012: EXS(); break; + case 0x013: INC(); break; + case 0x014: DEC(); break; + case 0x015: ADD(); break; + case 0x016: SUB(); break; + case 0x017: MUL(); break; + case 0x018: UMUL(); break; + case 0x019: DIV(); break; + case 0x01A: UDIV(); break; + case 0x01B: MOD(); break; + case 0x01C: UMOD(); break; + case 0x01D: DMOD(); break; + case 0x01E: UDMD(); break; + + // ── System ────────────────────────────────────── + case 0x01F: FBT(); break; + + // ── Bit Wise ──────────────────────────────────── + case 0x020: STB(); break; + case 0x021: CRB(); break; + case 0x022: TSB(); break; + case 0x023: BOOL(); break; + case 0x024: NOT(); break; + case 0x025: AND(); break; + case 0x026: OR(); break; + case 0x027: XOR(); break; + case 0x028: SHL(); break; + case 0x029: SHR(); break; + case 0x02A: SSR(); break; + case 0x02B: ROL(); break; + case 0x02C: ROR(); break; + case 0x02D: CNT(); break; + + // ── Boolean ───────────────────────────────────── + case 0x030: EQ(); break; + case 0x031: NE(); break; + case 0x032: GT(); break; + case 0x033: GE(); break; + case 0x034: LT(); break; + case 0x035: LE(); break; + + // ── Branch ────────────────────────────────────── + case 0x038: JMP(); break; + case 0x039: JEQ(); break; + case 0x03A: JNE(); break; + case 0x03B: JIF(); break; + case 0x03C: JMR(); break; + case 0x03D: JER(); break; + case 0x03E: JNR(); break; + case 0x03F: JIR(); break; + + // ── System ────────────────────────────────────── + case 0x040: SFB(); break; + case 0x041: LFB(); break; + + // ── Branch ────────────────────────────────────── + case 0x042: JUF(); break; + case 0x043: JUR(); break; + + // ── Memory ────────────────────────────────────── + case 0x044: PUSH(); break; + case 0x045: POP(); break; + case 0x046: ALLOC(); break; + case 0x047: HFREE(); break; + + // ── Branch ────────────────────────────────────── + case 0x04A: CALL(); break; + case 0x04B: RET(); break; + + // ── System ────────────────────────────────────── + case 0x04C: EDI(); break; + case 0x04D: SHSS(); break; + + // ── Floating Point ────────────────────────────── + case 0x050: FLI(); break; + case 0x051: FNEG(); break; + case 0x052: FADD(); break; + case 0x053: FSUB(); break; + case 0x054: FMUL(); break; + case 0x055: FDIV(); break; + case 0x056: FMOD(); break; + case 0x057: FDMOD(); break; + case 0x058: FEPS(); break; + case 0x059: FEEP(); break; + + // ── Boolean ───────────────────────────────────── + case 0x05A: FEQ(); break; + case 0x05B: FNE(); break; + case 0x05C: FGT(); break; + case 0x05D: FGE(); break; + case 0x05E: FLT(); break; + case 0x05F: FLE(); break; + + // ── Casts ─────────────────────────────────────── + case 0x060: F2D(); break; + case 0x061: D2F(); break; + case 0x062: I2F(); break; + case 0x063: I2D(); break; + case 0x064: L2F(); break; + case 0x065: L2D(); break; + case 0x066: F2I(); break; + case 0x067: F2L(); break; + case 0x068: D2I(); break; + case 0x069: D2L(); break; + + // ── Trigonometric ─────────────────────────────── + case 0x06C: SIN(); break; + case 0x06D: COS(); break; + case 0x06E: TAN(); break; + case 0x06F: ASIN(); break; + case 0x070: ACOS(); break; + case 0x071: ATAN(); break; + case 0x072: ATAN2(); break; + + // ── Exponential ───────────────────────────────── + case 0x074: EXP(); break; + case 0x075: LOG(); break; + case 0x076: LOGAB(); break; + case 0x077: POW(); break; + case 0x078: SQRT(); break; + case 0x079: ROOT(); break; + + // ── Integer ───────────────────────────────────── + case 0x07C: ADC(); break; + case 0x07D: SWC(); break; + case 0x07E: MWO(); break; + case 0x07F: UMO(); break; + + // ── Matrix ────────────────────────────────────── + case 0x080: MADD(); break; + case 0x081: MSUB(); break; + case 0x082: MMUL(); break; + case 0x083: MINV(); break; + case 0x084: MTRA(); break; + case 0x085: MDET(); break; + + // ── Quaternion ────────────────────────────────── + case 0x086: QMKA(); break; + case 0x087: QMUL(); break; + + // ── SIMD ──────────────────────────────────────── + case 0x08A: XADD(); break; + case 0x08B: XSUB(); break; + case 0x08C: XAMA(); break; + case 0x08D: XMUL(); break; + case 0x08E: XDIV(); break; + + // ── Easter Eggs ───────────────────────────────── + case 0x0F0: UPY(); break; + + default: + break; + } +} + +} // namespace spider diff --git a/src/spider/runtime/math/Quat.cpp b/src/spider/runtime/math/Quat.cpp new file mode 100644 index 0000000..ae40493 --- /dev/null +++ b/src/spider/runtime/math/Quat.cpp @@ -0,0 +1,22 @@ +#include "Quat.hpp" + +#include + +namespace spider { + + int quatMain() { + Quat q1 = { 1.0f, 0.0f, 0.0f, 0.0f }; + Quat q2 = { 0.5f, 0.5f, 0.5f, 0.5f }; + + Quat result = quat_multiply(q1, q2); // Returns the result! + + std::cout << "Result: (" + << result.w << ", " + << result.x << ", " + << result.y << ", " + << result.z << ")" << std::endl; + + return 0; + } + +} diff --git a/src/spider/runtime/math/Quat.hpp b/src/spider/runtime/math/Quat.hpp new file mode 100644 index 0000000..676778c --- /dev/null +++ b/src/spider/runtime/math/Quat.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace spider { + + template + struct Quat { + T w, x, y, z; + }; + + /** + * Multiplies two quaternions together. + */ + template inline Quat quat_multiply(Quat A, Quat B) { + return { + B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z, + B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y, + B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x, + B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w + }; + } + +} diff --git a/src/spider/runtime/math/Quat_Multiply.cpp b/src/spider/runtime/math/Quat_Multiply.cpp deleted file mode 100644 index f41651c..0000000 --- a/src/spider/runtime/math/Quat_Multiply.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -template -struct Quaternion { - T w, x, y, z; -}; - -template -Quaternion quat_multiply(Quaternion A, Quaternion 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 - }; -} - -int main() { - Quaternion q1 = {1.0f, 0.0f, 0.0f, 0.0f}; - Quaternion q2 = {0.5f, 0.5f, 0.5f, 0.5f}; - - Quaternion result = quat_multiply(q1, q2); // Returns the result! - - std::cout << "Result: (" - << result.w << ", " - << result.x << ", " - << result.y << ", " - << result.z << ")" << std::endl; - - return 0; -} \ No newline at end of file diff --git a/src/spider/runtime/memory/ByteArray.cpp b/src/spider/runtime/memory/ByteArray.cpp new file mode 100644 index 0000000..507fa67 --- /dev/null +++ b/src/spider/runtime/memory/ByteArray.cpp @@ -0,0 +1,74 @@ +#include "ByteArray.hpp" + +#include + +namespace spider { + + ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) { + if (_size > 0) { + _mem = new u8[_size]; + std::memset(_mem, 0, _size); + } + } + + ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) { + std::copy(other._mem, other._mem + _size, _mem); + } + + ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) { + other._mem = nullptr; + other._size = 0; + } + + ByteArray::~ByteArray() { + delete[] _mem; + } + + ByteArray& ByteArray::operator=(const ByteArray& other) { + if (this == &other) return *this; // lock self + + u8* new_mem = new u8[other._size]; + std::copy(other._mem, other._mem + other._size, new_mem); + + delete[] _mem; + _mem = new_mem; + _size = other._size; + + return *this; + } + + ByteArray& ByteArray::operator=(ByteArray&& other) noexcept { + if (this == &other) return *this; // lock self + + delete[] _mem; + + _mem = other._mem; // time to steal! + _size = other._size; + + other._mem = nullptr; // leave as a husk + other._size = 0; + + return *this; + } + + u8& ByteArray::operator[](isize index) { + return _mem[index]; + } + + u8 ByteArray::operator[](isize index) const { + return _mem[index]; + } + + u8* ByteArray::data() { + return _mem; + } + + const u8* ByteArray::data() const { + return _mem; + } + + isize ByteArray::size() const { + return _size; + } + +} diff --git a/src/spider/runtime/memory/ByteArray.hpp b/src/spider/runtime/memory/ByteArray.hpp new file mode 100644 index 0000000..69ca2e7 --- /dev/null +++ b/src/spider/runtime/memory/ByteArray.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +namespace spider { + + /** + * A general purpose byte array + * with RAII semantics. + */ + class ByteArray { + private: + + u8* _mem; + isize _size; + + public: + + ByteArray(isize length); + + ByteArray(const ByteArray& other); + + ByteArray(ByteArray&& other) noexcept; + + ~ByteArray(); + + public: + + ByteArray& operator=(const ByteArray& other); + + ByteArray& operator=(ByteArray&& other) noexcept; + + public: + + u8& operator[](isize index); + + u8 operator[](isize index) const; + + public: + + u8* data(); + + const u8* data() const; + + isize size() const; + + }; + +} diff --git a/src/spider/runtime/memory/RAM.cpp b/src/spider/runtime/memory/RAM.cpp index c47d7f2..5c65303 100644 --- a/src/spider/runtime/memory/RAM.cpp +++ b/src/spider/runtime/memory/RAM.cpp @@ -111,4 +111,20 @@ namespace spider { return _size; } + u8* RAM::begin() { + return this->_mem; + } + + u8* RAM::end() { + return this->_mem + this->_size; + } + + const u8* RAM::begin() const { + return this->_mem; + } + + const u8* RAM::end() const { + return this->_mem + this->_size; + } + } diff --git a/src/spider/runtime/memory/RAM.hpp b/src/spider/runtime/memory/RAM.hpp index 6df9cdc..c62cd46 100644 --- a/src/spider/runtime/memory/RAM.hpp +++ b/src/spider/runtime/memory/RAM.hpp @@ -49,6 +49,16 @@ namespace spider { u64 size() const; + public: + + u8* begin(); + + u8* end(); + + const u8* begin() const; + + const u8* end() const; + }; } \ No newline at end of file diff --git a/src/spider/runtime/memory/Types.hpp b/src/spider/runtime/memory/Types.hpp new file mode 100644 index 0000000..635dc67 --- /dev/null +++ b/src/spider/runtime/memory/Types.hpp @@ -0,0 +1,253 @@ +#pragma once + +#include + +#include + +#include + +#if __cplusplus >= 202002L + #include +#endif + +#if defined(SPIDER_COMPILER_MSVC) + #include +#endif + +#include + +namespace spider { + + /* + * This file contains cross platform type juggling. + * Optimized for each case. + * + * General assumtions is that unsigned and signed + * integers are the exact same bit representation. + * + * Floats to and from integers is the focus when + * juggling. + * + * Additionally, provides help selecting a specific + * type from raw bytes. + */ + + // Utilities // + +#if __cplusplus >= 202002L + using std::bit_cast; +#else + template + inline To bit_cast(const From& src) { + static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch"); + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; + } +#endif + + template + inline T byteswap(T v) { + static_assert(std::is_integral::value, "byteswap requires integral type"); + + using U = std::make_unsigned_t; + U u = static_cast(v); + + if constexpr (sizeof(T) == 1) { + return v; + } else if constexpr (sizeof(T) == 2) { + +#if defined(SPIDER_COMPILER_MSVC) + u = _byteswap_ushort(u); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + u = __builtin_bswap16(u); +#else + u = (u >> 8) | (u << 8); +#endif + + } else if constexpr (sizeof(T) == 4) { + +#if defined(SPIDER_COMPILER_MSVC) + u = _byteswap_ulong(u); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + u = __builtin_bswap32(u); +#else + u = + ((u & 0x000000FFu) << 24) | + ((u & 0x0000FF00u) << 8) | + ((u & 0x00FF0000u) >> 8) | + ((u & 0xFF000000u) >> 24); +#endif + + } else if constexpr (sizeof(T) == 8) { + +#if defined(SPIDER_COMPILER_MSVC) + u = _byteswap_uint64(u); +#elif defined(SPIDER_COMPILER_GCC_LIKE) + u = __builtin_bswap64(u); +#else + u = + ((u & 0x00000000000000FFull) << 56) | + ((u & 0x000000000000FF00ull) << 40) | + ((u & 0x0000000000FF0000ull) << 24) | + ((u & 0x00000000FF000000ull) << 8) | + ((u & 0x000000FF00000000ull) >> 8) | + ((u & 0x0000FF0000000000ull) >> 24) | + ((u & 0x00FF000000000000ull) >> 40) | + ((u & 0xFF00000000000000ull) >> 56); +#endif + + } else { + // Generic fallback (rare: non 1/2/4/8-byte types) + U result = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8); + } + u = result; + } + + return static_cast(u); + } + + // Store Big Endian // + + template + inline void storeBE(T n, u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + std::memcpy(bytes, &n, sizeof(T)); +#endif +#if SPIDER_LITTLE_ENDIAN + T tmp = byteswap(n); + std::memcpy(bytes, &tmp, sizeof(T)); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + for (size_t i = 0; i < sizeof(T); ++i) { + bytes[i] = static_cast( + (static_cast>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF + ); + } +#endif + } + + template<> + inline void storeBE(f32 n, u8* bytes) { + u32 tmp = bit_cast(n); + storeBE(tmp, bytes); + } + + template<> + inline void storeBE(f64 n, u8* bytes) { + u64 tmp = bit_cast(n); + storeBE(tmp, bytes); + } + + // Load Big Endian // + + template + inline void loadBE(T* n, const u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + std::memcpy(n, bytes, sizeof(T)); +#endif +#if SPIDER_LITTLE_ENDIAN + T tmp; + std::memcpy(&tmp, bytes, sizeof(T)); + *n = byteswap(tmp); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + using U = std::make_unsigned_t; + U result = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + result |= static_cast(bytes[i]) << ((sizeof(T) - 1 - i) * 8); + } + *n = static_cast(result); +#endif + } + + template<> + inline void loadBE(f32* n, const u8* bytes) { + u32 tmp; + loadBE(&tmp, bytes); + *n = bit_cast(tmp); + } + + template<> + inline void loadBE(f64* n, const u8* bytes) { + u64 tmp; + loadBE(&tmp, bytes); + *n = bit_cast(tmp); + } + + // Store Little Endian // + + template + inline void storeLE(T n, u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + T tmp = byteswap(n); + std::memcpy(bytes, &tmp, sizeof(T)); +#endif +#if SPIDER_LITTLE_ENDIAN + std::memcpy(bytes, &n, sizeof(T)); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + for (size_t i = 0; i < sizeof(T); ++i) { + bytes[i] = static_cast( + (static_cast>(n) >> (i * 8)) & 0xFF + ); + } +#endif + } + + template<> + inline void storeLE(f32 n, u8* bytes) { + u32 tmp = bit_cast(n); + storeLE(tmp, bytes); + } + + template<> + inline void storeLE(f64 n, u8* bytes) { + u64 tmp = bit_cast(n); + storeLE(tmp, bytes); + } + + // Load Little Endian // + + template + inline void loadLE(T* n, const u8* bytes) { + static_assert(std::is_trivially_copyable::value); +#if SPIDER_BIG_ENDIAN + T tmp; + std::memcpy(&tmp, bytes, sizeof(T)); + *n = byteswap(tmp); +#endif +#if SPIDER_LITTLE_ENDIAN + std::memcpy(n, bytes, sizeof(T)); +#endif +#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN + using U = std::make_unsigned_t; + U result = 0; + for (size_t i = 0; i < sizeof(T); ++i) { + result |= static_cast(bytes[i]) << (i * 8); + } + *n = static_cast(result); +#endif + } + + template<> + inline void loadLE(f32* n, const u8* bytes) { + u32 tmp; + loadLE(&tmp, bytes); + *n = bit_cast(tmp); + } + + template<> + inline void loadLE(f64* n, const u8* bytes) { + u64 tmp; + loadLE(&tmp, bytes); + *n = bit_cast(tmp); + } + +} + diff --git a/src/spider/runtime/native/machine.hpp b/src/spider/runtime/native/machine.hpp index 5d049b6..d48186c 100644 --- a/src/spider/runtime/native/machine.hpp +++ b/src/spider/runtime/native/machine.hpp @@ -55,9 +55,9 @@ // ========================================================== // // PACKING // +// (not used now) // // ========================================================== // - // Find out what compiler the user is using #if defined(__clang__) #define SPIDER_COMPILER_CLANG @@ -73,8 +73,9 @@ // Macros... #if defined(SPIDER_COMPILER_GCC_LIKE) - #define SPIDER_ATTRIBUTE_PACKED __attribute__((packed)) - #define SPIDER_PACKED_STRUCT(decl) decl SPIDER_ATTRIBUTE_PACKED + #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)) diff --git a/src/spider/runtime/cpu/InstrReel.cpp b/src/spider/runtime/reel/InstrReel.cpp similarity index 75% rename from src/spider/runtime/cpu/InstrReel.cpp rename to src/spider/runtime/reel/InstrReel.cpp index 3a6cfaa..6f90e03 100644 --- a/src/spider/runtime/cpu/InstrReel.cpp +++ b/src/spider/runtime/reel/InstrReel.cpp @@ -1,17 +1,17 @@ #include "InstrReel.hpp" +#include + +#include + namespace spider { + // Public Interface // + InstrReel::InstrReel() {} InstrReel::~InstrReel() {} - u16 InstrReel::instrAt(u64 ip) const {} - - u8 InstrReel::dataAt(u64 ip) const {} - - u8 InstrReel::feedNext(CPU& cpu) {} - // Static Utils // u16 InstrReel::unpackInstr(u16 bcode) { diff --git a/src/spider/runtime/reel/InstrReel.hpp b/src/spider/runtime/reel/InstrReel.hpp new file mode 100644 index 0000000..a60d9c3 --- /dev/null +++ b/src/spider/runtime/reel/InstrReel.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +namespace spider { + + /** + * Implements an instruction reel. + */ + class InstrReel { + 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 readU8(u64 ip) = 0; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u16 readU16(u64 ip) = 0; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u32 readU32(u64 ip) = 0; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u64 readU64(u64 ip) = 0; + + /** + * Reads a range of data, and + * outputs it. + */ + virtual void readRange(u64 ip, u8* out, u64 length) = 0; + + /** + * Current size of the instructions. + */ + virtual u64 size() = 0; + + public: // Static Utils // + + static u16 unpackInstr(u16 bcode); + + static u8 unpackAddrMode(u16 bcode); + + static u8 unpackTypeSize(u16 bcode); + + }; + +} diff --git a/src/spider/runtime/reel/InstrReelDyn.cpp b/src/spider/runtime/reel/InstrReelDyn.cpp new file mode 100644 index 0000000..0aceeb2 --- /dev/null +++ b/src/spider/runtime/reel/InstrReelDyn.cpp @@ -0,0 +1,206 @@ +#include "InstrReelDyn.hpp" + +#include + +namespace spider { + + InstrReelDyn::InstrReelDyn(u64 length) : _size(length) { + // Safe int ceil division + growTo((length >> 8) + ((length & 255) != 0)); + } + + InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {} + + InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) + : _blocks(copy._blocks), _size(copy._size) { + } + + InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept + : _blocks(std::move(move._blocks)), _size(std::move(move._size)) { + } + + InstrReelDyn::~InstrReelDyn() { + // .. // + } + + InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) { + _blocks = copy._blocks; + _size = copy._size; + return *this; + } + + InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept { + _blocks = std::move(move._blocks); + _size = std::move(move._size); + return *this; + } + + void InstrReelDyn::growTo(u64 ip) { + u64 b_index = (ip >> 8) + 1; + while (_blocks.size() < b_index) { + _blocks.emplace_back(); + } + if (ip >= _size) _size = ip + 1; + } + + std::pair InstrReelDyn::indexOf(u64 ip) { + return { ip >> 8, ip & 0xFF }; // { ip / 256, ip % 256 }; + } + + bool InstrReelDyn::continous(u64 ip0, u64 ip1, u64* b_index, u16* s_index) { + auto i = indexOf(ip0); + *b_index = i.first; + *s_index = i.second; + return i.first == (ip1 >> 8); + } + + // Particular Cases + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + u8 InstrReelDyn::readU8(u64 ip) { + if (ip + 1 > _size) return 0; + auto i = indexOf(ip); + return _blocks[i.first].data[i.second]; + } + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + u16 InstrReelDyn::readU16(u64 ip) { + if (ip + 2 > _size) return 0; + + u16 dat; + u64 b_index; + u16 s_index; + + if (continous(ip, ip + 1, &b_index, &s_index)) { + spider::loadLE(&dat, &_blocks[b_index].data[s_index]); + return dat; + } + + dat = 0; + for (isize i = 0; i < sizeof(dat); i++) { + auto& b = _blocks[(b_index + s_index) >> 8]; + dat |= u16(b.data[s_index++ & 0xFF]) << (i * 8); + } + return dat; + } + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + u32 InstrReelDyn::readU32(u64 ip) { + if (ip + 4 > _size) return 0; + + u32 dat; + u64 b_index; + u16 s_index; + + if (continous(ip, ip + 3, &b_index, &s_index)) { + spider::loadLE(&dat, &_blocks[b_index].data[s_index]); + return dat; + } + + dat = 0; + for (isize i = 0; i < sizeof(dat); i++) { + auto& b = _blocks[(b_index + s_index) >> 8]; + dat |= u32(b.data[s_index++ & 0xFF]) << (i * 8); + } + return dat; + } + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + u64 InstrReelDyn::readU64(u64 ip) { + if (ip + 8 > _size) return 0; + + u64 dat; + u64 b_index; + u16 s_index; + + if (continous(ip, ip + 7, &b_index, &s_index)) { + spider::loadLE(&dat, &_blocks[b_index].data[s_index]); + return dat; + } + + dat = 0; + for (isize i = 0; i < sizeof(dat); i++) { + auto& b = _blocks[(b_index + s_index) >> 8]; + dat |= u64(b.data[s_index++ & 0xFF]) << (i * 8); + } + return dat; + } + + /** + * Reads a range of data, and + * outputs it. + */ + void InstrReelDyn::readRange(u64 ip, u8* out, u64 length) { + if (ip + length > _size) { + std::memset(out, 0, length); + return; + } + + u64 b_index; + u16 s_index; + + if (continous(ip, ip + length, &b_index, &s_index)) { + std::memcpy(out, &_blocks[b_index].data[s_index], length); + return; + } + + u64 bytes_read = 0; + while (bytes_read < length) { + u64 remaining_in_block = 256 - s_index; + u64 chunk_size = std::min(remaining_in_block, length - bytes_read); + + // Perform bulk copy for the current segment + std::memcpy(out + bytes_read, &_blocks[b_index].data[s_index], chunk_size); + + // Advance pointers + bytes_read += chunk_size; + b_index++; + s_index = 0; // reset + } + } + + /** + * Current size of the instructions. + */ + u64 InstrReelDyn::size() { + return _size; + } + + // Mutation // + + // TODO! + + void InstrReelDyn::writeU8(u64 ip, u8 dat) {} + + void InstrReelDyn::writeU16(u64 ip, u16 dat) {} + + void InstrReelDyn::writeU32(u64 ip, u32 dat) {} + + void InstrReelDyn::writeU64(u64 ip, u64 dat) {} + + /** + * Appends instruction at the end. + */ + void InstrReelDyn::append(u16 bc) {} + +} diff --git a/src/spider/runtime/reel/InstrReelDyn.hpp b/src/spider/runtime/reel/InstrReelDyn.hpp new file mode 100644 index 0000000..d5ed28c --- /dev/null +++ b/src/spider/runtime/reel/InstrReelDyn.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include + +namespace spider { + + /** + * Implements an instruction reel. + */ + class InstrReelDyn : public InstrReel { + private: + + struct ReelBlock { + u8 data[256] = {}; + }; + + private: + + deque _blocks; + u64 _size; + + 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: + + std::pair indexOf(u64 ip); + + bool continous(u64 ip0, u64 ip1, u64* b_index, u16* s_index); + + void growTo(u64 ip); + + public: + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u8 readU8(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u16 readU16(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u32 readU32(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u64 readU64(u64 ip) override; + + /** + * Reads a range of data, and + * outputs it. + */ + virtual void readRange(u64 ip, u8* out, u64 length) override; + + /** + * Current size of the instructions. + */ + virtual u64 size() override; + + public: + + void writeU8(u64 ip, u8 dat); + + void writeU16(u64 ip, u16 dat); + + void writeU32(u64 ip, u32 dat); + + void writeU64(u64 ip, u64 dat); + + /** + * Appends instruction at the end. + */ + void append(u16 bc); + + }; + +} diff --git a/src/spider/runtime/reel/InstrReelFile.hpp b/src/spider/runtime/reel/InstrReelFile.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/spider/runtime/reel/InstrReelFixed.cpp b/src/spider/runtime/reel/InstrReelFixed.cpp new file mode 100644 index 0000000..15e62eb --- /dev/null +++ b/src/spider/runtime/reel/InstrReelFixed.cpp @@ -0,0 +1,183 @@ +#include "InstrReelFixed.hpp" + +#include + +#include + +namespace spider { + + // Constructors & Destructors // + + InstrReelFixed::InstrReelFixed(u64 length) + : _mem(nullptr), _size(length) { + if (_size > 0) { + _mem = new u8[_size]; + std::memset(_mem, 0, _size); + } + } + + InstrReelFixed::InstrReelFixed(const u8* data, u64 length) + : _mem(nullptr), _size(length) { + if (_size > 0) { + _mem = new u8[_size]; + std::copy(data, data + _size, _mem); + } + } + + InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) { + _size = other._size; + _mem = new u8[_size]; + std::copy(other._mem, other._mem + _size, _mem); + } + + InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept { + _mem = other._mem; + _size = other._size; + + other._mem = nullptr; + other._size = 0; + } + + InstrReelFixed::~InstrReelFixed() { + delete[] _mem; + } + + // General Case(s) // + + // Instruction abstraction // + + u8 InstrReelFixed::readU8(u64 ip) { + // guard against access + if(ip + 1 > _size) return 0; + + // send byte + return _mem[ip]; + } + + u16 InstrReelFixed::readU16(u64 ip) { + // guard against access + if(ip + 2 > _size) return 0; + + // build a 16-bit big endian number + u16 dat; + spider::loadLE(&dat, _mem + ip); + return dat; + } + + u32 InstrReelFixed::readU32(u64 ip) { + // guard against access + if(ip + 4 > _size) return 0; + + // build a 32-bit big endian number + u32 dat; + spider::loadLE(&dat, _mem + ip); + return dat; + } + + u64 InstrReelFixed::readU64(u64 ip) { + // guard against access + if(ip + 8 > _size) return 0; + + // build a 64-bit big endian number + u64 dat; + spider::loadLE(&dat, _mem + ip); + return dat; + } + + void InstrReelFixed::readRange(u64 ip, u8* out, u64 length) { + if(ip + length > _size) { + std::memset(out, 0, length); + return; + } + std::memcpy(out, _mem + ip, length); + } + + u64 InstrReelFixed::size() { + return _size; + } + + // 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; + _size = other._size; + + return *this; + } + + InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept { + if (this == &other) return *this; // lock self + + delete[] _mem; + + _mem = other._mem; // steal + _size = other._size; + + other._mem = nullptr; // leave as husk + other._size = 0; + + return *this; + } + + // Misc // + + void InstrReelFixed::writeU8(u64 ip, u8 dat) { + if(ip + 1 > _size) return; + _mem[ip] = dat; + } + + void InstrReelFixed::writeU16(u64 ip, u16 dat) { + if(ip + 2 > _size) return; + spider::storeLE(dat, _mem + ip); + } + + void InstrReelFixed::writeU32(u64 ip, u32 dat) { + if(ip + 4 > _size) return; + spider::storeLE(dat, _mem + ip); + } + + void InstrReelFixed::writeU64(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; + 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; + } + +} diff --git a/src/spider/runtime/reel/InstrReelFixed.hpp b/src/spider/runtime/reel/InstrReelFixed.hpp new file mode 100644 index 0000000..f9b09a8 --- /dev/null +++ b/src/spider/runtime/reel/InstrReelFixed.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include + +namespace spider { + + /** + * Implements an instruction reel. + */ + class InstrReelFixed : public InstrReel { + private: + u8* _mem; + u64 _size; + + 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: + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u8 readU8(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u16 readU16(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u32 readU32(u64 ip) override; + + /** + * Obtains a byte of data at + * the specific location. + * Reindexing may occur, continous access + * may incurr in less penalties. + */ + virtual u64 readU64(u64 ip) override; + + /** + * Reads a range of data, and + * outputs it. + */ + virtual void readRange(u64 ip, u8* out, u64 length) override; + + /** + * Current size of the instructions. + */ + virtual u64 size() override; + + public: + + void writeU8(u64 ip, u8 dat); + + void writeU16(u64 ip, u16 dat); + + void writeU32(u64 ip, u32 dat); + + void writeU64(u64 ip, u64 dat); + + void resize(u64 new_size); + + }; + +} diff --git a/src/spider/runtime/util/Terminal.cpp b/src/spider/runtime/util/Terminal.cpp new file mode 100644 index 0000000..52eb4c8 --- /dev/null +++ b/src/spider/runtime/util/Terminal.cpp @@ -0,0 +1,277 @@ +#include "Terminal.hpp" + +#include + +#if defined(SPIDER_OS_WINDOWS) +#include +#include +#endif + +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) +#include +#include +#include +#endif + +#if defined(SPIDER_DISTRO_DESKTOP) + +namespace spider { + + // Style // + const char* Terminal::RESET = "\033[0m"; + const char* Terminal::BOLD = "\033[1m"; + const char* Terminal::ITALIC = "\033[3m"; + const char* Terminal::FAINT = "\033[2m"; + const char* Terminal::STRIKE = "\033[9m"; + + // Foreground // + const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m"; + const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m"; + const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m"; + const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m"; + const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m"; + const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m"; + const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m"; + const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m"; + + // Background // + const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m"; + const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m"; + const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m"; + const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m"; + const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m"; + const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m"; + const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m"; + const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m"; + + Terminal::Terminal() { +#if defined(SPIDER_OS_WINDOWS) + // Enable UTF-8 + SetConsoleOutputCP(CP_UTF8); + SetConsoleCP(CP_UTF8); + + // enable vtp + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + GetConsoleMode(hOut, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hOut, dwMode); +#endif + } + + Terminal::~Terminal() { + altbuff(false).style(RESET).cursor(true).flush(); + } + + Terminal& Terminal::style(const std::string_view code) { + std::cout << code; + return *this; + } + + Terminal& Terminal::move(i32 row, i32 col) { + std::cout << "\033[" << row << ";" << col << "H"; + return *this; + } + + Terminal& Terminal::altbuff(bool enable) { + std::cout << (enable ? "\033[?1049h" : "\033[?1049l"); + return *this; + } + + Terminal& Terminal::cls() { + std::cout << "\033[2J"; + return *this; + } + + Terminal& Terminal::scrollRange(i32 start, i32 end) { + std::cout << "\033[" << start << ";" << end << "r\033[?6h"; + return *this; + } + + Terminal& Terminal::undoSRange() { + std::cout << "\033[r\033[?6l\033[H"; + return *this; + } + + Terminal& Terminal::fill(const std::string_view color) { + this->style(color); + this->cls(); + return *this; + } + + Terminal& Terminal::clearRow(i32 row) { + // Move to row, column 1 + this->move(row, 1); + // \033[2K clears the entire line + std::cout << "\033[2K"; + return *this; + } + + Terminal& Terminal::clearRows(i32 start, i32 end) { + // Ensure we don't loop infinitely if start > end + if (start > end) std::swap(start, end); + + for (i32 i = start; i <= end; ++i) { + this->clearRow(i); + } + + // Optional: Move cursor back to the start of the cleared block + this->move(start, 1); + return *this; + } + + Terminal& Terminal::cursor(bool show) { + std::cout << (show ? "\033[?25h" : "\033[?25l"); + return *this; + } + + Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) { + // 1. Draw the top border + move(startRow, startCol); + std::cout << "┌"; + for (i32 i = 0; i < width - 2; ++i) std::cout << "─"; + std::cout << "┐"; + + // 2. Draw the sides + for (i32 i = 1; i < height - 1; ++i) { + move(startRow + i, startCol); + std::cout << "│"; + move(startRow + i, startCol + width - 1); + std::cout << "│"; + } + + // 3. Draw the bottom border + move(startRow + height - 1, startCol); + std::cout << "└"; + for (i32 i = 0; i < width - 2; ++i) std::cout << "─"; + std::cout << "┘"; + + // 4. Overlay the title if provided + if (!title.empty()) { + move(startRow, startCol + (width - title.size() - 2) / 2); + std::cout << " " << title << " "; + } + + std::cout.flush(); + return *this; + } + + Terminal& Terminal::flush() { + std::cout << std::flush; + return *this; + } + + Terminal& Terminal::sink() { + std::cin.clear(); +#if defined(SPIDER_OS_WINDOWS) + while (_kbhit()) _getch(); +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + tcflush(STDIN_FILENO, TCIFLUSH); +#endif + return *this; + } + + std::pair Terminal::getSize() { + std::pair pair; +#if defined(SPIDER_OS_WINDOWS) + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { + pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1; + pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + } +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) { + pair.first = w.ws_col; + pair.second = w.ws_row; + } +#endif + return pair; + } + + Terminal& Terminal::wait() { + sink(); + std::cin.get(); + return *this; + } + + u8 Terminal::getKey() { +#if defined(SPIDER_OS_WINDOWS) + i32 ch = _getch(); + if (ch == 0 || ch == 224) { + switch (_getch()) { + case 72: return Terminal::UP; + case 80: return Terminal::DOWN; + case 75: return Terminal::LEFT; + case 77: return Terminal::RIGHT; + default: return Terminal::UNKNOWN; + } + } + if (ch == 13) return Terminal::ENTER; + if (ch == 27) return Terminal::ESC; + if (ch == 8) return Terminal::BACKSPACE; + return Terminal::UNKNOWN; +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + struct termios oldt, newt; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + u8 result = Terminal::UNKNOWN; + int ch = getchar(); + + if (ch == 27) { // Potential Escape Sequence + // Use a small timeout or check if more chars are in buffer + // to distinguish between 'Esc' key and 'Arrow' sequence + // Another Win for the Win API + struct timeval tv = { 0, 10000 }; // 10ms wait + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + + if (select(1, &fds, NULL, NULL, &tv) > 0) { + if (getchar() == '[') { + switch (getchar()) { + case 'A': result = Terminal::UP; break; + case 'B': result = Terminal::DOWN; break; + case 'D': result = Terminal::LEFT; break; + case 'C': result = Terminal::RIGHT; break; + } + } + } else { + result = Terminal::ESC; + } + } else if (ch == 10) result = Terminal::ENTER; + else if (ch == 127) result = Terminal::BACKSPACE; + else result = (u8)ch; + + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return result; +#endif + } + + u8 Terminal::getKeyNb() { +#if defined(SPIDER_OS_WINDOWS) + if (_kbhit()) return getKey(); + return Terminal::UNKNOWN; +#endif +#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS) + struct timeval tv = { 0, 0 }; + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + // select() returns > 0 if there is data to read + if (select(1, &fds, NULL, NULL, &tv) > 0) { + return getKey(); + } + return Terminal::UNKNOWN; +#endif + } + +} + +#endif diff --git a/src/spider/runtime/util/Terminal.hpp b/src/spider/runtime/util/Terminal.hpp new file mode 100644 index 0000000..3f183f1 --- /dev/null +++ b/src/spider/runtime/util/Terminal.hpp @@ -0,0 +1,176 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace spider { + + class Terminal { + public: + + static const char* RESET; + static const char* BOLD; + static const char* ITALIC; + static const char* FAINT; + static const char* STRIKE; + + static const char* FG_BLACK; static const char* FG_B_BLACK; + static const char* FG_RED; static const char* FG_B_RED; + static const char* FG_GREEN; static const char* FG_B_GREEN; + static const char* FG_YELLOW; static const char* FG_B_YELLOW; + static const char* FG_BLUE; static const char* FG_B_BLUE; + static const char* FG_MAGENTA; static const char* FG_B_MAGENTA; + static const char* FG_CYAN; static const char* FG_B_CYAN; + static const char* FG_WHITE; static const char* FG_B_WHITE; + + static const char* BG_BLACK; static const char* BG_B_BLACK; + static const char* BG_RED; static const char* BG_B_RED; + static const char* BG_GREEN; static const char* BG_B_GREEN; + static const char* BG_YELLOW; static const char* BG_B_YELLOW; + static const char* BG_BLUE; static const char* BG_B_BLUE; + static const char* BG_MAGENTA; static const char* BG_B_MAGENTA; + static const char* BG_CYAN; static const char* BG_B_CYAN; + static const char* BG_WHITE; static const char* BG_B_WHITE; + + public: + + // Key Definitions (ASCII OK) // + static constexpr const u8 UP = 0x80; + static constexpr const u8 DOWN = 0x81; + static constexpr const u8 LEFT = 0x82; + static constexpr const u8 RIGHT = 0x83; + static constexpr const u8 ENTER = 0x84; + static constexpr const u8 ESC = 0x85; + static constexpr const u8 BACKSPACE = 0x86; + static constexpr const u8 UNKNOWN = 0xFF; + + public: + + Terminal(); + + ~Terminal(); + + public: + + /** + * Sets a style + */ + Terminal& style(const std::string_view code); + + /** + * Fills the screen with a specific background color. + * @param color The background color constant (e.g., Terminal::BG_BLUE) + */ + Terminal& fill(const std::string_view color); + + /** + * Moves the cursor. + */ + Terminal& move(i32 row, i32 col); + + /** + * Clears the screen + */ + Terminal& cls(); + + Terminal& altbuff(bool enable); + + Terminal& scrollRange(i32 start, i32 end); + + Terminal& undoSRange(); + + /** + * Clears a specific row. + * @param row The 1-based index of the row to clear. + */ + Terminal& clearRow(i32 row); + + /** + * Clears a range of rows (inclusive). + * @param start The first row. + * @param end The last row. + */ + Terminal& clearRows(i32 start, i32 end); + + /** + * Shows / Hides the cursor. + */ + Terminal& cursor(bool show); + + public: + + Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title); + + public: + + /** + * Flushes the output buffer + */ + Terminal& flush(); + + /** + * Clears the input buffer. + * Useful for some specific input cases + */ + Terminal& sink(); + + public: + + Terminal& wait(); + + u8 getKey(); + + /** + * Get key non blocking + */ + u8 getKeyNb(); + + std::pair getSize(); + + public: + + template + Terminal& print(const T& msg) { + std::cout << msg; + return *this; + } + + template + Terminal& println(const T& msg) { + std::cout << msg << "\n"; + return *this; + } + + template + Terminal& print_center(i32 width, const T& msg) { + // to string + std::ostringstream oss; + oss << msg; + std::string s = oss.str(); + + // then print + if (s.length() >= isize(width)) { + std::cout << s; + } else { + i32 total_padding = width - s.length(); + i32 left_padding = total_padding / 2; + std::cout << std::string(left_padding, ' '); + std::cout << s; + std::cout << std::string(total_padding - left_padding, ' '); + } + return *this; + } + + template + Terminal& read(T& var) { + std::cin >> var; + return *this; + } + + }; + +} \ No newline at end of file