removed unnecessary things, updated and audited the code

This commit is contained in:
2026-06-13 11:31:07 -06:00
parent 29797fb707
commit a36705a931
13 changed files with 529 additions and 1718 deletions
+8
View File
@@ -58,6 +58,10 @@ constexpr u8 ADDR_MODE_MASKS[][2] = {
{ 0x1E, 0xFF }, // GE
{ 0x1E, 0xFF }, // LT
{ 0x1E, 0xFF }, // LE
{ 0x1E, 0xFF }, // GTU
{ 0x1E, 0xFF }, // GEU
{ 0x1E, 0xFF }, // LTU
{ 0x1E, 0xFF }, // LEU
{ 0xFF, 0x00 }, // JMP
{ 0xFF, 0x00 }, // JEQ
{ 0xFF, 0x00 }, // JNE
@@ -190,6 +194,10 @@ constexpr u8 TYPE_SIZE_MASKS[] = {
0x0F, // GE
0x0F, // LT
0x0F, // LE
0x0F, // GTU
0x0F, // GEU
0x0F, // LTU
0x0F, // LEU
0x0F, // JMP
0x0F, // JEQ
0x0F, // JNE
-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.
+15 -15
View File
@@ -144,7 +144,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 3,
"id": "58645013",
"metadata": {},
"outputs": [
@@ -152,16 +152,16 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Real instructions : 128\n",
"Reserved slots : 14\n",
"Real instructions : 132\n",
"Reserved slots : 10\n",
"Duplicate check : PASSED\n",
"\n",
"Groups found:\n",
"group\n",
"Integer 19\n",
"Boolean 16\n",
"System 15\n",
"Bit Wise 14\n",
"Boolean 12\n",
"Branch 12\n",
"Floating Point 10\n",
"Casts 10\n",
@@ -283,7 +283,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 4,
"id": "452bc76c",
"metadata": {},
"outputs": [
@@ -292,7 +292,7 @@
"output_type": "stream",
"text": [
"Masks written to: .//autogen/InstructionMasks.hpp\n",
"Lines generated : 272\n"
"Lines generated : 280\n"
]
}
],
@@ -357,7 +357,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 5,
"id": "5aaebef0",
"metadata": {},
"outputs": [
@@ -365,7 +365,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Instructions formatted: 128\n",
"Instructions formatted: 132\n",
"\n",
"--- Preview (first 2 instructions) ---\n",
" // [System] 0x000 — NOP: No Operation\n",
@@ -380,7 +380,7 @@
"\n",
"\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: 911\n"
]
}
],
@@ -451,7 +451,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 8,
"id": "instrmap_gen",
"metadata": {},
"outputs": [
@@ -460,9 +460,9 @@
"output_type": "stream",
"text": [
"InstrMap.cpp written to: .//src//spider/runtime/instr/InstrMap.cpp\n",
" Size : 34,157 bytes\n",
" Array entries : 512 (128 populated, 384 nullptr)\n",
" Switch cases : 128\n",
" Size : 33,581 bytes\n",
" Array entries : 512 (132 populated, 380 nullptr)\n",
" Switch cases : 132\n",
" Line endings : LF-only verified\n"
]
}
@@ -545,7 +545,7 @@
" mnem = opcode_to_mnem.get(opc)\n",
" if mnem:\n",
" name = opcode_to_name[opc]\n",
" L.append(f' &CPU::{mnem + \",\":<28s}// 0x{opc:03X} — {name}')\n",
" L.append(f' &CPU::{mnem + \",\":<22s}// 0x{opc:03X} — {name}')\n",
" else:\n",
" tag = ''\n",
" if opc in reserved_opcodes:\n",
@@ -681,7 +681,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.3"
"version": "3.13.7"
}
},
"nbformat": 4,
+1 -9
View File
@@ -1,18 +1,10 @@
#include "SpiderRuntime.hpp"
#include <spider/runtime/debug/LiveDebug.hpp>
#include <iostream>
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";
}
int main() {
spider::liveDebugMain();
return 0;
}
+20 -12
View File
@@ -76,8 +76,8 @@ namespace spider {
void CPU::fetchOperDst() {
// Move the operand ptrs
_alu = &ALU0;
_opers[1] = _opers[0];
_opers[0] = &ALU0;
// call specific addressing mode
(this->*(CPU::addrModes[_addrm & 0b111]))(); // mask added here too
@@ -85,7 +85,7 @@ namespace spider {
void CPU::fetchOperSrc() {
// set ALU
_alu = &ALU1;
_opers[0] = &ALU1;
// call specific addressing mode
(this->*(CPU::addrModes[_addrm & 0b111]))(); // mask keeps index within 0-7
@@ -95,13 +95,23 @@ namespace spider {
_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() {
(this->*(CPU::instrMap[_opcode]))(); // no null check needed
// vvv MUST PROFILE: Is this faster than executing an empty function?
if(_post) (this->*_post)();
}
// Addressing Modes //
/**
@@ -115,8 +125,7 @@ namespace spider {
* Immediate Addressing Mode
*/
void CPU::imm() {
_reel->loadRegister(RI, _size, _alu);
_opers[0] = _alu;
_reel->loadRegister(RI, _size, _opers[0]);
_post = &CPU::imp;
RI += 1 << _size;
}
@@ -127,19 +136,19 @@ namespace spider {
void CPU::abs() {
// Load the actual ptr into the ALU
u8 mm = u8(getFlag(CPU::FLAG_MEMORY_MODE));
_reel->loadRegister(RI, mm, _alu);
_reel->loadRegister(RI, mm, _opers[0]);
RI += 1 << mm;
// read the memory from RAM
_store = _alu->_u64;
_ram->loadRegister(_store, _size, _alu);
_store = _opers[0]->_u64;
_ram->loadRegister(_store, _size, _opers[0]);
_post = &CPU::psw;
}
/**
* Register Addressing Mode
*/
void CPU::reg() { // NOT FINISHED
void CPU::reg() {
// Two consecutive registers can be declared
// Shift if the top part will become .reg too
u8 sh = ((_addrm & 0b11000) == 0b11000) * 4;
@@ -147,12 +156,11 @@ namespace spider {
// get byte
u8 reg = (_reel->readU8(RI) >> sh) & 0xF;
_alu = &GPR[reg];
_opers[0] = _alu; // explicitly sets _opers[0] = _dst
_opers[0] = &GPR[reg]; // explicitly sets _opers[0] = _dst
RI += use;
// store no-op
_post = &CPU::imp;
_post = nullptr;
}
/**
+38 -23
View File
@@ -64,7 +64,6 @@ namespace spider {
struct {
register_t* _dst;
register_t* _src;
register_t* _alu;
};
register_t* _opers[2];
};
@@ -172,6 +171,18 @@ namespace spider {
*/
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
* accessing the instruction map and
@@ -469,36 +480,56 @@ namespace spider {
// Operation: # of 1's into Dst
void CNT();
// [Boolean] 0x030 — EQ: Equal
// [Boolean] 0x02E — EQ: Equal
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst == Src into Dst
void EQ();
// [Boolean] 0x031 — NE: Not Equal
// [Boolean] 0x02F — NE: Not Equal
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst != Src into Dst
void NE();
// [Boolean] 0x032 — GT: Greater Than
// [Boolean] 0x030 — GT: Greater Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst > Src into Dst
void GT();
// [Boolean] 0x033 — GE: Greater or Equal Than
// [Boolean] 0x031 — GE: Greater or Equal Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst >= Src into Dst
void GE();
// [Boolean] 0x034 — LT: Lower Than
// [Boolean] 0x032 — LT: Lower Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst < Src into Dst
void LT();
// [Boolean] 0x035 — LE: Lower or Equal Than
// [Boolean] 0x033 — LE: Lower or Equal Than
// Params: 2 | AddrMask1: 1E AddrMask2: FF | TypeMask: 0F
// Operation: Dst <= Src into Dst
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
// Params: 1 | AddrMask1: FF AddrMask2: 00 | TypeMask: 0F
// Operation: Dst -> Instruction Register
@@ -884,22 +915,6 @@ namespace spider {
// Operation:
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] 0x0F6 — DGANT: "In kaaba Spider" (Yucatec Maya: My name is Spider)
// Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
// Operation: Writes "IN KAABA SPIDER" one char per GP register
void DGANT();
/**
* @brief BRAD (0xF7) - Memory Integrity Checksum
* Escanea los primeros 256 bytes de memoria y valida contra una firma de seguridad.
* Implementado por Bradley Vergara Lara - Estancia 2026.
*/
void BRAD();
// </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();
}
+22 -20
View File
@@ -81,16 +81,16 @@ CPU::Fn CPU::instrMap[] = {
&CPU::ROL, // 0x02B — Rotate Left
&CPU::ROR, // 0x02C — Rotate Right
&CPU::CNT, // 0x02D — Counts bits
nullptr, // 0x02E (reserved)
nullptr, // 0x02F (reserved)
&CPU::EQ, // 0x030 — Equal
&CPU::NE, // 0x031 — Not Equal
&CPU::GT, // 0x032 — Greater Than
&CPU::GE, // 0x033 — Greater or Equal Than
&CPU::LT, // 0x034 — Lower Than
&CPU::LE, // 0x035 — Lower or Equal Than
nullptr, // 0x036 (reserved)
nullptr, // 0x037 (reserved)
&CPU::EQ, // 0x02E — Equal
&CPU::NE, // 0x02F — Not Equal
&CPU::GT, // 0x030 — Greater Than
&CPU::GE, // 0x031 — Greater or Equal Than
&CPU::LT, // 0x032 — Lower Than
&CPU::LE, // 0x033 — Lower or Equal Than
&CPU::GTU, // 0x034 — Greater Than, Unsigned
&CPU::GEU, // 0x035 — Greater or Equal Than, Unsigned
&CPU::LTU, // 0x036 — Lower Than, Unsigned
&CPU::LEU, // 0x037 — Lower or Equal Than, Unsigned
&CPU::JMP, // 0x038 — Jump to absolute position
&CPU::JEQ, // 0x039 — Jumps to position if EQ flag is set
&CPU::JNE, // 0x03A — Jumps to position if EQ flag is cleared
@@ -276,12 +276,12 @@ CPU::Fn CPU::instrMap[] = {
nullptr, // 0x0EE
nullptr, // 0x0EF
&CPU::UPY, // 0x0F0 — Will place "YUPI" in memory
&CPU::LLGS, // 0x0F1 — Spider ASCII art (LLGS easter egg)
nullptr, // 0x0F1
nullptr, // 0x0F2
nullptr, // 0x0F3
nullptr, // 0x0F4
nullptr, // 0x0F5
&CPU::DGANT, // 0x0F6
nullptr, // 0x0F6
nullptr, // 0x0F7
nullptr, // 0x0F8
nullptr, // 0x0F9
@@ -622,12 +622,16 @@ void CPU::executeSwLk() {
case 0x02D: CNT(); break;
// ── Boolean ─────────────────────────────────────
case 0x030: EQ(); break;
case 0x031: NE(); break;
case 0x032: GT(); break;
case 0x033: GE(); break;
case 0x034: LT(); break;
case 0x035: LE(); break;
case 0x02E: EQ(); break;
case 0x02F: NE(); break;
case 0x030: GT(); break;
case 0x031: GE(); break;
case 0x032: LT(); break;
case 0x033: LE(); break;
case 0x034: GTU(); break;
case 0x035: GEU(); break;
case 0x036: LTU(); break;
case 0x037: LEU(); break;
// ── Branch ──────────────────────────────────────
case 0x038: JMP(); break;
@@ -737,8 +741,6 @@ void CPU::executeSwLk() {
// ── Easter Eggs ─────────────────────────────────
case 0x0F0: UPY(); break;
case 0x0F1: LLGS(); break;
default:
break;
+56 -24
View File
@@ -4,15 +4,16 @@
*/
#include <spider/runtime/cpu/CPU.hpp>
#include <spider/runtime/memory/RAM.hpp>
namespace spider {
void CPU::NOP() {
// TODO: Implement NOP
// DONE ! //
}
void CPU::SPDR() {
// TODO: Implement SPDR
RA._u64 = spider::RUNTIME_VERSION_NO;
}
void CPU::MMODE() {
@@ -21,10 +22,13 @@ namespace spider {
void CPU::INT() {
// TODO: Implement INT
// We need to implement an interrupt
// table and interrupt system!
}
void CPU::LRV() {
// TODO: Implement LRV
fetchOperReg();
RV = _dst->_u64;
}
void CPU::FSR() {
@@ -32,11 +36,13 @@ namespace spider {
}
void CPU::FIR() {
// TODO: Implement FIR
fetchOperReg();
_dst->_u64 = RI;
}
void CPU::FZR() {
// TODO: Implement FZR
fetchOperReg();
_dst->_u64 = RZ;
}
void CPU::LSR() {
@@ -44,23 +50,63 @@ namespace spider {
}
void CPU::FVR() {
// TODO: Implement FVR
fetchOperReg();
_dst->_u64 = RV;
}
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() {
// TODO: Implement MOR
fetchOperRegReg();
*_dst = *_src;
}
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() {
// TODO: Implement SWP
// get registers in _dst and _src
fetchOperRegReg();
ALU0 = *_dst;
*_dst = *_src;
*_src = ALU0;
}
void CPU::AHM() {
@@ -86,7 +132,6 @@ namespace spider {
}
void CPU::NEG() {
// TODO: Implement NEG
fetchOperDst();
switch (_size) {
case 0b00: //byte
@@ -123,7 +168,6 @@ namespace spider {
}
void CPU::INC() {
// TODO: Implement INC
fetchOperDst();
switch (_size) {
case 0b00: //byte
@@ -142,7 +186,6 @@ namespace spider {
}
void CPU::DEC() {
// TODO: Implement DEC
fetchOperDst();
switch (_size) {
case 0b00: //byte
@@ -161,7 +204,6 @@ namespace spider {
}
void CPU::ADD() {
// TODO: Implement ADD
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -181,7 +223,6 @@ namespace spider {
}
void CPU::SUB() {
// TODO: Implement SUB
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -201,7 +242,6 @@ namespace spider {
}
void CPU::MUL() {
// TODO: Implement MUL
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -221,7 +261,6 @@ namespace spider {
}
void CPU::UMUL() {
// TODO: Implement UMUL
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -241,7 +280,6 @@ namespace spider {
}
void CPU::DIV() {
// TODO: Implement DIV
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -261,7 +299,6 @@ namespace spider {
}
void CPU::UDIV() {
// TODO: Implement UDIV
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -281,7 +318,6 @@ namespace spider {
}
void CPU::MOD() {
// TODO: Implement MOD
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -301,7 +337,6 @@ namespace spider {
}
void CPU::UMOD() {
// TODO: Implement UMOD
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -321,7 +356,6 @@ namespace spider {
}
void CPU::DMOD() {
// TODO: Implement DMOD
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -345,7 +379,6 @@ namespace spider {
}
void CPU::UDMD() {
// TODO: Implement UDMD
fetchOperSrc();
fetchOperDst();
switch (_size) {
@@ -369,7 +402,6 @@ namespace spider {
}
void CPU::FBT() {
// TODO: Implement FBT
fetchOperDst();
switch (_size) {
case 0b00: //byte
-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
-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;
}