feat: implement Spider VM 0.1 ABI and interrupt system

This commit is contained in:
Joel-Perez
2026-03-24 16:50:07 -06:00
parent 057ed48df1
commit 9cd0570edd

View File

@@ -11,7 +11,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 2,
"id": "b9c572cd", "id": "b9c572cd",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -61,7 +61,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 3,
"id": "a1ddd324", "id": "a1ddd324",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -102,87 +102,97 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": null,
"id": "02a2ad1a", "id": "02a2ad1a",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"# TODO!!!\n",
"def do_function_call(input_params: list, output_return: list):\n", "def do_function_call(input_params: list, output_return: list):\n",
" global my_language_name_vm\n", " global my_language_name_vm\n",
" \n", " \n",
" print(\"--- 1. Saving Caller State ---\")\n", " print(\"--- 1. Saving Caller State ---\")\n",
" # Push caller saved registers (R0, R1, R2, R3)\n", " # Paso 1: Respaldar registros salvados por el llamador (R0-R3) \n",
" caller_saved = ['R0', 'R1', 'R2', 'R3']\n", " caller_saved = ['R0', 'R1', 'R2', 'R3']\n",
" for reg in caller_saved:\n", " for reg in caller_saved:\n",
" # Guardamos el valor actual del registro\n",
" my_language_name_vm['stack'].append(my_language_name_vm['regs'][reg])\n", " my_language_name_vm['stack'].append(my_language_name_vm['regs'][reg])\n",
" \n", " \n",
" # If the return value is larger than 16 bytes, create space for on the caller's frame\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", " ret_size = sum(r['size'] for r in output_return)\n",
" if ret_size > 16:\n", " if ret_size > 16:\n",
" my_language_name_vm['stack'].append(\"RET_PTR_ALLOCATION\")\n", " # Se inserta al frente para que ocupe RA (o el primer espacio disponible) \n",
" \n", " actual_params.insert(0, {'name': 'RET_PTR_ALLOCATION', 'size': 8}) \n",
" print(\"--- 2. Allocating Parameters ---\")\n", "\n",
" # Registers RA RB RC RD R8 and R9 can be used to pass parameters\n", " param_regs = ['RA', 'RB', 'RC', 'RD', 'R8', 'R9'] # \n",
" param_regs = ['RA', 'RB', 'RC', 'RD', 'R8', 'R9']\n",
" reg_idx = 0\n", " reg_idx = 0\n",
" bool_queue = []\n", " bool_queue = []\n",
" stack_params = []\n", " stack_params = []\n",
" \n", " \n",
" # Register Allocation Phase\n", " # --- FASE 1: ASIGNACIÓN A REGISTROS ---\n",
" for param in input_params:\n", " for param in actual_params:\n",
" if reg_idx < len(param_regs):\n", " if reg_idx < len(param_regs):\n",
" if param['size'] == 1:\n", " if param['size'] == 1: # Es Booleano \n",
" bool_queue.append(param['name'])\n", " bool_queue.append(param['name'])\n",
" if len(bool_queue) == 8:\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]] = \"Packed_Bools\"\n", " my_language_name_vm['regs'][param_regs[reg_idx]] = f\"Packed_Bools({','.join(bool_queue)})\"\n",
" reg_idx += 1\n", " reg_idx += 1\n",
" bool_queue = []\n", " bool_queue = []\n",
" elif param['size'] <= 8:\n", " elif param['size'] <= 8: # Parámetro estándar\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = param['name']\n", " # Antes de asignar un no-booleano, si hay booleanos pendientes, se deben flashear \n",
" reg_idx += 1\n", " if bool_queue:\n",
" elif param['size'] <= 16 and (len(param_regs) - reg_idx) >= 2:\n", " my_language_name_vm['regs'][param_regs[reg_idx]] = f\"Padded_Bools({len(bool_queue)})\"\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = f\"{param['name']}_P1\"\n", " reg_idx += 1\n",
" my_language_name_vm['regs'][param_regs[reg_idx+1]] = f\"{param['name']}_P2\"\n", " bool_queue = []\n",
" reg_idx += 2\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", " else:\n",
" # Si es muy grande para un registro (>8), va a la pila después \n",
" stack_params.append(param)\n", " stack_params.append(param)\n",
" else:\n", " else:\n",
" stack_params.append(param)\n", " stack_params.append(param)\n",
" \n", "\n",
" # Flush remaining booleans zero-padded\n", " # Flashear booleanos restantes si queda espacio en registros \n",
" if len(bool_queue) > 0 and reg_idx < len(param_regs):\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", " my_language_name_vm['regs'][param_regs[reg_idx]] = f\"Padded_Bools({len(bool_queue)})\"\n",
" reg_idx += 1\n", " reg_idx += 1\n",
" bool_queue = []\n", " bool_queue = []\n",
" \n", " elif bool_queue:\n",
" # If no more arguments that fit, and we still have registers left, store the stack pointer into the register, and push it\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", " while reg_idx < len(param_regs):\n",
" my_language_name_vm['regs'][param_regs[reg_idx]] = \"SP_Backup\"\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", " my_language_name_vm['stack'].append(f\"SP_for_{param_regs[reg_idx]}\")\n",
" reg_idx += 1\n", " reg_idx += 1\n",
" \n", "\n",
" # Stack Allocation Phase\n", " # --- FASE 2: ASIGNACIÓN A PILA ---\n",
" bool_queue = []\n", " # 1. Parámetros <= 8 bytes (no booleanos)\n",
" large_params = []\n", " remaining_large = []\n",
" \n",
" for param in stack_params:\n", " for param in stack_params:\n",
" if param['size'] == 1:\n", " if param['size'] == 1:\n",
" bool_queue.append(param['name'])\n", " bool_queue.append(param['name'])\n",
" if len(bool_queue) == 8:\n", " if len(bool_queue) == 8: # Formó un \"byte\" (o bloque) \n",
" my_language_name_vm['stack'].append(\"Packed_Bools_Stack\")\n", " my_language_name_vm['stack'].append(\"Packed_Bools_Stack\")\n",
" bool_queue = []\n", " bool_queue = []\n",
" elif param['size'] <= 8:\n", " elif param['size'] <= 8:\n",
" my_language_name_vm['stack'].append(param['name'])\n", " my_language_name_vm['stack'].append(param['name'])\n",
" else:\n", " else:\n",
" large_params.append(param)\n", " remaining_large.append(param)\n",
" \n", " \n",
" if len(bool_queue) > 0:\n", " # Flashear booleanos de la pila con padding \n",
" if bool_queue:\n",
" my_language_name_vm['stack'].append(\"Padded_Bools_Stack\")\n", " my_language_name_vm['stack'].append(\"Padded_Bools_Stack\")\n",
" \n", " \n",
" # Finally, add the large parameters in order\n", " # 2. Finalmente parámetros grandes en orden \n",
" for param in large_params:\n", " for param in remaining_large:\n",
" my_language_name_vm['stack'].append(f\"LARGE_{param['name']}\")" " my_language_name_vm['stack'].append(f\"LARGE_{param['name']}\")"
] ]
}, },
@@ -203,7 +213,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 5,
"id": "d2e4ce44", "id": "d2e4ce44",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -294,7 +304,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 21, "execution_count": 6,
"id": "b58fbf72", "id": "b58fbf72",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -306,7 +316,7 @@
"--- 2. Allocating Parameters ---\n", "--- 2. Allocating Parameters ---\n",
"\n", "\n",
"[STATE AFTER CALL]\n", "[STATE AFTER CALL]\n",
"Registers: {'RA': 'int_a', 'RB': 'double_b', 'RC': 'Padded_Bools(2)', 'RD': 'SP_Backup', 'R8': 'SP_Backup', 'R9': 'SP_Backup'}\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", "Stack: [0, 0, 0, 0, 'SP_for_RD', 'SP_for_R8', 'SP_for_R9', 'LARGE_big_struct']\n",
"\n", "\n",
"========================================\n", "========================================\n",
@@ -323,7 +333,7 @@
"Restored R0 <- 0\n", "Restored R0 <- 0\n",
"\n", "\n",
"[STATE AFTER RETURN]\n", "[STATE AFTER RETURN]\n",
"Registers: {'RA': 'int_a', 'RB': 'double_b', 'RC': 'Padded_Bools(2)', 'RD': 'SP_Backup', 'R8': 'SP_Backup', 'R9': 'SP_Backup'}\n", "Registers: {'RA': 'int_a', 'RB': 'Padded_Bools(2)', 'RC': 'double_b', 'RD': 'SP_Backup', 'R8': 'SP_Backup', 'R9': 'SP_Backup'}\n",
"Stack: []\n" "Stack: []\n"
] ]
} }
@@ -356,7 +366,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 22, "execution_count": 7,
"id": "d225a397", "id": "d225a397",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@@ -383,7 +393,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 24, "execution_count": 8,
"id": "70347484", "id": "70347484",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -452,7 +462,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 25, "execution_count": 9,
"id": "0c46e3f2", "id": "0c46e3f2",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@@ -535,6 +545,93 @@
"\n", "\n",
"print(\"\\nFinal Stack (Should be empty):\", my_language_name_vm['stack'])" "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": { "metadata": {