Compare commits

..

19 Commits

Author SHA1 Message Date
Kittycannon 017a3f5f6d debug things 2026-06-16 10:59:48 -06:00
Kittycannon 708c4ab593 updated runtiem 2026-06-14 23:39:17 -06:00
Kittycannon 869ce0c7bf overengineered piece of shit, but compiles fine 2026-06-14 18:15:44 -06:00
Kittycannon 5f4c2abec8 fixed for library use 2026-06-13 13:12:06 -06:00
Kittycannon 0c21587e15 added interns easter eggs, compiles now 2026-06-13 12:45:29 -06:00
Kittycannon a36705a931 removed unnecessary things, updated and audited the code 2026-06-13 11:31:07 -06:00
AlmediaDaniel 29797fb707 test changes 2026-06-11 18:19:37 -06:00
AlmediaDaniel 22d7b0afbe test changes 2026-06-11 18:09:42 -06:00
AlmediaDaniel c3cf293bc9 test changes 2026-06-11 17:35:49 -06:00
AlmediaDaniel bc8fb3435d test changes 2026-06-11 17:34:45 -06:00
AlmediaDaniel 309b823f19 test changes 2026-06-11 17:33:28 -06:00
AlmediaDaniel 31dd45c932 test changes 2026-06-11 17:31:48 -06:00
AlmediaDaniel c018c2c668 undo changes 2026-06-11 17:13:24 -06:00
AlmediaDaniel 2d89f489ae test changes 2026-06-11 17:12:23 -06:00
AlmediaDaniel f1bb779e86 added breaks and removed (this -> *post) 2026-06-11 16:52:51 -06:00
AlmediaDaniel 56114dc1b6 deletion of instructions file outside instr folder. intruction changes 2026-06-11 16:05:06 -06:00
AlmediaDaniel 417bef1aa5 TSB changes 2026-06-11 15:44:53 -06:00
AlmediaDaniel 7cddb55469 TSB changes 2026-06-11 15:43:42 -06:00
AlmediaDaniel 7722e450d4 test changes 2026-06-11 15:25:20 -06:00
24 changed files with 1587 additions and 2488 deletions
-452
View File
@@ -1,452 +0,0 @@
/**
* @brief AUTO-GENERATED by pygen.ipynb BUT editable by hand!
*
*/
#include <spider/runtime/cpu/CPU.hpp>
namespace spider {
void CPU::STB() {
// TODO: Implement STB
fetchOperSrc();
fetchOperDst();
switch(_size){
case 0b00: //byte
_dst->_u8 |= (1 << _src->_u8);
break;
case 0b01: //short
_dst->_u16 |= (1 << _src->_u16);
break;
case 0b10: //int
_dst->_u32 |= (1 << _src->_u32);
break;
case 0b11: //long
_dst->_u64 |= (1 << _src->_u64);
break;
}
}
void CPU::CRB() {
// TODO: Implement CRB
fetchOperSrc();
fetchOperDst();
switch(_size){
case 0b00: //byte
_dst->_u8 &= ~(1 << _src->_u8);
break;
case 0b01: //short
_dst->_u16 &= ~(1 << _src->_u16);
break;
case 0b10: //int
_dst->_u32 &= ~(1 << _src->_u32);
break;
case 0b11: //long
_dst->_u64 &= ~(1 << _src->_u64);
break;
}
}
void CPU::TSB() {
// TODO: Implement TSB
fetchOperSrc();
fetchOperDst();
switch(_size){
case 0b00: //byte
switch (((RF >> _src->_u8) & 1) != ((_dst->_u8 >> _src->_u8) & 1)){
case 1:
RF |= (1 << _src->_u8);
break;
case 0:
RF &= ~(1 << _src->_u8);
break;
}
break;
case 0b01: //short
switch (((RF >> _src->_u16) & 1) != ((_dst->_u16 >> _src->_u16) & 1)){
case 1:
RF |= (1 << _src->_u16);
break;
case 0:
RF &= ~(1 << _src->_u16);
break;
}
break;
case 0b10: //int
switch (((RF >> _src->_u32) & 1) != ((_dst->_u32 >> _src->_u32) & 1)){
case 1:
RF |= (1 << _src->_u32);
break;
case 0:
RF &= ~(1 << _src->_u32);
break;
}
break;
case 0b11: //long
switch (((RF >> _src->_u64) & 1) != ((_dst->_u64 >> _src->_u64) & 1)){
case 1:
RF |= (1 << _src->_u64);
break;
case 0:
RF &= ~(1 << _src->_u64);
break;
}
break;
}
}
void CPU::BOOL() {
// TODO: Implement BOOL
fetchOperDst();
switch(_size){
case 0b00: //byte
_dst->_u8 = _dst != 0;
break;
case 0b01: //short
_dst->_u16 = _dst != 0;
break;
case 0b10: //int
_dst->_u32 = _dst != 0;
break;
case 0b11: //long
_dst->_u64 = _dst != 0;
break;
}
}
// ── 0x024 — NOT: Tests Dst == 0, updates Equal Flag ──
void CPU::NOT() {
fetchOperDst();
bool isZero = false;
switch(_size) {
case 0b00: isZero = (_dst->_u8 == 0); break;
case 0b01: isZero = (_dst->_u16 == 0); break;
case 0b10: isZero = (_dst->_u32 == 0); break;
case 0b11: isZero = (_dst->_u64 == 0); break;
}
if (isZero) {
RF |= CPU::FLAG_EQUAL; // Si es 0, el resultado de !0 es true (1), actualizamos bandera
// Dependiendo de la implementación de BOOL, podrías querer guardar el resultado en Dst
_dst->_u64 = 1;
} else {
RF &= ~CPU::FLAG_EQUAL;
_dst->_u64 = 0;
}
}
// ── 0x025 — AND
void CPU::AND() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 &= _src->_u8; break;
case 0b01: _dst->_u16 &= _src->_u16; break;
case 0b10: _dst->_u32 &= _src->_u32; break;
case 0b11: _dst->_u64 &= _src->_u64; break;
}
}
// ── 0x026 — OR
void CPU::OR() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 |= _src->_u8; break;
case 0b01: _dst->_u16 |= _src->_u16; break;
case 0b10: _dst->_u32 |= _src->_u32; break;
case 0b11: _dst->_u64 |= _src->_u64; break;
}
}
// ── 0x027 — XOR
void CPU::XOR() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 ^= _src->_u8; break;
case 0b01: _dst->_u16 ^= _src->_u16; break;
case 0b10: _dst->_u32 ^= _src->_u32; break;
case 0b11: _dst->_u64 ^= _src->_u64; break;
}
}
// ── 0x028 — SHL
void CPU::SHL() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 <<= _src->_u8; break;
case 0b01: _dst->_u16 <<= _src->_u16; break;
case 0b10: _dst->_u32 <<= _src->_u32; break;
case 0b11: _dst->_u64 <<= _src->_u64; break;
}
}
// ── 0x029 — SHR
void CPU::SHR() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 >>= _src->_u8; break;
case 0b01: _dst->_u16 >>= _src->_u16; break;
case 0b10: _dst->_u32 >>= _src->_u32; break;
case 0b11: _dst->_u64 >>= _src->_u64; break;
}
}
// ── 0x02A — SSR
void CPU::SSR() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_i8 >>= _src->_u8; break;
case 0b01: _dst->_i16 >>= _src->_u8; break;
case 0b10: _dst->_i32 >>= _src->_u8; break;
case 0b11: _dst->_i64 >>= _src->_u8; break;
}
}
// ── 0x02B — ROL: Rotate Left ──
void CPU::ROL() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 = (_dst->_u8 << _src->_u8) | (_dst->_u8 >> (8 - _src->_u8)); break;
case 0b01: _dst->_u16 = (_dst->_u16 << _src->_u8) | (_dst->_u16 >> (16 - _src->_u8)); break;
case 0b10: _dst->_u32 = (_dst->_u32 << _src->_u8) | (_dst->_u32 >> (32 - _src->_u8)); break;
case 0b11: _dst->_u64 = (_dst->_u64 << _src->_u8) | (_dst->_u64 >> (64 - _src->_u8)); break;
}
}
// ── 0x02C — ROR: Rotate Right ──
void CPU::ROR() {
fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 = (_dst->_u8 >> _src->_u8) | (_dst->_u8 << (8 - _src->_u8)); break;
case 0b01: _dst->_u16 = (_dst->_u16 >> _src->_u8) | (_dst->_u16 << (16 - _src->_u8)); break;
case 0b10: _dst->_u32 = (_dst->_u32 >> _src->_u8) | (_dst->_u32 << (32 - _src->_u8)); break;
case 0b11: _dst->_u64 = (_dst->_u64 >> _src->_u8) | (_dst->_u64 << (64 - _src->_u8)); break;
}
}
// ── 0x02D — CNT: Counts bits (# of 1's into Dst) ──
void CPU::CNT() {
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 = __builtin_popcount(_dst->_u8); break;
case 0b01: _dst->_u16 = __builtin_popcount(_dst->_u16); break;
case 0b10: _dst->_u32 = __builtin_popcount(_dst->_u32); break;
case 0b11: _dst->_u64 = __builtin_popcountll(_dst->_u64); break;
}
}
// ── 0x030 — EQ: Dst == Src into Dst ──
void CPU::EQ() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 == _src->_u8); break;
case 0b01: res = (_dst->_u16 == _src->_u16); break;
case 0b10: res = (_dst->_u32 == _src->_u32); break;
case 0b11: res = (_dst->_u64 == _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x031 — NE: Dst != Src into Dst ──
void CPU::NE() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 != _src->_u8); break;
case 0b01: res = (_dst->_u16 != _src->_u16); break;
case 0b10: res = (_dst->_u32 != _src->_u32); break;
case 0b11: res = (_dst->_u64 != _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x032 — GT: Dst > Src into Dst ──
void CPU::GT() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 > _src->_i8); break;
case 0b01: res = (_dst->_i16 > _src->_i16); break;
case 0b10: res = (_dst->_i32 > _src->_i32); break;
case 0b11: res = (_dst->_i64 > _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x033 — GE: Dst >= Src into Dst ──
void CPU::GE() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 >= _src->_i8); break;
case 0b01: res = (_dst->_i16 >= _src->_i16); break;
case 0b10: res = (_dst->_i32 >= _src->_i32); break;
case 0b11: res = (_dst->_i64 >= _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x034 — LT: Dst < Src into Dst ──
void CPU::LT() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 < _src->_i8); break;
case 0b01: res = (_dst->_i16 < _src->_i16); break;
case 0b10: res = (_dst->_i32 < _src->_i32); break;
case 0b11: res = (_dst->_i64 < _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x035 — LE: Dst <= Src into Dst ──
void CPU::LE() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 <= _src->_i8); break;
case 0b01: res = (_dst->_i16 <= _src->_i16); break;
case 0b10: res = (_dst->_i32 <= _src->_i32); break;
case 0b11: res = (_dst->_i64 <= _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x038 — JMP: Dst -> Instruction Register (PC) ──
// The IR adds 1 at the end, so we subtract 1 to compensate.
void CPU::JMP() {
fetchOperDst();
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
// ── 0x039 — JEQ: Jump if EQ flag is set ──
void CPU::JEQ() {
fetchOperDst();
if (RF & CPU::FLAG_EQUAL) {
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
}
// ── 0x03A — JNE: Jumps if EQ flag is cleared ──
void CPU::JNE() {
fetchOperDst();
if (!(RF & CPU::FLAG_EQUAL)) {
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
}
// ── 0x03B — JIF: Jumps if Src is booleanly true ──
void CPU::JIF() {
fetchOperSrc();
fetchOperDst();
if (_src->_u64 != 0) {
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
}
// ── 0x03C — JMR: Dst + Instruction Register -> Instruction Register ──
void CPU::JMR() {
fetchOperDst();
i64 offset;
switch (_size) {
case 0b00: offset = static_cast<i64>(_dst->_i8); break; // 1 byte
case 0b01: offset = static_cast<i64>(_dst->_i16); break; // 2 bytes
case 0b10: offset = static_cast<i64>(_dst->_i32); break; // 4 bytes
case 0b11: offset = _dst->_i64; break; // 8 bytes
}
RI = static_cast<u64>(static_cast<i64>(RI) + offset);
}
// ── 0x03D — JER: Dst + Instruction Register -> Instruction Register IF Flags.EQ ──
void CPU::JER() {
fetchOperDst();
if (RF & CPU::FLAG_EQUAL) {
i64 offset;
switch (_size) {
case 0b00: offset = static_cast<i64>(_dst->_i8); break;
case 0b01: offset = static_cast<i64>(_dst->_i16); break;
case 0b10: offset = static_cast<i64>(_dst->_i32); break;
case 0b11: offset = _dst->_i64; break;
}
RI = static_cast<u64>(static_cast<i64>(RI) + offset);
}
}
// ── 0x03E — JNR: Dst + Instruction Register -> Instruction Register IF NOT Flags.EQ ──
void CPU::JNR() {
fetchOperDst();
if (!(RF & CPU::FLAG_EQUAL)) {
i64 offset;
switch (_size) {
case 0b00: offset = static_cast<i64>(_dst->_i8); break;
case 0b01: offset = static_cast<i64>(_dst->_i16); break;
case 0b10: offset = static_cast<i64>(_dst->_i32); break;
case 0b11: offset = _dst->_i64; break;
}
RI = static_cast<u64>(static_cast<i64>(RI) + offset);
}
}
// ── 0x03F — JIR: Dst + Instruction Register -> Instruction Register IF Src ──
void CPU::JIR() {
fetchOperSrc();
fetchOperDst();
if (_src->_u64 != 0) {
i64 offset;
switch (_size) {
case 0b00: offset = static_cast<i64>(_dst->_i8); break;
case 0b01: offset = static_cast<i64>(_dst->_i16); break;
case 0b10: offset = static_cast<i64>(_dst->_i32); break;
case 0b11: offset = _dst->_i64; break;
}
RI = static_cast<u64>(static_cast<i64>(RI) + offset);
}
}
}
+20 -4
View File
@@ -21,7 +21,6 @@ constexpr u8 ADDR_MODE_MASKS[][2] = {
{ 0x04, 0x04 }, // MOR { 0x04, 0x04 }, // MOR
{ 0x00, 0x00 }, // AMOV { 0x00, 0x00 }, // AMOV
{ 0x04, 0x04 }, // SWP { 0x04, 0x04 }, // SWP
{ 0x04, 0x00 }, // AHM
{ 0xFF, 0x00 }, // COM { 0xFF, 0x00 }, // COM
{ 0xFF, 0x00 }, // NEG { 0xFF, 0x00 }, // NEG
{ 0xFF, 0x00 }, // EXS { 0xFF, 0x00 }, // EXS
@@ -37,7 +36,6 @@ constexpr u8 ADDR_MODE_MASKS[][2] = {
{ 0x1E, 0xFF }, // UMOD { 0x1E, 0xFF }, // UMOD
{ 0x1E, 0xFF }, // DMOD { 0x1E, 0xFF }, // DMOD
{ 0x1E, 0xFF }, // UDMD { 0x1E, 0xFF }, // UDMD
{ 0xFF, 0x00 }, // FBT
{ 0x1E, 0xFF }, // STB { 0x1E, 0xFF }, // STB
{ 0x1E, 0xFF }, // CRB { 0x1E, 0xFF }, // CRB
{ 0x1E, 0xFF }, // TSB { 0x1E, 0xFF }, // TSB
@@ -58,6 +56,10 @@ constexpr u8 ADDR_MODE_MASKS[][2] = {
{ 0x1E, 0xFF }, // GE { 0x1E, 0xFF }, // GE
{ 0x1E, 0xFF }, // LT { 0x1E, 0xFF }, // LT
{ 0x1E, 0xFF }, // LE { 0x1E, 0xFF }, // LE
{ 0x1E, 0xFF }, // GTU
{ 0x1E, 0xFF }, // GEU
{ 0x1E, 0xFF }, // LTU
{ 0x1E, 0xFF }, // LEU
{ 0xFF, 0x00 }, // JMP { 0xFF, 0x00 }, // JMP
{ 0xFF, 0x00 }, // JEQ { 0xFF, 0x00 }, // JEQ
{ 0xFF, 0x00 }, // JNE { 0xFF, 0x00 }, // JNE
@@ -135,6 +137,12 @@ constexpr u8 ADDR_MODE_MASKS[][2] = {
{ 0x00, 0x00 }, // XMUL { 0x00, 0x00 }, // XMUL
{ 0x00, 0x00 }, // XDIV { 0x00, 0x00 }, // XDIV
{ 0x00, 0x00 }, // UPY { 0x00, 0x00 }, // UPY
{ 0x00, 0x00 }, // INT_1_SLOT
{ 0x00, 0x00 }, // INT_2_SLOT
{ 0x00, 0x00 }, // INT_3_SLOT
{ 0x00, 0x00 }, // INT_4_SLOT
{ 0x00, 0x00 }, // BRAD
{ 0x00, 0x00 }, // DGANT
}; };
// Type size masks — indexed by opcode. // Type size masks — indexed by opcode.
@@ -153,7 +161,6 @@ constexpr u8 TYPE_SIZE_MASKS[] = {
0x08, // MOR 0x08, // MOR
0x08, // AMOV 0x08, // AMOV
0x08, // SWP 0x08, // SWP
0x08, // AHM
0x0F, // COM 0x0F, // COM
0x0F, // NEG 0x0F, // NEG
0x0F, // EXS 0x0F, // EXS
@@ -169,7 +176,6 @@ constexpr u8 TYPE_SIZE_MASKS[] = {
0x0F, // UMOD 0x0F, // UMOD
0x0F, // DMOD 0x0F, // DMOD
0x0F, // UDMD 0x0F, // UDMD
0x0F, // FBT
0x0F, // STB 0x0F, // STB
0x0F, // CRB 0x0F, // CRB
0x0F, // TSB 0x0F, // TSB
@@ -190,6 +196,10 @@ constexpr u8 TYPE_SIZE_MASKS[] = {
0x0F, // GE 0x0F, // GE
0x0F, // LT 0x0F, // LT
0x0F, // LE 0x0F, // LE
0x0F, // GTU
0x0F, // GEU
0x0F, // LTU
0x0F, // LEU
0x0F, // JMP 0x0F, // JMP
0x0F, // JEQ 0x0F, // JEQ
0x0F, // JNE 0x0F, // JNE
@@ -267,6 +277,12 @@ constexpr u8 TYPE_SIZE_MASKS[] = {
0x00, // XMUL 0x00, // XMUL
0x00, // XDIV 0x00, // XDIV
0x00, // UPY 0x00, // UPY
0x00, // INT_1_SLOT
0x00, // INT_2_SLOT
0x00, // INT_3_SLOT
0x00, // INT_4_SLOT
0x00, // BRAD
0x00, // DGANT
}; };
} // namespace spider } // namespace spider
-658
View File
@@ -1,658 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "1c7a11d9",
"metadata": {},
"source": [
"This test will test (lol) the calling convention in Spider.\n",
"As defined, it will use the CPU as a python object.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "b9c572cd",
"metadata": {},
"outputs": [],
"source": [
"# The state of the \"my-language-name\" vm in a simple\n",
"# python object abstraction\n",
"my_language_name_vm = {\n",
" 'regs':{\n",
" 'RA':0,\n",
" 'RB':0,\n",
" 'RC':0,\n",
" 'RD':0,\n",
" 'RX':0,\n",
" 'RY':0,\n",
" 'R0':0,\n",
" 'R1':0,\n",
" 'R2':0,\n",
" 'R3':0,\n",
" 'R4':0,\n",
" 'R5':0,\n",
" 'R6':0,\n",
" 'R7':0,\n",
" 'R8':0,\n",
" 'R9':0,\n",
" 'RF':0,\n",
" 'RI':0,\n",
" 'RS':0,\n",
" 'RZ':0,\n",
" 'RE':0,\n",
" 'RH':0,\n",
" 'RV':0,\n",
" 'RM':0,\n",
" },\n",
" 'stack': [],\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "3e3989dc",
"metadata": {},
"source": [
"**Test Data Definition**\n",
"\n",
"This block defines the parameters we want to pass into our hypothetical function and what we expect it to return. We use a mix of large data structures (sizes in bytes) and booleans (size 1) to force the VM to use all of its memory allocation rules."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "a1ddd324",
"metadata": {},
"outputs": [],
"source": [
"# Input parameters, measured in bytes (booleans are size 1 for logic triggers)\n",
"input_params = [\n",
" {'name': 'int_a', 'size': 4}, # Should go to RA\n",
" {'name': 'bool_1', 'size': 1}, # Should be queued\n",
" {'name': 'bool_2', 'size': 1}, # Should be queued\n",
" {'name': 'double_b', 'size': 8}, # Should go to RB\n",
" {'name': 'big_struct', 'size': 32} # Too large for registers, forces stack usage\n",
"]\n",
"\n",
"# Define the return types here\n",
"output_return = [ \n",
" {'name': 'ret1', 'size': 8} \n",
"]"
]
},
{
"cell_type": "markdown",
"id": "bbe2c356",
"metadata": {},
"source": [
"Now, on this function it will perform the tasks of ordering the registers and stack based on the parameters.\n",
"\n",
"**The Function Call ABI**\n",
"This is the core logic. It prepares the VM for a jump to another function by safely backing up the current context and routing the parameters to either the registers or the stack according to the strict hardware rules.\n",
"\n",
"**Step 1**: It pushes the caller-saved registers (R0-R3) to the stack so they aren't lost.\n",
"\n",
"**Step 2**: It checks if the function will return a massive object (> 16 bytes). If so, it reserves a pointer space.\n",
"\n",
"**Step 3**: It attempts to put parameters into RA, RB, RC, RD, R8, R9. Booleans are packed together to save space.\n",
"\n",
"**Step 4**: Anything that overflows the registers is pushed to the stack."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "02a2ad1a",
"metadata": {},
"outputs": [],
"source": [
"def do_function_call(input_params: list, output_return: list):\n",
" global my_language_name_vm\n",
" \n",
" print(\"--- 1. Saving Caller State ---\")\n",
" # Paso 1: Respaldar registros salvados por el llamador (R0-R3) \n",
" caller_saved = ['R0', 'R1', 'R2', 'R3']\n",
" for reg in caller_saved:\n",
" my_language_name_vm['stack'].append(my_language_name_vm['regs'][reg])\n",
" \n",
" print(\"--- 2. Allocating Parameters ---\")\n",
" \n",
" # Regla: Si el retorno > 16 bytes, se agrega un puntero al INICIO de los parámetros \n",
" actual_params = input_params.copy()\n",
" ret_size = sum(r['size'] for r in output_return)\n",
" if ret_size > 16:\n",
" # Se inserta al frente para que ocupe RA (o el primer espacio disponible) \n",
" actual_params.insert(0, {'name': 'RET_PTR_ALLOCATION', 'size': 8}) \n",
"\n",
" param_regs = ['RA', 'RB', 'RC', 'RD', 'R8', 'R9'] # \n",
" reg_idx = 0\n",
" bool_queue = []\n",
" stack_params = []\n",
" \n",
" # --- FASE 1: ASIGNACIÓN A REGISTROS ---\n",
" for param in actual_params:\n",
" if reg_idx < len(param_regs):\n",
" if param['size'] == 1: # Es Booleano \n",
" bool_queue.append(param['name'])\n",
" if len(bool_queue) == 8: # Cola llena (8 bytes/bits según lógica de la VM) \n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = f\"Packed_Bools({','.join(bool_queue)})\"\n",
" reg_idx += 1\n",
" bool_queue = []\n",
" elif param['size'] <= 8: # Parámetro estándar\n",
" # Antes de asignar un no-booleano, si hay booleanos pendientes, se deben flashear \n",
" if bool_queue:\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = f\"Padded_Bools({len(bool_queue)})\"\n",
" reg_idx += 1\n",
" bool_queue = []\n",
" \n",
" if reg_idx < len(param_regs):\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = param['name']\n",
" reg_idx += 1\n",
" else:\n",
" stack_params.append(param)\n",
" else:\n",
" # Si es muy grande para un registro (>8), va a la pila después \n",
" stack_params.append(param)\n",
" else:\n",
" stack_params.append(param)\n",
"\n",
" # Flashear booleanos restantes si queda espacio en registros \n",
" if bool_queue and reg_idx < len(param_regs):\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = f\"Padded_Bools({len(bool_queue)})\"\n",
" reg_idx += 1\n",
" bool_queue = []\n",
" elif bool_queue:\n",
" # Si no hubo registros, los booleanos pendientes pasan a la lógica de pila\n",
" stack_params = [{'name': b, 'size': 1} for b in bool_queue] + stack_params\n",
" bool_queue = []\n",
"\n",
" # Regla VI: Si sobran registros, guardar SP y respaldar en stack \n",
" while reg_idx < len(param_regs):\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = \"SP_Backup\"\n",
" my_language_name_vm['stack'].append(f\"SP_for_{param_regs[reg_idx]}\")\n",
" reg_idx += 1\n",
"\n",
" # --- FASE 2: ASIGNACIÓN A PILA ---\n",
" # 1. Parámetros <= 8 bytes (no booleanos)\n",
" remaining_large = []\n",
" for param in stack_params:\n",
" if param['size'] == 1:\n",
" bool_queue.append(param['name'])\n",
" if len(bool_queue) == 8: # Formó un \"byte\" (o bloque) \n",
" my_language_name_vm['stack'].append(\"Packed_Bools_Stack\")\n",
" bool_queue = []\n",
" elif param['size'] <= 8:\n",
" my_language_name_vm['stack'].append(param['name'])\n",
" else:\n",
" remaining_large.append(param)\n",
" \n",
" # Flashear booleanos de la pila con padding \n",
" if bool_queue:\n",
" my_language_name_vm['stack'].append(\"Padded_Bools_Stack\")\n",
" \n",
" # 2. Finalmente parámetros grandes en orden \n",
" for param in remaining_large:\n",
" my_language_name_vm['stack'].append(f\"LARGE_{param['name']}\")"
]
},
{
"cell_type": "markdown",
"id": "ac6440ca",
"metadata": {},
"source": [
"Now, unwind the stack and stuff to make sure the machine goes back to its previous state BEFORE the function\n",
"\n",
"**The Function Cleanup ABI**\n",
"Once the target function finishes executing and returns its answer in the registers, the caller function must clean up the mess it made on the stack before continuing.\n",
"\n",
"**Step 1**: It pops all the parameters that were pushed to the stack.\n",
"\n",
"**Step 2**: It pops the backup copies of R0-R3 and puts them back into the actual registers, restoring the caller's state perfectly."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "d2e4ce44",
"metadata": {},
"outputs": [],
"source": [
"# TODO \n",
"def undo_function_call(input_params: list, output_return: list):\n",
" global my_language_name_vm\n",
" \n",
" print(\"--- 3. Cleaning Up Stack ---\")\n",
" \n",
" # 1. Calcular EXACTAMENTE cuántos elementos se pusieron en la pila (simulando la asignación)\n",
" pops_needed = 0\n",
" \n",
" ret_size = sum(r['size'] for r in output_return)\n",
" if ret_size > 16:\n",
" pops_needed += 1\n",
" \n",
" param_regs = ['RA', 'RB', 'RC', 'RD', 'R8', 'R9']\n",
" reg_idx = 0\n",
" bool_queue = []\n",
" stack_params = []\n",
" \n",
" # Simular qué se fue a registros y qué se fue a la pila\n",
" for param in input_params:\n",
" if reg_idx < len(param_regs):\n",
" if param['size'] == 1:\n",
" bool_queue.append(param['name'])\n",
" if len(bool_queue) == 8:\n",
" reg_idx += 1\n",
" bool_queue = []\n",
" elif param['size'] <= 8:\n",
" reg_idx += 1\n",
" elif param['size'] <= 16 and (len(param_regs) - reg_idx) >= 2:\n",
" reg_idx += 2\n",
" else:\n",
" stack_params.append(param)\n",
" else:\n",
" stack_params.append(param)\n",
" \n",
" if len(bool_queue) > 0 and reg_idx < len(param_regs):\n",
" reg_idx += 1\n",
" bool_queue = []\n",
" \n",
" # Contar los respaldos del Stack Pointer (SP)\n",
" while reg_idx < len(param_regs):\n",
" pops_needed += 1 \n",
" reg_idx += 1\n",
" \n",
" # Contar los argumentos reales que cayeron en la pila\n",
" for param in stack_params:\n",
" if param['size'] == 1:\n",
" bool_queue.append(param['name'])\n",
" if len(bool_queue) == 8:\n",
" pops_needed += 1\n",
" bool_queue = []\n",
" else:\n",
" pops_needed += 1 # Tanto <=8 como >8 ocupan 1 espacio en nuestra lista de Python\n",
" \n",
" if len(bool_queue) > 0:\n",
" pops_needed += 1\n",
"\n",
" # 2. Hacer pop EXACTAMENTE de la cantidad calculada\n",
" for _ in range(pops_needed):\n",
" if my_language_name_vm['stack']:\n",
" removed = my_language_name_vm['stack'].pop()\n",
" print(f\"Popped parameter: {removed}\")\n",
" \n",
" # 3. Restaurar los Caller-Saved registers (siempre son 4)\n",
" print(\"--- 4. Restoring Caller Registers ---\")\n",
" caller_saved_order = ['R3', 'R2', 'R1', 'R0']\n",
" for reg in caller_saved_order:\n",
" if my_language_name_vm['stack']:\n",
" restored_val = my_language_name_vm['stack'].pop()\n",
" my_language_name_vm['regs'][reg] = restored_val\n",
" print(f\"Restored {reg} <- {restored_val}\")"
]
},
{
"cell_type": "markdown",
"id": "5397697f",
"metadata": {},
"source": [
"VERY GOOD\n",
"Now check the state of the machine before and after\n",
"\n",
"Try different combinations: One function call, multiple function calls, recursive calls, etc."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "b58fbf72",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--- 1. Saving Caller State ---\n",
"--- 2. Allocating Parameters ---\n",
"\n",
"[STATE AFTER CALL]\n",
"Registers: {'RA': 'int_a', 'RB': 'Padded_Bools(2)', 'RC': 'double_b', 'RD': 'SP_Backup', 'R8': 'SP_Backup', 'R9': 'SP_Backup'}\n",
"Stack: [0, 0, 0, 0, 'SP_for_RD', 'SP_for_R8', 'SP_for_R9', 'LARGE_big_struct']\n",
"\n",
"========================================\n",
"\n",
"--- 3. Cleaning Up Stack ---\n",
"Popped parameter: LARGE_big_struct\n",
"Popped parameter: SP_for_R9\n",
"Popped parameter: SP_for_R8\n",
"Popped parameter: SP_for_RD\n",
"--- 4. Restoring Caller Registers ---\n",
"Restored R3 <- 0\n",
"Restored R2 <- 0\n",
"Restored R1 <- 0\n",
"Restored R0 <- 0\n",
"\n",
"[STATE AFTER RETURN]\n",
"Registers: {'RA': 'int_a', 'RB': 'Padded_Bools(2)', 'RC': 'double_b', 'RD': 'SP_Backup', 'R8': 'SP_Backup', 'R9': 'SP_Backup'}\n",
"Stack: []\n"
]
}
],
"source": [
"# Execute the call simulation\n",
"do_function_call(input_params, output_return)\n",
"\n",
"print(\"\\n[STATE AFTER CALL]\")\n",
"print(\"Registers:\", {k: v for k, v in my_language_name_vm['regs'].items() if v != 0})\n",
"print(\"Stack:\", my_language_name_vm['stack'])\n",
"print(\"\\n\" + \"=\"*40 + \"\\n\")\n",
"\n",
"# Execute the cleanup simulation\n",
"undo_function_call(input_params, output_return)\n",
"\n",
"print(\"\\n[STATE AFTER RETURN]\")\n",
"print(\"Registers:\", {k: v for k, v in my_language_name_vm['regs'].items() if v != 0})\n",
"print(\"Stack:\", my_language_name_vm['stack'])"
]
},
{
"cell_type": "markdown",
"id": "4f700ac0",
"metadata": {},
"source": [
"**Setup and Helper Function**\n",
"First, let's create a quick helper to reset the VM so each test starts with a clean slate."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "d225a397",
"metadata": {},
"outputs": [],
"source": [
"def reset_vm():\n",
" global my_language_name_vm\n",
" my_language_name_vm['stack'] = []\n",
" for k in my_language_name_vm['regs']:\n",
" my_language_name_vm['regs'][k] = 0\n",
"\n",
"# Standard parameters for testing\n",
"test_params = [{'name': 'data', 'size': 8}]\n",
"test_returns = [{'name': 'ret', 'size': 8}]"
]
},
{
"cell_type": "markdown",
"id": "77df0216",
"metadata": {},
"source": [
"**Test - Sequential Calls**\n",
"This tests if the VM can call a function, clean up, and immediately call another function without the stack growing infinitely."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "70347484",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== TEST 1: MULTIPLE SEQUENTIAL CALLS ===\n",
"[Calling Function A]\n",
"--- 1. Saving Caller State ---\n",
"--- 2. Allocating Parameters ---\n",
"--- 3. Cleaning Up Stack ---\n",
"Popped parameter: SP_for_R9\n",
"Popped parameter: SP_for_R8\n",
"Popped parameter: SP_for_RD\n",
"Popped parameter: SP_for_RC\n",
"Popped parameter: SP_for_RB\n",
"--- 4. Restoring Caller Registers ---\n",
"Restored R3 <- 0\n",
"Restored R2 <- 0\n",
"Restored R1 <- 0\n",
"Restored R0 <- 0\n",
"\n",
"[Calling Function B]\n",
"--- 1. Saving Caller State ---\n",
"--- 2. Allocating Parameters ---\n",
"--- 3. Cleaning Up Stack ---\n",
"Popped parameter: SP_for_R9\n",
"Popped parameter: SP_for_R8\n",
"Popped parameter: SP_for_RD\n",
"Popped parameter: SP_for_RC\n",
"Popped parameter: SP_for_RB\n",
"--- 4. Restoring Caller Registers ---\n",
"Restored R3 <- 0\n",
"Restored R2 <- 0\n",
"Restored R1 <- 0\n",
"Restored R0 <- 0\n",
"\n",
"Final Stack (Should be empty): []\n"
]
}
],
"source": [
"print(\"=== TEST 1: MULTIPLE SEQUENTIAL CALLS ===\")\n",
"reset_vm()\n",
"\n",
"print(\"[Calling Function A]\")\n",
"do_function_call(test_params, test_returns)\n",
"undo_function_call(test_params, test_returns)\n",
"\n",
"print(\"\\n[Calling Function B]\")\n",
"do_function_call(test_params, test_returns)\n",
"undo_function_call(test_params, test_returns)\n",
"\n",
"print(\"\\nFinal Stack (Should be empty):\", my_language_name_vm['stack'])"
]
},
{
"cell_type": "markdown",
"id": "27f37c95",
"metadata": {},
"source": [
"**Test - Recursive / Nested Calls**\n",
"This is the most critical test. If Function A calls Function B, the VM must push a second frame onto the stack without destroying Function A's caller-saved registers (R0-R3)."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "0c46e3f2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== TEST 2: NESTED / RECURSIVE CALLS ===\n",
"\n",
"[1. Calling Outer Function]\n",
"--- 1. Saving Caller State ---\n",
"--- 2. Allocating Parameters ---\n",
"Outer function modifies R0: IMPORTANT_OUTER_DATA\n",
"\n",
"[2. Calling Inner Function (Nested)]\n",
"--- 1. Saving Caller State ---\n",
"--- 2. Allocating Parameters ---\n",
"Stack depth during nested call: 18\n",
"\n",
"[3. Returning from Inner Function]\n",
"--- 3. Cleaning Up Stack ---\n",
"Popped parameter: SP_for_R9\n",
"Popped parameter: SP_for_R8\n",
"Popped parameter: SP_for_RD\n",
"Popped parameter: SP_for_RC\n",
"Popped parameter: SP_for_RB\n",
"--- 4. Restoring Caller Registers ---\n",
"Restored R3 <- 0\n",
"Restored R2 <- 0\n",
"Restored R1 <- 0\n",
"Restored R0 <- IMPORTANT_OUTER_DATA\n",
"Did R0 survive the nested call?: IMPORTANT_OUTER_DATA\n",
"\n",
"[4. Returning from Outer Function]\n",
"--- 3. Cleaning Up Stack ---\n",
"Popped parameter: SP_for_R9\n",
"Popped parameter: SP_for_R8\n",
"Popped parameter: SP_for_RD\n",
"Popped parameter: SP_for_RC\n",
"Popped parameter: SP_for_RB\n",
"--- 4. Restoring Caller Registers ---\n",
"Restored R3 <- 0\n",
"Restored R2 <- 0\n",
"Restored R1 <- 0\n",
"Restored R0 <- 0\n",
"\n",
"Final Stack (Should be empty): []\n"
]
}
],
"source": [
"print(\"=== TEST 2: NESTED / RECURSIVE CALLS ===\")\n",
"reset_vm()\n",
"\n",
"# 1. We enter the Outer Function\n",
"print(\"\\n[1. Calling Outer Function]\")\n",
"do_function_call([{'name': 'outer_arg', 'size': 8}], test_returns)\n",
"\n",
"# Let's simulate the Outer Function doing some math and saving it in R0\n",
"my_language_name_vm['regs']['R0'] = \"IMPORTANT_OUTER_DATA\"\n",
"print(\"Outer function modifies R0:\", my_language_name_vm['regs']['R0'])\n",
"\n",
"# 2. Outer Function calls the Inner Function\n",
"print(\"\\n[2. Calling Inner Function (Nested)]\")\n",
"do_function_call([{'name': 'inner_arg', 'size': 8}], test_returns)\n",
"\n",
"print(\"Stack depth during nested call:\", len(my_language_name_vm['stack']))\n",
"# Notice that \"IMPORTANT_OUTER_DATA\" is now safely backed up inside the stack!\n",
"\n",
"# 3. Inner Function returns\n",
"print(\"\\n[3. Returning from Inner Function]\")\n",
"undo_function_call([{'name': 'inner_arg', 'size': 8}], test_returns)\n",
"\n",
"# 4. Check if the Outer Function's data survived\n",
"print(\"Did R0 survive the nested call?:\", my_language_name_vm['regs']['R0'])\n",
"\n",
"# 5. Outer Function returns\n",
"print(\"\\n[4. Returning from Outer Function]\")\n",
"undo_function_call([{'name': 'outer_arg', 'size': 8}], test_returns)\n",
"\n",
"print(\"\\nFinal Stack (Should be empty):\", my_language_name_vm['stack'])"
]
},
{
"cell_type": "markdown",
"id": "2439376d",
"metadata": {},
"source": [
"**1. External Interrupt**"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "48b4d8f2",
"metadata": {},
"outputs": [],
"source": [
"def trigger_external_interrupt(interrupt_handler_address):\n",
" global my_language_name_vm\n",
" print(f\"\\n--- [EXTERNAL INTERRUPT] jumping to {hex(interrupt_handler_address)} ---\")\n",
" \n",
" # 1. Guardar el registro de banderas (RF) en el stack\n",
" my_language_name_vm['stack'].append(my_language_name_vm['regs']['RF'])\n",
" \n",
" # 2. Guardar el valor actual de RV en el stack (para no perderlo)\n",
" my_language_name_vm['stack'].append(my_language_name_vm['regs']['RV'])\n",
" \n",
" # 3. El manual dice que se genera un function call al valor de RV\n",
" # Seteamos el destino en RV\n",
" my_language_name_vm['regs']['RV'] = interrupt_handler_address\n",
" \n",
" # 4. Activar el bit de \"Interrupt Request\" en el registro de banderas\n",
" # Asumiendo que es el Bit 2 (según convención estándar de este manual)\n",
" my_language_name_vm['regs']['RF'] |= (1 << 2)\n",
" \n",
" # 5. Si existe un IFH (Interrupt Finish Handle), se prepara para después\n",
" # (Por ahora simulamos que el PC/RI salta a la dirección de RV)\n",
" my_language_name_vm['regs']['RI'] = interrupt_handler_address \n",
" \n",
" print(\"Estado guardado: RF y RV están en el stack. Bit de interrupción activo.\")"
]
},
{
"cell_type": "markdown",
"id": "6ccdacec",
"metadata": {},
"source": [
"**2. Internal Interrupt**"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "6d3f0026",
"metadata": {},
"outputs": [],
"source": [
"def execute_internal_interrupt(interrupt_code):\n",
" global my_language_name_vm\n",
" \n",
" # El manual especifica el código 0x0A para llamadas al Host\n",
" if interrupt_code == 0x0A:\n",
" print(\"\\n--- [INTERNAL INTERRUPT 0x0A] Calling Host Function ---\")\n",
" \n",
" # 1. Obtener el 'handle' de la función desde RV\n",
" function_handle = my_language_name_vm['regs']['RV']\n",
" \n",
" # 2. Verificar si la función existe en la tabla del Host\n",
" # (Simulamos una tabla de funciones simple)\n",
" host_functions = {\n",
" 1: lambda: \"Hello from Host!\",\n",
" 2: lambda: 42\n",
" }\n",
" \n",
" if function_handle in host_functions:\n",
" # 3. Ejecutar y devolver resultado en registros de retorno (RA, RB, RC, RD)\n",
" result = host_functions[function_handle]()\n",
" print(f\"Executing handle {function_handle}: Result = {result}\")\n",
" \n",
" # Según la convención, el resultado va a RA\n",
" my_language_name_vm['regs']['RA'] = result\n",
" else:\n",
" # 4. Si no existe, RV debe ser seteado a cero\n",
" print(f\"Error: External function handle {function_handle} not found.\")\n",
" my_language_name_vm['regs']['RV'] = 0\n",
" else:\n",
" print(f\"Unknown internal interrupt code: {hex(interrupt_code)}\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Binary file not shown.
+19 -23
View File
@@ -1,8 +1,10 @@
#Compiler and Linker #Compiler, Archiver and Linker
CC := g++ CC := g++
AR := ar
ARFLAGS := rcs
#The Target Binary Program # The Target Static Library
TARGET := out.exe TARGET := libspider-runtime.a
#The Directories, Source, Includes, Objects, Binary and Resources #The Directories, Source, Includes, Objects, Binary and Resources
SRCDIR := src SRCDIR := src
@@ -15,49 +17,43 @@ OBJEXT := o
#Flags, Libraries and Includes #Flags, Libraries and Includes
ROOT := ./ ROOT := ./
CFLAGS := -std=c++20 -O2 \ CFLAGS := -std=c++20 -O2 \
-Wall -Werror -Wextra \ -Wall -Werror -Wextra \
-Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align \ -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align \
-Wunused -Woverloaded-virtual -Wconversion \ -Wunused -Woverloaded-virtual -Wconversion \
-Wsign-conversion -Wnull-dereference -Wdouble-promotion \ -Wsign-conversion -Wnull-dereference -Wdouble-promotion \
-Wformat=2 -Wimplicit-fallthrough -Wsuggest-override \ -Wformat=2 -Wimplicit-fallthrough -Wsuggest-override \
-Wextra-semi -Wduplicated-cond -Wduplicated-branches \ -Wextra-semi -Wduplicated-cond -Wduplicated-branches \
-Wlogical-op -Wuseless-cast -Wlogical-op -Wuseless-cast
LFLAGS := -std=c++20 -static-libstdc++ -static-libgcc \
-Wl,--fatal-warnings -Wl,--warn-common
LIB :=
INC := -I./src/ INC := -I./src/
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE #DO NOT EDIT BELOW THIS LINE
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
#Defauilt Make #Default Make
all: directories $(TARGET) all: directories $(TARGET)
#Remake #Remake
remake: cleaner all remake: clean all
#Make the Directories #Make the Directories
directories: directories:
@mkdir -p $(TARGETDIR) @mkdir -p $(TARGETDIR)
@mkdir -p $(BUILDDIR) @mkdir -p $(BUILDDIR)
#Clean only Objecst #Clean only Objects
clean: clean:
@$(RM) -rf $(BUILDDIR) @$(RM) -rf $(BUILDDIR)
#Full Clean, Objects and Binaries
cleaner: clean
@$(RM) -rf $(TARGETDIR)
#Pull in dependency info for *existing* .o files #Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) -include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
#Link #Create Static Library (Archive)
$(TARGET): $(OBJECTS) $(TARGET): $(OBJECTS)
$(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ $(LIB) $(AR) $(ARFLAGS) $(TARGETDIR)/$(TARGET) $^
#Compile #Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
@@ -70,4 +66,4 @@ $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
@rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
#Non-File Targets #Non-File Targets
.PHONY: all remake clean cleaner resources .PHONY: all remake clean
+363 -18
View File
@@ -152,26 +152,26 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Real instructions : 128\n", "Real instructions : 136\n",
"Reserved slots : 14\n", "Reserved slots : 12\n",
"Duplicate check : PASSED\n", "Duplicate check : PASSED\n",
"\n", "\n",
"Groups found:\n", "Groups found:\n",
"group\n", "group\n",
"Integer 19\n", "Integer 19\n",
"System 15\n", "Boolean 16\n",
"Bit Wise 14\n", "Bit Wise 14\n",
"Boolean 12\n", "System 14\n",
"Branch 12\n", "Branch 12\n",
"Floating Point 10\n", "Floating Point 10\n",
"Casts 10\n", "Casts 10\n",
"Memory 9\n", "Memory 8\n",
"Trigonometric 7\n", "Trigonometric 7\n",
"Easter Eggs 7\n",
"Exponential 6\n", "Exponential 6\n",
"Matrix 6\n", "Matrix 6\n",
"SIMD 5\n", "SIMD 5\n",
"Quaternion 2\n", "Quaternion 2\n",
"Easter Eggs 1\n",
"\n", "\n",
"First 5 instructions:\n", "First 5 instructions:\n",
" byte_code mnemonic group params addr_mask_1 type_mask\n", " byte_code mnemonic group params addr_mask_1 type_mask\n",
@@ -284,6 +284,351 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 5,
"id": "ac8bb791",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>skip_0</th>\n",
" <th>skip_1</th>\n",
" <th>byte_code</th>\n",
" <th>mnemonic</th>\n",
" <th>name</th>\n",
" <th>group</th>\n",
" <th>params</th>\n",
" <th>imp</th>\n",
" <th>imm</th>\n",
" <th>abs</th>\n",
" <th>...</th>\n",
" <th>B</th>\n",
" <th>S</th>\n",
" <th>I</th>\n",
" <th>L</th>\n",
" <th>F</th>\n",
" <th>D</th>\n",
" <th>type_mask</th>\n",
" <th>expensive</th>\n",
" <th>operation</th>\n",
" <th>skip_2</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>140</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>08C</td>\n",
" <td>XAMA</td>\n",
" <td>SIMD Alternate Multiply-Add</td>\n",
" <td>SIMD</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>141</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>08D</td>\n",
" <td>XMUL</td>\n",
" <td>SIMD Multiply</td>\n",
" <td>SIMD</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>142</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>08E</td>\n",
" <td>XDIV</td>\n",
" <td>SIMD Divide</td>\n",
" <td>SIMD</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>240</th>\n",
" <td>NaN</td>\n",
" <td>Easter Eggs</td>\n",
" <td>0F0</td>\n",
" <td>UPY</td>\n",
" <td>Will place \"YUPI\" in memory</td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>241</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0F1</td>\n",
" <td>INT_1_SLOT</td>\n",
" <td></td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>242</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0F2</td>\n",
" <td>INT_2_SLOT</td>\n",
" <td></td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>243</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0F3</td>\n",
" <td>INT_3_SLOT</td>\n",
" <td></td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>244</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0F4</td>\n",
" <td>INT_4_SLOT</td>\n",
" <td></td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>245</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0F5</td>\n",
" <td>BRAD</td>\n",
" <td></td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>246</th>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0F6</td>\n",
" <td>DGANT</td>\n",
" <td></td>\n",
" <td>Easter Eggs</td>\n",
" <td>0</td>\n",
" <td>1.0</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>...</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>X</td>\n",
" <td>00</td>\n",
" <td>NaN</td>\n",
" <td></td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>10 rows × 29 columns</p>\n",
"</div>"
],
"text/plain": [
" skip_0 skip_1 byte_code mnemonic name \\\n",
"140 NaN NaN 08C XAMA SIMD Alternate Multiply-Add \n",
"141 NaN NaN 08D XMUL SIMD Multiply \n",
"142 NaN NaN 08E XDIV SIMD Divide \n",
"240 NaN Easter Eggs 0F0 UPY Will place \"YUPI\" in memory \n",
"241 NaN NaN 0F1 INT_1_SLOT \n",
"242 NaN NaN 0F2 INT_2_SLOT \n",
"243 NaN NaN 0F3 INT_3_SLOT \n",
"244 NaN NaN 0F4 INT_4_SLOT \n",
"245 NaN NaN 0F5 BRAD \n",
"246 NaN NaN 0F6 DGANT \n",
"\n",
" group params imp imm abs ... B S I L F D type_mask \\\n",
"140 SIMD 0 1.0 X X ... X X X X X X 00 \n",
"141 SIMD 0 1.0 X X ... X X X X X X 00 \n",
"142 SIMD 0 1.0 X X ... X X X X X X 00 \n",
"240 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"241 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"242 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"243 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"244 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"245 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"246 Easter Eggs 0 1.0 X X ... X X X X X X 00 \n",
"\n",
" expensive operation skip_2 \n",
"140 NaN NaN \n",
"141 NaN NaN \n",
"142 NaN NaN \n",
"240 NaN NaN \n",
"241 NaN NaN \n",
"242 NaN NaN \n",
"243 NaN NaN \n",
"244 NaN NaN \n",
"245 NaN NaN \n",
"246 NaN NaN \n",
"\n",
"[10 rows x 29 columns]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"instrs_df.tail(10)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "452bc76c", "id": "452bc76c",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -292,7 +637,7 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Masks written to: .//autogen/InstructionMasks.hpp\n", "Masks written to: .//autogen/InstructionMasks.hpp\n",
"Lines generated : 272\n" "Lines generated : 288\n"
] ]
} }
], ],
@@ -357,7 +702,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 7,
"id": "5aaebef0", "id": "5aaebef0",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -365,7 +710,7 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Instructions formatted: 128\n", "Instructions formatted: 136\n",
"\n", "\n",
"--- Preview (first 2 instructions) ---\n", "--- Preview (first 2 instructions) ---\n",
" // [System] 0x000 — NOP: No Operation\n", " // [System] 0x000 — NOP: No Operation\n",
@@ -380,7 +725,7 @@
"\n", "\n",
"\n", "\n",
"CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n", "CPU.hpp updated successfully at: .//src//spider/runtime/cpu/CPU.hpp\n",
"Total lines in updated file: 883\n" "Total lines in updated file: 942\n"
] ]
} }
], ],
@@ -451,7 +796,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 8,
"id": "instrmap_gen", "id": "instrmap_gen",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -460,9 +805,9 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"InstrMap.cpp written to: .//src//spider/runtime/instr/InstrMap.cpp\n", "InstrMap.cpp written to: .//src//spider/runtime/instr/InstrMap.cpp\n",
" Size : 34,157 bytes\n", " Size : 33,582 bytes\n",
" Array entries : 512 (128 populated, 384 nullptr)\n", " Array entries : 512 (136 populated, 376 nullptr)\n",
" Switch cases : 128\n", " Switch cases : 136\n",
" Line endings : LF-only verified\n" " Line endings : LF-only verified\n"
] ]
} }
@@ -545,11 +890,11 @@
" mnem = opcode_to_mnem.get(opc)\n", " mnem = opcode_to_mnem.get(opc)\n",
" if mnem:\n", " if mnem:\n",
" name = opcode_to_name[opc]\n", " name = opcode_to_name[opc]\n",
" L.append(f' &CPU::{mnem + \",\":<28s}// 0x{opc:03X} — {name}')\n", " L.append(f' &CPU::{mnem + \",\":<22s}// 0x{opc:03X} — {name}')\n",
" else:\n", " else:\n",
" tag = ''\n", " tag = ''\n",
" if opc in reserved_opcodes:\n", " if opc in reserved_opcodes:\n",
" tag = ' (reserved)'\n", " tag = ' (reserved)'\n",
" L.append(f' {\"nullptr,\":<28s}// 0x{opc:03X}{tag}')\n", " L.append(f' {\"nullptr,\":<28s}// 0x{opc:03X}{tag}')\n",
"\n", "\n",
"L.append('};')\n", "L.append('};')\n",
@@ -618,7 +963,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 9,
"id": "9f190f4c", "id": "9f190f4c",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -681,7 +1026,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.14.3" "version": "3.13.7"
} }
}, },
"nbformat": 4, "nbformat": 4,
+2 -10
View File
@@ -1,18 +1,10 @@
#include "SpiderRuntime.hpp" #include "SpiderRuntime.hpp"
#include <spider/runtime/debug/LiveDebug.hpp>
#include <iostream> #include <iostream>
namespace spider { namespace spider {
const u32 RUNTIME_VERSION_NO = 0x00000000; // v0.1 const u32 RUNTIME_VERSION_NO = 0x00000001; // v0.1
const std::string RUNTIME_VERSION = "alpha v0.1"; const std::string RUNTIME_VERSION = "alpha v0.1";
} }
int main() {
spider::liveDebugMain();
return 0;
}
+36 -6
View File
@@ -1,5 +1,7 @@
#include "Runtime.hpp" #include "Runtime.hpp"
#include <chrono>
namespace spider { namespace spider {
// Constructors & Destructors // // Constructors & Destructors //
@@ -17,14 +19,17 @@ namespace spider {
// Stepping/Running the Machine // // Stepping/Running the Machine //
void Runtime::step() { void Runtime::step() {
// fetchInstr() decodes the opcode, addressing mode and type siz // fetchInstr() decodes the opcode,
// addressing mode and type size
cpu.fetchInstr(); cpu.fetchInstr();
// execute() completes the fetch-decode-execute cycle by calling the correct instruction method based on the opcode. // execute() completes the fetch-decode-execute
// cycle by calling the correct instruction
// method based on the opcode.
cpu.execute(); cpu.execute();
} }
void Runtime::step(u64 n) { void Runtime::step(u64 n) {
while(n >= 4) { while (n >= 4) {
step(); step();
step(); step();
step(); step();
@@ -34,9 +39,34 @@ namespace spider {
while (n--) step(); while (n--) step();
} }
void Runtime::run() {} u64 Runtime::run() {
// TODO: Must use the flag register
// for the enabled bit.
return 0;
}
//void Runtime::run(u64 n) {} u64 Runtime::run(u64 n) {
using namespace std::chrono;
u64 total_steps = 0;
auto start_time = high_resolution_clock::now();
// TODO: Must use the flag register
// for the enabled bit.
while (true) {
step();
step();
step();
step();
total_steps += 4;
// measure time!
auto current_time = high_resolution_clock::now();
auto elapsed = duration_cast<milliseconds>(current_time - start_time).count();
if (static_cast<u64>(elapsed) >= n) break;
}
return total_steps;
}
// Misc // // Misc //
@@ -50,7 +80,7 @@ namespace spider {
void Runtime::hookReel(InstrReel* newReel, bool own) { void Runtime::hookReel(InstrReel* newReel, bool own) {
delete this->reel; delete this->reel;
cpu.hookInstrReel(newReel); cpu.hookInstrReel(newReel);
if(own) this->reel = newReel; if (own) this->reel = newReel;
} }
} }
+6 -2
View File
@@ -55,14 +55,18 @@ namespace spider {
* Sets the machine to run continously. * Sets the machine to run continously.
* If interrupts occur, they will be handled * If interrupts occur, they will be handled
* automatically. * automatically.
*
* Returns the amount of cycles ran.
*/ */
void run(); u64 run();
/** /**
* Runs this machine for a set amount of * Runs this machine for a set amount of
* milliseconds. * milliseconds.
*
* Returns the amount of cycles ran.
*/ */
void run(u64 ms); u64 run(u64 ms);
public: public:
+22 -12
View File
@@ -67,7 +67,9 @@ namespace spider {
void CPU::fetchInstr() { void CPU::fetchInstr() {
u16 i = _reel->readU16(RI); u16 i = _reel->readU16(RI);
RX._u16 = i;
const u16 oc = (i >> 7); const u16 oc = (i >> 7);
RY._u16 = oc;
_opcode = oc & 0x1FF; // GCC WHY! _opcode = oc & 0x1FF; // GCC WHY!
_addrm = static_cast<u8>((i >> 2) & 0x1F); _addrm = static_cast<u8>((i >> 2) & 0x1F);
_size = static_cast<u8>(i & 0x3); _size = static_cast<u8>(i & 0x3);
@@ -76,8 +78,8 @@ namespace spider {
void CPU::fetchOperDst() { void CPU::fetchOperDst() {
// Move the operand ptrs // Move the operand ptrs
_alu = &ALU0;
_opers[1] = _opers[0]; _opers[1] = _opers[0];
_opers[0] = &ALU0;
// call specific addressing mode // call specific addressing mode
(this->*(CPU::addrModes[_addrm & 0b111]))(); // mask added here too (this->*(CPU::addrModes[_addrm & 0b111]))(); // mask added here too
@@ -85,7 +87,7 @@ namespace spider {
void CPU::fetchOperSrc() { void CPU::fetchOperSrc() {
// set ALU // set ALU
_alu = &ALU1; _opers[0] = &ALU1;
// call specific addressing mode // call specific addressing mode
(this->*(CPU::addrModes[_addrm & 0b111]))(); // mask keeps index within 0-7 (this->*(CPU::addrModes[_addrm & 0b111]))(); // mask keeps index within 0-7
@@ -95,13 +97,23 @@ namespace spider {
_addrm++; _addrm++;
} }
void CPU::fetchOperReg() {
_dst = &GPR[_reel->readU8(RI++) & 0xF];
}
void CPU::fetchOperRegReg() {
// read the full byte
u8 reg = _reel->readU8(RI++);
_src = &GPR[(reg >> 4) & 0xF];
_dst = &GPR[ reg & 0xF];
}
void CPU::execute() { void CPU::execute() {
(this->*(CPU::instrMap[_opcode]))(); // no null check needed (this->*(CPU::instrMap[_opcode]))(); // no null check needed
// vvv MUST PROFILE: Is this faster than executing an empty function?
if(_post) (this->*_post)(); if(_post) (this->*_post)();
} }
// Addressing Modes // // Addressing Modes //
/** /**
@@ -115,8 +127,7 @@ namespace spider {
* Immediate Addressing Mode * Immediate Addressing Mode
*/ */
void CPU::imm() { void CPU::imm() {
_reel->loadRegister(RI, _size, _alu); _reel->loadRegister(RI, _size, _opers[0]);
_opers[0] = _alu;
_post = &CPU::imp; _post = &CPU::imp;
RI += 1 << _size; RI += 1 << _size;
} }
@@ -127,19 +138,19 @@ namespace spider {
void CPU::abs() { void CPU::abs() {
// Load the actual ptr into the ALU // Load the actual ptr into the ALU
u8 mm = u8(getFlag(CPU::FLAG_MEMORY_MODE)); u8 mm = u8(getFlag(CPU::FLAG_MEMORY_MODE));
_reel->loadRegister(RI, mm, _alu); _reel->loadRegister(RI, mm, _opers[0]);
RI += 1 << mm; RI += 1 << mm;
// read the memory from RAM // read the memory from RAM
_store = _alu->_u64; _store = _opers[0]->_u64;
_ram->loadRegister(_store, _size, _alu); _ram->loadRegister(_store, _size, _opers[0]);
_post = &CPU::psw; _post = &CPU::psw;
} }
/** /**
* Register Addressing Mode * Register Addressing Mode
*/ */
void CPU::reg() { // NOT FINISHED void CPU::reg() {
// Two consecutive registers can be declared // Two consecutive registers can be declared
// Shift if the top part will become .reg too // Shift if the top part will become .reg too
u8 sh = ((_addrm & 0b11000) == 0b11000) * 4; u8 sh = ((_addrm & 0b11000) == 0b11000) * 4;
@@ -147,12 +158,11 @@ namespace spider {
// get byte // get byte
u8 reg = (_reel->readU8(RI) >> sh) & 0xF; u8 reg = (_reel->readU8(RI) >> sh) & 0xF;
_alu = &GPR[reg]; _opers[0] = &GPR[reg]; // explicitly sets _opers[0] = _dst
_opers[0] = _alu; // explicitly sets _opers[0] = _dst
RI += use; RI += use;
// store no-op // store no-op
_post = &CPU::imp; _post = nullptr;
} }
/** /**
+83 -48
View File
@@ -64,7 +64,6 @@ namespace spider {
struct { struct {
register_t* _dst; register_t* _dst;
register_t* _src; register_t* _src;
register_t* _alu;
}; };
register_t* _opers[2]; register_t* _opers[2];
}; };
@@ -172,6 +171,18 @@ namespace spider {
*/ */
void fetchOperSrc(); void fetchOperSrc();
/**
* Fetches special addressing where
* one register is addressed.
*/
void fetchOperReg();
/**
* Fetches special addressing where
* two registers are addressed.
*/
void fetchOperRegReg();
/** /**
* Executes an opcode, by means of directly * Executes an opcode, by means of directly
* accessing the instruction map and * accessing the instruction map and
@@ -314,11 +325,6 @@ namespace spider {
// Operation: Src <-> Dst // Operation: Src <-> Dst
void SWP(); void SWP();
// [Memory] 0x00E — AHM: Ask Host for Memory
// 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 // [Integer] 0x010 — COM: One's complement
// Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F
// Operation: ~ Dst -> Dst // Operation: ~ Dst -> Dst
@@ -394,11 +400,6 @@ namespace spider {
// Operation: Unsigned Dst / Src -> X, Dst % Src -> Y // Operation: Unsigned Dst / Src -> X, Dst % Src -> Y
void UDMD(); void UDMD();
// [System] 0x01F — FBT: Test and update Flag Register (Integer) Bits
// Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F
// Operation: Flags of Dst -
void FBT();
// [Bit Wise] 0x020 — STB: Set Bit // [Bit Wise] 0x020 — STB: Set Bit
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Src# bit is set on Dst // Operation: Src# bit is set on Dst
@@ -469,36 +470,56 @@ namespace spider {
// Operation: # of 1's into Dst // Operation: # of 1's into Dst
void CNT(); void CNT();
// [Boolean] 0x030 — EQ: Equal // [Boolean] 0x02E — EQ: Equal
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst == Src into Dst // Operation: Dst == Src into Dst
void EQ(); void EQ();
// [Boolean] 0x031 — NE: Not Equal // [Boolean] 0x02F — NE: Not Equal
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst != Src into Dst // Operation: Dst != Src into Dst
void NE(); void NE();
// [Boolean] 0x032 — GT: Greater Than // [Boolean] 0x030 — GT: Greater Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst > Src into Dst // Operation: Dst > Src into Dst
void GT(); void GT();
// [Boolean] 0x033 — GE: Greater or Equal Than // [Boolean] 0x031 — GE: Greater or Equal Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst >= Src into Dst // Operation: Dst >= Src into Dst
void GE(); void GE();
// [Boolean] 0x034 — LT: Lower Than // [Boolean] 0x032 — LT: Lower Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst < Src into Dst // Operation: Dst < Src into Dst
void LT(); void LT();
// [Boolean] 0x035 — LE: Lower or Equal Than // [Boolean] 0x033 — LE: Lower or Equal Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst <= Src into Dst // Operation: Dst <= Src into Dst
void LE(); void LE();
// [Boolean] 0x034 — GTU: Greater Than, Unsigned
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst > Src into Dst
void GTU();
// [Boolean] 0x035 — GEU: Greater or Equal Than, Unsigned
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst >= Src into Dst
void GEU();
// [Boolean] 0x036 — LTU: Lower Than, Unsigned
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst < Src into Dst
void LTU();
// [Boolean] 0x037 — LEU: Lower or Equal Than, Unsigned
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst <= Src into Dst
void LEU();
// [Branch] 0x038 — JMP: Jump to absolute position // [Branch] 0x038 — JMP: Jump to absolute position
// Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F
// Operation: Dst -> Instruction Register // Operation: Dst -> Instruction Register
@@ -541,22 +562,22 @@ namespace spider {
// [System] 0x040 — SFB: Store (User) Flag Bit // [System] 0x040 — SFB: Store (User) Flag Bit
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: // Operation:
void SFB(); void SFB();
// [System] 0x041 — LFB: Load (User) Flag Bit // [System] 0x041 — LFB: Load (User) Flag Bit
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: // Operation:
void LFB(); void LFB();
// [Branch] 0x042 — JUF: Jump to absolute position, if user flag is true // [Branch] 0x042 — JUF: Jump to absolute position, if user flag is true
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: // Operation:
void JUF(); void JUF();
// [Branch] 0x043 — JUR: Jump to relative position, if user flag is true // [Branch] 0x043 — JUR: Jump to relative position, if user flag is true
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F // Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: // Operation:
void JUR(); void JUR();
// [Memory] 0x044 — PUSH: Push to stack // [Memory] 0x044 — PUSH: Push to stack
@@ -601,7 +622,7 @@ namespace spider {
// [Floating Point] 0x050 — FLI: Float Load Immediate // [Floating Point] 0x050 — FLI: Float Load Immediate
// Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C // Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0C
// Operation: // Operation:
void FLI(); void FLI();
// [Floating Point] 0x051 — FNEG: Float negate // [Floating Point] 0x051 — FNEG: Float negate
@@ -816,90 +837,104 @@ namespace spider {
// [Matrix] 0x080 — MADD: Matrix Addition // [Matrix] 0x080 — MADD: Matrix Addition
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void MADD(); void MADD();
// [Matrix] 0x081 — MSUB: Matrix Subtraction // [Matrix] 0x081 — MSUB: Matrix Subtraction
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void MSUB(); void MSUB();
// [Matrix] 0x082 — MMUL: Matrix Multiply // [Matrix] 0x082 — MMUL: Matrix Multiply
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void MMUL(); void MMUL();
// [Matrix] 0x083 — MINV: Matrix Inverse // [Matrix] 0x083 — MINV: Matrix Inverse
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void MINV(); void MINV();
// [Matrix] 0x084 — MTRA: Matrix Transpose // [Matrix] 0x084 — MTRA: Matrix Transpose
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void MTRA(); void MTRA();
// [Matrix] 0x085 — MDET: Matrix Determinant // [Matrix] 0x085 — MDET: Matrix Determinant
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void MDET(); void MDET();
// [Quaternion] 0x086 — QMKA: Quaternion Make from Angles // [Quaternion] 0x086 — QMKA: Quaternion Make from Angles
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void QMKA(); void QMKA();
// [Quaternion] 0x087 — QMUL: Quaternion Multiply // [Quaternion] 0x087 — QMUL: Quaternion Multiply
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void QMUL(); void QMUL();
// [SIMD] 0x08A — XADD: SIMD Addition // [SIMD] 0x08A — XADD: SIMD Addition
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void XADD(); void XADD();
// [SIMD] 0x08B — XSUB: SIMD Subtract // [SIMD] 0x08B — XSUB: SIMD Subtract
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void XSUB(); void XSUB();
// [SIMD] 0x08C — XAMA: SIMD Alternate Multiply-Add // [SIMD] 0x08C — XAMA: SIMD Alternate Multiply-Add
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void XAMA(); void XAMA();
// [SIMD] 0x08D — XMUL: SIMD Multiply // [SIMD] 0x08D — XMUL: SIMD Multiply
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void XMUL(); void XMUL();
// [SIMD] 0x08E — XDIV: SIMD Divide // [SIMD] 0x08E — XDIV: SIMD Divide
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void XDIV(); void XDIV();
// [Easter Eggs] 0x0F0 — UPY: Will place "YUPI" in memory // [Easter Eggs] 0x0F0 — UPY: Will place "YUPI" in memory
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: // Operation:
void UPY(); void UPY();
//[Easter Egg] 0x0F1 - LLGS: Injects the custom 8x4 ASCII spider logo
// into RAM [0x80-0x9F] and signs Register RA with the "LLGS" hex literal.
void LLGS();
// [Easter Eggs] 0x0F6DGANT: "In kaaba Spider" (Yucatec Maya: My name is Spider) // [Easter Eggs] 0x0F1INT_1_SLOT:
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00 // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: Writes "IN KAABA SPIDER" one char per GP register // Operation:
void DGANT(); void INT_1_SLOT();
/** // [Easter Eggs] 0x0F2 — INT_2_SLOT:
* @brief BRAD (0xF7) - Memory Integrity Checksum // Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
* Escanea los primeros 256 bytes de memoria y valida contra una firma de seguridad. // Operation:
* Implementado por Bradley Vergara Lara - Estancia 2026. void INT_2_SLOT();
*/
// [Easter Eggs] 0x0F3 — INT_3_SLOT:
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation:
void INT_3_SLOT();
// [Easter Eggs] 0x0F4 — INT_4_SLOT:
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation:
void INT_4_SLOT();
// [Easter Eggs] 0x0F5 — BRAD:
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation:
void BRAD(); void BRAD();
// [Easter Eggs] 0x0F6 — DGANT:
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation:
void DGANT();
// </pygen-target> // // </pygen-target> //
}; };
-402
View File
@@ -1,402 +0,0 @@
#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) {
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();
}
u32 addressWidth(isize ramSize) {
if (ramSize == 0) return 1;
isize maxAddr = ramSize - 1;
u32 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, u32 x, u32 y, u32 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 (u32 i = 0; i < trackHeight; ++i) {
term.move(i32(y + i), i32(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
u32 thumbOffset = u32(ratio * (trackHeight - 1));
// 3. Draw the Thumb (Full Block: █)
term.move(i32(y + thumbOffset), i32(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
u32 y = 3;
u32 height = 36;
// 2. Configuration for the hex layout
u32 addrWidth = addressWidth(ram.size());
u32 bytesPerRow = 8;
u32 displayRows = height - 2; // Subtract top/bottom borders
u32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth;
u32 x = 37;
// create box
term.drawBox(i32(y), i32(x), i32(width), i32(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 (u32 i = 0; i < displayRows; ++i) {
isize currentRowAddr = scrollPos + (i * bytesPerRow);
// address lock
if (currentRowAddr >= ram.size()) {
term.move(i32(y + 1 + i), i32(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(i32(addrWidth)) << currentRowAddr << " ";
// Hex Bytes
std::string asciiPart = "";
for (u32 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(i32(y + 1 + i), i32(x + 2)); // Move inside the box
term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan
term.style(Terminal::FG_WHITE).print(ss.str());
term.style(Terminal::FG_B_YELLOW).print(" | ");
term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White
}
term.style(Terminal::RESET);
term.flush();
}
std::string getTimestamp() {
std::time_t t = std::time(nullptr);
std::tm lt;
#if defined(SPIDER_OS_WINDOWS)
localtime_s(&lt, &t);
#endif
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
localtime_r(&t, &lt);
#endif
return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}",
lt.tm_hour, lt.tm_min, lt.tm_sec,
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
}
void drawTime(Terminal& t) {
//auto now = std::chrono::system_clock::now();
//auto now_l = std::chrono::current_zone()->to_local(now);
//auto now_s = std::chrono::floor<std::chrono::seconds>(now_l);
//std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss
//std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY
t.move(1, 76);
t.style(Terminal::RESET);
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
}
void redraw(Terminal& t, Runtime& r, u64 scroll) {
// draw CPU, RAM
drawCPU(t, r.cpu);
drawRAM(t, r.ram, scroll);
}
int liveDebugMain() {
Terminal t;
Runtime runtime(1024);
InstrReelFixed fix(100);
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);
// 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.execute(); // looks up instrMap[_opcode] & calls the correct instruction method (e.g. FMUL)
break;
default:
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
t.altbuff(false).println("Stopped Spider live debug.").flush();
return 0;
}
}
-7
View File
@@ -1,7 +0,0 @@
#pragma once
namespace spider {
int liveDebugMain();
}
+164 -160
View File
@@ -35,149 +35,149 @@ namespace spider {
* if (fn) (cpu.*fn)(); * if (fn) (cpu.*fn)();
*/ */
CPU::Fn CPU::instrMap[] = { CPU::Fn CPU::instrMap[] = {
&CPU::NOP, // 0x000 — No Operation &CPU::NOP, // 0x000 — No Operation
&CPU::SPDR, // 0x001 — Will place the Spider version of the interpreter in RA &CPU::SPDR, // 0x001 — Will place the Spider version of the interpreter in RA
&CPU::MMODE, // 0x002 — Set Memory Mode &CPU::MMODE, // 0x002 — Set Memory Mode
&CPU::INT, // 0x003 — Interrupt &CPU::INT, // 0x003 — Interrupt
&CPU::LRV, // 0x004 — Load Interrupt Vector Register &CPU::LRV, // 0x004 — Load Interrupt Vector Register
&CPU::FSR, // 0x005 — Fetch System Register &CPU::FSR, // 0x005 — Fetch System Register
&CPU::FIR, // 0x006 — Fetch Instruction Register &CPU::FIR, // 0x006 — Fetch Instruction Register
&CPU::FZR, // 0x007 — Fetch Stack Base Register &CPU::FZR, // 0x007 — Fetch Stack Base Register
&CPU::LSR, // 0x008 — Load System Register &CPU::LSR, // 0x008 — Load System Register
&CPU::FVR, // 0x009 — Fetch Interrupt Vector Register &CPU::FVR, // 0x009 — Fetch Interrupt Vector Register
&CPU::MOV, // 0x00A — Moves values &CPU::MOV, // 0x00A — Moves values
&CPU::MOR, // 0x00B — Moves registers &CPU::MOR, // 0x00B — Moves registers
&CPU::AMOV, // 0x00C — Array Move, uses X and Y as ptrs, A as amount &CPU::AMOV, // 0x00C — Array Move, uses X and Y as ptrs, A as amount
&CPU::SWP, // 0x00D — Swap registers &CPU::SWP, // 0x00D — Swap registers
&CPU::AHM, // 0x00E — Ask Host for Memory nullptr, // 0x00E (reserved)
nullptr, // 0x00F (reserved) nullptr, // 0x00F (reserved)
&CPU::COM, // 0x010 — One's complement &CPU::COM, // 0x010 — One's complement
&CPU::NEG, // 0x011 — Two's complement &CPU::NEG, // 0x011 — Two's complement
&CPU::EXS, // 0x012 — Extend Sign &CPU::EXS, // 0x012 — Extend Sign
&CPU::INC, // 0x013 — Increment &CPU::INC, // 0x013 — Increment
&CPU::DEC, // 0x014 — Decrement &CPU::DEC, // 0x014 — Decrement
&CPU::ADD, // 0x015 — Addition &CPU::ADD, // 0x015 — Addition
&CPU::SUB, // 0x016 — Subtraction &CPU::SUB, // 0x016 — Subtraction
&CPU::MUL, // 0x017 — Multiplication &CPU::MUL, // 0x017 — Multiplication
&CPU::UMUL, // 0x018 — Unsigned Multiplication &CPU::UMUL, // 0x018 — Unsigned Multiplication
&CPU::DIV, // 0x019 — Division &CPU::DIV, // 0x019 — Division
&CPU::UDIV, // 0x01A — Unsigned Division &CPU::UDIV, // 0x01A — Unsigned Division
&CPU::MOD, // 0x01B — Modulus &CPU::MOD, // 0x01B — Modulus
&CPU::UMOD, // 0x01C — Unsigned Modulus &CPU::UMOD, // 0x01C — Unsigned Modulus
&CPU::DMOD, // 0x01D — Division and Modulus &CPU::DMOD, // 0x01D — Division and Modulus
&CPU::UDMD, // 0x01E — Unsigned Division and Modulus &CPU::UDMD, // 0x01E — Unsigned Division and Modulus
&CPU::FBT, // 0x01F — Test and update Flag Register (Integer) Bits nullptr, // 0x01F (reserved)
&CPU::STB, // 0x020 — Set Bit &CPU::STB, // 0x020 — Set Bit
&CPU::CRB, // 0x021 — Clear Bit &CPU::CRB, // 0x021 — Clear Bit
&CPU::TSB, // 0x022 — Test Bit &CPU::TSB, // 0x022 — Test Bit
&CPU::BOOL, // 0x023 — Sets the booleaness of a value &CPU::BOOL, // 0x023 — Sets the booleaness of a value
&CPU::NOT, // 0x024 — Sets the inverse booleaness of a value (! BOOL) &CPU::NOT, // 0x024 — Sets the inverse booleaness of a value (! BOOL)
&CPU::AND, // 0x025 — Boolean AND operation &CPU::AND, // 0x025 — Boolean AND operation
&CPU::OR, // 0x026 — Boolean OR operation &CPU::OR, // 0x026 — Boolean OR operation
&CPU::XOR, // 0x027 — Boolean XOR operation &CPU::XOR, // 0x027 — Boolean XOR operation
&CPU::SHL, // 0x028 — Arithmetic Shift Left &CPU::SHL, // 0x028 — Arithmetic Shift Left
&CPU::SHR, // 0x029 — Arithmetic Shift Right &CPU::SHR, // 0x029 — Arithmetic Shift Right
&CPU::SSR, // 0x02A — Signed Shift Right &CPU::SSR, // 0x02A — Signed Shift Right
&CPU::ROL, // 0x02B — Rotate Left &CPU::ROL, // 0x02B — Rotate Left
&CPU::ROR, // 0x02C — Rotate Right &CPU::ROR, // 0x02C — Rotate Right
&CPU::CNT, // 0x02D — Counts bits &CPU::CNT, // 0x02D — Counts bits
nullptr, // 0x02E (reserved) &CPU::EQ, // 0x02E — Equal
nullptr, // 0x02F (reserved) &CPU::NE, // 0x02F — Not Equal
&CPU::EQ, // 0x030 — Equal &CPU::GT, // 0x030 — Greater Than
&CPU::NE, // 0x031 — Not Equal &CPU::GE, // 0x031 — Greater or Equal Than
&CPU::GT, // 0x032 — Greater Than &CPU::LT, // 0x032 — Lower Than
&CPU::GE, // 0x033 — Greater or Equal Than &CPU::LE, // 0x033 — Lower or Equal Than
&CPU::LT, // 0x034 — Lower Than &CPU::GTU, // 0x034 — Greater Than, Unsigned
&CPU::LE, // 0x035 — Lower or Equal Than &CPU::GEU, // 0x035 — Greater or Equal Than, Unsigned
nullptr, // 0x036 (reserved) &CPU::LTU, // 0x036 — Lower Than, Unsigned
nullptr, // 0x037 (reserved) &CPU::LEU, // 0x037 — Lower or Equal Than, Unsigned
&CPU::JMP, // 0x038 — Jump to absolute position &CPU::JMP, // 0x038 — Jump to absolute position
&CPU::JEQ, // 0x039 — Jumps to position if EQ flag is set &CPU::JEQ, // 0x039 — Jumps to position if EQ flag is set
&CPU::JNE, // 0x03A — Jumps to position if EQ flag is cleared &CPU::JNE, // 0x03A — Jumps to position if EQ flag is cleared
&CPU::JIF, // 0x03B — Jumps if value provided is booleanly true &CPU::JIF, // 0x03B — Jumps if value provided is booleanly true
&CPU::JMR, // 0x03C — Jump Relative &CPU::JMR, // 0x03C — Jump Relative
&CPU::JER, // 0x03D — Jumps to relative position if EQ flag is set &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::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::JIR, // 0x03F — Jumps to relative position if value provided is booleanly true
&CPU::SFB, // 0x040 — Store (User) Flag Bit &CPU::SFB, // 0x040 — Store (User) Flag Bit
&CPU::LFB, // 0x041 — Load (User) Flag Bit &CPU::LFB, // 0x041 — Load (User) Flag Bit
&CPU::JUF, // 0x042 — Jump to absolute position, if user flag is true &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::JUR, // 0x043 — Jump to relative position, if user flag is true
&CPU::PUSH, // 0x044 — Push to stack &CPU::PUSH, // 0x044 — Push to stack
&CPU::POP, // 0x045 — Pop from stack &CPU::POP, // 0x045 — Pop from stack
&CPU::ALLOC, // 0x046 — Allocate to heap &CPU::ALLOC, // 0x046 — Allocate to heap
&CPU::HFREE, // 0x047 — Delete from heap &CPU::HFREE, // 0x047 — Delete from heap
nullptr, // 0x048 (reserved) nullptr, // 0x048 (reserved)
nullptr, // 0x049 (reserved) nullptr, // 0x049 (reserved)
&CPU::CALL, // 0x04A — Call function at instruction index &CPU::CALL, // 0x04A — Call function at instruction index
&CPU::RET, // 0x04B — Return from a function &CPU::RET, // 0x04B — Return from a function
&CPU::EDI, // 0x04C — Enable/Disable External Interrupts &CPU::EDI, // 0x04C — Enable/Disable External Interrupts
&CPU::SHSS, // 0x04D — Set Hotswap Signal Bit &CPU::SHSS, // 0x04D — Set Hotswap Signal Bit
nullptr, // 0x04E (reserved) nullptr, // 0x04E (reserved)
nullptr, // 0x04F (reserved) nullptr, // 0x04F (reserved)
&CPU::FLI, // 0x050 — Float Load Immediate &CPU::FLI, // 0x050 — Float Load Immediate
&CPU::FNEG, // 0x051 — Float negate &CPU::FNEG, // 0x051 — Float negate
&CPU::FADD, // 0x052 — Float add &CPU::FADD, // 0x052 — Float add
&CPU::FSUB, // 0x053 — Float subtract &CPU::FSUB, // 0x053 — Float subtract
&CPU::FMUL, // 0x054 — Float multiplication &CPU::FMUL, // 0x054 — Float multiplication
&CPU::FDIV, // 0x055 — Float division &CPU::FDIV, // 0x055 — Float division
&CPU::FMOD, // 0x056 — Float modulus &CPU::FMOD, // 0x056 — Float modulus
&CPU::FDMOD, // 0x057 — Float division and modulus &CPU::FDMOD, // 0x057 — Float division and modulus
&CPU::FEPS, // 0x058 — Sets the float epsilon value, for comparison &CPU::FEPS, // 0x058 — Sets the float epsilon value, for comparison
&CPU::FEEP, // 0x059 — Float Enable/Disable Epsilon &CPU::FEEP, // 0x059 — Float Enable/Disable Epsilon
&CPU::FEQ, // 0x05A — Float Equal &CPU::FEQ, // 0x05A — Float Equal
&CPU::FNE, // 0x05B — Float Not Equal &CPU::FNE, // 0x05B — Float Not Equal
&CPU::FGT, // 0x05C — Float Greater Than &CPU::FGT, // 0x05C — Float Greater Than
&CPU::FGE, // 0x05D — Float Greater or Equal Than &CPU::FGE, // 0x05D — Float Greater or Equal Than
&CPU::FLT, // 0x05E — Float Lower Than &CPU::FLT, // 0x05E — Float Lower Than
&CPU::FLE, // 0x05F — Float Lower or Equal Than &CPU::FLE, // 0x05F — Float Lower or Equal Than
&CPU::F2D, // 0x060 — F32 (Float) to F64 (Double) &CPU::F2D, // 0x060 — F32 (Float) to F64 (Double)
&CPU::D2F, // 0x061 — F64 (Double) to F32 (Float) &CPU::D2F, // 0x061 — F64 (Double) to F32 (Float)
&CPU::I2F, // 0x062 — I32 (Integer) to F32 (Float) &CPU::I2F, // 0x062 — I32 (Integer) to F32 (Float)
&CPU::I2D, // 0x063 — I32 (Integer) to F64 (Double) &CPU::I2D, // 0x063 — I32 (Integer) to F64 (Double)
&CPU::L2F, // 0x064 — I64 (Long) to F32 (Float) &CPU::L2F, // 0x064 — I64 (Long) to F32 (Float)
&CPU::L2D, // 0x065 — I64 (Long) to F64 (Double) &CPU::L2D, // 0x065 — I64 (Long) to F64 (Double)
&CPU::F2I, // 0x066 — F32 (Float) to I32 (Integer) &CPU::F2I, // 0x066 — F32 (Float) to I32 (Integer)
&CPU::F2L, // 0x067 — F32 (Float) to I64 (Long) &CPU::F2L, // 0x067 — F32 (Float) to I64 (Long)
&CPU::D2I, // 0x068 — F64 (Double) to I32 (Integer) &CPU::D2I, // 0x068 — F64 (Double) to I32 (Integer)
&CPU::D2L, // 0x069 — F64 (Double) to I64 (Long) &CPU::D2L, // 0x069 — F64 (Double) to I64 (Long)
nullptr, // 0x06A (reserved) nullptr, // 0x06A (reserved)
nullptr, // 0x06B (reserved) nullptr, // 0x06B (reserved)
&CPU::SIN, // 0x06C — Sine Function &CPU::SIN, // 0x06C — Sine Function
&CPU::COS, // 0x06D — Cosine Function &CPU::COS, // 0x06D — Cosine Function
&CPU::TAN, // 0x06E — Tangent Function &CPU::TAN, // 0x06E — Tangent Function
&CPU::ASIN, // 0x06F — Arc Sine Function &CPU::ASIN, // 0x06F — Arc Sine Function
&CPU::ACOS, // 0x070 — Arc Cosine Function &CPU::ACOS, // 0x070 — Arc Cosine Function
&CPU::ATAN, // 0x071 — Arc Tangent Function &CPU::ATAN, // 0x071 — Arc Tangent Function
&CPU::ATAN2, // 0x072 — Arc Tangent Function with 2 Arguments &CPU::ATAN2, // 0x072 — Arc Tangent Function with 2 Arguments
nullptr, // 0x073 (reserved) nullptr, // 0x073 (reserved)
&CPU::EXP, // 0x074 — Exponential Function &CPU::EXP, // 0x074 — Exponential Function
&CPU::LOG, // 0x075 — Natural Logarithm &CPU::LOG, // 0x075 — Natural Logarithm
&CPU::LOGAB, // 0x076 — Logarithm A of B &CPU::LOGAB, // 0x076 — Logarithm A of B
&CPU::POW, // 0x077 — Power Function &CPU::POW, // 0x077 — Power Function
&CPU::SQRT, // 0x078 — Square Root &CPU::SQRT, // 0x078 — Square Root
&CPU::ROOT, // 0x079 — General Root &CPU::ROOT, // 0x079 — General Root
nullptr, // 0x07A (reserved) nullptr, // 0x07A (reserved)
nullptr, // 0x07B (reserved) nullptr, // 0x07B (reserved)
&CPU::ADC, // 0x07C — Add with Carry &CPU::ADC, // 0x07C — Add with Carry
&CPU::SWC, // 0x07D — Subtract with Carry (Borrow) &CPU::SWC, // 0x07D — Subtract with Carry (Borrow)
&CPU::MWO, // 0x07E — Multiply with Overflow &CPU::MWO, // 0x07E — Multiply with Overflow
&CPU::UMO, // 0x07F — Unsigned Multiply with Overflow &CPU::UMO, // 0x07F — Unsigned Multiply with Overflow
&CPU::MADD, // 0x080 — Matrix Addition &CPU::MADD, // 0x080 — Matrix Addition
&CPU::MSUB, // 0x081 — Matrix Subtraction &CPU::MSUB, // 0x081 — Matrix Subtraction
&CPU::MMUL, // 0x082 — Matrix Multiply &CPU::MMUL, // 0x082 — Matrix Multiply
&CPU::MINV, // 0x083 — Matrix Inverse &CPU::MINV, // 0x083 — Matrix Inverse
&CPU::MTRA, // 0x084 — Matrix Transpose &CPU::MTRA, // 0x084 — Matrix Transpose
&CPU::MDET, // 0x085 — Matrix Determinant &CPU::MDET, // 0x085 — Matrix Determinant
&CPU::QMKA, // 0x086 — Quaternion Make from Angles &CPU::QMKA, // 0x086 — Quaternion Make from Angles
&CPU::QMUL, // 0x087 — Quaternion Multiply &CPU::QMUL, // 0x087 — Quaternion Multiply
nullptr, // 0x088 nullptr, // 0x088
nullptr, // 0x089 nullptr, // 0x089
&CPU::XADD, // 0x08A — SIMD Addition &CPU::XADD, // 0x08A — SIMD Addition
&CPU::XSUB, // 0x08B — SIMD Subtract &CPU::XSUB, // 0x08B — SIMD Subtract
&CPU::XAMA, // 0x08C — SIMD Alternate Multiply-Add &CPU::XAMA, // 0x08C — SIMD Alternate Multiply-Add
&CPU::XMUL, // 0x08D — SIMD Multiply &CPU::XMUL, // 0x08D — SIMD Multiply
&CPU::XDIV, // 0x08E — SIMD Divide &CPU::XDIV, // 0x08E — SIMD Divide
nullptr, // 0x08F nullptr, // 0x08F
nullptr, // 0x090 nullptr, // 0x090
nullptr, // 0x091 nullptr, // 0x091
@@ -275,13 +275,13 @@ CPU::Fn CPU::instrMap[] = {
nullptr, // 0x0ED nullptr, // 0x0ED
nullptr, // 0x0EE nullptr, // 0x0EE
nullptr, // 0x0EF nullptr, // 0x0EF
&CPU::UPY, // 0x0F0 — Will place "YUPI" in memory &CPU::UPY, // 0x0F0 — Will place "YUPI" in memory
&CPU::LLGS, // 0x0F1 — Spider ASCII art (LLGS easter egg) &CPU::INT_1_SLOT, // 0x0F1 —
nullptr, // 0x0F2 &CPU::INT_2_SLOT, // 0x0F2
nullptr, // 0x0F3 &CPU::INT_3_SLOT, // 0x0F3
nullptr, // 0x0F4 &CPU::INT_4_SLOT, // 0x0F4
nullptr, // 0x0F5 &CPU::BRAD, // 0x0F5
&CPU::DGANT, // 0x0F6 &CPU::DGANT, // 0x0F6
nullptr, // 0x0F7 nullptr, // 0x0F7
nullptr, // 0x0F8 nullptr, // 0x0F8
nullptr, // 0x0F9 nullptr, // 0x0F9
@@ -583,7 +583,6 @@ void CPU::executeSwLk() {
case 0x00B: MOR(); break; case 0x00B: MOR(); break;
case 0x00C: AMOV(); break; case 0x00C: AMOV(); break;
case 0x00D: SWP(); break; case 0x00D: SWP(); break;
case 0x00E: AHM(); break;
// ── Integer ───────────────────────────────────── // ── Integer ─────────────────────────────────────
case 0x010: COM(); break; case 0x010: COM(); break;
@@ -602,9 +601,6 @@ void CPU::executeSwLk() {
case 0x01D: DMOD(); break; case 0x01D: DMOD(); break;
case 0x01E: UDMD(); break; case 0x01E: UDMD(); break;
// ── System ──────────────────────────────────────
case 0x01F: FBT(); break;
// ── Bit Wise ──────────────────────────────────── // ── Bit Wise ────────────────────────────────────
case 0x020: STB(); break; case 0x020: STB(); break;
case 0x021: CRB(); break; case 0x021: CRB(); break;
@@ -622,12 +618,16 @@ void CPU::executeSwLk() {
case 0x02D: CNT(); break; case 0x02D: CNT(); break;
// ── Boolean ───────────────────────────────────── // ── Boolean ─────────────────────────────────────
case 0x030: EQ(); break; case 0x02E: EQ(); break;
case 0x031: NE(); break; case 0x02F: NE(); break;
case 0x032: GT(); break; case 0x030: GT(); break;
case 0x033: GE(); break; case 0x031: GE(); break;
case 0x034: LT(); break; case 0x032: LT(); break;
case 0x035: LE(); break; case 0x033: LE(); break;
case 0x034: GTU(); break;
case 0x035: GEU(); break;
case 0x036: LTU(); break;
case 0x037: LEU(); break;
// ── Branch ────────────────────────────────────── // ── Branch ──────────────────────────────────────
case 0x038: JMP(); break; case 0x038: JMP(); break;
@@ -737,8 +737,12 @@ void CPU::executeSwLk() {
// ── Easter Eggs ───────────────────────────────── // ── Easter Eggs ─────────────────────────────────
case 0x0F0: UPY(); break; case 0x0F0: UPY(); break;
case 0x0F1: LLGS(); break; case 0x0F1: INT_1_SLOT(); break;
case 0x0F2: INT_2_SLOT(); break;
case 0x0F3: INT_3_SLOT(); break;
case 0x0F4: INT_4_SLOT(); break;
case 0x0F5: BRAD(); break;
case 0x0F6: DGANT(); break;
default: default:
break; break;
+259 -212
View File
@@ -4,15 +4,16 @@
*/ */
#include <spider/runtime/cpu/CPU.hpp> #include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/RAM.hpp>
namespace spider { namespace spider {
void CPU::NOP() { void CPU::NOP() {
// TODO: Implement NOP // DONE ! //
} }
void CPU::SPDR() { void CPU::SPDR() {
// TODO: Implement SPDR RA._u64 = spider::RUNTIME_VERSION_NO;
} }
void CPU::MMODE() { void CPU::MMODE() {
@@ -21,10 +22,13 @@ namespace spider {
void CPU::INT() { void CPU::INT() {
// TODO: Implement INT // TODO: Implement INT
// We need to implement an interrupt
// table and interrupt system!
} }
void CPU::LRV() { void CPU::LRV() {
// TODO: Implement LRV fetchOperReg();
RV = _dst->_u64;
} }
void CPU::FSR() { void CPU::FSR() {
@@ -32,11 +36,13 @@ namespace spider {
} }
void CPU::FIR() { void CPU::FIR() {
// TODO: Implement FIR fetchOperReg();
_dst->_u64 = RI;
} }
void CPU::FZR() { void CPU::FZR() {
// TODO: Implement FZR fetchOperReg();
_dst->_u64 = RZ;
} }
void CPU::LSR() { void CPU::LSR() {
@@ -44,310 +50,351 @@ namespace spider {
} }
void CPU::FVR() { void CPU::FVR() {
// TODO: Implement FVR fetchOperReg();
_dst->_u64 = RV;
} }
void CPU::MOV() { void CPU::MOV() {
// TODO: Implement MOV fetchOperSrc();
fetchOperDst();
switch (_size) {
case 0b00: //byte
_dst->_u8 = _src->_u8;
break;
case 0b01: //short
_dst->_u16 = _src->_u16;
break;
case 0b10: //int
_dst->_u32 = _src->_u32;
break;
case 0b11: //long
_dst->_u64 = _src->_u64;
break;
}
} }
void CPU::MOR() { void CPU::MOR() {
// TODO: Implement MOR fetchOperRegReg();
*_dst = *_src;
} }
void CPU::AMOV() { void CPU::AMOV() {
// TODO: Implement AMOV // AMOV potential is capped at 256 bytes!
u64 amt = RA._u16;
u64 from = RX._u64;
u64 to = RY._u64;
if(amt > 256) return;
// are RX and RY in valid regions of memory?
u64 ramsize = _ram->size();
if (from >= ramsize || amt > (ramsize - from)) return;
if (to >= ramsize || amt > (ramsize - to)) return;
// Use std::copy_backward if destination overlaps ahead of source
auto ram_begin = _ram->begin();
if (to > from && to < from + amt) {
// Overlap case where destination is ahead of source: copy from back to front
std::copy_backward(ram_begin + from, ram_begin + from + amt, ram_begin + to + amt);
} else {
// No overlap, or destination is behind source: copy front to back
std::copy(ram_begin + from, ram_begin + from + amt, ram_begin + to);
}
} }
void CPU::SWP() { void CPU::SWP() {
// TODO: Implement SWP // get registers in _dst and _src
} fetchOperRegReg();
ALU0 = *_dst;
void CPU::AHM() { *_dst = *_src;
// TODO: Implement AHM *_src = ALU0;
} }
void CPU::COM() { void CPU::COM() {
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 = ~_dst->_u8; _dst->_u8 = ~_dst->_u8;
break; break;
case 0b01: //short case 0b01: //short
_dst->_u16 = ~_dst->_u16; _dst->_u16 = ~_dst->_u16;
break; break;
case 0b10: //int case 0b10: //int
_dst->_u32 = ~_dst->_u32; _dst->_u32 = ~_dst->_u32;
break; break;
case 0b11: //long case 0b11: //long
_dst->_u64 = ~_dst->_u64; _dst->_u64 = ~_dst->_u64;
break; break;
} }
(this->*_post)();
} }
void CPU::NEG() { void CPU::NEG() {
// TODO: Implement NEG
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 = 1 + ~_dst->_u8; _dst->_u8 = 1 + ~_dst->_u8;
break; break;
case 0b01: //short case 0b01: //short
_dst->_u16 = 1+ ~_dst->_u16; _dst->_u16 = 1 + ~_dst->_u16;
break; break;
case 0b10: //int case 0b10: //int
_dst->_u32 = 1 + ~_dst->_u32; _dst->_u32 = 1 + ~_dst->_u32;
break; break;
case 0b11: //long case 0b11: //long
_dst->_u64 = 1 + ~_dst->_u64; _dst->_u64 = 1 + ~_dst->_u64;
break; break;
} }
(this->*_post)();
} }
void CPU::EXS() { void CPU::EXS() {
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_i16 = static_cast<i16>(_dst->_i8); _dst->_i16 = static_cast<i16>(_dst->_i8);
break; break;
case 0b01: //short case 0b01: //short
_dst->_i32 = static_cast<i32>(_dst->_i16); _dst->_i32 = static_cast<i32>(_dst->_i16);
break; break;
case 0b10: //int case 0b10: //int
_dst->_i64 = static_cast<i64>(_dst->_i32); _dst->_i64 = static_cast<i64>(_dst->_i32);
break; break;
case 0b11: //long case 0b11: //long
_dst->_i64 = _dst->_i64; _dst->_i64 = _dst->_i64;
break; break;
} }
} }
void CPU::INC() { void CPU::INC() {
// TODO: Implement INC
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 += 1; _dst->_u8 += 1;
case 0b01: //short break;
_dst->_u16 += 1; case 0b01: //short
case 0b10: //int _dst->_u16 += 1;
_dst->_u32 += 1; break;
case 0b11: //long case 0b10: //int
_dst->_u64 += 1; _dst->_u32 += 1;
break;
case 0b11: //long
_dst->_u64 += 1;
break;
} }
(this->*_post)();
} }
void CPU::DEC() { void CPU::DEC() {
// TODO: Implement DEC
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 -= 1; _dst->_u8 -= 1;
case 0b01: //short break;
_dst->_u16 -= 1; case 0b01: //short
case 0b10: //int _dst->_u16 -= 1;
_dst->_u32 -= 1; break;
case 0b11: //long case 0b10: //int
_dst->_u64 -= 1; _dst->_u32 -= 1;
break;
case 0b11: //long
_dst->_u64 -= 1;
break;
} }
(this->*_post)();
} }
void CPU::ADD() { void CPU::ADD() {
// TODO: Implement ADD
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 += _src->_u8; _dst->_u8 += _src->_u8;
case 0b01: //short break;
_dst->_u16 += _src->_u16; case 0b01: //short
case 0b10: //int _dst->_u16 += _src->_u16;
_dst->_u32 += _src->_u32; break;
case 0b11: //long case 0b10: //int
_dst->_u64 += _src->_u64; _dst->_u32 += _src->_u32;
break;
case 0b11: //long
_dst->_u64 += _src->_u64;
break;
} }
(this->*_post)();
} }
void CPU::SUB() { void CPU::SUB() {
// TODO: Implement SUB
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 -= _src->_u8; _dst->_u8 -= _src->_u8;
case 0b01: //short break;
_dst->_u16 -= _src->_u16; case 0b01: //short
case 0b10: //int _dst->_u16 -= _src->_u16;
_dst->_u32 -= _src->_u32; break;
case 0b11: //long case 0b10: //int
_dst->_u64 -= _src->_u64; _dst->_u32 -= _src->_u32;
break;
case 0b11: //long
_dst->_u64 -= _src->_u64;
break;
} }
(this->*_post)();
} }
void CPU::MUL() { void CPU::MUL() {
// TODO: Implement MUL
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_i8 = _src->_i8 * _dst->_i8; _dst->_i8 = _src->_i8 * _dst->_i8;
case 0b01: //short break;
_dst->_i16 = _src->_i16 * _dst->_i16; case 0b01: //short
case 0b10: //int _dst->_i16 = _src->_i16 * _dst->_i16;
_dst->_i32 = _src->_i32 * _dst->_i32; break;
case 0b11: //long case 0b10: //int
_dst->_i64 = _src->_i64 * _dst->_i64; _dst->_i32 = _src->_i32 * _dst->_i32;
break;
case 0b11: //long
_dst->_i64 = _src->_i64 * _dst->_i64;
break;
} }
(this->*_post)();
} }
void CPU::UMUL() { void CPU::UMUL() {
// TODO: Implement UMUL
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 = _src->_u8 * _dst->_u8; _dst->_u8 = _src->_u8 * _dst->_u8;
case 0b01: //short break;
_dst->_u16 = _src->_u16 * _dst->_u16; case 0b01: //short
case 0b10: //int _dst->_u16 = _src->_u16 * _dst->_u16;
_dst->_u32 = _src->_u32 * _dst->_u32; break;
case 0b11: //long case 0b10: //int
_dst->_u64 = _src->_u64 * _dst->_u64; _dst->_u32 = _src->_u32 * _dst->_u32;
break;
case 0b11: //long
_dst->_u64 = _src->_u64 * _dst->_u64;
break;
} }
(this->*_post)();
} }
void CPU::DIV() { void CPU::DIV() {
// TODO: Implement DIV
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_i8 = _dst->_i8 / _src->_i8; _dst->_i8 = _dst->_i8 / _src->_i8;
case 0b01: //short break;
_dst->_i16 = _dst->_i16 / _src->_i16; case 0b01: //short
case 0b10: //int _dst->_i16 = _dst->_i16 / _src->_i16;
_dst->_i32 = _dst->_i32 / _src->_i32; break;
case 0b11: //long case 0b10: //int
_dst->_i64 = _dst->_i64 / _src->_i64; _dst->_i32 = _dst->_i32 / _src->_i32;
break;
case 0b11: //long
_dst->_i64 = _dst->_i64 / _src->_i64;
break;
} }
(this->*_post)();
} }
void CPU::UDIV() { void CPU::UDIV() {
// TODO: Implement UDIV
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 = _dst->_u8 / _src->_u8; _dst->_u8 = _dst->_u8 / _src->_u8;
case 0b01: //short break;
_dst->_u16 = _dst->_u16 / _src->_u16; case 0b01: //short
case 0b10: //int _dst->_u16 = _dst->_u16 / _src->_u16;
_dst->_u32 = _dst->_u32 / _src->_u32; break;
case 0b11: //long case 0b10: //int
_dst->_u64 = _dst->_u64 / _src->_u64; _dst->_u32 = _dst->_u32 / _src->_u32;
break;
case 0b11: //long
_dst->_u64 = _dst->_u64 / _src->_u64;
break;
} }
(this->*_post)();
} }
void CPU::MOD() { void CPU::MOD() {
// TODO: Implement MOD
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_i8 = _dst->_i8 % _src->_i8; _dst->_i8 = _dst->_i8 % _src->_i8;
case 0b01: //short break;
_dst->_i16 = _dst->_i16 % _src->_i16; case 0b01: //short
case 0b10: //int _dst->_i16 = _dst->_i16 % _src->_i16;
_dst->_i32 = _dst->_i32 % _src->_i32; break;
case 0b11: //long case 0b10: //int
_dst->_i64 = _dst->_i64 % _src->_i64; _dst->_i32 = _dst->_i32 % _src->_i32;
break;
case 0b11: //long
_dst->_i64 = _dst->_i64 % _src->_i64;
break;
} }
(this->*_post)();
} }
void CPU::UMOD() { void CPU::UMOD() {
// TODO: Implement UMOD
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
_dst->_u8 = _dst->_u8 % _src->_u8; _dst->_u8 = _dst->_u8 % _src->_u8;
case 0b01: //short break;
_dst->_u16 = _dst->_u16 % _src->_u16; case 0b01: //short
case 0b10: //int _dst->_u16 = _dst->_u16 % _src->_u16;
_dst->_u32 = _dst->_u32 % _src->_u32; break;
case 0b11: //long case 0b10: //int
_dst->_u64 = _dst->_u64 % _src->_u64; _dst->_u32 = _dst->_u32 % _src->_u32;
break;
case 0b11: //long
_dst->_u64 = _dst->_u64 % _src->_u64;
break;
} }
(this->*_post)();
} }
void CPU::DMOD() { void CPU::DMOD() {
// TODO: Implement DMOD
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
RX._i8 = _dst->_i8 / _src->_i8; RX._i8 = _dst->_i8 / _src->_i8;
RY._i8 = _dst->_i8 % _src->_i8; RY._i8 = _dst->_i8 % _src->_i8;
case 0b01: //short break;
RX._i16 = _dst->_i16 / _src->_i16; case 0b01: //short
RY._i16 = _dst->_i16 % _src->_i16; RX._i16 = _dst->_i16 / _src->_i16;
case 0b10: //int RY._i16 = _dst->_i16 % _src->_i16;
RX._i32 = _dst->_i32 / _src->_i32; break;
RY._i32 = _dst->_i32 % _src->_i32; case 0b10: //int
case 0b11: //long RX._i32 = _dst->_i32 / _src->_i32;
RX._i64 = _dst->_i64 / _src->_i64; RY._i32 = _dst->_i32 % _src->_i32;
RY._i64 = _dst->_i64 % _src->_i64; break;
case 0b11: //long
RX._i64 = _dst->_i64 / _src->_i64;
RY._i64 = _dst->_i64 % _src->_i64;
break;
} }
(this->*_post)();
} }
void CPU::UDMD() { void CPU::UDMD() {
// TODO: Implement UDMD
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch (_size) {
case 0b00: //byte case 0b00: //byte
RX._u8 = _dst->_u8 / _src->_u8; RX._u8 = _dst->_u8 / _src->_u8;
RY._u8 = _dst->_u8 % _src->_u8; RY._u8 = _dst->_u8 % _src->_u8;
case 0b01: //short break;
RX._u16 = _dst->_u16 / _src->_u16; case 0b01: //short
RY._u16 = _dst->_u16 % _src->_u16; RX._u16 = _dst->_u16 / _src->_u16;
case 0b10: //int RY._u16 = _dst->_u16 % _src->_u16;
RX._u32 = _dst->_u32 / _src->_u32; break;
RY._u32 = _dst->_u32 % _src->_u32; case 0b10: //int
case 0b11: //long RX._u32 = _dst->_u32 / _src->_u32;
RX._u64 = _dst->_u64 / _src->_u64; RY._u32 = _dst->_u32 % _src->_u32;
RY._u64 = _dst->_u64 % _src->_u64; break;
case 0b11: //long
RX._u64 = _dst->_u64 / _src->_u64;
RY._u64 = _dst->_u64 % _src->_u64;
break;
} }
(this->*_post)();
}
void CPU::FBT() {
// TODO: Implement FBT
fetchOperDst();
switch(_size){
case 0b00: //byte
RF = (RF & ~(0x3 << 9)) | ((_dst->_u8 >> 9) & 0x3) << 9;
case 0b01: //short
RF = (RF & ~(0x3 << 9)) | ((_dst->_u16 >> 9) & 0x3) << 9;
case 0b10: //int
RF = (RF & ~(0x3 << 9)) | ((_dst->_u32 >> 9) & 0x3) << 9;
case 0b11: //long
RF = (RF & ~(0x3 << 9)) | ((_dst->_u64 >> 9) & 0x3) << 9;
}
(this->*_post)();
} }
} }
+295 -76
View File
@@ -8,186 +8,405 @@
namespace spider { namespace spider {
void CPU::STB() { void CPU::STB() {
// TODO: Implement STB
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch(_size){
case 0b00: //byte case 0b00: //byte
_dst->_u8 |= (u64(1) << _src->_u8); _dst->_u8 |= (1 << _src->_u8);
break; break;
case 0b01: //short case 0b01: //short
_dst->_u16 |= (u64(1) << _src->_u16); _dst->_u16 |= (1 << _src->_u16);
break; break;
case 0b10: //int case 0b10: //int
_dst->_u32 |= (u64(1) << _src->_u32); _dst->_u32 |= (1 << _src->_u32);
break; break;
case 0b11: //long case 0b11: //long
_dst->_u64 |= (u64(1) << _src->_u64); _dst->_u64 |= (1 << _src->_u64);
break; break;
} }
(this->*_post)();
} }
void CPU::CRB() { void CPU::CRB() {
// TODO: Implement CRB
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){ switch(_size){
case 0b00: //byte case 0b00: //byte
_dst->_u8 &= ~u8(u64(1) << _src->_u8); _dst->_u8 &= u8(~(u8(1) << _src->_u8));
break; break;
case 0b01: //short case 0b01: //short
_dst->_u16 &= ~u16(u64(1) << _src->_u16); _dst->_u16 &= u16(~(u16(1) << _src->_u16));
break; break;
case 0b10: //int case 0b10: //int
_dst->_u32 &= ~u32(u64(1) << _src->_u32); _dst->_u32 &= ~(u32(1) << _src->_u32);
break; break;
case 0b11: //long case 0b11: //long
_dst->_u64 &= ~(u64(1) << _src->_u64); _dst->_u64 &= ~(u64(1) << _src->_u64);
break; break;
} }
(this->*_post)();
} }
void CPU::TSB() { void CPU::TSB() {
// TODO: Implement TSB
fetchOperSrc(); fetchOperSrc();
fetchOperDst(); fetchOperDst();
switch(_size){
case 0b00: //byte u64 s, d;
switch (((RF >> _src->_u8) & 1) != ((_dst->_u8 >> _src->_u8) & 1)){ switch(_size) {
case 1: case 0b00: // byte
RF |= (u64(1) << _src->_u8); s = _src->_u8;
d = _dst->_u8;
case 0: break;
RF &= ~(u64(1) << _src->_u8); case 0b01: // short
} s = _src->_u16;
case 0b01: //short d = _dst->_u16;
switch (((RF >> _src->_u16) & 1) != ((_dst->_u16 >> _src->_u16) & 1)){ break;
case 1: case 0b10: // int
RF |= (u64(1) << _src->_u16); s = _src->_u32;
d = _dst->_u32;
case 0: break;
RF &= ~(u64(1) << _src->_u16); case 0b11: // long
} s = _src->_u64;
case 0b10: //int d = _dst->_u64;
switch (((RF >> _src->_u32) & 1) != ((_dst->_u32 >> _src->_u32) & 1)){ break;
case 1:
RF |= (u64(1) << _src->_u32);
case 0:
RF &= ~(u64(1) << _src->_u32);
}
case 0b11: //long
switch (((RF >> _src->_u64) & 1) != ((_dst->_u64 >> _src->_u64) & 1)){
case 1:
RF |= (u64(1) << _src->_u64);
case 0:
RF &= ~(u64(1) << _src->_u64);
}
} }
(this->*_post)();
d >>= s;
d &= 1;
} }
void CPU::BOOL() { void CPU::BOOL() {
// TODO: Implement BOOL
fetchOperDst(); fetchOperDst();
switch(_size){ switch(_size){
case 0b00: //byte case 0b00: // byte
_dst->_u8 = _dst != 0; _dst->_u8 = _dst->_u8 != 0;
break; break;
case 0b01: //short case 0b01: // short
_dst->_u16 = _dst != 0; _dst->_u16 = _dst->_u16 != 0;
break; break;
case 0b10: //int case 0b10: // int
_dst->_u32 = _dst != 0; _dst->_u32 = _dst->_u32 != 0;
break; break;
case 0b11: //long case 0b11: // long
_dst->_u64 = _dst != 0; _dst->_u64 = _dst->_u64 != 0;
break; break;
} }
(this->*_post)();
} }
// ── 0x024 — NOT: Tests Dst == 0, updates Equal Flag ──
void CPU::NOT() { void CPU::NOT() {
// TODO: Implement NOT fetchOperDst();
bool isZero = false;
switch(_size) {
case 0b00: isZero = (_dst->_u8 == 0); break;
case 0b01: isZero = (_dst->_u16 == 0); break;
case 0b10: isZero = (_dst->_u32 == 0); break;
case 0b11: isZero = (_dst->_u64 == 0); break;
}
if (isZero) {
RF |= CPU::FLAG_EQUAL; // Si es 0, el resultado de !0 es true (1), actualizamos bandera
// Dependiendo de la implementación de BOOL, podrías querer guardar el resultado en Dst
_dst->_u64 = 1;
} else {
RF &= ~CPU::FLAG_EQUAL;
_dst->_u64 = 0;
}
} }
// ── 0x025 — AND
void CPU::AND() { void CPU::AND() {
// TODO: Implement AND fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 &= _src->_u8; break;
case 0b01: _dst->_u16 &= _src->_u16; break;
case 0b10: _dst->_u32 &= _src->_u32; break;
case 0b11: _dst->_u64 &= _src->_u64; break;
}
} }
// ── 0x026 — OR
void CPU::OR() { void CPU::OR() {
// TODO: Implement OR fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 |= _src->_u8; break;
case 0b01: _dst->_u16 |= _src->_u16; break;
case 0b10: _dst->_u32 |= _src->_u32; break;
case 0b11: _dst->_u64 |= _src->_u64; break;
}
} }
// ── 0x027 — XOR
void CPU::XOR() { void CPU::XOR() {
// TODO: Implement XOR fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 ^= _src->_u8; break;
case 0b01: _dst->_u16 ^= _src->_u16; break;
case 0b10: _dst->_u32 ^= _src->_u32; break;
case 0b11: _dst->_u64 ^= _src->_u64; break;
}
} }
// ── 0x028 — SHL
void CPU::SHL() { void CPU::SHL() {
// TODO: Implement SHL fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 <<= _src->_u8; break;
case 0b01: _dst->_u16 <<= _src->_u16; break;
case 0b10: _dst->_u32 <<= _src->_u32; break;
case 0b11: _dst->_u64 <<= _src->_u64; break;
}
} }
// ── 0x029 — SHR
void CPU::SHR() { void CPU::SHR() {
// TODO: Implement SHR fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 >>= _src->_u8; break;
case 0b01: _dst->_u16 >>= _src->_u16; break;
case 0b10: _dst->_u32 >>= _src->_u32; break;
case 0b11: _dst->_u64 >>= _src->_u64; break;
}
} }
// ── 0x02A — SSR
void CPU::SSR() { void CPU::SSR() {
// TODO: Implement SSR fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_i8 >>= _src->_u8; break;
case 0b01: _dst->_i16 >>= _src->_u8; break;
case 0b10: _dst->_i32 >>= _src->_u8; break;
case 0b11: _dst->_i64 >>= _src->_u8; break;
}
} }
// ── 0x02B — ROL: Rotate Left ──
void CPU::ROL() { void CPU::ROL() {
// TODO: Implement ROL fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 = (_dst->_u8 << _src->_u8) | (_dst->_u8 >> (8 - _src->_u8)); break;
case 0b01: _dst->_u16 = (_dst->_u16 << _src->_u8) | (_dst->_u16 >> (16 - _src->_u8)); break;
case 0b10: _dst->_u32 = (_dst->_u32 << _src->_u8) | (_dst->_u32 >> (32 - _src->_u8)); break;
case 0b11: _dst->_u64 = (_dst->_u64 << _src->_u8) | (_dst->_u64 >> (64 - _src->_u8)); break;
}
} }
// ── 0x02C — ROR: Rotate Right ──
void CPU::ROR() { void CPU::ROR() {
// TODO: Implement ROR fetchOperSrc();
fetchOperDst();
switch(_size) {
case 0b00: _dst->_u8 = (_dst->_u8 >> _src->_u8) | (_dst->_u8 << (8 - _src->_u8)); break;
case 0b01: _dst->_u16 = (_dst->_u16 >> _src->_u8) | (_dst->_u16 << (16 - _src->_u8)); break;
case 0b10: _dst->_u32 = (_dst->_u32 >> _src->_u8) | (_dst->_u32 << (32 - _src->_u8)); break;
case 0b11: _dst->_u64 = (_dst->_u64 >> _src->_u8) | (_dst->_u64 << (64 - _src->_u8)); break;
}
} }
// ── 0x02D — CNT: Counts bits (# of 1's into Dst) ──
void CPU::CNT() { void CPU::CNT() {
// TODO: Implement CNT fetchOperDst();
switch(_size) { // C++20 cross compatible version!!
case 0b00: _dst->_u8 = u8( std::popcount(_dst->_u8) ); break;
case 0b01: _dst->_u16 = u16(std::popcount(_dst->_u16)); break;
case 0b10: _dst->_u32 = u32(std::popcount(_dst->_u32)); break;
case 0b11: _dst->_u64 = u64(std::popcount(_dst->_u64)); break;
}
} }
void CPU::EQ() { void CPU::EQ() {
// TODO: Implement EQ fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 == _src->_u8); break;
case 0b01: res = (_dst->_u16 == _src->_u16); break;
case 0b10: res = (_dst->_u32 == _src->_u32); break;
case 0b11: res = (_dst->_u64 == _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
} }
void CPU::NE() { void CPU::NE() {
// TODO: Implement NE fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 != _src->_u8); break;
case 0b01: res = (_dst->_u16 != _src->_u16); break;
case 0b10: res = (_dst->_u32 != _src->_u32); break;
case 0b11: res = (_dst->_u64 != _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
} }
void CPU::GT() { void CPU::GT() {
// TODO: Implement GT fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 > _src->_i8); break;
case 0b01: res = (_dst->_i16 > _src->_i16); break;
case 0b10: res = (_dst->_i32 > _src->_i32); break;
case 0b11: res = (_dst->_i64 > _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
} }
void CPU::GE() { void CPU::GE() {
// TODO: Implement GE fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 >= _src->_i8); break;
case 0b01: res = (_dst->_i16 >= _src->_i16); break;
case 0b10: res = (_dst->_i32 >= _src->_i32); break;
case 0b11: res = (_dst->_i64 >= _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
} }
void CPU::LT() { void CPU::LT() {
// TODO: Implement LT fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 < _src->_i8); break;
case 0b01: res = (_dst->_i16 < _src->_i16); break;
case 0b10: res = (_dst->_i32 < _src->_i32); break;
case 0b11: res = (_dst->_i64 < _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
} }
void CPU::LE() { void CPU::LE() {
// TODO: Implement LE fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_i8 <= _src->_i8); break;
case 0b01: res = (_dst->_i16 <= _src->_i16); break;
case 0b10: res = (_dst->_i32 <= _src->_i32); break;
case 0b11: res = (_dst->_i64 <= _src->_i64); break;
}
_dst->_u64 = res ? 1 : 0;
} }
void CPU::GTU() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 > _src->_u8); break;
case 0b01: res = (_dst->_u16 > _src->_u16); break;
case 0b10: res = (_dst->_u32 > _src->_u32); break;
case 0b11: res = (_dst->_u64 > _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
}
void CPU::GEU() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 >= _src->_u8); break;
case 0b01: res = (_dst->_u16 >= _src->_u16); break;
case 0b10: res = (_dst->_u32 >= _src->_u32); break;
case 0b11: res = (_dst->_u64 >= _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
}
void CPU::LTU() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 < _src->_u8); break;
case 0b01: res = (_dst->_u16 < _src->_u16); break;
case 0b10: res = (_dst->_u32 < _src->_u32); break;
case 0b11: res = (_dst->_u64 < _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
}
void CPU::LEU() {
fetchOperSrc();
fetchOperDst();
bool res = false;
switch(_size) {
case 0b00: res = (_dst->_u8 <= _src->_u8); break;
case 0b01: res = (_dst->_u16 <= _src->_u16); break;
case 0b10: res = (_dst->_u32 <= _src->_u32); break;
case 0b11: res = (_dst->_u64 <= _src->_u64); break;
}
_dst->_u64 = res ? 1 : 0;
}
// ── 0x038 — JMP: Dst -> Instruction Register (PC) ──
// The IR adds 1 at the end, so we subtract 1 to compensate.
void CPU::JMP() { void CPU::JMP() {
// TODO: Implement JMP fetchOperDst();
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
} }
// ── 0x039 — JEQ: Jump if EQ flag is set ──
void CPU::JEQ() { void CPU::JEQ() {
// TODO: Implement JEQ fetchOperDst();
if (RF & CPU::FLAG_EQUAL) {
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
} }
// ── 0x03A — JNE: Jumps if EQ flag is cleared ──
void CPU::JNE() { void CPU::JNE() {
// TODO: Implement JNE fetchOperDst();
if (!(RF & CPU::FLAG_EQUAL)) {
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
} }
// ── 0x03B — JIF: Jumps if Src is booleanly true ──
void CPU::JIF() { void CPU::JIF() {
// TODO: Implement JIF fetchOperSrc();
fetchOperDst();
if (_src->_u64 != 0) {
u64 target;
switch(_size) {
case 0b00: target = static_cast<u64>(_dst->_u8); break;
case 0b01: target = static_cast<u64>(_dst->_u16); break;
case 0b10: target = static_cast<u64>(_dst->_u32); break;
case 0b11: target = _dst->_u64; break;
}
RI = target - 1;
}
} }
// ── 0x03C — JMR: Dst + Instruction Register -> Instruction Register ── // ── 0x03C — JMR: Dst + Instruction Register -> Instruction Register ──
+9 -1
View File
@@ -12,6 +12,14 @@ namespace spider {
// TODO: Implement UPY // TODO: Implement UPY
} }
void CPU::INT_1_SLOT() {}
void CPU::INT_2_SLOT() {}
void CPU::INT_3_SLOT() {}
void CPU::INT_4_SLOT() {}
// ── 0x0F6 — DGANT: "I'm SpiderLang" in a spider web ──────────── // ── 0x0F6 — DGANT: "I'm SpiderLang" in a spider web ────────────
void CPU::DGANT() { void CPU::DGANT() {
const char art[] = const char art[] =
@@ -53,7 +61,7 @@ namespace spider {
} }
/** /**
* @brief BRAD (0xF7) - Memory Integrity Checksum * @brief BRAD (0xF5) - Memory Integrity Checksum
* Escanea los primeros 256 bytes de memoria y valida contra una firma de seguridad. * Escanea los primeros 256 bytes de memoria y valida contra una firma de seguridad.
* Implementado por Bradley Vergara Lara - Estancia 2026. * Implementado por Bradley Vergara Lara - Estancia 2026.
*/ */
-61
View File
@@ -1,61 +0,0 @@
/**
* @brief LLGS — Easter egg by Arturo Balam (Data - 7A)
*
* Opcode: 0x0F1
*
* Writes a Spider ASCII art into RAM starting at address 0x00,
* and loads the author signature into RA as a packed ASCII string.
* This version matches the custom mechanical spider design
* and is formatted to fit an 8-byte RAM viewer width.
*
* RAM layout after LLGS executes (8 characters per row, 4 rows total):
* 0x00: "// _ \\" (Row 1)
* 0x08: "\\( )// " (Row 2)
* 0x10: " //()\\ " (Row 3)
* 0x18: " \\ // " (Row 4)
*
* RA after execution: 0x4C4C475300000000ULL ("LLGS" in ASCII, zero-padded)
* (L=0x4C, L=0x4C, G=0x47, S=0x53)
*/
#include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/RAM.hpp>
namespace spider {
void CPU::LLGS() {
// -- Write Spider ASCII art into RAM ---------------------------------
// Padded with exact spaces to ensure it never wraps in an 8-byte viewer
// Row 0: "// _ \\ "
_ram->at(0x00) = '/'; _ram->at(0x01) = '/';
_ram->at(0x02) = ' '; _ram->at(0x03) = '_';
_ram->at(0x04) = ' '; _ram->at(0x05) = '\\';
_ram->at(0x06) = '\\'; _ram->at(0x07) = ' ';
// Row 1: "\\( )// "
_ram->at(0x08) = '\\'; _ram->at(0x09) = '\\';
_ram->at(0x0A) = '('; _ram->at(0x0B) = ' ';
_ram->at(0x0C) = ')'; _ram->at(0x0D) = '/';
_ram->at(0x0E) = '/'; _ram->at(0x0F) = ' ';
// Row 2: " //()\\ "
_ram->at(0x10) = ' '; _ram->at(0x11) = '/';
_ram->at(0x12) = '/'; _ram->at(0x13) = '(';
_ram->at(0x14) = ')'; _ram->at(0x15) = '\\';
_ram->at(0x16) = '\\'; _ram->at(0x17) = ' ';
// Row 3: " \\ // "
_ram->at(0x18) = ' '; _ram->at(0x19) = '\\';
_ram->at(0x1A) = '\\'; _ram->at(0x1B) = ' ';
_ram->at(0x1C) = ' '; _ram->at(0x1D) = '/';
_ram->at(0x1E) = '/'; _ram->at(0x1F) = ' ';
// -- Load mnemonic into RA ------------------------
// "LLGS" packed as ASCII bytes into RA
RA._u64 = 0x4C4C475300000000ULL;
}
} // namespace spider
+7 -7
View File
@@ -26,7 +26,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u8 readU8(u64 ip) = 0; virtual u8 readU8(u64 ip) const = 0;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -34,7 +34,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u16 readU16(u64 ip) = 0; virtual u16 readU16(u64 ip) const = 0;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -42,7 +42,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u32 readU32(u64 ip) = 0; virtual u32 readU32(u64 ip) const = 0;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -50,20 +50,20 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u64 readU64(u64 ip) = 0; virtual u64 readU64(u64 ip) const = 0;
/** /**
* Reads a range of data, and * Reads a range of data, and
* outputs it. * outputs it.
*/ */
virtual void readRange(u64 ip, u8* out, u64 length) = 0; virtual void readRange(u64 ip, u8* out, u64 length) const = 0;
virtual void loadRegister(u64 ip, u8 size_code, register_t* r) = 0; virtual void loadRegister(u64 ip, u8 size_code, register_t* r) const = 0;
/** /**
* Current size of the instructions. * Current size of the instructions.
*/ */
virtual u64 size() = 0; virtual u64 size() const = 0;
public: // Static Utils // public: // Static Utils //
+268 -167
View File
@@ -5,181 +5,69 @@
namespace spider { namespace spider {
InstrReelDyn::InstrReelDyn(u64 length) : _size(length) { InstrReelDyn::InstrReelDyn(u64 length) : _size(length) {
// Safe int ceil division if (_size == 0) return;
growTo((length >> 8) + ((length & 255) != 0));
// 1. Allocate and fill the buffer with zeroed blocks
grow(_size);
_buffer.assign(_size, 0);
// 2. Pad the physical vector to match block alignment
if (_buffer.size() % _blocksize != 0) {
u64 padding = _blocksize - (_buffer.size() % _blocksize);
_buffer.insert(_buffer.end(), padding, 0);
}
// 3. Manifest the initial blank part in our orchestration
_pieces.push_back({ 0, _size });
} }
//InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {} InstrReelDyn::InstrReelDyn(const u8* data, u64 length) : _size(0) {
if (length == 0) return;
grow(length);
write(0, data, length);
}
InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy)
: _blocks(copy._blocks), _size(copy._size) { : _buffer(copy._buffer),
} _pieces(copy._pieces),
_size(copy._size) {}
// No-throw Move Constructor
InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept
: _blocks(std::move(move._blocks)), _size(std::move(move._size)) { : _buffer(std::move(move._buffer)),
_pieces(std::move(move._pieces)),
_size(move._size) {
move._size = 0;
} }
// Explicit Destructor execution
InstrReelDyn::~InstrReelDyn() { InstrReelDyn::~InstrReelDyn() {
// .. // _pieces.clear();
_buffer.clear();
} }
// Deep Copy Assignment Operator
InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) { InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) {
_blocks = copy._blocks; if (this != &copy) {
_size = copy._size; _buffer = copy._buffer;
_pieces = copy._pieces;
_size = copy._size;
}
return *this; return *this;
} }
// No-throw Move Assignment Operator
InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept { InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept {
_blocks = std::move(move._blocks); if (this != &move) {
_size = std::move(move._size); _buffer = std::move(move._buffer);
_pieces = std::move(move._pieces);
_size = move._size;
move._size = 0;
}
return *this; return *this;
} }
void InstrReelDyn::growTo(u64 ip) { void InstrReelDyn::loadRegister(u64 ip, u8 size_code, register_t* r) const {
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
}
}
void InstrReelDyn::loadRegister(u64 ip, u8 size_code, register_t* r) {
u8 bytes[8]; u8 bytes[8];
readRange(ip, bytes, 1 << size_code); readRange(ip, bytes, 1 << size_code);
spider::loadRegister[size_code](r, bytes, 8); spider::loadRegister[size_code](r, bytes, 8);
@@ -188,22 +76,235 @@ namespace spider {
/** /**
* Current size of the instructions. * Current size of the instructions.
*/ */
u64 InstrReelDyn::size() { u64 InstrReelDyn::size() const {
return _size; return _size;
} }
// Reading, Prepared //
u8 InstrReelDyn::readU8(u64 ip) const {
u8 dat;
u8 arr[sizeof(dat)];
readRange(ip, arr, sizeof(arr));
spider::loadPartialLE(&dat, arr, sizeof(arr));
return dat;
}
u16 InstrReelDyn::readU16(u64 ip) const {
u16 dat;
u8 arr[sizeof(dat)];
readRange(ip, arr, sizeof(arr));
spider::loadPartialLE(&dat, arr, sizeof(arr));
return dat;
}
u32 InstrReelDyn::readU32(u64 ip) const {
u32 dat;
u8 arr[sizeof(dat)];
readRange(ip, arr, sizeof(arr));
spider::loadPartialLE(&dat, arr, sizeof(arr));
return dat;
}
u64 InstrReelDyn::readU64(u64 ip) const {
u64 dat;
u8 arr[sizeof(dat)];
readRange(ip, arr, sizeof(arr));
spider::loadPartialLE(&dat, arr, sizeof(arr));
return dat;
}
// Mutation // // Mutation //
// TODO! void InstrReelDyn::readRange(u64 ip, u8* dat, const u64 len) const {
// 1. Boundary Guard
if (len == 0 || ip + len > _size || dat == nullptr) return;
//void InstrReelDyn::writeU8(u64 ip, u8 dat) {} u64 bytes_copied = 0;
//void InstrReelDyn::writeU16(u64 ip, u16 dat) {} u64 current_ip = 0;
//void InstrReelDyn::writeU32(u64 ip, u32 dat) {}
//void InstrReelDyn::writeU64(u64 ip, u64 dat) {}
/** for (const auto& p : _pieces) {
* Appends instruction at the end. u64 piece_start = current_ip;
*/ u64 piece_end = current_ip + p.length;
//void InstrReelDyn::append(u16 bc) {}
// 2. Determine if the requested read window overlaps with this piece
if (ip + bytes_copied < piece_end && (ip + len) > piece_start) {
// Calculate where inside this specific piece our read window begins
u64 read_start_logical = std::max(ip + bytes_copied, piece_start);
u64 local_offset_within_piece = read_start_logical - piece_start;
// Calculate how many remaining bytes can be extracted from this piece
u64 available_in_piece = p.length - local_offset_within_piece;
u64 bytes_to_copy = std::min(len - bytes_copied, available_in_piece);
// 3. Perform safe unaligned copy from our master buffer to the user's destination
const u8* src_ptr = _buffer.data() + p.offset + local_offset_within_piece;
std::memcpy(dat + bytes_copied, src_ptr, bytes_to_copy);
bytes_copied += bytes_to_copy;
// 4. Optimization: Break early if we've completely satisfied the read request
if (bytes_copied == len) {
break;
}
}
current_ip += p.length;
}
}
void InstrReelDyn::write(u64 ip, const u8* dat, const u64 len) {
if (len == 0) return;
// If writing inside existing data, we OVERWRITE by removing the old section first.
// If ip >= _size, it naturally appends, so remove does nothing.
if (ip < _size) {
u64 bytes_to_overwrite = std::min(len, _size - ip);
remove(ip, bytes_to_overwrite);
}
// 1. Capture the exact physical offset BEFORE inserting data or padding
grow(len);
u64 write_offset = _buffer.size();
_buffer.insert(_buffer.end(), dat, dat + len);
// Apply padding immediately so _buffer.size() is always clean for the next run
if (_buffer.size() % _blocksize != 0) {
u64 padding = _blocksize - (_buffer.size() % _blocksize);
_buffer.insert(_buffer.end(), padding, 0);
}
// 2. Orchestrate Pieces (This is strictly an Insertion now because Old Data was removed)
if (_pieces.empty() || ip >= _size) {
_pieces.push_back({ write_offset, len });
_size += len;
return;
}
u64 current_ip = 0;
for (auto it = _pieces.begin(); it != _pieces.end(); ++it) {
if (current_ip + it->length >= ip) {
u64 local_offset = ip - current_ip;
if (local_offset == 0) {
_pieces.insert(it, { write_offset, len });
} else {
// Split the piece cleanly
piece left = { it->offset, local_offset };
piece right = { it->offset + local_offset, it->length - local_offset };
*it = left; // Update existing piece to be the 'left' side
auto next_it = std::next(it);
next_it = _pieces.insert(next_it, { write_offset, len });
_pieces.insert(std::next(next_it), right);
}
break; // Essential: stop processing once the piece is handled!
}
current_ip += it->length;
}
_size += len;
}
void InstrReelDyn::remove(u64 ip, const u64 len) {
if (len == 0 || ip + len > _size) return;
u64 current_ip = 0;
u64 bytes_to_remove = len;
for (auto it = _pieces.begin(); it != _pieces.end() && bytes_to_remove > 0;) {
u64 piece_start = current_ip;
u64 piece_end = current_ip + it->length;
if (ip < piece_end && (ip + bytes_to_remove) > piece_start) {
u64 overlap_start = std::max(ip, piece_start);
u64 overlap_end = std::min(ip + bytes_to_remove, piece_end);
u64 overlap_len = overlap_end - overlap_start;
u64 local_offset = overlap_start - piece_start;
if (local_offset == 0 && overlap_len == it->length) {
it = _pieces.erase(it); // Returns next valid iterator safely
} else if (local_offset == 0) {
it->offset += overlap_len;
it->length -= overlap_len;
++it;
} else if (local_offset + overlap_len == it->length) {
it->length -= overlap_len;
++it;
} else {
// Slice a hole out of the middle
piece right = { it->offset + local_offset + overlap_len, it->length - (local_offset + overlap_len) };
it->length = local_offset;
_pieces.insert(std::next(it), right);
break;
}
bytes_to_remove -= overlap_len;
} else {
current_ip += it->length;
++it;
}
}
_size -= len;
}
void InstrReelDyn::defragment() {
// 1. Edge Case: If the buffer is completely empty, reset states cleanly
if (_size == 0) {
_pieces.clear();
_buffer.clear();
_size = 0;
return;
}
// 2. Optimization: If there is only 1 piece and it's already aligned at physical offset 0,
// then the buffer is already perfectly defragmented. Skip the work entirely.
if (_pieces.size() == 1 && _pieces.front().offset == 0) {
return;
}
// 3. Allocate a fresh, temporary vector aligned perfectly to your 256-byte blocks
std::vector<u8> clean_buffer;
// We use the same rounding formula to ensure clean_buffer matches block boundaries
u64 blocks_needed = (_size + _blocksize - 1) / _blocksize;
clean_buffer.reserve(blocks_needed * _blocksize);
// 4. Linearly stream only the ACTIVE byte chunks into our clean buffer
for (const auto& p : _pieces) {
const u8* src_ptr = _buffer.data() + p.offset;
clean_buffer.insert(clean_buffer.end(), src_ptr, src_ptr + p.length);
}
// 5. Enforce trailing block alignment padding
if (clean_buffer.size() % _blocksize != 0) {
u64 padding = _blocksize - (clean_buffer.size() % _blocksize);
clean_buffer.insert(clean_buffer.end(), padding, 0);
}
// 6. Fast O(1) swap to point your class to the new optimized buffer
_buffer = std::move(clean_buffer);
// 7. Reset piece orchestration to a single monolithic piece mapping 1:1
_pieces.clear();
_pieces.push_back({ 0, _size });
}
void InstrReelDyn::grow(u64 len) {
u64 current_capacity = _buffer.capacity();
// Account for requested bytes PLUS up to a block's worth of trailing alignment padding
u64 minimum_needed = _buffer.size() + len + (_blocksize - 1);
if (minimum_needed > current_capacity) {
// Grow exponentially (1.5x). If empty, seed it with 1 full block minimum.
u64 raw_growth = (current_capacity == 0) ? _blocksize : current_capacity + (current_capacity / 2);
u64 target_capacity = std::max(minimum_needed, raw_growth);
// Round the final target UP to the nearest 256-byte block
u64 blocks = (target_capacity + _blocksize - 1) / _blocksize;
_buffer.reserve(blocks * _blocksize);
}
}
} }
+20 -28
View File
@@ -2,6 +2,8 @@
#include <spider/runtime/reel/InstrReel.hpp> #include <spider/runtime/reel/InstrReel.hpp>
#include <list>
namespace spider { namespace spider {
/** /**
@@ -10,13 +12,14 @@ namespace spider {
class InstrReelDyn : public InstrReel { class InstrReelDyn : public InstrReel {
private: private:
struct ReelBlock { struct piece {
u8 data[256] = {}; u64 offset;
u64 length;
}; };
private: static constexpr u64 _blocksize = 256;
std::vector<u8> _buffer;
deque<ReelBlock> _blocks; std::list<piece> _pieces;
u64 _size; u64 _size;
public: public:
@@ -37,14 +40,6 @@ namespace spider {
InstrReelDyn& operator=(InstrReelDyn&& move) noexcept; 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: public:
/** /**
@@ -53,7 +48,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u8 readU8(u64 ip) override; virtual u8 readU8(u64 ip) const override;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -61,7 +56,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u16 readU16(u64 ip) override; virtual u16 readU16(u64 ip) const override;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -69,7 +64,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u32 readU32(u64 ip) override; virtual u32 readU32(u64 ip) const override;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -77,35 +72,32 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u64 readU64(u64 ip) override; virtual u64 readU64(u64 ip) const override;
/** /**
* Reads a range of data, and * Reads a range of data, and
* outputs it. * outputs it.
*/ */
virtual void readRange(u64 ip, u8* out, u64 length) override; virtual void readRange(u64 ip, u8* out, u64 length) const override;
virtual void loadRegister(u64 ip, u8 size_code, register_t* r) override; virtual void loadRegister(u64 ip, u8 size_code, register_t* r) const override;
/** /**
* Current size of the instructions. * Current size of the instructions.
*/ */
virtual u64 size() override; virtual u64 size() const override;
public: public:
void writeU8(u64 ip, u8 dat); void write(u64 ip, const u8* dat, const u64 len);
void writeU16(u64 ip, u16 dat); void remove(u64 ip, const u64 len);
void writeU32(u64 ip, u32 dat); void defragment();
void writeU64(u64 ip, u64 dat); private:
/** void grow(u64 len);
* Appends instruction at the end.
*/
void append(u16 bc);
}; };
+7 -9
View File
@@ -42,44 +42,42 @@ namespace spider {
delete[] _mem; delete[] _mem;
} }
// General Case(s) //
// Instruction abstraction // // Instruction abstraction //
u8 InstrReelFixed::readU8(u64 ip) { u8 InstrReelFixed::readU8(u64 ip) const {
u8 dat; u8 dat;
spider::loadPartialLE(&dat, _mem + ip, _size); spider::loadPartialLE(&dat, _mem + ip, _size);
return dat; return dat;
} }
u16 InstrReelFixed::readU16(u64 ip) { u16 InstrReelFixed::readU16(u64 ip) const {
u16 dat; u16 dat;
spider::loadPartialLE(&dat, _mem + ip, _size); spider::loadPartialLE(&dat, _mem + ip, _size);
return dat; return dat;
} }
u32 InstrReelFixed::readU32(u64 ip) { u32 InstrReelFixed::readU32(u64 ip) const {
u32 dat; u32 dat;
spider::loadPartialLE(&dat, _mem + ip, _size); spider::loadPartialLE(&dat, _mem + ip, _size);
return dat; return dat;
} }
u64 InstrReelFixed::readU64(u64 ip) { u64 InstrReelFixed::readU64(u64 ip) const {
u64 dat; u64 dat;
spider::loadPartialLE(&dat, _mem + ip, _size); spider::loadPartialLE(&dat, _mem + ip, _size);
return dat; return dat;
} }
void InstrReelFixed::readRange(u64 ip, u8* out, u64 length) { void InstrReelFixed::readRange(u64 ip, u8* out, u64 length) const {
spider::loadPartialBytes(_mem, isize(ip), _size, out, length); spider::loadPartialBytes(_mem, isize(ip), _size, out, length);
} }
void InstrReelFixed::loadRegister(u64 ip, u8 size_code, register_t* r) { void InstrReelFixed::loadRegister(u64 ip, u8 size_code, register_t* r) const {
ip = std::min(ip, _size); ip = std::min(ip, _size);
spider::loadRegister[size_code](r, _mem + ip, _size - ip); spider::loadRegister[size_code](r, _mem + ip, _size - ip);
} }
u64 InstrReelFixed::size() { u64 InstrReelFixed::size() const {
return _size; return _size;
} }
+7 -7
View File
@@ -38,7 +38,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u8 readU8(u64 ip) override; virtual u8 readU8(u64 ip) const override;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -46,7 +46,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u16 readU16(u64 ip) override; virtual u16 readU16(u64 ip) const override;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -54,7 +54,7 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u32 readU32(u64 ip) override; virtual u32 readU32(u64 ip) const override;
/** /**
* Obtains a byte of data at * Obtains a byte of data at
@@ -62,20 +62,20 @@ namespace spider {
* Reindexing may occur, continous access * Reindexing may occur, continous access
* may incurr in less penalties. * may incurr in less penalties.
*/ */
virtual u64 readU64(u64 ip) override; virtual u64 readU64(u64 ip) const override;
/** /**
* Reads a range of data, and * Reads a range of data, and
* outputs it. * outputs it.
*/ */
virtual void readRange(u64 ip, u8* out, u64 length) override; virtual void readRange(u64 ip, u8* out, u64 length) const override;
virtual void loadRegister(u64 ip, u8 size_code, register_t* r) override; virtual void loadRegister(u64 ip, u8 size_code, register_t* r) const override;
/** /**
* Current size of the instructions. * Current size of the instructions.
*/ */
virtual u64 size() override; virtual u64 size() const override;
public: public:
-118
View File
@@ -1,118 +0,0 @@
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_E
#define M_E 2.71828182845904523536
#endif
#include <spider/runtime/cpu/CPU.hpp>
#include <iostream>
#include <cmath>
using namespace spider;
void check(const char* name, double result, double expected, double tolerance = 1e-9) {
bool ok = std::abs(result - expected) <= tolerance;
std::cout << (ok ? "[PASS] " : "[FAIL] ") << name
<< " = " << result
<< " (expected " << expected << ")\n";
}
int main() {
std::cout << "=== Spider VM Instruction Test: 0x068-0x079 ===\n\n";
CPU cpu;
cpu._post = &CPU::imp;
std::cout << "-- Cast Instructions --\n";
cpu.RA._f64 = 3.9;
cpu._dst = &cpu.RA;
cpu.D2I();
check("D2I (3.9 -> 3)", cpu.RA._u32, 3.0);
cpu.RA._f64 = 1e12;
cpu._dst = &cpu.RA;
cpu.D2L();
check("D2L (1e12)", (double)cpu.RA._u64, 1e12);
std::cout << "\n-- Trigonometric Instructions --\n";
cpu.RA._f64 = M_PI / 2.0;
cpu._dst = &cpu.RA;
cpu.SIN();
check("SIN(pi/2)", cpu.RA._f64, 1.0);
cpu.RA._f64 = 0.0;
cpu._dst = &cpu.RA;
cpu.COS();
check("COS(0)", cpu.RA._f64, 1.0);
cpu.RA._f64 = M_PI / 4.0;
cpu._dst = &cpu.RA;
cpu.TAN();
check("TAN(pi/4)", cpu.RA._f64, 1.0);
cpu.RA._f64 = 1.0;
cpu._dst = &cpu.RA;
cpu.ASIN();
check("ASIN(1.0)", cpu.RA._f64, M_PI / 2.0);
cpu.RA._f64 = 1.0;
cpu._dst = &cpu.RA;
cpu.ACOS();
check("ACOS(1.0)", cpu.RA._f64, 0.0);
cpu.RA._f64 = 1.0;
cpu._dst = &cpu.RA;
cpu.ATAN();
check("ATAN(1.0)", cpu.RA._f64, M_PI / 4.0);
cpu.RA._f64 = 1.0;
cpu.RB._f64 = 1.0;
cpu._dst = &cpu.RA;
cpu._src = &cpu.RB;
cpu.ATAN2();
check("ATAN2(1,1)", cpu.RA._f64, M_PI / 4.0);
std::cout << "\n-- Exponential Instructions --\n";
cpu.RA._f64 = 1.0;
cpu._dst = &cpu.RA;
cpu.EXP();
check("EXP(1)", cpu.RA._f64, M_E);
cpu.RA._f64 = M_E;
cpu._dst = &cpu.RA;
cpu.LOG();
check("LOG(e)", cpu.RA._f64, 1.0);
cpu.RA._f64 = 100.0;
cpu.RB._f64 = 10.0;
cpu._dst = &cpu.RA;
cpu._src = &cpu.RB;
cpu.LOGAB();
check("LOGAB(100,10)", cpu.RA._f64, 2.0);
cpu.RA._f64 = 2.0;
cpu.RB._f64 = 10.0;
cpu._dst = &cpu.RA;
cpu._src = &cpu.RB;
cpu.POW();
check("POW(2,10)", cpu.RA._f64, 1024.0);
cpu.RA._f64 = 9.0;
cpu._dst = &cpu.RA;
cpu.SQRT();
check("SQRT(9)", cpu.RA._f64, 3.0);
cpu.RA._f64 = 27.0;
cpu.RB._f64 = 3.0;
cpu._dst = &cpu.RA;
cpu._src = &cpu.RB;
cpu.ROOT();
check("ROOT(27,3)", cpu.RA._f64, 3.0);
std::cout << "\n=== Tests complete ===\n";
return 0;
}