• No se han encontrado resultados

Figura 3.3 Emulación de compilación dinámica

En la figura se muestra el proceso de emulación dinámica:

B. El software de emulación traduce las instrucciones Intel a instrucciones Motorola, y envía estas instrucciones a un buffer especial donde pueden ser almacenadas y reusadas.

C. Las Instrucciones del buffer pueden ser enviadas al procesador Motorola para su ejecución.

D. Después de que las instrucciones han sido ejecutadas, pueden ser vueltas a llamar del RAM buffer, por lo que se elimina la necesidad de recompilarlas.

Esta emulación es mucho más rápida.



¿Cómo se instrumenta un emulador?

Para escribir un emulador, debe contarse con un buen conocimiento de programación de computadoras (ensamblador y algún lenguaje de alto nivel) y electrónica digital. Los pasos principales son:

1. Seleccionar el lenguaje de programación a usar.

2. Encontrar toda la información disponible sobre el hardware a emular.

3. Escribir la emulación del CPU u obtener algún código existente para la emulación del CPU. 4. Escribir un prototipo del código para emular el resto del hardware, al menos parcialmente. 5. En este punto, es útil escribir un depurador integrado que permita interrumpir la emulación

y ver lo que el programa está haciendo. Puede también necesitarse un desensamblador del lenguaje ensamblador del sistema emulado (hay que escribir un propio si no existe alguno).

6. Tratar de ejecutar programas en el emulador.

7. Usar un desensamblador y un depurador para ver como los programas usan el hardware y ajustar el código del emulador

3.2.2 Simulación de hardware

⊕⊕⊕⊕

El problema de simular hardware se origina de tratar de reproducir el paralelismo inherente de los circuitos electrónicos, usando lenguajes de programación que son de naturaleza y diseño secuencial. El fundamento central de cualquier simulador, es el concepto de tiempo, y como los elementos que conforman un componente se comportan a través de él.

El enfoque tradicional para simular dispositivos paralelos es tratar a todos los componentes como si estuvieran sincronizados con respecto a la llamada cola global de eventos (global event queue). Esta estructura consiste básicamente de una lista ligada de nodos de tiempo, donde cada nodo tiene un apuntador a una lista de componentes, o eventos, que tienen que ser procesados en el tiempo indicado.

Todos los eventos ligados al mismo nodo de tiempo están esencialmente en paralelo entre sí. Cuando un componente produce una salida, todos los componentes que tienen una entrada que depende de la salida son colocados en la cola global de eventos en el nodo que representa el momento en que la señal de salida fue producida. Puesto que los nodos de tiempo son

secuenciales, los componentes conectados a cada uno de los nodos son simulados y más eventos son planificados para instantes posteriores, reflejando la salida de estos componentes. Esto continua hasta el fin de la cola de tiempos es alcanzado o el tiempo asignado para la simulación se acaba.

Un segundo enfoque, las colas de eventos distribuidos, consiste en encapsular una o más colas dentro de lo mismos componentes, por lo que se elimina todos los problemas inherentes de mantener una estructura global. Las colas son distribuidas en el componente y pueden existir en casi cualquier nivel de descripción. Cada cola mantiene la historia de señales que han sido enviadas al componente durante el curso de la simulación y mantiene una lista de todos los componentes que están a la espera de la señal. Por lo tanto, la cola distribuida sirve como un conector entre 2 componentes y también sirve como el medio en que las señales pueden propagarse en paralelo usando un lenguaje secuencial de programación.

Con respecto al hardware, las colas de eventos distribuidos representan cables; las señales viajan a través de cables, y los cables conectan a los componentes entre sí. Puesto que las colas y los cables realizan la misma función y están estrechamente relacionados, el concepto de colas distribuidas es mucho más atractivo e intuitivo que una cola global de eventos.

Todos los componentes son simulados de la misma manera. En términos de pseudocódigo, el algoritmo podría resumirse como:

función simular (componente)

mientras (las entradas al componente están listas) hacer incrementar tiempo local del componente

si (el componente no tiene subcomponentes) entonces llamar función de proceso virtual

de otra forma

para cada (puerto de entrada del componente) hacer para cada (elemento en el puerto de salida) hacer

ejecutar función simular para el componente de salida fin mientras

El simulador no es un reemplazo para un emulador. Un simulador es una herramienta totalmente diferente. Mientras que un emulador permite depurar el software ejecutándolo en un hardware especifico, un simulador permite depurar el software así como entender el microprocesador y el lenguaje de programación.

3.3 Máquinas virtuales

⊕⊕⊕⊕

El concepto de máquinas virtuales es usado a menudo en computación para solucionar problemas importantes, pero por lo general estos son transparentes al usuario (son usadas en programas y sistemas operativos). Algunos de estos problemas incluyen:

compartir el mismo hardware entre varios programas dividiendo el hardware disponible,

permitir al software ser "portable" entre varios sistemas operativos, ejecutar viejo software en una computadora más nueva.

El término "virtual" ha evolucionado para describir casi cualquier cosa que sea una simulación de un objeto real, con términos como memoria virtual, discos virtuales, y realidad virtual. En el caso de las máquinas virtuales se desea que estas se vean y comporten exactamente como una máquina real. Esto significa que la máquina virtual no es realmente de hecho una máquina, pero se comporta exactamente como una verdadera.

Todas las máquinas tienen una cosa en común, ya sea un microondas, un refrigerador, una reproductora de video o una computadora; todas ellas están diseñadas para llevar a cabo ciertos tipos de conjuntos de instrucciones. Los conjuntos de instrucciones, pueden ser concebidos para cualquier máquina como piezas (como las de un rompecabezas o Lego) que al unirlas forman un objeto completo. Con las máquinas, estas piezas son instrucciones, las cuales son usadas para decirle a la máquina que hacer o que tareas realizar.

En el caso de las máquinas virtuales, lo virtual se refiere a los conjuntos de instrucciones. Hay muchos tipos de máquinas virtuales, pero lo común entre ellas es la idea de simular un conjunto de instrucciones. Cada máquina virtual usa un conjunto virtual de instrucciones al que el usuario tiene acceso, y después la máquina virtual "mapea" estas instrucciones virtuales a instrucciones reales de la computadora.

Hay cuatro corrientes principales en esta área:

a. La primera es un mapeo (casi) uno a uno (representado por el modelo de máquina virtual de IBM).

b. La segunda consiste de un mapeo de cada instrucción en la máquina con una instrucción virtual (representada por la máquina virtual de Java).

c. Los modelos de máquinas virtuales de Unix y OSI representan los últimos dos modelos, los cuales mapean algunas de las instrucciones directamente, y otras son llamadas directas a las funciones del sistema operativo.

Los modelos han sido utilizados para resolver problemas como: particionar una máquina (modelo IBM), crear una semi-plataforma independiente para lenguajes de programación (modelo Java), y crear sistemas operativos (modelo Unix y OSI).

El poder y éxito del concepto de la máquina virtual viene de brindar a los usuarios la habilidad de acceder y utilizar funciones y dispositivos que son simples combinaciones de conjuntos de instrucciones. La habilidad de proveer una solución virtual a las limitaciones reales de los sistemas de cómputo modernos es una herramienta muy poderosa que continua extendiendo las habilidades de los sistemas modernos.

3.3.1 El sistema P

⊕⊕⊕⊕

Un caso interesante relacionado a las máquinas virtuales es el sistema P, el cual está relacionado a RCOS, una de las plataformas de simulación de sistemas operativos que se analiza en las siguientes secciones.

El sistema P es un sistema operativo portable que fue popular en los primeros días de las computadoras personales, a fines de los 1970s y principios de los 1980s.

El sistema-P, como Java actualmente, estaba basado en una máquina virtual con un conjunto estándar de instrucciones de "código-p" (p-code es un lenguaje de máquina de bajo nivel para una máquina de pila hipotética llamada máquina-P, que es una imitación del conjunto de instrucciones de la Burroughs Large System) que eran emuladas en hardware diferente, incluyendo el 6502, el 8080, el Z-80, y el PDP-11. En esta forma, un compilador de Pascal que emitía ejecutables de código-p, podía producir programas que podían ejecutarse en los sistemas P en las Apple II, Xerox 820, o una DEC PDP-11.

El lenguaje más popular para el sistema P era el UCSD Pascal. De hecho, el sistema operativo del sistema P estaba escrito en UCSD Pascal, haciendo al SO relativamente fácil de portar entre plataformas. Al escribir un interprete de código P en el lenguaje ensamblador nativo de la plataforma y haciendo unos cuanto ajustes mínimos a las funciones del sistema operativo (sistemas de archivos e interacción con el usuario), era posible llevar ejecutables de un sistema y ejecutarlos en una nueva plataforma.

3.4 Plataformas de simulación de Sistemas Operativos

Al principio de este capitulo se mencionó que existen varios proyectos y enfoques en la simulación de sistemas operativos. Para comprender más a fondo como funcionan dichos modelos, se han incluido como casos de estudio:

a. Java Operating System Simulator b. NachOS

c. RCOS

A continuación se exponen brevemente las características de cada uno de estos simuladores.

3.4.1 Java Operating System Simulation

∇∇∇∇

Para tratar de responder a la pregunta "¿y cómo se implementa un servicio de planificación?" se presenta el Java Operating System Simulation (una aplicación hecha por Tony Teal que simula colas de planificación para procesos y dispositivos) para analizar cómo funciona la planificación de procesos.

Los archivos que lo conforman son:

 OSProcess.java Representación de una tarea del sistema.  OSQueue.java Representación de las colas ready y de E/S.  OSDevice.java Representación de un CPU o un dispositivo de E/S.  OSSystem.java Contiene 2 objetos Queue y 2 objetos Device.

Si se desean ver algunos detalles de bajo nivel como el intercambio de procesos, puede verse el apéndice "Caso de estudio: Implementación de un microkernel".

Hasta el momento se ha establecido que las principales entidades que deben implementarse son:

Procesos

Colas de procesos

Adicionalmente, puede incluirse a los dispositivos, pues como se mencionó hay procesos que pueden estar relacionados con el uso de los periféricos de la computadora.

Sea entonces un sistema que puede contener uno ó más dispositivos (tomando en cuenta al CPU como dispositivo), los cuales tienen asociada una cola de procesos. Cada cola puede implementar un algoritmo de planificación para administrar los procesos creados en el sistema. Aunque una decisión posible es implementar estas colas con estructuras de datos FIFO, el asunto es que dichas estructuras consumen memoria y no son la opción de implementación si lo que se desea es rendimiento y velocidad (además de que lo que deseamos ver es como lo hacen a bajo nivel)