Intento de mejora para multiples ramas

This commit is contained in:
Miguel 2025-04-18 16:33:36 +02:00
parent 94163baee0
commit 3787411cf5
1 changed files with 103 additions and 113 deletions

View File

@ -3,10 +3,14 @@ import json
import os import os
import copy import copy
import traceback import traceback
import re # Import regex for PBox SCL parsing if needed later
# --- Constantes y Configuración --- # --- Constantes y Configuración ---
SCL_SUFFIX = "_scl" SCL_SUFFIX = "_scl"
# Global data variable to be accessible by processors needing network context
data = {}
# --- Helper Functions --- # --- Helper Functions ---
def get_scl_representation(source_info, network_id, scl_map, access_map): def get_scl_representation(source_info, network_id, scl_map, access_map):
@ -126,19 +130,18 @@ def process_contact(instruction, network_id, scl_map, access_map):
instr_type = instruction['type'] instr_type = instruction['type']
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
is_negated = False # TODO: Determinar si es negado is_negated = False # TODO: Determinar si es negado (ej. por 'Name')
# print(f"DEBUG: Intentando procesar CONTACT{' (N)' if is_negated else ''} - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar CONTACT{' (N)' if is_negated else ''} - UID: {instr_uid} en Red: {network_id}")
# --- INICIO CORRECCIÓN --- # --- CORRECCIÓN: Manejar 'in' implícito ---
in_input = instruction['inputs'].get('in') in_input = instruction['inputs'].get('in')
in_rlo_scl = None in_rlo_scl = None
if in_input is None: if in_input is None:
# Si no hay pin 'in' conectado explícitamente, asumir TRUE (conectado a powerrail/riel vertical) # Si no hay pin 'in' conectado explícitamente, asumir TRUE
# print(f"DEBUG: Asumiendo IN=TRUE para CONTACT UID {instr_uid} (pin 'in' no conectado)") # print(f"DEBUG: Asumiendo IN=TRUE para CONTACT UID {instr_uid} (pin 'in' no conectado)")
in_rlo_scl = "TRUE" in_rlo_scl = "TRUE"
else: else:
# Si hay pin 'in', intentar resolverlo
in_rlo_scl = get_scl_representation(in_input, network_id, scl_map, access_map) in_rlo_scl = get_scl_representation(in_input, network_id, scl_map, access_map)
# --- FIN CORRECCIÓN --- # --- FIN CORRECCIÓN ---
@ -148,17 +151,18 @@ def process_contact(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Dependencia no resuelta para CONTACT UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})") # print(f"DEBUG: Dependencia no resuelta para CONTACT UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})")
return False return False
# ... (resto de process_contact sin cambios: construir RLO, actualizar scl_map y JSON, retornar True) ...
term = f"NOT {operand_scl}" if is_negated else operand_scl term = f"NOT {operand_scl}" if is_negated else operand_scl
# Envolver término en paréntesis si es necesario
if not (term.startswith('"') and term.endswith('"')): if not (term.startswith('"') and term.endswith('"')):
if not (term.startswith('(') and term.endswith(')')): if ' ' in term and not (term.startswith('(') and term.endswith(')')):
term = f"({term})" term = f"({term})"
new_rlo_scl = "" new_rlo_scl = ""
if in_rlo_scl == "TRUE": if in_rlo_scl == "TRUE":
new_rlo_scl = term new_rlo_scl = term
else: else:
if not (in_rlo_scl.startswith('(') and in_rlo_scl.endswith(')')) and 'AND' in in_rlo_scl or 'OR' in in_rlo_scl: # Envolver RLO anterior en paréntesis si es necesario
if ('AND' in in_rlo_scl or 'OR' in in_rlo_scl) and not (in_rlo_scl.startswith('(') and in_rlo_scl.endswith(')')):
in_rlo_processed = f"({in_rlo_scl})" in_rlo_processed = f"({in_rlo_scl})"
else: else:
in_rlo_processed = in_rlo_scl in_rlo_processed = in_rlo_scl
@ -186,23 +190,25 @@ def process_eq(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Dependencia no resuelta para EQ UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})") # print(f"DEBUG: Dependencia no resuelta para EQ UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})")
return False return False
# Poner operandos entre paréntesis si son complejos
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
comparison_scl = f"{op1} = {op2}" # SCL usa '=' para comparación comparison_scl = f"{op1} = {op2}"
map_key_out = (network_id, instr_uid, 'out') map_key_out = (network_id, instr_uid, 'out')
scl_map[map_key_out] = comparison_scl scl_map[map_key_out] = comparison_scl
# --- Manejo de ENO --- # --- Manejo de ENO (CORREGIDO) ---
# El 'pre' en LAD para comparación a menudo actúa como el EN. pre_input = instruction['inputs'].get('pre')
pre_scl = get_scl_representation(instruction['inputs'].get('pre'), network_id, scl_map, access_map) # Asumir TRUE si 'pre' no está conectado explícitamente
# Si 'pre' no está conectado, asumimos TRUE. pre_scl = "TRUE" if pre_input is None else get_scl_representation(pre_input, network_id, scl_map, access_map)
effective_en_scl = "TRUE" if pre_scl is None else pre_scl
# El estado ENO de una comparación es TRUE si se ejecuta (EN=TRUE) y FALSE si no. if pre_scl is None: # Si está conectado pero no resuelto
# print(f"DEBUG: Dependencia PRE no resuelta para EQ UID {instr_uid}")
return False # No se puede determinar ENO si PRE no está listo
# El estado ENO de una comparación es TRUE si se ejecuta (EN/PRE=TRUE) y FALSE si no.
map_key_eno = (network_id, instr_uid, 'eno') map_key_eno = (network_id, instr_uid, 'eno')
scl_map[map_key_eno] = effective_en_scl scl_map[map_key_eno] = pre_scl # ENO sigue a la habilitación PRE
# print(f"DEBUG: EQ UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {effective_en_scl}")
# --- Fin Manejo de ENO --- # --- Fin Manejo de ENO ---
instruction['scl'] = f"// Comparison Eq {instr_uid}: {comparison_scl}" instruction['scl'] = f"// Comparison Eq {instr_uid}: {comparison_scl}"
@ -218,19 +224,24 @@ def process_coil(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Intentando procesar COIL - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar COIL - UID: {instr_uid} en Red: {network_id}")
in_rlo_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map) in_rlo_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
operand_scl = get_scl_representation(instruction['inputs'].get('operand'), network_id, scl_map, access_map) operand_info = instruction['inputs'].get('operand') # Obtener info completa del operando
operand_scl = get_scl_representation(operand_info, network_id, scl_map, access_map)
if in_rlo_scl is None or operand_scl is None: if in_rlo_scl is None or operand_scl is None:
# print(f"DEBUG: Dependencia no resuelta para COIL UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})") # print(f"DEBUG: Dependencia no resuelta para COIL UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})")
return False return False
operand_info = instruction['inputs'].get('operand')
if not (operand_info and operand_info.get('type') == 'variable'): if not (operand_info and operand_info.get('type') == 'variable'):
print(f"Error: Operando de COIL UID {instr_uid} no es una variable: {operand_info}") print(f"Error: Operando de COIL UID {instr_uid} no es una variable: {operand_info}")
instruction['scl'] = f"// ERROR: Coil {instr_uid} operando no es variable" instruction['scl'] = f"// ERROR: Coil {instr_uid} operando no es variable"
instruction['type'] = instr_type + "_error" instruction['type'] = instr_type + "_error"
return True return True
# Simplificar RLO si es posible antes de asignar
if in_rlo_scl == "(TRUE)": in_rlo_scl = "TRUE"
elif in_rlo_scl == "(FALSE)": in_rlo_scl = "FALSE"
scl_final = f"{operand_scl} := {in_rlo_scl};" scl_final = f"{operand_scl} := {in_rlo_scl};"
instruction['scl'] = scl_final instruction['scl'] = scl_final
@ -247,7 +258,7 @@ def process_convert(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Intentando procesar CONVERT - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar CONVERT - UID: {instr_uid} en Red: {network_id}")
# --- Manejo de EN --- # --- CORRECCIÓN: Manejo de EN ---
en_input = instruction['inputs'].get('en') en_input = instruction['inputs'].get('en')
en_scl = None en_scl = None
if en_input is None: if en_input is None:
@ -255,12 +266,16 @@ def process_convert(instruction, network_id, scl_map, access_map):
en_scl = "TRUE" en_scl = "TRUE"
else: else:
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
# --- Fin Manejo de EN ---
if en_scl is None: # Bloquear si EN está conectado pero no resuelto
# print(f"DEBUG: Dependencia EN no resuelta para CONVERT UID: {instr_uid}")
return False
# --- FIN CORRECCIÓN ---
in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map) in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
if en_scl is None or in_scl is None: if in_scl is None:
# print(f"DEBUG: Dependencia no resuelta para CONVERT UID: {instr_uid} (en={en_scl}, in={in_scl})") # print(f"DEBUG: Dependencia IN no resuelta para CONVERT UID: {instr_uid}")
return False return False
target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True) target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True)
@ -271,14 +286,14 @@ def process_convert(instruction, network_id, scl_map, access_map):
return True return True
conversion_expr = in_scl # Asume conversión implícita por ahora conversion_expr = in_scl # Asume conversión implícita por ahora
# TODO: Añadir lógica de conversión explícita si se extraen tipos de TemplateValue
scl_core = f"{target_scl} := {conversion_expr};" scl_core = f"{target_scl} := {conversion_expr};"
# --- CORRECCIÓN: Generación de IF ---
if en_scl != "TRUE": if en_scl != "TRUE":
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
else: else:
# Si en_scl ES "TRUE", no se necesita IF
scl_final = scl_core scl_final = scl_core
# --- FIN CORRECCIÓN ---
instruction['scl'] = scl_final instruction['scl'] = scl_final
instruction['type'] = instr_type + SCL_SUFFIX instruction['type'] = instr_type + SCL_SUFFIX
@ -286,9 +301,10 @@ def process_convert(instruction, network_id, scl_map, access_map):
map_key_out = (network_id, instr_uid, 'out') map_key_out = (network_id, instr_uid, 'out')
scl_map[map_key_out] = target_scl scl_map[map_key_out] = target_scl
# --- CORRECCIÓN: Añadir ENO a scl_map ---
map_key_eno = (network_id, instr_uid, 'eno') map_key_eno = (network_id, instr_uid, 'eno')
scl_map[map_key_eno] = en_scl # ENO sigue a EN scl_map[map_key_eno] = en_scl # ENO sigue a EN
# print(f"DEBUG: CONVERT UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}") # --- FIN CORRECCIÓN ---
# print(f"INFO: CONVERT UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") # print(f"INFO: CONVERT UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
return True return True
@ -301,7 +317,7 @@ def process_mod(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Intentando procesar MOD - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar MOD - UID: {instr_uid} en Red: {network_id}")
# --- Manejo de EN --- # --- CORRECCIÓN: Manejo de EN ---
en_input = instruction['inputs'].get('en') en_input = instruction['inputs'].get('en')
en_scl = None en_scl = None
if en_input is None: if en_input is None:
@ -309,13 +325,17 @@ def process_mod(instruction, network_id, scl_map, access_map):
en_scl = "TRUE" en_scl = "TRUE"
else: else:
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
# --- Fin Manejo de EN ---
if en_scl is None: # Bloquear si EN está conectado pero no resuelto
# print(f"DEBUG: Dependencia EN no resuelta para MOD UID: {instr_uid}")
return False
# --- FIN CORRECCIÓN ---
in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map) in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map)
in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map) in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map)
if en_scl is None or in1_scl is None or in2_scl is None: if in1_scl is None or in2_scl is None:
# print(f"DEBUG: Dependencia no resuelta para MOD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})") # print(f"DEBUG: Dependencia no resuelta para MOD UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})")
return False return False
target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True) target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True)
@ -328,11 +348,12 @@ def process_mod(instruction, network_id, scl_map, access_map):
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
scl_core = f"{target_scl} := {op1} MOD {op2};" scl_core = f"{target_scl} := {op1} MOD {op2};"
# --- CORRECCIÓN: Generación de IF ---
if en_scl != "TRUE": if en_scl != "TRUE":
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
else: else:
# Si en_scl ES "TRUE", no se necesita IF
scl_final = scl_core scl_final = scl_core
# --- FIN CORRECCIÓN ---
instruction['scl'] = scl_final instruction['scl'] = scl_final
instruction['type'] = instr_type + SCL_SUFFIX instruction['type'] = instr_type + SCL_SUFFIX
@ -340,9 +361,10 @@ def process_mod(instruction, network_id, scl_map, access_map):
map_key_out = (network_id, instr_uid, 'out') map_key_out = (network_id, instr_uid, 'out')
scl_map[map_key_out] = target_scl scl_map[map_key_out] = target_scl
# --- CORRECCIÓN: Añadir ENO a scl_map ---
map_key_eno = (network_id, instr_uid, 'eno') map_key_eno = (network_id, instr_uid, 'eno')
scl_map[map_key_eno] = en_scl # ENO sigue a EN scl_map[map_key_eno] = en_scl # ENO sigue a EN
# print(f"DEBUG: MOD UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}") # --- FIN CORRECCIÓN ---
# print(f"INFO: MOD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") # print(f"INFO: MOD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
return True return True
@ -354,7 +376,7 @@ def process_add(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Intentando procesar ADD - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar ADD - UID: {instr_uid} en Red: {network_id}")
# --- Manejo de EN --- # --- CORRECCIÓN: Manejo de EN ---
en_input = instruction['inputs'].get('en') en_input = instruction['inputs'].get('en')
en_scl = None en_scl = None
if en_input is None: if en_input is None:
@ -362,13 +384,17 @@ def process_add(instruction, network_id, scl_map, access_map):
en_scl = "TRUE" en_scl = "TRUE"
else: else:
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
# --- Fin Manejo de EN ---
if en_scl is None: # Bloquear si EN está conectado pero no resuelto
# print(f"DEBUG: Dependencia EN no resuelta para ADD UID: {instr_uid}")
return False
# --- FIN CORRECCIÓN ---
in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map) in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map)
in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map) in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map)
if en_scl is None or in1_scl is None or in2_scl is None: if in1_scl is None or in2_scl is None:
# print(f"DEBUG: Dependencia no resuelta para ADD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})") # print(f"DEBUG: Dependencia no resuelta para ADD UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})")
return False return False
target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True) target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True)
@ -381,11 +407,12 @@ def process_add(instruction, network_id, scl_map, access_map):
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
scl_core = f"{target_scl} := {op1} + {op2};" scl_core = f"{target_scl} := {op1} + {op2};"
# --- CORRECCIÓN: Generación de IF ---
if en_scl != "TRUE": if en_scl != "TRUE":
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
else: else:
# Si en_scl ES "TRUE", no se necesita IF
scl_final = scl_core scl_final = scl_core
# --- FIN CORRECCIÓN ---
instruction['scl'] = scl_final instruction['scl'] = scl_final
instruction['type'] = instr_type + SCL_SUFFIX instruction['type'] = instr_type + SCL_SUFFIX
@ -393,9 +420,10 @@ def process_add(instruction, network_id, scl_map, access_map):
map_key_out = (network_id, instr_uid, 'out') map_key_out = (network_id, instr_uid, 'out')
scl_map[map_key_out] = target_scl scl_map[map_key_out] = target_scl
# --- CORRECCIÓN: Añadir ENO a scl_map ---
map_key_eno = (network_id, instr_uid, 'eno') map_key_eno = (network_id, instr_uid, 'eno')
scl_map[map_key_eno] = en_scl # ENO sigue a EN scl_map[map_key_eno] = en_scl # ENO sigue a EN
# print(f"DEBUG: ADD UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}") # --- FIN CORRECCIÓN ---
# print(f"INFO: ADD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") # print(f"INFO: ADD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
return True return True
@ -407,7 +435,7 @@ def process_move(instruction, network_id, scl_map, access_map):
# print(f"DEBUG: Intentando procesar MOVE - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar MOVE - UID: {instr_uid} en Red: {network_id}")
# --- Manejo de EN --- # --- CORRECCIÓN: Manejo de EN ---
en_input = instruction['inputs'].get('en') en_input = instruction['inputs'].get('en')
en_scl = None en_scl = None
if en_input is None: if en_input is None:
@ -415,12 +443,16 @@ def process_move(instruction, network_id, scl_map, access_map):
en_scl = "TRUE" en_scl = "TRUE"
else: else:
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
# --- Fin Manejo de EN ---
if en_scl is None: # Bloquear si EN está conectado pero no resuelto
# print(f"DEBUG: Dependencia EN no resuelta para MOVE UID: {instr_uid}")
return False
# --- FIN CORRECCIÓN ---
in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map) in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
if en_scl is None or in_scl is None: if in_scl is None:
# print(f"DEBUG: Dependencia no resuelta para MOVE UID: {instr_uid} (en={en_scl}, in={in_scl})") # print(f"DEBUG: Dependencia IN no resuelta para MOVE UID: {instr_uid}")
return False return False
target_scl = get_target_scl_name(instruction, 'out1', network_id, default_to_temp=False) # No usar temp por defecto target_scl = get_target_scl_name(instruction, 'out1', network_id, default_to_temp=False) # No usar temp por defecto
@ -430,16 +462,19 @@ def process_move(instruction, network_id, scl_map, access_map):
return False return False
scl_core = f"{target_scl} := {in_scl};" scl_core = f"{target_scl} := {in_scl};"
# --- CORRECCIÓN: Generación de IF ---
if en_scl != "TRUE": if en_scl != "TRUE":
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
else: else:
# Si en_scl ES "TRUE", no se necesita IF
scl_final = scl_core scl_final = scl_core
# --- FIN CORRECCIÓN ---
instruction['scl'] = scl_final instruction['scl'] = scl_final
instruction['type'] = instr_type + SCL_SUFFIX instruction['type'] = instr_type + SCL_SUFFIX
# print(f"INFO: MOVE UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") # print(f"INFO: MOVE UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
# Move no tiene ENO explícito en la mayoría de implementaciones LAD/SCL,
# por lo que no añadimos map_key_eno aquí normalmente.
return True return True
def process_pbox(instruction, network_id, scl_map, access_map, network_logic_list): def process_pbox(instruction, network_id, scl_map, access_map, network_logic_list):
@ -451,44 +486,34 @@ def process_pbox(instruction, network_id, scl_map, access_map, network_logic_lis
instr_type = instruction['type'] instr_type = instruction['type']
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
print(f"DEBUG: Intentando procesar PBOX - UID: {instr_uid} en Red: {network_id}") # print(f"DEBUG: Intentando procesar PBOX - UID: {instr_uid} en Red: {network_id}")
# 1. Obtener el bit de memoria (siempre presente en PBox para flancos)
mem_bit_input = instruction['inputs'].get('bit') mem_bit_input = instruction['inputs'].get('bit')
mem_bit_scl = get_scl_representation(mem_bit_input, network_id, scl_map, access_map) mem_bit_scl = get_scl_representation(mem_bit_input, network_id, scl_map, access_map)
if mem_bit_scl is None: if mem_bit_scl is None:
print(f"DEBUG: Dependencia no resuelta para PBOX UID: {instr_uid} (bit={mem_bit_scl})") # print(f"DEBUG: Dependencia no resuelta para PBOX UID: {instr_uid} (bit={mem_bit_scl})")
return False return False
# Validar que el bit de memoria sea una variable
if not (mem_bit_input and mem_bit_input.get('type') == 'variable'): if not (mem_bit_input and mem_bit_input.get('type') == 'variable'):
print(f"Error: Entrada 'bit' de PBOX UID {instr_uid} no es una variable: {mem_bit_input}") print(f"Error: Entrada 'bit' de PBOX UID {instr_uid} no es una variable: {mem_bit_input}")
instruction['scl'] = f"// ERROR: PBox {instr_uid} entrada 'bit' no es variable" instruction['scl'] = f"// ERROR: PBox {instr_uid} entrada 'bit' no es variable"
instruction['type'] += "_error" instruction['type'] += "_error"
return True return True
# 2. Determinar si es un flanco P_TRIG (heurística basada en patrón común)
# Patrón: La salida del PBox va a un Coil y el PBox está precedido por lógica booleana.
is_likely_p_trig = False is_likely_p_trig = False
consuming_coil_info = None
# Buscar Coil que consume la salida 'out' de este PBox
consuming_coil_uid = None consuming_coil_uid = None
for potential_consumer in network_logic_list: for potential_consumer in network_logic_list:
consumer_inputs = potential_consumer.get('inputs', {}) consumer_inputs = potential_consumer.get('inputs', {})
coil_input_signal = consumer_inputs.get('in') # Bobinas usan 'in' coil_input_signal = consumer_inputs.get('in')
if isinstance(coil_input_signal, dict) and \ if isinstance(coil_input_signal, dict) and \
coil_input_signal.get('type') == 'connection' and \ coil_input_signal.get('type') == 'connection' and \
coil_input_signal.get('source_instruction_uid') == instr_uid and \ coil_input_signal.get('source_instruction_uid') == instr_uid and \
coil_input_signal.get('source_pin') == 'out': coil_input_signal.get('source_pin') == 'out':
if potential_consumer.get('type', '').startswith('Coil'): consumer_type = potential_consumer.get('type', '').replace('_scl','').replace('_error','')
if consumer_type == 'Coil':
consuming_coil_uid = potential_consumer['instruction_uid'] consuming_coil_uid = potential_consumer['instruction_uid']
# print(f"DEBUG: PBox {instr_uid} alimenta Coil {consuming_coil_uid}") is_likely_p_trig = True
is_likely_p_trig = True # Fuerte indicio de P_TRIG
break break
# else: # Podría alimentar otra cosa, ¿quizás no es P_TRIG?
# print(f"DEBUG: Salida de PBox {instr_uid} no alimenta un Coil directamente.")
# pass
# 3. Encontrar la señal CLK implícita (Heurística: buscar RLO hacia atrás)
rlo_scl = None rlo_scl = None
if is_likely_p_trig: if is_likely_p_trig:
clk_source_found = False clk_source_found = False
@ -499,66 +524,49 @@ def process_pbox(instruction, network_id, scl_map, access_map, network_logic_lis
break break
if current_instr_index != -1: if current_instr_index != -1:
# Buscar hacia atrás desde ANTES del PBox
for i in range(current_instr_index - 1, -1, -1): for i in range(current_instr_index - 1, -1, -1):
prev_instr = network_logic_list[i] prev_instr = network_logic_list[i]
prev_instr_uid = prev_instr['instruction_uid'] prev_instr_uid = prev_instr['instruction_uid']
# Usar tipo original para la búsqueda
prev_instr_type = prev_instr.get('type', '').replace(SCL_SUFFIX, '').replace('_error', '') prev_instr_type = prev_instr.get('type', '').replace(SCL_SUFFIX, '').replace('_error', '')
# Instrucciones que generan el RLO relevante
if prev_instr_type in ['Contact', 'Eq', 'O', 'PBox', 'And', 'Xor', 'Ne', 'Gt', 'Lt', 'Ge', 'Le']: if prev_instr_type in ['Contact', 'Eq', 'O', 'PBox', 'And', 'Xor', 'Ne', 'Gt', 'Lt', 'Ge', 'Le']:
map_key_prev_out = (network_id, prev_instr_uid, 'out') map_key_prev_out = (network_id, prev_instr_uid, 'out')
potential_clk_scl = scl_map.get(map_key_prev_out) potential_clk_scl = scl_map.get(map_key_prev_out)
if potential_clk_scl is not None: if potential_clk_scl is not None:
rlo_scl = potential_clk_scl rlo_scl = potential_clk_scl
clk_source_found = True clk_source_found = True
# print(f"DEBUG: Fuente CLK para PBox {instr_uid} inferida de: {prev_instr_type} UID {prev_instr_uid} -> {rlo_scl}")
break break
elif prev_instr_type in ['Move', 'Add', 'Convert', 'Mod']: elif prev_instr_type in ['Move', 'Add', 'Convert', 'Mod']:
# Si encontramos un bloque funcional, el RLO podría venir de su ENO
map_key_prev_eno = (network_id, prev_instr_uid, 'eno') map_key_prev_eno = (network_id, prev_instr_uid, 'eno')
potential_clk_scl = scl_map.get(map_key_prev_eno) potential_clk_scl = scl_map.get(map_key_prev_eno)
if potential_clk_scl is not None: if potential_clk_scl is not None:
rlo_scl = potential_clk_scl rlo_scl = potential_clk_scl
clk_source_found = True clk_source_found = True
# print(f"DEBUG: Fuente CLK para PBox {instr_uid} inferida de ENO de: {prev_instr_type} UID {prev_instr_uid} -> {rlo_scl}")
break break
# Si no tiene ENO resuelto, seguimos buscando atrás
if not clk_source_found: if not clk_source_found:
# Podría estar conectado directamente a powerrail si es el inicio de la lógica
# O la heurística falló. Devolver error o asumir TRUE? Devolver error es más seguro.
print(f"Error: No se pudo inferir la fuente CLK para PBOX UID {instr_uid} (probable P_TRIG).") print(f"Error: No se pudo inferir la fuente CLK para PBOX UID {instr_uid} (probable P_TRIG).")
instruction['scl'] = f"// ERROR: PBox {instr_uid} sin fuente CLK implícita clara" instruction['scl'] = f"// ERROR: PBox {instr_uid} sin fuente CLK implícita clara"
instruction['type'] += "_error" instruction['type'] += "_error"
return True # Marcado como error return True
# Verificar si el RLO inferido se resolvió
if rlo_scl is None: if rlo_scl is None:
print(f"DEBUG: Dependencia CLK (inferida) no resuelta para PBOX UID: {instr_uid}") # print(f"DEBUG: Dependencia CLK (inferida) no resuelta para PBOX UID: {instr_uid}")
return False return False
# 4. Generar SCL
scl_comment = "" scl_comment = ""
if is_likely_p_trig: if is_likely_p_trig:
# Usar función hipotética P_TRIG_FUNC
clk_signal_formatted = f"({rlo_scl})" if ' ' in rlo_scl else rlo_scl clk_signal_formatted = f"({rlo_scl})" if ' ' in rlo_scl else rlo_scl
result_scl = f"P_TRIG_FUNC(CLK := {clk_signal_formatted}, M := {mem_bit_scl})" result_scl = f"P_TRIG_FUNC(CLK := {clk_signal_formatted}, M := {mem_bit_scl})"
scl_comment = f"// Edge detection PBox {instr_uid} -> {result_scl} (CLK source inferred)" scl_comment = f"// Edge detection PBox {instr_uid} -> {result_scl} (CLK source inferred)"
else: else:
# Si no parece P_TRIG, simplemente pasar el valor del bit de memoria?
# O podría ser un N_TRIG (flanco negativo)? O sólo lectura de M?
# Por seguridad, si no es el patrón P_TRIG->Coil, pasamos el bit.
print(f"Advertencia: PBox UID {instr_uid} no coincide con patrón P_TRIG->Coil. Pasando valor de {mem_bit_scl} directamente.") print(f"Advertencia: PBox UID {instr_uid} no coincide con patrón P_TRIG->Coil. Pasando valor de {mem_bit_scl} directamente.")
result_scl = mem_bit_scl result_scl = mem_bit_scl
scl_comment = f"// PBox {instr_uid} - Passing value from bit: {result_scl}" scl_comment = f"// PBox {instr_uid} - Passing value from bit: {result_scl}"
# 5. Poner el resultado en scl_map para la salida 'out'
map_key_out = (network_id, instr_uid, 'out') map_key_out = (network_id, instr_uid, 'out')
scl_map[map_key_out] = result_scl scl_map[map_key_out] = result_scl
# 6. Actualizar JSON
instruction['scl'] = scl_comment instruction['scl'] = scl_comment
instruction['type'] = instr_type + SCL_SUFFIX instruction['type'] = instr_type + SCL_SUFFIX
return True return True
@ -586,7 +594,6 @@ def process_o(instruction, network_id, scl_map, access_map):
all_resolved = False all_resolved = False
# print(f"DEBUG: Dependencia no resuelta para O UID: {instr_uid} (pin {pin})") # print(f"DEBUG: Dependencia no resuelta para O UID: {instr_uid} (pin {pin})")
break break
# Poner entre paréntesis si es complejo para seguridad en OR
term = f"({in_scl})" if (' ' in in_scl or 'AND' in in_scl) and not (in_scl.startswith('(') and in_scl.endswith(')')) else in_scl term = f"({in_scl})" if (' ' in in_scl or 'AND' in in_scl) and not (in_scl.startswith('(') and in_scl.endswith(')')) else in_scl
scl_parts.append(term) scl_parts.append(term)
@ -615,8 +622,7 @@ def process_json_to_scl(json_filepath):
print(f"Cargando JSON desde: {json_filepath}") print(f"Cargando JSON desde: {json_filepath}")
try: try:
with open(json_filepath, 'r', encoding='utf-8') as f: with open(json_filepath, 'r', encoding='utf-8') as f:
# Guardar data globalmente o pasarla a process_pbox si es necesario global data
global data # Hacer data accesible globalmente (o pasar como argumento)
data = json.load(f) data = json.load(f)
except Exception as e: except Exception as e:
print(f"Error al cargar o parsear JSON: {e}") print(f"Error al cargar o parsear JSON: {e}")
@ -629,14 +635,11 @@ def process_json_to_scl(json_filepath):
net_id = network['id'] net_id = network['id']
current_access_map = {} current_access_map = {}
for instr in network.get('logic', []): for instr in network.get('logic', []):
# (Código para reconstruir access_map - sin cambios)
# Chequear inputs
for pin, source in instr.get('inputs', {}).items(): for pin, source in instr.get('inputs', {}).items():
sources_to_check = source if isinstance(source, list) else ([source] if isinstance(source, dict) else []) sources_to_check = source if isinstance(source, list) else ([source] if isinstance(source, dict) else [])
for src in sources_to_check: for src in sources_to_check:
if isinstance(src, dict) and src.get('uid') and src.get('scope') and src.get('type') in ['variable', 'constant']: if isinstance(src, dict) and src.get('uid') and src.get('scope') and src.get('type') in ['variable', 'constant']:
current_access_map[src['uid']] = src current_access_map[src['uid']] = src
# Chequear outputs
for pin, dest_list in instr.get('outputs', {}).items(): for pin, dest_list in instr.get('outputs', {}).items():
if isinstance(dest_list, list): if isinstance(dest_list, list):
for dest in dest_list: for dest in dest_list:
@ -645,7 +648,7 @@ def process_json_to_scl(json_filepath):
network_access_maps[net_id] = current_access_map network_access_maps[net_id] = current_access_map
scl_map = {} scl_map = {}
max_passes = 20 max_passes = 25 # Aumentado ligeramente por si acaso
passes = 0 passes = 0
# Lista de procesadores con orden corregido # Lista de procesadores con orden corregido
@ -659,11 +662,10 @@ def process_json_to_scl(json_filepath):
process_add, process_add,
process_move, process_move,
process_coil, process_coil,
# process_group_ifs, # Aplazado por ahora para simplificar
] ]
# Crear el mapa para búsqueda rápida # Mapa de procesadores usando lower case para la clave
processor_map = {func.__name__.split('_')[1].capitalize(): func for func in processors} processor_map = {func.__name__.split('_')[1].lower(): func for func in processors}
# !!! POTENCIAL PROBLEMA 1: La clave aquí sigue siendo sensible a mayúsculas !!!
# Ejemplo: "Pbox" vs "PBox"
print("\n--- Iniciando Bucle de Procesamiento Iterativo ---") print("\n--- Iniciando Bucle de Procesamiento Iterativo ---")
while passes < max_passes: while passes < max_passes:
@ -671,57 +673,45 @@ def process_json_to_scl(json_filepath):
made_change_in_pass = False made_change_in_pass = False
print(f"\n--- Pase {passes} ---") print(f"\n--- Pase {passes} ---")
# Iterar sobre las redes
for network in data.get('networks', []): for network in data.get('networks', []):
network_id = network['id'] network_id = network['id']
access_map = network_access_maps.get(network_id, {}) access_map = network_access_maps.get(network_id, {})
network_logic = network.get('logic', []) network_logic = network.get('logic', [])
# Iterar sobre las instrucciones en la red
for instruction in network_logic: for instruction in network_logic:
instr_type_original = instruction['type'] instr_type_original = instruction['type']
# Saltar si ya está procesado o es error
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original: if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
continue continue
# --- Búsqueda del procesador (CORREGIR ESTA PARTE) --- # Búsqueda de procesador (case-insensitive)
processor_func = None
instr_type_lookup = instr_type_original.capitalize() # Capitalizar para buscar en el mapa
# !!! POTENCIAL PROBLEMA 2: Si el tipo es 'O', capitalize() da 'O', pero la clave es 'O'?
# Vamos a usar minúsculas para la búsqueda en el mapa también
instr_type_lower_lookup = instr_type_original.lower() instr_type_lower_lookup = instr_type_original.lower()
func_to_call = None func_to_call = processor_map.get(instr_type_lower_lookup)
for func_key_cap, func_obj in processor_map.items():
if func_key_cap.lower() == instr_type_lower_lookup:
func_to_call = func_obj
break
# --- Fin Corrección Búsqueda ---
# Si encontramos un procesador para este tipo
if func_to_call: if func_to_call:
# print(f"DEBUG: Encontrado procesador {func_to_call.__name__} para tipo {instr_type_original}") # Añadir para depurar # print(f"DEBUG: Intentando {func_to_call.__name__} para {instr_type_original} UID {instruction['instruction_uid']}")
try: try:
# Pasar lista lógica si es necesario # Pasar lista lógica si es PBox
if func_to_call == process_pbox: if func_to_call == process_pbox:
changed = func_to_call(instruction, network_id, scl_map, access_map, network_logic) changed = func_to_call(instruction, network_id, scl_map, access_map, network_logic)
else: else:
changed = func_to_call(instruction, network_id, scl_map, access_map) changed = func_to_call(instruction, network_id, scl_map, access_map)
if changed: if changed:
# print(f"DEBUG: Cambio realizado por {func_to_call.__name__} en UID {instruction['instruction_uid']}")
made_change_in_pass = True made_change_in_pass = True
# No hacer break aquí, seguir intentando otros procesadores # No hacer break, permite que el procesador de grupo actúe si se añade después
# en la misma instrucción podría tener sentido en algunos casos?
# Por ahora, SÍ hacemos break para procesar una vez por pase.
# break # <--- Quitar este break si queremos reintentar en el mismo pase? No, mantenerlo.
except Exception as e: except Exception as e:
# ... (manejo de errores) ...
print(f"ERROR al ejecutar {func_to_call.__name__} en UID {instruction.get('instruction_uid')} Red {network_id}: {e}") print(f"ERROR al ejecutar {func_to_call.__name__} en UID {instruction.get('instruction_uid')} Red {network_id}: {e}")
traceback.print_exc() traceback.print_exc()
instruction['scl'] = f"// ERROR during processing: {e}" instruction['scl'] = f"// ERROR during processing: {e}"
instruction['type'] += "_error" instruction['type'] += "_error"
made_change_in_pass = True made_change_in_pass = True
# else: # Reducir ruido
# print(f"DEBUG: No se encontró procesador para el tipo: {instr_type_original}") # --- Llamada Opcional al Procesador de Agrupación (APLAZADO) ---
# if made_change_in_pass: # Solo intentar agrupar si hubo otros cambios?
# for network in data.get('networks', []):
# # ... (código para llamar a process_group_ifs) ...
# pass
if not made_change_in_pass: if not made_change_in_pass: