From 9cd0570eddb9ab02aa79bdad11e085b499dea35c Mon Sep 17 00:00:00 2001 From: Joel-Perez Date: Tue, 24 Mar 2026 16:50:07 -0600 Subject: [PATCH] feat: implement Spider VM 0.1 ABI and interrupt system --- calling-convention.ipynb | 189 +++++++++++++++++++++++++++++---------- 1 file changed, 143 insertions(+), 46 deletions(-) diff --git a/calling-convention.ipynb b/calling-convention.ipynb index 7e39d62..c71af20 100644 --- a/calling-convention.ipynb +++ b/calling-convention.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 2, "id": "b9c572cd", "metadata": {}, "outputs": [], @@ -61,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 3, "id": "a1ddd324", "metadata": {}, "outputs": [], @@ -102,87 +102,97 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "02a2ad1a", "metadata": {}, "outputs": [], "source": [ - "# TODO!!!\n", "def do_function_call(input_params: list, output_return: list):\n", " global my_language_name_vm\n", " \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", " 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", " \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", " if ret_size > 16:\n", - " my_language_name_vm['stack'].append(\"RET_PTR_ALLOCATION\")\n", - " \n", - " print(\"--- 2. Allocating Parameters ---\")\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", + " # 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", - " # Register Allocation Phase\n", - " for param in input_params:\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:\n", + " if param['size'] == 1: # Es Booleano \n", " bool_queue.append(param['name'])\n", - " if len(bool_queue) == 8:\n", - " my_language_name_vm['regs'][param_regs[reg_idx]] = \"Packed_Bools\"\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:\n", - " my_language_name_vm['regs'][param_regs[reg_idx]] = param['name']\n", - " reg_idx += 1\n", - " elif param['size'] <= 16 and (len(param_regs) - reg_idx) >= 2:\n", - " my_language_name_vm['regs'][param_regs[reg_idx]] = f\"{param['name']}_P1\"\n", - " my_language_name_vm['regs'][param_regs[reg_idx+1]] = f\"{param['name']}_P2\"\n", - " reg_idx += 2\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", - " # Flush remaining booleans zero-padded\n", - " if len(bool_queue) > 0 and reg_idx < len(param_regs):\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", - " \n", - " # If no more arguments that fit, and we still have registers left, store the stack pointer into the register, and push it\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", - " # Stack Allocation Phase\n", - " bool_queue = []\n", - " large_params = []\n", - " \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:\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", - " large_params.append(param)\n", + " remaining_large.append(param)\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", " \n", - " # Finally, add the large parameters in order\n", - " for param in large_params:\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']}\")" ] }, @@ -203,7 +213,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 5, "id": "d2e4ce44", "metadata": {}, "outputs": [], @@ -294,7 +304,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 6, "id": "b58fbf72", "metadata": {}, "outputs": [ @@ -306,7 +316,7 @@ "--- 2. Allocating Parameters ---\n", "\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", "\n", "========================================\n", @@ -323,7 +333,7 @@ "Restored R0 <- 0\n", "\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" ] } @@ -356,7 +366,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 7, "id": "d225a397", "metadata": {}, "outputs": [], @@ -383,7 +393,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 8, "id": "70347484", "metadata": {}, "outputs": [ @@ -452,7 +462,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 9, "id": "0c46e3f2", "metadata": {}, "outputs": [ @@ -535,6 +545,93 @@ "\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": {