Merge branch 'main' of https://git.sintekanalytics.com/SpiderLang/spider-runtime
This commit is contained in:
@@ -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
|
||||
|
||||
Binary file not shown.
12
makefile
12
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/
|
||||
|
||||
|
||||
194
pygen.ipynb
194
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 <spider/runtime/cpu/CPU.hpp>')\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": {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
],
|
||||
"C_Cpp.default.includePath": [
|
||||
"./src"
|
||||
]
|
||||
],
|
||||
"terminal.integrated.defaultProfile.windows": "MSYS2 UCRT"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,18 @@
|
||||
#include "SpiderRuntime.hpp"
|
||||
|
||||
#include <spider/runtime/debug/LiveDebug.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
namespace spider {
|
||||
|
||||
extern const u32 RUNTIME_VERSION_NO;
|
||||
extern const std::string RUNTIME_VERSION;
|
||||
|
||||
class Runtime;
|
||||
class CPU;
|
||||
class RAM;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/cpu/CPU.hpp>
|
||||
|
||||
#include <spider/runtime/memory/RAM.hpp>
|
||||
|
||||
#include <spider/runtime/reel/InstrReel.hpp>
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
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;
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
#include "CPU.hpp"
|
||||
|
||||
#include <spider/runtime/native/machine.hpp>
|
||||
|
||||
#include <spider/runtime/memory/RAM.hpp>
|
||||
#include <spider/runtime/memory/Types.hpp>
|
||||
|
||||
#include <spider/runtime/reel/InstrReel.hpp>
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
namespace spider {
|
||||
|
||||
CPU::CPU()
|
||||
: RA{}, RB{}, RC{}, RD{},
|
||||
RX{}, RY{}, R0{}, R1{},
|
||||
R2{}, R3{}, R4{}, R5{},
|
||||
R6{}, R7{}, R8{}, R9{},
|
||||
RF{}, RI{}, RS{}, RZ{},
|
||||
RE{}, RN{}, RV{}, RM{},
|
||||
ALU0{}, ALU1{},
|
||||
_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() {}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/SpiderRuntime.hpp>
|
||||
#include <spider/runtime/cpu/Register.hpp>
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
// <pygen-target name=cpu-instructions> //
|
||||
@@ -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:
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/SpiderRuntime.hpp>
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
404
src/spider/runtime/debug/LiveDebug.cpp
Normal file
404
src/spider/runtime/debug/LiveDebug.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
#include "LiveDebug.hpp"
|
||||
|
||||
#include <spider/runtime/reel/InstrReelFixed.hpp>
|
||||
|
||||
#include <spider/runtime/Runtime.hpp>
|
||||
#include <spider/runtime/util/Terminal.hpp>
|
||||
#include <spider/runtime/native/distro.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <thread>
|
||||
namespace spider {
|
||||
|
||||
void drawHead(Terminal& t) {
|
||||
t.move(1, 1)
|
||||
.style(Terminal::FG_YELLOW)
|
||||
.print(" Spider Runtime Live Debug ")
|
||||
.style(Terminal::RESET).print(" | ")
|
||||
.style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ")
|
||||
.style(Terminal::RESET).print(" | ")
|
||||
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
|
||||
.style(Terminal::FG_BLACK)
|
||||
.style(Terminal::BG_YELLOW)
|
||||
.move(3, 1).print(" // __ \\\\").print(" ") // 27
|
||||
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
|
||||
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
|
||||
.move(6, 1).print(" \\\\ // ").print(" ")
|
||||
.style(Terminal::RESET)
|
||||
.style(Terminal::FG_B_BLACK) // 4x8 for the menu
|
||||
.move(3, 28).print("[ STEP ]")
|
||||
.move(4, 28).print("[ STOP ]")
|
||||
.move(5, 28).print("[ RUN ]")
|
||||
.move(6, 28).print("[ MENU ]")
|
||||
.style(Terminal::RESET)
|
||||
;
|
||||
}
|
||||
|
||||
void drawCPUTempl(Terminal& t, CPU& cpu) {
|
||||
i32 r = 8, c = 1;
|
||||
i32 w = 35, h = 31;
|
||||
t.drawBox(r, c, w, h, "CPU");
|
||||
|
||||
const std::string regs[] = {
|
||||
"RA", "RB", "RC", "RD",
|
||||
"RX", "RY", "R0", "R1",
|
||||
"R2", "R3", "R4", "R5",
|
||||
"R6", "R7", "R8", "R9",
|
||||
"RF", "RI", "RS", "RZ",
|
||||
"RE", "RN", "RV", "RM",
|
||||
"ALU0", "ALU1"
|
||||
};
|
||||
const std::string alt[] = {
|
||||
Terminal::FG_WHITE,
|
||||
Terminal::FG_B_BLACK,
|
||||
};
|
||||
|
||||
r++;
|
||||
c++;
|
||||
|
||||
t.move(r++, c);
|
||||
t.style(Terminal::FG_B_YELLOW);
|
||||
t.print_center(w - 2, "GP Registers");
|
||||
t.style(Terminal::RESET);
|
||||
for (i32 i = 0; i < 8; i++) {
|
||||
t.style(alt[i & 1]);
|
||||
t.move(r + i * 2, c);
|
||||
t.print(regs[i * 2]);
|
||||
t.move(r + i * 2, c + 17);
|
||||
t.print(regs[i * 2 + 1]);
|
||||
}
|
||||
|
||||
t.move(r += 16, c);
|
||||
t.style(Terminal::FG_B_CYAN);
|
||||
t.print_center(w - 2, "System Registers");
|
||||
t.style(Terminal::RESET);
|
||||
r++;
|
||||
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
||||
t.style(alt[j & 1]);
|
||||
t.move(r + j * 2, c);
|
||||
t.print(regs[i * 2]);
|
||||
t.move(r + j * 2, c + 17);
|
||||
t.print(regs[i * 2 + 1]);
|
||||
}
|
||||
|
||||
t.move(r += 8, c);
|
||||
t.style(Terminal::FG_GREEN);
|
||||
t.print_center(w - 2, "Extra Registers");
|
||||
t.style(Terminal::RESET);
|
||||
r++;
|
||||
for (i32 j = 0, i = 12; i < 13; j++, i++) {
|
||||
t.style(alt[j & 1]);
|
||||
t.move(r + j * 2, c);
|
||||
t.print(regs[i * 2]);
|
||||
t.move(r + j * 2, c + 17);
|
||||
t.print(regs[i * 2 + 1]);
|
||||
}
|
||||
|
||||
t.flush();
|
||||
}
|
||||
|
||||
void printU64Hex(u64 n) {
|
||||
std::ios state(nullptr);
|
||||
state.copyfmt(std::cout);
|
||||
std::cout
|
||||
<< std::hex
|
||||
<< std::uppercase
|
||||
<< std::setfill('0')
|
||||
<< std::setw(16)
|
||||
<< n;
|
||||
std::cout.copyfmt(state);
|
||||
}
|
||||
|
||||
void drawCPU(Terminal& t, CPU& cpu) {
|
||||
i32 r = 8, c = 1;
|
||||
|
||||
const register_t* regs[] = {
|
||||
&cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD,
|
||||
&cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1,
|
||||
&cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5,
|
||||
&cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9,
|
||||
//&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
||||
//&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
||||
&cpu.ALU0, &cpu.ALU1
|
||||
};
|
||||
const u64* sys_regs[] = {
|
||||
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
||||
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
||||
};
|
||||
const std::string alt[] = {
|
||||
Terminal::FG_WHITE,
|
||||
Terminal::FG_B_BLACK,
|
||||
};
|
||||
|
||||
r++;
|
||||
c++;
|
||||
t.move(r++, c);
|
||||
t.style(Terminal::RESET);
|
||||
r++;
|
||||
for (i32 i = 0; i < 8; i++) {
|
||||
t.style(alt[i & 1]);
|
||||
t.move(r + i * 2, c);
|
||||
printU64Hex(regs[i * 2]->_u64);
|
||||
t.move(r + i * 2, c + 17);
|
||||
printU64Hex(regs[i * 2 + 1]->_u64);
|
||||
}
|
||||
|
||||
t.move(r += 16, c);
|
||||
r++;
|
||||
for (i32 j = 0; 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<std::chrono::seconds>(now_l);
|
||||
//std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss
|
||||
//std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY
|
||||
|
||||
t.move(1, 76);
|
||||
t.style(Terminal::RESET);
|
||||
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
|
||||
}
|
||||
|
||||
void redraw(Terminal& t, Runtime& r, u64 scroll) {
|
||||
// draw CPU, RAM
|
||||
drawCPU(t, r.cpu);
|
||||
drawRAM(t, r.ram, scroll);
|
||||
}
|
||||
|
||||
int liveDebugMain() {
|
||||
Terminal t;
|
||||
Runtime runtime(1024);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
7
src/spider/runtime/debug/LiveDebug.hpp
Normal file
7
src/spider/runtime/debug/LiveDebug.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace spider {
|
||||
|
||||
int liveDebugMain();
|
||||
|
||||
}
|
||||
746
src/spider/runtime/instr/InstrMap.cpp
Normal file
746
src/spider/runtime/instr/InstrMap.cpp
Normal file
@@ -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 <spider/runtime/cpu/CPU.hpp>
|
||||
|
||||
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
|
||||
22
src/spider/runtime/math/Quat.cpp
Normal file
22
src/spider/runtime/math/Quat.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "Quat.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace spider {
|
||||
|
||||
int quatMain() {
|
||||
Quat<double> q1 = { 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
Quat<double> q2 = { 0.5f, 0.5f, 0.5f, 0.5f };
|
||||
|
||||
Quat<double> result = quat_multiply(q1, q2); // Returns the result!
|
||||
|
||||
std::cout << "Result: ("
|
||||
<< result.w << ", "
|
||||
<< result.x << ", "
|
||||
<< result.y << ", "
|
||||
<< result.z << ")" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
24
src/spider/runtime/math/Quat.hpp
Normal file
24
src/spider/runtime/math/Quat.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/common.hpp>
|
||||
|
||||
namespace spider {
|
||||
|
||||
template<typename T>
|
||||
struct Quat {
|
||||
T w, x, y, z;
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiplies two quaternions together.
|
||||
*/
|
||||
template<typename T> inline Quat<T> quat_multiply(Quat<T> A, Quat<T> B) {
|
||||
return {
|
||||
B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z,
|
||||
B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y,
|
||||
B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x,
|
||||
B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
template<typename T>
|
||||
struct Quaternion {
|
||||
T w, x, y, z;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Quaternion<T> quat_multiply(Quaternion<T> A, Quaternion<T> B) {
|
||||
return {
|
||||
B.w * A.w - B.x * A.x - B.y * A.y - B.z * A.z,
|
||||
B.w * A.x + B.x * A.w - B.y * A.z + B.z * A.y,
|
||||
B.w * A.y + B.x * A.z + B.y * A.w - B.z * A.x,
|
||||
B.w * A.z - B.x * A.y + B.y * A.x + B.z * A.w
|
||||
};
|
||||
}
|
||||
|
||||
int main() {
|
||||
Quaternion<double> q1 = {1.0f, 0.0f, 0.0f, 0.0f};
|
||||
Quaternion<double> q2 = {0.5f, 0.5f, 0.5f, 0.5f};
|
||||
|
||||
Quaternion<double> result = quat_multiply(q1, q2); // Returns the result!
|
||||
|
||||
std::cout << "Result: ("
|
||||
<< result.w << ", "
|
||||
<< result.x << ", "
|
||||
<< result.y << ", "
|
||||
<< result.z << ")" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
74
src/spider/runtime/memory/ByteArray.cpp
Normal file
74
src/spider/runtime/memory/ByteArray.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "ByteArray.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace spider {
|
||||
|
||||
ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) {
|
||||
if (_size > 0) {
|
||||
_mem = new u8[_size];
|
||||
std::memset(_mem, 0, _size);
|
||||
}
|
||||
}
|
||||
|
||||
ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) {
|
||||
std::copy(other._mem, other._mem + _size, _mem);
|
||||
}
|
||||
|
||||
ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) {
|
||||
other._mem = nullptr;
|
||||
other._size = 0;
|
||||
}
|
||||
|
||||
ByteArray::~ByteArray() {
|
||||
delete[] _mem;
|
||||
}
|
||||
|
||||
ByteArray& ByteArray::operator=(const ByteArray& other) {
|
||||
if (this == &other) return *this; // lock self
|
||||
|
||||
u8* new_mem = new u8[other._size];
|
||||
std::copy(other._mem, other._mem + other._size, new_mem);
|
||||
|
||||
delete[] _mem;
|
||||
_mem = new_mem;
|
||||
_size = other._size;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteArray& ByteArray::operator=(ByteArray&& other) noexcept {
|
||||
if (this == &other) return *this; // lock self
|
||||
|
||||
delete[] _mem;
|
||||
|
||||
_mem = other._mem; // time to steal!
|
||||
_size = other._size;
|
||||
|
||||
other._mem = nullptr; // leave as a husk
|
||||
other._size = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
u8& ByteArray::operator[](isize index) {
|
||||
return _mem[index];
|
||||
}
|
||||
|
||||
u8 ByteArray::operator[](isize index) const {
|
||||
return _mem[index];
|
||||
}
|
||||
|
||||
u8* ByteArray::data() {
|
||||
return _mem;
|
||||
}
|
||||
|
||||
const u8* ByteArray::data() const {
|
||||
return _mem;
|
||||
}
|
||||
|
||||
isize ByteArray::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
}
|
||||
49
src/spider/runtime/memory/ByteArray.hpp
Normal file
49
src/spider/runtime/memory/ByteArray.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/common.hpp>
|
||||
|
||||
namespace spider {
|
||||
|
||||
/**
|
||||
* A general purpose byte array
|
||||
* with RAII semantics.
|
||||
*/
|
||||
class ByteArray {
|
||||
private:
|
||||
|
||||
u8* _mem;
|
||||
isize _size;
|
||||
|
||||
public:
|
||||
|
||||
ByteArray(isize length);
|
||||
|
||||
ByteArray(const ByteArray& other);
|
||||
|
||||
ByteArray(ByteArray&& other) noexcept;
|
||||
|
||||
~ByteArray();
|
||||
|
||||
public:
|
||||
|
||||
ByteArray& operator=(const ByteArray& other);
|
||||
|
||||
ByteArray& operator=(ByteArray&& other) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
u8& operator[](isize index);
|
||||
|
||||
u8 operator[](isize index) const;
|
||||
|
||||
public:
|
||||
|
||||
u8* data();
|
||||
|
||||
const u8* data() const;
|
||||
|
||||
isize size() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@ namespace spider {
|
||||
|
||||
u64 size() const;
|
||||
|
||||
public:
|
||||
|
||||
u8* begin();
|
||||
|
||||
u8* end();
|
||||
|
||||
const u8* begin() const;
|
||||
|
||||
const u8* end() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
253
src/spider/runtime/memory/Types.hpp
Normal file
253
src/spider/runtime/memory/Types.hpp
Normal file
@@ -0,0 +1,253 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/common.hpp>
|
||||
|
||||
#include <spider/runtime/cpu/Register.hpp>
|
||||
|
||||
#include <spider/runtime/native/machine.hpp>
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
#if defined(SPIDER_COMPILER_MSVC)
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace spider {
|
||||
|
||||
/*
|
||||
* This file contains cross platform type juggling.
|
||||
* Optimized for each case.
|
||||
*
|
||||
* General assumtions is that unsigned and signed
|
||||
* integers are the exact same bit representation.
|
||||
*
|
||||
* Floats to and from integers is the focus when
|
||||
* juggling.
|
||||
*
|
||||
* Additionally, provides help selecting a specific
|
||||
* type from raw bytes.
|
||||
*/
|
||||
|
||||
// Utilities //
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
using std::bit_cast;
|
||||
#else
|
||||
template<typename To, typename From>
|
||||
inline To bit_cast(const From& src) {
|
||||
static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch");
|
||||
To dst;
|
||||
std::memcpy(&dst, &src, sizeof(To));
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline T byteswap(T v) {
|
||||
static_assert(std::is_integral<T>::value, "byteswap requires integral type");
|
||||
|
||||
using U = std::make_unsigned_t<T>;
|
||||
U u = static_cast<U>(v);
|
||||
|
||||
if constexpr (sizeof(T) == 1) {
|
||||
return v;
|
||||
} else if constexpr (sizeof(T) == 2) {
|
||||
|
||||
#if defined(SPIDER_COMPILER_MSVC)
|
||||
u = _byteswap_ushort(u);
|
||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||
u = __builtin_bswap16(u);
|
||||
#else
|
||||
u = (u >> 8) | (u << 8);
|
||||
#endif
|
||||
|
||||
} else if constexpr (sizeof(T) == 4) {
|
||||
|
||||
#if defined(SPIDER_COMPILER_MSVC)
|
||||
u = _byteswap_ulong(u);
|
||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||
u = __builtin_bswap32(u);
|
||||
#else
|
||||
u =
|
||||
((u & 0x000000FFu) << 24) |
|
||||
((u & 0x0000FF00u) << 8) |
|
||||
((u & 0x00FF0000u) >> 8) |
|
||||
((u & 0xFF000000u) >> 24);
|
||||
#endif
|
||||
|
||||
} else if constexpr (sizeof(T) == 8) {
|
||||
|
||||
#if defined(SPIDER_COMPILER_MSVC)
|
||||
u = _byteswap_uint64(u);
|
||||
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||
u = __builtin_bswap64(u);
|
||||
#else
|
||||
u =
|
||||
((u & 0x00000000000000FFull) << 56) |
|
||||
((u & 0x000000000000FF00ull) << 40) |
|
||||
((u & 0x0000000000FF0000ull) << 24) |
|
||||
((u & 0x00000000FF000000ull) << 8) |
|
||||
((u & 0x000000FF00000000ull) >> 8) |
|
||||
((u & 0x0000FF0000000000ull) >> 24) |
|
||||
((u & 0x00FF000000000000ull) >> 40) |
|
||||
((u & 0xFF00000000000000ull) >> 56);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// Generic fallback (rare: non 1/2/4/8-byte types)
|
||||
U result = 0;
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8);
|
||||
}
|
||||
u = result;
|
||||
}
|
||||
|
||||
return static_cast<T>(u);
|
||||
}
|
||||
|
||||
// Store Big Endian //
|
||||
|
||||
template<typename T>
|
||||
inline void storeBE(T n, u8* bytes) {
|
||||
static_assert(std::is_trivially_copyable<T>::value);
|
||||
#if SPIDER_BIG_ENDIAN
|
||||
std::memcpy(bytes, &n, sizeof(T));
|
||||
#endif
|
||||
#if SPIDER_LITTLE_ENDIAN
|
||||
T tmp = byteswap(n);
|
||||
std::memcpy(bytes, &tmp, sizeof(T));
|
||||
#endif
|
||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
bytes[i] = static_cast<u8>(
|
||||
(static_cast<std::make_unsigned_t<T>>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void storeBE<f32>(f32 n, u8* bytes) {
|
||||
u32 tmp = bit_cast<u32>(n);
|
||||
storeBE(tmp, bytes);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void storeBE<f64>(f64 n, u8* bytes) {
|
||||
u64 tmp = bit_cast<u64>(n);
|
||||
storeBE(tmp, bytes);
|
||||
}
|
||||
|
||||
// Load Big Endian //
|
||||
|
||||
template<typename T>
|
||||
inline void loadBE(T* n, const u8* bytes) {
|
||||
static_assert(std::is_trivially_copyable<T>::value);
|
||||
#if SPIDER_BIG_ENDIAN
|
||||
std::memcpy(n, bytes, sizeof(T));
|
||||
#endif
|
||||
#if SPIDER_LITTLE_ENDIAN
|
||||
T tmp;
|
||||
std::memcpy(&tmp, bytes, sizeof(T));
|
||||
*n = byteswap(tmp);
|
||||
#endif
|
||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||
using U = std::make_unsigned_t<T>;
|
||||
U result = 0;
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
result |= static_cast<U>(bytes[i]) << ((sizeof(T) - 1 - i) * 8);
|
||||
}
|
||||
*n = static_cast<T>(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void loadBE<f32>(f32* n, const u8* bytes) {
|
||||
u32 tmp;
|
||||
loadBE(&tmp, bytes);
|
||||
*n = bit_cast<f32>(tmp);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void loadBE<f64>(f64* n, const u8* bytes) {
|
||||
u64 tmp;
|
||||
loadBE(&tmp, bytes);
|
||||
*n = bit_cast<f64>(tmp);
|
||||
}
|
||||
|
||||
// Store Little Endian //
|
||||
|
||||
template<typename T>
|
||||
inline void storeLE(T n, u8* bytes) {
|
||||
static_assert(std::is_trivially_copyable<T>::value);
|
||||
#if SPIDER_BIG_ENDIAN
|
||||
T tmp = byteswap(n);
|
||||
std::memcpy(bytes, &tmp, sizeof(T));
|
||||
#endif
|
||||
#if SPIDER_LITTLE_ENDIAN
|
||||
std::memcpy(bytes, &n, sizeof(T));
|
||||
#endif
|
||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
bytes[i] = static_cast<u8>(
|
||||
(static_cast<std::make_unsigned_t<T>>(n) >> (i * 8)) & 0xFF
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void storeLE<f32>(f32 n, u8* bytes) {
|
||||
u32 tmp = bit_cast<u32>(n);
|
||||
storeLE(tmp, bytes);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void storeLE<f64>(f64 n, u8* bytes) {
|
||||
u64 tmp = bit_cast<u64>(n);
|
||||
storeLE(tmp, bytes);
|
||||
}
|
||||
|
||||
// Load Little Endian //
|
||||
|
||||
template<typename T>
|
||||
inline void loadLE(T* n, const u8* bytes) {
|
||||
static_assert(std::is_trivially_copyable<T>::value);
|
||||
#if SPIDER_BIG_ENDIAN
|
||||
T tmp;
|
||||
std::memcpy(&tmp, bytes, sizeof(T));
|
||||
*n = byteswap(tmp);
|
||||
#endif
|
||||
#if SPIDER_LITTLE_ENDIAN
|
||||
std::memcpy(n, bytes, sizeof(T));
|
||||
#endif
|
||||
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||
using U = std::make_unsigned_t<T>;
|
||||
U result = 0;
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
result |= static_cast<U>(bytes[i]) << (i * 8);
|
||||
}
|
||||
*n = static_cast<T>(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void loadLE<f32>(f32* n, const u8* bytes) {
|
||||
u32 tmp;
|
||||
loadLE(&tmp, bytes);
|
||||
*n = bit_cast<f32>(tmp);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void loadLE<f64>(f64* n, const u8* bytes) {
|
||||
u64 tmp;
|
||||
loadLE(&tmp, bytes);
|
||||
*n = bit_cast<f64>(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#include "InstrReel.hpp"
|
||||
|
||||
#include <spider/runtime/cpu/CPU.hpp>
|
||||
|
||||
#include <spider/runtime/memory/Types.hpp>
|
||||
|
||||
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) {
|
||||
73
src/spider/runtime/reel/InstrReel.hpp
Normal file
73
src/spider/runtime/reel/InstrReel.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/SpiderRuntime.hpp>
|
||||
#include <spider/runtime/memory/ByteArray.hpp>
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
206
src/spider/runtime/reel/InstrReelDyn.cpp
Normal file
206
src/spider/runtime/reel/InstrReelDyn.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "InstrReelDyn.hpp"
|
||||
|
||||
#include <spider/runtime/memory/Types.hpp>
|
||||
|
||||
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<u64, u8> 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) {}
|
||||
|
||||
}
|
||||
110
src/spider/runtime/reel/InstrReelDyn.hpp
Normal file
110
src/spider/runtime/reel/InstrReelDyn.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/reel/InstrReel.hpp>
|
||||
|
||||
namespace spider {
|
||||
|
||||
/**
|
||||
* Implements an instruction reel.
|
||||
*/
|
||||
class InstrReelDyn : public InstrReel {
|
||||
private:
|
||||
|
||||
struct ReelBlock {
|
||||
u8 data[256] = {};
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
deque<ReelBlock> _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<u64, u8> 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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
0
src/spider/runtime/reel/InstrReelFile.hpp
Normal file
0
src/spider/runtime/reel/InstrReelFile.hpp
Normal file
183
src/spider/runtime/reel/InstrReelFixed.cpp
Normal file
183
src/spider/runtime/reel/InstrReelFixed.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
#include "InstrReelFixed.hpp"
|
||||
|
||||
#include <spider/runtime/memory/Types.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
92
src/spider/runtime/reel/InstrReelFixed.hpp
Normal file
92
src/spider/runtime/reel/InstrReelFixed.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/reel/InstrReel.hpp>
|
||||
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
277
src/spider/runtime/util/Terminal.cpp
Normal file
277
src/spider/runtime/util/Terminal.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
#include "Terminal.hpp"
|
||||
|
||||
#include <spider/runtime/native/distro.hpp>
|
||||
|
||||
#if defined(SPIDER_OS_WINDOWS)
|
||||
#include <conio.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if defined(SPIDER_DISTRO_DESKTOP)
|
||||
|
||||
namespace spider {
|
||||
|
||||
// Style //
|
||||
const char* Terminal::RESET = "\033[0m";
|
||||
const char* Terminal::BOLD = "\033[1m";
|
||||
const char* Terminal::ITALIC = "\033[3m";
|
||||
const char* Terminal::FAINT = "\033[2m";
|
||||
const char* Terminal::STRIKE = "\033[9m";
|
||||
|
||||
// Foreground //
|
||||
const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m";
|
||||
const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m";
|
||||
const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m";
|
||||
const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m";
|
||||
const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m";
|
||||
const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m";
|
||||
const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m";
|
||||
const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m";
|
||||
|
||||
// Background //
|
||||
const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m";
|
||||
const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m";
|
||||
const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m";
|
||||
const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m";
|
||||
const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m";
|
||||
const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m";
|
||||
const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m";
|
||||
const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m";
|
||||
|
||||
Terminal::Terminal() {
|
||||
#if defined(SPIDER_OS_WINDOWS)
|
||||
// Enable UTF-8
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
SetConsoleCP(CP_UTF8);
|
||||
|
||||
// enable vtp
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
GetConsoleMode(hOut, &dwMode);
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
SetConsoleMode(hOut, dwMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
Terminal::~Terminal() {
|
||||
altbuff(false).style(RESET).cursor(true).flush();
|
||||
}
|
||||
|
||||
Terminal& Terminal::style(const std::string_view code) {
|
||||
std::cout << code;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::move(i32 row, i32 col) {
|
||||
std::cout << "\033[" << row << ";" << col << "H";
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::altbuff(bool enable) {
|
||||
std::cout << (enable ? "\033[?1049h" : "\033[?1049l");
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::cls() {
|
||||
std::cout << "\033[2J";
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::scrollRange(i32 start, i32 end) {
|
||||
std::cout << "\033[" << start << ";" << end << "r\033[?6h";
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::undoSRange() {
|
||||
std::cout << "\033[r\033[?6l\033[H";
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::fill(const std::string_view color) {
|
||||
this->style(color);
|
||||
this->cls();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::clearRow(i32 row) {
|
||||
// Move to row, column 1
|
||||
this->move(row, 1);
|
||||
// \033[2K clears the entire line
|
||||
std::cout << "\033[2K";
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::clearRows(i32 start, i32 end) {
|
||||
// Ensure we don't loop infinitely if start > end
|
||||
if (start > end) std::swap(start, end);
|
||||
|
||||
for (i32 i = start; i <= end; ++i) {
|
||||
this->clearRow(i);
|
||||
}
|
||||
|
||||
// Optional: Move cursor back to the start of the cleared block
|
||||
this->move(start, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::cursor(bool show) {
|
||||
std::cout << (show ? "\033[?25h" : "\033[?25l");
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title) {
|
||||
// 1. Draw the top border
|
||||
move(startRow, startCol);
|
||||
std::cout << "┌";
|
||||
for (i32 i = 0; i < width - 2; ++i) std::cout << "─";
|
||||
std::cout << "┐";
|
||||
|
||||
// 2. Draw the sides
|
||||
for (i32 i = 1; i < height - 1; ++i) {
|
||||
move(startRow + i, startCol);
|
||||
std::cout << "│";
|
||||
move(startRow + i, startCol + width - 1);
|
||||
std::cout << "│";
|
||||
}
|
||||
|
||||
// 3. Draw the bottom border
|
||||
move(startRow + height - 1, startCol);
|
||||
std::cout << "└";
|
||||
for (i32 i = 0; i < width - 2; ++i) std::cout << "─";
|
||||
std::cout << "┘";
|
||||
|
||||
// 4. Overlay the title if provided
|
||||
if (!title.empty()) {
|
||||
move(startRow, startCol + (width - title.size() - 2) / 2);
|
||||
std::cout << " " << title << " ";
|
||||
}
|
||||
|
||||
std::cout.flush();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::flush() {
|
||||
std::cout << std::flush;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Terminal& Terminal::sink() {
|
||||
std::cin.clear();
|
||||
#if defined(SPIDER_OS_WINDOWS)
|
||||
while (_kbhit()) _getch();
|
||||
#endif
|
||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||
tcflush(STDIN_FILENO, TCIFLUSH);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::pair<i32, i32> Terminal::getSize() {
|
||||
std::pair<i32, i32> pair;
|
||||
#if defined(SPIDER_OS_WINDOWS)
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
|
||||
pair.first = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
pair.second = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||
}
|
||||
#endif
|
||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||
struct winsize w;
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
|
||||
pair.first = w.ws_col;
|
||||
pair.second = w.ws_row;
|
||||
}
|
||||
#endif
|
||||
return pair;
|
||||
}
|
||||
|
||||
Terminal& Terminal::wait() {
|
||||
sink();
|
||||
std::cin.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
u8 Terminal::getKey() {
|
||||
#if defined(SPIDER_OS_WINDOWS)
|
||||
i32 ch = _getch();
|
||||
if (ch == 0 || ch == 224) {
|
||||
switch (_getch()) {
|
||||
case 72: return Terminal::UP;
|
||||
case 80: return Terminal::DOWN;
|
||||
case 75: return Terminal::LEFT;
|
||||
case 77: return Terminal::RIGHT;
|
||||
default: return Terminal::UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (ch == 13) return Terminal::ENTER;
|
||||
if (ch == 27) return Terminal::ESC;
|
||||
if (ch == 8) return Terminal::BACKSPACE;
|
||||
return Terminal::UNKNOWN;
|
||||
#endif
|
||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||
struct termios oldt, newt;
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
|
||||
u8 result = Terminal::UNKNOWN;
|
||||
int ch = getchar();
|
||||
|
||||
if (ch == 27) { // Potential Escape Sequence
|
||||
// Use a small timeout or check if more chars are in buffer
|
||||
// to distinguish between 'Esc' key and 'Arrow' sequence
|
||||
// Another Win for the Win API
|
||||
struct timeval tv = { 0, 10000 }; // 10ms wait
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
|
||||
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
||||
if (getchar() == '[') {
|
||||
switch (getchar()) {
|
||||
case 'A': result = Terminal::UP; break;
|
||||
case 'B': result = Terminal::DOWN; break;
|
||||
case 'D': result = Terminal::LEFT; break;
|
||||
case 'C': result = Terminal::RIGHT; break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = Terminal::ESC;
|
||||
}
|
||||
} else if (ch == 10) result = Terminal::ENTER;
|
||||
else if (ch == 127) result = Terminal::BACKSPACE;
|
||||
else result = (u8)ch;
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 Terminal::getKeyNb() {
|
||||
#if defined(SPIDER_OS_WINDOWS)
|
||||
if (_kbhit()) return getKey();
|
||||
return Terminal::UNKNOWN;
|
||||
#endif
|
||||
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||
struct timeval tv = { 0, 0 };
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
// select() returns > 0 if there is data to read
|
||||
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
||||
return getKey();
|
||||
}
|
||||
return Terminal::UNKNOWN;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
176
src/spider/runtime/util/Terminal.hpp
Normal file
176
src/spider/runtime/util/Terminal.hpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#pragma once
|
||||
|
||||
#include <spider/runtime/common.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <sstream>
|
||||
|
||||
namespace spider {
|
||||
|
||||
class Terminal {
|
||||
public:
|
||||
|
||||
static const char* RESET;
|
||||
static const char* BOLD;
|
||||
static const char* ITALIC;
|
||||
static const char* FAINT;
|
||||
static const char* STRIKE;
|
||||
|
||||
static const char* FG_BLACK; static const char* FG_B_BLACK;
|
||||
static const char* FG_RED; static const char* FG_B_RED;
|
||||
static const char* FG_GREEN; static const char* FG_B_GREEN;
|
||||
static const char* FG_YELLOW; static const char* FG_B_YELLOW;
|
||||
static const char* FG_BLUE; static const char* FG_B_BLUE;
|
||||
static const char* FG_MAGENTA; static const char* FG_B_MAGENTA;
|
||||
static const char* FG_CYAN; static const char* FG_B_CYAN;
|
||||
static const char* FG_WHITE; static const char* FG_B_WHITE;
|
||||
|
||||
static const char* BG_BLACK; static const char* BG_B_BLACK;
|
||||
static const char* BG_RED; static const char* BG_B_RED;
|
||||
static const char* BG_GREEN; static const char* BG_B_GREEN;
|
||||
static const char* BG_YELLOW; static const char* BG_B_YELLOW;
|
||||
static const char* BG_BLUE; static const char* BG_B_BLUE;
|
||||
static const char* BG_MAGENTA; static const char* BG_B_MAGENTA;
|
||||
static const char* BG_CYAN; static const char* BG_B_CYAN;
|
||||
static const char* BG_WHITE; static const char* BG_B_WHITE;
|
||||
|
||||
public:
|
||||
|
||||
// Key Definitions (ASCII OK) //
|
||||
static constexpr const u8 UP = 0x80;
|
||||
static constexpr const u8 DOWN = 0x81;
|
||||
static constexpr const u8 LEFT = 0x82;
|
||||
static constexpr const u8 RIGHT = 0x83;
|
||||
static constexpr const u8 ENTER = 0x84;
|
||||
static constexpr const u8 ESC = 0x85;
|
||||
static constexpr const u8 BACKSPACE = 0x86;
|
||||
static constexpr const u8 UNKNOWN = 0xFF;
|
||||
|
||||
public:
|
||||
|
||||
Terminal();
|
||||
|
||||
~Terminal();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Sets a style
|
||||
*/
|
||||
Terminal& style(const std::string_view code);
|
||||
|
||||
/**
|
||||
* Fills the screen with a specific background color.
|
||||
* @param color The background color constant (e.g., Terminal::BG_BLUE)
|
||||
*/
|
||||
Terminal& fill(const std::string_view color);
|
||||
|
||||
/**
|
||||
* Moves the cursor.
|
||||
*/
|
||||
Terminal& move(i32 row, i32 col);
|
||||
|
||||
/**
|
||||
* Clears the screen
|
||||
*/
|
||||
Terminal& cls();
|
||||
|
||||
Terminal& altbuff(bool enable);
|
||||
|
||||
Terminal& scrollRange(i32 start, i32 end);
|
||||
|
||||
Terminal& undoSRange();
|
||||
|
||||
/**
|
||||
* Clears a specific row.
|
||||
* @param row The 1-based index of the row to clear.
|
||||
*/
|
||||
Terminal& clearRow(i32 row);
|
||||
|
||||
/**
|
||||
* Clears a range of rows (inclusive).
|
||||
* @param start The first row.
|
||||
* @param end The last row.
|
||||
*/
|
||||
Terminal& clearRows(i32 start, i32 end);
|
||||
|
||||
/**
|
||||
* Shows / Hides the cursor.
|
||||
*/
|
||||
Terminal& cursor(bool show);
|
||||
|
||||
public:
|
||||
|
||||
Terminal& drawBox(i32 startRow, i32 startCol, i32 width, i32 height, std::string_view title);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Flushes the output buffer
|
||||
*/
|
||||
Terminal& flush();
|
||||
|
||||
/**
|
||||
* Clears the input buffer.
|
||||
* Useful for some specific input cases
|
||||
*/
|
||||
Terminal& sink();
|
||||
|
||||
public:
|
||||
|
||||
Terminal& wait();
|
||||
|
||||
u8 getKey();
|
||||
|
||||
/**
|
||||
* Get key non blocking
|
||||
*/
|
||||
u8 getKeyNb();
|
||||
|
||||
std::pair<i32, i32> getSize();
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
Terminal& print(const T& msg) {
|
||||
std::cout << msg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Terminal& println(const T& msg) {
|
||||
std::cout << msg << "\n";
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Terminal& print_center(i32 width, const T& msg) {
|
||||
// to string
|
||||
std::ostringstream oss;
|
||||
oss << msg;
|
||||
std::string s = oss.str();
|
||||
|
||||
// then print
|
||||
if (s.length() >= isize(width)) {
|
||||
std::cout << s;
|
||||
} else {
|
||||
i32 total_padding = width - s.length();
|
||||
i32 left_padding = total_padding / 2;
|
||||
std::cout << std::string(left_padding, ' ');
|
||||
std::cout << s;
|
||||
std::cout << std::string(total_padding - left_padding, ' ');
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Terminal& read(T& var) {
|
||||
std::cin >> var;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user