feat: implement Spider VM 0.1 ABI and interrupt system
This commit is contained in:
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user