Diseño y Programación Orientados a Objetos
1er. Sem 2013
Tarea 4: Compuertas Digitales como Objetos de Software en C++

Recomendación: Lea detenidamente la tarea. Si algo no lo entiende, consulte en clases. Si es preciso, se incorporarán aclaraciones al final.
Esta tarea tiene por objetivos:
* Ejercitar la configuración de un ambiente de trabajo para desarrollo de aplicaciones en lenguaje C (puede usar Jgrasp o Eclipse)
* Reconocer objetos de software como modelos de objetos reales.
* Reconocer clases y relaciones entre ellas en códigos fuentes C++.
* Ejercitar el diseño e implementación de una clase simple en C++.
* Ejercitar la extensión de clases dadas para satisfacer nuevos requerimientos. 
* Ejercitar la entrada y salida de datos en C++.
* Ejercitar una estrategia para programar simulaciones de fenómenos discretos.

Descripción General
  En esta tarea se modela la interacción entre compuertas digitales básicas: NOT, OR, AND, NAND y NOR. Cada compuerta se modela según su función lógica y un retardo fijo para cada compuerta. A partir de estos modelos se construyen clases en Java que permiten crear objetos de software para representar compuertas reales. Decimos que las clases representan un modelo de la realidad pues no incorporamos todos los elementos presentes en compuertas reales; por ejemplo, las transiciones entre los niveles digitales se supondrán instantáneas. Veremos cómo este modelo genera resultados "curiosos" cuando analizamos el circuito de la figura 1:

Figura 1: Inversores interconectados: almacena 1 bit, sin control.

Modelos para los Objetos del Problema

Modelo de compuertas: Para modelar cada compuerta usaremos una etapa de entrada y otra de salida. La de entrada conoce el número de entradas de la compuerta y qué tiene conectada en cada una.  La otra etapa tiene sólo una señal de salida, el retardo de propagación de la compuerta y un punto de conexión externo. Todas las compuertas comparten al descripción de la etapa de salida. Así podemos definir la clase abstracta Gate para representar los aspectos comunes de toda compuerta e incluir en ella al menos un método abstaracto que permita calcular el valor lógico de salida que dependerá del número de entrada y la lógica de cada compuerta en particular. Será responsabilidad de cada subclase (Not, And, Or, etc) impementar ese método. En los archivos Gate.h y Gate.cpp usted encontrará un modelo para la parte común de toda compuerta lógica.

Modelo para la señales de entrada: las entradas provendrán de un archivo de texto con líneas con el siguiente formato:
<tiempo>  <valor>
Se propone modelar cada fuente digital como una salida que varía según los valores del archivo de entrada y cambia conforme pasa el tiempo. En archivo Source.h usted encontrará el modelo para las fuentes digitales.

Modelos para las interconexiones (cables): En los circuitos digitales los cables tienen un flujo causal bien definido. Así identificamos un punto desde cual proviene la señal (from) y por ende está conectado a alguna salida digital y otro extremo conectado a una entrada digital (to). Cabe destacar que no tiene sentido considerar dos exitaciones para un mismo cable, pero en general sí varias entradas digitales donde éste está conectado. Un cable es un mero transportador de los valores lógicos desde una salida digital a una o más entradas. Lo modelaremos sin retardo y sin estado lógico propio. Cuando alguien se lo pida, éste lo obtendrá del valor lógico de la salida digital que lo alimenta. En archivo Wire.h usted encontrará el modelo para los cables.

Modelo para un instrumento de medición: Para observar el valor de las señales en el tiempo es conveniente crear algún modelo para un instrumento que registre la evolución de ciertas variables lógicas. Es así como se modela un instrumento medidor a cuya entrada se conectan los cables de interés registrar en el tiempo. Este instrumento grabará en archivo los cambios de estado en el tiempo. En archivo Meter.h usted encontrará un modelo para el instrumento registrador.

Modelo para el avance del tiempo: El tiempo es una variable continua; sin embargo, en los circuitos digitales los estados cambian sólo cuando hay transiciones en las entradas y éstas se dan en tiempos discretos. Así los cambios ocurren en instantes discretos y no hay cambios de interés en otros instantes.
En presencia de variables con cambios discretos en el tiempo, como en las señales digitales, las simulaciones consideran avances no regulares del tiempo y definidos según el evento de interés futuro más próximo. En estos casos el algoritmo de simulación calcula los cambios de estado bajo demanda de los objetos modelados que requieren cambio. En cada iteración se pide actualización del objeto con actualización más próximo en el futuro. Para ello el algoritmo hace uso de la esturtura de datos Cola de Prioridad. Ésta es una cola donde los objetos insertados deben tener una relación de orden. Se insertan en la cola según se necesite y la operación para sacar elementos siempre extrae el más pequeño de los insertados. Si la relación de orden es el tiempo en que los cambios tendrán lugar, entonces al sacar objetos de la cola obtendremos el primero cuyo estado debe ser actualizado.
   En el caso de esta tarea, esa actualización afectará la entrada de  otras compuertas que deberán insertar eventos de actualización futura en el cola. El tiempo futuro de actualización depende del retardo de propagación de cada compuerta.
  El algoritmo para un simulador de eventos discretos es del tipo:

simulate(PriorityQueue & pq) {
      ChangeEvent &e;                             // Objeto ChangeEvent almacena referencia a objeto 
                                                            //involucrado, tiempo y valor de cambio futuro. 

      insertar_eventos_de_partida(pq); // primer cambio para cada fuente digital e itinerar 
                                                           // cambios para condición inicial de cada compuerta.

      while ( (e=pq.poll())!=null) {         // mientras haya eventos por procesar
            Avanzar el tiempo;
            Identificar todos los eventos simultáneos para el tiempo actual;
            Pedir a cada compuerta o fuente involucrada reflejar el nuevo valor en salida;
            Pedir a cada compuerta o fuente involucrada propagar la salida a nuevas compuertas; 
// esto gatilla 
                                                                          //nuevos eventos de cambios itinerados en pq. 

      }                                                   
   }

Resultados Esperados de su Grupo
Si bien usted puede usar un IDE (Integrated Development Environment), usted debe saber cómo compilar y correr su tarea dese la línea de comandos.
Su tarea debe ser ejecutable en aragorn.elo.utfsm.cl usando:
  $ make run
ante lo cual el programa pide:
1st. Source filename:  <First input signal filename>
2nd. Source filename:  <Second input signal filename>
Output filename:  <Output signal filename>

Luego el programa corre hasta generar toda la salida indicada.
Para correr los circuitos de la figura 1 (pregunta b) y figura 2 (pregunta d) usar
  $ make run1
y
  $ make run2

Usted deberá entregar los siguientes archivos:
- readme
- Archivo de Documentación: En éste usted responda las siguientes preguntas:
a) Para el código entregado analice el código del método simulate() de la clase Simulator. Haga los gráficos de las señales para ver el efecto de dejar sólo un llamado a log(currentTime) o dos (uno antes y otro después de pfocesar los eventos). ¿Cuál es la ventaja de poner dos llamados en lugar de uno?. ¿Podría usted armar este circuito sin usar instancias de Wire?
b) Cambie y el archivo DigitalCircuit1.cpp para  simular el circuito de la Figura 1. Incorpore un contador de instancias activas de ChangeEvent. Su objetivo es identificar si todos los objetos creados en el Heap son luego destruidos. Este programa no tiene archivos de entrada, sólo pida el archivo de salida por consola. Además pida un límite para el tiempo de simulación.Al término de su programa muestre por pantalla en número máximo de instancias creadas y el valor final de instancias activas (debería ser cero en circuitos que lleguen a estados estables). Haga los cambios necesarios si no es el caso. Utilice 2 [ns] (en realidad las unidades de tiempo son irrelevantes) como retardo de cada inversor.
Muestre un diagrama temporal para la salida de ambos inversores.
c) Cree la clase And. Utilice los mismos tipos de constructores que en Or
d) Cree la clase Nand.
   Usando esta implementación para la compuerta nand, cree un DigitalCircuit2.cpp para el siguiente circuito:

Figura 2: FlipFlip D de canto positivo de reloj (tomado de Wikipedia).
 En su documentación muestre el diagrama temporal generado cuando el reloj es de frecuencia igual a 20 veces el mayor retardo por usted considerado y la señal Data también es cuadrada y de la mitad de la frecuencia del reloj. Muestre 1,5 periodos de la señal D. No se espera que su programa genere el diagrama temporal. Puede usar el dibujo aquí incluido y el gráfico lo puede generar con una planilla de cálculo a partir de los datos de salida de su programa.
-  Códigos fuentes correspondiente a  DigitaCircuit1.cpp de la pregunta b), And.h, And.cpp de pregunta c), Nand.h, Nand.cpp y DigitalCircuit2.java de pregunta d).
- La entrega de la tarea será a través de Assembla usando GIT. Para ello revise esta documentación.

Ayudas
* Dé una mirada a la solución parcial del problema. Si encuentra errores o algo que pueda ser mejorado, avise al profesor.
* Como extensión para el archivo de salida use .csv. Luego trate este archivo como si fuera planilla electrónica. Usted podrá usar "tabs" como separador de columnas.

* No dude en consultar al profesor o ayudante sobre dudas de esta tarea.
* Espero esta tarea sea de su interés y lo motive a hacer pruebas adicionales a las aquí pedidas, se agradece; si embargo, sea cuidadoso, este ramo no es el único donde usted debe rendir bien.