Proyecto Fin de Carrera EMULADOR DE COMPUTADOR DIGITAL SIMPLE Autor: Félix Robles Elvira Tutor: José Ángel Acosta Rodríguez Ingeniería de Telecomunicación Departamento de Ingeniería de Sistemas y Automática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Dedicado a mis padres, a mis hermanos, a mi tutor José Ángel Acosta Rodríguez por su ayuda, y a todos los amigos y familiares a los que les guste que les dediquen proyectos n de carrera. Índice 1. Introducción y objetivos 1 2. Elección del lenguaje de programación a usar 3 3. Fundamentos de un computador digital 5 3.1. Codicación binaria de la información . . . . . . . . . . . . . . . . . . . 5 3.1.1. Numeraciones binaria y decimal . . . . . . . . . . . . . . . . . . 5 3.1.2. Codicación de números enteros . . . . . . . . . . . . . . . . . . 6 3.2. Codicación de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.3. Álgebra de boole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.3.1. Denición . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3.3.2. Propiedades del álgebra de boole . . . . . . . . . . . . . . . . . 11 3.3.3. Funciones booleanas . . . . . . . . . . . . . . . . . . . . . . . . 11 3.3.4. Puertas lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 4. Estructura general de un computador digital 15 4.1. Arquitectura de Von Neumann . . . . . . . . . . . . . . . . . . . . . . . 15 4.2. Almacenamiento de la información . . . . . . . . . . . . . . . . . . . . 16 4.3. Unidad de memoria central . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.4. Unidad aritmético-lógica . . . . . . . . . . . . . . . . . . . . . . . . . . 21 4.5. Unidad de entrada y salida . . . . . . . . . . . . . . . . . . . . . . . . . 22 4.6. Enlaces o buses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 4.7. Unidad de control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 5. Descripción de la máquina a implementar 27 5.1. Elementos del computador . . . . . . . . . . . . . . . . . . . . . . . . . 27 5.2. Funcionamiento del computador . . . . . . . . . . . . . . . . . . . . . . 29 5.2.1. Ejecución de instrucciones . . . . . . . . . . . . . . . . . . . . . 31 5.2.2. Instruciones de salto . . . . . . . . . . . . . . . . . . . . . . . . 33 5.2.3. Funcionamiento de la unidad de control . . . . . . . . . . . . . . 34 5.3. Código máquina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 5.4. Lenguaje ensamblador . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 5.5. Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 5.5.1. Media de tres números . . . . . . . . . . . . . . . . . . . . . . . 40 4 5.5.2. Cálculo de número primo . . . . . . . . . . . . . . . . . . . . . . 41 5.5.3. Módulo al cuadrado de un vector . . . . . . . . . . . . . . . . . 43 5.5.4. Frase o palabra en orden inverso . . . . . . . . . . . . . . . . . . 44 5.5.5. Lectura de una matriz . . . . . . . . . . . . . . . . . . . . . . . 46 5.5.6. Submatriz triangular . . . . . . . . . . . . . . . . . . . . . . . . 48 6. Estructura del emulador 53 6.1. Código ensablador y código binario . . . . . . . . . . . . . . . . . . . . 53 6.2. Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 6.2.1. Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 6.2.2. ProjectsManager . . . . . . . . . . . . . . . . . . . . . . . . . . 58 6.2.3. TabsManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 6.2.4. DebugViewManager . . . . . . . . . . . . . . . . . . . . . . . . 61 6.2.5. Sobre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 6.2.6. Emulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 6.2.7. VirtualComputer . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.2.8. ButtonTabComponent . . . . . . . . . . . . . . . . . . . . . . . 71 6.2.9. XenonHelper . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 6.2.10. LineCode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 6.2.11. Instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 6.2.12. PopupListener . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 6.2.13. Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 6.2.14. ProjectFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.2.16. JConnector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 6.2.17. ConnectorContainer . . . . . . . . . . . . . . . . . . . . . . . . 80 6.2.18. ConnectLine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 6.2.15. Tab 7. Manual de usuario 83 7.1. Ejecución . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.2. Vista de desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.3. Vista de emulación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 7.4. Vista de depuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 5 8. Posibles ampliaciones 91 8.1. Interfaz gráca para plataformas móviles . . . . . . . . . . . . . . . . . 91 8.2. Ampliación del juego de instrucciones del computador . . . . . . . . . . 95 9. Conclusiones y cumplimiento de objetivos 103 10.Bibliografía 105 11.Anexos 107 11.1. Código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 11.1.1. ButtonTabComponent.java . . . . . . . . . . . . . . . . . . . . . 107 11.1.2. JConnector.java . . . . . . . . . . . . . . . . . . . . . . . . . . 109 . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 11.1.4. ConnectLine.java . . . . . . . . . . . . . . . . . . . . . . . . . . 120 11.1.5. LineCode.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 11.1.6. Sobre.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 11.1.7. ConnectorContainer.java . . . . . . . . . . . . . . . . . . . . . 128 11.1.8. PopupListener.java . . . . . . . . . . . . . . . . . . . . . . . . . 129 11.1.9. Tab.java 130 11.1.3. Emulator.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.10.DebugViewManager.java . . . . . . . . . . . . . . . . . . . . . 132 . . . . . . . . . . . . . . . . . . . . . . . . . . 159 . . . . . . . . . . . . . . . . . . . . . . . . . 160 11.1.13.Project.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 11.1.14.VirtualComputer.java . . . . . . . . . . . . . . . . . . . . . . . 166 11.1.15.Instruction.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 11.1.16.ProjectsManager.java . . . . . . . . . . . . . . . . . . . . . . . 213 11.1.17.XenonHelper.java . . . . . . . . . . . . . . . . . . . . . . . . . . 217 11.1.18.Interface.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 11.1.11.ProjectFile.java 11.1.12.TabsManager.java 6 Índice de guras 1. Vista del gestor de versiones del software . . . . . . . . . . . . . . . . . 4 2. Circuito de la suma de a y b . . . . . . . . . . . . . . . . . . . . . . . . 10 3. Circuito simbólico del producto de a y b . . . . . . . . . . . . . . . . . 10 4. Circuito simbólico de ā . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 5. Circuito con interruptores de ejemplo de función booleana . . . . . . . 12 6. Símbolos de las puertas lógicas más comunes . . . . . . . . . . . . . . . 14 7. Arquitectura de Von Neumann con un único bus . . . . . . . . . . . . . 16 8. Estructura matricial de una memoria . . . . . . . . . . . . . . . . . . . 19 9. Diagrama de bloques de la memoria principal . . . . . . . . . . . . . . 20 10. Diagrama de bloques de una UAL, su acumulador, y señales de control 21 11. Control de conexión de un dispositivo a un enlace con puertas triestado 24 12. Esquema de una computadora digital mostrando los enlaces y las señales de gobierno. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 13. Fases de la ejecución de la instrucción suma. . . . . . . . . . . . . . . . 31 14. Diagrama de bloques de la unidad de control . . . . . . . . . . . . . . . 34 15. Cronograma de la instrucción suma . . . . . . . . . . . . . . . . . . . . 35 16. Esquema del funcionamiento del programa que realiza media de tres números . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17. Diagrama de funcionamiento delprograma que calcula si un número es primo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18. 42 Diagrama de funcionamiento delprograma que calcula el módulo al cuadrado de un vector de 4 componentes . . . . . . . . . . . . . . . . . . . 19. 41 44 Diagrama de funcionamiento de programa que escribe una frase en orden inverso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 20. Diagrama de funcionamiento de programa que almacena una matriz . . 48 21. Diagrama de funcionamiento de programa que lee una matriz y luego escribe los elementos de su submatriz triangular . . . . . . . . . . . . . 51 22. Diagrama de clases de las clases principales . . . . . . . . . . . . . . . . 56 23. Diagrama de la clase Interface . . . . . . . . . . . . . . . . . . . . . . . 57 24. Diagrama de la clase ProjectsManager . . . . . . . . . . . . . . . . . . 58 25. Diagrama de la clase TabsManager . . . . . . . . . . . . . . . . . . . . 60 26. Diagrama de la clase DebugViewManager . . . . . . . . . . . . . . . . . 62 27. Diagrama de la clase Sobre . . . . . . . . . . . . . . . . . . . . . . . . . 66 7 28. Diagrama de la clase Emulator . . . . . . . . . . . . . . . . . . . . . . . 66 29. Diagrama de la clase VirtualComputer . . . . . . . . . . . . . . . . . . 69 30. Diagrama de la clase ButtonTabComponent . . . . . . . . . . . . . . . 71 31. Diagrama de la clase XenonHelper . . . . . . . . . . . . . . . . . . . . 72 32. Diagrama de la clase LineCode . . . . . . . . . . . . . . . . . . . . . . 73 33. Diagrama de la clase Instruction . . . . . . . . . . . . . . . . . . . . . . 74 34. Diagrama de la clase PopupListener . . . . . . . . . . . . . . . . . . . . 76 35. Diagrama de la clase Project . . . . . . . . . . . . . . . . . . . . . . . . 77 36. Diagrama de la clase ProjectFile . . . . . . . . . . . . . . . . . . . . . . 77 37. Diagrama de la clase Tab . . . . . . . . . . . . . . . . . . . . . . . . . . 78 38. Diagrama de la clase JConnector . . . . . . . . . . . . . . . . . . . . . 79 39. Diagrama de la clase ConnectorContainer . . . . . . . . . . . . . . . . . 80 40. Diagrama de la clase ConnectLine . . . . . . . . . . . . . . . . . . . . . 81 41. Vista inicial de desarrollo. . . . . . . . . . . . . . . . . . . . . . . . . . 84 42. Ejemplo de desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 43. Barra de herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 44. Barra de menús de la vista de desarrollo . . . . . . . . . . . . . . . . . 86 45. Vista de emulación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 46. Barra de herramientas de la vista de emulación . . . . . . . . . . . . . 87 47. Barra de menús de la vista de emulación . . . . . . . . . . . . . . . . . 88 48. Vista de depuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 49. Barra de control de de la vista de depuración . . . . . . . . . . . . . . . 89 50. Barra de menús de la vista de depuración . . . . . . . . . . . . . . . . . 90 51. Traducción de texto a instrucciones ensamblador . . . . . . . . . . . . . 93 52. Ejecución de una instrucción . . . . . . . . . . . . . . . . . . . . . . . . 94 53. Cambios de constantes de la Clase Instruction . . . . . . . . . . . . . . 96 54. Cambios en la enumeración OperationCode . . . . . . . . . . . . . . . . 96 55. Cambios en Instruction::updateFromData() . . . . . . . . . . . . . . . . 98 56. Cambios en Instruction::updateFromInstruction() . . . . . . . . . . . . 99 57. Cambios en VirtualComputer::executeNextInstruction() . . . . . . . . . 100 58. Cambios en VirtualComputer::executeNextInstruction() (continuación) 101 59. Cambios en XenonHelper::translateToBinary() . . . . . . . . . . . . . . 101 60. Cambios en XenonHelper::translateFromBinary() . . . . . . . . . . . . 102 8 Índice de cuadros 1. Parte de la tabla ISO 8859-1 . . . . . . . . . . . . . . . . . . . . . . . . 8 2. Algunos códigos de control . . . . . . . . . . . . . . . . . . . . . . . . . 8 3. Tabla de la verdad de la suma de a y b . . . . . . . . . . . . . . . . . . 9 4. Tabla de la verdad del producto de a y b . . . . . . . . . . . . . . . . . 10 5. Tabla de la verdad de ā . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6. Tabla de la verdad de ejemplo de función booleana . . . . . . . . . . . 12 7. Tabla de la verdad de NO . . . . . . . . . . . . . . . . . . . . . . . . . 13 8. Tabla de la verdad de O . . . . . . . . . . . . . . . . . . . . . . . . . . 13 9. Tabla de la verdad de Y . . . . . . . . . . . . . . . . . . . . . . . . . . 13 10. Tabla de la verdad de O negado . . . . . . . . . . . . . . . . . . . . . . 13 11. Tabla de la verdad de Y negado . . . . . . . . . . . . . . . . . . . . . . 14 12. Tabla de la verdad de O . . . . . . . . . . . . . . . . . . . . . . . . . . 14 13. Tabla de transición del biestable RS . . . . . . . . . . . . . . . . . . . . 17 14. Tabla de la verdad de circuito multiplicador . . . . . . . . . . . . . . . 22 15. Ejemplo de instrucción . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 16. Ejemplo de programa en código máquina para el computador . . . . . . 36 17. Las columnas indican el código de operación, modo de direccionamiento, el código mnemotécnico y una somera explicación para cada una de las instrucciones de CESIUS. 18. . . . . . . . . . . . . . . . . . . . . . . . . . 38 Las columnas indican el código de operación, modo de direccionamiento, el código mnemotécnico y una somera explicación para cada una de las instrucciones de CESIUS (Continuación). . . . . . . . . . . . . . . . . . 19. 39 Ejemplo de programa. A la izquierda se presenta una lista de las operaciones a efectuar, a la derecha se tiene el programa en la memoria. El contenido de los registros de la memoria se ha separado en tres bloques (CO, MD y D) para facilitar el estudio, dicha separación no existe en la realidad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 20. Código mnemoténico de programa que realiza media de tres números . 40 21. Código Mnemotécnico de programa que calcula si un número es primo . 42 22. Código Mnemotécnico de programa que calcula el módulo al cuadrado de un vector de 4 componentes . . . . . . . . . . . . . . . . . . . . . . 43 23. Programa que escribe una frase en orden inverso . . . . . . . . . . . . . 45 24. Programa que almacena una matriz . . . . . . . . . . . . . . . . . . . . 47 9 25. Programa que lee una matriz y luego escribe los elementos de su submatriz triangular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26. 49 Programa que lee una matriz y luego escribe los elementos de su submatriz triangular (continuación) . . . . . . . . . . . . . . . . . . . . . . . 10 50 11 1. Introducción y objetivos En este proyecto se desarrolla una implementación emulada por software de una computadora digital simple. La computadora solo existe a nivel virtual y a nivel teórico, no existe una implementación tangible o física de dicha computadora. Dicha implementación virtual cuenta con un entorno de desarrollo, programa de traducción de código ensamblador a código máquina, depurador y emulador. El esquema de funcionamiento de la computadora es simple, y ha sido desarrollado a partir del esquema de Von Neumann para una computadora de programa almacenado. El actual proyecto tiene como nombre clave Xenon, y está basado en el programa antiguamente llamado CESIUS Arahal, Manuel R; Hernández, José Julio; Limón, Daniel (1986)Acosta Rodriguez, José Ángel (2009). El proyecto consta de varias partes: el programa desarrollado, su código fuente, y la documentación, siendo este documento la última parte. Los objetivos del proyecto son: Diseño de una computadora simple y desarrollo de un programa software llamado Xenon que permita emular dicha computadora. Dicho software habrá de incluir un entorno de programación simple para escribir y compilar programas para el computador, así como la posibilidad de depurar y ejecutar dichos programas. Estudio de posibles ampliaciones de este proyecto. El software Xenon ha de servir para mostrar el funcionamiento de las computadoras a personas que estén aprendiendo dicha materia. El software Xenon ha de poderse ejecutar en diversas plataformas y sistemas operativos, como pueden ser Windows, Linux, Mac. La estructura del documento se detalla a continuación: En el Capítulo 2 se razona el lenguaje de programación escogido para desarrollar el emulador Xenon. Explicación teórica del funcionamiento de los computadores digitales en los capítulo 3 y 4, basada en los apuntes de la asignatura de Informática Acosta Rodriguez, José Ángel (2009). 1 Se realiza una descripción del computador a implementar en el capítulo 5, explicando los elementos del computador y su funcionamiento, el lenguaje de código máquina, y el lenguaje ensamblador del computador. El capítulo 6 trata de la estructura del proyecto de software Xenon, incluyendo una descripción de las clases y métodos que contiene. El manual de usuario del software Xenon está contenido en el capítulo 7. El capítulo 8 detalla una descripción de posibles ampliaciones de este proyecto, como la implementación del software para plataformas móviles como Android, o ampliar el juego de instrucciones del computador emulado. Las conclusiones del proyecto y análisis de los objetivos alcanzados se realiza en el capítulo 9. Siguen las referencias bibliográcas en el capítulo 10 y el código del emulador en la parte de anexos correspondiente al capítulo 11. 2 2. Elección del lenguaje de programación a usar El lenguaje escogido para desarrollar la aplicación ha sido Java. Las principales motivaciones para usar Java es permite la ejecución de un mismo programa en diversas plataformas hardware y sistemas operativos, y la velocidad de ejecución es superior a la de un lenguaje interpretado, acercándose a la velocidad que se consigue con lenguajes compilados. Los lenguajes de programación compilados son más rápidos que los interpretados porque el código interpretado ha de ser reducido a código máquina en tiempo real. Java compila el código, pero es compilado en bytecode, para una máquina que realmente no existe, la Máquina Virtual Java (JVM). El código bytecode a su vez es interpretado durante la ejecución del programa Java. Así pues la estrategia de Java es mixta entre código interpretado y compilado. Comúnmente el código bytecode no es simplemente interpretado, sino que usa compiladores just-in-time que traducen partes del programa a código máquina de forma que puedan ejecutarse mucho más rápido que si fueran interpretadas. Por todo esto, un programa Java suele ejecutarse más rápido que un programa hecho para un lenguaje interpretado. Además, el programa compilado a bytecode puede ejecutarse sin necesidad de recompilación en cualquier plataforma que cuente con un intérprete de bytecode, como en los sistemas operativos Windows, Linux y Mac. Otras opciones son usar: C/C++. Como desventaja principal, el ejecutable es dependiente del sistema operativo. La mayor ventaja radica en que es un lenguaje de más bajo nivel, lo que permite crear ejecutables más rápidos. Lenguajes intepretados, como python. Suelen ser multiplataforma, sin embargo su ejecución, al ser lenguaje interpretado, es más lenta. Además requiere que el usuario tenga instalado un intérprete, lo cual no siempre ocurre. Una posible solución a ese problema sería realizar la aplicación web, de modo que sea el servidor quien ejecute el código. Pero entonces estamos obligando al usuario a disponer de conexión a internet, y al servidor a ejecutar el código de todos los usuarios, lo cual puede sobrecargar el servidor. Otra opción es implementar el emulador en una página web, por ejemplo haciendo uso de javascript (otro lenguaje interpretado) en la parte del cliente para no sobrecargar el servidor web. 3 Figura 1: Vista del gestor de versiones del software A su vez, se ha hecho uso de un sistema de versiones en el desarrollo del software. El uso de un sistema de versiones permite volver hacia atrás en el tiempo así como saber exactamente en qué momento se escribió una parte del código o funcionalidad. Los sistemas de control de versiones son muy útiles cuando el desarrollo de un software es realizado por un equipo de varias personas, permitiendo añadir cambios locales a una versión global. En proyectos de cierta envergadura, un sistema de versiones es casi una necesidad. Este proyecto cuenta con más de 9000 líneas de código, por lo que no haber hecho uso de un sistema de versiones habría dicultado el desarrollo del proyecto. El sistema de versiones usado es Subversion, concretamente el cliente tortoisehg Varios (2013). En la gura 1 se puede ver el entorno de dicho cliente subversion. 4 3. Fundamentos de un computador digital A continuación se presenta un resumen de los fundamentos de un computador digital. Para ello en primer lugar se dene cómo se puede codicar en forma binaria cualquier información. Después se denen diferentes codicaciones de caracteres que se pueden usar. En el siguiente apartado se describe el álgebra de boole, que permite denir operaciones matemáticas y funciones haciendo uso de información binaria. Finalmente se realiza una introducción a las puertas lógicas, que implementan funciones que usan el álgebra de boole mediante circuitos electrónicos. 3.1. Codicación binaria de la información Las computadoras digitales hacen uso de información en forma binaria. La razón radica en que los dispositivos electrónicos usados en las computadoras hacen uso de dos niveles de voltaje, correspondientes a los valores binarios 1 y 0. Sin embargo, las computadoras son capaces de hacer uso de información de muchos tipos, como grácos, textos y sonidos. Dicha información es posible Shannon, Claude E. (1948) representarla en codicación binaria. 3.1.1. Numeraciones binaria y decimal En el computador que aquí se presenta, solo se hacen uso de números enteros, no maneja de forma directa números fraccionarios o de punto otante. El sistema de numeración de uso más común es aquél en base 10, llamado sistema decimal. En el sistema decimal, las cifras representan coecientes de un polinomio de potencias de 10. A los coecientes di se les denomina dígitos. D| 10 = dn ·10n + ...+d1 ·101 +d0 ·100 Por ejemplo, el número 9482 se descompone en: 9481 |10 = 9 · 103 + 4 · 102 + 8 · 101 + 1 · 100 En el sistema binario, la base es 2, y los únicos dígitos posibles son 0 y 1. A los coecientes bi se les denomina bits. B| 2 = bn ·2n + ...+b1 ·21 +b0 ·20 Por ejemplo, el número 11101 en base dos se puede descomponer: 11101 |2 = 1 · 24 + 1 · 23 + 1 · 22 + 0 · 21 + 1 · 20 = 29 |10 En general, el Teorema Fundamental de la Numeración permite construir números en un sistema de numeración posicional en una base b cualquiera, siendo b un número 5 natural. 3.1.2. Codicación de números enteros En un computador digital, la memoria está compuesta por celdas elementales que corresponden con dígitos binarios, o bits. A su vez, una dirección de memoria en un computador digital, o un registro, está formado por un grupo de celdas, de forma que su conjunto permite codicar números tan grandes como la cantidad de bits del registro permita, en una representación posicional en base 2. Por ejemplo, si un registro tiene 16 celdas binarias, es posible almacenar en él números entre 0 y 216 − 1, es decir entre 0 y 65535. En general un computador digital hace uso de registros de una cantidad de bits determinada, si bien ciertos registros pueden tener un mayor o menor tamaño. Si bien la representación binaria de un número entero positivo que acabamos de explicar es ampliamente usado, existen diferentes opciones de representación de los números enteros negativos: Signo-valor absoluto: Una celda, normalmente la correspondiente al dígito más signicativo, es aquella que indica si el número es positivo (con un 0) o negativo (con un 1). De este modo, el resto de bits del registro, que se reeren al valor absoluto del número, son los mismos tanto si el número es negativo como si es positivo. En este sistema, el número cero tiene dos representaciones. Complemento a 1: Se reserva el primer bit para el signo. Si el bit es positivo el resto de números se representa en base dos, si es negativo s realiza el complemento bit a bit (sustituir ceros por unos, y unos por ceros) del valor absoluto. En este sistema también existen dos ceros. Por ejemplo, si existen 4 celdas, en complemento a 1: 0|10 = 0000 = 1111 3| 10 = 0011 -3|10 = 1100 Complemento a 2: El complemento a dos es igual que el complemento a 1 cuando el número es positivo. Cuando el número es negativo, es como el complemento a 1 mas la unidad. En este caso solo existe una representación del cero, y tambien es capaz de representar un número negativo más que las anteriores opciones. Ejemplos de representación en complemento a dos con 4 celdas son: 6 0|10 = 0000 4| 10 = 0100 -4|10 = 1100 Se puede comprobar que, si el registro tiene n bits, y el número A es negativo, la representación en complemento a 2 corresponde con A+2n . Por ejemplo: -4|10 = 1100|complemento2 ≡ −4 + 24 = 12 Los dos primeros sistemas presentan dicultades para realizar operaciones aritméticas elementales mediante el uso de circuitos electrónicos, es por ello que se ideó el sistema de complemento a 2, que es ampliamente usado en los computadores digitales. 3.2. Codicación de caracteres La mayoría de computadoras han de ser capaces de procesar, además de números, caracteres de texto, como por eemplo: Letras mayúsculas y minúsculas. Dígitos. Signos. Como por ejemplo + - , / ( ) . $ % = ¾ ? [ ] { } Códigos que no tienen representación gráca, pero con funciones de control. Existen multitud de códigs que permiten almacenar de forma binaria información de este tipo, entre los que destaca el ASCII (American Standard Code for Information Interchange), que asigna un número a cada signo. El ASCII necesita 7 bits por carácter, siendo por tanto capaz de representar 128 signos diferentes. El ASCII extendido es una versión posterior que hace uso de 8 bits, y es capaz de representar 256 signos. Concretamente en el computador que se desarrolla en este proyecto, se hace uso del código ISO 8859-1, que es una norma ISO que dene la codicación del alfabeto latino e incluye los diacríticos (como las letras acentuadas, ñ y ç) Esta norma se caracteriza por coincidir con la codicación ASCII en los primeros 128 caracteres, y añadir otros 128 más, haciendo uso de un total de 8 bits. Se puede observar que las letras son asignadas un número en orden alfabético, y los dígitos del 0 al 9 son asignados de forma consecutiva, así como que las mayúsculas se asignan antes que las minúsculas. También cuenta con códigos de control, que no tienen 7 representación gráca y tienen un signicado especial. A continuación, en los cuadros 1 y 2 se representan algunos caracteres ISO 8859-1: Dec 32 33 47 48 49 57 Signo espacio ! / 0 1 9 Dec 65 66 67 68 69 90 Signo A B C D E Z Dec 97 98 99 100 101 122 Signo a b c d e z Dec 169 225 233 237 243 250 Signo © á é í ó ú Cuadro 1: Parte de la tabla ISO 8859-1 Dec 1 2 3 4 5 6 7 8 9 10 11 13 Abreviatura SOH STX ETX EOT ENQ ACK BEL BS HT LF VT CR Transmisiones Comienzo de cabecera Comienzo de texto Fin de texto Fin de transmisión Petición de transmisión Reconocimiento de transmisión Señal audible Retroceso Tabulación horizontal Avance de línea Tabulación vertical Retorno de carro Cuadro 2: Algunos códigos de control 3.3. Álgebra de boole El álgebra de boole es un área del álgebra en que el valor de las variables son los valores de verdad verdadero y falso, denotados como 0 y 1 comunmente. En álgebra elemental, los valores de las variables son números y las principales operaciones son la suma y multiplicación. En cambio, en el álgebra de boole las operaciones principales son la conjunción (AND) y la disjunción (OR). George Boole introdujo dicho álgebra en 1854Boole, George (1854). Más tarde, en 1938 Claude ShannonShannon, Claude E. (1937) encontró una aplicación de dicho álgebra a los circuitos eléctricos de conmutación. La lógica de boole tiene como aplicaciones 8 principales en el mundo de la computación el análisis y el diseño de circuitos. El análisis de circuitos mediante álgebra de boole permite describir el funcionamiento de los mismos. El diseño permite desarrollar implementaciones concretas de funciones de dicho álgebra. La potencia del álgebra de boole en el campo de la computación proviene de que tanto los circuitos digitales como el álgebra de boole hacen uso de información binaria, donde la unidad elemental solo puede tomar dos valores: verdadero o falso, cero o uno. 3.3.1. Denición Formalmente el álgebra de boole está compuesto por variables por y operaciones: Una variable lógica tomará uno y solo un valor, entre dos opciones posibles. Esas dos opciones posibles pueden ser cero o uno, o verdadero y falso matemáticamente, o interruptor abierto e interruptor cerrado en un circuito, o un led encendido o apagado. Operaciones binarias. Una operación binaria sobre un conjunto es un cálculo sobre dos elementos de dicho conjunto, llamados operandos, y que producen otro elemento del conjunto. Las operaciones básicas del álgebra de boole son: Suma lógica. A+B, también llamado OR. El resultado es 1 si al menos uno de los operandos vale 1, en otro caso el resultado es cero. El circuito de la gura es un ejemplo simbólico de una implementación por medio de interruptores de esta operación. También se incluye una tabla de la verdad de dicha operación. En el cuadro 3 se representa la tabla de la verdad de la suma lógica y en la gura 2 el circuito simbólico asociado. a/b 0 1 0 0 1 1 1 1 Cuadro 3: Tabla de la verdad de la suma de a y b Producto lógico. A·B, también llamado AND. El resultado es 1 si y solo si ambos operadores valen 1, en otro caso el resultado es cero. El circuito 9 Figura 2: Circuito de la suma de a y b de la gura es un ejemplo simbólico de una implementación por medio de interruptores de esta operación.También se incluye una tabla de la verdad de dicha operación. En el cuadro 4 se representa la tabla de la verdad del producto lógico y en la gura 3 el circuito simbólico asociado. a/b 0 1 0 0 0 1 0 1 Cuadro 4: Tabla de la verdad del producto de a y b Figura 3: Circuito simbólico del producto de a y b Negación lógica. a, también llamado NOT. El resultado es 1 si el operador es 0, el resultado es 0 si el operador es 1. El circuito de la gura es un ejemplo simbólico de una implementación por medio de interruptores de esta operación.También se incluye una tabla de la verdad de dicha operación. En el cuadro 5 se representa la tabla de la verdad de la negación lógica y en la gura 4 el circuito simbólico asociado. 10 a 0 1 ā 1 0 Cuadro 5: Tabla de la verdad de ā Figura 4: Circuito simbólico de ā 3.3.2. Propiedades del álgebra de boole Las operaciones denidas tienen las siguientes propiedades: Elementos neutros: Para la suma el cero es elemento neutro, es decir a+0 = a. Para el producto el 1 es el elemento neutro pues a·1 = a. Conmutatividad: Para la suma, se cumple que a + b = b + a. Para el producto se cumple que a·b = b·a. Asociatividad: Los paréntesis indican el orden en que se realizan una serie de operaciones. La asociatividad implica que (a + b) + c = a + (b + c) para la suma, y que (a·b)·c = a·(b·c) para el producto. Distributividad: Es una propiedad que implica dos reglas válidas para reemplazar una operación por otra. Implica que (a + b)·c = a · c + b · c y que a + (b · c) = (a + b) · (a + c). Leyes de Morgan, esta propiedad hace uso de las tres operaciones elementales del álgebra de boole. Implica que a + b̄ = a · b y a · b = a + b. 3.3.3. Funciones booleanas Una función es una expresión que contiene varias operaciones booleanas sobre un conjunto de variables. Existirá un valor unívoco de la función dados unos valores concretos para las variables de la función. Existen varias formas de denir la función, una forma es mediante el uso de operaciones sobre dichas variables, otra forma es mediante una tabla de la verdad que explicite el valor de la función para todas y cada una de las 11 combinaciones de valores posibles de las variables de la función. Otra forma es mediante un circuito con interruptores controlados por las variables de la función. Por ejemplo una función f(a, b, c) se puede expresar de las siguientes formas: f : (a, b, c) 7→ L = f (a, b, c) = a · b · c a 0 0 0 0 1 1 1 1 b 0 0 1 1 0 0 1 1 c 0 1 0 1 0 1 0 1 L 0 0 0 0 0 0 0 1 Cuadro 6: Tabla de la verdad de ejemplo de función booleana Figura 5: Circuito con interruptores de ejemplo de función booleana 3.3.4. Puertas lógicas La equivalencia elemental entre elementos del álgebra de boole con los dispositivos electrónicos de un computador digital está en las puertas lógicas, que son capaces de realizar operaciones y funciones booleanas. Dichas puertas lógicas no contienen partes móviles, sino que manejan el paso de señales mediante el uso de elementos electrónicos como diodos y transistores, entre otros. En la gura 6 se representan los símbolos de diferentes puertas lógicas. Las puertas lógicas elementales son: NOT. También llamado puerta NO. La tabla de la verdad se puede ver en el Cuadro 7. OR. Llamada suma lógica o puerta O. La tabla de la verdad se puede ver en el Cuadro 8. 12 a 0 1 ā 1 0 Cuadro 7: Tabla de la verdad de NO a 0 0 1 1 b 0 1 0 1 a+b 0 1 1 1 Cuadro 8: Tabla de la verdad de O AND. Producto lógico o puerta Y. La tabla de la verdad se puede ver en el Cuadro 9. a 0 0 1 1 b 0 1 0 1 a·b 0 0 0 1 Cuadro 9: Tabla de la verdad de Y NOR. También llamado O negado. La tabla de la verdad se puede ver en el Cuadro 10. a 0 0 1 1 b 0 1 0 1 a+b 1 0 0 0 Cuadro 10: Tabla de la verdad de O negado NAND. Llamado Y negado. La tabla de la verdad se puede ver en el Cuadro 11. 13 a 0 0 1 1 b 0 1 0 1 a·b 1 1 1 0 Cuadro 11: Tabla de la verdad de Y negado XOR. Suma lógica exclusiva o puerta O exclusivo. La tabla de la verdad se puede ver en el Cuadro 12. a 0 0 1 1 b 0 1 0 1 a ⊕b 0 1 1 0 Cuadro 12: Tabla de la verdad de O Figura 6: Símbolos de las puertas lógicas más comunes 14 4. Estructura general de un computador digital En este capítulo se describe la estructura de un computador digital sencillo. Para ello primero se introduce la arquitectura de Von Neumann, que es la arquitectura que usa el computador digital en que se enmarca este proyecto. A continuación se describen los principios básicos del almacenamiento de datos en una computadora digital.Después, se introduce el funcionamiento de diferentes elementos que componen un computador con la arquitectura de Von Neumann: La unidad de memoria central, que es la unidad principal de almacenamiento del computador. La unidad aritmético-lógica, que permite realizar operaciones matemáticas con datos. La unidad de entrada y salida se encarga de comunicar al computador con el exterior, ya sea con otras computadoras o periféricos. Los enlaces y buses, cuya función es conectar todos los demás elementos del computador. La unidad de control, cuya tarea es coordinar y hacer uso de los demás elementos del computador para ejecutar cada instrucción correctamente. 4.1. Arquitectura de Von Neumann La computadora digital que en este proyecto se desarrolla tiene una arquitectura de Von Neuman. El modelo de Von Neumann, o la arquitectura de Princeton deriva de la descripción de una arquitectura de computador digital realizada por el cientíco John von Neumann en 1945 von Neumann, John (1945). En dicha arquitectura existe una unidad de proceso consistente en una unidad aritmético-lógica, una serie de registros del procesador, una unidad de control que contiene un registro de instrucción y un contador de programa, una memoria para guardar instrucciones, un sistema de almacenamiento externo masivo y mecanismos de entrada y salida de datos. La arquitectura describe un computador de programa almacenado donde la búsqueda de instrucciones y el desarrollo de operaciones sobre datos no pueden ocurrir de forma simultánea porque comparten un bus común. Esta limitación se conoce como el cuello de botella de Von Neumann y a menudo limita el rendimiento del sistema. Otras 15 arquitecturas, como la llamada arquitectura de Harvard, no presentan dicho cuello de botella, pues presentan caminos diferentes para el almacenamiento y encaminamiento de señales de instrucciones y de datos. En general, un computador de programa almacenado mantiene sus instrucciones programadas y sus datos en memoria de acceso aleatorio con capacidad de escritura y lectura. La mayoría de los computadores modernos almacenan los datos y las instrucciones en una misma memoria. La gura 7 muestra un esquema de la arquitectura de Von Neumann con un único bus. Figura 7: Arquitectura de Von Neumann con un único bus 4.2. Almacenamiento de la información Un computador necesitará guardar en algún dispositivo la información si quiere poder procesarla. Como antes hemos dicho, la unidad fundamental de información de un computador digital es el bit, o dígito binario. El dispositivo físico elemental que es capaz de almacenar un bit se denomina celda o célula elemental. Existen diversos tipos de dispositivos físicos capaces de almacenar un bit. Entre ellos se encuentran los biestables. Los biestables suelen realizarse mediante circuitos electrónicos basados en las puertas lógicas que ya hemos analizado, pero la principal diferencia radica en que los biestables tienen memoria. Es decir, las salidas de un biestable no solo dependen de las entradas, sino del estado en que se encuentra, es decir dependen del valor de sus entradas anteriores. Este tipo de circuitos se llaman circuitos secuenciales. Entre los diversos tipos de biestables se encuentra el biestable RS. Se puede denir para el biestable RS una tabla de transición, que da la salida y(t1 ) en el instante t1 a 16 partir de las entradas RS y la salida y(t0 ) en el instante anterior t0 . El cuadro 13 muestra la tabla de transición del biestable RS. RS→ y(t0 )=0 y(t0 )=1 00 0 1 01 1 1 10 0 0 11 X X Cuadro 13: Tabla de transición del biestable RS El valor X para la columna RS=11 indica que el biestable no ha de usarse con esas entradas. La entrada S signica set y como se puede observar en la table, pone a 1 el biestable. La entrada R signica reset y pone a cero el biestable. Si ambas entradas están a cero, la salida del biestable será conservada. Si bien las celdas son las unidades elementales de memoria, para representar números mayores a 1 o 0 es necesario hacer uso de conjuntos de celdas, que componen un registro. Como ya se ha mencionado, un registro corresponde con una representación posicional en base 2 de un número. Por ejemplo un registro de 11 células será capaz de representar 211 =2048 números diferentes. Al equiparar un conjunto de biestables con el concepto de registro, es a menudo necesario que cuando dicho registro es actualizado todas las celdas se actualicen de forma coordinada, de forma que añadimos a los biestables una entrada de sincronismo. En el contexto de la memoria principal de un computador digital, se denen diferentes unidades de memoria, de entre las cuales ya hemos visto varias: Bit: Unidad elemental de información binaria y que se almacena en una celda elemental Byte u octeto: Formada por 8 bits, y necesita por tanto de 8 celdas de memoria. Palabra: La información almacenada en un registro de un computador se denomina palabra. Un registro puede tener cualquier número de celdas, si bien los más usuales son de 16, 32, y 64 bits o 2, 4, y 8 bytes. En la arquitectura de Von Neumann la memoria permite tanto almacenar datos como instrucciones y se denen 3 operaciones de memoria: Direccionamiento: Selecciona la información de un sector de memoria a partir de la posición (dirección) de ese sector en la memoria. 17 Lectura: Lleva a cabo una copia de la información que existen en un sector de la memoria a otro bloque del computador, como un registro o un bus. En general la lectura es no destructiva, de forma que tras la lectura del dato, el mismo sigue almacenado en memoria. Escritura: Almacena información en un sector de memoria. Es una operación destructiva de forma que el dato que había almacenado previamente en memoria es destruido y reemplazado por un nuevo dato. Existen multitud de tipos de memorias, y multitud de clasicaciones, entre otras: Tiempo de acceso: Según el tiempo que transcurre desde que se ordena la operación de memoria hasta que ésta termina. Capacidad: Se reere a la cantidad de información que es capaz de almacenar la memoria. Se suele hacer uso de los prejos kilo- y mega-, entre otros. Modo de acceso: Dene las formas en que se accede a la información, por ejemplo: Acceso directo: para acceder al dato basta con acceder a una posición de memoria conocida. El tiempo de acceso en este caso es independiente de dónde se encuentra el dato. Acceso indirecto: Para acceder al dato es necesario acceder a una posición de memoria que nos indicará en qué posición de memoria se encuentra el dato. Acceso secuencial: Para acceder al dato hemos de leer o dejar pasar la información que le precede. Volatilidad: Indica si la información almacenada puede ser modicada o destruida cuando no se suministra energía a la memoria. Las memorias de semiconductores suele ser volátil, y la de discos y cintas suele ser no volátil. Papel de la memoria en el computador: Memoria principal: En ella se almacena el programa que se está ejecutando, en general es volátil y de acceso directo y está implementada con circuitos de semiconductores. 18 Memoria auxiliar: Suele ser mucho más masiva, no volátil y suele tener un mayor tiempo de acceso. Estos dispositivos se consideran periféricos y por ello es necesario una unidad de adaptación llamada de entrada y salida para conectarla con el computador. Figura 8: Estructura matricial de una memoria La memoria principal suele implementarse con una serie de registros, todos del mismo tamaño, en una disposición matricial. Recordemos que el ancho del registro es también la longitud de una palabra en el computador. En la disposición matricial, cada columna representa un bit de cada registro, y el número de las es el número de registros. El número de las suele ser mucho mayor al de columnas, y suele ser un múltiplo de base 2. A su vez cada la, es decir, cada registro, corresponde con una única dirección de memoria, de forma que para realizar una operación de lectura o escritura sobre ese registro basta con conocer la dirección de dicho registro. Si, por ejemplo, una memoria tiene 210 registros de 16 bit cada uno, la capacidad de la memoria, en bits es de 16·210 = 16384 bits. La gura 8 muestra la estructura matricial de una memoria. La selección de una dirección de memoria es un paso que hay que realizar antes de la lectura/escritura de dicho registro. El elemento de la memoria que se encarga de realizar la selección es el decodicador de direcciones. Si por ejemplo existen 210 direcciones de memoria, para seleccionar una dirección concreta habrá que pasar una dirección de 10 bits al decodicador de direcciones. 4.3. Unidad de memoria central La unidad de memoria central contiene tanto las instrucciones del programa a ejecutar como los datos almacenados por el usuario. La gura 9 presenta el diagrama de bloques de la memoria principal. Los bloques de la unidad de memoria central son: 19 S. Es el registro que se encarga de seleccionar una dirección de memoria. Si existen 2m direcciones de memoria, el registro S tendrá un tamaño de m bits. LECM, ESCM. Señales de control, LECM de lectura, y ESCM de escritura. T. Registro de almacenamiento temporal. En caso de realizar una lectura de la memoria, el dato leído será almacenado en este registro. En caso de escritura en memoria, será el dato de este registro el que será escrito en memoria. El tamaño de este registro coincide con el tamaño de los registros de la memoria. Figura 9: Diagrama de bloques de la memoria principal Es decir, para realizar una operación de lectura: En primer lugar es necesario seleccionar la posición de memoria que vamos a leer. Para ello introducimos la dirección de memoria en el registro S. Después activamos la señal LECM, de forma que el dato de la dirección seleccionada es copiado al registro T. Finalmente copiamos el contenido del registro T al lugar de destino (un bus u otro registro). Los pasos para una operación de escritura son parecidos: En primer lugar es necesario seleccionar la posición de memoria en la que vamos a escribir. Para ello introducimos la dirección de memoria en el registro S. Copiamos el dato que queremos escribir en el registro T. 20 Finalmente copiamos el contenido de T en la posición adecuada en la memoria, activando la señal de control ESCM. 4.4. Unidad aritmético-lógica Un elemento muy importante del computador digital es la unidad aritmético lógica. Esta unidad es capaz de realizar operaciones aritméticas y lógicas sobre una o varias señales de entrada. Para ello hace uso de circuitos electrónicos con puertas lógicas y del álgebra de boole. Algunas operaciones aritméticas comunes de una UAL son la suma, resta, multiplicación o división. Ejemplo de operaciones lógicas son comparaciones de igualdad. La gura 10 representa el diagrama de bloques de una UAL. Figura 10: Diagrama de bloques de una UAL, su acumulador, y señales de control De forma frecuente, el resultado de las operaciones de la UAL se guarda en un registro Acumulador, el cual a su vez se retroalimenta como operando de la UAL. De este modo, por ejemplo, para realizar una suma: Primero se lleva el primer operando a la UAL, y con la señal de control CARGA el operando pasa al acumulador. Después se lleva el segundo operando a la entrada de la UAL. Como el primer operando está en el Acumulador y éste está retroalimentado a la UAL, en este momento los dos operandos están como sendas entradas de la UAL, por lo que ahora se activa la señal de control SUMA, realizando de forma efectiva la suma. 21 Finalmente el resultado, que está en el acumulador, se puede transferir a otros elemenos del computador. Puesto que el resultado de la UAL solo depende de las señales de control y operandos de entrada en un momento dado, para crear una UAL simple basta con hacer uso de circuitos combinacionales. Por ejemplo, un circuito multiplicador de números de dos bits tiene la tabla de la verdad del cuadro 14, que habrá que implementar con puertas lógicas: a1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 a0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 b1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 b0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 m3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 m2 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 m1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 m0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 Cuadro 14: Tabla de la verdad de circuito multiplicador 4.5. Unidad de entrada y salida Las computadoras interaccionan con el exterior por medio de los periféricos. Esta interacción con el exterior es necesaria para que una computadora resulte de alguna utilidad. Los periféricos más comunes son el teclado y la pantalla. Una característica típica de los periféricos es la diferente velocidad o tasa de transmisión de datos entre diferentes periféricos. El computador ha de ser capaz de tratar con periféricos que se comunican con éste a muy diversas velocidades. Por ejemplo, una pantalla puede necesitar recibir varios megabits de datos por segundo y un teclado normalmente no va a enviar más de 20 caracteres por segundo. Por lo general, 22 son los propios periféricos los que cuentan con los adaptadores necesarios para poderse comunicar con el computador de forma adecuada. El computador digital que aquí se desarrolla cuenta solo con dos periféricos: un teclado y una pantalla. Otros periféricos comunes para computadoras digitales son el ratón, la impresora y dispositivos de almacenamiento masivo. Teclado de computador. Es un dispositivo con botones o teclas dispuestas de forma similar a en una máquina de escribir, que actúan como conmutadores electrónicos. La pulsación de dichas teclas, ya sea de forma individual o de forma combinada, es detectada por el teclado y manda al computador señales codicadas de caracteres de texto, números y señales de control. Dicha información es leída de forma periódica por el computador. La velocidad de transmisión de los teclados suele ser baja (del orden de 10 caracteres por segundo). Monitor de visualización. Es una pantalla electrónica de visualización de datos. Cuando un programa quiere que el usuario reciba datos, éstos son mandados al monitor o pantalla. Existen multitud de tipos de pantallas, como por ejemplo las pantallas de tubos de rayos catódicos y las pantallas planas LCD. A su vez las pantallas pueden comunicarse a más o menos velocidad con el computador, si bien por lo general la velocidad de transmisión requerida por una pantalla es superior a la requerida por un teclado. El uso de un monitor requiere de un dispositivo llamado tarjeta de vídeo que funcione como intermediario y adaptador entre ésta y el computador. La resolución de la pantalla, la cantidad de colores disponibles, así como el ratio de refresco de la misma, son factores que imponen requerimientos mínimos en la cantidad de memoria y potencia de cálculo necesarias para que un computador pueda hacer uso de una pantalla. 4.6. Enlaces o buses Los enlaces, o buses en inglés, cumplen el objetivo de conectar los diferentes elementos del computador. La forma más básica de conectar una serie de dispositivos es conectarlos todos con todos, pero si tenemos n dispositivos eso signica tener n(n−1) conexiones 2 bidireccionales, con lo que el número de conexiones necesarias para un número no muy grande de dispositivos es poco factible. En un bus de datos, varios dispositivos se conectan a un mismo bus, y en un momento dado solo existirá una fuente de datos, pudiendo recibir esos datos todos los demás 23 dispositivos. Es decir, un dispositivo hablará y los demás estarán a la escucha. Los enlaces entre dispositivos mediante un mismo bus tienen diversas ventajas, entre ellas: Número reducido de conexiones necesarias. Simplicación del sistema, de forma que cada dispositivo solo necesita una entrada y una salida. Facilidad para la expansión, es decir, facilidad para añadir mas dispositivos. Facilidad de implementación en circuitos electrónicos. Posibilidad de que los dispositivos se encuentren a distancias grandes unos de otros. Figura 11: Control de conexión de un dispositivo a un enlace con puertas triestado A su vez los buses tienen algunos inconvenientes, como un mayor tiempo de transmisión, ya que varios dispositivos que quieran transmitir a la vez no podrán hacerlo, alguno tendrá que esperar. Para evitar colisiones de mensajes, existen protocolos que por ejemplo delimitan los momentos en que los dispositivos pueden comenzar a hablar. En general, por cada dispositivo existirá una señal de gobierno que marcará si el dispositivo accede al bus (ya sea para leer o para escribir en él). La señal de gobierno se suele conectar a puertas triestado, de forma que cuando la señal de gobierno es cero, la salida uctúa libremente tomando el valor que otro dispositivo le impone, y cuando es uno, la puerta transmite la información a la salida. La gura 11 representa el control de conexión de un dispositivo a un enlace con puertas triestado. 4.7. Unidad de control La unidad de control se encarga de interpretar las instrucciones a ejecutar, y mandar las señales de control necesarias a los elementos correspondientes del computador, en el 24 tiempo y orden adecuados según la instrucción. Es decir, la ejecución de una instrucción se realiza activando señales de gobierno, a las que se denomina microórdenes. Estas microórdenes se ejecutan todas dentro de un solo ciclo de reloj (el tiempo de ejecución de una instrucción, por lo general). Se denomina cronograma de operaciones de una instrucción a la representación temporal de la evolución de las distintas señales de gobierno y control activadas en dicha instrucción. Cada arquitectura de computador tiene cronogramas diferentes para cada instrucción, pues dichos cronogramas dependen de la arquitectura especíca del computador. En la próxima sección se desarrollará la unidad de control especíca del computador que describe este documento. Un tipo de unidades de control es el llamado unidad de control cableada. Esta unidad se implementa con una serie de circuitos lógicos y biestables que activa y desactiva las señales de control y gobierno en el momento adecuado en cada tipo de instrucción. Como cada instrucción necesita de un cronograma diferente, el circuito de las unidades de control cableadas suele ser complejo, sobre todo cuantas más instrucciones diferentes implemente el computador. Otro tipo de unidades de control son las unidades de control microprogramadas, que hacen uso de una micro-memoria, eliminando la complejidad del sistema. 25 26 5. Descripción de la máquina a implementar Este capítulo describe el computador que el software Xenon ha de implementar. En la primera sección se enumeran los elementos de dicho computador, incluyento entre otros los registros y las señales de control. Sigue un apartado que explica cómo procede la ejecución de una instrucción del computador. A continuación se describe el código máquina del computador, que es el código binario que maneja el computador. Después se detalla el código ensamblador, que es un lenguaje simbólico más sencillo de usar por una persona que el código máquina. El capítulo termina con una serie de ejemplos de programas escritos en lenguaje ensamblador. 5.1. Elementos del computador Figura 12: Esquema de una computadora digital mostrando los enlaces y las señales de gobierno. El computador implementa una arquitectura basada en la de Von Neumann, donde los periféricos de la unidad de entrada y salida son la pantalla y el teclado. Los elementos con que cuenta el computador y que aparecen en la gura 12 son: 1. Un enlace M que une la memoria, la unidad de control y la UAL. La información que se o transmite puede ser de diversas clases: datos y resultados de operaciones, instrucciones del programa y direcciones de memoria. 2. Otro enlace S que une la unidad de control y el selector de posiciones de memoria. Por él se transmiten direcciones de memoria. 3. La memoria principal, con organización matricial. 27 4. La UAL con registro acumulador que almacena uno de los operandos y el resultado de las operaciones. 5. Los siguientes registros: A. Registro acumulador de la UAL. S. Registro de selección de memoria. T. Registro tampón de comunicación entre la memoria y la línea M. P. Contador de pasos de programa. Indica la posición dentro de la memoria de la o instrucción a ejecutar. I. Registro de instrucción. Guarda en cada momento la instrucción que se ejecuta en o o ese paso. E. Registro de comunicación con el exterior. Permite tomar datos del teclado o llevarlos o a la pantalla. Es una forma simple e idealizada de la unidad de control que se ha descrito anteriormente. 6. Las señales del computador: EA. Señal de escritura en el registro A. Guardará en A el resultado de la ALU. Si además de EA, la señal EO está activada pero las señales SUMA, RESA, MULTA, DIVA y MODA no están activadas, la ALU leerá el bus M y será el dato del bus M el que se guarde en el registro A. SA. Permite escribir el dato del registro A en el bus M. EO. Asigna el dato del bus M a la entrada de la ALU. SUMA. Realiza la operación suma A+M en la ALU de los datos de A y del bus M (si la señal EO está activada). RESA. Realiza la operación resta A−M en la ALU de los datos de A y del bus M (si la señal EO está activada). MULTA. Realiza la operación multiplicación A·M en la ALU de los datos de A y del bus M (si la señal EO está activada). DIVA. Realiza la operación división A/M en la ALU de los datos de A y del bus M (si la señal EO está activada). 28 MODA. Realiza la operación división Amod M en la ALU de los datos de A y del bus M (si la señal EO está activada). INCP. Incrementa P en una unidad. EP. Asigna al registro P el valor del bus S. SP. Escribe el valor del registro P en el bus S. ES. Escribe el valor del bus S en el registro S, seleccionando dicha posición de memoria. SD. Escribe el valor del registro D (los 11 bits menos signicativos del registro I) en el bus S. EI. Escribe el valor del bus M en el registro I. LECM. Lee la posición de memoria seleccionada por el registro S y la escribe en el registro T. ESCM. Escribe el valor del registro T en la posición de memoria seleccionada por el registro S. ET. Escribe el valor del bus M en el registro T. ST. Escribe el valor del registro T en el bus M. EE. Escribe el valor del bus M en el registro E. SE. Escribe el valor del registro E en el bus M. LEET. Lee el valor de los datos de entrada del teclado y lo escribe en el registro E. ESCP. Muestra en la consola el valor del registro E. 5.2. Funcionamiento del computador Como ya se ha mencionado con anterioridad, el computador que aquí se presenta es una máquina de programa almacenado, de modo que en la memoria se almacenan tanto datos como instrucciones.El computador cuenta con la mayoría de los dispositivos ya mencionados, conectados a través de enlaces de tipo bus, permitiendo la transferencia de información de un dispositivo a otro. La unidad de control es el elemento que envía órdenes a todos los demás. El programa se encuentra almacenado en memoria, con las instrucciones situadas de forma secuencial. La unidad de control se encargará de ir leyendo y ejecutando las 29 instrucciones del programa en el orden adecuado. La unidad de control cuenta con un registro P que guarda la posición de memoria de la instrucción que se ejecuta. En general el valor del registro P se incrementa en una unidad tras ejecutar cada instrucción, si bien existen como excepciones las instrucciones de salto. El registro P sirve para localizar la instrucción a ejecutar. Después de ser localizada en memoria, dicha instrucción se copia al registro I. Entonces la unidad de control interpreta la instrucción y activa las señales de gobierno que correspondan con dicha instrucción en el orden adecuado. Una instrucción, que al n y al cabo es un número que es guardado en el computador en binario, se puede dividir en tres partes: Código de operación (CO): Indica la operación a realizar. En este computador consta de 4 bits, de modo que existen hasta 16 operaciones diferentes. Modo de direccionamiento (MD): El computador trabajará con modos de direccionamiento directo e indirecto. Como solo trabajaremos con esos dos posibles modos de direccionamiento, usaremos 1 bit para indicar el modo. En el modo directo el operando es la dirección del dato, o de la posición de memoria donde se guardará el resultado de la operación. Dirección de memoria u operando: Esta dirección tendrá diferentes signicados dependiendo del código de operación y del modo de direccionamiento. Por ejemplo, en la suma directa indica la dirección de memoria donde se encuentra el dato a sumar. La dirección de memoria consta de 11 bits. En total una instrucción está formada por 16 bits, que a su vez es la longitud de cada registro en la memoria principal. A su vez, las direcciones de memoria tienen una longitud de 11 bits, lo cual permite direccionar 211 =2024 direcciones de memoria, de forma que la memoria principal tiene una capacidad total de 16·2048 = 32738 bits = 4 kilobytes. Como ejemplo, podemos analizar la instrucción del cuadro 15: CO 0101 MD 0 D 000 0000 1000 Cuadro 15: Ejemplo de instrucción El código de operación 0101 indica en este caso sumar al acumulador el contenido de una dirección de memoria. El modo de direccionamiento 0 es directo, de forma que 30 el el dato a sumar se encuentra en la dirección 000 0000 1000, que corresponde en base 2 con la dirección 8. 5.2.1. Ejecución de instrucciones La ejecución de cada instrucción se divide en 4 fases. Las fases corresponden con acciones diferentes en cada instrucción. Estas fases se representan en la gura 13 para el caso sencillo de una suma. Figura 13: Fases de la ejecución de la instrucción suma. Búsqueda de la instrucción. En la gura P indica que la instrucción está en la dirección de memoria 17. Se direcciona dicha posición de memoria copiado P al registro S. Luego realiza una lectura y se copia el contenido de la memoria en esa posición al registro I, que pasa a contener la dirección a ejecutar. Búsqueda del operando. En este caso el operando está en la posición de memoria 8, luego el computador direcciona dicha posición copiando 8 al registro S. Ejecución de la instrucción. El contenido de memoria en dicha posición es leído y se traslada al registro de operando de la UAL. Entonces se realiza la suma del acumulador con el operando, y dicha suma se guarda en el registro acumulador. Preparación de la siguiente instrucción. Se incrementa en una unidad el registro P, que pasará a contener la posición de memoria de la siguiente instrucción. 31 La ejecución de una instrucción es dirigida por la unidad de control mediante cambios en las señales de gobierno, que permiten realizar tanto operaciones como transferencias entre registros. Una descripción más formal de la ejecución de una instrucción es aquella en que se detallan las transferencias entre los registros, a la vez que las operaciones aritméticas y de lectura y escritura en memoria. Por ejemplo, la ejecución de la instrucción descrita anteriormente se puede describir de la siguiente forma: Búsqueda de la instrucción. Se lee de memoria la instrucción a ejecutar, que está en la dirección que indica el registro P. Las operaciones elementales a realizar son: Direccionamiento: Transferir a S el contenido de P, se simboliza mediante (P)→S. Lectura de memoria: Se transere al registro T el dato guardado en la posición de memoria direccionada: M(S)→T Transferencia del registro T al registro I, que es el registro que la unidad de control interpreta como instrucción: T→I Búsqueda del operando: En la instrucción de este ejemplo, el código de operación corresponde a una suma, y el direccionamiento es directo, de forma que el operador está en la posición de memoria que indica D. Para leer el operando: Direccionamiento de D: (D)→S. Lectura de memoria: M(S)→T. Lee la posición de memoria direccionada, copiándola al registro T. Ejecución de la instrucción. Se realiza la operación de suma y ésta se guarda en el registro acumulador. Es decir, (T)+(A)→A. Preparación de la siguiente instrucción. En el caso de la suma, la siguiente instrucción viene dada por P+1, de modo que P+1 →P. Este método de representación de operaciones consiste en detallas las transferencias elementales entre registros. Es importante recalcar que dichas transferencias y operaciones son llevadas a cabo por la unidad de control mediante la activación coordinada, por parte de dicha unidad de control, de las diversas señales de gobierno que posee el computador. Por ejemplo, para escribir en el registro T será necesario activar ET y para leer T habrá que activar ST. 32 5.2.2. Instruciones de salto En multitud de instrucciones, tras su ejecución el registro P contador de pasos se incrementa en la unidad. Existe otro tipo de instrucciones que realizan saltos entre instrucciones, de una posición de memoria a otra. Por ejemplo, la instrucción de salto incondicional carga en P la dirección del operando de dicha instrucción, de forma que tras esta instrucción será la instrucción situada en esa posición la que se ejecutará. De este modo, los pasos de ejecución de la instrucción salto incondicional son: Búsqueda de la instrucción. Se lee la instrucción que se va a ejecutar a partir del conocimiento de su posición en la memoria, dato contenido en el registro P. Direccionamiento: Transferir a S el contenido de P, se simboliza mediante (P)→S. Lectura de memoria: Se transere al registro T el dato guardado en la posición de memoria direccionada: M(S)→T Transferencia del registro T al registro I, que es el registro que la unidad de control interpreta como instrucción: T→I Búsqueda del operando. El operando de la instrucción es directamente D, de forma que no hace falta acceder a la memoria principal para acceder al operando. Ejecución de la instrucción. En este caso solo es necesario transferir el contenido de D al registro P. (D)→P Preparación de la siguiente instrucción. Normalmente esto signicaría modicar el registro P, pero en el caso de las instrucciones de salto esto ya se realiza en la fase de ejecución de la instrucción, así que en esta fase no hacemos nada. Si bien la instrucción de salto incondicional es la más sencilla dentro de las instrucciones de salto, existen instrucciones de salto llamadas condicionales, de forma que el resultado de la ejecución de la instrucción, esto es el contenido del registro P, será uno u otro dependiendo de si se cumple cierta condición. Esta condición puede ser por ejemplo una comparación. Este tipo de instrucciones es importante a la hora de realizar lo que se denominan bifurcaciones en un programa. 33 5.2.3. Funcionamiento de la unidad de control La unidad de control de interpretar las instrucciones a ejecutar y activar las señales de gobierno o control adecuadas para asegurar su ejecución. Como ya se ha mencionado la ejecución de cada instrucción se divide en una serie de etapas, en las cuales se activarán unas señales de gobierno u otras dependiendo de la instrucción que se esté tratando (concretamente dependiendo del código de operación y modo de direccionamiento). La activación de las señales de gobierno en el transcurso de la ejecución de la instrucción se denomina microórdenes. La gura 14 muestra un diagrama de la unidad de control. Las microórdenes tienen como objetivo realizar transferencias entre registros, así como realizar operaciones sobre el contenido de los mismos. La complejidad de un cronograma depende de factores como la cantidad de registros del computador, la complejidad de la UAL o la diversidad de instrucciones que implementa el computador. El diseñador de la computadora tendrá que encargarse de realizar el cronograma de cada instrucción, y a partir de él crear un diseño de circuitos combinacionales y secuenciales que implemente físicamente la unidad de control. El circuito de la unidad de control suele ser complejo y como ya se ha mencionado con anterioridad existe otra opción para su realización, ideada por Wilkes, que trata de evitar dicha complejidad haciendo uso de una memoria especial donde se guarden las microórdenes. Figura 14: Diagrama de bloques de la unidad de control Para visualizar el trabajo de la unidad de control es útil representar el estado de las señales de gobierno utilizadas por la instrucción a través del tiempo, en lo que se denomina un cronograma. En los cronogramas, el eje horizontal representa el transcurso del tiempo y en el vertical se representa el voltaje o estado activado/alto y desactivado/bajo de las diferentes señales. A su vez, en la parte superior se ha representado la señal de reloj del computador. 34 La señal de reloj ha sido dividida en cuatro diferentes fases (θ1 ,θ2 ,θ3 ,θ4 ), que a su vez pueden ser agrupadas en dos etapas principales: Ciclo de instrucción. Ocupa las fases θ1 y θ2 . Se lee de la memoria principal la instrucción a ejecutar y se carga en el registro I. Ciclo de operando. Ocupa las fases θ3 yθ4 y en dicho ciclo se realiza la búsqueda del operando, la ejecución de la operación, y la preparación de la siguiente instrucción. Figura 15: Cronograma de la instrucción suma 5.3. Código máquina Las instrucciones que procesa un computador digital forman un lenguaje del tipo denominado código máquina o código binario. Recordemos que el computador digital maneja solo números binarios, de modo que el código máquina es directamente escrito en binario. Como el código máquina del juego de instrucciones del computador, los lenguajes de código máquina son muy dependientes de la arquitectura de cada computador, y por tanto el código de un programa es difícilmente transportable a otras arquitecturas. El lenguaje de código máquina es el tipo de lenguaje más primitivo en que un programa se puede escribir, y por ello es un lenguaje de bajo nivel, pues no está pensado para que sea fácil de usar y entender por parte de un humano y es poco transportable. Los lenguajes de más alto nivel son más transportables y fáciles de entender por las personas. Una ventaja de los lenguajes de código máquina es que permiten escribir los programas de la forma más eciente. El computador en que se enmarca este proyecto tiene una longitud de instrucción de 16 bits, que como ya se ha explicado se divide en 3 partes: el código de operación, el modo de direccionamiento y el operador o dirección. El código de operación cuenta con 4 bits, el modo de direccionamiento de un bit y el operador cuenta con 11 bits. 35 En el cuadro 16 se puede ver el código de un pedazo de un programa. El programa leerá dos números del teclado, los guardará en las posiciones de memoria 10 y 11, los sumará y guardará el resultado en la posición de memoria 12, para nalmente mostrar el resultado en pantalla. Si bien este programa es muy simple, realizar programas no mucho más complejos en código binario se hace una tarea demasiado tediosa y cada vez más difícil. Por esa razón se diseñaron lenguajes cada vez más sencillos de usar y entender. El próximo paso en facilidad de uso es el código mnemotécnicos. Dirección 50 CO 0100 MD 0 D 000 0000 1010 51 0100 0 000 0000 1011 52 0010 0 000 0000 1010 53 0101 0 000 0000 1011 54 0001 0 000 0000 1100 55 0011 0 000 0000 1100 56 0000 0 000 0000 0000 Signicado Leer del teclado un número y guardarlo en la posición de memoria 10 Leer del teclado un número y guardarlo en la posición de memoria 11 Llevar al acumulador el valor de la posición de memoria 10 Sumar al acumulador el número guardado en la posición de memoria 11 Almacenar el valor del acumulador en la posición de memoria 12 Escribir en pantalla el valor de la posición de memoria 12 Parar la máquina Cuadro 16: Ejemplo de programa en código máquina para el computador 5.4. Lenguaje ensamblador Un lenguaje ensamblador es un lenguaje de programación de bajo nivel que se usa para programara computadores, microprocesadores, microcontroladores etc. Implementa una representación simbólica (o código mnemotécnico) de los códigos de máquina binarios, así como de una serie de pseudoinstrucciones. El código máquina ha de ser traducido a código máquina por un programa de traducción. Mientras que la traduc- 36 ción de los códigos mnemotécnicos a código máquina es directa, las pseudoinstrucciones requieren que el programa traductor realice tareas adicionales durante la traducción, como por ejemplo situar constantes en posiciones concretas de la memoria, situar ciertas instrucciones a partir de cierta posición de memoria o traducción de etiquetas del código ensamblador a posiciones de memoria de código máquina. Tanto las instrucciones del procesador como los registros y posiciones de memoria, y las pseudoinstrucciones, son especícos de cierta arquitectura de computador, con lo que el código generado no es directamente portable a otra arquitectura diferente. Esta es una característica común en lenguajes de bajo nivel. El lenguaje ensamblador de la máquina virtual implementada en este proyecto cuenta con las instrucciones denidas en los cuadros 17 y 18. En el cuadro 19 se muestra un ejemplo de programa en código ensamblador. A su vez el lenguaje ensamblador implementa las siguientes pseudoinstrucciones: ORG Sirve para indicar en qué dirección de memoria comenzarán a colocarse las instrucciones y espacios para datos y resultados al realizarse la traducción. Permite al programador o indicar de forma simple dónde va a ir ubicado su programa dentro de la memoria. ESP Sirve para dejar un espacio en la memoria en el cual no habrá ninguna Este tipo de espacios se utiliza para datos y resultados. instrucción. CTE Es similar a ESP pero además deja un valor en el espacio. Permite tener constantes que el programa vaya a necesitar, por ejemplo el número dos en caso de que se necesite realizar una media, etc. FIN Indica al traductor que cese la traducción. No debe confundirse con ALT que es la instrucción de parada de la máquina. DRE Signica Dirección Representada por la Etiqueta. Guarda como constante en memoria la posición de memoria en que se encuentra la etiqueta que toma como parámetro esta pseudoinstrucción. 37 CO MD Código Operación realizada 0000 0001 0 0 ALT ALM 0001 1 ALMI Parar la máquina Almacenar el contenido del acumulador en la memoria Almacenar indirectamente 0010 0 CAR 0010 0011 1 0 CARI ESC 0011 1 ESCI 0100 0100 0101 0 1 0 LEE LEEI SUM Cargar de la memoria al acumulador Cargar indirectamente Escribir un entero en la pantalla Escribir indirectamente un entero en la pantalla Leer un entero del teclado Leer indirectamente Sumar al acumulador 0101 1 SUMI Sumar indirectamente 0110 0 RES Restar al acumulador 0110 1 RESI Restar indirectamente 0111 0111 0 1 MUL MULI Multiplicar por A Multiplicar indirectamente 1000 0 DIV 1000 1 DIVI Dividir el acumulador entre el operando Dividir indirectamente 1001 0 MOD 1001 1 MODI 1010 1010 0 1 SAL SALI Módulo del acumulador o y el operando Módulo realizado o indirectamente Salto incondicional Salto incondicional indirecto Transferencia entre registros (A)→M(D), P→(P) + 1 (A)→M(M(D)), P→(P) + 1 M(D)→A, P→(P) + 1 M(M(D))→A, P→(P)+ 1 M(D)→E, P→(P) + 1 M(M(D))→E, P→(P) + 1 E→M(D), P→(P) + 1 E→M(M(D)), P→(P)+1 (A) + M(D)→A, P→(P) + 1 (A) + M(M(D))→A, P→(P) + 1 (A) - M(D)→A, P→(P) + 1 (A) - M(M(D))→A, P→(P) + 1 (A)·M(D)→A, P→(P) + 1 (A)·M(M(D))→A, P→(P) + 1 (A) / M(D)→A, P→(P) + 1 (A) / M(M(D))→A, P→(P) + 1 (A) mod M(D)→A, P→(P) +1 (A) mod M(M(D))→A, P→(P) + 1 (D)→P M(D)→P Cuadro 17: Las columnas indican el código de operación, modo de direccionamiento, el código mnemotécnico y una somera explicación para cada una de las instrucciones de CESIUS. 38 CO MD Código Operación realizada 1011 0 SAN Salto si A es negativo 1011 1 SANI 1100 0 SAC Salto indirecto si A es negativo Salto si A es cero 1100 1 SACI Salto indirecto si A es cero 1101 0 SAP Salto si A es positivo 1101 1 SAPI 1110 0 ECA 1110 1 ECAI 1111 1111 0 1 LCA LCAI Salto indirecto si A es positivo Escribir carácter a en la pantalla Escribir carácter a indirectamente Leer carácter Leer carácter a indirectamente Transferencia entre registros (D)→P si (A)<0 si no P→(P) + 1 M(D)→P si (A)<0 si no P→(P) + 1 (D)→P si (A)=0 si no P→(P) + 1 M(D)→P si (A)=0 si no P→(P) + 1 (D)→P si (A)>0 si no P→(P) + 1 M(D)→P si (A)>0 si no P→(P) + 1 M(D)→E, P→(P) + 1 M(M(D))→E, P→(P) + 1 E→M(D), P→(P) + 1 E→M(M(D)), P→(P)+1 Cuadro 18: Las columnas indican el código de operación, modo de direccionamiento, el código mnemotécnico y una somera explicación para cada una de las instrucciones de CESIUS (Continuación). Instrucción LEER LEER CARGAR SUMAR ALMACENAR ESCRIBIR PARAR 10 11 10 11 12 12 Dirección 20 21 22 23 24 25 26 CO 0100 0100 0010 0101 0001 0011 0000 MD 0 0 0 0 0 0 0 D 00000001010 00000001011 00000001010 00000001011 00000001100 00000001100 00000000000 Cuadro 19: Ejemplo de programa. A la izquierda se presenta una lista de las operaciones a efectuar, a la derecha se tiene el programa en la memoria. El contenido de los registros de la memoria se ha separado en tres bloques (CO, MD y D) para facilitar el estudio, dicha separación no existe en la realidad. 39 5.5. Ejemplos 5.5.1. Media de tres números Este programa calcula la media de tres números. Primero el programa pide tres números, los cuales almacena en memoria. Después calcula la media y nalmente muestra en pantalla dicha media. El cuadro 20 presenta el código ensamblador del programa, y la gura 16 el esquema de funcionamiento del mismo. A: B: C: TRES: RES: INI: ORG SAL ESP ESP ESP CTE ESP LEE LEE LEE CAR SUM SUM DIV ALM ESC ALT FIN 0 INI 1 1 1 3 1 A B C A B C TRES RES RES Cuadro 20: Código mnemoténico de programa que realiza media de tres números 40 Figura 16: Esquema del funcionamiento del programa que realiza media de tres números 5.5.2. Cálculo de número primo Este programa comprueba si un número es primo. En primer lugar el programa pide un número N al usuario, que es guardado en memoria. Después el programa calcula si el resto de dividir N entre los números 2 a N-1 es cero para alguno de ellos, en cuyo caso N no sería primo. Si N es primo, el programa escribirá '0' en pantalla. Si es primo, escribirá '1' en pantalla. El cuadro 21 presenta el código ensamblador del programa, y la gura 17 el esquema de funcionamiento del mismo. 41 PRIMO: CONTADOR: SI: NO: INI: BUCLE PRINTSI: PRINTNO: ORG SAL ESP CTE CTE CTE LEE CAR RES SAC CAR MOD SAC CAR SUM ALM SAL ESC ALT ESC ALT FIN 0 INI 1 2 1 0 PRIMO PRIMO CONTADOR PRINTSI PRIMO CONTADOR PRINTNO CONTADOR SI CONTADOR BUCLE SI NO Cuadro 21: Código Mnemotécnico de programa que calcula si un número es primo Figura 17: Diagrama de funcionamiento delprograma que calcula si un número es primo 42 5.5.3. Módulo al cuadrado de un vector Este programa calcula el módulo de un vector de cuatro componentes. El programa pide cuatro números como datos de entrada, los cuales guarda en memoria. Después calcula la suma de los cuadrados de las componentes del vector, es decir, el módulo al cuadrado del vector. Finalmente el programa muestra el número calculado en pantalla. El cuadro 22 presenta el código ensamblador del programa, y la gura 18 el esquema de funcionamiento del mismo. VECTOR: TAM: RES: PUN: VPOS: UNO: INI: LEER: PRINT: ORG SAL ESP CTE ESP ESP DRE CTE CAR ALM CAR SUM RES SAC LEEI CARI MULI SUM ALM CAR SUM ALM ESC ALT FIN 0 INI 4 4 1 1 VECTOR 1 VPOS PUN VPOS TAM PUN PRINT PUN PUN PUN RES RES PUN UNO PUN RES Cuadro 22: Código Mnemotécnico de programa que calcula el módulo al cuadrado de un vector de 4 componentes 43 Figura 18: Diagrama de funcionamiento delprograma que calcula el módulo al cuadrado de un vector de 4 componentes 5.5.4. Frase o palabra en orden inverso Este programa pide caracteres como datos de entrada, los cuales guarda en memoria, hasta que el usuario escriba un punto. Entonces el programa escribe los caracteres introducidos en orden inverso. El cuadro 23 presenta el código ensamblador del programa, y la gura 19 el esquema de funcionamiento del mismo. 44 P: PUNTO: VPOS: UNO: INI: LEER: PRINT: PARAR: FRASE: ORG SAL ESP CTE DRE CTE CAR ALM LCAI CARI RES SAC CAR SUM ALM SAL CAR RES SAC CAR RES ALM ECAI SAL ALT ESP FIN 0 INI 1 46 FRASE 1 VPOS P P P PUNTO PRINT P UNO P LEER P VPOS PARAR P UNO P P PRINT 100 Cuadro 23: Programa que escribe una frase en orden inverso 45 Figura 19: Diagrama de funcionamiento de programa que escribe una frase en orden inverso 5.5.5. Lectura de una matriz Este programa guarda en memoria una matriz. Para ello primero pide dos números 'm' y 'n' como parámetros de entrada, que corresponden con el número de las y columnas de dicha matriz. Se supone que m · n < 50. A continuación el usuario introduce los elementos de dicha matriz. El cuadro 24 presenta el código ensamblador del programa, y la gura 20 el esquema de funcionamiento del mismo. 46 M: N: MATA: DCM: K: J: PUN: UNO: INI: BUCLK: BUCLJ: ORG SAL ESP ESP ESP DRE ESP ESP ESP CTE LEE LEE CAR ALM CAR ALM CAR RES MUL SUM RES SUM ALM LEEI CAR SUM ALM RES SAN SAC CAR SUM ALM RES SAN SAC ALT FIN 0 INI 1 1 50 MATA 1 1 1 1 M N UNO K UNO J K UNO N J UNO DCM PUN PUN J UNO J N BUCLJ BUCLJ K UNO K M BUCLK BUCLK Cuadro 24: Programa que almacena una matriz 47 Figura 20: Diagrama de funcionamiento de programa que almacena una matriz 5.5.6. Submatriz triangular Programa que lee una matriz y luego escribe los elementos de su submatriz triangular inferior en el orden indicado en la gura. La submatriz triangular inferior está formada por los elementos de la diagonal de la matriz y los de debajo. Los cuadros 25 y 26 presenta el código ensamblador del programa, y la gura 21 el esquema de funcionamiento del mismo. 48 M: N: MATA: DCM: K: J: PUN: UNO: INI: BUCLK: BUCLJ: BSK: ORG SAL ESP ESP ESP DRE ESP ESP ESP CTE LEE LEE CAR ALM CAR ALM CAR RES MUL SUM RES SUM ALM LEEI CAR SUM ALM RES SAN SAC CAR SUM ALM RES SAN SAC CAR ALM CAR ALM 0 INI 1 1 50 MATA 1 1 1 1 M N UNO K UNO J K UNO N J UNO DCM PUN PUN J UNO J N BUCLJ BUCLJ K UNO K M BUCLK BUCLK UNO K UNO J Cuadro 25: Programa que lee una matriz y luego escribe los elementos de su submatriz triangular 49 BSJ: CAR RES MUL SUM RES SUM ALM ESCI CAR SUM ALM RES SAN SAC CAR SUM ALM RES SAN SAC ALT FIN K UNO N J UNO DCM PUN PUN J UNO J K BSJ BSJ K UNO K M BSK BSK Cuadro 26: Programa que lee una matriz y luego escribe los elementos de su submatriz triangular (continuación) 50 Figura 21: Diagrama de funcionamiento de programa que lee una matriz y luego escribe los elementos de su submatriz triangular 51 52 6. Estructura del emulador El programa desarrollado es un emulador de un computador digital sencillo denominado Xenon, que cuenta con las instrucciones de código máquina que se han descrito en secciones previas. Este programa está implementado en lenguaje Java, lo cual permite que un mismo ejecutable pueda ser usado sin modicación alguna en muy diversas arquitecturas y sistemas operativos. Este programa no solo sirve como emulador de dicho computador, sino como plataforma de desarrollo y depuración de aplicaciones en lenguaje ensamblador para dicho computador. Existen tres partes diferenciadas en este programa, que corresponden con tres vistas diferentes de la aplicación: Vista de desarrollo: Esta vista permite al usuario crear y gestionar proyectos y código ensamblador, además de permitir acceder al resto de vistas. Desde esta vista será posible compilar el código ensamblador para pasarlo a código binario. Vista de depuración: Desde la vista de depuración, el usuario puede controlar la ejecución de un programa. El depurador puede abrir tanto archivos en código ensamblador como en código binario. Vista de emulación: Esta vista abre el emulador del computador digital. Puesto que el computador digital solo entiende código binario, el emulador solo es capaz de ejecutar código binario. La sección de manual de usuario describe de forma más detallada el aspecto visual de cada vista. Tal y como describe la sección de manual de usuario, el programa cuenta con dos ejecutables. El ejecutable xenon.main.jar abre la vista de desarrollo, desde la cual se puede acceder a las demás vistas. El ejecutable xenon.emu.jar es una versión standalone del emulador, de forma que no sea necesario abrir el entorno de desarrollo para emular la ejecución de un programa en el computador digital. 6.1. Código ensablador y código binario Los dos lenguajes que entiende este computador son el código ensamblador y el código binario denidos en anteriores secciones. Sin embargo, como el computador digital descrito, llamado Xenon, no tiene implementación física, estos códigos han de ser guardados por el emulador en algún formato que sea capaz de entender el programa emulador. 53 El código ensamblador es guardado en cheros de texto, de forma que cada instrucción es contenida en una línea. El tamaño de estos cheros dependerá de cuántas líneas de código tenga dicho programa. El código ensamblador es guardado en cheros de texto con extensión ls2. En cambio, el código binario es guardado en un archivo binario. Recordemos que el computador tiene una capacidad de direccionamiento de la memoria principal de 11 bits, contando con 2048 posibles direcciones de memoria. A su vez la longitud de un registro de memoria es de 16bits, o 2 bytes.Los cheros de código binario contienen una copia del contenido de toda la memoria principal del computador. Estos archivos están en formato binario, de modo que los primeros 2 bytes corresponden a la dirección de memoria 0, los siguientes 2 bytes corresponden a la dirección de memoria 1 y así hasta llegar a la última dirección de memoria, 2047. Como se puede comprobar, el formato de los archivos de código binario del computador Xenon es muy sencillo. Dichos cheros tienen una extensión ece que los identica. Además, todos los archivos de código binario tendrán el mismo tamaño, pues el tamaño de la memoria principal no cambia y los archivos de código binario contienen una copia bit a bit de dicha memoria, de forma secuencial. 6.2. Clases El código está documentado en doxygen van Heesch, Dimitri (1997), de forma que sea fácil de entender. Las clases principales implementadas en el código son: Interface. Es la clase principal del ejecutable xenon.main.jar, por ello contiene una función main. Dene una ventana que contiene un JPanel con un CardLayout, que permite alternar entre las vistas de desarrollo y depuración dentro de una misma ventana. ProjectsManager. Gestiona el árbol de proyectos de la vista de desarrollo. TabsManager. Gestiona las pestañas de los archivos abiertos en la vista de desarrollo. DebugViewManager. Implementa la vista de depuración. Sobre. Esta clase implementa una ventana popup que muestra información sobre el autor del proyecto, así como del profesor tutor del mismo. 54 Emulator. Es la clase principal del ejecutable xenon.emu.jar, por ello contiene una función main. Esta clase es la principal de la vista de emulación. La vista de emulación es accesible tanto desde la vista de desarrollo del ejecutable xenon.main.jar como desde el ejecutable xenon.emu.jar de forma standalone. ButtonTabComponent. Esta clase es usada por cada pestaña, en la vista de desarrollo. Permite mostrar el nombre del archivo de una pestaña, así como un botón con una X que sirve para cerrar dicha pestaña. XenonHelper. En esta clase se encuentran métodos que permiten compilar código ensamblador, así como la lectura e interpretación de código binario. Instruction. Una instancia de esta clase contendrá toda la información de una instrucción: la posición de memoria en que se encuentra, el código de operación y el operador de la instrucción. PopupListener. Implementa un listener que muestra un popup cuando se hace click derecho con el ratón en cierto objeto. Project. Dene un proyecto y sus propiedades básicas. ProjectFile. Dene un chero perteneciente a un proyecto. Tab. Implementa una pestaña que muestra un archivo, en la vista de desarrollo. VirtualComputer. Es una abstracción del funcionamiento del computador Xenon. El emulador y el depurador usan una instancia de esta clase para ejecutar cada instrucción. Las siguientes clases tienen como objetivo conectar visualmente con líneas y echas componentes grácos en un JPanel, de forma sencilla. Este código es una modicación del código de Stanislav Lapitsky Lapitsky, Stanislav (2007). JConnector. Clase principal del conector que conecta dos objetos con echas. ConnectorContainer. Extensión de JPanel que permite añadir conectores con echas entre objetos contenidos en dicho JPanel. ConnectLine. Dene una línea usada por un JConnector. 55 Para hacerse una primera idea de la estructura del programa, la gura 22 es un diagrama de clases UML del código que incluye las clases anteriormente mencionadas. Cuando dos clases son conectadas por una echa, como DebugViewManager→VirtualComputer, signica que DebugViewManager tiene un atributo que es una instancia de la clase VirtualComputer. A su vez, a un lado de dicha echa se sitúa el nombre de dicho atributo. Figura 22: Diagrama de clases de las clases principales 6.2.1. Interface Es la clase principal del ejecutable Xenon.main.jar, por ello contiene una función main. Dene una ventana que contiene un JPanel con un CardLayout, que permite alternar entre las vistas de desarrollo y depuración dentro de una misma ventana. La gura 23 muestra un diagrama de la clase. El punto de partida del programa es el método main(), que crea una instancia de la clase Interface. El constructor de Interface a su vez llama al método addComponentToPane(). Interface dene la clase SliderListener, que tiene como objeto actualizar la frecuencia de ejecución del computador cuando el usuario mueve el deslizador que marca la 56 Figura 23: Diagrama de la clase Interface frecuencia en la vista de depuración. Los atributos de la clase Interface son: JPanel cardPanel. Panel que usa un layout de tipo CardLayout para poder cambiar entre la vista de depuración y de código. String state. Variable que informa de si estamos actualmente en la vista de código o de depuración. JTree projectsTree. Árbol de proyectos, muestra los proyectos y los archivos contenidos en cada proyecto. TabsManager tabsManager. Gestor de pestañas. Cada pestaña permite visualizar un archivo que pertenece a alguno de los proyecto abiertos. DebugViewManager debugViewManager. Controlador principal de la vista de depuración. JTextArea problemasArea. Área que informa de problemas en la vista de desarrollo, como por ejemplo problemas de compilación. ProjectsManager projectsManager. Clase gestora de los proyectos abiertos. JSlider slider. Slider que sirve para cambiar la frecuencia de ejecución del computador. Los métodos que dene la clase Interface son: main(). Lanza la aplicación, creando una instancia de Interface. 57 Interface(). Dene la posición de la ventana en pantalla, asigna el título de la ventana y llama al método addComponentToPane(). addComponentToPane() se encarga de inicializar los atributos de Interface, instanciando por ejemplo el gestor de la vista de depuración y el gestor del árbol de proyectos y de las pestañas de la vista de desarrollo. Este método se encarga no solo de inicializar los atributos de la clase sino de dar contenido a la ventana, añadiendo los menús, las barras de herramientas y demás objetos que se pueden ver en las vistas de desarrollo y depuración. 6.2.2. ProjectsManager Figura 24: Diagrama de la clase ProjectsManager La vista de desarrollo contiene un árbol de proyectos. En ese árbol se muestran los proyectos abiertos, y en un nivel del árbol inferior, los archivos contenidos en dichos proyectos. La clase ProjectsManager gestiona dicho árbol de proyectos, y una instancia de esta clase es asignada al atributo projectsManager de la clase Interface. La gura 24 muestra un diagrama de esta clase. Esta clase contiene una serie de atributos: ArrayList<Project> projectsList. Lista de proyectos abiertos. Project currentlySelectedProject. Proyecto seleccionado actualmente. Esta información es útil para realizar acciones como cerrar proyecto o para compilar. 58 ProjectFile currentlySelectedFileInTree. Fichero actualmente seleccionado en el árbol de proyectos. Este atributo es usado en acciones como depurar, compilar, emular, o guardar o cerrar archivo. JTree projectsTree. Es el árbol de proyectos, es el objeto que es mostrado en pantalla. TabsManager tabsManager. Gestor de pestañas. Es necesario por ejemplo para poder todas las pestañas relacionadas con el proyecto al ejecutar la acción cerrar proyecto. Respecto de los métodos de la clase ProjectsManager: En el constructor se inicializan todos los atributos de la clase. Los métodos getProjectsTree(), getCurrentlySelectedProject(), y getCurrentlySelectedFileInJTree() son métodos get que devuelven los atributos de la clase correspondientes. Los métodos mouseClicked(), mouseEntered(), mouseExited(), mousePressed(), y mouseReleased() implementan la interfaz MouseListener. Concretamente usaremos mousePressed() de forma que un click con el ratón seleccione un proyecto o archivo en el árbol de proyectos, y un doble click abra el chero clickeado. El método closeProject() elimina el proyecto actualmente seleccionado del árbol de proyectos, a la vez que cierra las pestañas abiertas relacionadas con dicho proyecto. El método removeFileFromJTree() elimina un chero, que es parámetro de entrada de dicho método, del árbol de proyectos. Este método es llamado por el gestor de pestañas cuando addBinaryFromCode() es usado para añadir un chero binario al árbol de proyectos que tenga el mismo nombre que un chero de código ensamblador, pero con la extensión ls2. createProject() muestra un diálogo para elegir el nombre y ubicación del proyecto a crear, y después lo crea, añadiendo un chero de código ensamblador al mismo. openProject() abre un proyecto situado en el directorio que el parámetro de entrada contiene. 59 6.2.3. TabsManager Figura 25: Diagrama de la clase TabsManager Esta clase permite gestionar el conjunto de archivos abiertos para su edición, los cuales se muestran en pestañas en la vista de desarrollo. Contiene un solo atributo privado, tabbedFilePane, que es el panel con todas las pestañas. La gura 25 muestra un diagrama de esta clase. Los métodos de esta clase son: getTabbedPane(). Devuelve el panel de pestañas, el atributo tabbedFilePane. TabsManager(JTabbedPane tab). Constructor, inicializa el atributo tabbedFilePane de la clase. searchTab(ProjectFile ple). Busca una pestaña que contenga el chero ple. dontAskAndRemoveTab(Tab t). Elimina la pestaña sin preguntar si quieres guardar el chero. askAndRemoveTab(Tab t). Si el chero ha sido modicado, pregunta si quieres guardarlo. Entonces lo cierra. removeTab(ButtonTabComponent ct). Elimina una pestaña a partir de su etiqueta ButtonTabComponent, que contiene el nombre del archivo y el botón en forma de X que sirve para cerrarla. 60 addTab(ProjectFile ple) Este método añadirá una pestaña al panel de pestañas si no existe una pestaña con el chero ple. En otro caso seleccionará y mostrará dicha pestaña. saveTabTo(Tab t, String path). Guarda el chero de una pestaña t en la ruta path. saveCurrentlySelectedTab(). Guarda el chero de la pestaña actualmente seleccionado. getCurrentlySelectedTab(). Devuelve la pestaña actualmente seleccionada, o null si no existe ninguna pestaña. saveCurrentlySelectedTabAs(). Crea un diálogo que pregunta dónde se quiere guardar el texto de la actual pestaña, y lo guarda. saveAllTabs(). Guarda los cambios realizados en los cheros de todas las pestañas. saveIfModied(ProjectFile codeToDebug). Comprueba si el chero ha sido modicado y pregunta al usuario si quiere guardar los cambios. closeAllTabsOfProject(Project p). Cierra todas las pestañas del proyecto p. closeCurrentlySelectedTab(). Cierra la pestaña actualmente seleccionada. closeAllTabs(). Cierra todas las pestañas, preguntando si guardar cambios en aquellos cheros que se han modicado. 6.2.4. DebugViewManager Clase gestora de la vista de depuración. Esta clase realiza todas las tareas de la interfaz gráca de la vista de depuración, además de lidiar con la clase VirtualComputer. La gura 26 muestra un diagrama de esta clase. En esta clase se denen otras subclases y enumeraciones: Base es una enumeración que indica la base de representación numérica de los registros y de la memoria principal del computador. InputType es una enumeración que indica si el computador está pidiendo un carácter o número como dato de entrada o no está pidiendo datos. 61 Figura 26: Diagrama de la clase DebugViewManager 62 La clase Trace permite crear una traza de la ejecución de un programa. Escribe en un chero traza.txt en el directorio del proyecto el resultado de cada operación realizada: el valor de los registros del computador, la dirección de la operación y la operación. ExecuteInstructionTask es una clase que extiende la clase TimerTask. En DebugViewManager, una instancia de este clase es usada para llamar de forma periódica al computador virtual para que ejecute la siguiente instrucción. TableListener. Clase que escucha cuándo se selecciona una nueva posición de memoria. Cuando el usuario seleccione una posición de memoria en la tabla, el registro P cambiará su valor. ConsoleKeyListener. Clase que escucha la entrada del teclado y la representa en la consola, e implementa la interfaz KeyListener. Cuando el usuario presione ENTER, los datos se mandarán al computador. ColorCellRenderer. Esta clase sirve para resaltar las posiciones de memoria que cambian en la JTable correspondiente. FlashySignal. Versión de JLabel que sirve para marcar cuándo se usan las señales del computador. FlashyTextField. Versión de JTextField que marca en rojo cuando un registro es actualizado. Atributos de la clase: JTextPane consolaPane. Es la consola de entrada y salida de datos. ConsoleKeyListener consolaListener. Listener que recoge y trata la entrada proveniente del teclado. String inputBuer. Buer de entrada. Se van añadiendo datos hasta recibir un enter (en el caso de que el computador esté pidiendo datos). long period. Período de reloj de una instrucción del computador en milisegundos, 1000/f(Hz). int runTo. En el caso de "Ejecutar Hasta", dirección de memoria en la que parar la ejecución. 63 ColorCellRenderer pTableRenderer, memoriaTableRenderer. Renderers de las tablas pTable y memoriaTable. Timer instructionTimer. Timer usado para organizar la ejecución de instrucciones en modo runMode. Timer changesTimer. Timer usado para los cambios de registro. ExecuteInstructionTask instructionTask. Tarea de ejecución de una instrucción. Base base. Variable que contiene la base que actualmente se usa para representar datos. VirtualComputer computer. Instancia del computador que se está emulando. Los métodos de la clase son: setPidiendoDatos(InputType b). Método que sirve para dar a conocer a la vista de depuración si el computador está a la espera de datos. setRegistersBase(Base b). Método que cambia la base en que se muestran los datos. setExecutionPeriod(long millisecs). Método que cambia el período de ejecución. Este cambio de período se notará la siguiente vez que se ejecute el código en modo "Ejecutar todo" o "Ejecutar hasta". getConsoleInput(). Devuelve los datos del buer de entrada del teclado. addConsoleOutput(String text). Añade el texto del parámetro text a la consola. selectNextInstructionInMemoryNearP(int p). Centra la tabla pTable en la posición indicada por el parámetro de entrada p. actionRun(). Acción "Ejecutar Todo". Ejecuta las instrucciones del ordenador hasta llegar a un ALT, con la frecuencia del computador seleccionada. actionRunTo(int num). Acción "Ejecutar Todo". Ejecuta las instrucciones del ordenador hasta llegar a cierta instrucción, * o a un ALT, con la frecuencia del computador seleccionada. actionPause(). Acción Pausar. Detiene la ejecución de instrucciones. 64 actionRestart(). Acción Reiniciar. Reinicia el estado del computador. actionExecuteNextInstruction(). Acción Ejecutar siguiente instrucción. Solo ejecuta una instrucción. changeMemoryAddress(Instruction i). Cuando cierta posición de memoria cambia, este método es llamado para actualizar la la adecuada de tabla de memoria de la interfaz gráca. updateJTableModel(). Cuando muchas posiciones de memoria cambian, este método es llamado para actualizar la tabla de memorian entera de la interfaz gráca. setDebugCode(ArrayList<Instruction> codeArray, File le). Inicializa la memoria del computador con cierto código. DebugViewManager(). Constructor de la vista depuración. Los siguientes métodos son implementaciones de la interfaz VirtualComputer.VirtualComputerListener que es el Listener del computador: writeNumberToScreen(). Este método es llamado cuandoquiera que el computador quiera escribir números en pantalla. stateChanged(). Este método es llamado cuandoquiera que el estado del computador cambie. addZeros(String s, int a). Añade ceros a la cadena 's' hasta que dicha cadena tenga una longitud 'a'. memoryChanged(Instruction i). Este método será llamado cuando el contenido de la dirección de memoria i cambie. writeCharacterToScreen(). Este método será llamado cuandoquiera que el computador quiera escribir un carácter en pantalla. 6.2.5. Sobre Esta clase implementa una ventana popup que muestra información sobre el autor del proyecto, así como del profesor tutor del mismo. Esta clase es muy simple, y consta de un constructor y de un método. En el constructor se pasan dos parámetros, que son la posición x e y en la pantalla. A su vez, el método actionPerformed(ActionEvent e) sirve para cerrar el popup. La gura 27 muestra un diagrama de esta clase. 65 Figura 27: Diagrama de la clase Sobre 6.2.6. Emulator Figura 28: Diagrama de la clase Emulator Es la clase principal del ejecutable Xenon.emu.jar, por ello contiene una función main. Esta clase es la principal de la vista de emulación. La vista de emulación es accesible tanto desde la vista de desarrollo del ejecutable xenon.main.jar como desde el ejecutable xenon.emu.jar de forma standalone. Esta clase realiza todas las tareas de la interfaz gráca de la vista de emulación, además de lidiar con la clase VirtualComputer, que es la que ejecuta cada instrucción del computador. A nivel de código, es una versión más sencilla que el DebugViewManager, pues el usuario no visualiza los registros ni las posiciones de memoria ni tiene un control de la ejecución como en el modo de depuración. La gura 28 muestra un diagrama de esta clase. Esta clase dene una serie de subclases: ExecuteInstructionTask es una clase que extiende la clase TimerTask. Una instancia de este clase es usada para llamar de forma periódica al computador virtual 66 para que ejecute la siguiente instrucción. ConsoleKeyListener. Clase que escucha la entrada del teclado y la representa en la consola, e implementa la interfaz KeyListener. Cuando el usuario presione ENTER, los datos se mandarán al computador. BinaryFilter. Sirve de ltro para mostrar solo los cheros con la extensión binaria "ece". A diferencia del DebugViewManager, que permite depurar tanto código binario como código ensamblador, el emulador solo permite ejecutar código binario. Atributos de la clase: JTextPane consoleArea. Es la consola de entrada y salida de datos. ConsoleKeyListener consolaListener. Listener que recoge y trata la entrada proveniente del teclado. String inputBuer. Buer de entrada. Se van añadiendo datos hasta recibir un enter (en el caso de que el computador esté pidiendo datos). long period. Período de reloj de una instrucción del computador en milisegundos, 1000/f(Hz). Timer timer. Timer usado para organizar la ejecución de instrucciones. ExecuteInstructionTask task. Tarea de ejecución de una instrucción. VirtualComputer computer. Instancia del computador que se está emulando. boolean exitOnClose. Si el emulador se está ejecutando en forma standalone, cerrar la ventana cerrará todoel programa, en ese caso esta variable será true. Los métodos de la clase son: getConsoleInput(). Devuelve los datos del buer de entrada del teclado. setMyTitle(String s). Método que cambia el título de la ventana del emulador. Sirve para añadir al título del emulador el archivo abierto. Emulator(). Es el constructor que inicializa la clase. Inicializa los atributos de la clase, luego llama a addComponentToPane(), que añade todos los elementos grácos necesarios a la ventana, incluyendo el menú, la barra de herramientas y la consola. addComponentToPane(Container pane). Añade todos los componentes visuales necesarios al panel. 67 addConsoleOutput(String text). Añade el texto del parámetro text a la consola. setPidiendoDatos(InputType b). Método que sirve para dar a conocer a la vista de depuración si el computador está a la espera de datos. actionExecuteNextInstruction(). Acción Ejecutar siguiente instrucción. Solo ejecuta una instrucción. actionPause(). Acción Pausar. Detiene la ejecución de instrucciones. setRunCode(ArrayList<Instruction> codeArray). Inicializa la memoria del computador con cierto código. actionRestart(). Acción Reiniciar. Reinicia el estado del computador. actionRun(). Acción "Ejecutar Todo". Ejecuta las instrucciones del ordenador hasta llegar a un ALT, con la frecuencia del computador seleccionada. Los siguientes métodos son implementaciones de la interfaz VirtualComputer.VirtualComputerListener que es el Listener del computador: writeNumberToScreen(). Este método es llamado cuandoquiera que el computador quiera escribir números en pantalla. stateChanged(). Este método es llamado cuandoquiera que el estado del computador cambie. addZeros(String s, int a). Añade ceros a la cadena 's' hasta que dicha cadena tenga una longitud 'a'. memoryChanged(Instruction i). Este método será llamado cuando el contenido de la dirección de memoria i cambie. writeCharacterToScreen(). Este método será llamado cuandoquiera que el computador quiera escribir un carácter en pantalla. 68 6.2.7. VirtualComputer Figura 29: Diagrama de la clase VirtualComputer Es una abstracción del funcionamiento del computador Xenon. El emulador y el depurador usan una instancia de esta clase para ejecutar cada instrucción. Esta clase mantiene la memoria principal del computador, así como el valor de sus registros. Cuando se ejecuta una instrucción, los registros y la memoria principal cambian de acuerdo con el funcionamiento denido para el computador. La gura 29 muestra un diagrama de esta clase. En VirtualComputer se denen una serie de clases y enumeraciones: 69 VirtualComputerListener. Listener del computador, sirve para avisar de que el computador ha cambiado de estado, o de que el computador quiere escribir en pantalla. ComputerSignal. Enumeración de las señales del computador. ComputerRegister. Enumeración de los registros del computador. ComputerState. Clase que dene el estado del computador, a nivel de registros y señales del mismo. Contiene un listener del computador virtual, el valor de los registros, un mapa que contiene qué registros han cambiado y otro que contiene qué señales se han activado. Los atributos de la clase son: Instruction[] memoryMap. Mapa de memoria del computador. Instruction[] InitialMemoryMap. Mapa de memoria inicial del computador. Este dato se guarda para poder retornar el computador al estado inicial. ComputerState state. Estado del computador. boolean tracLight. Semáforo que asegura una ejecución ordenada. En cuanto a los métodos de la clase: VirtualComputer(). Constructor del computador, inicializa variables. VirtualComputer(ArrayList<Instruction> memory). Constructor del computador que inicializa la memoria con el parámetro de entrada 'memory'. restart(). Lleva el ordenador al estado inicial. Pone a cero los registros y las señales, y devuelve la memoria principal a su estado inicial. setListener(VirtualComputerListener l). Asigna un nuevo listener al computador. getListener(). Devuelve el listener del computador. setMemoryMap(ArrayList<Instruction> memory). Modica la memoria del computador con el parámetro 'memory'. setMemoryMapToZero(). Inicializa a cero la memoria del computador. 70 getMemoryMap(). Devuelve el mapa de memoria del computador. getIndirectAddress(int d). Devuelve M(D), la dirección de memoria contenida en la posición D. getNextInstruction(). Devuelve la próxima instrucción a ejecutar, posición que marca el registro P. executeNextInstruction(). Método que ejecuta la siguiente instrucción. Este método solo se ejecutará si el semáforo tracLight es false, y la ejecución del método asigna true al semáforo. De este modo se impide en todo caso la ejecución de este método de forma concurrente. 6.2.8. ButtonTabComponent Figura 30: Diagrama de la clase ButtonTabComponent Esta clase es usada por cada pestaña, en la vista de desarrollo. Permite mostrar el nombre del archivo de una pestaña, así como un botón con una X que sirve para cerrar dicha pestaña. En ButtonTabComponent se dene la clase TabButton, que crea un botón con una x que cierra la pestaña. La gura 30 muestra un diagrama de esta clase. ButtonTabComponent contiene tres atributos: TabsManager manager. Es necesario conocer este dato para poder llamar al método del gestor de pestañas con el n de cerrar la pestaña al presionar el botón x. JLabel label. Etiqueta con el nombre del archivo de la pestaña. 71 MouseListener buttonMouseListener. Es una implementación de un MouseAdapter que cierra la pestaña cuando se hace click en el botón x, además de resaltar dicho botón cuando el ratón pasa por encima. Los dos métodos de la clase ButtonTabComponent son getLabel(), que devuelve el valor de la etiqueta de la pestaña que contiene el nombre del archivo abierto; y el constructor de la clase, que inicializa las variables, añadiendo la etiqueta con el nombre del archivo de la pestaña, y el botón x de cerrar pestaña. 6.2.9. XenonHelper Figura 31: Diagrama de la clase XenonHelper En esta clase se encuentran métodos que permiten compilar código ensamblador, así como la lectura e interpretación de código binario. Esta clase no contiene ningún atributo y todos sus métodos son estáticos. La gura 31 muestra un diagrama de esta clase. En esta clase se denen: La enumeración PseudoInstruction. Enumera las pseudoinstrucciones válidas en lenguaje ensamblador. Los métodos de la clase son: generateMemoryMap(ArrayList<Instruction> in). Este método recoge la salida del método translateToInstructions(String) y lo convierte en un mapa de memoria. 72 ArrayList<Instruction> translateToInstructions(String code). Lee una cadena de texto y la traduce a instrucciones. Es el método principal en la compilación de código ensamblador a código binario. searchLabel(ArrayList<LineCode> lineCodeArray, String addressLabel). Busca etiqueta en una lista de líneas de código. translateToBinary(ArrayList<Instruction> code). Traduce a binario un programa, una vez tenemos las instrucciones que lo forman. Este es el principal método que permite guardar en formato ece el código binario de un programa. intToByte(int i). Método usado para convertir de int a byte. byteToInt(byte b). Método usado para convertir de byte a int. translateFromBinary(byte[] binary). Traduce código binario a un mapa de memoria que contiene un programa. Es el método principal a la hora de leer código binario y traducirlo a instrucciones que entienda el computador virtual Xenon. openBinaryFile(File le). Abre un chero binario y devuelve el mapa de instrucciones, haciendo uso del método translateFromBinary(byte[] binary). saveToBinaryFile(File le, ArrayList<Instruction> ins) . Guarda el código binario de un programa en formato "ece", para ello hace uso de translateToBinary(ArrayList<Instruction> code). 6.2.10. LineCode Figura 32: Diagrama de la clase LineCode La clase LineCode. Contiene la información de una línea de texto del código ensamblador. Es una clase intermediaria usada en la compilación del código ensamblador. 73 Contiene información como: la instrucción a la que se traduce la línea de código, el número de línea, la pseudoInstrucción a la que se reere la línea de código, y etiqueta (en formato texto) usada en dicha línea de código ensamblador. La gura 32 muestra un diagrama de esta clase. 6.2.11. Instruction Figura 33: Diagrama de la clase Instruction La clase Instruction dene una instrucción, así como una serie de métodos para manejar dicha instrucción. Una instancia de esta clase contendrá toda la información de una instrucción: la posición de memoria en que se encuentra, el código de operación y el operador de la instrucción. La gura 33 muestra un diagrama de esta clase. Instruction contiene la enumeración OperationCode, que enumera todos los códigos de operación posibles. Aquí, en código de operación se incluye tanto el código de operación como el modo de direccionamiento, de forma que si por ejemplo el código de operación es SUM y el modo de direccionamiento es directo, el OperationCode es SUM; 74 y si es indirecto el OperationCode es SUMI. Los atributos que contiene un objeto de la clase Instruction son: OperationCode operationCode. Código de operación de la instrucción, e incluye el modo de direccionamiento. int insOperator. Operador de la instrucción (normalmente será una dirección de memoria. int data. Dato sin signo de 16 bit, correspondiente a la instrucción tal y como se guarda en binario, pero en formato decimal. Contendrá un valor entre 0 y 65535. Los números negativos se guardarán en complemento a 2 de 16bit. int addressLocation. Posición de memoria en que se encuentra la instrucción, tendrá un valor entre 0 y 2048 puesto que el direccionamiento es de 11 bits. Si no se ha denido, la posición de memoria será -1. Los métodos de la clase son: Instruction(). Constructor que incializa todo a cero. Instruction(OperationCode oc, int operator). Constructor que inicializa el contenido de la instrucción (código+operador), pero no dene la posición de memoria en que se encuentra la instrucción. setInstruction(OperationCode oc, int operator). Método que inicializa el contenido de la instrucción (código+operador), pero no dene la posición de memoria en que se encuentra la instrucción. setAddressLocation(int ma). Sitúa la instrucción en la posición de memoria 'ma'. getAddressLocation(). Devuelve la posición de memoria de la instrucción. setOperationCode(OperationCode oc). Método que cambia el código de operación de la instrucción. setInstructionOperator(int operator). Método que cambia el operador de la instrucción. setInstructionSigned(int d). Toma como entrada el dato (con signo) que corresponde a la instrucción. El parámetro d debe pertenecer a [-32768, 32767] o lanzará una excepción 75 setInstructionUnsigned(int d). Toma como entrada el dato (sin signo) que corresponde a la instrucción. El parámetro d debe pertenecer a [0, 65535] o lanzará una excepción. getOperationCode(). Devuelve el código de operación de la instrucción. getInstructionOperator(). Devuelve el operador de la instrucción (en general será una dirección de memoria). getDataUnsigned(). Devuelve el dato guardado en memoria, sin signo, con un valor entre 0 y 65535. getDataSigned(). Devuelve el dato guardado en memoria, sin signo, con un valor entre 32768 y 32767. updateFromData(). Calcula qué código de operación y operador tiene la instrucción a partir del dato guardado en memoria. updateFromInstruction(). Calcula el dato a guardar en memoria, a partir del código de operación y la dirección en memoria. toString(). Crea una cadena que representa la instrucción. 6.2.12. PopupListener Figura 34: Diagrama de la clase PopupListener Esta clase extiende la clase MouseAdapter e implementa un listener que muestra un popup cuando se hace click derecho con el ratón en cierto objeto. Como atributo tiene JPopupMenu popup, que dene el popup a mostrar y es un parámetro que se pasa en el constructor de la clase. Los demás métodos denidos sirven para mostrar dicho popup. La gura 34 muestra un diagrama de esta clase. 76 Figura 35: Diagrama de la clase Project 6.2.13. Project La clase Project dene un proyecto y sus propiedades básicas. Los únicos métodos denidos en esta clase son el constructor, que inicializa los atributos de la clase, y el método toString(), que da el nombre del chero en formato cadena. La gura 35 muestra un diagrama de esta clase. Los atributos de la clase son: File le. Contiene el directorio donde está localizado el proyecto. ArrayList <ProjectFile> projectFiles. Lista de cheros pertenecientes al proyecto. DefaultMutableTreeNode pnode. Nodo del proyecto en el árbol de proyectos. 6.2.14. ProjectFile Figura 36: Diagrama de la clase ProjectFile Dene un chero perteneciente a un proyecto. Esta clase dene la enumeración FileType, que enumera los tipos de archivo que un chero de un proyecto puede ser: código binario, código ensamblador, o texto. La gura 36 muestra un diagrama de esta clase. A su vez, un objeto de la clase ProjectFile contendrá los siguientes atributos: DefaultMutableTreeNode fnode. Nodo de este chero en el árbol de proyectos. FileType type. Dene el tipo de chero. 77 File le. Ruta del chero en el sistema de archivos. Project project. Proyecto al que pertenece el chero Los métodos de esta clase: ProjectFile(File f, Project p). Constructor, inicializa los atributos de la clase. Las extensiones reconocidas para los cheros de un proyecto son ls2 (código) y ece (binario). El resto de archivos es tratado como texto. toString(). Devuelve el nombre del chero en una cadena. setNode(DefaultMutableTreeNode no). Asigna 'no' como nodo de este chero en el árbol de proyectos. 6.2.15. Tab Figura 37: Diagrama de la clase Tab Implementa una pestaña que muestra un archivo, en la vista de desarrollo. Una pestaña mostrará un archivo, que pertenecerá a un proyecto abierto. La gura 37 muestra un diagrama de esta clase. Los atributos que un objeto de esta clase contendrá son: ProjectFile pFile. Fichero que contiene la pestaña. JTextArea textArea. Área de texto de la pestaña. JLabel label. Etiqueta de la pestaña boolean isModied. Indica si el texto ha sido modicado y todavía no se ha guardado. 78 Esta clase implementa una interfaz KeyListener, de forma que cuando el texto de la pestaña, la pestaña quede marcada mostrando que las modicaciones del archivo realizadas por el usuario no han sido guardadas todavía. Es por ello que se han añadido los métodos keyPressed(KeyEvent arg0) , keyReleased(KeyEvent arg0), y keyTyped(KeyEvent arg0). Los demás métodos de esta clase son: setLabel(JLabel l). Modica la etiqueta de la pestaña. isModied(). Indica si hay cambios no guardados del chero. setModied(boolean b). Marca el chero como modicado/no modicado. Tab(JTextArea ta, ProjectFile pf). Constructor que inicializa los atributos del objeto. 6.2.16. JConnector Figura 38: Diagrama de la clase JConnector Clase principal del conector que conecta dos objetos con echas. El constructor tiene como parámetros los dos objetos JComponent a conectar mediante echas, el tipo de línea que los conecta y el color. La gura 38 muestra un diagrama de esta clase. 79 6.2.17. ConnectorContainer Figura 39: Diagrama de la clase ConnectorContainer Extensión de JPanel que permite añadir conectores con echas entre objetos contenidos en dicho JPanel. El panel que contiene el dibujo del computador digital en la vista de depuración ha de ser de esta clase para poder pintar las echas que conectan los diferentes elementos del computador, como los registros, la memoria, los buses o las señales de control. La gura 39 muestra un diagrama de esta clase. Contiene un atributo, ArrayList<JConnector> connectors, donde se guardan todos los conectores. A su vez dene los siguientes métodos: ConnectorContainer(). Constructor de la clase, inicializa el atributo connectors. addConnector(JConnector c). Añade un conector al panel. addConnectors(ArrayList<JConnector> c). Añade una lista de conectores al panel. getConnectors(). Devuelve los conectores del panel. paint(Graphics g). Pinta los conectores del panel. 80 6.2.18. ConnectLine Figura 40: Diagrama de la clase ConnectLine Dene una línea usada por un JConnector. Es la clase que se encarga de pintar la línea de acuerdo a los parámetros establecidos, como por ejemplo el color, grosor de la línea y los extremos con echa. La gura 40 muestra un diagrama de esta clase. 81 82 7. Manual de usuario El programa tiene 3 vistas principales: Vista de desarrollo: En esta vista se desarrolla el código ensamblador del computador. Desde esta vista se tiene acceso a las vistas de depuración y de emulación. Vista de depuración: En esta vista se controla la ejecución del programa ensamblador, teniendo acceso a los registros del computador y las posiciones de memoria. Esta vista solo es accesible desde la vista de desarrollo. Vista de emulación: En esta vista se ejecuta la emulación del computador, representándose en la consola la entrada y salida de datos del computador. Esta vista es accesible desde la vista de desarrollo y también se puede ejecutar de forma autónoma. 7.1. Ejecución Existen dos ejecutables, el entorno de desarrollo y el emulador. Los ejecutables java son: xenon.main.jar xenon.emu.jar Para ejecutarlos desde Linux, Mac o Windows, se pueden ejecutar desde la línea de comandos: $ java -jar xenon.main.jar $ java -jar xenon.emu.jar Otra opción en Linux es ejecutar los scriptsGite, Vivek (1999) main.sh y emu.sh. En multitud de versiones de windows basta con hacer doble click sobre los archivos jar para que estos se ejecuten. 7.2. Vista de desarrollo Al iniciar el ejecutable xenon.main.jar, el programa muestra la vista de desarrollo. Desde esta vista el usuario es capaz de desarrollar el código ensamblador, depurarlo, así como entrar en el emulador. La vista cuenta con una barra de menú, una barra de herramientas, un árbol de proyectos, una zona de edición y un cuadro de información. 83 La mayoría de acciones posibles están disponibles tanto desde la barra de herramientas como desde la barra de menú. La gura 41 muestra la vista que el programa presenta al iniciar el programa: Figura 41: Vista inicial de desarrollo. En la vista de la gura 42 se puede observar un escenario típico en donde se han abierto diversos proyectos, con un archivo de código abierto. 84 Figura 42: Ejemplo de desarrollo Figura 43: Barra de herramientas La gura 43 muestra la barra de herramientas. Desde la barra de herramientas se tiene acceso a diversas acciones comunes: Nuevo chero. Crea un nuevo chero dentro del proyecto que esté seleccionado. Guardar. Guarda el chero seleccionado. Guardar como... Guarda el chero seleccionado con un nuevo nombre. Guardar todo. Guarda todos los cheros modicados. Abrir proyecto. Cerrar proyecto. 85 Compilar. Compila el chero de código fuente seleccionado. En caso de no haber seleccionado un chero con código fuente, compila el archivo de código fuente del proyecto al que pertenece el chero seleccionado. Depurar. Abre la vista de depuración con las instrucciones del chero de código fuente o binario seleccionado. Ejecutar. Abre la vista de emulación con las instrucciones del chero binario seleccionado. Desde la barra de menús también se tiene acceso a todas las acciones. Como se puede observar en la gura 44, muchas de las acciones cuentan con combinaciones de teclas de acceso rápido. Figura 44: Barra de menús de la vista de desarrollo 7.3. Vista de emulación La vista de emulación permite ejecutar código binario. En esta vista no se puede controlar la ejecución de un programa, a diferencia de la vista de depuración. Tampoco se puede visualizar los registros del computador ni los registros de la memoria principal. El motivo es que uno no puede visualizar de forma directa los registros del computador digital ni su memoria principal, a menos que el propio programa en ejecución esté diseñado para hacerlo. La vista cuenta con una barra de menú, una barra de herramientas que se puede ver en la gura 46, un árbol de proyectos, una zona de edición y un cuadro de información. La mayoría de acciones posibles están disponibles tanto desde la barra de herramientas como desde la barra de menú. La vista de ejecución está disponible tanto desde la vista de desarrollo como de forma standalone desde el ejecutable xenon.emu.jar. La gura 45 la vista que el programa presenta al iniciar el programa: 86 Figura 45: Vista de emulación Figura 46: Barra de herramientas de la vista de emulación Las acciones disponibles son: Abrir ejecutable.Abre un ejecutable en formato de código binario de la máquina Xenon. Guardar texto de la consola. Guarda el texto mostrado en la consola. Reiniciar máquina. Reinicia el programa así como el estado de los registros y memoria principal de la computadora digital, limpiando el texto de la consola. Salir. Si se está ejecutando el emulador en forma standalone, cierra todo el programa. Si el emulador se ha abierto desde la vista de desarrollo, solo cierra la vista de emulación. Desde la barra de menús también se tiene acceso a todas las acciones. Dicha barra de menús se presenta en la gura 47. 87 Figura 47: Barra de menús de la vista de emulación 7.4. Vista de depuración La vista de depuración permite controlar el ujo de ejecución de un programa. Esta vista es accesible desde la vista de desarrollo, y permite depurar tanto archivos de código binario como de código ensamblador. Las acciones de control de la ejecución incluyen la ejecución de una sola instrucción, la ejecución hasta llegar cierta dirección de memoria, ejecución completa y pausa de la ejecución. Además permite congurar la frecuencia de proceso de instrucciones del computador digital xenon, así como observar el tiempo transcurrido en la ejecución del programa. También contiene una representación del computador digital, junto con sus registros y señales, así como el contenido de la memoria principal. Tras la ejecución de cada instrucción, los registros del computador y los registros de memoria que han cambiado se marcarán en azul. A su vez también se marcarán las señales de gobierno que el computador ha usado en la ejecución de la instrucción. El visor entorno a P centrará la visualización de la memoria entorno a la dirección de la instrucción ejecutada tras su ejecución, mientras que el visor de la memoria de la parte inferior solo cambiará de posición según el usuario lo elija. Cuando el usuario hace click en un registro de la memoria principal en el visor de memoria entorno a P, el registro P cambia a la dirección del registro clickeado, de forma que esa será la próxima instrucción que se ejecutará. En la gura 48 se puede ver la vista de depuración en uso: 88 Figura 48: Vista de depuración Figura 49: Barra de control de de la vista de depuración La gura 49 muestra la barra de control de de la vista de depuración. Las acciones que se pueden realizar son: Ejecutar Instrucción. Ejecuta la siguiente instrucción, que viene dada por el valor del registro P. Ejecutar Hasta... Mostrará un diálogo donde el programa pide al usuario la dirección de memoria hasta la que el usuario quiere ejecutar el programa. Entonces el programa se ejecutará hasta llegar a una instrucción de parada (ALT) o hasta llegar a la dirección de memoria indicada. Comenzar de nuevo. Reinicia tanto los registros del computador como la memoria principal. Ejecutar todo. Ejecuta el programa desde la posición de memoria actual indicada por el registro P hasta llegar a una instrucción ALT de parada. 89 Pausar. Pausa la ejecución del programa, en el caso de que el programa se esté ejecutando. Salir del modo depuración. Devuelve al usuario a la vista de desarrollo. Salir. Accesible desde el menú Archivo>Salir. Cierra el programa. Elegir base. Haciendo uso del menú, se llega a Vista>Base, desde donde se puede elegir la base de representación de los registros del computador y de la memoria principal. Las opciones son Binario, Decimal, y Hexadecimal. Cambiar la frecuencia del reloj, haciendo uso del slider o deslizador horizontal. También es importante notar que a la izquierda del deslizador de frecuencia se muestra el tiempo de ejecución del programa, que se actualiza tras la ejecución de cada instrucción. Desde la barra de menús, mostrada en la gura 50, también se tiene acceso a todas las acciones. Como se puede observar, muchas de las acciones cuentan con combinaciones de teclas de acceso rápido. Figura 50: Barra de menús de la vista de depuración 90 8. Posibles ampliaciones En este capítulo analizamos una serie de posibles ampliaciones del presente proyecto que, si bien su implementación no entra dentro del ámbito del proyecto, si puede resultar interesante a la hora de continuar con el trabajo del emulador. Las ampliaciones que se proponen son: Una interfaz gráca para plataformas móviles. Una ampliación del juego de instrucciones del computador digital. En lo que sigue se detallan las acciones que habrían de llevarse a cabo a la hora de implementar dichas ampliaciones. 8.1. Interfaz gráca para plataformas móviles El código java no funciona directamente en plataformas móviles, pues el bytecode no es el mismo y la interfaz gráca tampoco. Para realizar una versión del emulador en plataformas móviles como AndroidMednieks, Zigurd (2012), es necesario reimplementar la interfaz gráca pero se puede reusar el código referente a la lectura de binarios, compilación de código ensamblador y emulación del computador. Es importante recalcar que de hecho la mayor parte del código corresponde a la interfaz gráca, por ello una implementación del emulador del computador virtual Xenon en otra plataforma, como Android, donde se tenga que rehacer desde cero la interfaz gráca, no es trivial. El código del programa es reusable, ya que existe una clara separación entre las clases que pertenecen a la interfaz gráca y aquellas que no pertenecen a ella. De hecho, gracias a esa separación, la vista de emulación y la vista de depuración usan la misma clase para emular la ejecución de instrucciones del computador virtual xenon, y para pasar de código binario a código que pueda interpretar el computador virtual xenon. Dicho de otro modo, la separación entre clases relativas a la interfaz gráca y clases relativas al funcionamiento abstracto del computador permite que el código sea reusable, sin embargo es inevitable que la parte de la interfaz gráca tenga que reescribirse al usarse otra librería gráca. Las clases que si se pueden reusar son aquellas independientes de la interfaz gráca, relativas al funcionamiento abstracto del computador digital Xenon: Instruction. Esta clase dene una instrucción y unos métodos útiles para manejarla. No necesitaría ninguna modicación. 91 XenonHelper. Esta clase dene una serie de métodos que sirven para convertir un texto en instrucciones que pueda entender el emulador, es decir compilar; y para guardar y leer un archivo de código binario del computador. Los métodos saveToBinaryFile() y openBinaryFile() es posible que necesiten alguna modicación, pues acceder al sistema de cheros y leer o guardar un archivo es posible que no se realice de la forma estándar en plataformas como un móvil Android. Todos los demás métodos de esta clase son reusables tal cual. VirtualComputer. Esta clase contiene los registros del computador digital y su memoria principal y es la que se encarga de ejecutar instrucciones y modicar los registros, memoria y señales de gobierno que sea necesario para ello. Esta clase tampoco hace falta que sea modicada, es independiente de la interfaz gráca. Todas las demás clases del programa son totalmente dependientes de la interfaz gráca y habrán de ser reimplementadas desde cero haciendo uso de las librerías de interfaz gráca de Android. Será necesario por tanto reimplementar las tres vistas: emulación, depuración y desarrollo. A continuación sigue una breve introducción para el uso de las clases anteriormente mencionadas de forma que se pueda implementar una nueva interfaz gráca. En los siguientes ejemplos haremos un uso básico de las clases Instruction, XenonHelper y VirtualComputer, que son las clases reusables e independientes de la interfaz gráca. Es decir, una interfaz gráca para Android hará un uso de estas clases similar al que se muestra en los siguientes ejemplos. Supongamos que tenemos una cadena de texto correspondiente al código ensamblador, en una variable de tipo String. El contenido de dicha cadna de texto podría ser algo tan sencillo como ORG 0\n ALT\n FIN. En el ejemplo de la gura 51 queremos convertir la cadena de texto a un conjunto de instrucciones que el computador virtual de VirtualComputer pueda entender. 92 String codigo_ensamblador ; . . . A r r a y L i s t <I n s t r u c t i o n > try program_instructions = null ; { program_instructions = XenonHelper . t r a n s l a t e T o I n s t r u c t i o n s ( t e x t ) ; } catch ( E x c e p t i o n ce ) { System . o u t . p r i n t l n ( c e . g e t M e s s a g e ( ) ) ; } Figura 51: Traducción de texto a instrucciones ensamblador Una vez tenemos el programa almacenado como un conjunto de instrucciones en la variable program_instructions, una instancia del computador virtual puede ejecutar dicho programa. Es importante añadir un listener al computador virtual para poder estar al tanto de los cambios de los registros y señales del computador. En este caso la clase principal implementará el listener. En este ejemplo solo ejecutamos una instrucción. El computador inicialmente tendrá el puntero P a cero, luego ejecutaremos la instrucción que esté en la posición de memoria cero. La gura 52 muestra el código necesario para ejecutar una instrucción. 93 c l a s s Program implements V i r t u a l C o m p u t e r . V i r t u a l C o m p u t e r L i s t e n e r public V i r t u a l C o m p u t e r c o m p u t e r ; public Program ( A r r a y L i s t <I n s t r u c t i o n > p r o g r a m _ i n s t r u c t i o n s ) { c o m p u t e r = new V i r t u a l C o m p u t e r ( ) ; c o m p u t e r . s e t L i s t e n e r ( this ) ; // I n i c i a l i z a m o s l a memoria d e l { computador c o m p u t e r . setMemoryMap ( c o d e A r r a y ) ; // E j e c u t a m o s una i n s t r u c c i ó n . computer . e x e c u t e N e x t I n s t r u c t i o n ( ) ; } // Métodos de V i r t u a l C o m p u t e r L i s t e n e r @Override public void writeNumberToScreen ( ) { } @Override public void stateChanged ( ) { } @Override public void memoryChanged ( I n s t r u c t i o n i ) { } @Override public void writeCharacterToScreen () { } } Figura 52: Ejecución de una instrucción Se puede observar que hemos incluido las implementaciones de la interfaz VirtualComputerListener, si bien dichas implementaciones no hacen nada. Para poder realizar una interfaz que sea capaz de manejar el computador virtual Xenon, habremos de implementar los métodos de dicha interfaz. Por ejemplo, writeCharacterToScreen() será llamado cuando el computador quiera mostrar un carácter en pantalla. Y memoryChanged() será llamado cuando durante la ejecución de una instrucción, se modique una posición de memoria. A su vez el computador llamará a stateChanged() tras la ejecución de una instrucción, de modo que la interfaz pueda hacer uso del método VirtualComputer::getState() y comprobar qué registros y señales se han usado o activado durante la ejecución de dicha instrucción. Para un ejemplo sencillo pero más completo de interfaz gráca, ver el código del emulador, en el archivo fuente Emulator.java. En el código, en 94 la denición de cada método se puede encontrar una explicación más detallada de la funcionalidad y características de cada método. 8.2. Ampliación del juego de instrucciones del computador El computador digital que aquí se ha presentado tiene instrucciones con un ancho de 16 bits, y una capacidad de direccionamiento de 11 bits. Esto deja 5 bits para elegir el código de operación (y modo de direccionamiento) de cada instrucción, lo cual como mucho da para 32 instrucciones diferentes, las cuales todas menos una ya han sido usadas. Y sin embargo existen todavía muchos tipos de operaciones que se podrían denir para el computador. Para ello sería necesario o bien aumentar el tamaño de la instrucción, es decir la cantidad de bits por instrucción; o disminuir la capacidad de direccionamiento, sin embargo la capacidad de direccionamiento no es muy grande ahora mismo. Por tanto la opción preferible es aumentar el tamaño de la instrucción. De forma general, los cambios en el código del programa que habría que realizar para añadir operaciones al computador virtual Xenon aumentando el tamaño de la instrucción son: Añadir los códigos de operación a la enumeración de códigos de operación. También será necesario cambiar la constante que dene el número máximo de código de operación. Modicar aquellas partes del código que hagan uso de las instrucciones. Por ejemplo, habrá que añadir el comportamiento de las nuevas instrucciones en la clase VirtualComputer en el método que ejecuta una instrucción. Modicar aquellas partes del código que hacen uso del tamaño de las instrucciones. Por ejemplo, los registros del computador así como los registros de la memoria principal pasarán a tener otro tamaño. A su vez, la clase Instruction hace uso del tamaño de una instrucción para interpretar correctamente un dato en formato decimal y pasarlo a binario o viceversa. Modicar aquellas partes del código que escriben o leen e interpretan código binario. Ahora mismo una instrucción, o un registro de la memoria principal, tiene el tamaño de 2 bytes. Si se añade 1 byte mas, hará falta modicar por ejemplo la clase XenonHelper, que guarda e interpreta archivos binarios. 95 De forma más concreta, si por ejemplo queremos que la capacidad de direccionamiento sea de 16 bits y que 8 bits pertenezcan al código de operación (incluyendo modo de direccionamiento), esto permitiría 28 = 256 operaciones diferentes y una capacidad de direccionamiento de 216 = 65536 direcciones de memoria diferentes, de forma que cada instrucción contara con 16+8 = 24 bits = 3 bytes. Los primeros cambios a realizar serán en la clase Instruction, referentes a las constantes se pueden ver en la gura 53. public public public public public static static static static static final final final final final int int int int int Memory_Address_Limit = Instruction_Size_Limit Register_Max_Limit = Register_Min_Limit = Operation_Code_Max = 65535; = 16777215; 8388607; −8388608; 255; Figura 53: Cambios de constantes de la Clase Instruction También será necesario añadir los códigos de operación a la enumeración de códigos de operación, como se muestra en la gura 54. public enum ALT( 0 , 0) , OperationCode ALM( 1 , ESCI ( 6 , 7) , RES ( 1 1 , 12) , LEE ( 7 , 2) , 8) , RESI ( 1 2 , { ALMI ( 2 , LEEI ( 8 , 3) , CAR( 3 , 9) , 13) , MUL( 1 3 , 4) , SUM( 9 , 14) , CARI ( 4 , 10) , SUMI ( 1 0 , MULI ( 1 4 , 15) , 20) , DIVI ( 1 6 , 17) , MOD( 1 7 , 18) , MODI( 1 8 , 19) , SAL ( 1 9 , SALI ( 2 0 , 21) , SAN ( 2 1 , 22) , SANI ( 2 2 , 23) , SAC ( 2 3 , 24) , SACI ( 2 4 , 25) , SAP ( 2 5 , 26) , SAPI ( 2 6 , 27) , ECA( 2 7 , 28) , LCAI ( 3 0 , 31) , LCA( 2 9 , 30) , 5) , ESC ( 5 , 6) , 11) , DIV ( 1 5 , ECAI ( 2 8 , 16) , 29) , // Nuevos c ó d i g o s de o p e r a c i ó n : OP32 ( 3 1 , 3 2 ) , OP33 ( 3 2 , 33) , OP34 ( 3 3 , 34) ; Figura 54: Cambios en la enumeración OperationCode La clase Instruction, como se ha explicado en la sección 6.2.11, permite almacenar una instrucción en un objeto java. Internamente, un objeto Instruction almacena la instrucción tanto en forma binaria como en forma simbólica (código de operación y operador). A la hora de actualizar la instrucción que contiene una variable Instruction, existe tanto la opción de pasar la nueva instrucción en forma binaria como la opción de pasar el código de operación y el operador. 96 Si por ejemplo realizamos una llamada a Instruction::setInstruction(OperationCode oc, int operator), estaremos actualizando la instrucción a partir del código de operación y el operador de forma simbólica, sin embargo internamente la instrucción también ha de ser guardada en formato binario. Para ello, internamente, el método setInstruction(OperationCode oc, int operator), hará una llamada a updateFromInstruction(). Del mismo modo, podremos actualizar la instrucción a partir del número en formato binario (en realidad en complemento a 2) que se almacenaría en la memoria del computador, realizando una llamada a Instruction::setInstructionOperator(int operator). De nuevo, internamente la instrucción también ha de ser guardada en formato simbólico separando el código de operación y el operador. Para ello, internamente, el método Instruction::setInstructionOperator(int operator) realizará una llamada a updateFromData(). El método updateFromData() devuelve el operador y el operando a partir del dato de la instrucción (que se guarda en decimal en complemento a 2). Este método es dependiente del tamaño de la instrucción y del código de operación y del direccionamiento, luego habría que modicarlo tal y como se muestra en la gura 55: También es necesario hacer cambios en el método updateFromInstruction(), que actualiza el dato en complemento a 2 a partir del operador y código de operación. Ese método también depende del formato de un registro de memoria. Dichos cambios se muestran en la gura 56. 97 private void { updateFromData ( ) int c o d e = i f ( c o d e >= { ( data 0 && & 0 xFF0000 ) int i = − 1; for ( O p e r a t i o n C o d e { >> 16; c o d e <= Operation_Code_Max ) i f ( code == getIndex : OperationCode . v a l u e s ( ) ) getIndex . code ( ) ) { i = getIndex . index ( ) ; break ; } } if ( i != −1) { operationCode insOperator = isInstruction = OperationCode . v a l u e s ( ) [ i ] ; ( data & = true ; = false ; 0xFFFF ) ; } else { isInstruction } } else { isInstruction = false ; } } Figura 55: Cambios en Instruction::updateFromData() 98 private void { updateFromInstruction () int f o o = 0 ; if ( isInstruction ()) { foo = ( operationCode . code ( ) << 16) | insOperator ; } else { i f ( operationCode == null && insOperator != −1) { foo = insOperator ; } else i f ( operationCode != null&& insOperator == −1) { foo = operationCode . code ( ) << 16; } } try { setInstructionUnsigned ( foo ) ; } catch ( E x c e p t i o n e) { } } Figura 56: Cambios en Instruction::updateFromInstruction() Serían necesarios cambios en la clase VirtualComputer. En el método que ejecuta la siguiente instrucción, habría que añadir el código que ejecuta las nuevas instrucciones, es decir, que modica registros y hace uso de las señales de gobierno. Como se puede ver en la gura 57, hay que modicar los registros necesarios, e indicar al estado del computador aquellos registros y señales que se han usado para la ejecución de la instrucción: 99 public ComputerState // Usamos e l executeNextInstruction () semáforo trafficLight throws // l l a m a d a s en p a r a l e l o / c o n c u r r e n t e s a e s t a if ( trafficLight trafficLight = // Recogemos l a Instruction false ) true ; == Exception p a r a q u e no s e puedan { realizar instrucción . { instrucción a ejecutar ins = memoryMap [ s t a t e . g e t P ( ) ] ; // Marcamos t o d o s los registros y s e ñ a l e s como no m o d i f i c a d o s state . resetSignalsRegisters (); if ( ins . isInstruction () { == true ) switch ( i n s . g e t O p e r a t i o n C o d e ( ) ) // E l e g i m o s q u é o p e r a c i ó n // s e g ú n el ejecutar c ó d i g o de o p e r a c i ó n . { case ALT : break ; . . . // Nuevas instrucciones case OP32 : try { int o p e r a t o r = ins . getInstructionOperator ( ) ; memoryMap [ o p e r a t o r ] . s e t I n s t r u c t i o n S i g n e d ( s t a t e . g e t A ( ) ) ; s t a t e . g e t L i s t e n e r ( ) . memoryChanged ( memoryMap [ o p e r a t o r ] ) ; s t a t e . setChangedMemory ( memoryMap [ o p e r a t o r ] . g e t A d d r e s s L o c a t i o n ( ) ) ; s t a t e . s e t T ( s t a t e . getA ( ) ) ; s t a t e . s e t I ( i n s . getDataSigned ( ) ) ; state . setS ( operator ) ; s t a t e . incrementP ( ) ; // Ahora s e ñ a l a m o s q u é registros han cambiado true ) ; true ) ; s t a t e . s e t R e g i s t e r C h a n g e d ( C o m p u t e r R e g i s t e r . S , true ) ; s t a t e . s e t R e g i s t e r C h a n g e d ( C o m p u t e r R e g i s t e r . P , true ) ; s t a t e . s e t R e g i s t e r C h a n g e d ( ComputerRegister . T, s t a t e . setRegisterChanged ( ComputerRegister . I , // Aquí mostramos // e j e c u c i ó n de las la // A l g u n o s setSignal // r e p e t i r llamadas //M(P) señales u s a d a s en el t r a n s c u r s o de instrucción . los comento , pero solo iguales −> I true ) ; true ) ; s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . LECM, true ) ; s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . ST , true ) ; s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . SP , s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . ES , Figura 57: Cambios en VirtualComputer::executeNextInstruction() 100 p a r a no la s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . EI , //A −> M(D) s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . SD , true ) ; true ) ; // s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . ES , true ); true ) ; s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . ET , true ) ; s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . ESCM, true ) ; s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . SA , //P −> P+1 s t a t e . s e t S i g n a l ( C o m p u t e r S i g n a l . INCP , true ) ; state . sendSignals ( ) ; } catch ( I n d e x O u t O f B o u n d s E x c e p t i o n { throw new exception ) E x c e p t i o n ( "ALM" ) ; } break ; case OP33 : . . . Figura 58: Cambios en VirtualComputer::executeNextInstruction() (continuación) La clase XenonHelper necesitará cambios. Por ejemplo, a la hora de leer o escribir un archivo de código binario ahora una instrucción no ocupa dos sino tres bytes. Por ello habrá que modicar translateToBinary() tal y como se puede observar en la gura 59: public s t a t i c byte [ ] { t r a n s l a t e T o B i n a r y ( A r r a y L i s t <I n s t r u c t i o n > code ) byte [ ] b i n a r y = new byte [ ( I n s t r u c t i o n . Memory_Address_Limit + 1 ) * 3 ] ; int f o o = 0 ; for ( I n s t r u c t i o n i : c o d e ) { foo = i . getDataUnsigned ( ) ; // BigEndian o r LittleEndian ? * 3 ] = intToByte ( f o o . getAddressLocation ()*3 + 1] = binary [ i . getAddressLocation ( ) binary [ i intToByte ( ( f o o & 0 x00FF00 ) binary [ i . getAddressLocation () intToByte ( ( f o o & 0 x00FF00 ) >> *3 + >> 8); 2] = 16); } return binary ; } Figura 59: Cambios en XenonHelper::translateToBinary() 101 & 0 x0000FF ) ; De igual modo también será necesario modicar translateFromBinary() para tener en cuenta el mayor tamaño de cada instrucción, según se muestra en el código de la gura 60: public s t a t i c A r r a y L i s t <I n s t r u c t i o n > { A r r a y L i s t <I n s t r u c t i o n > int foo = i = new byte [ ] binary ) A r r a y L i s t <I n s t r u c t i o n > ( ) ; 0; Instruction for ( int array translateFromBinary ( sr ; = 0; i < binary . length /3; i ++) { f o o= + byteToInt ( binary [ i ( byteToInt ( binary [ i i f ( foo != { sr = try { *3 *3]) + + 2]) ( byteToInt ( binary [ i << 16); 0) new Instruction (); sr . setInstructionUnsigned ( foo ) ; sr . setAddressLocation ( i ) ; } catch ( E x c e p t i o n e) { } a r r a y . add ( s r ) ; } } return array ; } Figura 60: Cambios en XenonHelper::translateFromBinary() 102 *3 + 1]) << 8) 9. Conclusiones y cumplimiento de objetivos En este Proyecto Fin de Carrera se ha estudiado un computador digital, creando un emulador y un entorno de programación simple llamado Xenon que permite el uso de dicho computador. El programa Xenon permite escribir, compilar, ejecutar y depurar código ensamblador del computador digital diseñado. Se ha utilizado el lenguaje de programación Java para la programación del emulador Xenon, ya que un ejecutable Java se puede ejecutar sin cambio alguno en múltiples plataformas, sin que se concurra en una gran pérdida de rendimiento. Se han propuesto dos ampliaciones: La implementación del programa Xenon para plataformas móviles, como por ejemplo Android. Para ello, sería necesario escribir una nueva interfaz gráca. Ampliación de las instrucciones que maneja el computador digital. Para ello sería necesario realizar modicaciones tanto en la parte de la interfaz gráca como la parte del código relativa al emulador. En cuanto a los objetivos del proyecto, se puede decir que: El diseño de la computadora simple se ha cumplido con el presente documento. El desarrollo del software que permite emular dicho computador, también se ha realizado satisfactoriamente, incluyendo un entorno de programación, un depurador y un emulador. En el presente documento se han detallado dos posibles ampliaciones de este proyecto. Gracias a una implementación del emulador Xenon en Java, el emulador puede ser ejecutado tanto en Windows como Mac y Linux sin necesidad de recompilar el programa. El software Xenon se usará en el próximo curso para introducir al alumnado el funcionamiento de un computador digital simple. El entorno de programación y el emulador permitirán a los alumnos experimentar con el computador como si éste fuera una realidad física. A su vez, el depurador muestra el funcionamiento interno del computador, con detalles como qué registros y señales usa cada instrucción en cada ciclo, y mostrando al alumno el contenido de dichos registros y de la memoria del computador. 103 Por tanto se concluye que todos los objetivos del proyecto se han cumplido. 104 10. Bibliografía Referencias Acosta Rodriguez, José Ángel (2009). Asignatura de informática de ingeniería aeroespacial. http://www.esi2.us.es/ jaar/docencia.htm. Arahal, Manuel R; Hernández, José Julio; Limón, Daniel (1986). CESIUS. http://www.esi2.us.es/ arahal/CESIUS/cesius.html. Boole, George (1854). An Investigation of the Laws of Thought on Which are Founded the Mathematical Theories of Logic and Probabilities. Gite, Vivek (1999). Linux Shell Scripting Tutorial. Macmillan. http://bash.cyberciti.biz/guide/. Lapitsky, Stanislav (2007). Jconnector project. http://java-sl.com/connector.html. Mednieks, Zigurd (2012). Programming Android: Java Programming for the New Ge- neration of Mobile Devices. O'Reilly Media. Shannon, Claude E. (1937). A symbolic analysis of relay and switching circuits. Master's thesis, Massachusetts Institute of Technology. Shannon, Claude E. (1948). A mathematical theory of communication. Technical Journal, Bell System -:. van Heesch, Dimitri (1997). Announcing: the rst release of doxygen. -. Varios (2013). Tortoisehg webpage. http://tortoisehg.bitbucket.org/. von Neumann, John (1945). First draft of a report on the edvac. Technical report, United States Army Ordenance Department and the University of Pennsylvania. 105 106 11 Anexos 11.1 Código 11.1.1 ButtonTabComponent.java package xenon; import import import import javax.swing.*; javax.swing.plaf.basic.BasicButtonUI; java.awt.*; java.awt.event.*; /** * @brief Usado como tabComponent * @detail Contiene una JLabel para mostrar el texto y un JButton para * cerrar la pestaña a la que pertenece. */ public class ButtonTabComponent extends JPanel { /** * */ private static final long serialVersionUID = 1L; @SuppressWarnings("unused") private TabsManager manager; private JLabel label; public JLabel getLabel() { return label; } public ButtonTabComponent(TabsManager manager, String Name) { super(new FlowLayout(FlowLayout.LEFT, 0, 0)); if (manager.getTabbedPane() == null) { throw new NullPointerException("TabbedPane is null"); } this.manager = manager; setOpaque(false); //Hacer que la JLabel muestre los títulos del JTabbedPane label = new JLabel(Name); } add(label); //Añadir más espacio entre la etiqueta y el botón label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); //Botón de la pestaña JButton button = new TabButton(manager); add(button); //Añadir más espacio a la parte superior del componente setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0)); /** * * @brief Crea botón con X para cerrar pestaña. * */ private class TabButton extends JButton implements ActionListener { /** * */ private static final long serialVersionUID = 1L; private TabsManager manager; public TabButton(TabsManager manager) { this.manager = manager; int size = 17; setPreferredSize(new Dimension(size, size)); setToolTipText("Cerrar esta pestaña"); setUI(new BasicButtonUI()); //Hacerlo transparente setContentAreaFilled(false); //No necesitamos que se pueda enfocar setFocusable(false); setBorder(BorderFactory.createEtchedBorder()); setBorderPainted(false); //Usamos el mismo listener para todos los botones addMouseListener(buttonMouseListener); setRolloverEnabled(true); //Cerrar la pestaña adecuada al hacer click en el botón addActionListener(this); } 107 public void actionPerformed(ActionEvent e) { manager.getTabbedPane().indexOfTabComponent(ButtonTabComponent.this); manager.removeTab(ButtonTabComponent.this); } //No necesitamos actualizar la UI en este caso public void updateUI() { } //Pintar la cruz protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g.create(); //Mover la imagen si se presiona if (getModel().isPressed()) { g2.translate(1, 1); } g2.setStroke(new BasicStroke(2)); g2.setColor(Color.BLACK); if (getModel().isRollover()) { g2.setColor(Color.MAGENTA); } int delta = 6; g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1); g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1); g2.dispose(); } } private final static MouseListener buttonMouseListener = new MouseAdapter() { public void mouseEntered(MouseEvent e) { Component component = e.getComponent(); if (component instanceof AbstractButton) { AbstractButton button = (AbstractButton) component; button.setBorderPainted(true); } } public void mouseExited(MouseEvent e) { Component component = e.getComponent(); if (component instanceof AbstractButton) { AbstractButton button = (AbstractButton) component; button.setBorderPainted(false); } } }; } 108 11.1.2 JConnector.java package xenon; import javax.swing.*; import java.awt.*; /** * The class represents pair of components with a connecting line. * * <p>Copyright: Copyright (c) 2007</p> * * @author Stanislav Lapitsky * @version 1.0 */ /** * @brief Una de las clases usada para pintar flechitas de un lado a otro * @detail Librería modificada por Félix Robles, código original de Stanislav Lapitsky. */ public class JConnector extends JPanel { /** * */ private static final long serialVersionUID = 1L; public static final int CONNECT_LINE_TYPE_SIMPLE = 0; public static final int CONNECT_LINE_TYPE_RECTANGULAR = 1; protected JComponent source; protected JComponent dest; protected ConnectLine line; protected int lineArrow = ConnectLine.LINE_ARROW_NONE; protected int lineType = CONNECT_LINE_TYPE_RECTANGULAR; protected Color lineColor; /** * Constructs default connector. * @param source JComponent * @param dest JComponent */ public JConnector(JComponent source, JComponent dest) { this(source, dest, ConnectLine.LINE_ARROW_NONE, Color.BLACK); } /** * Constructs a connector with specified arrow and color. * @param source JComponent * @param dest JComponent * @param lineArrow int * @param lineColor Color */ public JConnector(JComponent source, JComponent dest, int lineArrow, Color lineColor) { this(source, dest, lineArrow, CONNECT_LINE_TYPE_RECTANGULAR, lineColor); } /** * Constructs a connector with specified arrow, line type and color. * @param source JComponent * @param dest JComponent * @param lineArrow int * @param lineType int * @param lineColor Color */ public JConnector(JComponent source, JComponent dest, int lineArrow, int lineType, Color lineColor) { this.source = source; this.dest = dest; this.lineArrow = lineArrow; this.lineType = lineType; this.lineColor = lineColor; } /** * Overrides parent's paint(). It resets clip to draw connecting line * between components and set the clip back. * @param g Graphics */ public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; calculateLine(); if (line != null) { Shape oldClip = g2d.getClip(); g2d.setClip(getLineBounds()); g2d.setColor(lineColor); line.paint(g2d); g2d.setClip(oldClip); } } protected void calculateLine() { Rectangle rSource = source.getBounds(); 109 Rectangle rDest = dest.getBounds(); if (rSource.intersects(rDest)) { line = null; return; } boolean xIntersect = (rSource.x <= rDest.x && rSource.x + rSource.width >= rDest.x) || (rDest.x <= rSource.x && rDest.x + rDest.width >= rSource.x); boolean yIntersect = rSource.y <= rDest.y && rSource.y + rSource.height >= rDest.y || (rDest.y <= rSource.y && rDest.y + rDest.height >= rSource.y); if (xIntersect) { int y1; int y2; int x1 = rSource.x + rSource.width / 2; int x2 = rDest.x + rDest.width / 2; if (rSource.y + rSource.height <= rDest.y) { //source higher y1 = rSource.y + rSource.height; y2 = rDest.y; } else { y1 = rSource.y; y2 = rDest.y + rDest.height; } line = new ConnectLine(new Point(x1, y1), new Point(x2, y2), ConnectLine.LINE_TYPE_RECT_VERTICAL, ConnectLine.LINE_START_VERTICAL, lineArrow); if (lineType == CONNECT_LINE_TYPE_SIMPLE) { line.setLineType(ConnectLine.LINE_TYPE_SIMPLE); } } else if (yIntersect) { int y1 = rSource.y + rSource.height / 2; ; int y2 = rDest.y + rDest.height / 2; ; int x1; int x2; if (rSource.x + rSource.width <= rDest.x) { x1 = rSource.x + rSource.width; x2 = rDest.x; } else { x1 = rSource.x; x2 = rDest.x + rDest.width; } line = new ConnectLine(new Point(x1, y1), new Point(x2, y2), ConnectLine.LINE_TYPE_RECT_HORIZONTAL, ConnectLine.LINE_START_HORIZONTAL, lineArrow); if (lineType == CONNECT_LINE_TYPE_SIMPLE) { line.setLineType(ConnectLine.LINE_TYPE_SIMPLE); } } else { int y1; int y2; int x1; int x2; if (rSource.y + rSource.height <= rDest.y) { //source higher y1 = rSource.y + rSource.height / 2; y2 = rDest.y; if (rSource.x + rSource.width <= rDest.x) { x1 = rSource.x + rSource.width; } else { x1 = rSource.x; } x2 = rDest.x + rDest.width / 2; } else { y1 = rSource.y + rSource.height / 2; y2 = rDest.y + rDest.height; if (rSource.x + rSource.width <= rDest.x) { x1 = rSource.x + rSource.width; } else { x1 = rSource.x; } x2 = rDest.x + rDest.width / 2; } line = new ConnectLine(new Point(x1, y1), new Point(x2, y2), ConnectLine.LINE_TYPE_RECT_1BREAK, ConnectLine.LINE_START_HORIZONTAL, lineArrow); if (lineType == CONNECT_LINE_TYPE_SIMPLE) { line.setLineType(ConnectLine.LINE_TYPE_SIMPLE); } } } protected Rectangle getLineBounds() { int add = 10; int maxX = Math.max(line.getP1().x, line.getP2().x); 110 int minX = Math.min(line.getP1().x, line.getP2().x); int maxY = Math.max(line.getP1().y, line.getP2().y); int minY = Math.min(line.getP1().y, line.getP2().y); Rectangle res = new Rectangle(minX - add, minY - add, maxX - minX + 2 * add, maxY - minY + 2 * add); return res; } public Color getLineColor() { return lineColor; } public void setLineColor(Color c) { lineColor = c; } public int getLineType() { return lineType; } public void setLineType(int type) { lineType = type; } public int getLineArrow() { return lineArrow; } public void setLineArrow(int arrow) { lineArrow = arrow; } } 111 11.1.3 Emulator.java package xenon; import import import import import import import import import import import import import java.awt.Container; java.awt.EventQueue; java.awt.event.ActionEvent; java.awt.event.KeyEvent; java.awt.event.KeyListener; java.awt.event.MouseListener; java.io.BufferedWriter; java.io.File; java.io.FileWriter; java.io.IOException; java.util.ArrayList; java.util.Timer; java.util.TimerTask; import import import import import import import import import import import import import import import import import import javax.swing.AbstractAction; javax.swing.Action; javax.swing.GroupLayout; javax.swing.GroupLayout.Alignment; javax.swing.filechooser.FileFilter; javax.swing.ImageIcon; javax.swing.JButton; javax.swing.JFileChooser; javax.swing.JFrame; javax.swing.JMenu; javax.swing.JMenuBar; javax.swing.JMenuItem; javax.swing.JPanel; javax.swing.JPopupMenu; javax.swing.JScrollPane; javax.swing.JTextPane; javax.swing.JToolBar; javax.swing.KeyStroke; import xenon.DebugViewManager.InputType; import xenon.Instruction.OperationCode; /** * @brief Clase gestora de la vista de emulación. * @detail Esta clase realiza todas las tareas de la interfaz gráfica de la vista de emulación, * además de lidiar con la clase VirtualComputer. */ public class Emulator extends JFrame implements VirtualComputer.VirtualComputerListener { private static final long serialVersionUID = 1L; private JTextPane consoleArea; //Consola de entrada y salida de datos //Buffer de entrada. Se van añadiendo datos hasta recibir un enter (en el caso de que el computador esté pidiendo datos) private String inputBuffer; //Timer usado para organizar la ejecución de instrucciones. private VirtualComputer computer; //Instancia del computador que se está emulando private ConsoleKeyListener consolaListener; //Listener que recoge y trata la entrada proveniente del teclado //Si el simulador se está ejecutando en forma standalone, cerrar la ventana cerrará todo //el programa, en ese caso esta variable valdrá true. private boolean exitOnClose; Timer timer; ExecuteInstructionTask task; //Tarea de ejecución de una instrucción. private long period; //Período de reloj de una instrucción del computador en milisegundos = 1000/f /** * @brief Tarea que ejecuta una instrucción. * @detail El timer instructionTimer llamará a la función run() una vez por el período de tiempo fijado. * Esa función se encarga de ejecutar la siguiente instrucción. */ class ExecuteInstructionTask extends TimerTask{ @Override public void run() { if(consolaListener.getPidiendoDatos() == InputType.FALSE) { actionExecuteNextInstruction(); } } public void stop(){ this.cancel(); } } /** * * @brief Sirve de filtro para mostrar solo los ficheros con la extensión binaria "ece". * */ 112 public class BinaryFilter extends FileFilter { //Aceptar todos los directorios y los ficheros .ece (binarios) public boolean accept(File f) { if (f.isDirectory()) { return true; } String arg1 = f.getName().toLowerCase(); if(arg1.lastIndexOf('.')>0) { // get last index for '.' char int lastIndex = arg1.lastIndexOf('.'); // get extension String extension = arg1.substring(lastIndex); if (extension != null) { if (extension.equals(".ece") ) { return true; } } } return false; } //Descripción de este filtro public String getDescription() { return "Binarios"; } } /** * @brief Clase que escucha la entrada del teclado y la representa en la consola. * @detail Cuando el usuario presione ENTER, los datos se mandarán al computador. */ class ConsoleKeyListener implements KeyListener { private InputType inputAsked; /** * Informa al listener de si el computador está pidiendo datos. * @param b Define si el computador está pidiendo datos, y de qué tipo */ public void setPidiendoDatos(InputType b) { inputAsked = b; if(inputAsked != InputType.FALSE) { consoleArea.requestFocus(); if(inputAsked == InputType.CARACTER) { consoleArea.setText(consoleArea.getText() + "\nIntroduzca un carácter: "); } else if(inputAsked == InputType.NUMBER) { consoleArea.setText(consoleArea.getText() + "\nIntroduzca un número: "); } } } /** * @brief Informa de si actualmente el computador está a la espera de datos de entrada. */ public InputType getPidiendoDatos() { return inputAsked; } void displayInfo(KeyEvent e) { if(inputAsked != InputType.FALSE) { String s = consoleArea.getText(); int id = e.getID(); if (id == KeyEvent.KEY_TYPED) { s += e.getKeyChar(); } consoleArea.setText(s); if(inputBuffer == null) { inputBuffer = new String(""); } if(KeyEvent.VK_ENTER == e.getKeyChar()) { String in = getConsoleInput(); if(in == null) //Se ha pulsado enter pero no se han introducido datos { try{ 113 computer.getState().setE(0); } catch (Exception x) { } } else { if(inputAsked == InputType.NUMBER) //El dato pedido es un número { try{ int inn = Integer.parseInt(in); try{ computer.getState().setE(inn); } catch (Exception xx) { //TODO: } } catch (NumberFormatException nfe) { //TODO: } } else if(inputAsked == InputType.CARACTER) //El dato pedido es un carácter { if(in.length() == 1) { try{ int inn = (char)in.charAt(0);//Character.getNumericValue(in.charAt(0)); try{ computer.getState().setE(inn); } catch (Exception xx) { //TODO: } } catch (NumberFormatException nfe) { //TODO: } } else { //TODO: Error la cadena introducida es demasiado larga (debería ser 1 solo carácter). } } } try{ computer.executeNextInstruction(); } catch(Exception excep) { } setPidiendoDatos(InputType.FALSE); } else //Si no se ha pulsado ENTER, añadimos la entrada del teclado al buffer de entrada { inputBuffer += e.getKeyChar(); } } } @Override public void keyPressed(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } //Esta función es llamada cada vez que se pulsa una tecla mientras la consola esté enfocada. @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub displayInfo(e); } } /** * @detail Devuelve los datos del buffer de entrada del teclado * @return */ 114 public String getConsoleInput() { String r = null; if(inputBuffer != null) { r = new String(inputBuffer); } inputBuffer = null; return r; } /** * Método main, es el método de entrada del programa, el primero que se ejecuta. * @param args */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Emulator frame = new Emulator(); frame.pack(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * @brief Método que cambia el título de la ventana del emulador * @param s */ public void setMyTitle(String s) { setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); exitOnClose = false; setTitle("Emulador CESIUS - " + s); } /** * @brief Constructor que inicializa la clase */ public Emulator(){ super(); setBounds(100, 100, 800, 600); setTitle("Emulador CESIUS"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); exitOnClose = true; consoleArea = null; inputBuffer = ""; computer = new VirtualComputer(); computer.setListener(this); timer = new Timer("Timer"); task = null; //Período del reloj de la máquina en milisegundos. period = 50L; addComponentToPane(getContentPane()); } /** * Añade la cadena text a la consola * @param text */ public void addConsoleOutput(String text) { String s = consoleArea.getText(); s += text; consoleArea.setText(s); } /** * @detail Método que sirve para dar a conocer a la vista de depuración si * el computador está a la espera de datos. * @param b */ public void setPidiendoDatos(InputType b) { consolaListener.setPidiendoDatos(b); } /** * @detail Acción Ejecutar siguiente instrucción. Solo ejecuta una instrucción. */ public void actionExecuteNextInstruction() { //Check if next instruction needs some kind of input. OperationCode op = computer.getNextInstruction().getOperationCode(); 115 if(op == OperationCode.LCA || op == OperationCode.LCAI ) { /* * In that case the instruction will be executed when when we get the input. */ setPidiendoDatos(InputType.CARACTER); } else if(op == OperationCode.LEE || op == OperationCode.LEEI) { /* * In that case the instruction will be executed when when we get the input. */ setPidiendoDatos(InputType.NUMBER); } else{ //If it's not needed, execute instruction. if(op == OperationCode.ALT) { actionPause(); } else { try{ computer.executeNextInstruction(); } catch(Exception e) { //TODO: Catch exception } } } } /** * @detail Acción Pausar. Detiene la ejecución de instrucciones. */ public void actionPause() { if(task != null) { task.cancel(); task = null; } } /** * @brief Inicializa la memoria del computador con cierto código * @param codeArray Código a ejecutar */ public void setRunCode(ArrayList<Instruction> codeArray) { actionRestart(); computer.setMemoryMap(codeArray); actionRun(); } /** * @brief Acción Reiniciar. Reinicia el estado del computador. */ public void actionRestart() { if(task != null) { task.cancel(); task = null; } consoleArea.setText(""); consolaListener.setPidiendoDatos(InputType.FALSE); try { computer.restart(); actionRun(); } catch(Exception e) { } } /** * @detail Acción "Ejecutar Todo". Ejecuta las instrucciones del ordenador hasta llegar a un ALT, * con la frecuencia del computador seleccionada. */ public void actionRun() { if(task == null) { consolaListener.setPidiendoDatos(InputType.FALSE); task = new ExecuteInstructionTask(); 116 timer.scheduleAtFixedRate(task, 0, period); } } @Override public void writeNumberToScreen() { addConsoleOutput("" + computer.getState().getE()); } @Override public void stateChanged() { } @Override public void memoryChanged(Instruction i) { } /** * @brief Añade todos los componentes visuales necesarios al panel. * @param pane */ public void addComponentToPane(Container pane) { //A continuación definimos todas las acciones de la vista de emulación java.net.URL imageURL = Interface.class.getResource("images/gtk-quit.png"); ImageIcon icon = new ImageIcon(imageURL); Action actionSalir = new AbstractAction("Salir", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { if(exitOnClose) { //Cerrar todo System.exit(0); } else { //No cierra toda la aplicación, solo esta ventana. dispose(); } } }; imageURL = Interface.class.getResource("images/gnome-fs-directory.png"); icon = new ImageIcon(imageURL); Action actionAbrirEjecutable = new AbstractAction("Abrir Ejecutable", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { JFileChooser SaveAs = new JFileChooser(); ProjectFile.FileType.BINARY) SaveAs.setFileFilter(new BinaryFilter()); SaveAs.setAcceptAllFileFilterUsed(false); int actionDialog = SaveAs.showDialog(null, "Abrir"); if(actionDialog == JFileChooser.APPROVE_OPTION) { String path = SaveAs.getSelectedFile().getPath(); File fileName = new File(path); if (fileName != null) { ProjectFile codeToExecute = new ProjectFile(fileName,null); if(codeToExecute != null && codeToExecute.type == { try { //CesiusHelper core = new CesiusHelper(); ArrayList<Instruction> in = XenonHelper.openBinaryFile(codeToExecute.file); setRunCode(in); System.out.println("Ejecutando binario: " + codeToExecute.file.getName()); setTitle("Emulador CESIUS - " + codeToExecute.file.getPath()); } catch(Exception x){ System.out.println(x.getMessage()); } } } } 117 } }; imageURL = Interface.class.getResource("images/document-save.png"); icon = new ImageIcon(imageURL); Action actionGuardar = new AbstractAction("Guardar Texto de Consola", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { JFileChooser SaveAs = new JFileChooser(); int actionDialog = SaveAs.showDialog(null, "Guardar Como..."); if(actionDialog == JFileChooser.APPROVE_OPTION) { String path = SaveAs.getSelectedFile().getPath(); File fileName = new File(path); if (fileName != null) { System.out.println("Guardando " + path + " ..."); try { BufferedWriter outFile = new BufferedWriter(new FileWriter(fileName)); outFile.write(consoleArea.getText()); //put in textfile outFile.close(); } catch (IOException ex) { } } } } }; Action actionLimpiarProblemas = new AbstractAction("Limpiar", null) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { consoleArea.setText(""); } }; imageURL = Interface.class.getResource("images/reload.png"); icon = new ImageIcon(imageURL); Action actionReiniciar = new AbstractAction("Reiniciar máquina", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { actionRestart(); actionRun(); } }; //A continuación definimos la barra de menús JMenuBar menuBar = new JMenuBar(); JMenu menu; JMenuItem menuItem; menu = new JMenu("Archivo"); menuBar.add(menu); menuItem = menu.add(actionAbrirEjecutable); menu.add(menuItem); menuItem = menu.add(actionGuardar); menu.add(menuItem); menu = new JMenu("Emulador"); menuBar.add(menu); menuItem = menu.add(actionReiniciar); menu.add(menuItem); menuItem = menu.add(actionSalir); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, ActionEvent.CTRL_MASK)); menu.add(menuItem); //A continuación, la barra de herramientas JToolBar toolBar; toolBar = new JToolBar(); toolBar.setFloatable(false); 118 JButton button = toolBar.add(actionAbrirEjecutable); button.setToolTipText("Abrir Ejecutable"); button = toolBar.add(actionGuardar); button.setToolTipText("Guardar texto de la consola"); button = toolBar.add(actionReiniciar); button.setToolTipText("Reiniciar máquina"); //Iniciamos la consola consoleArea = new JTextPane(); consoleArea.setEditable(false); //Con esto, el enter será sólo un carácter raro sin efecto consoleArea.setFocusTraversalKeysEnabled(false); consolaListener = new ConsoleKeyListener(); consoleArea.addKeyListener(consolaListener); consolaListener.setPidiendoDatos(InputType.FALSE); JScrollPane scrollPane = new JScrollPane(consoleArea); JPanel codeJPanel = new JPanel(); //Añadimos el popup de limpiar consola JPopupMenu popup = new JPopupMenu(); popup.add(actionLimpiarProblemas); MouseListener popupListener = new PopupListener(popup); consoleArea.addMouseListener(popupListener); //Aquí definimos la disposición gráfica de los componentes en la vista de emulación. GroupLayout gl_menu1 = new GroupLayout(codeJPanel); gl_menu1.setHorizontalGroup( gl_menu1.createParallelGroup(Alignment.LEADING) .addComponent(menuBar, 0, 800, Short.MAX_VALUE) .addComponent(toolBar, 0, 800, Short.MAX_VALUE) .addComponent(scrollPane, 0, 800, Short.MAX_VALUE) ); gl_menu1.setVerticalGroup( gl_menu1.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu1.createSequentialGroup() .addComponent(menuBar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(toolBar, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE) .addComponent(scrollPane, 0, 560, Short.MAX_VALUE) ) ); codeJPanel.setLayout(gl_menu1); pane.add(codeJPanel); } @Override public void writeCharacterToScreen() { // TODO Auto-generated method stub char c = (char)computer.getState().getE(); addConsoleOutput(Character.toString(c)); } } 119 11.1.4 ConnectLine.java package xenon; import java.awt.*; import java.awt.geom.Point2D; /** * The class represents base line model and rendering according to multiple params. * * <p>Copyright: Copyright (c) 2007</p> * * @author Stanislav Lapitsky * @version 1.0 */ /** * @brief Una de las clases usada para pintar flechitas de un lado a otro * @detail Librería modificada por Félix Robles, código original de Stanislav Lapitsky. */ public class ConnectLine { public static final int LINE_TYPE_SIMPLE = 0; public static final int LINE_TYPE_RECT_1BREAK = 1; public static final int LINE_TYPE_RECT_2BREAK = 2; public static final int LINE_TYPE_RECT_HORIZONTAL = 3; public static final int LINE_TYPE_RECT_VERTICAL = 4; public static final int LINE_START_HORIZONTAL = 0; public static final int LINE_START_VERTICAL = 1; public public public public static static static static final final final final int int int int LINE_ARROW_NONE = LINE_ARROW_SOURCE LINE_ARROW_DEST = LINE_ARROW_BOTH = 0; = 1; 2; 3; public static int LINE_ARROW_WIDTH = 5; /** * Source line point */ Point p1; /** * Destination line point */ Point p2; /** * Line type can be one of LINE_TYPE_SIMPLE, LINE_TYPE_RECT_1BREAK, LINE_TYPE_RECT_2BREAK */ int lineType = LINE_TYPE_SIMPLE; /** * for the LINE_TYPE_RECT_2BREAK type the param defines how line should be rendered */ int lineStart = LINE_START_HORIZONTAL; /** * arrow can be one of following * LINE_ARROW_NONE - no arrow * LINE_ARROW_SOURCE - arrow beside source point * LINE_ARROW_DEST - arrow beside dest point * LINE_ARROW_BOTH - both source and dest has arrows */ int lineArrow = LINE_ARROW_NONE; /** * Constructs default line * @param p1 Point start * @param p2 Point end */ public ConnectLine(Point p1, Point p2) { this(p1, p2, LINE_TYPE_SIMPLE, LINE_START_HORIZONTAL, LINE_ARROW_NONE); } /** * Constructs line with specified params * @param p1 Point start * @param p2 Point end * @param lineType int type of line (LINE_TYPE_SIMPLE, LINE_TYPE_RECT_1BREAK, LINE_TYPE_RECT_2BREAK) * @param lineStart int for the LINE_TYPE_RECT_2BREAK type the param defines how line should be rendered * @param lineArrow int defines line arrow type */ public ConnectLine(Point p1, Point p2, int lineType, int lineStart, int lineArrow) { this.p1 = p1; this.p2 = p2; this.lineType = lineType; this.lineStart = lineStart; this.lineArrow = lineArrow; } /** * Paints the line with specified params * @param g2d Graphics2D */ public void paint(Graphics2D g2d) { 120 switch (lineType) { case LINE_TYPE_SIMPLE: paintSimple(g2d); break; case LINE_TYPE_RECT_1BREAK: paint1Break(g2d); break; case LINE_TYPE_RECT_2BREAK: paint2Breaks(g2d); break; case LINE_TYPE_RECT_HORIZONTAL: paintHorizontal(g2d); break; case LINE_TYPE_RECT_VERTICAL: paintVertical(g2d); break; } } protected void paintVertical(Graphics2D g2d) { Point pp1 = new Point(p1.x, p1.y); Point pp2 = new Point(p1.x, p2.y); g2d.drawLine(p1.x, p1.y, p1.x, p2.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, pp1, pp2); break; case LINE_ARROW_SOURCE: paintArrow(g2d, pp2, pp1); break; case LINE_ARROW_BOTH: paintArrow(g2d, pp1, pp2); paintArrow(g2d, pp2, pp1); break; } } protected void paintHorizontal(Graphics2D g2d) { Point pp1 = new Point(p1.x, p1.y); Point pp2 = new Point(p2.x, p1.y); g2d.drawLine(p1.x, p1.y, p2.x, p1.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, pp1, pp2); break; case LINE_ARROW_SOURCE: paintArrow(g2d, pp2, pp1); break; case LINE_ARROW_BOTH: paintArrow(g2d, pp1, pp2); paintArrow(g2d, pp2, pp1); break; } } protected void paintSimple(Graphics2D g2d) { g2d.drawLine(p1.x, p1.y, p2.x, p2.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, p1, p2); break; case LINE_ARROW_SOURCE: paintArrow(g2d, p2, p1); break; case LINE_ARROW_BOTH: paintArrow(g2d, p1, p2); paintArrow(g2d, p2, p1); break; } } protected void paintArrow(Graphics2D g2d, Point p1, Point p2) { paintArrow(g2d, p1, p2, getRestrictedArrowWidth(p1, p2)); } protected void paintArrow(Graphics2D g2d, Point p1, Point p2, int width) { Point2D.Float pp1 = new Point2D.Float(p1.x, p1.y); Point2D.Float pp2 = new Point2D.Float(p2.x, p2.y); Point2D.Float left = getLeftArrowPoint(pp1, pp2, width); Point2D.Float right = getRightArrowPoint(pp1, pp2, width); Polygon arrowHead = arrowHead.addPoint( arrowHead.addPoint( arrowHead.addPoint( new Polygon(); p2.x, p2.y); Math.round(left.x), Math.round(left.y)); Math.round(right.x), Math.round(right.y)); Graphics2D g = (Graphics2D) g2d.create(); g.fill(arrowHead); g.dispose(); /* g2d.drawLine(p2.x, p2.y, Math.round(left.x), Math.round(left.y)); g2d.drawLine(p2.x, p2.y, Math.round(right.x), Math.round(right.y)); */ } 121 protected void paint1Break(Graphics2D g2d) { if (lineStart == LINE_START_HORIZONTAL) { g2d.drawLine(p1.x, p1.y, p2.x, p1.y); g2d.drawLine(p2.x, p1.y, p2.x, p2.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, new Point(p2.x, p1.y), break; case LINE_ARROW_SOURCE: paintArrow(g2d, new Point(p2.x, p1.y), break; case LINE_ARROW_BOTH: paintArrow(g2d, new Point(p2.x, p1.y), paintArrow(g2d, new Point(p2.x, p1.y), break; } } else if (lineStart == LINE_START_VERTICAL) { g2d.drawLine(p1.x, p1.y, p1.x, p2.y); g2d.drawLine(p1.x, p2.y, p2.x, p2.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, new Point(p1.x, p2.y), break; case LINE_ARROW_SOURCE: paintArrow(g2d, new Point(p1.x, p2.y), break; case LINE_ARROW_BOTH: paintArrow(g2d, new Point(p1.x, p2.y), paintArrow(g2d, new Point(p1.x, p2.y), break; } } } p2); p1); p2); p1); p2); p1); p2); p1); protected void paint2Breaks(Graphics2D g2d) { if (lineStart == LINE_START_HORIZONTAL) { g2d.drawLine(p1.x, p1.y, p1.x + (p2.x - p1.x) / 2, p1.y); g2d.drawLine(p1.x + (p2.x - p1.x) / 2, p1.y, p1.x + (p2.x - p1.x) / 2, p2.y); g2d.drawLine(p1.x + (p2.x - p1.x) / 2, p2.y, p2.x, p2.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, new Point(p1.x + (p2.x - p1.x) / 2, p2.y), p2); break; case LINE_ARROW_SOURCE: paintArrow(g2d, new Point(p1.x + (p2.x - p1.x) / 2, p1.y), p1); break; case LINE_ARROW_BOTH: paintArrow(g2d, new Point(p1.x + (p2.x - p1.x) / 2, p2.y), p2); paintArrow(g2d, new Point(p1.x + (p2.x - p1.x) / 2, p1.y), p1); break; } } else if (lineStart == LINE_START_VERTICAL) { g2d.drawLine(p1.x, p1.y, p1.x, p1.y + (p2.y - p1.y) / 2); g2d.drawLine(p1.x, p1.y + (p2.y - p1.y) / 2, p2.x, p1.y + (p2.y - p1.y) / 2); g2d.drawLine(p2.x, p1.y + (p2.y - p1.y) / 2, p2.x, p2.y); switch (lineArrow) { case LINE_ARROW_DEST: paintArrow(g2d, new break; case LINE_ARROW_SOURCE: paintArrow(g2d, new break; case LINE_ARROW_BOTH: paintArrow(g2d, new paintArrow(g2d, new break; } Point(p2.x, p1.y + (p2.y - p1.y) / 2), p2); Point(p1.x, p1.y + (p2.y - p1.y) / 2), p1); Point(p2.x, p1.y + (p2.y - p1.y) / 2), p2); Point(p1.x, p1.y + (p2.y - p1.y) / 2), p1); } } public int getLineType() { return lineType; } public void setLineType(int type) { lineType = type; } public int getLineStart() { return lineStart; } public void setLineStart(int start) { lineStart = start; } public int getLineArrow() { return lineArrow; 122 } public void setLineArrow(int arrow) { lineType = lineArrow; } public Point getP1() { return p1; } public void setP1(Point p) { p1 = p; } public Point getP2() { return p2; } public void setP2(Point p) { p2 = p; } protected static Point2D.Float getMidArrowPoint(Point2D.Float p1, Point2D.Float p2, float w) { Point2D.Float res = new Point2D.Float(); float d = Math.round(Math.sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))); if (p1.x < p2.x) { res.x = p2.x - w * Math.abs(p1.x - p2.x) / d; } else { res.x = p2.x + w * Math.abs(p1.x - p2.x) / d; } if (p1.y < p2.y) { res.y = p2.y - w * Math.abs(p1.y - p2.y) / d; } else { res.y = p2.y + w * Math.abs(p1.y - p2.y) / d; } return res; } protected static Point2D.Float getLeftArrowPoint(Point2D.Float p1, Point2D.Float p2) { return getLeftArrowPoint(p1, p2, LINE_ARROW_WIDTH); } protected static Point2D.Float getLeftArrowPoint(Point2D.Float p1, Point2D.Float p2, float w) { Point2D.Float res = new Point2D.Float(); double alpha = Math.PI / 2; if (p2.x != p1.x) { alpha = Math.atan( (p2.y - p1.y) / (p2.x - p1.x)); } alpha += Math.PI / 5; float xShift = Math.abs(Math.round(Math.cos(alpha) * w)); float yShift = Math.abs(Math.round(Math.sin(alpha) * w)); if (p1.x <= p2.x) { res.x = p2.x - xShift; } else { res.x = p2.x + xShift; } if (p1.y < p2.y) { res.y = p2.y - yShift; } else { res.y = p2.y + yShift; } return res; } protected static Point2D.Float getRightArrowPoint(Point2D.Float p1, Point2D.Float p2) { return getRightArrowPoint(p1, p2, LINE_ARROW_WIDTH); } protected static Point2D.Float getRightArrowPoint(Point2D.Float p1, Point2D.Float p2, float w) { Point2D.Float res = new Point2D.Float(); double alpha = Math.PI / 2; if (p2.x != p1.x) { alpha = Math.atan( (p2.y - p1.y) / (p2.x - p1.x)); } alpha -= Math.PI / 5; float xShift = Math.abs(Math.round(Math.cos(alpha) * w)); float yShift = Math.abs(Math.round(Math.sin(alpha) * w)); if (p1.x < p2.x) { res.x = p2.x - xShift; } else { res.x = p2.x + xShift; } if (p1.y <= p2.y) { res.y = p2.y - yShift; 123 } else { res.y = p2.y + yShift; } return res; } protected int getRestrictedArrowWidth(Point p1, Point p2) { return Math.min(LINE_ARROW_WIDTH, (int) Math.sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))); } } 124 11.1.5 LineCode.java package xenon; import xenon.XenonHelper.PseudoInstruction; /** * @brief Contiene la información de una línea de texto del código ensamblador. * Es una clase intermediaria usada en la compilación del código ensamblador. */ public class LineCode{ public Instruction instruction; public String label; public int address; //Posición de memoria donde se encuentra esta instrucción, no confundir con LineCode.instruction.getMemoryAddress. public String addressLabel; // Necesario en un paso intermedio. Hay que traducirlo y meterlo en LineCode.instruction.setMemoryAddress. public int lineNumber; public PseudoInstruction pseudoInstruction; LineCode() { instruction = new Instruction(); label = null; address = -1; addressLabel = null; pseudoInstruction = null; lineNumber = -1; } public String toString() { String s = new String(); return s; } public int check() { int r = 0; if(lineNumber < 0) { r = -1; } else if(address < 0 || address > Instruction.Memory_Address_Limit) { System.out.println("Error: address " + address + " out of bounds"); r = -2; } else if(pseudoInstruction == null) { if(instruction == null) { r = -3; } else if( instruction.isInstruction() ) { //Es una instrucción } else if( !instruction.isInstruction() ) { //Es simplemente datos } } else if(pseudoInstruction != null) { switch(pseudoInstruction) { case ORG: case FIN: case ESP: case CTE: //Todo OK break; //No deberíamos haber guardado esta pseudo instrucción!! r = -4; break; int d = 0; try { instruction.setInstructionSigned(d); } catch(Exception e) { } break; break; } } return r; } }; 125 11.1.6 Sobre.java package xenon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import import import import import javax.swing.JButton; javax.swing.JDialog; javax.swing.JLabel; javax.swing.UIManager; javax.swing.GroupLayout; /** * @brief Esta clase implementa una ventana popup que muestra información sobre el autor * del proyecto, así como del profesor tutor del mismo. * */ public class Sobre extends JDialog implements ActionListener{ /** * */ private static final long serialVersionUID = 1L; /** * Lanzar ventana/aplicación */ public static void main(String[] args) { try { Sobre dialog = new Sobre(0,0); dialog.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } public void actionPerformed(ActionEvent e) { //No cierra toda la aplicación, solo esta ventana. dispose(); } /** * Crear diálogo. */ public Sobre(int xoffset, int yoffset) { setBounds(285+xoffset, 220+yoffset, 360, 245); setTitle("Sobre este programa"); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); JLabel infoIcon = new JLabel( UIManager.getIcon("OptionPane.informationIcon")); JLabel info1 = new JLabel(" CESIUS IDE v0.3"); JLabel info2 = new JLabel("© Copyright 2013"); JLabel info3 = new JLabel("Proyecto Fin de Carrera"); JLabel info4 = new JLabel("E.T.S.I. Universidad de Sevilla"); JLabel info5 = new JLabel("Autor: Félix Robles Elvira,"); JLabel info6 = new JLabel("e-mail: [email protected]"); JLabel info7 = new JLabel("Tutor: José Ángel Acosta Rodríguez,"); JLabel info8 = new JLabel("e-mail: [email protected]"); JLabel info9 = new JLabel("Licencia GPLv3.0"); JButton okButton = new JButton("OK"); okButton.addActionListener(this); GroupLayout groupLayout = new GroupLayout(getContentPane()); groupLayout.setHorizontalGroup( groupLayout.createSequentialGroup() .addGap(30) .addComponent(infoIcon) .addGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(info1) .addComponent(info2) .addComponent(info3) .addComponent(info4) .addComponent(info5) .addComponent(info6) .addComponent(info7) .addComponent(info8) .addComponent(info9) .addComponent(okButton) ) ); groupLayout.setVerticalGroup(groupLayout.createSequentialGroup() .addGap(10) .addGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(infoIcon) .addComponent(info1) ) .addComponent(info2) .addComponent(info3) 126 .addComponent(info4) .addComponent(info5) .addComponent(info6) .addComponent(info7) .addComponent(info8) .addComponent(info9) .addGap(20) .addComponent(okButton) ); getContentPane().setLayout(groupLayout); } } 127 11.1.7 ConnectorContainer.java package xenon; import javax.swing.*; import java.awt.*; import java.util.ArrayList; /** * The collateral class contains array of connectors and renders them. * The rendering can be called in a different way. E.g. JConnectors can be just * added as usual component. In this case programmer must care about their size, * and layout. * * <p>Copyright: Copyright (c) 2007</p> * * @author Stanislav Lapitsky * @version 1.0 */ /** * @brief Una de las clases usada para pintar flechitas de un lado a otro * @detail Librería modificada por Félix Robles, código original de Stanislav Lapitsky. */ public class ConnectorContainer extends JPanel { /** * */ private static final long serialVersionUID = 1L; ArrayList<JConnector> connectors; /** * @brief Constructor de la clase, inicializa el atributo connectors. */ public ConnectorContainer() { connectors = new ArrayList<JConnector> (); } /** * @brief Añade un conector al panel. */ public void addConnector(JConnector c) { connectors.add(c); } /** * @brief Añade una lista de conectores al panel. */ public void addConnectors(ArrayList<JConnector> c) { for(JConnector i: c) { connectors.add(i); } } /** * @brief Devuelve los conectores del panel. */ public ArrayList<JConnector> getConnectors() { return connectors; } /** * @brief Pinta los conectores del panel. */ public void paint(Graphics g) { super.paint(g); for(JConnector c: connectors) { c.paint(g); } } } 128 11.1.8 PopupListener.java package xenon; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JPopupMenu; /** * * @brief Esta clase hace de listener de forma que muestra un popup cuando lo activa el ratón. * */ class PopupListener extends MouseAdapter { private JPopupMenu popup; PopupListener(JPopupMenu p) { popup = p; } public void mousePressed(MouseEvent e) { showPopup(e); } public void mouseReleased(MouseEvent e) { showPopup(e); } private void showPopup(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } 129 11.1.9 Tab.java package xenon; import import import import java.awt.event.KeyEvent; java.awt.event.KeyListener; java.io.BufferedReader; java.io.FileReader; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import xenon.ProjectFile.FileType; /** * * @brief Esta clase define una pestaña. * */ public class Tab extends JScrollPane implements KeyListener{ /** * */ public static final long serialVersionUID = -8100218024452896927L; public ProjectFile pFile; //Fichero que contiene la pestaña public JTextArea textArea; //Área de texto de la pestaña private JLabel label; //Etiqueta de la pestaña private boolean isModified; //Indica si el texto ha sido modificado y todavía no se ha guardado /** * @brief Modifica la etiqueta de la pestaña. * @param l */ public void setLabel(JLabel l) { label = l; } /** * @brief Indica si hay cambios no guardados del fichero. * @return */ public boolean isModified() { return isModified; } /** * @brief Marca el fichero como modificado/no modificado. * @param b */ public void setModified(boolean b) { if(isModified == false && b == true) { label.setText("*" + label.getText()); } else if (isModified == true && b == false) { label.setText(label.getText().substring(1)); } isModified = b; } /** * Constructor * @param ta JTextArea de la pestaña * @param pf Fichero que contiene la pestaña */ Tab(JTextArea ta, ProjectFile pf) { super(ta); textArea = ta; pFile = pf; isModified = false; label = null; if(pFile.type == ProjectFile.FileType.TEXT || pFile.type == ProjectFile.FileType.CODE) { try { String strLine; BufferedReader br = new BufferedReader(new FileReader(pFile.file)); while((strLine = br.readLine()) != null) { textArea.append(strLine + "\n"); } } catch(Exception e) { 130 } System.err.println("Error: " + e.getMessage()); } else if(pFile.type == ProjectFile.FileType.BINARY) { textArea.setEditable(false); } textArea.addKeyListener(this); } /** * Al escribir en una pestaña, indicamos que el archivo de texto está siendo modificado. */ @Override public void keyPressed(KeyEvent arg0) { if(pFile.type != FileType.BINARY) { setModified(true); } } @Override public void keyReleased(KeyEvent arg0) { } @Override public void keyTyped(KeyEvent arg0) { } } 131 11.1.10 DebugViewManager.java package xenon; import import import import import import import import import import import import import import import import import import import java.awt.Color; java.awt.Component; java.awt.Dimension; java.awt.event.ActionEvent; java.awt.event.ItemEvent; java.awt.event.ItemListener; java.awt.event.KeyEvent; java.awt.event.KeyListener; java.awt.event.MouseListener; java.beans.PropertyChangeEvent; java.beans.PropertyChangeListener; java.io.BufferedWriter; java.io.File; java.io.FileWriter; java.io.IOException; java.util.ArrayList; java.util.Timer; java.util.TimerTask; java.util.Vector; import import import import import import import import import import import import import import import import import import import javax.swing.AbstractAction; javax.swing.Action; javax.swing.BorderFactory; javax.swing.GroupLayout; javax.swing.GroupLayout.Alignment; javax.swing.ImageIcon; javax.swing.JLabel; javax.swing.JPopupMenu; javax.swing.JScrollPane; javax.swing.JSplitPane; javax.swing.JTabbedPane; javax.swing.JTable; javax.swing.JTextField; javax.swing.JTextPane; javax.swing.ListSelectionModel; javax.swing.event.ListSelectionEvent; javax.swing.event.ListSelectionListener; javax.swing.table.DefaultTableCellRenderer; javax.swing.table.DefaultTableModel; import xenon.VirtualComputer.ComputerRegister; import xenon.VirtualComputer.ComputerSignal; import xenon.VirtualComputer.ComputerState; /** * @brief Clase gestora de la vista de depuración. * @detail Esta clase realiza todas las tareas de la interfaz gráfica de la vista de depuración, * además de lidiar con la clase VirtualComputer. */ public class DebugViewManager extends JSplitPane implements VirtualComputer.VirtualComputerListener, ItemListener{ /** * * @brief Base usada para representar los registros y el contenido de la memoria. * */ public enum Base { BINARY, DECIMAL, HEXADECIMAL }; /** * * @brief FALSE: Actualmente no se está pidiendo ningún dato de entrada. * CARACTER: El computador necesita un carácter como dato de entrada. * NUMBER: El computador necesita un número como dato de entrada. * */ public enum InputType { FALSE,CARACTER, NUMBER }; private boolean isCheckBoxSelected, executeSemisteps; private JTextPane consolaPane; //Consola private ConsoleKeyListener consolaListener; //Listener que recoge y trata //Buffer de entrada. Se van añadiendo datos hasta recibir un enter (en el caso de que el private String inputBuffer; private long period; del computador en milisegundos = 1000/f private int runTo; dirección de memoria en la que parar la ejecución private ColorCellRenderer pTableRenderer; //Renderer de la tabla pTable private ColorCellRenderer memoriaTableRenderer;//Renderer de la tabla memoriaTable private File debugFile; private Trace execTrace; //Variables que sirven para mantener la cuenta del reloj del computador public long startTime; 132 de entrada y salida de datos la entrada proveniente del teclado computador esté pidiendo datos) //Período de reloj de una instrucción //En el caso de "Ejecutar Hasta", public long nextTime, nextTime2; //Timer usado para organizar la ejecución de instrucciones en modo runMode Timer instructionTimer; //Timer usado para los cambios de registro Timer changesTimer; //Tarea de ejecución de una instrucción ExecuteInstructionTask instructionTask; //Etiqueta del reloj del computador JLabel timeLabel; //Tablas de memoria. pTable muestra la memoria entorno a P. private JTable pTable, memoriaTable; //Etiquetas que muestran el contenido de los registros del computador private FlashyTextField textFieldA, textFieldP, textFieldS, textFieldI, textFieldT, textFieldE, textFieldCO, textFieldMD; //Etiquetas que muestran las señales del computador private FlashySignal etLabel, stLabel, eeLabel, seLabel, escpLabel, leetLabel, eaLabel, saLabel, eoLabel, sumaLabel, resaLabel, multaLabel, incpLabel, epLabel, spLabel, esLabel, sdLabel, eiLabel, lecmLabel, escmLabel, divaLabel, modaLabel; //Etiquetas CO/MD/D que han de ser no visibles cuando no estamos en modo binario JLabel coLabel, mdLabel, dLabel; //Variable que contiene la base que actualmente se usa para representar datos private Base base; //Instancia del computador que se está emulando private VirtualComputer computer; /** * */ private static final long serialVersionUID = 1L; /** * @brief Esta clase sirve para crear una traza de la ejecución del programa. */ class Trace{ File f; Trace(File file) { String dir = file.getParent(); f = new File(dir + "/traza.txt"); System.out.println(f.getAbsolutePath()); restart(); } public void restart(){ try { BufferedWriter outFile = new BufferedWriter(new FileWriter(f, false)); outFile.write("Address\t\tP\t\tI\t\tA\t\tT\t\tS\t\tS"); outFile.newLine(); outFile.close(); } catch (IOException ex) { } } public void registerStep(Instruction i, VirtualComputer.ComputerState s){ try { BufferedWriter outFile = new BufferedWriter(new FileWriter(f, true)); outFile.write(i.getAddressLocation() + "\t\t" + s.getP() + "\t\t" + i.getOperationCode().name() + " " + i.getInstructionOperator() + "\t\t" + s.getA() + "\t\t" + s.getT() + "\t\t" + s.getS() + "\t\t" + s.getE()); //put in textfile outFile.newLine(); outFile.close(); } catch (IOException ex) { } } } /** * @brief Tarea que ejecuta una instrucción. * @detail El timer instructionTimer llamará a la función run() una vez por el período de tiempo fijado. * Esa función se encarga de ejecutar la siguiente instrucción. */ class ExecuteInstructionTask extends TimerTask{ @Override public void run() { //Hemos llegado a la instrucción en la que queríamos parar if(runTo != -1 && computer.getState().getP() == runTo) { actionPause(); } //Si el computador no está pidiendo datos de entrada, ejecutamos la siguiente instrucción else if(consolaListener.getPidiendoDatos() == InputType.FALSE) { executeNextInstruction(); if(startTime > 0) { //Actualizamos el tiempo de ejecución después de ejecutar cada instrucción timeLabel.setText(addZeros((System.currentTimeMillis()-startTime)+"", 6) + " ms"); 133 } } } public void stop(){ this.cancel(); } } /** * @brief Clase que escucha cuándo se selecciona una nueva posición de memoria. * @detail Cuando el usuario seleccione una posición de memoria en la tabla, el registro P cambiará su valor. */ class TableListener implements ListSelectionListener { @Override public void valueChanged(ListSelectionEvent arg0) { try{ if(computer.getState().getP() != pTable.getSelectedRow()) { consolaListener.setPidiendoDatos(InputType.FALSE); computer.getState().setP(pTable.getSelectedRow()); computer.getState().setRegisterChanged(ComputerRegister.P, true); computer.getState().sendSignals(); } } catch(Exception e) { } } } /** * @brief Clase que escucha la entrada del teclado y la representa en la consola. * @detail Cuando el usuario presione ENTER, los datos se mandarán al computador. */ class ConsoleKeyListener implements KeyListener { private InputType inputAsked; /** * Informa al listener de si el computador está pidiendo datos. * @param b Define si el computador está pidiendo datos, y de qué tipo */ public void setPidiendoDatos(InputType b) { inputAsked = b; if(inputAsked != InputType.FALSE) { consolaPane.requestFocus(); if(inputAsked == InputType.CARACTER) { consolaPane.setText(consolaPane.getText() + "\nIntroduzca un carácter: "); } else if(inputAsked == InputType.NUMBER) { consolaPane.setText(consolaPane.getText() + "\nIntroduzca un número: "); } } } /** * @brief Informa de si actualmente el computador está a la espera de datos de entrada. */ public InputType getPidiendoDatos() { return inputAsked; } void displayInfo(KeyEvent e) { if(e.getModifiers() == 0 &&inputAsked != InputType.FALSE) { String s = consolaPane.getText(); int id = e.getID(); if (id == KeyEvent.KEY_TYPED) { s += e.getKeyChar(); } consolaPane.setText(s); if(inputBuffer == null) 134 { inputBuffer = new String(""); } //Cuando se pulsa Enter, se envían los datos al computador if(KeyEvent.VK_ENTER == e.getKeyChar()) { String in = getConsoleInput(); Instruction.OperationCode op = computer.getNextInstruction().getOperationCode(); Instruction nextIns = new Instruction(); try{ nextIns.setInstructionSigned(computer.getNextInstruction().getDataSigned()); nextIns.setAddressLocation(computer.getNextInstruction().getAddressLocation()); } catch (Exception ee) { } if(in == null) { //Se ha pulsado enter pero no se han introducido datos try{ computer.getState().setE(0); computer.getState().setRegisterChanged(ComputerRegister.E, true); computer.getState().sendSignals(); } catch (Exception x) { } } else { if(inputAsked == InputType.NUMBER) { //El dato pedido es un número try{ int inn = Integer.parseInt(in); try{ computer.getState().setE(inn); computer.getState().setRegisterChanged(ComputerRegister.E, true); computer.getState().sendSignals(); } catch (Exception xx) { //TODO: } } catch (NumberFormatException nfe) { //TODO: } } else if(inputAsked == InputType.CARACTER) { //El dato pedido es un carácter if(in.length() == 1) { try{ int inn = (char)in.charAt(0);//Character.getNumericValue(in.charAt(0)); try{ computer.getState().setE(inn); computer.getState().setRegisterChanged(ComputerRegister.E, true); computer.getState().sendSignals(); } catch (Exception xx) { //TODO: } } catch (NumberFormatException nfe) { //TODO: } } else { //TODO: Error la cadena introducida es demasiado larga (debería ser 1 solo carácter). } } } try{ if(executeSemisteps == false) { computer.executeNextInstruction(); } else if(executeSemisteps == true) { if(computer.getSemistepInfo() == VirtualComputer.Last_Semistep) { computer.executeSemistep(); 135 } } if(execTrace != null) { execTrace.registerStep(nextIns, computer.getState()); } if(nextTime > 0) { nextTime = System.currentTimeMillis()-nextTime2+nextTime; timeLabel.setText(addZeros(nextTime+"", 6) + " ms"); } else if( startTime > 0) { timeLabel.setText(addZeros((System.currentTimeMillis()-startTime)+"", 6) + " ms"); } } catch(Exception excep) { } setPidiendoDatos(InputType.FALSE); } else // Si no se ha pulsado ENTER, añadimos la entrada del teclado al buffer de entrada { inputBuffer += e.getKeyChar(); } } } @Override public void keyPressed(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } //Esta función es llamada cada vez que se pulsa una tecla mientras la consola esté enfocada. @Override public void keyTyped(KeyEvent e) { displayInfo(e); } } /** * * @brief Esta clase sirve para resaltar las posiciones de memoria que cambian en la JTable correspondiente * */ class ColorCellRenderer extends DefaultTableCellRenderer{ JTable table; //Tabla a la que pertenecen las celdas private int dir; /** * */ ColorCellRenderer(JTable t) { table = t; dir = -1; this.setHorizontalAlignment(RIGHT); } private static final long serialVersionUID = 1L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); //cellComponent.setBackground(Color.WHITE); if(row != dir && !isSelected) { cellComponent.setBackground(Color.WHITE); } else if(row == dir && !isSelected) { cellComponent.setBackground(new Color(0, 184, 245)); } return cellComponent; } void restart(){ dir = -1; table.repaint(); } 136 void flash(int row) { if (row >= 0 && row < table.getRowCount()) { if(dir != row) { dir = row; table.repaint(); } } } } /** * * @brief Versión de JLabel que sirve para marcar cuándo se usan las señales del computador * */ class FlashySignal extends JLabel{ /** * */ private static final long serialVersionUID = 1L; FlashySignal(String s, Timer t){ super(s); setForeground(Color.LIGHT_GRAY); } /** * @brief Desmarca la señal */ public void restart() { setForeground(Color.LIGHT_GRAY); } /** * Marca la señal */ public void flash(Color c) { //setForeground(new Color(0, 184, 245)); setForeground(c); } } /** * @brief Versión de JTextField que marca en azul cuando un registro es actualizado. */ class FlashyTextField extends JTextField{ /** * */ private static final long serialVersionUID = 1L; private Color baseBackground; FlashyTextField(String text, Timer t) { super(text); baseBackground = new Color(238,238, 238); //fondo gris } /** * @brief Desmarca la señal */ public void restart() { setBackground(baseBackground); } /** * Marca la señal */ public void flash(Color c) { if(getBackground() != c) { setBackground(c); } } } /** * @detail Método que sirve para dar a conocer a la vista de depuración si * el computador está a la espera de datos. * @param b */ public void setPidiendoDatos(InputType b) { consolaListener.setPidiendoDatos(b); } 137 /** * @brief Método que cambia la base en que se muestran los datos */ public void setRegistersBase(Base b) { base = b; if(base == Base.BINARY) { //En este caso mostramos CO y MD textFieldCO.setBorder(textFieldA.getBorder()); textFieldMD.setBorder(textFieldA.getBorder()); coLabel.setForeground(Color.BLACK); mdLabel.setForeground(Color.BLACK); dLabel.setForeground(Color.BLACK); } else { //En este caso ocultamos CO y MD textFieldCO.setBorder(BorderFactory.createLineBorder(new Color(238, 238, 238))); textFieldMD.setBorder(BorderFactory.createLineBorder(new Color(238, 238, 238))); coLabel.setForeground(new Color(238, 238, 238)); mdLabel.setForeground(new Color(238, 238, 238)); dLabel.setForeground(new Color(238, 238, 238)); } updateJTableModel(); stateChanged(); } /** * Método que cambia el período de ejecución. Este cambio de período se notará la siguiente vez * que se ejecute el código en modo "Ejecutar todo" o "Ejecutar hasta" * @param millisecs */ public void setExecutionPeriod(long millisecs) { period = millisecs; } /** * @detail Devuelve los datos del buffer de entrada del teclado * @return */ public String getConsoleInput() { String r = null; if(inputBuffer != null) { r = new String(inputBuffer); } inputBuffer = null; return r; } /** * @detail Añade el texto del parámetro text a la consola * @param text */ public void addConsoleOutput(String text) { String s = consolaPane.getText(); s += text; consolaPane.setText(s); } /** * @brief Centra la tabla pTable en la posición indicada por el parámetro de entrada p * @param p */ public void selectNextInstructionInMemoryNearP(int p) { int count = (int)pTable.getRowCount(); if(p >= 0 && p < count && count > 0) { pTable.setRowSelectionInterval(p, p); int scrollTo = Math.min(p+7, count-1); if(scrollTo >= 0 && scrollTo < count) { pTable.scrollRectToVisible(pTable.getCellRect(scrollTo, 0, true)); } } } /** * @detail Acción "Ejecutar Todo". Ejecuta las instrucciones del ordenador hasta llegar a un ALT, * con la frecuencia del computador seleccionada. */ public void actionRun() { if(instructionTask == null) { //runMode = true; if(isCheckBoxSelected == false) 138 { executeSemisteps = false; consolaListener.setPidiendoDatos(InputType.FALSE); instructionTask = new ExecuteInstructionTask(); instructionTimer.scheduleAtFixedRate(instructionTask, 0, period); startTime = System.currentTimeMillis(); nextTime = -1; } else if (isCheckBoxSelected == true) { executeSemisteps = true; consolaListener.setPidiendoDatos(InputType.FALSE); instructionTask = new ExecuteInstructionTask(); instructionTimer.scheduleAtFixedRate(instructionTask, 0, period/2); startTime = System.currentTimeMillis(); nextTime = -1; } } } /** * @detail Acción "Ejecutar Todo". Ejecuta las instrucciones del ordenador hasta llegar a cierta instrucción, * o a un ALT, con la frecuencia del computador seleccionada. */ public void actionRunTo(int num) { actionPause(); if(instructionTask == null && num >= 0 && num <= Instruction.Memory_Address_Limit) { //runMode = true; if(isCheckBoxSelected == false) { executeSemisteps = false; runTo = num; consolaListener.setPidiendoDatos(InputType.FALSE); instructionTask = new ExecuteInstructionTask(); instructionTimer.scheduleAtFixedRate(instructionTask, 0, period); startTime = System.currentTimeMillis(); nextTime = -1; } else if (isCheckBoxSelected == true) { executeSemisteps = true; runTo = num; consolaListener.setPidiendoDatos(InputType.FALSE); instructionTask = new ExecuteInstructionTask(); instructionTimer.scheduleAtFixedRate(instructionTask, 0, period/2); startTime = System.currentTimeMillis(); nextTime = -1; } } } /** * @detail Acción Pausar. Detiene la ejecución de instrucciones. */ public void actionPause() { //runMode = false; runTo = -1; if(instructionTask != null) { instructionTask.cancel(); instructionTask = null; } } /** * @detail Acción Reiniciar. Reinicia el estado del computador. */ public void actionRestart() { if(execTrace != null) { execTrace.restart(); } pTableRenderer.restart(); memoriaTableRenderer.restart(); runTo = -1; if(instructionTask != null) { instructionTask.cancel(); instructionTask = null; } consolaPane.setText(""); startTime = -1; nextTime = -1; timeLabel.setText(addZeros("0", 6) + " ms"); try { computer.restart(); 139 consolaListener.setPidiendoDatos(InputType.FALSE); } catch(Exception e) { } } /** * @detail Acción Ejecutar siguiente instrucción. Solo ejecuta una instrucción. */ public void actionExecuteNextInstruction() { if(isCheckBoxSelected == false) { executeSemisteps = false; } else if (isCheckBoxSelected == true) { executeSemisteps = true; } executeNextInstruction(); } public void executeNextInstruction() { pTableRenderer.restart(); memoriaTableRenderer.restart(); if(nextTime < 0) { nextTime = 0; } nextTime2 = System.currentTimeMillis(); if(executeSemisteps == false) { //Check if next instruction needs some kind of input. Instruction.OperationCode op = computer.getNextInstruction().getOperationCode(); Instruction nextIns = new Instruction(); try{ nextIns.setInstructionSigned(computer.getNextInstruction().getDataSigned()); nextIns.setAddressLocation(computer.getNextInstruction().getAddressLocation()); } catch (Exception e) { } if(op == Instruction.OperationCode.LCA || op == Instruction.OperationCode.LCAI ) { /* * In that case the instruction will be executed when when we get the input. */ setPidiendoDatos(InputType.CARACTER); } else if(op == Instruction.OperationCode.LEE || op == Instruction.OperationCode.LEEI) { /* * In that case the instruction will be executed when when we get the input. */ setPidiendoDatos(InputType.NUMBER); } else{ //If it's not needed, execute instruction. if(op == Instruction.OperationCode.ALT) { actionPause(); nextTime = System.currentTimeMillis()-nextTime2+nextTime; timeLabel.setText(addZeros(nextTime+"", 6) + " ms"); } else { try{ computer.executeNextInstruction(); if(execTrace != null) { execTrace.registerStep(nextIns, computer.getState()); } nextTime = System.currentTimeMillis()-nextTime2+nextTime; timeLabel.setText(addZeros(nextTime+"", 6) + " ms"); } catch(Exception e) { //TODO: Catch exception } } } } else if (executeSemisteps == true) { if(computer.getSemistepInfo() == VirtualComputer.First_Semistep) { try{ computer.executeSemistep(); 140 } catch (Exception e) { } } else if(computer.getSemistepInfo() == VirtualComputer.Last_Semistep) { //Check if next instruction needs some kind of input. Instruction.OperationCode op = computer.getNextInstruction().getOperationCode(); Instruction nextIns = new Instruction(); try{ nextIns.setInstructionSigned(computer.getNextInstruction().getDataSigned()); nextIns.setAddressLocation(computer.getNextInstruction().getAddressLocation()); } catch (Exception e) { } if(op == Instruction.OperationCode.LCA || op == Instruction.OperationCode.LCAI ) { /* * In that case the instruction will be executed when when we get the input. */ setPidiendoDatos(InputType.CARACTER); } else if(op == Instruction.OperationCode.LEE || op == Instruction.OperationCode.LEEI) { /* * In that case the instruction will be executed when when we get the input. */ setPidiendoDatos(InputType.NUMBER); } else{ //If it's not needed, execute instruction. if(op == Instruction.OperationCode.ALT) { actionPause(); nextTime = System.currentTimeMillis()-nextTime2+nextTime; timeLabel.setText(addZeros(nextTime+"", 6) + " ms"); } else { try{ computer.executeSemistep(); if(execTrace != null) { execTrace.registerStep(nextIns, computer.getState()); } nextTime = System.currentTimeMillis()-nextTime2+nextTime; timeLabel.setText(addZeros(nextTime+"", 6) + " ms"); } catch(Exception e) { //TODO: Catch exception } } } } } } /** * @detail Cuando cierta posición de memoria cambia, este método es llamado para actualizar * la fila adecuada de tabla de memoria de la interfaz gráfica. */ public void changeMemoryAddress(Instruction i) throws IndexOutOfBoundsException { int ma = i.getAddressLocation(); DefaultTableModel tModel = (DefaultTableModel) pTable.getModel(); DefaultTableModel mModel = (DefaultTableModel) memoriaTable.getModel(); if(ma >= 0 && ma < tModel.getRowCount()) { //colorRenderer.flash(memoriaTable, ma, changesTimer); if(i.isInstruction()) { tModel.setValueAt(Integer.toString(ma), ma, 0); tModel.setValueAt(i.getOperationCode().name(), ma, 1); tModel.setValueAt(Integer.toString(i.getInstructionOperator()), ma, 2); if(base == Base.DECIMAL) { tModel.setValueAt(Integer.toString(i.getDataSigned()), ma, 3); mModel.setValueAt(Integer.toString(i.getDataSigned()), ma, 3); } else if(base == Base.BINARY) { tModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), 2), 16), ma, 3); mModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), 2), 16), ma, 3); } else if(base == Base.HEXADECIMAL) 141 { } } else { tModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), 16), 4), ma, 3); mModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), 16), 4), ma, 3); mModel.setValueAt(Integer.toString(ma), ma, 0); mModel.setValueAt(i.getOperationCode().name(), ma, 1); mModel.setValueAt(Integer.toString(i.getInstructionOperator()), ma, 2); tModel.setValueAt(Integer.toString(ma), ma, 0); tModel.setValueAt("", ma, 1); tModel.setValueAt("", ma, 2); if(base == Base.DECIMAL) { tModel.setValueAt(Integer.toString(i.getDataSigned()), ma, 3); mModel.setValueAt(Integer.toString(i.getDataSigned()), ma, 3); } else if(base == Base.BINARY) { tModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), mModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), } else if(base == Base.HEXADECIMAL) { tModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), mModel.setValueAt(addZeros(Integer.toString(i.getDataUnsigned(), } mModel.setValueAt(Integer.toString(ma), ma, 0); mModel.setValueAt("", ma, 1); mModel.setValueAt("", ma, 2); } } else { throw new IndexOutOfBoundsException(i.toString()); } } /** * @detail Cuando muchas posiciones de memoria cambian, este método es llamado para actualizar * la tabla de memorian entera de la interfaz gráfica. */ private void updateJTableModel() { String[] columnas = {"Dirección","Instrucción", "Operador", "Dato" }; DefaultTableModel tModel = (new DefaultTableModel() { /** * */ private static final long serialVersionUID = 1L; public boolean isCellEditable(int rowIndex, int colIndex) { return false; } }); DefaultTableModel mModel = (new DefaultTableModel() { /** * */ private static final long serialVersionUID = 1L; public boolean isCellEditable(int rowIndex, int colIndex) { return false; } }); pTable.setModel(tModel); memoriaTable.setModel(mModel); tModel.setColumnIdentifiers(columnas); mModel.setColumnIdentifiers(columnas); DefaultTableCellRenderer rightRenderer = new DefaultTableCellRenderer(); rightRenderer.setHorizontalAlignment( DefaultTableCellRenderer.RIGHT ); pTable.getColumnModel().getColumn(3).setCellRenderer( rightRenderer ); pTable.getColumnModel().getColumn(0).setMaxWidth(80); pTable.getColumnModel().getColumn(1).setMaxWidth(80); pTable.getColumnModel().getColumn(2).setMaxWidth(80); memoriaTable.getColumnModel().getColumn(3).setCellRenderer( rightRenderer ); memoriaTable.getColumnModel().getColumn(0).setMaxWidth(80); memoriaTable.getColumnModel().getColumn(1).setMaxWidth(80); memoriaTable.getColumnModel().getColumn(2).setMaxWidth(80); DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); centerRenderer.setHorizontalAlignment( DefaultTableCellRenderer.CENTER ); 142 2), 16), ma, 3); 2), 16), ma, 3); 16), 4), ma, 3); 16), 4), ma, 3); pTable.getColumnModel().getColumn(2).setCellRenderer( centerRenderer ); memoriaTable.getColumnModel().getColumn(2).setCellRenderer( centerRenderer ); pTable.getColumnModel().getColumn(1).setCellRenderer( centerRenderer ); memoriaTable.getColumnModel().getColumn(1).setCellRenderer( centerRenderer ); pTable.getColumnModel().getColumn(0).setCellRenderer( centerRenderer ); memoriaTable.getColumnModel().getColumn(0).setCellRenderer( centerRenderer ); Vector<String> line; for(Instruction i: computer.getMemoryMap()) { line = new Vector<String>(); if(i.isInstruction() == true) { line.add(Integer.toString(i.getAddressLocation())); line.add(i.getOperationCode().name()); line.add(Integer.toString(i.getInstructionOperator())); if(base == Base.DECIMAL) { line.add(Integer.toString(i.getDataSigned())); } else if(base == Base.BINARY) { line.add(addZeros(Integer.toString(i.getDataUnsigned(), 2), 16) ); } else if(base == Base.HEXADECIMAL) { line.add(addZeros(Integer.toString(i.getDataUnsigned(), 16), 4) ); } } else { line.add(Integer.toString(i.getAddressLocation())); line.add(""); line.add(""); if(base == Base.DECIMAL) { line.add(Integer.toString(i.getDataSigned())); } else if(base == Base.BINARY) { line.add(addZeros(Integer.toString(i.getDataUnsigned(), 2), 16) ); } else if(base == Base.HEXADECIMAL) { line.add(addZeros(Integer.toString(i.getDataUnsigned(), 16),4) ); } } tModel.addRow(line); mModel.addRow(line); //System.out.println(i); } pTableRenderer = new ColorCellRenderer(pTable); memoriaTableRenderer = new ColorCellRenderer(memoriaTable); pTable.getColumnModel().getColumn(3).setCellRenderer(pTableRenderer); pTable.getColumnModel().getColumn(2).setCellRenderer(pTableRenderer); pTable.getColumnModel().getColumn(1).setCellRenderer(pTableRenderer); pTable.getColumnModel().getColumn(0).setCellRenderer(pTableRenderer); memoriaTable.getColumnModel().getColumn(3).setCellRenderer(memoriaTableRenderer); memoriaTable.getColumnModel().getColumn(2).setCellRenderer(memoriaTableRenderer); memoriaTable.getColumnModel().getColumn(1).setCellRenderer(memoriaTableRenderer); memoriaTable.getColumnModel().getColumn(0).setCellRenderer(memoriaTableRenderer); } /** * @brief Inicializa la memoria del computador con cierto código * @param codeArray Código a depurar */ public void setDebugCode(ArrayList<Instruction> codeArray, File file) { actionRestart(); debugFile = file; execTrace = new Trace(debugFile); computer.setMemoryMap(codeArray); updateJTableModel(); selectNextInstructionInMemoryNearP(0); } /** * Constructor de la vista depuración. */ public DebugViewManager() { super(); //Inicializar algunas variables de la clase. isCheckBoxSelected = executeSemisteps = false; execTrace = null; debugFile = null; 143 pTableRenderer = null; memoriaTableRenderer = null; startTime = -1; nextTime = -1; instructionTimer = new Timer("Timer"); changesTimer = new Timer("Changes"); instructionTask = null; //runMode = false; runTo = -1; setOrientation(JSplitPane.HORIZONTAL_SPLIT); setResizeWeight(0); setDividerLocation(630); //Queremos que la barra de separación no se pueda mover addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent pce) { // do here setDividerLocation(630); } }); //Inicializamos el computador computer = new VirtualComputer(); computer.setListener(this); //Período inicial de 500ms period = 500L; //JSplitPlane que contiene el visor de memoria entorno a P y el visor general de memoria JSplitPane memoryViewers= new JSplitPane(); memoryViewers.setOrientation(JSplitPane.VERTICAL_SPLIT); memoryViewers.setDividerLocation(300); setRightComponent(memoryViewers); JTabbedPane nearPViewer = new JTabbedPane(JTabbedPane.TOP); nearPViewer.setMinimumSize(new Dimension(417, 300)); JScrollPane scrollNearP = new JScrollPane(); nearPViewer.addTab("Memoria entorno a P", null, scrollNearP, null); JTabbedPane allMemoryViewer = new JTabbedPane(JTabbedPane.TOP); JScrollPane scrollAllMemory = new JScrollPane(); allMemoryViewer.addTab("Visor de Memoria", null, scrollAllMemory, null); memoryViewers.setLeftComponent(nearPViewer); memoryViewers.setRightComponent(allMemoryViewer); //Tabla de memoria del visor de memoria entorno a P pTable = new JTable(new DefaultTableModel() { /** * */ private static final long serialVersionUID = 1L; public boolean isCellEditable(int rowIndex, int colIndex) { return false; } }); //El usuario solo debería poder seleccionar una fila/instrucción. ListSelectionModel psm = pTable.getSelectionModel(); psm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); TableListener tl = new TableListener(); psm.addListSelectionListener(tl); scrollNearP.setViewportView(pTable); //Aquí inicializamos todos los campos de los registros textFieldA = new FlashyTextField("0", changesTimer); textFieldA.setColumns(12); textFieldA.setHorizontalAlignment(JTextField.RIGHT); textFieldA.setEditable(false); textFieldP = new FlashyTextField("0", changesTimer); textFieldP.setColumns(8); textFieldP.setHorizontalAlignment(JTextField.RIGHT); textFieldP.setEditable(false); textFieldS = new FlashyTextField("0", changesTimer); textFieldS.setColumns(8); textFieldS.setHorizontalAlignment(JTextField.RIGHT); textFieldS.setEditable(false); textFieldI = new FlashyTextField("0", changesTimer); textFieldI.setColumns(8); textFieldI.setHorizontalAlignment(JTextField.RIGHT); textFieldI.setEditable(false); textFieldT = new FlashyTextField("0", changesTimer); textFieldT.setColumns(12); 144 textFieldT.setHorizontalAlignment(JTextField.RIGHT); textFieldT.setEditable(false); textFieldE = new FlashyTextField("0", changesTimer); textFieldE.setColumns(12); textFieldE.setHorizontalAlignment(JTextField.RIGHT); textFieldE.setEditable(false); textFieldCO = new FlashyTextField("0000", changesTimer); textFieldCO.setColumns(3); textFieldCO.setHorizontalAlignment(JTextField.RIGHT); textFieldCO.setEditable(false); textFieldMD = new FlashyTextField("0", changesTimer); textFieldMD.setColumns(1); textFieldMD.setHorizontalAlignment(JTextField.RIGHT); textFieldMD.setEditable(false); //tabbedMonitor es la pantalla de la consola JTabbedPane tabbedMonitor = new JTabbedPane(JTabbedPane.TOP); JScrollPane scrollMonitor = new JScrollPane(); tabbedMonitor.addTab("Monitor", null, scrollMonitor, null); consolaPane = new JTextPane(); consolaPane.setEditable(false); //Con esto el enter será sólo un carácter raro sin efecto consolaPane.setFocusTraversalKeysEnabled(false); consolaListener = new ConsoleKeyListener(); consolaPane.addKeyListener(consolaListener); scrollMonitor.setViewportView(consolaPane); //A continuación cargamos todos los iconos que necesitamos java.net.URL imageURL = Emulator.class.getResource("images/bus.png"); ImageIcon icon = new ImageIcon(imageURL); JLabel busLabel = new JLabel(); busLabel.setIcon(icon); imageURL = Emulator.class.getResource("images/ALU.png"); icon = new ImageIcon(imageURL); JLabel aluLabel = new JLabel(); aluLabel.setIcon(icon); imageURL = Emulator.class.getResource("images/sBus.png"); icon = new ImageIcon(imageURL); JLabel sBusLabel = new JLabel(); sBusLabel.setIcon(icon); imageURL = Emulator.class.getResource("images/keyboard-icon2.png"); icon = new ImageIcon(imageURL); JLabel keyboardButton = new JLabel(); keyboardButton.setIcon(icon); //Los siguientes iconos no serán visibles, son un hack para poder pintar correctamente las flechas //que conectan los registros imageURL = Emulator.class.getResource("images/point.png"); icon = new ImageIcon(imageURL); JLabel point = new JLabel(); point.setIcon(icon); JLabel point2 = new JLabel(); point2.setIcon(icon); point2.setVisible(false); JLabel point3 = new JLabel(); point3.setIcon(icon); point3.setVisible(false); JLabel point4 = new JLabel(); point4.setIcon(icon); point4.setVisible(false); JLabel point5 = new JLabel(); point5.setIcon(icon); point5.setVisible(false); //Estos puntos son las válvulas de control de flujo que manejan las señales del computador imageURL = Emulator.class.getResource("images/punto.png"); icon = new ImageIcon(imageURL); JLabel punto1 = new JLabel(); punto1.setIcon(icon); JLabel punto2 = new JLabel(); punto2.setIcon(icon); JLabel punto3 = new JLabel(); punto3.setIcon(icon); JLabel punto4 = new JLabel(); punto4.setIcon(icon); JLabel punto5 = new JLabel(); punto5.setIcon(icon); JLabel punto6 = new JLabel(); punto6.setIcon(icon); JLabel punto7 = new JLabel(); punto7.setIcon(icon); JLabel punto8 = new JLabel(); 145 punto8.setIcon(icon); JLabel punto9 = new JLabel(); punto9.setIcon(icon); JLabel punto10 = new JLabel(); punto10.setIcon(icon); JLabel punto11 = new JLabel(); punto11.setIcon(icon); JLabel punto12 = new JLabel(); punto12.setIcon(icon); JLabel punto13 = new JLabel(); punto13.setIcon(icon); JLabel punto14 = new JLabel(); punto14.setIcon(icon); //JButton keyboardButton = new JButton("Abrir Teclado Virtual"); //Etiquetas de los registros JLabel eLabel = new JLabel("E"); JLabel tLabel = new JLabel("T"); JLabel aLabel = new JLabel("A"); JLabel pLabel = new JLabel("P"); JLabel sLabel = new JLabel("S"); JLabel iLabel = new JLabel("I"); JLabel mLabel = new JLabel("M"); JLabel ssLabel = new JLabel("S"); coLabel = new JLabel("CO"); mdLabel = new JLabel("MD"); dLabel = new JLabel("D"); //Etiquetas de las señales etLabel = new FlashySignal("ET", changesTimer); stLabel = new FlashySignal("ST", changesTimer); eeLabel = new FlashySignal("EE", changesTimer); seLabel = new FlashySignal("SE", changesTimer); escpLabel = new FlashySignal("ESCP", changesTimer); leetLabel = new FlashySignal("LEET", changesTimer); eaLabel = new FlashySignal("EA", changesTimer); saLabel = new FlashySignal("SA", changesTimer); eoLabel = new FlashySignal("EO", changesTimer); sumaLabel = new FlashySignal("SUMA", changesTimer); resaLabel = new FlashySignal("RESA", changesTimer); multaLabel = new FlashySignal("MULTA", changesTimer); incpLabel = new FlashySignal("INCP", changesTimer); spLabel = new FlashySignal("SP", changesTimer); epLabel = new FlashySignal("EP", changesTimer); sdLabel = new FlashySignal("SD", changesTimer); eiLabel = new FlashySignal("EI", changesTimer); esLabel = new FlashySignal("ES", changesTimer); lecmLabel = new FlashySignal("LECM", changesTimer); escmLabel = new FlashySignal("ESCM", changesTimer); divaLabel = new FlashySignal("DIVA", changesTimer); modaLabel = new FlashySignal("MODA", changesTimer); //computerGraphics es el panel donde se dibujará el esquema del computador //Es de tipo ConnectorContainer para poder pintar flechas fácilmente en él ConnectorContainer computerGraphics = new ConnectorContainer(); computerGraphics.setMinimumSize(new Dimension(630, 400)); computerGraphics.setMaximumSize(new Dimension(630, Short.MAX_VALUE)); setLeftComponent(computerGraphics); //Layout del computador GroupLayout gl_menu2 = new GroupLayout(computerGraphics); gl_menu2.setHorizontalGroup( gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addComponent(aLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(textFieldA, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(72, 72) .addComponent(punto7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(eaLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(40, 40) .addComponent(aluLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addGroup(gl_menu2.createParallelGroup(A lignment.LEADING) .addComponent(sumaLa bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(resaLa 146 bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(multaL abel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(divaLa bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, .addComponent(modaLa ) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(54, 54) .addComponent(point, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(26, 26) .addComponent(punto8, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(saLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(23, 23) .addComponent(punto9, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(eoLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(30, 30) .addComponent(mLabel, GroupLayout.PREFERRED_SIZE) ) ) .addContainerGap(90, 90) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addComponent(pLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(textFieldP, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(incpLabel, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addComponent(epLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(punto10, GroupLayout.PREFERRED_SIZE) .addContainerGap(25, 25) .addComponent(punto11, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(spLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(ssLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(42, 42) .addComponent(esLabel, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addComponent(sBusLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(punto12, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(textFieldS, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(sLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(24, 24) .addComponent(point4, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(70, 70) .addComponent(sdLabel, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(punto13, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addComponent(coLabel, GroupLayout.PREFERRED_SIZE) 147 GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(15, 15) .addComponent(mdLabel, .addContainerGap(15, 15) .addComponent(dLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addComponent(textFieldCO, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(1, 1) .addComponent(textFieldMD, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(1, 1) .addComponent(textFieldI, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(15, 15) .addComponent(iLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(280, 280) .addComponent(lecmLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(point2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(280, 280) .addComponent(escmLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(point3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(80, 80) .addComponent(eiLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(punto14, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) ) ) .addComponent(busLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addGroup(gl_menu2.createParallelGroup(A lignment.LEADING) .addGroup(gl_menu2.createSeque ntialGroup() .addContai nerGap(20, 20) .addCompon ent(eeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContai nerGap(20, 20) .addCompon ent(punto3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContai nerGap(40, 40) .addCompon ent(seLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContai nerGap(20, 20) .addCompon ent(punto4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createSeque ntialGroup() .addCompon ent(eLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContai nerGap(10, 10) .addCompon ent(textFieldE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) ) .addContainerGap(280, 280) .addGroup(gl_menu2.createParallelGroup(A lignment.LEADING) .addGroup( gl_menu2.createSequentialGroup() .addComponent(etLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) 148 .addComponent(punto1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(40, 40) .addComponent(stLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(20, 20) .addComponent(punto2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup( gl_menu2.createSequentialGroup() .addComponent(tLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(textFieldT, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap(10, 10) .addComponent(point5, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) ) ) .addGroup(gl_menu2.createSequentialGroup() .addGroup(gl_menu2.createSequentialGroup() .addCompon ent(leetLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addCompon ent(punto6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(5, 5) .addGroup(gl_menu2.createParallelGroup(Alignment. LEADING) .addGroup(gl_menu2.createSeque ntialGroup() .addCompon ent(escpLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContai nerGap(20, 20) .addCompon ent(punto5, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addComponent(tabbedMonitor, 0, 400, 400) ) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(20, 20) .addComponent(keyboardButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) ) ) ); gl_menu2.setVerticalGroup( gl_menu2.createSequentialGroup() .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(7, 7) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addComponent(aLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(textFieldA, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(punto7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(eaLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addComponent(aluLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(gl_menu2.createSequentialGroup () .addComponent(sumaLa bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(resaLa bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(multaL abel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(divaLa bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(modaLa 149 bel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, ) ) .addContainerGap(20, 20) .addComponent(point, GroupLayout.PREFERRED_SIZE, .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(punto8, GroupLayout.PREFERRED_SIZE) .addComponent(saLabel, GroupLayout.PREFERRED_SIZE) .addComponent(punto9, GroupLayout.PREFERRED_SIZE) .addComponent(eoLabel, GroupLayout.PREFERRED_SIZE) .addComponent(mLabel, GroupLayout.PREFERRED_SIZE) ) ) .addGroup(gl_menu2.createSequentialGroup() .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(pLabel, GroupLayout.PREFERRED_SIZE) .addComponent(textFieldP, GroupLayout.PREFERRED_SIZE) .addComponent(incpLabel, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(epLabel, GroupLayout.PREFERRED_SIZE) .addComponent(punto10, GroupLayout.PREFERRED_SIZE) .addComponent(punto11, GroupLayout.PREFERRED_SIZE) .addComponent(spLabel, GroupLayout.PREFERRED_SIZE) .addGroup(gl_menu2.createSequentialGroup () .addContainerGap(15, 15) l, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, .addComponent(ssLabe ) .addComponent(esLabel, ) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(sBusLabel, GroupLayout.PREFERRED_SIZE) .addComponent(punto12, GroupLayout.PREFERRED_SIZE) .addComponent(textFieldS, GroupLayout.PREFERRED_SIZE) .addComponent(sLabel, GroupLayout.PREFERRED_SIZE) .addComponent(point4, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(5, 5) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(sdLabel, GroupLayout.PREFERRED_SIZE) .addComponent(punto13, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(1, 1) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addComponent(coLabel, GroupLayout.PREFERRED_SIZE) .addComponent(mdLabel, GroupLayout.PREFERRED_SIZE) .addComponent(dLabel, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addComponent(textFieldCO, GroupLayout.PREFERRED_SIZE) .addComponent(textFieldMD, GroupLayout.PREFERRED_SIZE) .addComponent(textFieldI, GroupLayout.PREFERRED_SIZE) .addComponent(iLabel, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(lecmLabel, GroupLayout.PREFERRED_SIZE) 150 GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) lignment.CENTER) .addComponent(point2, .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(escmLabel, GroupLayout.PREFERRED_SIZE) .addComponent(point3, GroupLayout.PREFERRED_SIZE) ) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(eiLabel, GroupLayout.PREFERRED_SIZE) .addComponent(punto14, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(2, 2) ) ) .addComponent(busLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addGroup(gl_menu2.createSequentialGroup() .addGroup(gl_menu2.createParallelGroup(A .addComponent(eeLabe l, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(punto3 , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(seLabe l, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) lignment.LEADING) .addComponent(punto4 ) .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(A .addComponent(eLabel , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) eldE, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(textFi ) ) .addGroup(gl_menu2.createSequentialGroup() .addGroup(gl_menu2.createParallelGroup(A lignment.CENTER) .addComponent(etLabe l, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(punto1 , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(stLabe l, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) lignment.CENTER) .addComponent(punto2 ) .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(A .addComponent(tLabel , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(textFi eldT, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(point5 , GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) ) ) ) .addGroup(gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(leetLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(punto6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) ) .addGroup(gl_menu2.createSequentialGroup() .addContainerGap(10, 10) .addGroup(gl_menu2.createParallelGroup(Alignment.CENTER) .addComponent(escpLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(punto5, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ) .addContainerGap(10, 10) .addComponent(tabbedMonitor, 0, 300, 300) 151 GroupLayout.PREFERRED_SIZE) ) ) .addContainerGap(10, 10) .addComponent(keyboardButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, ); computerGraphics.setLayout(gl_menu2); //Lista de flechas del esquema del computador ArrayList<JConnector> con = new ArrayList<JConnector>(); con.add( new JConnector(etLabel ,punto1, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto1 ,textFieldT, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto1 ,busLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(stLabel ,punto2, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto2 ,textFieldT, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(punto2 ,busLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(sLabel ,point4, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); /////// con.add( new JConnector(eeLabel ,punto3, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto3 ,textFieldE, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto3 ,busLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(seLabel ,punto4, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto4 ,textFieldE, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(punto4 ,busLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); ////////// con.add( new JConnector(escpLabel ,punto5, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto5 ,textFieldE, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto5 ,tabbedMonitor, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); //////// con.add( new JConnector(punto6 ,textFieldE, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto6 ,keyboardButton, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); ///////// con.add( new JConnector(eaLabel ,punto7, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto7 ,aluLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto7 ,textFieldA, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(resaLabel ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); /////// con.add( new JConnector(saLabel ,punto8, ConnectLine.LINE_ARROW_DEST, 152 ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto8 ,textFieldA, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto8 ,busLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add( new JConnector(point ,punto8, ConnectLine.LINE_ARROW_NONE, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(point ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); //////// con.add( new JConnector(eoLabel ,punto9, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto9 ,busLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto9 ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); //////// con.add( new JConnector(sumaLabel ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(multaLabel ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(divaLabel ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(modaLabel ,aluLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); ///// con.add( new JConnector(incpLabel ,textFieldP, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); //// con.add( new JConnector(epLabel ,punto10, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto10 ,textFieldP, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto10 ,sBusLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); /////// con.add( new JConnector(spLabel ,punto11, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto11 ,textFieldP, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto11 ,sBusLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); ////// con.add( new JConnector(esLabel ,punto12, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto12 ,sBusLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto12 ,textFieldS, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); ////// con.add( new JConnector(sdLabel ,punto13, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto13 ,textFieldI, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto13 ,sBusLabel, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); ////// 153 con.add( new JConnector(eiLabel ,punto14, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(punto14 ,busLabel, ConnectLine.LINE_ARROW_SOURCE, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); con.add(new JConnector(punto14 ,textFieldI, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_VERTICAL, Color.BLACK)); ////// con.add( new JConnector(lecmLabel ,point2, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(escmLabel ,point3, ConnectLine.LINE_ARROW_DEST, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); con.add( new JConnector(textFieldT ,point5, ConnectLine.LINE_ARROW_BOTH, ConnectLine.LINE_TYPE_RECT_HORIZONTAL, Color.BLACK)); ////// //Añadimos las flechas al panel que contiene el esquema del computador computerGraphics.addConnectors(con); Action actionLimpiarConsola = new AbstractAction("Limpiar", null) { private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { consolaPane.setText(""); } }; //menú que sirve para limpiar la consola JPopupMenu popup = new JPopupMenu(); popup.add(actionLimpiarConsola); MouseListener popupListener = new PopupListener(popup); consolaPane.addMouseListener(popupListener); memoriaTable = new JTable(); memoriaTable.setModel(new DefaultTableModel() { /** * */ private static final long serialVersionUID = 1L; public boolean isCellEditable(int rowIndex, int colIndex) { return false; } }); //Los usuarios solo deberían ser capaces de seleccionar una fila/instrucción ListSelectionModel msm = memoriaTable.getSelectionModel(); msm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); scrollAllMemory.setViewportView(memoriaTable); //Actualiza los registros y señales del computador en la interfaz gráfica setRegistersBase(Base.DECIMAL); //El buffer inicial no contiene datos inputBuffer = null; } @Override public void writeNumberToScreen() { addConsoleOutput("" + computer.getState().getE()); } @Override public void stateChanged() { //Recolectamos el estado del computador ComputerState c = computer.getState(); Color myColor = null; if(c.getSemiState() == VirtualComputer.First_Semistep) { myColor = new Color(0, 184, 245); } else { myColor = new Color(245, 0, 0); } ///////////////////////////////////// //Actualizamos el estado de todas las señales if(c.getSignal(ComputerSignal.ET) == true) { etLabel.flash(myColor); } else { 154 etLabel.restart(); } if(c.getSignal(ComputerSignal.ST) == true) { stLabel.flash(myColor); } else { stLabel.restart(); } if(c.getSignal(ComputerSignal.EE) == true) { eeLabel.flash(myColor); } else { eeLabel.restart(); } if(c.getSignal(ComputerSignal.SE) == true) { seLabel.flash(myColor); } else { seLabel.restart(); } if(c.getSignal(ComputerSignal.ESCP) == true) { escpLabel.flash(myColor); } else { escpLabel.restart(); } if(c.getSignal(ComputerSignal.LEET) == true) { leetLabel.flash(myColor); } else { leetLabel.restart(); } if(c.getSignal(ComputerSignal.EA) == true) { eaLabel.flash(myColor); } else { eaLabel.restart(); } if(c.getSignal(ComputerSignal.SA) == true) { saLabel.flash(myColor); } else { saLabel.restart(); } if(c.getSignal(ComputerSignal.EO) == true) { eoLabel.flash(myColor); } else { eoLabel.restart(); } if(c.getSignal(ComputerSignal.SUMA) == true) { sumaLabel.flash(myColor); } else { sumaLabel.restart(); } if(c.getSignal(ComputerSignal.RESA) == true) { resaLabel.flash(myColor); } else { resaLabel.restart(); } if(c.getSignal(ComputerSignal.MULTA) == true) { multaLabel.flash(myColor); } else { multaLabel.restart(); } if(c.getSignal(ComputerSignal.DIVA) == true) { 155 divaLabel.flash(myColor); } else { divaLabel.restart(); } if(c.getSignal(ComputerSignal.MODA) == true) { modaLabel.flash(myColor); } else { modaLabel.restart(); } if(c.getSignal(ComputerSignal.INCP) == true) { incpLabel.flash(myColor); } else { incpLabel.restart(); } if(c.getSignal(ComputerSignal.EP) == true) { epLabel.flash(myColor); } else { epLabel.restart(); } if(c.getSignal(ComputerSignal.SP) == true) { spLabel.flash(myColor); } else { spLabel.restart(); } if(c.getSignal(ComputerSignal.ES) == true) { esLabel.flash(myColor); } else { esLabel.restart(); } if(c.getSignal(ComputerSignal.SD) == true) { sdLabel.flash(myColor); } else { sdLabel.restart(); } if(c.getSignal(ComputerSignal.EI) == true) { eiLabel.flash(myColor); } else { eiLabel.restart(); } if(c.getSignal(ComputerSignal.ESCM) == true) { escmLabel.flash(myColor); } else { escmLabel.restart(); } if(c.getSignal(ComputerSignal.LECM) == true) { lecmLabel.flash(myColor); } else { lecmLabel.restart(); } if(c.hasRegisterChanged(ComputerRegister.A) == true) { textFieldA.flash(myColor); } else { textFieldA.restart(); } if(c.hasRegisterChanged(ComputerRegister.E) == true) { textFieldE.flash(myColor); } else { textFieldE.restart(); } 156 if(c.hasRegisterChanged(ComputerRegister.T) == true) { textFieldT.flash(myColor); } else { textFieldT.restart(); } if(c.hasRegisterChanged(ComputerRegister.I) == true) { textFieldI.flash(myColor); if(base == Base.BINARY) { textFieldCO.flash(myColor); textFieldMD.flash(myColor); } else { textFieldCO.restart(); textFieldMD.restart(); } } else { textFieldI.restart(); textFieldCO.restart(); textFieldMD.restart(); } if(c.hasRegisterChanged(ComputerRegister.S) == true) { textFieldS.flash(myColor); } else { textFieldS.restart(); } if(c.hasRegisterChanged(ComputerRegister.P) == true) { textFieldP.flash(myColor); } else { textFieldP.restart(); } if(c.hasChangedMemory() == true) { pTableRenderer.flash(c.getChangedMemory()); memoriaTableRenderer.flash(c.getChangedMemory()); } else { pTableRenderer.restart(); memoriaTableRenderer.restart(); } //las señales han sido leidas //c.resetSignalsRegisters(); ///////////////////////////////////// //Actualizamos la posición de memoria seleccionada en el visor de memoria entorno a P selectNextInstructionInMemoryNearP(c.getP()); //Actualizamos los registros, dependiendo de la base usada try{ if(base == Base.BINARY) { Instruction i = new Instruction(); i.setInstructionSigned(c.getA()); textFieldA.setText(addZeros(Integer.toString(i.getDataUnsigned(), 2), i.setInstructionSigned(c.getP()); textFieldP.setText(addZeros(Integer.toString(i.getDataUnsigned(), 2), i.setInstructionSigned(c.getS()); textFieldS.setText(addZeros(Integer.toString(i.getDataUnsigned(), 2), i.setInstructionSigned(c.getI()); String s = addZeros(Integer.toString(i.getDataUnsigned(), 2), 16); String co = s.substring(0, 4); String md = s.substring(4, 5); String d = s.substring(5); textFieldCO.setText(co); textFieldMD.setText(md); textFieldI.setText(d); i.setInstructionSigned(c.getT()); textFieldT.setText(addZeros(Integer.toString(i.getDataUnsigned(), 2), i.setInstructionSigned(c.getE()); textFieldE.setText(addZeros(Integer.toString(i.getDataUnsigned(), 2), } else if(base == Base.DECIMAL) { textFieldA.setText(Integer.toString(c.getA(), 10)); textFieldP.setText(Integer.toString(c.getP(), 10)); textFieldS.setText(Integer.toString(c.getS(), 10)); textFieldI.setText(Integer.toString(c.getI(), 10)); textFieldT.setText(Integer.toString(c.getT(), 10)); textFieldE.setText(Integer.toString(c.getE(), 10)); textFieldCO.setText(""); textFieldMD.setText(""); } else if(base == Base.HEXADECIMAL) 157 16)); 11)); 11)); 16)); 16)); { Instruction i = new Instruction(); i.setInstructionSigned(c.getA()); textFieldA.setText(addZeros(Integer.toString(i.getDataUnsigned(), i.setInstructionSigned(c.getP()); textFieldP.setText(addZeros(Integer.toString(i.getDataUnsigned(), i.setInstructionSigned(c.getS()); textFieldS.setText(addZeros(Integer.toString(i.getDataUnsigned(), i.setInstructionSigned(c.getI()); textFieldI.setText(addZeros(Integer.toString(i.getDataUnsigned(), i.setInstructionSigned(c.getT()); textFieldT.setText(addZeros(Integer.toString(i.getDataUnsigned(), i.setInstructionSigned(c.getE()); textFieldE.setText(addZeros(Integer.toString(i.getDataUnsigned(), textFieldCO.setText(""); textFieldMD.setText(""); } } catch (Exception excep) { } } /** * Añade ceros a la cadena 's' hasta que dicha cadena tenga una longitud 'a' * @param s * @param a * @return */ String addZeros(String s, int a) { String r = ""; int b = a - s.length(); if (b > 0) { for(int j = 0; j < b; j++) { r = r + "0"; } } r = r + s; return r; } @Override public void memoryChanged(Instruction i) { try { changeMemoryAddress(i); } catch(Exception e) { // TODO Auto-generated method stub } } @Override public void writeCharacterToScreen() { // TODO Auto-generated method stub char c = (char)computer.getState().getE(); addConsoleOutput(Character.toString(c)); } @Override public void itemStateChanged(ItemEvent itemEvent) { int state = itemEvent.getStateChange(); if (state == ItemEvent.SELECTED) { isCheckBoxSelected = true; System.out.println("SELECTED"); } else if (state == ItemEvent.DESELECTED) { isCheckBoxSelected = false; System.out.println("DESELECTED"); } } } 158 16), 4)); 16), 4)); 16), 4)); 16), 4)); 16), 4)); 16), 4)); 11.1.11 ProjectFile.java package xenon; import java.io.File; import javax.swing.tree.DefaultMutableTreeNode; /** * * @brief Define un fichero que pertenece a un proyecto. * */ public class ProjectFile { public DefaultMutableTreeNode fnode; //Nodo perteneciente al fichero en el árbol de ficheros public enum FileType {BINARY, TEXT, CODE}; //Tipos de fichero; Código binario, código ensamblador o texto. public FileType type; //Tipo de fichero public File file; //Ruta del fichero en el sistema de archivos public Project project; //Proyecto al que pertenece el fichero /** * @brief Devuelve el nombre del fichero en una cadena. */ public String toString() { String s = ""; if(file != null) { s = file.getName(); } return s; } /** * @brief Constructor. * Las extensiones reconocidas para los ficheros de un proyecto * son ls2 (código) y ece (binario). El resto de archivos es tratado * como texto. */ public ProjectFile(File f, Project p) { file = f; String arg1 = f.getName().toLowerCase(); if(arg1.lastIndexOf('.')>0) { // Obtener el último índice del carácter '.' int lastIndex = arg1.lastIndexOf('.'); // Obtener extensión String str = arg1.substring(lastIndex); // Comprobar la extensión del fichero if(str.equals(".ls2")) { type = FileType.CODE; } else if(str.equals(".ece")) { type = FileType.BINARY; } else { type = FileType.TEXT; } } project = p; } /** * @brief Asigna 'no' como nodo de este fichero en el árbol de proyectos. * @param no */ public void setNode(DefaultMutableTreeNode no) { fnode = no; } } 159 11.1.12 TabsManager.java package xenon; import import import import import java.io.BufferedWriter; java.io.File; java.io.FileWriter; java.io.IOException; java.util.ArrayList; import import import import javax.swing.JFileChooser; javax.swing.JOptionPane; javax.swing.JTabbedPane; javax.swing.JTextArea; /** * @brief Clase gestora de las pestañas. * */ public class TabsManager{ private JTabbedPane tabbedFilePane; //Panel que contiene las pestañas /** * @brief Devuelve el panel de pestañas * @return */ public JTabbedPane getTabbedPane() { return tabbedFilePane; } /** * @brief Constructor * @param tab */ public TabsManager(JTabbedPane tab) { tabbedFilePane = tab; } /** * @brief Busca una pestaña que contenga el fichero pfile * @param pfile * @return null si ninguna pestaña contiene pfile, en caso contrario devuelve dicha pestaña */ public Tab searchTab(ProjectFile pfile) { //TODO: Tab tt = null; boolean bFlag = true; for(int i = 0, n = tabbedFilePane.getTabCount(); i < n && bFlag; i++) { Tab t = (Tab)tabbedFilePane.getComponentAt(i); if(t.pFile == pfile) { bFlag = false; tt = t; break; } } return tt; } /** * Elimina la pestaña sin preguntar si quieres guardar el fichero. * @param t */ public void dontAskAndRemoveTab(Tab t) { tabbedFilePane.remove(t); } /** * @brief Si el fichero ha sido modificado, pregunta si quieres guardarlo. Entonces lo cierra. * @param t */ public void askAndRemoveTab(Tab t) { int i = tabbedFilePane.indexOfComponent(t); if (i != -1) { if(t.isModified()) { Object[] options = {"Si", "No", "Cancelar"}; int n = JOptionPane.showOptionDialog(null, "'" + t.pFile.file.getName() + "'" + " ha sido modificado. ¿Desea guardar los cambios realizados?", "Guardar Fichero", JOptionPane.YES_NO_CANCEL_OPTION, 160 JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if(n == JOptionPane.YES_OPTION) { saveTabTo(t, t.pFile.file.getPath()); tabbedFilePane.remove(t); } else if(n == JOptionPane.NO_OPTION) { tabbedFilePane.remove(t); } else if(n == JOptionPane.CANCEL_OPTION) { //Do nothing! } } else { tabbedFilePane.remove(t); } } } /** * @brief Elimina una pestaña a partir de su etiqueta ButtonTabComponent, * que contiene el nombre del archivo y el botón en forma de X que sirve para cerrarla. * @param ct */ public void removeTab(ButtonTabComponent ct) { int i = tabbedFilePane.indexOfTabComponent(ct); Tab t = (Tab)tabbedFilePane.getComponentAt(i); askAndRemoveTab(t); } /** * @brief Este método añadirá una pestaña al panel de pestañas si no existe una pestaña con el fichero * pfile. En otro caso seleccionará y mostrará dicha pestaña. */ public void addTab(ProjectFile pfile) { //Comprobamos si existe una pestaña con ese fichero boolean bFlag = true; for(int i = 0, n = tabbedFilePane.getTabCount(); i < n && bFlag; i++) { Tab t = (Tab)tabbedFilePane.getComponentAt(i); if(t.pFile == pfile) //La pestaña existe, la seleccionamos y mostramos { bFlag = false; tabbedFilePane.setSelectedIndex(i); } } if(bFlag == true) { //No existe, luego añadimos la pestaña JTextArea textArea = new JTextArea(); Tab t = new Tab(textArea, pfile); tabbedFilePane.addTab(null, t); tabbedFilePane.setSelectedComponent(t); int index = tabbedFilePane.indexOfComponent(t); ButtonTabComponent btc = new ButtonTabComponent(this,pfile.file.getName()); t.setLabel(btc.getLabel()); tabbedFilePane.setTabComponentAt(index,btc); } } /** * @brief Guarda el fichero de una pestaña t en la ruta path. * @param t * @param path */ private void saveTabTo(Tab t, String path) { File fileName = new File(path); if (fileName != null) { if(t.pFile.type == ProjectFile.FileType.CODE || t.pFile.type == ProjectFile.FileType.TEXT) { System.out.println("Guardando " + path + " ..."); try { BufferedWriter outFile = new BufferedWriter(new FileWriter(fileName)); outFile.write(t.textArea.getText()); //put in textfile outFile.close(); } catch (IOException ex) { } } else if(t.pFile.type == ProjectFile.FileType.BINARY) 161 { } } } /** * @brief Guarda el fichero de la pestaña actualmente seleccionado. */ public void saveCurrentlySelectedTab() { if(tabbedFilePane.getTabCount() > 0) { Tab t = (Tab)tabbedFilePane.getComponentAt(tabbedFilePane.getSelectedIndex()); saveTabTo(t, t.pFile.file.getPath()); t.setModified(false); } } /** * @brief Devuelve la pestaña actualmente seleccionada, o null si no existe ninguna pestaña. * @return */ public Tab getCurrentlySelectedTab() { int i = tabbedFilePane.getSelectedIndex(); return (i >= 0)? (Tab)tabbedFilePane.getComponentAt(i): null; } /** * @brief Crea un diálogo que pregunta dónde se quiere guardar el texto de la actual pestaña, y lo guarda. */ public void saveCurrentlySelectedTabAs() { if(tabbedFilePane.getTabCount() > 0) { Tab t = (Tab)tabbedFilePane.getComponentAt(tabbedFilePane.getSelectedIndex()); JFileChooser SaveAs = new JFileChooser(); int actionDialog = SaveAs.showDialog(null, "Guardar Como..."); if(actionDialog == JFileChooser.APPROVE_OPTION) { saveTabTo(t, SaveAs.getSelectedFile().getPath()); } } } /** * @brief Guarda los cambios realizados en los ficheros de todas las pestañas. */ public void saveAllTabs() { for(int i = 0, n = tabbedFilePane.getTabCount(); i < n; i++) { Tab t = (Tab)tabbedFilePane.getComponentAt(i); saveTabTo(t, t.pFile.file.getPath()); t.setModified(false); } } /** * @brief Comprueba si el fichero ha sido modificado y pregunta al usuario si quiere guardar los cambios. */ public void saveIfModified(ProjectFile codeToDebug) { boolean bFlag = true; for(int i = 0, n = tabbedFilePane.getTabCount(); i < n && bFlag; i++) { Tab t = (Tab)tabbedFilePane.getComponentAt(i); if(t.pFile == codeToDebug && t.isModified()) { bFlag = false; Object[] options = {"Si", "No"}; int ss = JOptionPane.showOptionDialog(null, "El fichero " +codeToDebug.file.getName() + " ha sido modificado. ¿Desea guardar los cambios realizados?", "Guardar fichero", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if(ss == JOptionPane.YES_OPTION) { saveTabTo(t, t.pFile.file.getPath()); t.setModified(false); } } } 162 } /** * Cierra todas las pestañas del proyecto p. * @param p * @return */ public boolean closeAllTabsOfProject(Project p) { if (p == null){ return false; } boolean result = true; ArrayList<Tab> list = new ArrayList<Tab>(); boolean modified = false; for(int i = 0, n = tabbedFilePane.getTabCount(); i < n ; i++) { Tab t = (Tab)tabbedFilePane.getComponentAt(i); //System.out.println(t); if(t.pFile.project == p) { list.add(t); if(t.isModified()) { modified = true; } } } if(modified) { Object[] options = {"Si", "No", "Cancelar"}; int n = JOptionPane.showOptionDialog(null, "Algunos ficheros han sido modificados. ¿Desea guardar los cambios realizados?", "Guardar Ficheros", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if(n == JOptionPane.YES_OPTION) { for(Tab t: list) { if (t.isModified()) { saveTabTo(t, t.pFile.file.getPath()); } tabbedFilePane.remove(t); } } else if(n == JOptionPane.NO_OPTION) { for(Tab t: list) { tabbedFilePane.remove(t); } } else if(n == JOptionPane.CANCEL_OPTION) { result = false; } } else { for(Tab t: list) { tabbedFilePane.remove(t); } } return result; } /** * @brief Cierra la pestaña actualmente seleccionada. */ public void closeCurrentlySelectedTab() { if(tabbedFilePane.getTabCount() > 0) { Tab t = (Tab)tabbedFilePane.getComponentAt(tabbedFilePane.getSelectedIndex()); askAndRemoveTab(t); } } /** * @brief Cierra todas las pestañas, preguntando si guardar cambios en aquellos ficheros que se han modificado. */ 163 public void closeAllTabs() { ArrayList<Tab> list = new ArrayList<Tab>(); boolean modified = false; for(int i = 0, m = tabbedFilePane.getTabCount(); i < m ; i++) { Tab t = (Tab)tabbedFilePane.getComponentAt(i); list.add(t); //System.out.println(t); if(t.isModified()) { modified = true; } } if(modified) { Object[] options = {"Si", "No", "Cancelar"}; int dialogResult = JOptionPane.showOptionDialog(null, "Algunos ficheros han sido modificados. ¿Desea guardar los cambios realizados?", "Guardar Ficheros", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if(dialogResult == JOptionPane.YES_OPTION) { for(Tab t: list) { if (t.isModified()) { saveTabTo(t, t.pFile.file.getPath()); } tabbedFilePane.remove(t); } } else if(dialogResult == JOptionPane.NO_OPTION) { for(Tab t: list) { tabbedFilePane.remove(t); } } else if(dialogResult == JOptionPane.CANCEL_OPTION) { //Do nothing! } } else { for(Tab t: list) { tabbedFilePane.remove(t); } } } } 164 11.1.13 Project.java package xenon; import java.io.File; import java.util.ArrayList; import javax.swing.tree.DefaultMutableTreeNode; /** * * @brief Define un proyecto y sus propiedades básicas * */ public class Project { public File file; //Localización del proyecto public ArrayList <ProjectFile> projectFiles; //Ficheros pertenecientes al proyecto DefaultMutableTreeNode pnode; //Nodo del proyecto en el árbol de proyectos public Project() { file = null; projectFiles = new ArrayList <ProjectFile>(); } public String toString() { String s = ""; if(file != null) { s = file.getName(); } return s; } }; 165 11.1.14 VirtualComputer.java package xenon; import java.util.ArrayList; import java.util.EnumMap; /** * @brief Clase que abstrae el comportamiento del computador. * */ public class VirtualComputer { public final static int First_Semistep = 0; public final static int Last_Semistep = 1; private Instruction[] memoryMap; //Mapa de memoria del computador private private private private Instruction[] InitialMemoryMap; //Mapa de memoria inicial del computador ComputerState state; //Estado del computador boolean trafficLight; //Semáforo que asegura una ejecución ordenada. int semiStep; /** * @brief Listener del computador * */ interface VirtualComputerListener { /** * Este método será llamado cuandoquiera que el computador quiera escribir números en pantalla. */ public void writeNumberToScreen(); /** * Este método será llamado cuandoquiera que el estado del computador cambie. */ public void stateChanged(); /** * Este método será llamado cuando el contenido de la dirección de memoria i cambie. */ public void memoryChanged(Instruction i); /** * Este método será llamado cuandoquiera que el computador quiera escribir un carácter en pantalla. */ public void writeCharacterToScreen(); } /** * @brief Enumeración de las señales del computador. */ public enum ComputerSignal{ ET, ST, EE, SE, ESCP, LEET, EA, SA, EO, SUMA, RESA, MULTA, DIVA, MODA, INCP, EP, SP, ES, SD, EI, LECM, ESCM; } /** * @brief Enumeración de los registros del computador. * */ public enum ComputerRegister{ A, S, T, P, I, E; } /** * @brief Clase que define el estado del computador, a nivel de registros y señales del mismo. * */ class ComputerState { //A, I, T, E: signed 16 bit, [-32768, 32767] //P, S: unsigned 11 bit, [0, 2047] VirtualComputerListener listener; private EnumMap<ComputerSignal, Boolean> signals; //Mapa de las señales private EnumMap<ComputerRegister, Boolean> changedRegisters; //Mapa de los registros private boolean changedMemory; private int dirOfChanchedMemory; private int semiStep; private int A, S, T, P, I, E; /** * @brief Constructor que inicializa los parámetros del objeto. */ ComputerState() { semiStep = First_Semistep; changedMemory = false; dirOfChanchedMemory = -1; listener = null; A = S = T = P = I = E = 0; signals = new EnumMap<ComputerSignal, Boolean>(ComputerSignal.class); changedRegisters = new EnumMap<ComputerRegister, Boolean>(ComputerRegister.class); ComputerSignal[] c = ComputerSignal.values(); for(ComputerSignal i: c) 166 { signals.put(i, false); } ComputerRegister[] r = ComputerRegister.values(); for(ComputerRegister i: r) { changedRegisters.put(i, false); } } /** * @brief Método que marca si una posición de memoria ha sido modificada en la ejecución de la última instrucción. * @param d Posición de memoria que ha cambiado. Ha de pertenecer al rango de memoria o de lo * contrario indicará que ninguna posición de memoria ha sido modificada en la ejecución * de la última instrucción. */ void setChangedMemory(int d) { if (d > 0 && d < Instruction.Memory_Address_Limit) { changedMemory = true; dirOfChanchedMemory = d; } else { changedMemory = false; dirOfChanchedMemory = -1; } } /** * @brief Indica si la última instrucción ejecutada ha modificado una posición de memoria. * @return */ boolean hasChangedMemory() { return changedMemory; } void setSemiState(int s) { semiStep = s; } int getSemiState() { return semiStep; } /** * @detail Indica qué posición de memoria ha sido modificada tras la última instrucción ejecutada. * En caso de que no se haya modificado ninguna posición, devolverá -1. * @return */ int getChangedMemory() { return dirOfChanchedMemory; } /** * @brief Llama al listener para indicarle el estado actual del computador. */ public void sendSignals() { callChange(); } /** * @brief Devuelve al estado inicial (= no modificado) los registros del computador. */ public void resetSignalsRegisters() { changedMemory = false; dirOfChanchedMemory = -1; ComputerSignal[] c = ComputerSignal.values(); for(ComputerSignal i: c) { signals.put(i, false); } ComputerRegister[] r = ComputerRegister.values(); for(ComputerRegister i: r) { changedRegisters.put(i, false); } } /** * @brief Marca cierto registro como modificado o no modificado. * @param s Registro * @param b true si el registro ha sido modificado, false en caso contrario */ public void setRegisterChanged(ComputerRegister s, boolean b) { changedRegisters.put(s, b); } /** * @brief Indica si cierto registro ha sido modificado por la última instrucción ejecutada. 167 * @param s Registro * @return */ public boolean hasRegisterChanged(ComputerRegister s) { boolean b = false; try{ b = changedRegisters.get(s); } catch (NullPointerException e) { } return b; } /** * @brief Marca cierta señal como modificada o no modificada. * @param s señal * @param b true si la señal ha sido modificada, false en caso contrario */ public void setSignal(ComputerSignal s, boolean b) { signals.put(s, b); } /** * @brief Indica si cierta señal ha sido modificada por la última instrucción ejecutada. * @param s Señal * @return */ public boolean getSignal(ComputerSignal s) { boolean b = false; try{ b = signals.get(s); } catch (NullPointerException e) { } return b; } /** * @brief Llama al listener para indicarle el estado actual del computador. */ private void callChange() { if(listener != null) { listener.stateChanged(); } else { //throw new NullPointerException(""); } } /** * Asigna un listener al ComputerState * @param l Listener */ void setListener(VirtualComputerListener l) { listener = l; } /** * Devuelve el listener. * @return Listener */ VirtualComputerListener getListener() { return listener; } /** * @brief Devuelve el contenido del registro A. * @return Registro A. */ public int getA() { return A; } /** * Cambia el registro A con el dato 'a' * @param a * @throws Exception Registro A fuera de rango */ public void setA(int a) throws Exception { if(a >= Instruction.Register_Min_Limit && a <= Instruction.Register_Max_Limit) { A = a; } else { throw new Exception("Registro A fuera de rango"); } 168 } /** * @brief Devuelve el contenido del registro S. * @return Registro S. */ public int getS() { return S; } /** * Cambia el registro S con el dato 's' * @param s * @throws Exception Registro S fuera de rango */ public void setS(int s) throws Exception { if(s >= 0 && s <= Instruction.Memory_Address_Limit) { S = s; } else { throw new Exception("Input register S out of boundaries"); } } /** * @brief Devuelve el contenido del registro T. * @return Registro T. */ public int getT() { return T; } /** * Cambia el registro T con el dato 't' * @param t * @throws Exception Registro T fuera de rango */ public void setT(int t) throws Exception { if(t >= Instruction.Register_Min_Limit && t <= Instruction.Register_Max_Limit) { T = t; } else { throw new Exception("Input register T out of boundaries"); } } /** * @brief Devuelve el contenido del registro P. * @return Registro P. */ public int getP() { return P; } /** * Cambia el registro P con el dato 'p' * @param p * @throws Exception Registro P fuera de rango */ public void setP(int p) throws Exception { if(p >= 0 && p <= Instruction.Memory_Address_Limit) { P = p; } else { throw new Exception("Input register P out of boundaries"); } callChange(); } /** * @brief Devuelve el contenido del registro I. * @return Registro I. */ public int getI() { return I; } /** * Cambia el registro I con el dato 'i' * @param i * @throws Exception Registro I fuera de rango */ public void setI(int i) throws Exception { if(i >= Instruction.Register_Min_Limit && i <= Instruction.Register_Max_Limit) { I = i; } else { throw new Exception("Input register I out of boundaries"); } } 169 /** * @brief Devuelve el contenido del registro E. * @return Registro E. */ public int getE() { return E; } /** * Cambia el registro E con el dato 'e' * @param e * @throws Exception Registro E fuera de rango */ public void setE(int e) throws Exception{ if(e >= Instruction.Register_Min_Limit && e <= Instruction.Register_Max_Limit) { E = e; } else { throw new Exception("Input register E out of boundaries"); } } /** * @brief Incrementa en una unidad el registro P. */ public void incrementP() { if(P >= Instruction.Memory_Address_Limit) { P = 0; } else { P += 1; } } } /** * @brief Constructor del computador, inicializa variables. */ VirtualComputer() { semiStep = First_Semistep; trafficLight = false; memoryMap = new Instruction[Instruction.Memory_Address_Limit+1]; InitialMemoryMap = new Instruction[Instruction.Memory_Address_Limit+1]; for(int i = 0; i < memoryMap.length; i++) { memoryMap[i] = new Instruction(); InitialMemoryMap[i] = new Instruction(); } setMemoryMapToZero(); state = new ComputerState(); } /** * @brief Constructor del computador que inicializa su memoria con 'memory' * @param memory Mapa de memoria del computador */ VirtualComputer(ArrayList<Instruction> memory) { memoryMap = new Instruction[Instruction.Memory_Address_Limit+1]; InitialMemoryMap = new Instruction[Instruction.Memory_Address_Limit+1]; for(int i = 0; i < memoryMap.length; i++) { memoryMap[i] = new Instruction(); InitialMemoryMap[i] = new Instruction(); } setMemoryMap(memory); state = new ComputerState(); /* //Innecesario, ya lo hace setMemoryMap(memory); for(int i = 0; i < memoryMap.length; i++) { try{ InitialMemoryMap[i].setInstructionSigned(memoryMap[i].getDataSigned()); } catch(Exception e) { } }*/ } /** * @brief Lleva el ordenador al estado inicial. * Pone a cero los registros y las señales, y devuelve la memoria principal a su estado inicial. */ public void restart() { try { state.resetSignalsRegisters(); 170 state.setA(0); state.setS(0); state.setT(0); state.setP(0); state.setI(0); state.setE(0); for(int i = 0; i < memoryMap.length; i++) { if(memoryMap[i].getDataSigned() != InitialMemoryMap[i].getDataSigned()) { memoryMap[i].setInstructionSigned(InitialMemoryMap[i].getDataSigned()); state.getListener().memoryChanged(memoryMap[i]); } } } catch(Exception e) { } } /** * @brief Asigna un nuevo listener al computador * @param l Listener */ public void setListener(VirtualComputerListener l) { state.setListener(l); } /** * Devuelve el listener del computador * @return Listener */ VirtualComputerListener getListener() { return state.getListener(); } /** * @biref Modifica la memoria del computador con 'memory' * @param memory Mapa de memoria */ public void setMemoryMap(ArrayList<Instruction> memory) { setMemoryMapToZero(); for(Instruction i: memory) { memoryMap[i.getAddressLocation()]= i; } for(int i = 0; i < memoryMap.length; i++) { try{ InitialMemoryMap[i].setInstructionSigned(memoryMap[i].getDataSigned()); } catch(Exception e) { } } } /** * @brief Inicializa a cero la memoria del computador. */ private void setMemoryMapToZero() { int d = 0; for(int i = 0; i < memoryMap.length; i++) { try{ memoryMap[i].setInstructionSigned(d); memoryMap[i].setAddressLocation(i); } catch(Exception e) { //TODO: } } } /** * @brief Devuelve el mapa de memoria del computador. * @return Mapa de memoria */ public ArrayList<Instruction> getMemoryMap() { ArrayList<Instruction> a = new ArrayList<Instruction>(); for(Instruction i: memoryMap) { a.add(i); } return a; } /** * Devuelve el estado del computador. * @return */ 171 ComputerState getState() { return state; } /** * Devuelve M(D), la dirección de memoria contenida en la posición D * @param d Posición de memoria * @return * @throws IndexOutOfBoundsException */ private int getIndirectAddress(int d) throws IndexOutOfBoundsException { int r = 0; if(d < 0 || d > Instruction.Memory_Address_Limit) { throw new IndexOutOfBoundsException("" + d); } r = memoryMap[d].getDataSigned(); if(r < 0 || r > Instruction.Memory_Address_Limit) { throw new IndexOutOfBoundsException("" + r); } return r; } /** * @brief Devuelve la próxima instrucción a ejecutar, posición que marca el registro P. * @return */ public Instruction getNextInstruction() { return memoryMap[state.getP()]; } public int getSemistepInfo() { return semiStep; } public ComputerState executeSemistep() throws Exception { //Usamos el semáforo trafficLight para que no se puedan realizar //llamadas en paralelo/concurrentes a esta instrucción. if(trafficLight == false) { trafficLight = true; //Recogemos la instrucción a ejecutar Instruction ins = memoryMap[state.getP()]; //Marcamos todos los registros y señales como no modificados state.resetSignalsRegisters(); state.setSemiState(semiStep); if(semiStep == First_Semistep) { try{ //int operator = ins.getInstructionOperator(); state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I equivalente a: P -> S. M(S) -> T. T -> I. state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("Primer semipaso de instrucción"); } semiStep = Last_Semistep; } else if(semiStep == Last_Semistep) { if(ins.isInstruction() == true) { switch(ins.getOperationCode()) //Elegimos qué operación ejecutar según el código de operación. { case ALT: break; 172 case ALM: try{ int operator = ins.getInstructionOperator(); memoryMap[operator].setInstructionSigned(state.getA()); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.setT(state.getA()); //state.setI(ins.getDataSigned()); state.setS(operator); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I equivalente a: P -> S. M(S) -> T. T -> I. /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A -> M(D) state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.SA, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("ALM"); } break; case ALMI: try{ int operator = getIndirectAddress( ins.getInstructionOperator() ); memoryMap[operator].setInstructionSigned(state.getA()); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.getListener().memoryChanged(memoryMap[operator]); state.setT(state.getA()); state.setI(operator); state.setS(operator); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A -> M(M(D)) state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.SA, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); 173 case CAR: } catch(IndexOutOfBoundsException exception) { throw new Exception("ALMI"); } break; try{ state.setA(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(state.getA()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("CAR"); } break; case CARI: try{ state.setA(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(state.getA()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.EA, true); 174 //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case ESC: } catch(IndexOutOfBoundsException exception) { throw new Exception("CARI"); } break; try{ state.setE(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(state.getE()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.getListener().writeNumberToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) ->E state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("ESC"); } break; case ESCI: try{ state.setE(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(state.getE()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.getListener().writeNumberToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); 175 state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case LEE: } catch(IndexOutOfBoundsException exception) { throw new Exception("ESCI"); } break; try{ /** * Before executing this instruction, * the input from the keyboard should have been saved into register E. */ int operator = ins.getInstructionOperator(); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); //state.setI(ins.getDataSigned()); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //E -> M(D) state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("LEE"); } break; case LEEI: try{ /** * Before executing this instruction, * the input from the keyboard should have been saved into register E. */ int operator = getIndirectAddress( ins.getInstructionOperator() ); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); state.setI(operator); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales 176 //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A -> M(M(D)) state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SUM: } catch(IndexOutOfBoundsException exception) { throw new Exception("LEEI"); } break; try{ state.setA(state.getA() + memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.SUMA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("SUM"); } break; case SUMI: try{ state.setA(state.getA() + memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); 177 state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.SUMA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case RES: } catch(IndexOutOfBoundsException exception) { throw new Exception("SUMI"); } break; try{ state.setA(state.getA() - memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.RESA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("RES"); } break; case RESI: try{ state.setA(state.getA() memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); 178 state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.RESA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case MUL: } catch(IndexOutOfBoundsException exception) { throw new Exception("RESI"); } break; try{ state.setA(state.getA() * memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MULTA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("MUL"); } break; case MULI: 179 try{ state.setA(state.getA() * memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MULTA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case DIV: } catch(IndexOutOfBoundsException exception) { throw new Exception("MULI"); } break; try{ state.setA(state.getA() / memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.DIVA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); 180 state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("DIV"); } break; case DIVI: try{ state.setA(state.getA() / memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.DIVA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case MOD: } catch(IndexOutOfBoundsException exception) { throw new Exception("DIVI"); } break; try{ state.setA(state.getA() % memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); 181 state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MODA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("MOD"); } break; case MODI: try{ state.setA(state.getA() % memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MODA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SAL: } catch(IndexOutOfBoundsException exception) { throw new Exception("MODI"); } break; try{ //state.setS(state.getP()); //state.setT(ins.getDataSigned()); //state.setI(ins.getDataSigned()); state.setP(ins.getInstructionOperator()); //Ahora señalamos qué registros han cambiado //state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); //state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ 182 //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("SAL"); } break; case SALI: try{ state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); case SAN: } catch(IndexOutOfBoundsException exception) { throw new Exception("SALI"); } break; try{ //state.setS(state.getP()); //state.setT(ins.getDataSigned()); //state.setI(ins.getDataSigned()); if(state.getA() < 0) { state.setP(ins.getInstructionOperator()); //Ahora señalamos qué registros han cambiado //state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); //state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.incrementP(); //Ahora señalamos qué registros han cambiado //state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); //state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir 183 llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAN"); } break; case SANI: try{ if(state.getA() < 0) { state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { /*state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned());*/ state.incrementP(); //Ahora señalamos qué registros han cambiado /*state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true);*/ state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SAC: } } catch(IndexOutOfBoundsException exception) { throw new Exception("SANI"); } break; 184 try{ /*state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned());*/ //Ahora señalamos qué registros han cambiado /*state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true);*/ state.setRegisterChanged(ComputerRegister.P, true); if(state.getA() == 0) { state.setP(ins.getInstructionOperator()); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.incrementP(); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAC"); } break; case SACI: try{ //Ahora señalamos qué registros han cambiado if(state.getA() == 0) { state.setRegisterChanged(ComputerRegister.T, state.setRegisterChanged(ComputerRegister.I, state.setRegisterChanged(ComputerRegister.S, state.setRegisterChanged(ComputerRegister.P, true); true); true); true); state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); 185 state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { /*state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true);*/ state.setRegisterChanged(ComputerRegister.P, true); /*state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned());*/ state.incrementP(); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SAP: } } catch(IndexOutOfBoundsException exception) { throw new Exception("SACI"); } break; try{ /*state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned());*/ //Ahora señalamos qué registros han cambiado /*state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true);*/ state.setRegisterChanged(ComputerRegister.P, true); if(state.getA() > 0) { state.setP(ins.getInstructionOperator()); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.incrementP(); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } } 186 catch(IndexOutOfBoundsException exception) { throw new Exception("SAP"); } break; case SAPI: try{ if(state.getA() > 0) { state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, state.setRegisterChanged(ComputerRegister.I, state.setRegisterChanged(ComputerRegister.S, state.setRegisterChanged(ComputerRegister.P, true); true); true); true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { /*state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned());*/ state.incrementP(); //Ahora señalamos qué registros han cambiado /*state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true);*/ state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case ECA: } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAPI"); } break; try{ state.setE(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(state.getE()); //state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); 187 state.getListener().writeCharacterToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(D) ->E state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("ECA"); } break; case ECAI: try{ state.setE(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(state.getE()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.getListener().writeCharacterToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case LCA: } catch(IndexOutOfBoundsException exception) { throw new Exception("ECAI"); } break; try{ /** * Before executing this instruction, 188 * the input from the keyboard should have been saved into register E. */ int operator = ins.getInstructionOperator(); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); //state.setI(ins.getDataSigned()); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); //state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //E -> M(D) state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("LCA"); } break; case LCAI: try{ /** * Before executing this instruction, * the input from the keyboard should have been saved into register E. */ int operator = getIndirectAddress( ins.getInstructionOperator() ); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); state.setI(operator); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I /*state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ //A -> M(M(D)) state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); 189 state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("LCAI"); } break; } } else { throw new Exception("The emulator arrived to a memory address with no instruction. The memory map may have not ben properly initialized"); } semiStep = First_Semistep; } } //Ya hemos ejecutado la instrucción así que apagamos el semáforo. trafficLight = false; return getState(); } /** * @brief Método que ejecuta la siguiente instrucción. * @return * @throws Exception */ public ComputerState executeNextInstruction() throws Exception { //Usamos el semáforo trafficLight para que no se puedan realizar //llamadas en paralelo/concurrentes a esta instrucción. if(trafficLight == false) { trafficLight = true; //Recogemos la instrucción a ejecutar Instruction ins = memoryMap[state.getP()]; //Marcamos todos los registros y señales como no modificados state.resetSignalsRegisters(); state.setSemiState(First_Semistep); if(ins.isInstruction() == true) { switch(ins.getOperationCode()) //Elegimos qué operación ejecutar según el código de operación. { case ALT: break; case ALM: try{ /*int operator = ins.getInstructionOperator(); state.setT(memoryMap[operator].getDataSigned()); state.setI(memoryMap[operator].getDataSigned()); state.setS(state.getP()); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //M(P) -> I equivalente a: P -> S. M(S) -> T. T -> I. state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true);*/ int operator = ins.getInstructionOperator(); memoryMap[operator].setInstructionSigned(state.getA()); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.setT(state.getA()); 190 state.setI(ins.getDataSigned()); state.setS(operator); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I equivalente a: P -> S. M(S) -> T. T -> I. state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A -> M(D) state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.SA, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("ALM"); } break; case ALMI: try{ int operator = getIndirectAddress( ins.getInstructionOperator() ); memoryMap[operator].setInstructionSigned(state.getA()); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.getListener().memoryChanged(memoryMap[operator]); state.setT(state.getA()); state.setI(operator); state.setS(operator); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A -> M(M(D)) state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.SA, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case CAR: } catch(IndexOutOfBoundsException exception) { throw new Exception("ALMI"); } break; try{ state.setA(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(state.getA()); 191 state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(D) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("CAR"); } break; case CARI: try{ state.setA(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(state.getA()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case ESC: } catch(IndexOutOfBoundsException exception) { throw new Exception("CARI"); } break; try{ state.setE(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(state.getE()); 192 state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.getListener().writeNumberToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(D) ->E state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("ESC"); } break; case ESCI: try{ state.setE(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(state.getE()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.getListener().writeNumberToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case LEE: } catch(IndexOutOfBoundsException exception) { throw new Exception("ESCI"); } break; try{ /** * Before executing this instruction, 193 * the input from the keyboard should have been saved into register E. */ int operator = ins.getInstructionOperator(); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); state.setI(ins.getDataSigned()); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //E -> M(D) state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("LEE"); } break; case LEEI: try{ /** * Before executing this instruction, * the input from the keyboard should have been saved into register E. */ int operator = getIndirectAddress( ins.getInstructionOperator() ); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); state.setI(operator); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A -> M(M(D)) state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); 194 //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SUM: } catch(IndexOutOfBoundsException exception) { throw new Exception("LEEI"); } break; try{ state.setA(state.getA() + memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.SUMA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("SUM"); } break; case SUMI: try{ state.setA(state.getA() + memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); 195 //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.SUMA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case RES: } catch(IndexOutOfBoundsException exception) { throw new Exception("SUMI"); } break; try{ state.setA(state.getA() - memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.RESA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("RES"); } break; case RESI: try{ state.setA(state.getA() memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); 196 //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.RESA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case MUL: } catch(IndexOutOfBoundsException exception) { throw new Exception("RESI"); } break; try{ state.setA(state.getA() * memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MULTA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("MUL"); } break; case MULI: try{ state.setA(state.getA() * memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); 197 state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MULTA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case DIV: } catch(IndexOutOfBoundsException exception) { throw new Exception("MULI"); } break; try{ state.setA(state.getA() / memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.DIVA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("DIV"); } break; case DIVI: try{ state.setA(state.getA() / memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la 198 instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.DIVA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case MOD: } catch(IndexOutOfBoundsException exception) { throw new Exception("DIVI"); } break; try{ state.setA(state.getA() % memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A+M(D) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MODA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("MOD"); } break; case MODI: try{ state.setA(state.getA() % memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.incrementP(); //Ahora señalamos qué registros han cambiado 199 state.setRegisterChanged(ComputerRegister.A, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EO, true); state.setSignal(ComputerSignal.MODA, true); state.setSignal(ComputerSignal.EA, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SAL: } catch(IndexOutOfBoundsException exception) { throw new Exception("MODI"); } break; try{ state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); state.setP(ins.getInstructionOperator()); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("SAL"); } break; case SALI: try{ state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); 200 state.setSignal(ComputerSignal.EI, true); //M(D) -> P state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); case SAN: } catch(IndexOutOfBoundsException exception) { throw new Exception("SALI"); } break; try{ state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); if(state.getA() < 0) { state.setP(ins.getInstructionOperator()); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAN"); } break; case SANI: try{ if(state.getA() < 0) { state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); 201 state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(D) -> P state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SAC: } } catch(IndexOutOfBoundsException exception) { throw new Exception("SANI"); } break; try{ state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, state.setRegisterChanged(ComputerRegister.I, state.setRegisterChanged(ComputerRegister.S, state.setRegisterChanged(ComputerRegister.P, true); true); true); true); if(state.getA() == 0) { state.setP(ins.getInstructionOperator()); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.incrementP(); 202 //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAC"); } break; case SACI: try{ //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); if(state.getA() == 0) { state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(D) -> P state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); state.incrementP(); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case SAP: } } catch(IndexOutOfBoundsException exception) { throw new Exception("SACI"); } break; try{ state.setS(state.getP()); state.setT(ins.getDataSigned()); state.setI(ins.getDataSigned()); 203 //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, state.setRegisterChanged(ComputerRegister.I, state.setRegisterChanged(ComputerRegister.S, state.setRegisterChanged(ComputerRegister.P, true); true); true); true); if(state.getA() > 0) { state.setP(ins.getInstructionOperator()); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //D -> P state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.incrementP(); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAP"); } break; case SAPI: try{ //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); if(state.getA() > 0) { state.setS(ins.getInstructionOperator()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setT(getIndirectAddress( ins.getInstructionOperator() )); state.setP( getIndirectAddress( ins.getInstructionOperator() ) ); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(D) -> P state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); state.setSignal(ComputerSignal.EP, true); state.sendSignals(); } else { state.setS(state.getP()); state.setT(ins.getDataSigned()); 204 state.setI(ins.getDataSigned()); state.incrementP(); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case ECA: } } catch(IndexOutOfBoundsException exception) { throw new Exception("SAPI"); } break; try{ state.setE(memoryMap[ins.getInstructionOperator()].getDataSigned()); state.setT(state.getE()); state.setI(ins.getDataSigned()); state.setS(ins.getInstructionOperator()); state.getListener().writeCharacterToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(D) ->E state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("ECA"); } break; case ECAI: try{ state.setE(memoryMap[ getIndirectAddress( ins.getInstructionOperator() ) ].getDataSigned()); state.setT(state.getE()); state.setI(getIndirectAddress( ins.getInstructionOperator() )); state.setS(getIndirectAddress( ins.getInstructionOperator() )); state.getListener().writeCharacterToScreen(); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.E, true); state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); 205 state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //M(M(D)) ->A state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EE, true); state.setSignal(ComputerSignal.ESCP, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); case LCA: } catch(IndexOutOfBoundsException exception) { throw new Exception("ECAI"); } break; try{ /** * Before executing this instruction, * the input from the keyboard should have been saved into register E. */ int operator = ins.getInstructionOperator(); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); state.setI(ins.getDataSigned()); state.setS(operator); state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //E -> M(D) state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("LCA"); } break; case LCAI: try{ /** * Before executing this instruction, * the input from the keyboard should have been saved into register E. */ int operator = getIndirectAddress( ins.getInstructionOperator() ); memoryMap[operator].setInstructionSigned(state.getE()); state.setT(state.getE()); state.setI(operator); state.setS(operator); 206 state.getListener().memoryChanged(memoryMap[operator]); state.setChangedMemory(memoryMap[operator].getAddressLocation()); state.incrementP(); //Ahora señalamos qué registros han cambiado state.setRegisterChanged(ComputerRegister.T, true); state.setRegisterChanged(ComputerRegister.I, true); state.setRegisterChanged(ComputerRegister.S, true); state.setRegisterChanged(ComputerRegister.P, true); //Aquí mostramos las señales usadas en el transcurso de la ejecución de la instrucción. //Algunos setSignal los comento, pero solo para no repetir llamadas iguales //M(P) -> I state.setSignal(ComputerSignal.SP, true); state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LECM, true); state.setSignal(ComputerSignal.ST, true); state.setSignal(ComputerSignal.EI, true); //A -> M(M(D)) state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); //state.setSignal(ComputerSignal.LECM, true); //state.setSignal(ComputerSignal.ST, true); //state.setSignal(ComputerSignal.EI, true); //state.setSignal(ComputerSignal.SD, true); //state.setSignal(ComputerSignal.ES, true); state.setSignal(ComputerSignal.LEET, true); state.setSignal(ComputerSignal.SE, true); state.setSignal(ComputerSignal.ET, true); state.setSignal(ComputerSignal.ESCM, true); //P -> P+1 state.setSignal(ComputerSignal.INCP, true); state.sendSignals(); } catch(IndexOutOfBoundsException exception) { throw new Exception("LCAI"); } break; } } else { throw new Exception("The emulator arrived to a memory address with no instruction. The memory map may have not ben properly initialized"); } } //Ya hemos ejecutado la instrucción así que apagamos el semáforo. trafficLight = false; return getState(); } } 207 11.1.15 Instruction.java package xenon; /** * * @brief Clase que contiene una instrucción * */ public class Instruction { //Constantes útiles public static final int Memory_Address_Limit = 2047; public static final int Instruction_Size_Limit = 65535; public static final int Register_Max_Limit = 32767; public static final int Register_Min_Limit = -32768; public static final int Operation_Code_Max = 31; /** * * @brief Códigos de operación. * */ public enum OperationCode { ALT(0, 0), ALM(1, 2), ALMI(2, 3), CAR(3, 4), CARI(4, 5), ESC(5, 6), ESCI(6, 7), LEE(7, 8), LEEI(8, 9), SUM(9, 10), SUMI(10, 11), RES(11, 12), RESI(12, 13), MUL(13, 14), MULI(14, 15), DIV(15, 16), DIVI(16, 17), MOD(17, MODI(18, 19), SAL(19, 20), SALI(20, 21), SAN(21, 22), SANI(22, 23), SAC(23, SACI(24, 25), SAP(25, 26), SAPI(26, 27), ECA(27, 28), ECAI(28, 29), LCA(29, 30), LCAI(30, 31); 18), 24), private int index; //Código de operación, en base 10 private int code; OperationCode(int i, int c) { index = i; code = c; } public int index() { return index; } public int code() { return code; } public boolean addressingMode() { return ((code & 0x01) == 1)? true : false; } }; //Una instrucción es un código de operación + operador (una dirección de memoria) private OperationCode operationCode; private int insOperator; //Operador de la instrucción (normalmente será una dirección de memoria) private int data; //sin signo 16 bit, [0, 65535]. Los números negativos se guardarán en complemento a 2 de 16bit private boolean isInstruction; private int addressLocation; /** * @brief Constructor. */ Instruction() { data = 0; isInstruction = false; insOperator = -1; addressLocation = -1; } /** * @detail Constructor que inicializa el contenido de la instrucción (código+operador), * pero no define la posición de memoria en que se encuentra la instrucción. * @param oc Código de operación * @param operator operador */ Instruction(OperationCode oc, int operator) { addressLocation = -1; data = 0; isInstruction = false; insOperator = -1; setInstruction(oc, operator); } /** * @detail Método que inicializa el contenido de la instrucción (código+operador), * pero no define la posición de memoria en que se encuentra la instrucción. * @param oc Código de operación * @param operator operador */ public int setInstruction(OperationCode oc, int operator)//TODO: throws Exception { 208 int r = 0; operationCode = oc; if(operator <= Memory_Address_Limit && operator >= 0) { if(oc != null) { isInstruction = true; insOperator = operator; } else { isInstruction = false; r = -2; } } else { isInstruction = false; r = -1; } updateFromInstruction(); return r; } /** * @detail Sitúa la instrucción en la posición de memoria 'ma'. * @param ma posición de memoria de la instrucción * @return * @throws Exception Será lanzada si la posición de memoria está fuera de rango */ public int setAddressLocation(int ma) throws Exception { int r = -1; if(ma <= Memory_Address_Limit && ma >= 0) { addressLocation = ma; r = 0; } else { throw new Exception("Error: Dirección " + ma + " fuera de rango"); } return r; } /** * @brief Devuelve la posición de memoria de la instrucción * @return Posición de memoria de la instrucción */ public int getAddressLocation() { return addressLocation; } public boolean isInstruction() { return isInstruction; } /** * Método que cambia el código de operación de la instrucción * @param oc * @return * TODO: Eliminar return parametro */ public int setOperationCode(OperationCode oc) { operationCode = oc; int r = 0; if(insOperator <= Memory_Address_Limit && insOperator >= 0) { if(operationCode != null) { isInstruction = true; } else { isInstruction = false; r = -2; } } else { isInstruction = false; r = -1; } updateFromInstruction(); return r; } /** * Método que cambia el operador de la instrucción * @param operator * @return 209 */ public int setInstructionOperator(int operator) { int r = 0; if(operator <= Memory_Address_Limit && operator >= 0) { if(operationCode != null) { isInstruction = true; } else { isInstruction = false; r = -2; } insOperator = operator; updateFromInstruction(); } else { isInstruction = false; r = -1; } return r; } /** * @brief Toma como entrada el dato (con signo) que corresponde a la instrucción. * El parámetro d debe pertenecer a [-32768, 32767] o lanzará una excepción */ public void setInstructionSigned(int d) throws Exception { if(d >= -(Instruction_Size_Limit+1)/2 && d <= (Instruction_Size_Limit+1)/2 -1) { if(d >= 0) { data = d; } else { //Pasamos de número negativo a complemento a 2 (16bit). data = d+(Instruction_Size_Limit+1); } updateFromData(); } else { throw new Exception("The number " + d + " cannot be an instruction"); } } /** * @brief Toma como entrada el dato (sin signo) que corresponde a la instrucción. * El parámetro d debe pertenecer a [0, 65535] o lanzará una excepción. */ public void setInstructionUnsigned(int d) throws Exception { if(d >= 0 && d <= Instruction_Size_Limit) { data = d; updateFromData(); } else { throw new Exception("The number " + d + " cannot be an instruction"); } } /** * Devuelve el código de operación de la instrucción. * @return Código de operación */ public OperationCode getOperationCode() { return operationCode; } /** * Devuelve el operador de la instrucción * @return Operador de la instrucción */ public int getInstructionOperator() { return insOperator; } /** * Devuelve el dato guardado en memoria, sin signo * @return */ 210 public int getDataUnsigned() { return data; } /** * Devuelve el dato guardado en memoria, con signo * @return */ public int getDataSigned() { int r = 0; int conditional = (((Instruction_Size_Limit+1)/2)-1); if(data <= conditional) { r = data; } else { //Pasamos de complemento a 2 a número con signo r = data-(Instruction_Size_Limit+1); } return r; } /** * @brief Calcula qué código de operación y operador tiene la instrucción a partir del dato guardado en memoria */ private void updateFromData() { //int oc = (data & 0xF000) >> 12; int code = (data & 0xF800) >> 11; //if( oc >= 0 && oc <= Operation_Code_Max ) if( code >= 0 && code <= Operation_Code_Max ) { int i = -1; for(OperationCode getIndex: OperationCode.values()) { if(code == getIndex.code()) { i = getIndex.index(); break; } } if(i != -1) { operationCode = OperationCode.values()[i]; insOperator = (data & 0x07FF); isInstruction = true; } else { isInstruction = false; } } else { isInstruction = false; } } /** * Calcula el dato a guardar en memoria */ private void updateFromInstruction() { int foo = 0; if(isInstruction()) { foo = (operationCode.code() << 11) | insOperator; } else { if(operationCode == null && insOperator != -1) { foo = insOperator; } else if (operationCode != null&& insOperator == -1) { foo = operationCode.code() << 11; } } try{ setInstructionUnsigned(foo); } catch(Exception e) { //TODO: } } /** 211 * @brief Crea una cadena que representa la instrucción. */ public String toString() { String s = null; if(isInstruction()) { if(operationCode == OperationCode.ALT) { s = Integer.toString(addressLocation,16)+ ": " + operationCode.name() + " : " + Integer.toString(getDataSigned(), 16); } else { s = Integer.toString(addressLocation,16)+ ": " + operationCode.name() + " " + Integer.toString(insOperator, 16) + " : " + Integer.toString(getDataSigned(), 16); } } else { s = Integer.toString(addressLocation,16)+ ": " + Integer.toString(getDataSigned(), 16); } return s; } } 212 11.1.16 ProjectsManager.java package xenon; import import import import import java.awt.event.MouseEvent; java.awt.event.MouseListener; java.io.File; java.io.FilenameFilter; java.util.ArrayList; import import import import import import import javax.swing.JFileChooser; javax.swing.JOptionPane; javax.swing.JTree; javax.swing.tree.DefaultMutableTreeNode; javax.swing.tree.DefaultTreeModel; javax.swing.tree.TreePath; javax.swing.tree.TreeSelectionModel; /** * * @brief Clase gestora de los proyectos abiertos * */ public class ProjectsManager implements MouseListener { ArrayList<Project> projectsList; //Lista de proyectos Project currentlySelectedProject;//Proyecto que se encuentra seleccionado actualmente ProjectFile currentlySelectedFileInJTree; //Fichero seleccionado en el árbol de ficheros JTree projectsTree; //Árbol de ficheros TabsManager tabsManager; //Gestor de pestañas public ProjectsManager(TabsManager tm) { //Inicializamos variables currentlySelectedFileInJTree = null; projectsList = new ArrayList<Project>(); DefaultMutableTreeNode top = new DefaultMutableTreeNode("Proyectos"); projectsTree = new JTree(top); projectsTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); projectsTree.addMouseListener(this); tabsManager = tm; currentlySelectedProject = null; } public JTree getProjectsTree() { return projectsTree; } public Project getCurrentlySelectedProject() { return currentlySelectedProject; } public ProjectFile getCurrentlySelectedFileInJTree() { return currentlySelectedFileInJTree; } public void closeProject() { boolean b = true; if(currentlySelectedProject != null) { //Cerramos pestañas b = tabsManager.closeAllTabsOfProject(currentlySelectedProject); //Si todo fue bien eliminamos los nodos del proyecto del árbol de proyectos if (b == true) { DefaultTreeModel model = (DefaultTreeModel) projectsTree.getModel(); model.removeNodeFromParent(currentlySelectedProject.pnode); projectsTree.setModel(model); projectsList.remove(currentlySelectedProject); } } } /** * @brief Elimina un fichero del árbol de proyectos * @param pf */ public void removeFileFromJTree(ProjectFile pf) { TreePath tp = new TreePath(pf.project.pnode.getPath()); DefaultMutableTreeNode root = (DefaultMutableTreeNode)projectsTree.getModel().getRoot(); DefaultTreeModel tm = new DefaultTreeModel(root); pf.project.projectFiles.remove(pf); pf.project.pnode.remove(pf.fnode); 213 projectsTree.setModel(tm); projectsTree.expandPath(tp); } /** * * @param pf * @return */ public File addBinaryFromCode(ProjectFile pf) { String arg1 = pf.file.getPath(); int lastIndex = arg1.lastIndexOf('.'); String str = arg1.substring(0, lastIndex) + ".ece"; File filep = new File(str); //Si el fichero ya existe en el árbol, no necesitamos añadirlo boolean flag = true; for(ProjectFile p : pf.project.projectFiles) { if( filep.getAbsolutePath().equals( p.file.getAbsolutePath() ) ) { flag = false; filep = p.file; } } //Si flag == true, el fichero todavía no existe en el árbol de proyectos, luego lo añadimos if(flag == true) { DefaultMutableTreeNode root = (DefaultMutableTreeNode)projectsTree.getModel().getRoot(); //Creamos un nuevo ProjectFile ProjectFile prfile = new ProjectFile(filep, pf.project); //Añadimos dicho ProjectFile a la lista de ficheros del proyecto pf.project.projectFiles.add(prfile); //Creamos un TreeNode para dicho ProjectFile DefaultMutableTreeNode node = new DefaultMutableTreeNode(prfile); prfile.setNode(node); //Añadimos dicho nodo a la lista de nodos del proyecto pf.project.pnode.add(node); //Actualizamos el modelo del árbol de proyectos DefaultTreeModel tm = new DefaultTreeModel(root); projectsTree.setModel(tm); //Seleccionamos el nodo perteneciente al fichero añadido en el árbol de proyectos projectsTree.expandPath(new TreePath(pf.project.pnode.getPath())); //System.out.println("Añadido fichero " + filep.getName() + " al proyecto " + pf.project.file.getName() // + " " + pf.project.pnode.isNodeChild(node)); } return filep; } /** * @brief Crea un nuevo proyecto. */ public void createProject() { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = fc.showDialog(null, "Nuevo Proyecto"); if (returnVal == JFileChooser.APPROVE_OPTION) { File projectDir = fc.getSelectedFile(); if(projectDir.exists()) { JOptionPane.showMessageDialog(null, "El proyecto no ha podido ser creado en el directorio elegido " + "porque dicho directorio ya existe."); } else { //Creamos un nuevo directorio boolean success = projectDir.mkdir(); if(success) { //Creamos un fichero ls2 con el nombre del proyecto File f = new File(projectDir.getAbsolutePath() + "/" + projectDir.getName() + ".ls2"); try{ f.createNewFile(); } catch(Exception y) { } //Abrimos el proyecto openProject(projectDir); } 214 else { JOptionPane.showMessageDialog(null, "Ha ocurrido un error al crear el directorio del proyecto."); } } System.out.println("Creando proyecto en: " + projectDir.getPath() + "."); } else { System.out.println("Comando de crear proyecto cancelado por el usuario."); } } /** * @brief Abre el proyecto que está en el directorio que contiene el parámetro file * @param file */ private void openProject(File file) { //Comprobamos si dicho proyecto ya está abierto boolean flag = true; for(Project p : projectsList) { if( file.getPath().equals( p.file.getPath() ) ) { flag = false; } } //Si flag == true, el proyecto todavía no se ha abierto if (flag == true) { System.out.println("Abriendo: " + file.getAbsolutePath() + "."); //Creamos un filtro de forma que solo obtengamos ficheros con las extensiones txt, ls2 o ece FilenameFilter filter = new FilenameFilter(){ @Override public boolean accept(File arg0, String name) { String arg1 = name.toLowerCase(); if(arg1.lastIndexOf('.')>0) { // get last index for '.' char int lastIndex = arg1.lastIndexOf('.'); // get extension String str = arg1.substring(lastIndex); // match path name extension if(str.equals(".txt") || str.equals(".ls2") || str.equals(".ece")) { return true; } } return false; } }; //Obtenemos la lista de ficheros del proyecto aplicando el filtro. File[] fileList = file.listFiles(filter); Project p = new Project(); p.file = file; DefaultMutableTreeNode root = (DefaultMutableTreeNode)projectsTree.getModel().getRoot(); //Nodo del proyecto en el árbol de proyectos DefaultMutableTreeNode project = new DefaultMutableTreeNode(p); p.pnode = project; DefaultMutableTreeNode node; for(File filep:fileList) { if(filep.exists()) { //Añadimos el fichero al proyecto ProjectFile prfile = new ProjectFile(filep, p); p.projectFiles.add(prfile); node = new DefaultMutableTreeNode(prfile); prfile.setNode(node); project.add(node); //tabsManager.addTab(prfile); } } //Añadir proyecto a la lista de proyectos root.add(project); //Actualizar el modelo del árbol de proyectos con los nuevos nodos DefaultTreeModel tm = new DefaultTreeModel(root); projectsTree.setModel(tm); //Seleccionar el proyecto que acabamos de abrir 215 projectsTree.expandPath(new TreePath(project.getPath())); projectsList.add(p); } } /** * @brief Muestra una ventana para seleccionar el proyecto que queremos abrir, y luego abre dicho proyecto */ public void openProject() { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = fc.showDialog(null, "Abrir Proyecto"); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); openProject(file); } else { System.out.println("Comando de apertura cancelado por el usuario."); } } @Override public void mouseClicked(MouseEvent arg0) { } @Override public void mouseEntered(MouseEvent arg0) { } @Override public void mouseExited(MouseEvent arg0) { } /** * @detail Un click selecciona el fichero/proyecto. Dos clicks abre el fichero en cuestión */ @Override public void mousePressed(MouseEvent e) { int selRow = projectsTree.getRowForLocation(e.getX(), e.getY()); TreePath selPath = projectsTree.getPathForLocation(e.getX(), e.getY()); if(selRow != -1) { if(e.getClickCount() == 2) //doble click, abrir fichero seleccionado { DefaultMutableTreeNode node = (DefaultMutableTreeNode)selPath.getLastPathComponent(); if(selPath.getPathCount() == 3 && node.isLeaf()) { ProjectFile pf = (ProjectFile)node.getUserObject(); //System.out.println(selPath.getPathCount() + " " + selPath + " " + pf.file.getPath()); //Añadir pestaña, o, si ya existía, seleccionarla y mostrar el archivo tabsManager.addTab(pf); } } else if(e.getClickCount() == 1) //un click, actualizamos el fichero y proyecto seleccionados { DefaultMutableTreeNode l = (DefaultMutableTreeNode)selPath.getLastPathComponent(); if(selPath.getPathCount() >= 2) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)selPath.getPathComponent(1); currentlySelectedProject = (Project)node.getUserObject(); //System.out.println(currentlySelectedProject); } if(selPath.getPathCount() == 3 && l.isLeaf()) { currentlySelectedFileInJTree = (ProjectFile)l.getUserObject(); } else { currentlySelectedFileInJTree = null; } } } } @Override public void mouseReleased(MouseEvent arg0) { } } 216 11.1.17 XenonHelper.java package xenon; import import import import import import java.io.File; java.io.FileInputStream; java.io.FileNotFoundException; java.io.FileOutputStream; java.io.IOException; java.util.ArrayList; /** * * @brief Clase que realiza tareas de compilación y lectura de binarios. * */ public class XenonHelper { /** * * @brief Lista de pseudoinstrucciones * */ public enum PseudoInstruction { ORG, ESP, CTE, FIN, DRE }; /* * Este método recoge la salida del método translateToInstructions(String) y lo convierte * en un mapa de memoria */ public static ArrayList<Instruction> generateMemoryMap(ArrayList<Instruction> in) { int n = 0; //Primero localizamos la dirección de memoria más alta con alguna instrucción. for(Instruction i: in) { int m = i.getAddressLocation(); if(m > n) { n = m; } } ArrayList<Instruction> map = new ArrayList<Instruction>(n+1); int d = 0; //Rellenamos el mapa de memoria con instrucciones en blanco for(int i = 0; i <= n; i++) { Instruction e = new Instruction(); try{ e.setAddressLocation(i); e.setInstructionSigned(d); } catch(Exception x){ //TODO } map.add(e); } //Reemplazamos las instrucciones en blanco con las reales for(Instruction i: in) { map.set(i.getAddressLocation(), i); } return map; } /** * @brief Lee una cadena de texto y la traduce a instrucciones * @param code * @return */ @SuppressWarnings("unused") public static ArrayList<Instruction> translateToInstructions(String code) throws Exception { ArrayList<Instruction> array = new ArrayList<Instruction>(); ArrayList<LineCode> lineCodeArray = new ArrayList<LineCode>(); String[] lines = code.split(System.getProperty("line.separator")); int lineCounter = 0; boolean arrivedToFIN = false; for(String line: lines) { if(arrivedToFIN == false) { lineCounter++; boolean thereIsSomething = false; LineCode l = new LineCode(); //String[] words = line.split(" "); String[] words = line.split("\\s+"); 217 ArrayList<String> awords = new ArrayList<String>(); String mensaje = new String(""); for(String w: words) { if(w.indexOf(" ") == -1 && w.length() > 0) { awords.add(new String(w)); } } words = awords.toArray(new String[awords.size()]); for(String w: words) { mensaje += " | " + w ; } //System.out.println("Línea " + lineCounter + " : " + mensaje); int index = 0; if(words.length > 0) { if(words[index].lastIndexOf(":") == words[index].length()-1 && words[index].length() > 1) { l.label = words[index].substring(0, words[0].length()-1); index++; } } if(words.length > index) { try{ l.instruction.setOperationCode(Instruction.OperationCode.valueOf(words[index])); index++; if(words.length == index + 1) { //There is an address thereIsSomething = true; l.addressLabel = words[index]; } else if(l.instruction.getOperationCode() == Instruction.OperationCode.ALT) { thereIsSomething = true; l.addressLabel = "0"; } else if(words.length == index ) { throw new Exception("Error en línea " + lineCounter + " : falta dirección de memoria en la instrucción: " + line); } else if(words.length >= index + 2) { throw new Exception("Error en línea " + lineCounter + " : la instrucción solo ha de tener un argumento: " + line); } } catch (IllegalArgumentException e) { try{ l.pseudoInstruction = PseudoInstruction.valueOf(words[index]); } catch(Exception excp) { throw new Exception("Error en línea " + lineCounter + " : instrucción '" + words[index] + "' no reconocida en: "+ line ); } index++; if(l.pseudoInstruction == PseudoInstruction.FIN) { if(words.length == index) { thereIsSomething = true; arrivedToFIN = true; } else { throw new Exception("Error en línea " + lineCounter + " : La pseudoinstrucción FIN no ha de tener argumentos: " + line); } //Salimos del bucle for break; } else if(l.pseudoInstruction == PseudoInstruction.ORG) { if(words.length == index +1) { 218 l.addressLabel = words[index]; thereIsSomething = true; } else if (words.length == index) { throw new Exception("Error en línea " + lineCounter + " : falta dirección de memoria en la pseudoinstrucción: " + line); } else if (words.length >= index +2) { throw new Exception("Error en línea " + lineCounter + " : la pseudoinstrucción solo ha de tener un argumento: " + line); } } else if(l.pseudoInstruction == PseudoInstruction.ESP) { if(words.length == index +1) { l.addressLabel = words[index]; thereIsSomething = true; } else if (words.length >= index +2) { throw new Exception("Error en línea " + lineCounter + " : la pseudoinstrucción solo ha de tener un argumento: " + line); } else if (words.length == index) { throw new Exception("Error en línea " + lineCounter + " : falta número de espacios en la pseudoinstrucción: " + line); } } else if(l.pseudoInstruction == PseudoInstruction.CTE) { if(words.length == index + 1) { //l.addressLabel = words[index]; int bar = -1; try{ bar = Integer.parseInt(words[index]); } catch (Exception ex) { throw new Exception("Error en línea " + lineCounter + " : la constante "+ words[index] + " no es un número: " + line.toString()); } if(bar < Instruction.Register_Min_Limit || bar > Instruction.Register_Max_Limit) { throw new Exception("Error en línea " + lineCounter + " : constante fuera de rango en la pseudoinstrucción: " + line.toString()); } else { l.instruction.setInstructionSigned(bar); thereIsSomething = true; } } else if (words.length == index) { throw new Exception("Error en línea " + lineCounter + " : falta definir la constante en la pseudoinstrucción: " + line.toString()); } else if (words.length >= index +2) { throw new Exception("Error en línea " + lineCounter + " : la pseudoinstrucción solo ha de tener un argumento: " + line); } } else if(l.pseudoInstruction == PseudoInstruction.DRE) { if(words.length == index +1) { l.addressLabel = words[index]; thereIsSomething = true; } 219 else if (words.length == index) { throw new Exception("Error en línea " + lineCounter + " : falta etiqueta en la instrucción: " + line); } else if (words.length >= index +2) { throw new Exception("Error en línea " + lineCounter + " : la pseudoinstrucción solo ha de tener un argumento: " + line); } } } } if(thereIsSomething) { l.lineNumber = lineCounter; l.address = lineCodeArray.size(); lineCodeArray.add(l); } } } if(arrivedToFIN == false) { throw new Exception("Error de sintaxis: Falta la directiva FIN" ); } //Hemos leído las lineas, pero no hemos interpretado dónde está cada línea dentro de la posición de memoria int indexCounter = 0; int lastORGContent = 0; int lastORGIndex = 0; int lastESPContent = 0; /** * TODO: La instrucción ESP 4 debría dejar 4 espacios (cada espacio es del tamaño de una instr, 2 bytes) * en blanco. */ for(LineCode line: lineCodeArray) { if(line.pseudoInstruction == PseudoInstruction.ORG) { //El +1 es porque ORG es una pseudoinstrucción que no se encuentra en ninguna posición de memoria lastORGIndex = indexCounter + 1; try { lastORGContent = Integer.parseInt(line.addressLabel); line.instruction.setAddressLocation(lastORGContent); line.address = line.instruction.getAddressLocation(); lastESPContent = 0; } catch (Exception e) { throw new Exception("Error en línea " + line.lineNumber + " : '" + line.addressLabel + "' no es un número: " + lines[line.lineNumber-1]); } } else if(line.pseudoInstruction == PseudoInstruction.ESP) { int a =0; line.address = lastORGContent + lastESPContent + indexCounter - lastORGIndex; try { a = Integer.parseInt(line.addressLabel)-1; } catch (Exception e) { throw new Exception("Error en línea " + line.lineNumber + " : '" + a + "' no es un número: " + lines[line.lineNumber-1]); } if(a < 0) { throw new Exception("Error en línea " + line.lineNumber + " : El argumento '" + (a+1) + "' es un número de espacios menor que 1: " + lines[line.lineNumber-1]); } else if(lastESPContent + line.address + a > Instruction.Memory_Address_Limit) { throw new Exception("Error en línea " + line.lineNumber + " : Añadir '" + (int)(a+1) + "' espacios no es posible porque no hay memoria suficiente: " + lines[line.lineNumber-1]); } 220 else { lastESPContent += a; line.instruction.setAddressLocation(line.address); } } else { line.address = lastORGContent + lastESPContent + indexCounter - lastORGIndex; line.instruction.setAddressLocation(line.address); } indexCounter++; } //Ahora sustituimos las etiquetas por direcciones de memoria lineCounter = 0; for(LineCode line: lineCodeArray) { if(line.label != null) { try { int a = Integer.parseInt(line.label); throw new Exception("Error en línea " + line.lineNumber + " : La etiqueta '" + a + "' no puede ser un número: " + lines[line.lineNumber-1]); } catch (NumberFormatException e) { searchLabel(lineCodeArray, line.label); } } if(line.addressLabel != null && line.pseudoInstruction == null) { int address = searchLabel(lineCodeArray, line.addressLabel); if(address > 0 ) { line.instruction.setInstructionOperator(address); } else if (address == -1) { //Comprobar si la etiqueta es un número try { address = Integer.parseInt(line.addressLabel); } catch(Exception e) { throw new Exception("Error en línea " + line.lineNumber + " : Etiqueta '" + line.addressLabel + "' no encontrada: " + lines[line.lineNumber - 1]); } int r = line.instruction.setInstructionOperator(address); if( r == -1) { throw new Exception("Error en línea " + line.lineNumber + " : Dirección de memoria '" + line.addressLabel + "' fuera de rango: " + lines[line.lineNumber - 1]); } else { //Todo ok } } } else if(line.addressLabel != null && line.pseudoInstruction == PseudoInstruction.DRE) { int address = searchLabel(lineCodeArray, line.addressLabel); if(address > 0 ) { line.instruction.setInstructionOperator(address); } else if (address == -1) { //Comprobar si la etiqueta es un número try { address = Integer.parseInt(line.addressLabel); } catch(Exception e) { throw new Exception("Error en línea " + line.lineNumber + " : Etiqueta '" + line.addressLabel + "' no encontrada: " + lines[line.lineNumber - 1]); } throw new Exception("Error en línea " + line.lineNumber + " : El operador '" + line.addressLabel + "' de la pseudoinstrucción ha de ser una etiqueta: " + lines[line.lineNumber - 1]); } 221 } lineCounter++; } int okay = 0; for(LineCode line: lineCodeArray) { okay = line.check(); switch(okay) { case 0: break; case -1: throw new Exception("Error: número de línea negativo " + line.lineNumber); case -2: throw new Exception("Error en la línea " + line.lineNumber + " : memoria fuera de rango" ); case -3: throw new Exception("Error en la línea " + line.lineNumber + " : pseudoInstruction e instruction nulos! "); case -4: throw new Exception("Error: número de línea negativo " + line.lineNumber + " : Pseudoinstrucción FIN no procesada correctamente"); default: throw new Exception("Error no reconocido"); } } //Rellenamos el array de instrucciones for(LineCode line: lineCodeArray) { if(line.pseudoInstruction != null) { switch(line.pseudoInstruction) { case ORG: case FIN: case ESP: case CTE: case DRE: //Todo OK break; //No deberíamos haber guardado esta pseudo instrucción!! throw new Exception("Error: número de línea negativo" + line.lineNumber + " : Pseudoinstrucción FIN no procesada correctamente"); array.add(line.instruction); break; array.add(line.instruction); break; array.add(line.instruction); break; } } else if(line.instruction != null && line.instruction.isInstruction()) { array.add(line.instruction); } } return array; } /** * @brief Busca una etiqueta en una lista de líneas de código. */ private static int searchLabel(ArrayList<LineCode> lineCodeArray, String addressLabel) throws Exception { int indexCounter = 0; int out = -1; //Etiqueta no encontrada int lastMod = 0; for(LineCode line: lineCodeArray) { if(addressLabel.equals(line.label)) { if(out != -1) { throw new Exception("Error en línea " + lineCodeArray.get(lastMod).lineNumber " : etiqueta '" + line.label + "' duplicada en la línea: " + line.lineNumber); } else { lastMod = indexCounter; out = line.address; } } indexCounter++; } return out; 222 + } /** * @brief Traduce a binario un programa, una vez tenemos las instrucciones que lo forman. * Este es el principal método que permite guardar en formato “ece” el código binario de un programa. */ public static byte[] translateToBinary(ArrayList<Instruction> code) { byte[] binary = new byte[(Instruction.Memory_Address_Limit+1)*2]; int foo = 0; for(Instruction i: code) { foo = i.getDataUnsigned(); //BigEndian or LittleEndian? binary[i.getAddressLocation()*2] = intToByte(foo & 0x00FF); binary[i.getAddressLocation()*2 + 1] = intToByte((foo & 0xFF00) >> 8); } return binary; } /** * @brief Método usado para convertir de int a byte. */ public static byte intToByte(int i) { return (byte)i; } /** * @brief Método usado para convertir de byte a int. */ public static int byteToInt(byte b) { int i = (byte)b; if(b < 0) { i = i - 2*((int)Byte.MIN_VALUE); } return i; } /** * @brief Traduce código binario a un mapa de memoria que contiene un programa. * Es el método principal a la hora de leer código binario y traducirlo a instrucciones * que entienda el computador virtual Xenon. */ public static ArrayList<Instruction> translateFromBinary(byte[] binary) { ArrayList<Instruction> array = new ArrayList<Instruction>(); int foo = 0; Instruction sr; for(int i = 0; i < binary.length/2; i++) { //BigEndian or LittleEndian? foo= byteToInt(binary[i*2]) + (byteToInt(binary[i*2 + 1]) << 8); if(foo != 0) { sr = new Instruction(); try{ sr.setInstructionUnsigned(foo); sr.setAddressLocation(i); } catch(Exception e) { } array.add(sr); } } return array; } /** * @brief Abre un fichero binario y devuelve el mapa de instrucciones. * @param file * @return * @throws Exception * @throws FileNotFoundException */ public static ArrayList<Instruction> openBinaryFile(File file) throws Exception, FileNotFoundException { long lSize=file.length(); int size= (int)lSize; if(lSize > Integer.MAX_VALUE) { throw new Exception("File is too big"); } 223 byte[] contents=new byte[size]; try { FileInputStream fis = new FileInputStream(file); fis.read(contents, 0, size); fis.close(); } catch (FileNotFoundException e){ throw e; } } return translateFromBinary(contents); /** * @brief Guarda el código binario de un programa en formato "ece". * @param file * @param ins * @throws IOException * @throws FileNotFoundException */ public static void saveToBinaryFile(File file, ArrayList<Instruction> ins) throws IOException, FileNotFoundException { byte[] contents = translateToBinary(ins); try { FileOutputStream fos = new FileOutputStream(file); fos.write(contents, 0, contents.length); fos.flush(); fos.close(); } catch (FileNotFoundException e){ throw e; } catch (IOException e){ throw e; } } } 224 11.1.18 Interface.java package xenon; import java.awt.Container; import java.awt.EventQueue; import java.awt.Rectangle; import import import import import import import import import import import import import import import import import import import import import import import import import import import javax.swing.AbstractAction; javax.swing.Action; javax.swing.ImageIcon; javax.swing.JCheckBox; javax.swing.JDialog; javax.swing.JFrame; javax.swing.JLabel; javax.swing.JMenu; javax.swing.JMenuBar; javax.swing.JMenuItem; javax.swing.JOptionPane; javax.swing.JPanel; javax.swing.JPopupMenu; javax.swing.JScrollPane; javax.swing.JSlider; javax.swing.JSplitPane; javax.swing.JTabbedPane; javax.swing.JTextArea; javax.swing.JToolBar; javax.swing.JTree; javax.swing.KeyStroke; javax.swing.JButton; java.awt.event.ActionEvent; java.awt.event.KeyEvent; java.awt.event.MouseListener; java.awt.event.MouseWheelEvent; java.awt.event.MouseWheelListener; import import import import javax.swing.GroupLayout; javax.swing.GroupLayout.Alignment; javax.swing.event.ChangeEvent; javax.swing.event.ChangeListener; import import import import import java.awt.CardLayout; java.io.BufferedReader; java.io.File; java.io.FileReader; java.util.ArrayList; // Font source: http://art.gnome.org/themes/icon?page=2 // License: GPL /** * @brief Vista principal del entorno de desarrollo * @details * En esta clase se encuentra el main(). Permite conmutar entre las vistas de desarrollo y depuración, * así como entrar en la vista de emulación. * */ public class Interface extends JFrame { /** * * @brief Listener que actualiza la frecuencia de ejecución cuando cambia el slider. * */ class SliderListener implements ChangeListener { //Etiqueta que muestra al usuario la frecuencia escogida. private JLabel label; DebugViewManager manager; SliderListener(JLabel l, DebugViewManager dvm) { label = l; manager = dvm; } @Override public void stateChanged(ChangeEvent arg0) { JSlider source = (JSlider)arg0.getSource(); long hz = (long)source.getValue(); label.setText(hz + " Hz"); if (!source.getValueIsAdjusting() && manager != null) { //Usamos 1000/f porque la función setExecutionPeriod hace uso de T=milisegundos. manager.setExecutionPeriod(1000L/hz); } } } /** * */ private static final long serialVersionUID = 1L; JPanel cardPanel; //Panel que usa CardLayout para cambiar entre la vista de depuración y de código. 225 final static String CODEVIEW = "Code"; final static String DEBUGVIEW = "Debug"; String state = CODEVIEW; //Variable que informa de si estamos actualmente en la vista de código o de depuración JTree projectsTree; //Árbol de proyectos TabsManager tabsManager; //Gestor de pestañas. DebugViewManager debugViewManager; //Controlador principal de la vista de depuración JTextArea problemasArea; //Área que informa de problemas en la vista de desarrollo JLabel time; //CesiusHelper core; ProjectsManager projectsManager; JSlider slider; //Slider que sirve para cambiar la frecuencia de ejecución del computador. /** * @brief Añade todos los componentes necesarios al panel. * @param pane */ public void addComponentToPane(Container pane) { debugViewManager = new DebugViewManager(); //Este panel contiene la vista de desarrollo JPanel codeJPanel = new JPanel(); //Barra de menú de la vista de desarrollo JMenuBar menuBarCodeView = new JMenuBar(); JMenu menu, submenu; JMenuItem menuItem; JToolBar toolBar; JButton button; ImageIcon icon; //A continuación definimos todas las acciones de la vista de código/desarrollo java.net.URL imageURL = Interface.class.getResource("images/window-new.png"); icon = new ImageIcon(imageURL); Action actionNuevoProyecto = new AbstractAction("Nuevo Proyecto", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { projectsManager.createProject(); } }; imageURL = Interface.class.getResource("images/document-save.png"); icon = new ImageIcon(imageURL); Action actionGuardar = new AbstractAction("Guardar", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { tabsManager.saveCurrentlySelectedTab(); } }; imageURL = Interface.class.getResource("images/gnome-fs-directory.png"); icon = new ImageIcon(imageURL); Action actionAbrirProyecto = new AbstractAction("Abrir Proyecto", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { projectsManager.openProject(); } }; imageURL = Interface.class.getResource("images/gtk-close.png"); icon = new ImageIcon(imageURL); Action actionCerrarProyecto = new AbstractAction("Cerrar Proyecto", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { projectsManager.closeProject(); } }; imageURL = Interface.class.getResource("images/document-save-as.png"); icon = new ImageIcon(imageURL); Action actionGuardarComo = new AbstractAction("Guardar Como...", icon) { 226 /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { tabsManager.saveCurrentlySelectedTabAs(); } }; imageURL = Interface.class.getResource("images/stock_data-linked-table.png"); icon = new ImageIcon(imageURL); Action actionGuardarTodo = new AbstractAction("Guardar Todo", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { tabsManager.saveAllTabs(); } }; imageURL = Interface.class.getResource("images/gtk-quit.png"); icon = new ImageIcon(imageURL); Action actionSalir = new AbstractAction("Salir", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { System.exit(0); } }; imageURL = Interface.class.getResource("images/gtk-delete.png"); icon = new ImageIcon(imageURL); Action actionEliminarFichero = new AbstractAction("Eliminar Fichero", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { //Adquirimos la información del fichero actualmente seleccionado en el árbol de ficheros ProjectFile currentFile = projectsManager.getCurrentlySelectedFileInJTree(); Object[] options = {"OK", "Cancelar"}; if(currentFile != null) { //Preguntamos al usuario si realmente desea eliminar el fichero int n = JOptionPane.showOptionDialog(null, "Desea eliminar " + currentFile.file.getName() + " del sistema?", "Confirme borrado",JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if(n == JOptionPane.OK_OPTION) { //Lo eliminamos de la lista de pestañas así como del árbol de ficheros tabsManager.dontAskAndRemoveTab(tabsManager.searchTab(currentFile)); projectsManager.removeFileFromJTree(currentFile); try{ //Eliminamos el fichero del sistema de archivos/disco duro. currentFile.file.delete(); } catch (Exception x) { problemasArea.append(x.getMessage() + "\n"); } } } } }; imageURL = Interface.class.getResource("images/stock_compile.png"); icon = new ImageIcon(imageURL); Action actionCompilar = new AbstractAction("Compilar", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { if(state.compareTo(CODEVIEW) == 0) { /* * Primero intentamos seleccionar para compilar la pestaña actual; * Si no es código o no hay ninguna pestaña seleccionada, comprobamos si hay * algún fichero de código seleccionado en el árbol de ficheros. En última instancia 227 * seleccionamos el fichero de código del actual proyecto. */ ProjectFile codeToCompile = null; Tab currentTab = tabsManager.getCurrentlySelectedTab(); ProjectFile currentFile = projectsManager.getCurrentlySelectedFileInJTree(); if(currentTab != null && currentTab.pFile.type == ProjectFile.FileType.CODE) { codeToCompile = currentTab.pFile; } else if(currentFile != null && currentFile.type == ProjectFile.FileType.CODE) { codeToCompile = currentFile; } else { Project p = projectsManager.getCurrentlySelectedProject(); if(p != null) { for(ProjectFile pFile: p.projectFiles) { if(pFile.type == ProjectFile.FileType.CODE) { codeToCompile = pFile; break; } } } } if(codeToCompile != null) { //Si el archivo ha sido modificado, preguntar si el usuario quiere guardarlo antes de compilar tabsManager.saveIfModified(codeToCompile); //Leer el fichero String code = ""; try { String strLine; BufferedReader br = new BufferedReader(new FileReader(codeToCompile.file)); while((strLine = br.readLine()) != null) { code += strLine + "\n"; } } catch(Exception ex) { } System.err.println("Error: " + ex.getMessage()); //Traducir a instrucciones y guardarlas en formato binario try { /** * Si el archivo seleccionado para compilar se llama X.ls2, esta * función añadirá al proyecto el archivo binario X.ece. */ File f = projectsManager.addBinaryFromCode(codeToCompile); if(!f.exists()) { //Crear el fichero f.createNewFile(); } //Crear el código binario, guardarlo, y avisar de que todo ha ido bien. XenonHelper.saveToBinaryFile(f, XenonHelper.translateToInstructions(code) ); problemasArea.append("Compilación de " + codeToCompile.file.getName() + " correcta y guardada en " } catch(Exception ce) { problemasArea.append(ce.getMessage() + "\n"); } } } } }; imageURL = Interface.class.getResource("images/stock_smart-playlist.png"); icon = new ImageIcon(imageURL); Action actionDepurar = new AbstractAction("Depurar", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { //state = !state; 228 + f.getName() +"\n"); ProjectFile.FileType.BINARY) if(state.compareTo(CODEVIEW) == 0) { ProjectFile codeToDebug = null; /* * Primero intentamos seleccionar para depurar la pestaña actual; * Si no es código o binario, o no hay ninguna pestaña seleccionada, comprobamos si hay * algún fichero de código seleccionado en el árbol de ficheros. En última instancia * seleccionamos el fichero de código del actual proyecto. */ Tab currentTab = tabsManager.getCurrentlySelectedTab(); ProjectFile currentFile = projectsManager.getCurrentlySelectedFileInJTree(); if(currentTab != null && (currentTab.pFile.type == ProjectFile.FileType.CODE || currentTab.pFile.type == ProjectFile.FileType.BINARY)) { codeToDebug = currentTab.pFile; } else if(currentFile != null && (currentFile.type == ProjectFile.FileType.CODE || currentFile.type == ProjectFile.FileType.BINARY)) { codeToDebug = currentFile; } else { Project p = projectsManager.getCurrentlySelectedProject(); if(p != null) { for(ProjectFile pFile: p.projectFiles) { if(pFile.type == ProjectFile.FileType.CODE || pFile.type == { codeToDebug = pFile; break; } } } } if(codeToDebug != null && codeToDebug.type == ProjectFile.FileType.CODE) { //Comprobar si el fichero ha sido modificado y preguntar al usuario si quiere guardarlo tabsManager.saveIfModified(codeToDebug); //Leer el fichero String code = ""; try { String strLine; BufferedReader br = new BufferedReader(new FileReader(codeToDebug.file)); while((strLine = br.readLine()) != null) { code += strLine + "\n"; } } catch(Exception ex) { System.err.println("Error: " + ex.getMessage()); problemasArea.append(ex.getMessage() + "\n"); } //Traducirlo a instrucciones ArrayList<Instruction> in = null; try { //Cargar el programa en el gestor de la vista de depuración, y abrir dicha vista in = XenonHelper.generateMemoryMap(XenonHelper.translateToInstructions(code)); debugViewManager.setDebugCode(in, codeToDebug.file); setTitle("CESIUS IDE - " + codeToDebug.file.getPath()); state = DEBUGVIEW; } catch(Exception ce) { System.out.println(ce.getMessage()); problemasArea.append(ce.getMessage() + "\n"); } System.out.println("Debugging code: " + codeToDebug.file.getName()); //Add those instructions to the debug } else if(codeToDebug != null && codeToDebug.type == ProjectFile.FileType.BINARY) { try { //Cargar binario en la vista de depuración ArrayList<Instruction> in = XenonHelper.openBinaryFile(codeToDebug.file); debugViewManager.setDebugCode(in, codeToDebug.file); state = DEBUGVIEW; System.out.println("Debugging binary: " + codeToDebug.file.getName()); setTitle("CESIUS IDE - " + codeToDebug.file.getPath()); } catch(Exception x){ 229 System.out.println(x.getMessage()); problemasArea.append(x.getMessage() + "\n"); } } } else if(state.compareTo(DEBUGVIEW) == 0) { state = CODEVIEW; setTitle("CESIUS IDE"); } CardLayout ml = (CardLayout)(cardPanel.getLayout()); //Cargar la vista actual ml.show(cardPanel, state); } }; imageURL = Interface.class.getResource("images/stock_data-next.png"); icon = new ImageIcon(imageURL); Action actionEjecutar = new AbstractAction("Ejecutar", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { Emulator sim = new Emulator(); ProjectFile codeToExecute = null; /* * Primero intentamos seleccionar para depurar la pestaña actual; * Si no es código o binario, o no hay ninguna pestaña seleccionada, comprobamos si hay * algún fichero de código seleccionado en el árbol de ficheros. En última instancia * seleccionamos el fichero de código del actual proyecto. */ Tab currentTab = tabsManager.getCurrentlySelectedTab(); ProjectFile currentFile = projectsManager.getCurrentlySelectedFileInJTree(); if(currentTab != null && (currentTab.pFile.type == ProjectFile.FileType.BINARY)) { codeToExecute = currentTab.pFile; } else if(currentFile != null && (currentFile.type == ProjectFile.FileType.BINARY)) { codeToExecute = currentFile; } else { Project p = projectsManager.getCurrentlySelectedProject(); if(p != null) { for(ProjectFile pFile: p.projectFiles) { if(pFile.type == ProjectFile.FileType.BINARY) { codeToExecute = pFile; break; } } } } if(codeToExecute != null && codeToExecute.type == ProjectFile.FileType.BINARY) { try { //Leer las instrucciones del archivo binario y abrir el emulador. ArrayList<Instruction> in = XenonHelper.openBinaryFile(codeToExecute.file); sim.setRunCode(in); sim.setMyTitle(codeToExecute.file.getPath()); System.out.println("Running binary: " + codeToExecute.file.getName()); sim.setVisible(true); } catch(Exception x){ System.out.println(x.getMessage()); problemasArea.append(x.getMessage() + "\n"); } } } }; imageURL = Interface.class.getResource("images/gtk-close.png"); icon = new ImageIcon(imageURL); Action actionCerrarFichero = new AbstractAction("Cerrar Fichero", icon) { /** * */ private static final long serialVersionUID = 1L; 230 public void actionPerformed(ActionEvent e) { tabsManager.closeCurrentlySelectedTab(); } }; imageURL = Interface.class.getResource("images/gtk-close.png"); icon = new ImageIcon(imageURL); Action actionCerrarTodos = new AbstractAction("Cerrar Todos", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { tabsManager.closeAllTabs(); } }; Action actionLimpiarProblemas = new AbstractAction("Limpiar", null) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { problemasArea.setText(""); } }; imageURL = Interface.class.getResource("images/help.png"); icon = new ImageIcon(imageURL); Action actionSobre = new AbstractAction("Sobre este programa...", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { Rectangle r = getBounds(); Sobre dialog = new Sobre(r.x, r.y); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setVisible(true); } }; //Creamos la barra de menú de la vista de código/desarrollo menu = new JMenu("Archivo"); menuBarCodeView.add(menu); menuItem = menu.add(actionNuevoProyecto); menu.add(menuItem); menu.addSeparator(); menuItem = menu.add(actionCerrarFichero); menu.add(menuItem); menuItem = menu.add(actionCerrarTodos); menu.add(menuItem); menuItem = menu.add(actionEliminarFichero); menu.add(menuItem); menu.addSeparator(); menuItem = menu.add(actionGuardar); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_S, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionGuardarComo); menu.add(menuItem); menuItem = menu.add(actionGuardarTodo); menu.add(menuItem); menu.addSeparator(); menuItem = menu.add(actionSalir); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, ActionEvent.CTRL_MASK)); menu.add(menuItem); ////////// menu = new JMenu("Proyecto"); menuBarCodeView.add(menu); menuItem = menu.add(actionAbrirProyecto); 231 menu.add(menuItem); menuItem = menu.add(actionCerrarProyecto); menu.add(menuItem); menu.addSeparator(); menuItem = menu.add(actionCompilar); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_B, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionDepurar); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_D, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionEjecutar); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_E, ActionEvent.CTRL_MASK)); menu.add(menuItem); /////////// menu = new JMenu("Ayuda"); menuBarCodeView.add(menu); menuItem = menu.add(actionSobre); menu.add(menuItem); //////////// //Creamos la barra de herramientas de la vista de desarrollo toolBar = new JToolBar(); toolBar.setFloatable(false); button = toolBar.add(actionNuevoProyecto); button.setToolTipText("Nuevo Fichero"); button = toolBar.add(actionGuardar); button.setToolTipText("Guardar"); button = toolBar.add(actionGuardarComo); button.setToolTipText("Guardar Como..."); button = toolBar.add(actionGuardarTodo); button.setToolTipText("Guardar Todo"); button = toolBar.add(actionAbrirProyecto); button.setToolTipText("Abrir Proyecto"); button = toolBar.add(actionCerrarProyecto); button.setToolTipText("Cerrar Proyecto"); button = toolBar.add(actionCompilar); button.setToolTipText("Compilar"); button = toolBar.add(actionDepurar); button.setToolTipText("Depurar"); button = toolBar.add(actionEjecutar); button.setToolTipText("Ejecutar"); //////////// /* * splitPane es un panel dividido de forma que en su parte izquierda tiene el árbol de archivos, * y en su parte derecha están las pestañas de los archivos abiertos y el panel de problemas. */ JSplitPane splitPane = new JSplitPane(); splitPane.setResizeWeight(0.15); //El árbol de archivos ha de estar dentro de un panel que permita el desplazamiento horiz/vertical. JScrollPane scrollPane = new JScrollPane(); splitPane.setLeftComponent(scrollPane); //rightSplitPane contiene el panel de problemas y las pestañas de archivos abiertos. JSplitPane rightSplitPane = new JSplitPane(); rightSplitPane.setResizeWeight(0.8); rightSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); splitPane.setRightComponent(rightSplitPane); JTabbedPane tabbedFilePane = new JTabbedPane(JTabbedPane.TOP); //Iniciamos el gestor de pestañas tabsManager = new TabsManager(tabbedFilePane); rightSplitPane.setLeftComponent(tabbedFilePane); projectsManager = new ProjectsManager(tabsManager); 232 scrollPane.setViewportView(projectsManager.getProjectsTree()); //El panel de problemas estará dentro de una pestaña JTabbedPane tabbedPane_1 = new JTabbedPane(JTabbedPane.TOP); rightSplitPane.setRightComponent(tabbedPane_1); problemasArea = new JTextArea(); problemasArea.setEditable(false); JScrollPane scrollPane_2 = new JScrollPane(problemasArea); tabbedPane_1.addTab("Problemas", null, scrollPane_2, null); //Creamos un menú vinculado al panel de problemas para poder vaciar dicho panel JPopupMenu popup = new JPopupMenu(); popup.add(actionLimpiarProblemas); MouseListener popupListener = new PopupListener(popup); problemasArea.addMouseListener(popupListener); //Aquí definimos la disposición gráfica de los componentes en la vista de desarrollo. GroupLayout gl_menu1 = new GroupLayout(codeJPanel); gl_menu1.setHorizontalGroup( gl_menu1.createParallelGroup(Alignment.LEADING) .addComponent(menuBarCodeView, 0, 1060, Short.MAX_VALUE) .addComponent(toolBar, 0, 1060, Short.MAX_VALUE) .addComponent(splitPane, 0, 1060, Short.MAX_VALUE) ); gl_menu1.setVerticalGroup( gl_menu1.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu1.createSequentialGroup() .addComponent(menuBarCodeView, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(toolBar, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE) .addComponent(splitPane, 0, 560, Short.MAX_VALUE) ) ); codeJPanel.setLayout(gl_menu1); ////////////// //Panel que contendrá toda la vista de depuración. JPanel debugJPanel = new JPanel(); //Barra de menús de la vista de depuración. JMenuBar menuBarDebug = new JMenuBar(); //A continuación definimos todas las acciones de la vista de depuración. imageURL = Interface.class.getResource("images/player_play.png"); icon = new ImageIcon(imageURL); Action actionEjecutarIns = new AbstractAction("Ejecutar Instrucción", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { debugViewManager.actionExecuteNextInstruction(); } }; imageURL = Interface.class.getResource("images/player_end.png"); icon = new ImageIcon(imageURL); Action actionEjecutarHasta = new AbstractAction("Ejecutar Hasta...", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { String s = (String)JOptionPane.showInputDialog( null, "Ejecutar hasta la instrucción en la posición de memoria:\n", "Introduzca dato", JOptionPane.PLAIN_MESSAGE, new ImageIcon(), null, "0"); if(s.compareTo("") != 0) { int num = Integer.parseInt(s); System.out.println("Ejecutar hasta la instrucción "+ num); if(num >= 0 && num <= Instruction.Memory_Address_Limit) { debugViewManager.actionRunTo(num); } } } }; imageURL = Interface.class.getResource("images/reload.png"); icon = new ImageIcon(imageURL); Action actionReiniciar = new AbstractAction("Comenzar de nuevo", icon) { /** 233 * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { debugViewManager.actionRestart(); } }; imageURL = Interface.class.getResource("images/player_fwd.png"); icon = new ImageIcon(imageURL); Action actionEjecutarTodo = new AbstractAction("Ejecutar Todo", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { debugViewManager.actionRun(); } }; imageURL = Interface.class.getResource("images/player_pause.png"); icon = new ImageIcon(imageURL); Action actionPausar = new AbstractAction("Pausar", icon) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { debugViewManager.actionPause(); } }; Action actionBinario = new AbstractAction("Binario", null) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { } debugViewManager.setRegistersBase(DebugViewManager.Base.BINARY); }; Action actionDecimal = new AbstractAction("Decimal", null) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { } debugViewManager.setRegistersBase(DebugViewManager.Base.DECIMAL); }; Action actionHexadecimal = new AbstractAction("Hexadecimal", null) { /** * */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { } debugViewManager.setRegistersBase(DebugViewManager.Base.HEXADECIMAL); }; menu = new JMenu("Archivo"); menuBarDebug.add(menu); menuItem = menu.add(actionSalir); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, ActionEvent.CTRL_MASK)); menu.add(menuItem); ////////////// menu = new JMenu("Vista"); menuBarDebug.add(menu); menuItem = menu.add(actionDepurar); menuItem.setText("Salir del modo depuración"); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_F, ActionEvent.CTRL_MASK)); menu.add(menuItem); menu.addSeparator(); submenu = new JMenu("Base"); 234 menu.add(submenu); submenu.add(actionBinario); submenu.add(actionDecimal); submenu.add(actionHexadecimal); ////////////// menu = new JMenu("Operaciones"); menuBarDebug.add(menu); menuItem = menu.add(actionEjecutarIns); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_S, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionEjecutarHasta); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_H, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionReiniciar); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_Q, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionEjecutarTodo); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_R, ActionEvent.CTRL_MASK)); menu.add(menuItem); menuItem = menu.add(actionPausar); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_P, ActionEvent.CTRL_MASK)); menu.add(menuItem); ////////////// //Definimos la barra de herramientas de la vista de depuración. toolBar = new JToolBar(); toolBar.setFloatable(false); button = toolBar.add(actionEjecutarIns); button.setToolTipText("Ejecutar Instrucción"); button = toolBar.add(actionEjecutarHasta); button.setToolTipText("Ejecutar Hasta..."); button = toolBar.add(actionReiniciar); button.setToolTipText("Comenzar de nuevo"); button = toolBar.add(actionEjecutarTodo); button.setToolTipText("Ejecutar Todo"); button = toolBar.add(actionPausar); button.setToolTipText("Pausar"); button = toolBar.add(actionDepurar); button.setToolTipText("Salir del modo depuración"); JLabel timeLabel = new JLabel(" T: "); JCheckBox checkBox = new JCheckBox(); checkBox.addItemListener(debugViewManager); JLabel checkBoxLabel = new JLabel("Ejecutar en 2 pasos"); time = new JLabel("000000 ms"); time.setToolTipText("Tiempo de ejecución"); debugViewManager.timeLabel = time; slider = new JSlider(JSlider.HORIZONTAL, 1, 1000, 2); slider.setToolTipText("Frecuencia del procesador"); //Etiqueta que muestra al usuario la frecuencia escogida. JLabel l = new JLabel("2 Hz"); l.setToolTipText("Frecuencia del procesador"); //El listener detectará que el slider ha cambiado y modificará la frecuencia del procesador SliderListener slistener = new SliderListener(l, debugViewManager); slider.addChangeListener(slistener); //Este listener sirve para poder mover el slider con la rueda del ratón slider.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent arg0) { if(slider != null) { int notches = arg0.getWheelRotation(); if (notches < 0) { slider.setValue(slider.getValue() + 1); } else { slider.setValue(slider.getValue() - 1); } } } 235 }); toolBar.add(timeLabel); toolBar.add(time); toolBar.add(checkBox); toolBar.add(checkBoxLabel); toolBar.add(slider); toolBar.add(l); //Definimos la disposición de los componentes de la vista de depuración. GroupLayout gl_menu2 = new GroupLayout(debugJPanel); gl_menu2.setHorizontalGroup( gl_menu2.createParallelGroup(Alignment.LEADING) .addComponent(menuBarDebug, 0, 1060, Short.MAX_VALUE) .addComponent(toolBar, 0, 1060, Short.MAX_VALUE) .addComponent(debugViewManager, 0, 1060, Short.MAX_VALUE) ); gl_menu2.setVerticalGroup( gl_menu2.createParallelGroup(Alignment.LEADING) .addGroup(gl_menu2.createSequentialGroup() .addComponent(menuBarDebug, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(toolBar, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE) .addComponent(debugViewManager, 0, 692, Short.MAX_VALUE)) ); debugJPanel.setLayout(gl_menu2); //Instanciamos el panel que contiene ambas vistas. cardPanel = new JPanel(new CardLayout()); cardPanel.add(codeJPanel, CODEVIEW); cardPanel.add(debugJPanel, DEBUGVIEW); //Añadimos dicho panel al panel principal pane.add(cardPanel); } /** * @brief Lanza la aplicación */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Interface frame = new Interface(); frame.pack(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Crear el frame */ public Interface() { //core = new CesiusHelper(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Definimos la posición en pantalla y el tamaño de la ventana. setBounds(100, 100, 1060, 750); setTitle("CESIUS IDE"); addComponentToPane(getContentPane()); } } 236