Desarrollo de un paquete de programación del MC68000...

255
Desarrollo de un paquete de programación del MC68000 para un entorno Windows mediante C++ Builder. Creación de un editor de código y un macroensamblador AUTOR: Eloy Vilella Guiu DIRECTOR: Enrique Cantó Navarro FECHA: Abril 2004

Transcript of Desarrollo de un paquete de programación del MC68000...

Page 1: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

Desarrollo de un paquete de programación del MC68000 para un entorno Windows mediante C++ Builder.

Creación de un editor de código y un macroensamblador

AUTOR: Eloy Vilella Guiu DIRECTOR: Enrique Cantó Navarro

FECHA: Abril 2004

Page 2: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

2

ÍNDICE GENERAL:

1 INTRODUCCIÓN..................................................................................................................4

1.1 OBJETO DEL PROYECTO ............................................................................................4

1.2 TITULAR ..........................................................................................................................4

1.3 ANTECEDENTES ...........................................................................................................4

1.4 POSIBLES SOLUCIONES Y SOLUCIÓN ADOPTADA............................................5

2 MEMORIA DESCRIPTIVA................................................................................................8

2.1 INTRODUCCIÓN AL C++ BUILDER..........................................................................8

2.2 DESCRIPCIÓN GENERAL ..........................................................................................11

2.2.1 CORRECCIÓN DE BUGS DEL PROGRAMA ORIGINAL ............................11 2.2.1.0 Introducción: .............................................................................................11 2.2.1.1 Bugs corregidos: .......................................................................................11

2.2.2 ESTRUCTURA EN DLL’s ...................................................................................21 2.2.2.0 Introducción: .............................................................................................21 2.2.2.1 Definición de una DLL: ............................................................................21 2.2.2.2 Comunicación con la DLL: ......................................................................22 2.2.2.3 Creación de una aplicación con una estructura con DLL: ....................23

2.2.3 CREACIÓN DEL INTERFACE DE USUARIO.................................................25 2.2.3.0 Introducción: .............................................................................................25 2.2.3.1 Estructura principal:.................................................................................25 2.2.3.2 Creación del editor de texto .....................................................................29 2.2.3.3 Creación de la página ensamblador........................................................38 2.2.3.4 Creación de la página linkador................................................................44 2.2.3.5 Creación de la página proyecto ...............................................................46 2.2.3.6 Adaptación de tamaños: ...........................................................................60

2.2.4 MACROS ...............................................................................................................64 2.2.4.0 Introducción: .............................................................................................64 2.2.4.1 Concepto general:.....................................................................................64 2.2.4.2 Diseño estructural:....................................................................................64 2.2.4.3 Definicion:.................................................................................................65 2.2.4.4 Calling Method: ........................................................................................66 2.2.4.5 Argumentos:...............................................................................................66 2.2.4.6 Labels inside:.............................................................................................68

2.2.5 USO DEL REGISTRO DE WINDOWS ..............................................................71 2.2.5.0 Introducción: .............................................................................................71

Page 3: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

3

2.2.5.1 Estructura:.................................................................................................71 2.2.5.2 Acceso al registro: ....................................................................................72 2.2.5.3 Aplicación del registro en el macroensamblador:..................................77

2.2.6 DESCRIPCIÓN INTERNA DEL PROYECTO ..................................................79 2.2.6.1 Esquema del proyecto:..............................................................................79 2.2.6.2 Detallado de los ficheros:.........................................................................80 2.2.6.3 Descripción de las clases: ........................................................................87 2.2.6.4 Descripción de las funciones: ..................................................................95

3 CONCLUSIONES..............................................................................................................122

4 PLIEGO DE CONDICIONES .........................................................................................128

4.1. CONDICIONES GENERALES .................................................................................128

4.2 CONDICIONES ECONÓMICAS ...............................................................................132

4.3 CONDICIONES FACULTATIVAS ...........................................................................135

4.4 CONDICIONES TÉCNICAS ......................................................................................135

5 ANEXOS..............................................................................................................................136

5.1 CÓDIGO DEL PROGRAMA......................................................................................136

Page 4: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

4

1 INTRODUCCIÓN

1.1 OBJETO DEL PROYECTO

El objeto del presente proyecto es el desarrollo de un paquete de programación del

MC68000 de Motorola. Esto consiste en el diseño de un interface gráfico de usuario que debe integrar un editor de texto, un ensamblador y un linkador, además de tener acceso a los programas de simulación y de comunicaciones (ambos proyectos ajenos al presente). El interface, además, debe ser soportado por una plataforma Windows 9X, 2000... El programa ensamblador debe admitir el uso de macros.

1.2 TITULAR

El titular del presente proyecto es:

-Nombre: Escola Tècnica Superior d’Enginyeria (E.T.S.E.)

Universitat Rovira i Virgili

-Dirección: Av. Països Catalans, 26

Campus Sescelades

43007 Tarragona

Telf: 977559610

1.3 ANTECEDENTES

Hasta el momento en los laboratorios docentes del DEEEA se disponía de un Ensamblador y un Linkador (además de un simulador y un software de interface del PC con el módulo docente) que tan sólo eran soportados por el sistema operativo DOS. En proyectos anteriores se adaptaron los programas de simulación y de comunicaciones con éxito a la plataforma de Windows. En un último proyecto se trató de adaptar los programas ensamblador y linkador pero resultó un fracaso. Algunos de los problemas importantes que se encontraron fueron la falta de portabilidad del código, la multitud de bugs contenidos en el programa, la excesiva simplicidad del interface de usuario (operabilidad insuficiente), el caotismo y la falta de limpieza en la programación... Las funciones de entrada y salida fueron adaptadas a la plataforma de Windows, aunque el código no fue reciclado de la forma necesaria.

Page 5: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

5

1.4 POSIBLES SOLUCIONES Y SOLUCIÓN ADOPTADA

Inicialmente se optó por buscar programas robustos para iniciar el trabajo sobre

una base sólida. Se visitaron infinidad de websites de empresas importantes del sector y otras de recursos informáticos en la red, pero resultó imposible encontrar la versión freeware de algún cross assembler comercial y/o de calidad con los códigos fuente disponibles.

No hubo otra elección que basarse en el ensamblador y linkador usados en los

laboratorios del DEEEA adaptados a la plataforma de Windows en proyectos anteriores. La primera tarea fue realizar las adaptaciones necesarias a la versión y compilador utilizados (C++ Builder 5): la manera de pasar los argumentos a las funciones y la omisión del uso de variables long debido a que el sistema operativo sobre el que trabajaba el programa original era de 16 bits (DOS) cuando Windows es un SO de 32 bits. El problema se resume en: DOS: int = 16bits long int = 32bits

WIN: int = 32bits long int = 64bits (no lo usamos) Una segunda adaptación consistió en la eliminación de las directivas del lenguaje

C obsoletas. Muchas han sido modificadas por otras directivas más potentes en el lenguaje C++. La palabra clave malloc se utilizaba en C para reservar zonas de memoria de una forma dinámica, pero que podía causar graves problemas de colisiones en caso de un uso demasiado liviano con estructuras complejas. Toda estructura reservada en memoria con la palabra malloc debe ser eliminada mediante el uso de la directiva free y la inicialización del puntero utilizado. El C++ ha introducido las nuevas directivas new y delete que tienen una funcionalidad similar a las anteriormente mencionadas pero con una robustez y una potencia muy superior. Se ha tenido que sustituir las palabras malloc y free, además de adaptar el código relacionado, en los trozos de código donde se usan listas complejas o árboles binarios.

Se pudo reciclar poco del proyecto anteriormente mencionado. El interface de

usuario original fue desechado por su excesiva simplicidad y su falta de operabilidad, además hubo que trabajar la portabilidad de las funciones principales de los programas ensamblador y linkador.

El proceso seguido para optimizar el paquete de programación fue el siguiente:

1. Realizar adaptaciones necesarias a la versión y compilador utilizados (C++

Builder 5): sintaxis de las cabeceras de las funciones y omisión del uso de variables long.

2. Eliminar interface original.

Page 6: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

6

3. Eliminar los ficheros inútiles para la aplicación y limpiar el directorio de archivos de la antigua versión.

4. Tratar la portabilidad de las funciones principales del ensamblador y el linkador. 5. Estructurar , ordenar y limpiar el código original. 6. Tratar de entender el complejo funcionamiento del ensamblador y linkador.

7. Crear un interface temporal.

8. Corregir una infinidad de bugs del programa.

9. Diseñar el programa en una estructura con DLL (subdivisión de los ficheros en

carpetas).

10. Crear el interface definitivo.

11. Diseñar el editor de código.

12. Ampliar el programa a macroensamblador.

13. Adaptar aplicación al uso del Registro de Windows.

14. Creación de la herramienta de procesado de proyectos.

15. Redacción de la memoria definitiva del proyecto. El programa se ha diseñado, como se ha mencionado en la lista anterior, en una

estructura con DLL. El esqueleto de la aplicación es el siguiente:

Interface (Editor+Plataforma) àSimulador (exe)

àComunicaciones (exe)

⇔Ensamblador (dll)

⇔Linkador (dll)

Page 7: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

7

Figura 1 – Esqueleto de la aplicación

El paquete de programación debe ser capaz de procesar un fichero fuente de la

forma siguiente:

Figura 2 – Proceso general

Se podría haber realizado el proyecto con cualquier tipo de los diversos lenguajes

visuales para Windows existentes en el mercado, como por ejemplo el Visual C, Visual Basic... pero finalmente se ha optado por el C++ Builder de Borland por diversas razones, entre las que podemos destacar su gran potencia heredada del C, la posibilidad de programar en modo orientado a objetos (POO) como en C++ y, la última y más importante, debido a que facilita y ahorra mucho tiempo a la hora de programar, ya incluye clases creadas con lo cual se agiliza en gran medida la generación de código nuevo y complejo. En resumen, mediante C++ Builder se consigue una programación orientada a componentes (POC). Un componente es similar a una clase, pero además consta de propiedades y eventos. Cada componente nuevo de una clase existente en las librerías del compilador, genera una serie de expansiones de código que integran en el documento un componente plantilla. Con este proceso de standarización ahorra tiempo y esfuerzos para programar dichos objetos, lo cual suele ser bastante engorroso y complejo en lenguajes como C++.

Page 8: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

8

2 MEMORIA DESCRIPTIVA

2.1 INTRODUCCIÓN AL C++ BUILDER

A continuación se hace una breve introducción al lenguaje seleccionado finalmente

para realizar el proyecto. El C++ es una extensión o ampliación del lenguaje C y a diferencia de éste último,

permite programar en modo orientado a objetos. Anteriormente, la gran mayoría de las aplicaciones desarrolladas para Windows eran realizadas en lenguaje C, del mismo modo que las librerías de las funciones de las API. Sin embargo estas aplicaciones fueron construidas pensando en objetos, de forma que lo más conveniente era usar un interface basado en objetos, que realizara las llamadas a las API de Windows.

Con la finalidad de facilitar la programación orientada a objetos se crearon las

frameworks. Las framework son librerías que encapsulan las técnicas de programación más empleadas. Una aplicación basada en framework en comparación con otra que se basa directamente en llamadas a las API contiene menos código, con lo cual es más óptima desde un punto de vista temporal y es mucho más fácil de crear. Además el uso de MFC permite el uso de funciones de los lenguajes C o C++ y el uso directo de API.

Los frameworks para Windows que más se han extendido en la actualidad son el MFC (Microsoft), OWL (Borland) y VCL (Borland).

Las librerías VCL (Visual Component Library) son las que se han utilizado en este proyecto. Fueron desarrolladas originalmente para el compilador de Pascal de Borland, el Delphi. El nuevo compilador Borland C++ Builder incluye las VCL (además de poder compilar programas basados en OWL, MFC y Delphi). Este framework es el más avanzado ya que permite una auténtica programación visual C++ basada en componentes y formularios que pueden funcionar sin ficheros .dll adicionales. Además, permite la creación de aplicaciones de mediana complejidad para Windows en un tiempo relativamente corto.

A continuación se explicarán algunos de los nuevos conceptos (y otros no tan

nuevos) introducidos con la programación orientada a objetos. Se tratarán conceptos como clases, constructores y destructores entre otros. Éste es un tema bastante complejo pero se tratará de resumir y simplificar los conceptos (consúltese libro de programación C++ para más información):

a) Class ( clase): Se trata de una de las extensiones más importantes que se han

introducido con la programación orientada a objetos (POO). Es una wordkey con efectos muy similares a la palabra struct, pero con las siguientes diferencias:

Page 9: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

9

o En una estructura, los campos de datos y las funciones son públicos de modo predeterminado, lo que significa que se podrá acceder a los campos de datos sin restricciones.

o En una clase, son privados de modo predeterminado, lo que significa que sólo se pude acceder a los distintos campos por medio de ciertas funciones.

En definitiva, struct no asegura la protección de los campos. Pero la búsqueda de esta protección es una de las bases de la programación orientada a objetos. En el código anterior, los campos y funciones contenidos en la sección private no son accesibles directamente por el usuario de la clase. La función pública f puede ser llamada desde cualquier función del programa. Ésta es la única función que tiene acceso a la función privada g. Y sólo las funciones f y g pueden manipular los campos privados x e y.

b) Constructor: Un constructor permite que se ejecute automáticamente una

función de inicialización, llamada constructor, en la creación de un objeto perteneciente a una clase. El constructor también es llamado en la creación de un objeto con new.

c) Destructor: Una función destructor permite liberar zonas de memoria que

se han asignado dinámicamente (a menudo en el constructor) o bien cerrar un archivo abierto en el constructor. El destructor se llama también en la destrucción de un objeto con delete.

d) Puntero this: En una función miembro, this (palabra reservada del C++)

designa un puntero al objeto que se está tratando. This contiene la dirección de dicho objeto.

class CLS1 { private: int x; float y; void g();

public: void f(); }

Código 1

Page 10: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

10

e) La herencia: La técnica de la herencia constituye sin duda la aportación más interesante de la POO. Permite crear una clase a partir de otra, heredando propiedades de esta última. Se ha creado en primer lugar una clase A que sirve de base para crear otras clases (clase de base). La clase B se construye a partir de A (clase derivada). En este caso, los campos y funciones x, f, g y h de la clase A pasan a ser campos de la clase B.

o Los campos protected pueden ser accedidos desde B y sus derivadas.

o Los campos public pueden ser accedidos desde todo el programa.

o Los campos private no pueden ser accedidos. En caso de que la clase B se defina private de A, las palabras clave pasan a significar lo mismo pero anulando el acceso de las clases derivadas de B en todos los casos.

Class A { protected: int x; void f(); public: void g(); private: void h(); }

class B::public A { private:

int y; public: void j(); }

Código 2

Page 11: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

11

2.2 DESCRIPCIÓN GENERAL

2.2.1 CORRECCIÓN DE BUGS DEL PROGRAMA ORIGINAL

2.2.1.0 Introducción:

Los programas ensamblador y linkador originales contenían múltiples errores de programación. Tras solucionar los problemas de portabilidad del código y adaptar el programa original al lenguaje y versión utilizados, se hizo un trabajo importante para comprender el código y entender el método de trabajo de los programas. Cabe resaltar que un ensamblador y un linkador son programas muy complejos. En apartados anteriores se han añadido esquemas que han sido elaborados para simplificar este trabajo de comprensión. En el apartado siguiente se procede a explicar algunos de los bugs corregidos del programa original. Muchos han sido omitidos por su parecido o poco interés para el proyecto, y otros no han sido descubiertos todavía. Para su corrección se ha tenido que realizar un trabajo de localización (mucho código y muy complejo), entendimiento perfecto del código, comprensión del lenguaje ensamblador y posterior corrección del error. El bug aparentemente más simple puede ocasionar serios problemas en su corrección.

2.2.1.1 Bugs corregidos: (DDD: destino, FFF:fuente)

a) MOVEQ #0,D1 El nemónico moveq mueve un byte en modo direccionamiento inmediato a un registro de datos de 32 bits. El valor de 8 bits es extendido en signo en el registro de datos una vez transferido. Ensamblado general: 0111 DDD0 BBBB BBBB B:dato Ensamblado de la línea (anterior): 0111 0010 1000 0000 = 0x7280 Ensamblado de la línea (correcto): 0111 0010 0000 0000 = 0x7200 El problema estaba en que ensamblaba el dato #0 como 80 (cero negativo)

Page 12: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

12

b) CMPM.B (A0)+,(A1)+ El nemónico cmpm resta el operando origen del operando destino y actualiza los flags según el resultado. Los operandos se introducen siempre en modo de direccionamiento con postincremento. Ensamblado general: 1011 DDD1 AA00 1FFF A:size Ensamblado de la línea (anterior): 1011 0011 1000 1000 = 0xB388 Ensamblado de la línea (correcto): 1011 0011 0000 1000 = 0xB308 El problema estaba en que ensamblaba el size=10 (tamaño long), es decir, ensambla cmpm.l (a0)+,(a1)+ La función que codifica la size (mete los 1’s y 0’s) es: cmpm ( ) { if (size==2) valor+=64; //tratamiento .W else if (size==1) valor+=128; //tratamiento .L if (aa!=6 || bb!=6) RETURN (DIR_INCORR); return sp(valor+opp1.op<<9)+8+op1.op); }

La codificación interna del ensamblador es: .B >>> size=1 .W >>> size=2 .L >>> size=4 .S >>> size=8 nada >>> size=32 El error se encuentra en el else if (linea 2), debe entrar si size==4 (LONG)

c) DIVS.W D0,D2 y DIVS.L D0,D2 El nemónico divs divide el operando con signo destino por el operando con signo origen y almacena el resultado en el destino. La operación tiene 4 modos de trabajo según la sintaxis usada. Ensamblado general: 1000 DDD1 11MM MFFF M:modo direccionamiento de fuente Ensamblado de la línea (anterior): 1000 0101 1100 0000 = 0x85C0 Ensamblado de la línea (correcto): 1000 0101 1100 0000 = 0x85C0

Page 13: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

13

El error que nos muestra el ensamblador es “Error de tamaño incorrecto”. En realidad en la familia 68K no existe la opción .W/L en la operación DIVS. Se trata de un error de concepto del programador del código original.

d) CMPA.L A0,A1 y CMPA.W A0,A1

El nemónico cmpa resta el operando fuente del registro de direcciones destino y actualiza los flags según el resultado. Ensamblado general: 1011 DDDM MMFF FFFF M:modo direccionamiento de fuente El problema está en que la familia 68K no distingue entre W/L Solución: dependiendo de la variable size, codificará el modo de una forma u otra.

e) JMP L1 El ensamblador trataba este nemónico haciendo un salto relativo respecto al Program Counter (PC): 4EFA XXXX Existían problemas cuando la instrucción anterior era del tipo DC y ocupaba un número de bytes impares Solución: existe un bug posterior en el que luego resolveremos los problemas

de la directiva DC y la paridad del PC. Sin haberlo resuelto todavía, usaremos uno de los recursos de la instrucción JMP. Podemos codificarla para que haga el salto a una dirección absoluta (en lugar de relativa al PC):

4EF9 XXXX XXXX

Page 14: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

14

f) DC.B ...

El nemónico DC es una directiva del ensamblador usada para mapear datos en memoria. Ensamblado general: XXXX XXXX XXXX XXXX

X:carácter de la cadena Este nemónico tenía dos bugs diferentes: a) Cuando el número de caracteres de la cadena es impar, entonces el ensamblador

reserva un número impar de bytes (siguiente instrucción en zona impar). El ensamblador entonces llenaba los huecos libres con espacios y añadía otra línea en el fichero de listado con el formato: ‘xxxxxx : 00 :’. La solución adoptada es la de incrementar el Program Counter para que la siguiente instrucción se encuentre en posición par.

b) En las mismas condiciones del punto anterior, el ensamblador asigna a las 2

siguientes instrucciones al DC la misma posición de memoria. El problema viene por la línea añadida para tener un número de bytes par. La solución adoptada esta vez se basa en concatenar (cuando el número de caracteres es impar) la línea ensamblada con ‘00’ y rellenarla entonces los huecos libres con espacios. De esta manera, no hay necesidad de añadir una línea auxiliar al fichero listado.

g) Direccionamientos (d16,An) y (d8,An,Xn)

MOVE.B normalmente ensambla:

00SS DDDd ddff fFFF S: size (.B=01, .W=11, .L=10) D: reg d: modo direccionamiento F: reg f: modo direccionamiento

Según el direccionamiento, a veces se añade una palabra más (2 bytes = 4 hexa): a) (d16,An) XXXX XXXX XXXX XXXX (desplazamiento) b) (d8,An,Xn) ARRR S000 XXXX XXXX A: !A/D (An) R: reg (Xn)

S: size

Page 15: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

15

h) MOVE.B –3(A0),D1 (-3 se codifica en hexadecimal con FFFD)

Ensamblado de la línea (anterior): 0001 0010 0010 1000 = 0x1228 1111 1111 1111 1111 = 0xFFFF 1111 1111 1111 1101 = 0xFFFD >>> 1228 FFFF FFFD Ensamblado de la línea (correcto): 0001 0010 0010 1000 = 0x1228 1111 1111 1111 1101 = 0xFFFD

>>> 1228 FFFD Problema: Cuando el desplazamiento es negativo, el programa extiende el signo

a 32 bits (4 bytes). Por ello nos ensambla las dos palabras: la primera con el valor de 16 bits y la segunda con el signo extendido.

Solución: Cuando el desplazamiento sea negativo, recortamos una palabra del

valor del desplazamiento ensamblado antes de concatenarlo con la instrucción move ensamblada. Para corregirlo, accederemos a la función de la directiva DC y buscaremos el caso de direccionamiento aa=10 (línea 520 de Func.cpp)

Page 16: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

16

i) MOVE.B –3(A0,D3),D1 (-3 se codifica hexadecimal con FD)

Ensamblado de la línea (anterior): 0001 0010 0011 0000 = 0x1230 1111 1111 1111 1111 = 0xFFFF 0011 1111 1111 1101 = 0x3FFD >>> 1230 FFFF 3FFD Ensamblado de la línea (correcto): 0001 0010 0011 0000 = 0x1230 0011 0000 1111 1101 = 0x30FD

>>> 1230 30FD Problema 1: Mismo que en el caso anterior Solución: Se accede a la función de la directiva DC y se busca el caso de

direccionamiento aa=2 (línea 533 de Func.cpp) Problema 2: Si nos fijamos en el formato de la palabra añadida con este tipo de

direccionamiento, vemos que los 2 primeros bytes no deben extender el signo tampoco, ya que se usan para otros fines.

Solución: En un principio, simplemente preparaba la palabra (para escribirla en

el fichero listado) concatenando los carácteres ‘00’ con los 2 bytes útiles del desplazamiento (FFFF FFXX). Pero surgió un problema: simplemente superponía los carácteres ‘00’ a la información necesaria. La solución que se adoptó finalmente fue restarle al desplazamiento FFXX el valor equivalente a FF00

j) GLOBAL etiqueta Supongamos un código con la estructura siguiente:

global valor ... JMP valor ... valor ...

Page 17: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

17

El programa contenía un error en la función int valor(char *) del fichero parser.cpp que erraba en el tratamiento de la etiqueta de tipo global. El código de dicha función queda de la forma siguiente tras ser modificado:

static int valor (char *puntero) { struct arbol *r; r=buscar_rama(raiz,puntero); if (r != NULL) { reub=reub2; switch (r->tipodevariable) { case 0 : reub2=0; break; case 1 : reub2=1; break; case 2 : reub2=0; segpasadaparser=1; break; case 3 : if(segunda_pasada==2) longjmp(ebuf,16); break; case 4 : reub2=0; break; case 5 : reub2=1; break; } return r->valor; } if (segunda_pasada==2) longjmp(ebuf,16); reub2=0; if (codigoreub) reub2=1; return 0; }

Código 3

Page 18: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

18

j) Árboles binarios:

En el apartado referente a las macros se explica el procedimiento que sigue

el programa cuando encuentra una etiqueta de definición de macro del tipo macro. Se informa de que el programa crea una estructura del tipo árbol binario llamada arbolm para almacenar los objetos macro y rellenar los campos necesarios.

... Figura 3 – Árboles binarios

Otro caso de utilización de una estructura compleja como la anterior es en la

definición de etiquetas en el código fuente. Cuando el ensamblador encuentra la palabra clave ETI u otro sistema de definición de una etiqueta en el fichero asm, el programa crea un objeto del tipo arbol que corresponde al componente de un árbol binario. La definición del objeto arbol y el objeto arbolm es :

Para el manejo de una estructura del tipo árbol binario compuesta por

objetos de la clase arbol se utilizan punteros a objetos de dicha clase. Mediante una serie de funciones recursivos (funciones que son llamadas desde el interior de su propio código) el puntero recorre el árbol con un sistema “inteligente” para localizar el objeto buscado. La declaración de estas funciones pueden ser localizadas en el fichero ens.h:

struct arbol *buscar_rama (...); struct arbol *insarbol(...); void listar_arbol (...); void eliminar_rama(...); void eliminar_arbol (...);

struct arbol {

struct arbol *arbol_der; struct arbol *arbol_izq; char label[16]; int valor; int tipodevariable; };

struct arbolm { struct arbolm *arbol_der; struct arbolm *arbol_izq; char label[16]; AnsiString text; int llamadas; int argumentos; };

Código 5 Código 4

Código 6

Page 19: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

19

Las funciones siguientes son referentes a la estructura de árbol binario utilizada en el caso de la definición de macros. La declaración se puede encontrar en el fichero macros.h:

Todas las funciones referentes a los objetos tipo arbol (excepto

eliminar_arbol) fueron desarrolladas por el programador del ensamblador original. Sin embargo, el programa original procedía de forma incorrecta:

El código anterior son las últimas instrucciones ejecutadas para cualquier

fichero fuente en la DLL ensamblador. Una vez compilado el código fuente, se procede a cerrar los ficheros utilizados y se lanza una excepción. Podemos comprobar que no se libera la memoria reservada para los objetos de los árboles binarios ni se inicializan las variables globales puntero creadas en la cabecera del fichero ens68k.cpp. Las carencias anteriores nos provocan errores de ejecución del programa ensamblador en compilaciones posteriores y nos puede provocar problemas de memoria.

struct arbolm *buscar_rama (...); struct arbolm *insarbol(...); void listar_arbol (...); void eliminar_rama(...); void eliminar_arbol (...);

fin: //cerrar ficheros fclose(ff); fclose(fs); remove("..\\usuario\\xxx.xxx"); fclose(fd); if (flistado!=NULL) { flWrite(); fclose(fl); } //Falta recorrer los arboles de macros y etiquetas

y borrarlos punteros if (errores) { remove(fdestino); throw "ENS1"; } throw "ENS0"; }

Código 7

Código 8

Page 20: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

20

La solución adoptada fue desarrollar las funciones eliminar_arbol(arbol *) y eliminar_arbol(arbolm *). Estas funciones son algorismos recursivos que recorren el árbol hasta sus extremos y eliminan los componentes desde las ramas hasta la raiz de la estructura. El código en ambos casos sigue el siguiente esquema:

Las cinco funciones referentes a los objetos tipo arbolm han sido recicladas

y modificadas de sus respectivas referentes a arbol. El código puede ser consultado en el anexo de Código del Programa en el fichero arboles.cpp.

void eliminar_arbol (struct arbol *a) { if (!a) return; eliminar_arbol (a->arbol_izq); eliminar_arbol (a->arbol_der); delete(a); a=NULL; }

Código 9

Page 21: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

21

2.2.2 ESTRUCTURA EN DLL’s

2.2.2.0 Introducción:

El principal objetivo del proyecto ha sido crear una plataforma de trabajo donde se integren el editor, el ensamblador y el linkador. Una consecuencia directa ha sido la aparición de problemas en el orden y en la legibilidad del código. Puede resultar caótico tener varios programas complejos en una misma aplicación. La solución adoptada para resolver los problemas ha sido la estructuración de la plataforma en un diseño de programa principal y DLL’s.

Figura 4 – Estructura en DLL

2.2.2.1 Definición de una DLL:

DLL es una acrónimo de Dynamic Link Library (o librería de acceso dinámico). Se trata de un archivo que contiene funciones que se pueden llamar desde aplicaciones u otras DLL en tiempo de ejecución. Los desarrolladores utilizan las DLL para poder reciclar el código y aislar las diferentes tareas. Las DLL no pueden ejecutarse directamente, es necesario llamarlas desde un código externo.

Ventajas principales de las DLL:

• Las DLL nos ahorran espacio en disco. Si tenemos 501 aplicaciones y utlidades que utilizan la xxx.dll, montando ésta estáticamente en cada aplicación se incrementa el espacio utilizado en 500 veces el tamaño de la xxx.dll

• Las DLL ahorran memoria al utilizar un técnica de memoria compartida llamada "mapeo de memoria". Windows carga las DLL en la zona común global de memoria y mapea el rango de direcciones de la DLL en el espacio de direcciones de cada aplicación que hace la carga de dicha DLL. Por tanto,

Page 22: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

22

procesos diferentes que utilizan por ejemplo la xxx.dll, pueden compartir la misma instancia de la DLL en memoria sin necesidad de cargar copias de ella

• La localización de errores (bugs) es más sencilla debido a que un bug está

típicamente localizado en una única DLL. Por tanto no necesitamos redistribuir toda nuestra aplicación, sino únicamente la DLL errónea para solucionar un problema

Diferentes usos de las DLL:

• Enlace estático significa que se accede con una librería que contiene todos los OBJs necesarios. No es una DLL, sino una librería estática. La extensión suele ser .lib

• Enlace estático con una DLL significa que se accede con una librería import que contiene referencias a la DLL (nuestro caso)

• Cargar dinámicamente la DLL significa que debemos utilizar la función del API de Windows LoadLibrary

2.2.2.2 Comunicación con la DLL:

Como se ha definido anteriormente, las DLL representan paquetes ejecutables (EXE’s complejos), así que no se pueden pasar argumentos tan fácilmente como en el caso de las funciones. La comunicación más importante entre el interface y las DLL son el paso de argumentos en las llamadas a las funciones principales de las DLL y los mensajes que devuelven las DLL mientras analizan el código y que deben ser mostrados al usuario mediante el interface.

La parte de las llamadas se resolvió mediante la declaración de las funciones Ens68K(...) y Lnk68K(...) como IMPORT/EXPORT en el fichero .h de las DLL. No se puede interactuar con los objetos del formulario principal directamente desde un archivo de la DLL (informa de un linker error). Simplemente, debo tratar los datos puestos en el formulario antes de ejecutar la DLL correspondiente, pasando los datos necesarios a la DLL como argumentos:

a) DLL ensamblador: se pasan el nombre de los archivos asm, obj y lst y la ruta de usuario

b) DLL linkador: se pasa el nombre de cada archivo obj, si éste es absoluto o reubicable, el origen/fin (caso absoluto), y el nombre de los s28 y map y la ruta de usuario

La parte de los mensajes es algo más compleja. Los mensajes no se pueden enviar

en tiempo real, ya que se debería cortar la ejecución de la DLL cada vez, cosa dificil y poco práctica. La solución adoptada al problema ha sido crear una variable del tipo

Page 23: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

23

AnsiString (este tipo se encarga de reservar zonas de memoria según el tamaño de la variable en tiempo de ejecución, además de proporcionar otra información como el tamaño...). Durante la ejecución de la DLL, cuando se debía enviar el mensaje pertinente, ahora se acumula en esta variable. Cuando se acaba la ejecución total de la DLL (ensamblado o linkado), entonces se llama desde el interface a una función creada previamente que imprime el contenido de la variable en el lugar adecuado. Pueden existir varias variables simultáneamente debido a que existen mensajes de salida y de errores.

2.2.2.3 Creación de una aplicación con una estructura con DLL:

a) Creación de un proyecto normal (intefens.bpr) en la carpeta interface desde el que se llamará a las funciones principales de las DLL. El proyecto estará formado por interfens.bpr+cpp (proyecto) y Principal.cpp+dfm+h (ventana principal). • En el archivo de llamada a las DLL’s (Principal.cpp) se incluyen (#include)

los archivos .h de las DLL (ensdll.h y lnkdll.h) • Se deben adherir al proyecto interfens los archivos de librerías de las DLL

(ensdll.lib y lnkdll.lib)

b) Creación de otro proyecto con “Dll Wizard” (opción de creación) llamado ensdll.brp en la carpeta ensamblador (contiene todos los archivos importantes del ensamblador). Este proyecto contiene básicamente ensdll.brp+cpp+h (proyecto) y demás archivos importantes para ensamblador (*.cpp y *.h) contenidos en la carpeta

c) Creación de la DLL del linkador de la misma forma que la anterior

d) Edición especial de los archivos .h de la DLL (ejemplo ensamblador):

#ifndef ensdllH

#define ensdllH

#ifdef __DLL__ #define EXPORT_IMPORT __declspec(dllexport) #define interfens "dllexport" #else #define EXPORT_IMPORT __declspec(dllimport) #define interfens "dllimport" #endif

EXPORT_IMPORT declaración de función/es principal/es de

Dll (accesible desde el exterior) #endif

Código 10

Page 24: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

25

2.2.3 CREACIÓN DEL INTERFACE DE USUARIO

2.2.3.0 Introducción:

El diseño y creación de la plataforma interface de usuario ha sido la parte del proyecto que más libertad ha permitido al proyectista. Tras el trabajo de creatividad de la estructura básica del formulario se ha efectuado la labor de programación (especialmente difícil puesto que se trata de mi primera experiencia con la POO –Programación Orientada a Objetos-) para plasmar la idea en el programa.

2.2.3.1 Estructura principal:

Figura 5 – Pantalla principal

El formulario principal de la aplicación se compone de un menú principal y de dos

frames. El frame de la parte izquierda se denomina frame de selección y sirve para especificar el programa que queremos visualizar. El nombre del frame de la parte derecha es frame de visualización.

Page 25: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

26

El menú principal es un objeto de la clase TMainMenu. Un menú está casi siempre asociado a una aplicación. Aparece en la barra de menú, que se encuentra directamente bajo la barra de título del formulario. Un ítem de menú puede activar un submenú, llamado popup en inglés. Existe una herramienta de creción de menú en C++ Builder que nos permite diseñar el esqueleto de una manera bastante visual. Se crea un nuevo objeto de la clase TItemMenu por cada opción añadida al menú. Podemos tratar el evento OnClick de los objetos TItemMenu para especificar la función de la opción seleccionada. El menú principal se subdivide de la siguiente manera: Menú à Programas àEditor

àEns68K àLnk68K àSimulador àITF àProyecto àOpciones àRuta de Usuario àSalir

El submenú programas resume el frame de selección en una lista sin imágenes. Los eventos OnClick de dichas opciones coinciden con los eventos de los botones del frame de selección. Por lo tanto, ambos elementos tienen el mismo efecto en la aplicación.

La opción Ruta de Usuario abre un formulario diálogo para que el usuario

especifique la ruta (o directorio) de trabajo de todos los programas. Dicha información se almacena en la base de datos Registry de Windows.

Figura 6 – Diálogo de Ruta de Usuario

Para crear el diálogo de la figura anterior se ha creado un nuevo formulario, es

decir, un objeto de la clase TForm. Los archivos RutaDlg.cpp, RutaDlg.h y RutaDlg.dfm contienen toda la información referente al nuevo formulario. Se han añadido los sigiuentes componentes para su diseño: TLabel (etiqueta), TButton (botones) y TComboBox (lista combo). El código que representa las funciones de Aceptar Aceptar y Cancelar es el siguiente:

Page 26: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

27

El programa actualiza el valor “HKEY_CURRENT_USER\\SOFTWARE\\TM683\\Ruta”

del registro de Windows con la cadena de caracteres especificada en el objeto TComboBox si la opción seleccionada es Ok. En caso contrario, el programa restaura el texto del objeto TComboBox con la cadena de caracteres almacenada en el valor anteriormente definido y no modifica el base de datos de registro. La opción Salir cierra la aplicación.

El frame de selección está compuesto por cinco botones y sus respectivas imágenes.

El código que representa sus funciones es el siguiente:

void __fastcall TRutaDialog::RutaBOkClick(TObject *Sender) { TRegistry *Registro = new TRegistry; Ruta=RutaDialog->RutaCombo->Text; try { Registro->RootKey = HKEY_CURRENT_USER; Registro->OpenKey("\\SOFTWARE\\TM683",true); Registro->WriteString("Ruta",Ruta); } __finally { delete Registro; } RutaCombo->Items->Add(Ruta); Interf_form->OpenDialog->InitialDir=Ruta; Interf_form->SaveDialog->InitialDir=Ruta; RutaDialog->Hide(); Interf_form->Enabled=True; } void __fastcall TRutaDialog::RutaBCancelClick(TObject *Sender) { TRegistry *Registro = new TRegistry; try { Registro->RootKey = HKEY_CURRENT_USER; Registro->OpenKey("\\SOFTWARE\\TM683",true); RutaCombo->Text=Registro->ReadString("Ruta"); } __finally { delete Registro; } RutaDialog->Hide(); Interf_form->Enabled=True; } Código 11

Page 27: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

28

Los tres primeros botones modifican la propiedad PageIndex del objeto TNoteBook

que será explicado posteriormente. El efecto es la visualización de los programas Editor, Ensamblador y Linkador respectivamente en el frame de visualización. Los dos últimos botones llaman a la función del API de Windows spawnlp que abre un nuevo formulario con el programa especificado como argumento. El primer argumento puede contener los siguientes valores entre otros: P_WAIT o P_NOWAIT (indican si el formulario padre debe esperar a que el hijo finalice o no)

El frame de visualización se compone básicamente de un objeto de la clase

TNoteBook. Los componentes NoteBook, también llamados clasificadores, implementan varias páginas que se recubren. Una página está asociada generalmente a una pestaña (botón en nuestro caso). Una página, como una ventana, puede contener cualquier componente. Accionando sobre la propiedad Pages del componente se accede a la herramienta editor de páginas que ayuda al programador a crear y ordenar las páginas deseadas de una forma visual. Después de su creación, las páginas deben ser diseñadas individualmente de forma similar a un formulario.

//Click en boton BEditorClick. Presenta la pagina del editor. void __fastcall TInterf_form::BEditorClick(TObject *Sender) { Paginas->PageIndex=1; } //Click en boton BPag_EnsClick. Presenta la pagina del ensamblador. void __fastcall TInterf_form::BPag_EnsClick(TObject *Sender) { Paginas->PageIndex=2; } //Click en boton BPag_LnkClick. Presenta la pagina del linkador. void __fastcall TInterf_form::BPag_LnkClick(TObject *Sender)

{ Paginas->PageIndex=3; } //Click en boton BPag_SimClick. Ejecuta el programa Simulador. void __fastcall TInterf_form::BPag_SimClick(TObject *Sender) {

spawnlp(P_WAIT,"..\\Interface\\Programs\\Simulador.exe",".. \\Interface\\Programs\\Simulador.exe",NULL);

} //Click en boton BPag_ComClick. Ejecuta el programa Comunicador. void __fastcall TInterf_form::BPag_ComClick(TObject *Sender) { spawnlp(P_WAIT,"..\\Interface\\Programs\\WinItf68K.exe",".. \\Interface\\Programs\\WinItf68K.exe",NULL);

}

Código 12

Page 28: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

29

2.2.3.2 Creación del editor de texto

..0 Introducción:

En un paquete como el TM683, que realiza todas las funciones necesarias para trabajar con el chip 68000 de Motorola, debe existir un editor que nos permita la creación y modificación de los diferentes ficheros relacionados en el proceso de una forma cómoda. Este programa realiza un tratamiento personalizado de los ficheros fuente y listado (ambos relacionados con el usuario del paquete).

..1 Diseño: La pantalla del editor está dividida en dos partes:

a) La parte superior la componen una serie de botones de la clase TButton integrados en un panel de la clase TPanel. Desde este panel se llaman a las funciones principales del editor.

b) La parte inferior se trata de un objeto de la clase TPageControl. Este tipo

de objeto se trata de un administrador de múltiples páginas. Se controla mediante la interacción con las pestañas de la parte inferior. Se ha creado una nueva clase llamada TEditASM para la creación y actualización del contenido de las páginas múltiples. La definición de la nueva clase es:

La clase está formada básicamente por su constructor y destructor, dos punteros a los objetos de las clases TRichEdit y TTabSheet, y varios métodos que serán explicados en apartados posteriores. Cada objeto TRichEdit se trata de un editor complejo de texto y ocupa las múltiples ventanas del administrador, mientras que el objeto TTabSheet relaciona cada ventana con su pestaña correspondiente.

class TEditASM { private: void TestLinea(int); public: TEditASM(TPageControl*); ~TEditASM(); TRichEdit *Edit; TTabSheet *Hoja; void EditColor(); void CursorPoint();

void __fastcall EditKey(TObject *Sender, WORD &Key, TShiftState Shift);

void __fastcall EditMouse(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);

};

Código 13

Page 29: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

30

El resultado visual de lo anteriormente explicado puede apreciarse en la figura siguiente:

Figura 7 – Página editor

..2 Personalización del código fuente:

La función EditColor( ) trabaja sobre el editor de la clase TRichEdit seleccionado y da un formato determinado a su texto. Este proceso es llamado desde las funciones BOpenClick, BSaveClick y BColorClick que responden a las acciones de accionar sobre los botones de Abrir, Guardar y Arreglar del panel. El código de la función principal de este proceso es el siguiente:

void TEditASM::EditColor(void) { int Pos; Pos=Edit->SelStart; Edit->SelStart=0; Edit->SelLength=Edit->Text.Length(); Edit->SelAttributes->Style=TFontStyles(); Edit->SelAttributes->Color=clBlack; Edit->SelStart=Pos; for(int i=1;i<=Edit->Lines->Count;i++) { TestLinea(i);

Page 30: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

31

El programa inicializa algunas propiedades del objeto TRichEdit para tratar el texto. Un bucle recorre el texto línea por línea y llama a la función TestLinea. Se trata de una función que mediante un largo y complejo proceso pone en negrita las palabras clave del lenguaje ensamblador y pone en color azul los comentarios.

* Consultar el código de la función TestLinea(...) en el archivo edit.cpp (demasiado largo para extenderlo en este apartado).

El programa recorre todos los caracteres de la línea hasta que se encuentra con algo

diferente a un símbolo de tabulación o espaciado. Entonces distingue si se trata de el inicio de un comentario. En caso afirmativo selecciona el texto desde el símbolo de inicio de comentario hasta el final de la línea y cambia su formato de color. En caso negativo se selecciona la palabra entera (hasta que encuentra un símbolo de espaciado, puntuación...) y comprueba si se trata de un nemónico del lenguaje. La comprobación se realiza recorriendo una tabla de nemónicos y comparando strings. En caso afirmativo se modifica el formato de la palabra seleccionada a negrita. En caso negativo se continúa con el programa. Se repite el proceso para cada una de las palabras de la línea. Y se trata de forma especial la última palabra de cada línea. Además, se repite el bucle entero para cada línea como se ha visto en el código de la función EditColor( ).

..3 Acciones principales del editor:

Las lista siguiente resume las acciones del editor. Cada acción viene representada por uno de los botones del panel del editor.

a) Nuevo Documento b) Abrir Documento c) Guardar Documento d) Cerrar Documento e) Arreglar Código f) Imprimir Documento

* Recuérdese que el editor trabaja con la ruta especificada en el registro de Windows

Edit->SelStart+=2; } Edit->SelStart=Pos;

} Código 14

Page 31: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

32

..3.1 Nuevo Documento:

El código ejecutado cuando se acciona el botón de Nuevo Documento es el siguiente:

El programa crea un objeto de la nueva clase TEditASM, forzando así la ejecución

del constructor de la clase contenido en el fichero edit.cpp. En el constructor se crean los objetos TTabSheet y TRichEdit mencionados en apartados anteriores, y se inicializan las propiedades correspondientes de ambos objetos. Entonces se especifica la nueva página como activa y se introduce el objeto TEditASM en la lista del tipo TList, que almacena todos los objetos TEditASM creados para su posterior tratamiento.

..3.2 Abrir Documento:

El código ejecutado cuando se acciona el botón de Abrir Documento es el siguiente:

editasm=new TEditASM(Ed_Pags); Ed_Pags->ActivePage=editasm->Hoja; Lista_Ed->Add(editasm); nlinea->Caption="0";

FILE *file; char caracter; AnsiString line; if (OpenDialog->Execute())

{ editasm=new TEditASM (Ed_Pags); Ed_Pags->ActivePage=editasm->Hoja; Lista_Ed->Add(editasm); AnsiString &a=OpenDialog->FileName; char *fname=new char[a.Length()+1]; strcpy(fname,a.c_str()); file=fopen(fname,"r"); caracter=fgetc(file); while(caracter!=EOF) { line=""; while((caracter!='\n')&&(caracter!=EOF)) { line+=caracter;

caracter=fgetc(file); } editasm->Edit->Lines->Add(line); caracter=fgetc(file); } fclose(file); int b=a.LastDelimiter("\\:" ); editasm->Hoja->Caption=a.c_str()+b; editasm->EditColor(); nlinea->Caption="0"; } Código 15

Page 32: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

33

Figura 8 – Diálogo de apertura de documento

El programa ejecuta el OpenDialog para que el usuario especifique la ruta y el archivo que desea abrir. Entonces crea un nuevo documento como en el apartado anterior. Abre el fichero especificado por el usuario en modo lectura y trata el contenido del archivo de texto. Mientras el puntero al fichero no encuentra un EOF (end of file) el programa procede a leer un carácter del fichero y lo añade en una variable del tipo AnsiString. Cuando el puntero encuentra un símbolo de retorno de carro ‘\n’ el programa añade el objeto AnsiString al objeto TRichEdit en forma de lista de líneas de texto e inicia el bucle de nuevo. Cuando el puntero encuentra el EOF, el programa cierra el fichero de texto y ejecuta la función EditColor( ) explicada en apartados anteriores.

..3.3 Guardar Documento:

El código ejecutado cuando se acciona el botón de Guardar Documento es el siguiente:

int p=Ed_Pags->ActivePage->PageIndex; editasm=(TEditASM*)Lista_Ed->Items[p]; editasm->Edit->PlainText=true; if(SaveDialog->Execute())

{ AnsiString &a=SaveDialog->FileName; if (!a.AnsiPos(".")) { switch(SaveDialog->FilterIndex) { case 1: a+=".txt";break; case 2: a+=".asm";break; case 3: a+=".obj";break; case 4: a+=".lst";break; } } char *fname=new char[a.Length()+1];

Page 33: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

34

El programa “extrae” de la lista de objetos TEditASM la pareja de objetos TRichEdit y TTabSheet activos en el administrador de múltiples páginas. Entonces ejecuta el SaveDialog donde el usuario especifica el nombre del archivo y la ruta:

Figura 9 – Diálogo de guardar de documento

El programa abre el fichero especificado (con la extensión adecuada) en modo escritura y ejecuta un bucle donde se copia el texto del documento al fichero línea por línea. Entonces se cierra el fichero y se inicializan las propiedades del texto del TRichEdit. Al final se llama a la función EditColor para dar el formato adecuado al texto.

strcpy(fname,a.c_str()); file=fopen(fname,"w"); for(i=0;i<=editasm->Edit->Lines->Count;i++) { AnsiString &s=editasm->Edit->Lines->Strings[i]; char *line=new char[s.Length()+1]; strcpy(line,s.c_str()); fprintf(file,"%s\n",line); } fclose(file); int b=a.LastDelimiter("\\:" ); editasm->Hoja->Caption=a.c_str()+b; editasm->Edit->PlainText=false; editasm->Edit->SelStart=0; editasm->Edit->SelLength=editasm->Edit->Text.Length(); editasm->Edit->SelAttributes->Color=clBlack; editasm->Edit->SelAttributes->Style=TFontStyles(); editasm->EditColor(); nlinea->Caption="0"; }

Código 16

Page 34: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

35

..3.4 Cerrar Documento:

El código ejecutado cuando se acciona el botón de Cerrar Documento es el siguiente:

El programa comprueba que existe algún documento abierto. Entonces selecciona el documento activo y lo borra de la lista de objetos TEditASM. Para eliminar los huecos que el borrado produce ejecuta el método Pack( ) de la clase TList. Cuando borra el objeto TEditASM de la lista, el programa ejecuta el destructor de la clase que simplemente elimina la pareja de objetos TRichEdit y TTabSheet para liberar la memoria.

..3.5 Arreglar Documento: Llama a la función EditColor analizada en el apartado ..2.

..3.6 Imprimir Documento: Se ejecuta el diálogo de impresión. Éste solamente nos proporciona la información que necesitamos de una forma ordenada y estructurada en un objeto de clase TPrintDialog.

Figura 10

if (Lista_Ed->Count) { int p=Ed_Pags->ActivePage->PageIndex; delete (TEditASM*)Lista_Ed->Items[p]; Lista_Ed->Delete(p); Lista_Ed->Pack(); Lista_Ed->Capacity=Lista_Ed->Count; nlinea->Caption="0"; }

Código 17

Page 35: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

36

La función global Printer( ) devuelve un puntero a un objeto de la clase TPrinter que da acceso a las características y a los métodos de impresión de la impresora activa. La clase TPrinter contiene una propiedad llamada Canvas de la clase TCanvas que a su vez contiene una propiedad llamada Font. Ésta permite la modificación del tipo, tamaño y color de la fuente. Código utilizado para la impresión:

//Boton Imprimir. void __fastcall TInterf_form::BPrintClick(TObject *Sender) { if(Lista_Ed->Count) { int p=Ed_Pags->ActivePage->PageIndex; editasm=(TEditASM*)Lista_Ed->Items[p]; editasm->Edit->PlainText=true; PrintDialog->Execute(); Printer()->BeginDoc(); Printer()->Canvas->Font->Name="Courier New"; Printer()->Canvas->Font->Size=12; int i,j=0; AnsiString Pag; Pag=IntToStr(Printer()->PageNumber); Printer()->Canvas->TextOutA(2500,62*100,Pag.c_str()); for(i=0;i<=editasm->Edit->Lines->Count;i++) { j++; if (j>60) { j=1; Printer()->NewPage(); Pag=IntToStr(Printer()->PageNumber); Printer()->Canvas->TextOutA(2500,62*100,Pag.c_str()); } AnsiString &s=editasm->Edit->Lines->Strings[i]; int a=s.AnsiPos("\t"); while (a) { s.Delete(a,1); s.Insert(" ",a); a=s.AnsiPos("\t"); } char *line=new char[s.Length()+1]; strcpy(line,s.c_str()); Printer()->Canvas->TextOutA(100,j*100,line); } Printer()->EndDoc(); editasm->Edit->PlainText=false; } }

Código 18

Page 36: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

37

Existen diferentes problemas derivados del uso de la función Printer( ). Ésta función global comunica a las aplicaciones de Windows con el software relacionado a la impresora, es decir, con los drivers. Los controladores de la impresora no reconocen los símbolos de tabulación ni retorno de carro como lo hacen los editores de texto convencionales. La solución adoptada ha sido tratar el texto para la impresión línea a línea. El programa contabiliza el número de líneas recorridas (introduciendo saltos de página cuando sea necesario), recorre el texto en busca de símbolos de tabulación (que sustituye por los caracteres correspondientes) y añade las líneas tratadas al documento de impresión. Cuando el programa no encuentra más líneas en el texto, se llama a la función Printer( )àEndDoc( ), que indica el final de la configuración de impresión y envía el documento a la impresora.

Page 37: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

38

2.2.3.3 Creación de la página ensamblador

Figura 11 – Página ensamblador

La función principal de esta página es facilitar la comunicación entre la DLL ensamblador y el usuario de la aplicación. Por ello, la página se divide en dos secciones diferentes: sección de entrada de datos y sección de salida de datos. En la primera el usuario introduce el nombre de los ficheros fuente, objeto y listado en los objetos de la clase TEdit. Cuando se pulsa el botón Ensamblar el programa concatena esas cadenas de caracteres con la ruta de usuario almacenada en la base de datos Registro de Windows y las pasa como argumentos a la DLL. El código que representa el evento OnClick sobre el botón Ensamblar es el siguiente:

void __fastcall TInterf_form::Ens_buttonClick(TObject *Sender) { flag=0; char *aux1=new char[100]; strcpy(aux1,Ruta.c_str()); char *aux2=new char[100]; strcpy(aux2,Ruta.c_str()); char *aux3=new char[100]; strcpy(aux3,Ruta.c_str());

Page 38: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

39

La sección de salida de datos está compuesta por dos componentes parecidos pero diferentes: un objeto TRichEdit para los mensajes de ensamblador y un objeto TListBox para los mensajes de error. El objeto TRichEdit visualiza mensajes de error en la ubicación de los ficheros así como información sobre el proceso de ensamblaje. El texto puede ser tratado como un bloque uniforme, por ello se ha optado por el uso de un objeto de la clase TRichEdit. El objeto TListBox visualiza los diferentes mensajes de error cometidos en el código del archivo fuente. El interface está diseñado para responder a un doble-click con el mouse sobre un mensaje de error determinado visualizando la línea errónea del fichero determinado en el editor de código (el programa visualiza el fichero listado para un reconocimiento del error más cómodo). Por lo tanto, los mensajes de error son tratados

AnsiString &edit1=Interf_form->asm_edit->Text; char *fich_asm=new char[edit1.Length()+1];

strcpy(fich_asm,edit1.c_str()); fich_asm=strcat(aux1,fich_asm);

AnsiString &edit2=Interf_form->obj_edit->Text; char *fich_obj=new char[edit2.Length()+1]; strcpy(fich_obj,edit2.c_str()); fich_obj=strcat(aux2,fich_obj); AnsiString &edit3=Interf_form->lst_edit->Text; char *fich_lst=new char[edit3.Length()+1]; strcpy(fich_lst,edit3.c_str()); fich_lst=strcat(aux3,fich_lst); try { Ens68K(fich_asm,fich_obj,fich_lst); } catch(...) { AnsiString msgErrAnsi,msgErrLine; int pos=0; char *msg=Ens68K_Mensaje(); Interf_form->EnsMns->Text=msg; char *msgErr=Ens68K_MensajeErr(); msgErrAnsi.printf("%s",msgErr); pos=msgErrAnsi.Pos('\n'); while (pos>1) { msgErrLine=msgErrAnsi.SubString(1,pos-1); msgErrAnsi.Delete(1,pos);

EnsErr->Items->Add(msgErrLine); pos=msgErrAnsi.Pos('\n');

} } }

Código 19

Page 39: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

40

individualmente como líneas en una lista, por ello se ha optado por el uso de un objeto de la clase TListBox. El código que representa el evento OnDblClick sobre un elemento de la ListBox es el siguiente:

Page 40: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

41

void __fastcall TInterf_form::EnsErrDblClick(TObject *Sender) { int i=EnsErr->ItemIndex;

if (i<=EnsErr->Items->Count) { AnsiString line1=EnsErr->Items->Strings[i]; AnsiString numstring=line1; numstring.Delete(1,14);

numstring.Delete(6,1000); int num=numstring.ToInt(); AnsiString filestring=line1; filestring.Delete(1,24); int j=filestring.AnsiPos("'"); filestring.Delete(j,1000); j=line1.AnsiPos(">>>"); line1.Delete(1,j+3); j=line1.AnsiPos("\t"); line1.Delete(j,1000); while(line1[line1.Length()]==' ') line1.SetLength(line1.Length()-1); //si archivo no abierto-->abrir int i=filestring.LastDelimiter("\\");

filestring.Delete(1,i); i=filestring.LastDelimiter("."); filestring.Delete(i,9999); filestring+=".LST"; int found=0; i=0; while((!found)&&(i<Lista_Ed->Count))

{ editasm=(TEditASM*)Lista_Ed->Items[i];

if(filestring.AnsiCompareIC(editasm->Hoja->Caption)==0) found++; else { i++; } } //abrir if(!found) { FILE *file; char caracter; AnsiString line; Paginas->PageIndex=1; editasm=new TEditASM (Ed_Pags); Ed_Pags->ActivePage=editasm->Hoja; Lista_Ed->Add(editasm);

filestring=Ruta+filestring;

Page 41: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

42

AnsiString &a=filestring; char *fname=new char[a.Length()+1]; strcpy(fname,a.c_str()); file=fopen(fname,"r"); if(file!=NULL) { caracter=fgetc(file); while(caracter!=EOF) { line=""; while ((caracter!='\n')&&(caracter!=EOF))

{ line+=caracter; caracter=fgetc(file); } editasm->Edit->Lines->Add(line); caracter=fgetc(file); } fclose(file); int b=a.LastDelimiter("\\:" ); editasm->Hoja->Caption=a.c_str()+b; editasm->EditColor(); } } else //archivo ya abierto { editasm=(TEditASM*)Lista_Ed->Items[i]; Paginas->PageIndex=1; Ed_Pags->ActivePage=editasm->Hoja; } //seleccionamos la linea determinada AnsiString Texto=editasm->Edit->Text; int a=1; char caracter1=' '; int num_lst=0; while(num_lst!=num) { while(caracter1!='\n') { caracter1=Texto[a]; a++; } caracter1=Texto[a++]; AnsiString Auxcar; Auxcar=caracter1; if(Auxcar.IsDelimiter("0123456789",1)) { int x=1; caracter1=Texto[a++];

Page 42: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

43

Código 20

while((caracter1!=' ')&&(caracter1!=':')) { Auxcar+=caracter1; caracter1=Texto[a++]; } num_lst=Auxcar.ToInt(); } } editasm->Edit->SelStart=a; a=0; while(caracter1!='\n') { caracter1=Texto[editasm->Edit->SelStart+a]; a++; } editasm->Edit->SelLength=a-1; nlinea->Caption=num; } }

Page 43: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

44

2.2.3.4 Creación de la página linkador

Figura 12 – Página linkador

La función principal de esta página es facilitar la comunicación entre la DLL

linkador y el usuario de la aplicación. Por ello, la página se divide en dos secciones diferentes: sección de entrada de datos y sección de salida de datos.

En la sección de entrada de datos el usuario introduce los nombres de los archivos

objeto y el campo de dirección de memoria opcional en una lista. Se pueden eliminar los elementos de la lista de forma individual o colectiva mediante la pulsación de un botón en la pantalla. Cuando el usuario acciona el botón Linkar Proyecto el programa procede con la ejecución del código siguiente:

Page 44: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

45

El programa prepara un array de 20 punteros a carácter. Llama a la función

arg_lnk(...) que prepara los argumentos para ser pasados a la DLL. Entonces llama a la función de la DLL Lnk68K(...) y pasa como argumentos el número de ficheros objeto en la lista, el array de punteros con los ficheros objeto ordenados, los nombres de los ficheros destino (s28 y map) y la ruta de usuario almacenada en el Registro de Windows.

Cuando programa acaba de ejecutar la DLL visualiza los mensajes de linkaje y error

en sus respectivos componentes. Se trata de objetos de la clase TRichEdit puesto que el usuario no puede interactuar con los mensajes.

void __fastcall TInterf_form::lin_buttonClick(TObject *Sender) { int n_objs,a; char *array_objs[20]; char *path=new char[100]; strcpy(path,Ruta.c_str()); if(Lista_arch->Items->Count) { Interf_form->LnkMns->Clear(); Interf_form->LnkErr->Clear(); for (a=0;a<20;a++) array_objs[a]=NULL; arg_lnk(n_objs,array_objs); //mando puntero a int try

{ Lnk68K(n_objs,array_objs,Interf_form->s28_edit-

>Text.c_str(),Interf_form->map_edit- >Text.c_str(),path);

} catch(...) { char *msg=Lnk68K_Mensaje(); Interf_form->LnkMns->Text=msg; char *msgErr=Lnk68K_MensajeErr(); Interf_form->LnkErr->Text=msgErr; } arg_lnk(array_objs); } }

Código 21

Page 45: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

46

2.2.3.5 Creación de la página proyecto

Figura 13 – Página proyecto

La función principal de esta página es la de facilitar el trabajo con proyectos complejos. Mediante unas simples indicaciones es posible crear un fichero de proyecto (.prj) que permite el ensamblado y el linkado de todos los ficheros fuente con dos simples acciones del ratón.

La página de proyecto está dividida en tres partes importantes: el panel de edición

(primera tercera parte de la página), el panel de acción (botones intermedios) y la ventana de visualización (parte inferior de la página).

El panel de edición resume la entrada de las páginas ensamblador y linkador en un

mismo panel. El componente más importante de este panel es el objeto de la clase TListBox situado en el centro del panel. Este componente tiene un funcionamiento bastante intuitivo (gracias al diseño del entorno visual). Un proyecto está formado por una lista de x ficheros fuente (asm) que son compilados en sus respectivos x ficheros objeto (obj) en la posición de memoria especificada por el usuario o el código. Los tres campos mencionados son representados por los tres objetos de las clase TEdit situados a la izquierda de la lista. El formato visual de la lista es el siguente:

Page 46: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

47

Figura 14 – Detalle del objeto TListBox de entrada

La acción del mouse sobre el objeto TButton con el texto Añadir creará una línea

con el formato anterior, con la única condición de que los campos Text de los objetos TEdit contengan un valor diferente a nulo (el campo dirección de memoria es opcional). Los botones Borrar y Borrar Lista tienen el mismo modo de funcionamiento que sus equivalentes en la página linkador. Los objetos TEdit situados a la derecha de la TListBox corresponden a los nombres de los ficheros de salida de la DLL linkador (s28 y map). Estos componentes deben tener algún valor diferente a nulo en el campo Text para proceder a ensamblar y/o linkar el fichero proyecto.

El panel de acción es un objeto de la clase TPanel que engloba las funciones

principales de la página proyecto. Se compone de cuatro botones de la clase TBitBtn y de un objeto de la clase TEdit. El campo Text de este último componente contiene el objeto AnsiString que almacena el nombre del fichero proyecto (prj) sobre el que repercuten las acciones realizadas por el usuario. Los cuatro botones corresponden a las siguientes funciones:

a) Guardar Proyecto b) Cargar Proyecto c) Ensamblar Proyecto d) Linkar Proyecto

Page 47: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

48

a) Guardar Proyecto:

El código ejecutado cuando se acciona el botón Guardar Proyecto es el siguiente:

void __fastcall TInterf_form::Prj_BSaveClick(TObject *Sender) { Proyecto=new TPrjClass(Interf_form); Proyecto->Guardar(); delete(Proyecto); }

void TPrjClass::Guardar() { if (Interf_form->Prj_prj->Text.Length()!=0) { //llena el objeto de la clase TPrjClass con datos de pantalla prj_file=Interf_form->Prj_prj->Text; s28_file=Interf_form->Prj_s28->Text; map_file=Interf_form->Prj_map->Text; n_elems=Interf_form->Prj_list->Items->Count; for(int i=1;i<=n_elems;i++) { AnsiString &linea=Interf_form->Prj_list->Items->Strings[i-1]; char *aux=new char[linea.Length()+1]; strcpy(aux,linea.c_str()); elems[i-1]=aux; } if(!prj_file.AnsiPos(".")) prj_file+=".prj"; if(!s28_file.AnsiPos(".")) s28_file+=".s28"; if(!map_file.AnsiPos(".")) map_file+=".map"; //prepara texto de fichero .prj

AnsiString Text; Text=prj_file+AnsiString("\n")+s28_file+AnsiString("\n")+map_file

+AnsiString("\n")+n_elems+AnsiString("\n"); for(int i=0;i<n_elems;i++) { AnsiString linea; linea.printf("%s",elems[i]); Text+=linea+AnsiString("\n"); } //crea fichero .prj AnsiString filename; filename=Ruta+prj_file; FILE *fprj; fprj=fopen(filename.c_str(),"w");

Page 48: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

49

La función guardar tiene como objetivo tomar los datos que el usuario ha

introducido en los componentes del panel de edición y crear un fichero de proyecto (prj) con un formato determinado. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

El programa crea un objeto de la clase TPrjClass con la directiva de C++ llamada

new. Este objeto se elimina y la zona de memoria reservada se libera al final del proceso de almacenamiento. La definición de la clase TPrjClass es la siguiente:

Un objeto de la clase TPrjClass posee un constructor y un destructor (como todas las clases) en este caso vacíos, además de las cuatro funciones públicas que se corresponden con las acciones de los cuatro botones del panel de acción. El objeto también posee una serie de campos que almacenan la información contenida en el panel de edición. Estos campos se resumen en tres variables de la clase AnsiString que equivalen a los nombres de los ficheros de salida del proyecto (s28, map, prj), además de una variable entera que indica el número de ficheros fuente de entrada al proyecto y

class TPrjClass {

private: public:

TPrjClass(TComponent* Owner); ~TPrjClass(); char *elems[30]; int n_elems; AnsiString s28_file; AnsiString map_file; AnsiString prj_file; void Guardar(); void Cargar(); void Ensamblar(); void Linkar(); };

//llena fichero con texto fprintf(fprj,"%s",Text.c_str()); //acabar AnsiString Text2; Text2=AnsiString("Fichero de proyecto creado correctamente:

")+filename; Interf_form->Prj_Mensajes->Text=Text2; fclose(fprj); }//if }

Código 22

Código 23

Page 49: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

50

un array de 30 punteros a carácter que apuntan a las cadenas de caracteres resultantes de la TListBox.

Inicialmente, el programa llena el objeto de la clase TPrjClass con los datos

contenidos en el panel de edición. Además añade la extensión a los ficheros de salida del proyecto (s28, map, prj) en el caso que fuera necesario. La extensión de los ficheros fuente (asm) y objeto (obj) será tratada en el código de las DLL.

Posteriormente, el programa crea y edita una variable de la clase AnsiString para

que contenga la información de una forma ordenada y con un formato específico. El tratamiento de la información se generaliza con este proceso. Se crea y se abre el fichero de proyecto en modo escritura con la siguiente línea:

fprj=fopen(filename.c_str(),"w"); El programa actualiza el contenido del fichero con la variable AnsiString

anteriormente preparada. El formato interno del fichero de proyecto creado es el siguiente:

proyecto1.prj proyecto1.s28 proyecto1.map 6 file1 file1 024000 file2 file2 024500 file3 file3 025000 file4 file4 025500 file_libs file_libs 030000 file_end file_end 040000

Código 24

Page 50: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

51

b) Cargar Proyecto:

El código ejecutado cuando se acciona el botón Guardar Proyecto es el siguiente:

void TPrjClass::Cargar() { if (Interf_form->Prj_prj->Text.Length()!=0) { LimpiarPantalla(); //abre el fichero .prj especificado en pantalla FILE *fprj; AnsiString filename; filename=Ruta+Interf_form->Prj_prj->Text; if (filename.AnsiPos(".")<3) filename+=".prj"; if((fprj=fopen(filename.c_str(),"r"))==NULL) Interf_form->Prj_Mensajes->Text=AnsiString("El fichero de

proyecto '")+filename+AnsiString("' no existe"); else { //rellena pantalla con datos de fichero char c='\0';int i=1; AnsiString Linea=""; c=getc(fprj); while(c!=EOF) { while((c!='\n')&&(c!='\r')) { Linea+=c; c=getc(fprj); } switch (i) { case 1: Interf_form->Prj_prj->Text=Linea; break; case 2: Interf_form->Prj_s28->Text=Linea; break; case 3: Interf_form->Prj_map->Text=Linea; break; case 4: break; default: Interf_form->Prj_list->Items->Add(Linea); } Linea=""; i++; c=getc(fprj); } //acabar AnsiString Text2;

Page 51: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

52

La función cargar tiene como objetivo recuperar los datos que el usuario ha

almacenado en un fichero de proyecto (prj) y actualizar con esa información los componentes del panel de edición. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

Inicialmente, el programa llama a la función LimpiarPantalla( ). El objetivo es

borrar los campos Text de los componentes TEdit del panel de edición, limpiar el contenido del objeto TRichEdit llamado ventana de visualización y vaciar la lista TListBox. El código ejecutado en esta función es el siguiente:

Posteriormente, el programa abre el fichero de proyecto especificado en el campo Text del objeto TEdit en el panel de acción en modo lectura con la línea siguiente:

fprj=fopen(filename.c_str(),"r") Se realiza una comprobación de la extensión del fichero en prevención de posibles errores del usuario. En el caso de que el fichero de proyecto especificado no exista, el programa presenta el mensaje de error pertinente por la ventana de visualización. En caso contrario se procede con la ejecución del resto del código de la función. En caso de correcta apertura del fichero de proyecto, el programa actualiza los campos de los componentes del panel de edición con los datos del fichero de proyecto. El puntero de fichero recorre el contenido del archivo secuencialmente de inicio a fin. En función de la línea en que se encuentre y mediante el uso de una estructura de tipo switch el programa se encarga de actualizar el campo del componente determinado. Alcanzado el símbolo EOF (end of file) por el puntero de fichero, el programa presenta el mensaje pertinente por la ventana de visualización y cierra el fichero de proyecto.

Text2=AnsiString("Fichero de proyecto cargado correctamente: ")+filename;

Interf_form->Prj_Mensajes->Text=Text2; fclose(fprj); } } }

void LimpiarPantalla() { Interf_form->Prj_Mensajes->Clear(); Interf_form->Prj_list->Clear(); Interf_form->Prj_asm->Clear(); Interf_form->Prj_obj->Clear(); Interf_form->Prj_dir->Clear(); Interf_form->Prj_s28->Clear(); Interf_form->Prj_map->Clear(); }

Código 25

Page 52: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

53

c) Ensamblar Proyecto: El código ejecutado cuando se acciona el botón Guardar Proyecto es el siguiente:

void TPrjClass::Ensamblar() { if (Interf_form->Prj_prj->Text.Length()!=0) { //carga fichero de proyecto especificado Cargar(); //llena el objeto de la clase TPrjClass con datos de pantalla n_elems=Interf_form->Prj_list->Items->Count; for(int i=1;i<=n_elems;i++) { AnsiString &linea=Interf_form->Prj_list->Items->Strings[i-

1]; char *aux=new char[linea.Length()+1]; strcpy(aux,linea.c_str()); elems[i-1]=aux; } //ensambla ficheros .asm for(int i=0;i<n_elems;i++) { //prepara nombres ficheros .asm y .obj AnsiString Linea; Linea.printf("%s",elems[i]); AnsiString f_asm; AnsiString f_obj; AnsiString f_lst; int x; x=Linea.AnsiPos("\t"); f_asm=Ruta+Linea.SubString(1,x-1); Linea.Delete(1,x); x=Linea.AnsiPos("\t"); if(x!=0) Linea.Delete(x,99999); f_obj=Ruta+Linea; f_lst=f_obj; if(f_asm.AnsiPos(".")<3) f_asm+=AnsiString(".asm"); if(f_obj.AnsiPos(".")<3) f_obj+=AnsiString(".obj"); if(f_lst.AnsiPos(".")<3) f_lst+=AnsiString(".lst"); char *fich_asm=new char[f_asm.Length()+1]; strcpy(fich_asm,f_asm.c_str()); char *fich_obj=new char[f_obj.Length()+1]; strcpy(fich_obj,f_obj.c_str()); char *fich_lst=new char[f_lst.Length()+1]; strcpy(fich_lst,f_lst.c_str()); //llama a ensamblar el fichero try { Ens68K(fich_asm,fich_obj,fich_lst); }

Page 53: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

54

La función ensamblar tiene como objetivo recuperar los datos que el usuario ha

almacenado en un fichero de proyecto (prj), actualizar con esa información los

catch(char *a) { if(strcmp(a,"ENS0")==0) { AnsiString LineaMens; LineaMens=AnsiString("\nFichero fuente

'")+f_asm+AnsiString("' ensamblado correctamente en '")+f_obj+AnsiString("'");

Interf_form->Prj_Mensajes->Lines->Add(LineaMens); Interf_form->Prj_Mensajes->Lines->Add(" "); } else if(strcmp(a,"ENS1")==0) { AnsiString LineaMens; LineaMens=AnsiString("\nFichero fuente

'")+f_asm+AnsiString("' ensamblado incorrectamente por errores en el proceso o por no existencia del fichero fuente");

Interf_form->Prj_Mensajes->Lines->Add(LineaMens); Interf_form->Prj_Mensajes->Lines->Add(" "); int ini=Interf_form->Prj_Mensajes->Text.Length(); AnsiString msgErrAnsi,msgErrLine; int pos=0; char *msgErr=Ens68K_MensajeErr(); msgErrAnsi.printf("%s",msgErr); pos=msgErrAnsi.Pos('\n'); while (pos>1) { msgErrLine=msgErrAnsi.SubString(1,pos-1); msgErrAnsi.Delete(1,pos); Interf_form->Prj_Mensajes->Lines->Add(msgErrLine); pos=msgErrAnsi.Pos('\n'); } Interf_form->Prj_Mensajes->SelStart=ini; Interf_form->Prj_Mensajes->SelLength=Interf_form-

>Prj_Mensajes->Text.Length()-ini; Interf_form->Prj_Mensajes->SelAttributes->Color=clRed; Interf_form->Prj_Mensajes->SelStart=Interf_form-

>Prj_Mensajes->Text.Length(); Interf_form->Prj_Mensajes->SelAttributes->Color=clBlack; Interf_form->Prj_Mensajes->SelLength=1; }//else if } //acabar delete[] fich_asm; delete[] fich_obj; delete[] fich_lst; } } }

Código 26

Page 54: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

55

componentes del panel de edición y ensamblar los ficheros fuente en los ficheros objeto especificados por el usuario. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

Inicialmente, el programa llama a la función Cargar( ). El objetivo es actualizar los

campos Text de los componentes TEdit del panel de edición, limpiar el contenido del objeto TRichEdit llamado ventana de visualización y actualizar la lista TListBox con los datos contenidos en el fichero de proyecto especificado en el panel de acción. También actualiza los campos del objeto de la clase TPrjClass creado en la función TInterf_form::Prj_BOpenClick(TObject *Sender).

El programa entra en una estructura bucle del tipo for en el que tratará de igual

forma a todas las líneas del array de 30 punteros a carácter. El proceso es el siguiente:

• Copia la cadena de caracteres apuntada por el puntero del array en el campo Text de una variable AnsiString. Separa el nombre del fichero fuente (asm) y del fichero objeto (obj). Realiza una comprobación de la extensión de los ficheros de entrada y salida de la DLL ensamblador (asm, obj y lst).

• Llama a la función principal de la DLL ensamblador con la línea siguiente

dentro de una estructura try: Ens68K(fich_asm,fich_obj,fich_lst);

• Realiza un tratamiento específico para cada posible excepción dentro de una estructura catch:

a) ENS0: presenta un mensaje de fichero ensamblado correctamente

en la ventana de visualización. b) ENS1: presenta un mensaje de fichero ensamblado incorrecta-

mente en la ventana de visualización. Presenta, además, los errores cometidos en color clRed.

Una vez tratadas todas las cadenas de caracteres y ensamblados todos los ficheros

fuente del proyecto, el programa termina la ejecución de la función liberando con la palabra clave delete todas las zonas de memoria reservadas con new.

Page 55: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

56

d) Linkar Proyecto:

El código ejecutado cuando se acciona el botón Guardar Proyecto es el siguiente:

void TPrjClass::Linkar() { if (Interf_form->Prj_prj->Text.Length()!=0) { //carga fichero de proyecto especificado Cargar(); //llena el objeto de la clase TPrjClass con datos de pantalla prj_file=Interf_form->Prj_prj->Text; s28_file=Interf_form->Prj_s28->Text; map_file=Interf_form->Prj_map->Text; n_elems=Interf_form->Prj_list->Items->Count; if(n_elems>20) { AnsiString LineaMens; LineaMens=AnsiString("\nEl fichero de proyecto se compone de

")+n_elems+AnsiString("ficheros objeto (max: 20)"); Interf_form->Prj_Mensajes->Text=LineaMens; } else { for(int i=1;i<=n_elems;i++) { AnsiString &linea=Interf_form->Prj_list->Items->Strings[i-

1]; char *aux=new char[linea.Length()+1]; strcpy(aux,linea.c_str()); elems[i-1]=aux; } //prepara array de ficheros .obj y las direcciones int n_objs=n_elems; char *array_objs[20]; for(int k=0;k<20;k++) array_objs[k]=NULL; char *path=new char[100]; strcpy(path,Ruta.c_str()); for(int i=0;i<n_elems;i++) { AnsiString Linea; Linea.printf("%s",elems[i]); AnsiString f_obj; int x; x=Linea.AnsiPos("\t"); Linea.Delete(1,x); x=Linea.AnsiPos("\t"); if(x!=0) { f_obj=Linea.SubString(1,x-1); Linea.Delete(1,x); f_obj+=AnsiString("@")+Linea; }

Page 56: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

57

else f_obj=Linea; char *faux_obj=new char[f_obj.Length()+1]; strcpy(faux_obj,f_obj.c_str()); array_objs[i]=faux_obj; } char *f_s28=new char[s28_file.Length()+1]; strcpy(f_s28,s28_file.c_str()); char *f_map=new char[map_file.Length()+1]; strcpy(f_map,map_file.c_str()); //llama a linkar el proyecto try { Lnk68K(n_objs,array_objs,f_s28,f_map,path); } catch(char *a) { if(strcmp(a,"ENS0")==0) { AnsiString LineaMens; LineaMens=AnsiString("\nFichero de proyecto linkado

correctamente"); Interf_form->Prj_Mensajes->Lines->Add(LineaMens); Interf_form->Prj_Mensajes->Lines->Add(" "); } else if((strcmp(a,"ENS1")==0)||(strcmp(a,"ENS2")==0)) { AnsiString LineaMens; LineaMens=AnsiString("\nDetención del proceso de linkado

por aparición de errores en alguno de los ficheros objeto");

Interf_form->Prj_Mensajes->Lines->Add(LineaMens); Interf_form->Prj_Mensajes->Lines->Add(" "); } else if(strcmp(a,"LNK3")==0) { AnsiString LineaMens; LineaMens=AnsiString("\nDetención del proceso de linkado

por problemas de reubicabilidad en alguno de los ficheros objeto");

Interf_form->Prj_Mensajes->Lines->Add(LineaMens); Interf_form->Prj_Mensajes->Lines->Add(" "); } AnsiString msgAnsi,msgErrAnsi; char *msg=Lnk68K_Mensaje(); msgAnsi.printf("%s",msg); Interf_form->Prj_Mensajes->Lines->Add(msgAnsi); char *msgErr=Lnk68K_MensajeErr(); msgErrAnsi.printf("%s",msgErr); Interf_form->Prj_Mensajes->Lines->Add(msgErrAnsi); }

Page 57: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

58

La función linkar tiene como objetivo recuperar los datos que el usuario ha

almacenado en un fichero de proyecto (prj), actualizar con esa información los componentes del panel de edición y linkar los ficheros objeto en los ficheros s28 y map especificados por el usuario. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

Inicialmente, el programa llama a la función Cargar( ). El objetivo es actualizar los

campos Text de los componentes TEdit del panel de edición, limpiar el contenido del objeto TRichEdit llamado ventana de visualización y actualizar la lista TListBox con los datos contenidos en el fichero de proyecto especificado en el panel de acción. También actualiza los campos del objeto de la clase TPrjClass creado en la función TInterf_form::Prj_BEnsClick(TObject *Sender). Recuérdese que una de las limitaciones del programa linkador es que el número máximo de ficheros objeto que pueden componer un proyecto es 20. Limitación también aplicable a los ficheros de proyecto.

Posteriormente, el programa procede a preparar el argumento principal de la DLL

linkador: un array de 20 punteros a carácter. Cada pointer apunta al inicio de una cadena de caracteres que contiene el nombre de un fichero objeto y la dirección en un formato específico. El formato de la cadena es el siguiente:

“ruta_usuario+nombre_obj+@+dir_memoria”

La ruta de usuario se obtiene del registro de Windows como se ha explicado en apartados posteriores. El símbolo @ seguido de la dirección de memoria en hexadecimal es de carácter opcional, es decir, solamente aparecerá en caso que el usuario especifique una dirección de memoria durante la creación del proyecto. La extensión de los ficheros objeto será tratada en el interior de la DLL. El programa llama a la función principal de la DLL linkador mediante la ejecución de la línea siguiente, donde path es un puntero a la ruta de usuario:

Lnk68K(n_objs,array_objs,f_s28,f_map,path);

//acabar delete[] path; int j=0; while(array_objs[j]!=NULL) delete array_objs[j++]; }//else }//if }

Código 27

Page 58: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

59

Realiza un tratamiento específico para cada posible excepción dentro de una estructura catch:

a) ENS0: presenta un mensaje de fichero de proyecto linkado correctamente en la ventana de visualización.

b) ENS1 y ENS2: presenta un mensaje de fichero de proyecto linkado incorrectamente (por aparición de errores en alguno de los ficheros objeto) en la ventana de visualización.

c) LNK3: presenta un mensaje de fichero de proyecto linkado incorrectamente (por errores de reubicabilidad en alguno de los ficheros objeto) en la ventana de visualización.

El programa presenta en todos los casos los errores cometidos y termina la ejecución de la función liberando con la palabra clave delete todas las zonas de memoria reservadas con new.

Page 59: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

60

2.2.3.6 Adaptación de tamaños:

El aspecto visual del interface de usuario es un handicap importante en el desarrollo de un programa complejo como el presente proyecto. El usuario debe ser capaz de tener una visibilidad y un manejo correcto de todos los componentes en todo momento.

La posible diversidad en el tamaño y resolución de las pantallas utilizadas para

trabajar con el paquete de programación presente es la razón principal de este apartado. Actualmente, cualquier ordenador personal tiene una resolución mínima de 1024 por 768 píxeles, alcanzando valores superiores a 1600 por 1200 píxeles. Por otra parte, las pantallas de las computadoras de los laboratorios del DEEEA tienen una resolución máxima de 800 por 600 píxeles. Cualquier entorno visual desarrollado en un ordenador actual debe tener un sistema de adaptación del tamaño del formulario principal y de los componentes al tamaño de la pantalla.

El sistema diseñado se basa en la edición del evento FormResize y del constructor

de la clase TInterf_form. Estas funciones ejecutan su código tras el cambio de tamaño y la creación del formulario principal respectivamente. El código de ambas funciones es parecido al siguiente:

if ((Interf_form->Width<700)||(Interf_form->Height<500)) { if(Interf_form->Width<700) Interf_form->Width=700; if(Interf_form->Height<500) Interf_form->Height=500; } else { //TAMAÑOS Y CONFIGURACIONES //Principal PanelB->Width=0.15*Interf_form->Width; PanelB->Width=0.15*Interf_form->Width; BEditor->Width=0.64*Interf_form->PanelB->Width; BPag_Ens->Width=0.64*Interf_form->PanelB->Width; BPag_Sim->Width=0.64*Interf_form->PanelB->Width; BPag_Lnk->Width=0.64*Interf_form->PanelB->Width; BPag_Com->Width=0.64*Interf_form->PanelB->Width; BPag_Prj->Width=0.64*Interf_form->PanelB->Width; BEditor->Height=PanelB->Height/6*0.70; BPag_Ens->Height=PanelB->Height/6*0.70; BPag_Sim->Height=PanelB->Height/6*0.70; BPag_Lnk->Height=PanelB->Height/6*0.70; BPag_Com->Height=PanelB->Height/6*0.70; BPag_Prj->Height=PanelB->Height/6*0.70; BEditor->Left=(PanelB->Width/2)-BEditor->Width/2; BPag_Ens->Left=BEditor->Left; BPag_Lnk->Left=BEditor->Left; BPag_Sim->Left=BEditor->Left; BPag_Com->Left=BEditor->Left; BPag_Prj->Left=BEditor->Left;

Page 60: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

61

BEditor->Top=(PanelB->Height/6)*0+PanelB->Height/6*0.15; BPag_Ens->Top=(PanelB->Height/6)*1+PanelB->Height/6*0.15; BPag_Lnk->Top=(PanelB->Height/6)*2+PanelB->Height/6*0.15; BPag_Sim->Top=(PanelB->Height/6)*3+PanelB->Height/6*0.15; BPag_Com->Top=(PanelB->Height/6)*4+PanelB->Height/6*0.15; BPag_Prj->Top=(PanelB->Height/6)*5+PanelB->Height/6*0.15; //Editor Linea->Left=BPrint->Left+BPrint->Width+90; nlinea->Left=Linea->Left+Linea->Width+5; //Proyecto Prj_panel->Width=Interf_form->Paginas->Width; Prj_Mensajes->Width=Interf_form->Paginas->Width-20; int aux=Prj_panel->Top+Interf_form->Prj_panel->Height; Prj_Mensajes->Top=aux+10; Prj_Mensajes->Height=Interf_form->Paginas->Height-aux-20; Prj_Mensajes->Left=10; aux=Paginas->Width-(Label15->Left+Label15->Width+10); Prj_asm->Width+=aux/3; Prj_obj->Width+=aux/3; Prj_dir->Width+=aux/3; Prj_list->Width+=aux/3; Prj_s28->Width+=aux/3; Prj_map->Width+=aux/3; Label14->Left=Prj_asm->Left+Prj_asm->Width+2; Label13->Left=Label14->Left; Label17->Left=Label14->Left; Image9->Left=Label14->Left+Label14->Width+4; Prj_add->Left=Image9->Left+Image9->Width+4; Image10->Left=Prj_add->Left+Prj_add->Width+4; Prj_list->Left=Image10->Left+Image10->Width+4; Label8->Left=Prj_list->Left; Image12->Left=Prj_list->Left+Prj_list->Width+4; Image13->Left=Image12->Left; Prj_s28->Left=Image12->Left+Image12->Width+4; Prj_map->Left=Prj_s28->Left; Label16->Left=Prj_s28->Left+Prj_s28->Width+2; Label15->Left=Label16->Left; Prj_del->Left=Image13->Left+Image13->Width+4; Prj_delall->Left=Prj_del->Left; Image14->Left=Prj_del->Left+Prj_del->Width+4; //Linkador LnkMns->Left=20; LnkErr->Left=20; LnkMns->Top=(PanelLnk->Height)+25; LnkErr->Top=PanelLnk->Height+((Paginas->Height-PanelLnk-

>Height)/2+25); LnkMns->Width=Interf_form->Paginas->Width-40; LnkErr->Width=Interf_form->Paginas->Width-40; LnkMns->Height=(Paginas->Height-PanelLnk->Height)/2-40; LnkErr->Height=(Paginas->Height-PanelLnk->Height)/2-40; Label9->Top=Interf_form->LnkMns->Top-15; Label10->Top=Interf_form->LnkErr->Top-15;

Page 61: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

62

El programa realiza un control del tamaño al inicio del programa, imponiendo un tamaño mínimo del formulario en 700 por 500 píxeles. Un tamaño menor podría disminuir problemáticamente la visibilidad de los componentes y el manejo del programa. Luego, el programa procede a actualizar los tamaños de los componentes importantes en función del tamaño del formulario principal. Algunos componentes modifican su tamaño, otros

Label9->Left=Interf_form->LnkMns->Left+Interf_form->LnkMns- >Width-150;

Label10->Left=Interf_form->LnkErr->Left+Interf_form->LnkErr- >Width-135;

aux=Paginas->Width-(Label5->Left+Label5->Width+10); obj_lnk->Width+=aux/3; obj_direcc->Width+=aux/3; Lista_arch->Width+=aux/3; s28_edit->Width+=aux/3; map_edit->Width+=aux/3; Label6->Left=obj_lnk->Left+obj_lnk->Width+2; Label7->Left=obj_lnk->Left+obj_lnk->Width+2; Arrow4->Left=Label6->Left+Label6->Width+4; Button_add->Left=Arrow4->Left+Arrow4->Width+4; Arrow6->Left=Button_add->Left+Button_add->Width+4; Lista_arch->Left=Arrow6->Left+Arrow6->Width+4; Arrow7->Left=Lista_arch->Left+Lista_arch->Width+4; Arrow10->Left=Arrow7->Left; lin_button->Left=Arrow7->Left+Arrow7->Width+4; Button_del->Left=lin_button->Left; Button_All->Left=lin_button->Left; Image6->Left=Button_del->Left+Button_All->Width+4; Arrow8->Left=lin_button->Left+lin_button->Width+4; s28_edit->Left=Arrow8->Left+Arrow8->Width+4; map_edit->Left=Arrow8->Left+Arrow8->Width+4; Label4->Left=s28_edit->Left+s28_edit->Width+2; Label5->Left=Label4->Left; //Ensamblador EnsMns->Left=20; EnsErr->Left=20; EnsMns->Top=(PanelEns->Height)+25; EnsErr->Top=PanelEns->Height+((Paginas->Height-PanelEns-

>Height)/2+25); EnsMns->Width=Interf_form->Paginas->Width-40; EnsErr->Width=Interf_form->Paginas->Width-40; EnsMns->Height=(Paginas->Height-PanelEns->Height)/2-40; EnsErr->Height=(Paginas->Height-PanelEns->Height)/2-40; Label11->Top=Interf_form->EnsMns->Top-15; Label12->Top=Interf_form->EnsErr->Top-15; Label11->Left=Interf_form->EnsMns->Left+Interf_form->LnkMns-

>Width-185; Label12->Left=Interf_form->EnsErr->Left+Interf_form->LnkErr-

>Width-170; } Código 28

Page 62: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

63

simplemente se recolocan en el formulario en función de la posición de otros componentes. En definitiva, todos los componentes tienen un tamaño y una posición relativa, en algunos casos relativa al formulario principal y en otros relativa a otros componentes. La estructura principal de la pantalla se reparte de la forma siguiente:

a) El frame de selección es una columna que ocupa el 15% del ancho del formulario principal. Los botones tienen un tamaño y una posición proporcional al ancho del frame.

b) El frame de visualización ocupa el 85% restante. c) El menú principal de la aplicación es una línea de poco grosor que ocupa la

parte directamente inferior al head (cabecera) del formulario.

La parte superior de la página editor (botones) tiene un tamaño y posicion fija. Los únicos componentes que se adaptan al tamaño del formulario son: el objeto TPageControl que adapta su tamaño al espacio libre y el objeto TLabel linea que adapta su posición horizontal al tamaño del formulario para ser visible en todo momento. Los componentes de la parte superior de la página ensamblador están contenidos en un objeto TPanel de altura constante. La escasa cantidad de componentes en esta parte de la página ha hecho que el control de tamaño mínimo del formulario realizado al inicio de la función permita la visibilidad de los componentes en todo momento. Los objetos TRichEdit y TListBox que se encargan de la visualización de los mensajes en la parte inferior de la página se reparten el espacio restante dejando unos márgenes a su alrededor. La estructura visual de los componentes de la parte superior de la página linkador debe ser constante, es decir, deben conformar un dibujo determinado en todo momento. Todos ellos están contenidos en un objeto TPanel de altura constante también. Los componentes obj_lnk, obj_direcc, Lista_arch, s28_edit y map_edit se reparten el valor de los incrementos (o decrementos) del ancho del formulario principal previamente calculado. Los demás componentes del panel se recolocan en función de la posición y tamaño de estos objetos principales. Los objetos TRichEdit que se encargan de la visualización de los mensajes en la parte inferior de la página se reparten el espacio restante dejando unos márgenes a su alrededor. La página de proyecto se divide, como se ha explicado en apartados anteriores en tras partes diferentes: el panel de edición, el panel de acción y la ventana de visualización. El primer panel tiene un comportamiento muy parecido al objeto TPanel de la página linkador. Los objetos que modifican su ancho, en este caso, son: Prj_asm, Prj_obj, Prj_dir, Prj_list, Prj_s28 y Prj_map. El panel de acción tiene un tamaño y posición constante. La ventana de visualización es un objeto de la clase TRichEdit que adapta su tamaño al espacio restante en la página dejando unos márgenes a su alrededor.

Page 63: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

64

2.2.4 MACROS

2.2.4.0 Introducción: Una herramienta importante en el lenguaje ensamblador es el uso de macros. Esta parte es la modificación más importante realizada sobre el ensamblador original en todo el proyecto. El código original se ha ampliado para crear un macroensamblador, es decir, un ensamblador que admite el uso de macros. La forma de definir, llamar y tratar a las macros depende del macroensamblador. La sintaxis utilizada en el programa está basada en el ensamblador de 68k de Motorola.

2.2.4.1 Concepto general: Cuando el ensamblador encuentra una llamada a macro debe reemplazarla por una

secuencia predefinida de instrucciones, sustituyendo los argumentos de la llamada en los lugares especificados en la definición de la macro. A esto se le llama expansión de una macro.

Las macros, al contrario que las subrutinas, son expandidas en cada llamada, por lo que no se debe guardar ningún valor en pila. La ventaja de las macros es que hacen que la programación sea más sencilla, tienen un tiempo de ejecución menor que una subrutina (debido a que no tienen que guardar ni restaurar pila) y dan al programa mayor claridad y legibilidad. El macroensamblador no admite el concepto de macros anidadas (llamadas a macro desde el código de una macro).

2.2.4.2 Diseño estructural: El ensamblador original trabajaba con una estructura basada en dos pasadas. La

función principal del decodificador de líneas en la primera pasada era la de insertar todas las etiquetas del código en un árbol binario. Tras ello el ensamblador trabajaba sobre el código en la segunda pasada utilizando los valores de las etiquetas para sus cálculos.

En el diseño del macroensamblador se ha tratado de respetar lo máximo posible la

forma de trabajo del ensamblador original, tratando el código por pasadas del decodificador de líneas. Para no incrementar demasiado la complejidad del código, se ha elaborado una tercera pasada, la “pasada cero”, que se ejecutará antes de las dos pasadas originales, las cuales solamente habrán sufrido algunos cambios para integrar el tratamiento de macros. En esta “pasada cero” se tratará la definición de las macros y se ejecutarán las llamadas a macro (ver apartados siguientes).

La pasada inicial crea un archivo temporal del programa a partir del fichero fuente.

Este fichero temporal contiene el código del programa definitivo tras la pasada inicial, es decir, un código donde las definiciones y las llamadas a macro han sido resueltas. La tarea principal de la “pasada 0” es la crear un árbol binario de estructuras marbol (tipo macro) y crear una variable de tipo AnsiString que contenga el código del programa con

Page 64: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

65

las expansiones de macro ya realizadas. Posteriormente se crea un fichero de texto temporal donde se almacena el contenido de dicha variable.

2.2.4.3 Definicion:

La definición de una macro determinada siempre debe aparecer antes de la primera llamada a dicha macro. Preferiblemente deben colocarse todas las definiciones de macro antes de cualquier directiva del ensamblador que indique inicio de programa (absolute, relative...) o de cualquier línea de código de programa.

Se han creado tres palabras clave del ensamblador nuevas para implementar la

definición de las macros: macro, endm y callm. El encabezamiento de una definición de macro debe ser una línea formada por el nombre de la macro (en la columna tabulada para las etiquetas) seguido por la palabra clave macro. Tras esta primera línea, todo el texto siguiente es considerado el código de la macro hasta que el ensamblador encuentra la palabra clave endm, que indica el final de la definición de la macro.

Véase un ejemplo de definición de una macro cualquiera:

Obsérvese que no se han tratado puntos importantes como los argumentos de la macro \1, \2, ..., \9 o las etiquetas internas a la macro. Ver apartados siguientes.

Cuando el macroensamblador encuentra una línea de encabezamiento con la sintaxis

correcta, introduce la etiqueta name (contiene el nombre de la macro) en un árbol binario de objetos etiqueta donde, entre otras cosas, se pone su valor a cero y se asigna un 6 a su variable tipo (objeto de tipo macro). Esto se hace para que el ensamblador no acepte en ningún momento macros repetidas o etiquetas y macros con el mismo nombre. Al final del programa se aprovecha el árbol binario para imprimir el listado de objetos en el fichero listado con las macros añadidas.

La etiqueta name se introduce posteriormente en otro árbol binario solamente de

objetos macro donde se inicializan y se preparan todos sus campos. El campo text es preparado para ser actualizado en cada línea, y los campos llamadas y argumentos se inicializan a cero. Estos objetos son actualizados continuamente durante la definición de las macro y se accede a ellos en cada llamada a macro posterior.

NAME MACRO MOVE.W \1,-(SP) PEA \2

SUBQ.L #4,SP JSR ADDNUMS MOVE.L 0(SP),\3 LEA 10(SP),SP

ENDM Código 29

Page 65: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

66

Las líneas posteriores al encabezamiento se tratan como simples arrays de caracteres

y se añaden al campo text del tipo AnsiString de la macro. Al mismo tiempo se actualizan los flags de un array de booleanos conforme aparecen los símbolos que representan un espacio para un argumento determinado en el texto de la macro. Cuando el macroensamblador encuentra la palabra clave endm tenemos todo el texto de la macro en el campo text del objeto y el número de argumentos calculado. El número máximo de argumentos pasados a una macro es 99 argumentos.

2.2.4.4 Calling Method:

La directiva CALLM representa la operación de llamada a macro. Este tipo de directivas deben aparecer dentro del código del programa, es decir, entre la palabra clave de inicio (ABSOLUTE/RELATIVE) y la de fin de programa (END). La sintaxis correcta de una línea de llamada a macro es la siguiente:

[label] CALLM NAME arg1,arg2,...

Donde: [label] es el nombre de una etiqueta (opcional)

NAME es el nombre de la macro llamada

argi es el nombre del argumento i pasado a la macro

Cuando una operación de llamada a macro es ejecutada, el decodificador de líneas usa el nombre de la macro para localizar el objeto correspondiente en el árbol binario de estructuras tipo marbol (de tipo macro). Incrementa el campo llamadas de tipo entero y concatena el contenido del campo text del tipo AnsiString a una variable del mismo tipo que contiene el código parcial del programa definitivo tras la pasada inicial. Posteriormente trata los argumentos pasados a la macro y las etiquetas internas al código de la macro (véase apartados siguientes)

2.2.4.5 Argumentos:

El tratamiento de los argumentos de la macro se controla mediante un array de booleanos. Cuando el decodificador de líneas se encuentra con un encabezamiento correcto de una macro: se crea un array temporal de un tamaño predefinido a 99 valores booleanos y se inicializan todas las posiciones a 0. Esto significa que todavía no se ha encontrado ningún argumento en la macro. Las líneas posteriores al encabezamiento de la definición de la macro se tratan como simples arrays de caracteres y se añaden al campo text del tipo AnsiString de la macro. Al mismo tiempo se actualizan los flags del array de booleanos conforme aparecen los

Page 66: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

67

símbolos que representan un espacio para un argumento determinado en el texto de la macro. Estos símbolos son representados con la forma \x siendo x un número entero comprendido en [1,99]. Se puede comprobar que el número máximo de argumentos introducidos en una macro es 99. Cuando el macroensamblador se encuentra con un símbolo de los anteriormente definidos actualiza la posición correspondiente del array mediante la operación lógica OR: array[x] | 1. El tratamiento de los errores dentro de la definición de la macro referentes al paso de argumentos desde el exterior se efectúa cuando el ensamblador detecta la directiva endm, que corresponde al final de la definición de la macro. La definición de los n argumentos de la macro habrá sido correcta cuando nos encontremos en este punto con un array de la forma siguiente:

El decodificador recorre el array de booleanos comprobando la estructura de la información contenida. Si el contenido es correcto procede al cálculo de los argumentos en la definición de la macro y actualiza el campo argumentos de tipo entero. Si, por el contrario, aparecen errores en el contenido del array, el ensamblador informa del tipo de error y sigue con la ejecución del programa. Tras la definición de las macros en la pasada inicial del macroensamblador, el decodificador de líneas recorre el programa hasta detectar las directivas de llamada a macro, es decir, la palabra clave callm. Recordemos que la sintaxis seguida en la llamada a macro es la siguiente:

[label] CALLM NAME arg1,arg2,...

Cuando el programa detecta una llamada a macro, localiza el objeto correspondiente en el árbol binario de estructuras marbol (tipo macro). El programa entra entonces en un bucle donde se selecciona el primer argumento de la línea de llamada y se sobreescribe en todos los lugares donde aparece el símbolo \1 en el campo Texto de tipo AnsiString. Se procede de la misma forma con todos los argumentos existentes en la línea de código y sus respectivas parejas de símbolos (\2, \3, ...) sin realizar ninguna comprobación de errores en el número de argumentos pasados a la macro ni en la sintaxis del código resultante. Cuando el programa sale del bucle de sustitución, el decodificador compara el número de argumentos calculados en la definición de la macro con el número de argumentos reales encontrados en la llamada. Si ambos valores difieren se informa del error.

Page 67: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

68

2.2.4.6 Labels inside:

En este apartado se procede a explicar un recurso utilizado para solventar un posible error del macroensamblador. Explicaremos el problema mediante un sencillo ejemplo:

Se identifica la definición de la macro KK antes de la directiva del macroensamblador ABSOLUTE. El código de la macro se compone de dos líneas útiles: la primera una operación MOVE que precisa dos argumentos en la llamada de la macro y la segunda un salto condicional a una etiqueta definida internamente en el código de la macro. Tras la pasada inicial del macroensamblador se obtiene el código siguiente:

El código resultante contiene errores provocados por las múltiples llamadas de una misma macro que contiene la definición interna de una etiqueta. La etiqueta X está definida varias veces dentro de un mismo programa, siendo imposible que una etiqueta corresponda a múltiples valores simultáneamente. Este primer error nos conduce a un segundo problema: cuando el decodificador ejecute la línea BEQ X, el programa será incapaz de determinar el valor correcto de la etiqueta para sustituirlo en el código.

KK MACRO X MOVE \1,\2 BEQ X ENDM

ABSOLUTE ORG $27000 CALLM KK D1,D2

ADDI.L #1,D1 CALLM KK D1,D3 CALLM KK D1,D3

END

ABSOLUTE ORG $27000 X MOVE D1,D2 BEQ X

ADDI.L #1,D1 X MOVE D1,D3 BEQ X X MOVE D1,D3 BEQ X

END

Page 68: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

69

Estos problemas se han solucionado mediante la definición de un nuevo símbolo en el lenguaje de programación con el macroensamblador. El símbolo @ puede ser utilizado en la definición de una macro para informar al decodificador que debe añadir un índice al texto posterior al símbolo en cada llamada a la macro. Por consiguiente la sintaxis correcta del código ejemplo anterior es:

El código resultante tras la pasada inicial del decodificador de líneas es:

Cabe resaltar que la longitud máxima de las etiquetas en el ensamblador original era de 8 caracteres. El decodificador forzaba esta longitud eliminando los símbolos posteriores al octavo carácter. El macroensamblador actual trabaja del mismo modo, pero se debe tener en cuenta un detalle: el uso de etiquetas dentro de macros.

Las etiquetas interiores a una macro predecidas por el símbolo @ generan un índice de valor correspondiente al número de llamadas. Este índice se concatena al final de la etiqueta en la pasada inicial, es decir, antes de tratar el código con el ensamblador original y, por lo tanto, antes de limitar la longitud de la etiqueta. Véase un ejemplo para localizar el problema:

KK MACRO @X MOVE \1,\2 BEQ @X ENDM

ABSOLUTE ORG $27000 CALLM KK D1,D2

ADDI.L #1,D1 CALLM KK D1,D3 CALLM KK D1,D3

END

ABSOLUTE ORG $27000 X1 MOVE D1,D2 BEQ X1

ADDI.L #1,D1 X2 MOVE D1,D3 BEQ X2 X3 MOVE D1,D3 BEQ X3

END

Page 69: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

70

El código resultante tras la pasada inicial del decodificador de líneas es:

El código del programa resultante contiene múltiples definiciones de una misma

etiqueta. En la pasada inicial del macroensamblador se ha concatenado un índice tras la palabra ETIQUETA, pero después se ha forzado la longitud de la etiqueta resultante a 8 caracteres, eliminando así el índice que resolvía el problema de las múltiples definiciones de la etiqueta. Por ello se propone una longitud máxima de las etiquetas internas predecidas por el símbolo @ de 6 caracteres. Esta medida garantiza el correcto funcionamiento del método de los índices para un máximo de 99 llamadas a la macro.

KK MACRO @ETIQUETA MOVE D1,D2 BEQ @ETIQUETA ENDM

ABSOLUTE

ORG $27000 CALLM KK

CALLM KK ... CALLM KK

END

ABSOLUTE ORG $27000 ETIQUETA MOVE D1,D2 BEQ ETIQUETA ETIQUETA MOVE D1,D2 BEQ ETIQUETA

... ETIQUETA MOVE D1,D2 BEQ ETIQUETA END

Page 70: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

71

2.2.5 USO DEL REGISTRO DE WINDOWS

2.2.5.0 Introducción:

La base de datos de registro es una herramienta de Windows que mucha gente conoce superficialmente. Esta razón ha propiciado que el presente apartado sea, como en el caso de las DLL’s, extenso en explicaciones y definiciones. El registro puede ser utilizado para almacenar informaciones de arranque del software instalado en nuestra computadora. El interface de usuario del macroensamblador aprovecha dicha utilidad para arrancar el programa en el directorio de trabajo fijado por el usuario en la sesión anterior.

2.2.5.1 Estructura: La proliferación de archivos de configuración y los problemas derivados de las modificaciones indiscriminadas de estos archivos han llevado a Microsoft a centralizar todos los datos diseminados en una multitud de archivos INI en la base de datos de registro. Esta base de datos se organiza como un árbol binario, jerarquizado en secciones (directorios) donde se encuentran las diferentes variables (ficheros).

Se puede utilizar el programa RegEdit (del directorio de instalación de Windows) para visualizar y modificar el contenido de la base de datos de registro. Se advierte que toda modificación poco meditada sobre el registro mediante esta aplicación puede tener en el futuro graves consecuencias. Por ello se aconseja el uso de las funciones (del API de Windows) relacionadas con la base de datos para modificar su contenido (RegOpenKeyEx...).

La base de datos de registro se organiza pues de manera racional y en un árbol

binario, lo que hace su acceso muy rápido. Los diferentes nodos del árbol se llaman claves o secciones. Las diferentes salidas contenidas en una sección terminal se denominan variables. Las variables pueden contener valores de diferentes tipos.

Page 71: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

72

2.2.5.2 Acceso al registro:

La estructura principal del registro se divide en seis secciones tituladas: HKEY_CLASSES_ROOT HKEY_CURRENT_USER

HKEY_LOCAL_MACHINE HKEY_USERS HKEY_CURRENT_CONFIG HKEY_DYN_DATA

En la sección HKEY_LOCAL MACHINE, Windows guarda informaciones sobre la

configuración del hardware. En la sección HKEY_CURRENT_USER se guardan informaciones sobre los programas instalados en el ordenador. Esta sección se divide a su vez en secciones, una de las cuales se llama Software. A partir de esta sección es el software instalado el que se encarga de dividir la sección Software en secciones hijas y almacenar los valores en sus lugares correspondientes. El procedimiento usual para acceder a la base de datos de registro es mediante las funciones del API de Windows, es decir, mediante el lenguaje interno del sistema operativo. En primer lugar se debe abrir la clave con RegOpenKeyEx. A continuación se presenta una lista detallada de las funciones de acceso al registro fundamentales: Funciones de acceso a la base de datos de registro (funciones API) LONG RegOpenKeyEx (HKEY hkey, LPSTR lpszSubKey, DWORD dwReserved, REGSAM samDesired, PHKEY phkResult);

Page 72: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

73

Abre una sección que debe existir en la base de datos de registro. Devuelve (como todas las demás funciones de la serie) el valor ERROR_SUCCESS si la operación se ha ejecutado correctamente. Hkey designa la sección en la base del árbol y debe contener uno de los valores siguientes: HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE o HKEY_CURRENT_USER. Para guardar informaciones sobre un programa, hay que pasar HKEY_CURRENT_USER como argumento. LpszSubKey designa la serie de secciones a partir de la primera. En una cadena de caracteres no olvide duplicar el \ para separar los diferentes nodos. En el caso del macroensamblador sería “Software\\TM68K”. DwReserved debe dejarse a 0 SamDesired indica las seguridades de acceso. El valor KEY_ALL_ACCESS da todos los derechos. PhkResult debe apuntar a una variable de tipo HKEY en la que Windows copiará un handle de clave. Se trata en realidad de un valor entero. Habrá que usar esta clave en las otras funciones (salvo RegCreateKeyEx) para tener acceso a las diferentes variables de la sección. LONG RegCreateKeyEx (HKEY hkey, LPSTR lpszSubKey, DWORD dwReserved, LPSTR lpszClass, DWORD fdwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecAttr, PHKEY phkResult, LPDWORD lpdwDisposition); Crea una nueva sección. Si ya existe, simplemente se abre. Varios argumentos corresponden a los de RegOpenKeyEx. FdwOptions puede tener uno de los siguientes valores: REG_OPTION_VOLATILE esta sección se olvidará cuando se termine la sesión actual de Windows. REG_OPTION_NO_VOLATILE aparecerá esta sección en el próximo arranque de Windows. Se pone Null en lpSecAttr y en lpszClass. LpdwDisposition debe contener la dirección de una variable de tipo DWORD en la que Windows copiará uno de los valores siguientes: REG_CREATED_NEW_KEY si realmente se ha creado una nueva sección. REG_OPENED_EXISTING_KEY si simplemente se ha abierto la sección.

Page 73: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

74

LONG RegCloseKey (HKEY hkey); Finaliza el acceso a una sección. Si se ha modificado, la base de datos de registro se actualiza. LONG RegQueryValueEx (HKEY hkey, LPSTR lpszValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData); Copia en un buffer (la variable lpbData) el valor correspondiente a una variable. Se deja lpbData a NULL para recibir sólo informaciones sobre la variable. En este caso, Windows no copia nada en el buffer. Si el buffer es del tipo DWORD, no olvide efectuar el casting (LPBYTE) a la dirección de la variable de su programa (variable de tipo DWORD o int o long) El tamaño del buffer se especifica en la variable (de tipo DWORD) apuntada por lpcbData. Windows copia en la variable (de tipo DWORD) apuntada por lpdwType el tipo de la entrada. Este tipo puede ser: REG_BINARY en el caso de un dato codificado en binario sobre un cierto número de caracteres REG_DWORD en el caso de un dato codificado sobre 32 bits (tipo int) REG_SZ en el caso de una cadena de caracteres Si el buffer es demasiado pequeño para almacenar todo el contenido de la variable, la función RegQueryValueEx devuelve el valor ERROR_MORE_DATA y copia el tamaño necesario en el buffer de la variable apuntada por lpbcData. Generalmente, un programa llama una primera vez a RegQueryValueEx para conocer el tipo de la variablo y/o el tamaño mínimo del buffer. LONG RegSetValueEx (HKEY hkey, LPSTR lpValueName, DWORD Reserved, DWORD dwType, BYTE *lpData, DWORD cbData); Modifica el contenido o crea una nueva variable en la sección abierta o creada previamente. El nombre de la variable se pasa como segundo argumento. Su tipo (REG_WORD, REG_SZ,...) se pasa como cuarto argumento. Los dos últimos argumentos se refieren al contenido de la variable (dirección y tamaño) LONG RegFlushKey (HKEY hkey);

Page 74: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

75

Fuerza la actualización inmediata de la base de datos de registro. Esta operación se efectúa al cerrar con RegCloseKey, pero pueden pasar muchas cosas entre las dos operaciones. LONG RegDeleteKey (HKEY hkey, LPSTR lpszSubKey); Suprime una sección y eventualmente todas las secciones que dependen de la que se suprime. RegDeleteKey devuelve ERROR_ACCESS_DENIED si no tiene derecho a efectuar la operación o si la entrada está abierta por otro programa.

Page 75: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

76

Borland ha diseñado (en el lenguaje C++) la clase TRegistry para facilitar el acceso y actualización de la base de datos de registro. Los métodos y propiedades pertenecientes a la clase TRegistry basan su modo de funcionamiento en las funciones API anteriormente definidas. Se presenta a continuación una breve lista con los métodos fundamentales de la clase TRegistry (concepto similar a operaciones anteriores):

CloseKey Actualiza y cierra la clave correspondiente del registro CreateKey Crea una nueva clave en el registro

DeleteKey Elimina una clave específica y todas sus subclaves DeleteValue Elimina un valor específico de la clave seleccionada GetDataInfo Informa del tipo y tamaño del valor GetKeyInfo Información sobre la clave OpenKey Abre o crea (opcional) una clave determinada ReadBinaryData ReadBool ReadFloat ReadInteger ReadString WriteBinaryData WriteBool WriteFloat WriteInteger WriteString

Algunas de las propiedades fundamentales de la clase TRegistry se resumen en la siguiente lista (facilitan el modo de acceso al registro):

Access Especifica el nivel de accesibilidad a las claves abiertas KEY_ALL_ACCESS proporciona acceso total

CurrentKey Especifica la clave abierta actualmente CurrentPath Especifica el path asociado con la clave actual RootKey Especifica una de las 6 claves básicas del registro

Se debe añadir la siguiente línea en el encabezamiento para utilizar la clase TRegistry: #include <Registry.hpp>

Page 76: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

77

2.2.5.3 Aplicación del registro en el macroensamblador: El algoritmo principal de la aplicación de la base de datos de registro de Windows en el interface de usuario del programa viene dado en la figura siguiente:

Figura 15 – Organigrama del tratamiento del registro de Windows

El valor almacenado en el registro es de tipo string (cadena de caracteres) y contiene

el path de usuario. Se ha creado el objeto Registro de la clase TRegistry en el constructor de la ventana

principal del programa, es decir, en la función Tinterform del archivo Principal.cpp. A su vez, se ha definido la variable Ruta de tipo AnsiString, de modo que sea global para poder funcionar como argumento de las funciones que llaman al ensamblador y al linkador en el fichero Principal.cpp.

En el caso del ensamblador, se ha concatenado la ruta de usuario con los nombres de los ficheros (fuente, objeto y listado) respetando así el número y el tipo de los argumentos . La variable Ruta debe ser pasada como argumento a la DLL’s del linkador

Page 77: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

78

puesto que los ficheros objeto pueden ser múltiples cadenas de caracteres y los strings son tratados en el código del programa linkador. Los programas exteriores como el Simulador y el Comunicador deben consultar el registro por sus propios medios, debido a que no tienen ningún tipo de conexión con el programa principal. En el código del constructor del formulario principal (inicio del programa), se guarda en la variable Ruta del tipo AnsiString la cadena de caracteres almacenada en el registro en HKEY_CURRENT_USER\Software\TM683\Ruta. En el caso de que el valor no exista, entonces se crea y se almacena el path por defecto: c:\TM683\Usuario\ Para facilitar la tarea de cambio de la ruta al usuario en tiempo de ejecución, se ha creado un menú principal de la aplicación. Se trata del objeto Menu de la clase TMainMenu. El proceso sigue los pasos siguientes:

• Creación de una nueva ventana llamada RutaDialog del tipo TForm. La información

se almacena en los archivos RutaDlg.cpp (código relacionado con la ventana) y RutaDlg.dfm (componente visual). Se han modificado todas las propiedades necesarias para que la ventana sea tratada como un cuadro de diálogo.

• Creación del objeto RutaCombo de la clase TcomboBox para introducir la ruta de usuario. El combo guarda en memoria todas las entradas anteriores desde que el programa ha sido ejecutado.

• Adaptación del Editor para que trabaje en los directorios especificados por el registro. Se inicializa la propiedad InitialDir de los objetos OpenDialog y SaveDialog y se tratan las actualizaciones en los cambios de ruta.

Recuérdese que la ruta especificada debe existir. En caso contrario, el editor trabajará en el directorio Mis Documentos de Windows y los programas ensamblador y linkador informarán del error.

Page 78: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

79

2.2.6 DESCRIPCIÓN INTERNA DEL PROYECTO

2.2.6.1 Esquema del proyecto:

El proyecto, como ya se ha explicado, se divide en cinco partes importantes. La parte principal es el Interface de Usuario. Se trata de Interfens.exe, el fichero ejecutable principal del proyecto. Desde el programa interface se accede a los diferentes programas del proyecto. El programa Editor se encuentra integrado en el formulario principal del proyecto, además de aportar múltiples herramientas al usuario como la posibilidad de trabajar con un fichero de proyecto o de trabajar en un directorio de trabajo (mediante la Ruta de Usuario). El diagrama del proyecto es el siguiente:

Figura 16 – Diagrama del proyecto

Los programas a los que se accede desde el Interface de Usuario son cuatro. El

ensamblador y el linkador son estructuras DLL que deben ser llamadas mediante las funciones de entrada/salida de la DLL. El simulador y el ITF de comunicaciones son, en

Proyecto.bpg

Edit.cpp Proj.cpp

RutaDlg.cpp

arboles.cpp tabla.cpp

errores.cpp func.cpp

parser.cpp

ens68k.cpp

ensdll.cpp

Ensdll.dll

parserl.cpp

linker.cpp

ensdll.cpp

Lnkdll.dll SuperSimu.exe ITF68k.exe

principal.cpp

Interfens.cpp

Interfens.exe

Page 79: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

80

cambio, programas externos al proyecto. Se trata de archivos ejecutables que son simplemente llamados desde el formulario principal.

2.2.6.2 Detallado de los ficheros: a) Interface.exe

Principal.cpp Class TInterf_form

__fastcall TInterf_form(TComponent* Owner)

__fastcall ~TInterf_form()

void __fastcall Ens_buttonClick(TObject *Sender)

void __fastcall lin_buttonClick(TObject *Sender)

void __fastcall Button_addClick(TObject *Sender)

void __fastcall BEditorClick(TObject *Sender)

void __fastcall BPag_EnsClick(TObject *Sender)

void __fastcall FormCreate(TObject *Sender)

void __fastcall BPag_LnkClick(TObject *Sender)

void __fastcall asm_editChange(TObject *Sender)

void __fastcall Button_delClick(TObject *Sender)

void __fastcall Button_AllClick(TObject *Sender)

void __fastcall BSaveClick(TObject *Sender)

void __fastcall BOpenClick(TObject *Sender)

void __fastcall BNewClick(TObject *Sender)

void __fastcall BCloseClick(TObject *Sender)

void __fastcall BColorClick(TObject *Sender)

void __fastcall BPrintClick(TObject *Sender)

void __fastcall FormResize(TObject *Sender)

void __fastcall s28_editChange(TObject *Sender)

void __fastcall BPag_SimClick(TObject *Sender)

void __fastcall BPag_ComClick(TObject *Sender)

void __fastcall mnusalirClick(TObject *Sender)

void __fastcall mnurutaClick(TObject *Sender)

void __fastcall EnsErrDblClick(TObject *Sender)

void __fastcall BPag_PrjClick(TObject *Sender)

void __fastcall Prj_asmChange(TObject *Sender)

Page 80: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

81

void __fastcall Prj_delClick(TObject *Sender)

void __fastcall Prj_delallClick(TObject *Sender)

void __fastcall Prj_addClick(TObject *Sender)

void __fastcall Prj_s28Change(TObject *Sender)

void __fastcall Prj_BSaveClick(TObject *Sender)

void __fastcall Prj_BOpenClick(TObject *Sender)

void __fastcall Prj_BEnsClick(TObject *Sender)

void __fastcall Prj_BLnkClick(TObject *Sender)

void arg_lnk(int&,char *arg[])

void arg_lnk(char *arg[])

void OpenButton()

void SaveButton()

Edit.cpp Class TEditASM

TEditASM(TPageControl*)

~TEditASM()

void __fastcall EditKey(TObject *Sender, WORD &Key, TShiftState

Shift)

void __fastcall EditMouse(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

void EditColor()

void CursorPoint()

void TestLinea(int)

Proj.cpp Class TPrjClass

TPrjClass(TComponent* Owner)

~TPrjClass()

void Guardar()

void Cargar()

void Ensamblar()

void Linkar()

void LimpiarPantalla()

Page 81: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

82

RutaDlg.cpp

Class TRutaDialog

__fastcall TRutaDialog(TComponent* Owner)

void __fastcall RutaBOkClick(TObject *Sender)

void __fastcall RutaBCancelClick(TObject *Sender)

b) Ensdll.dll

Ens68k.cpp

EXPORT_IMPORT int Ens68K(char*,char*,char*)

EXPORT_IMPORT char* Ens68K_Mensaje()

EXPORT_IMPORT char* Ens68K_MensajeErr()

static int lee_linea(char *s,FILE *ff)

static int trans(char *,char *,int *)

static void mostrar_pantalla_ayuda(void)

char *treutabs(char *,char *)

void ini()

void Mensaje(char*)

void MensajeErr(char*)

void flMens(char*)

void flErr(char*)

void flWrite()

Arboles.cpp

struct arbol

struct arbolm

struct arbol *buscar_rama (struct arbol *a,char *label)

struct arbol *insarbol(struct arbol *r,struct arbol *a,char *label,

int *error,int dato,int tipodevariable)

void listar_arbol (struct arbol *a,int)

void eliminar_rama(struct arbol *,char *)

Page 82: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

83

void eliminar_arbol (struct arbol *a)

struct arbolm *buscar_rama (struct arbolm *a,char *label)

struct arbolm *insarbol(struct arbolm *r,struct arbolm *a,char

*label,int *error)

void listar_arbol (struct arbolm *a,int)

void eliminar_rama(struct arbolm *,char *)

void eliminar_arbol (struct arbolm *a)

Tabla.cpp

int decodifica(char *,char *)

int pasada_macros(char *)

static int:

tipo1(void),add(void),adda(void),addi(void),addq(void),and(void),

andi(void),asr(void),bra(void),bchg(void),chk(void),neg(void),

cmp(void),cmpm(void),nbcd(void),endd(void),eor(void),equ(void),

exg(void),ext(void),exter(void),glob(void),jmp(void),lea(void),

link(void),move(void),movea(void),movem(void),movep(void),

moveq(void),page(void),nada(void),or(void),org(void),rel(void),

stop(void),sub(void),swap(void),title(void),trap(void),unlk(voi

abso(void),dc(void),ds(void),dbcc(void),scc(void),high(void),

low(void),macro(void),callm(void),endm(void)

procesar(int (*f)())

static char* String_Hex(int,int)

int buscar_tabla(void)

static void stcat(void)

static void invertir (char *)

static int mascara(char *,char *linea)

static int sp(int)

static void opp_a_op(void)

Errores.cpp

void error (int,int,char *)

Page 83: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

84

Func.cpp

char *coger_palabra(char *,char *,int *)

char *cogeyanal(char *,int *,int *,int *)

int tipo2( int,int,char *,char *)

int tipo3( int,int,char *)

int masde4bits( int)

int masde8bits( int)

int masde16bits( int)

int esta_en (char,char *s)

int hexdec(char *,int *)

int bindec(char *,int *)

static struct operando registro (char *,int)

Parser.cpp

static void coger_expresion( int *)

static void nivel1(int *)

static void nivel2(int *)

static void nivel3(int *)

static void nivel4(int *)

static void nivel5(int *)

static void nivel6(int *)

static void primitiva(int *)

static void arit (char ,int *,int *)

static void unitario (char, int *)

static void coger_termino(void)

static esdelimitador(char)

static int valor(char *)

int hallar_valor (char *palabra,int longitud,int *err,

int *reubicable,int *segunda_pasada)

Page 84: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

85

c) Lnkdll.dll

Linker.cpp

Struct albolink

Struct etiqueta

Struct lista

EXPORT_IMPORT int Lnk68K(int,char **,char*,char*,char*)

EXPORT_IMPORT char* Lnk68K_Mensaje()

EXPORT_IMPORT char* Lnk68K_MensajeErr()

void Mensaje(char*)

void MensajeErr(char*)

static void insertarabs(struct lista *)

static void insertarreu(struct lista *)

static void listar(struct lista *)

static void listar_arbol (struct etiqueta *)

static void comprobar_externas(struct etiqueta *)

static void s28(char *)

static void volcars28(void)

static void nexit(int,char *)

static void sexit(void)

static int cogerfichero(char *,int,int,char**,char*,char*,char*)

static int buscarlista(struct lista *,char *)

static int insertar_etiqueta(struct etiqueta **,char *,char *)

static int checksum(char*)

static int cogerposicion(char**)

static struct etiqueta *buscar_etiqueta(struct etiqueta *,char *)

int hex_dec(char *)

int lee_linea(char *,FILE *)

static int esta_en (char,char *)

Parserl.cpp

int hallar_valor (char *puntero,int *)

int buscar_etiqueta_global(struct etiqueta *,char *)

struct etiqueta *buscar_etiqueta_local(struct etiqueta *,char *)

Page 85: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

86

static void coger_expresion(int *)

static void nivel1( int *)

static void nivel2( int *)

static void nivel3( int *)

static void nivel4( int *)

static void nivel5( int *)

static void nivel6( int *)

static void primitiva( int *)

static void arit (char , int *, int *)

static void unitario (char, int *)

static void coger_token(void)

static esdelimitador(char)

static int valor(char *)

Page 86: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

87

2.2.6.3 Descripción de las clases: a) Class TInterf_form

class TInterf_form : public TForm { __published: // IDE-managed Components TPanel *PanelPant; TPanel *PanelB; TOpenDialog *OpenDialog; TSaveDialog *SaveDialog; TPrintDialog *PrintDialog; TNotebook *Paginas; TPanel *Ed_Panel; TRichEdit *EnsMns; TRichEdit *LnkMns; TRichEdit *LnkErr; TPanel *Panel_CtrlEd; TBitBtn *BSave; TBitBtn *BOpen; TBitBtn *BNew; TPageControl *Ed_Pags; TBitBtn *BClose; TBitBtn *BColor;

TBitBtn *BPrint; TLabel *Label9; TLabel *Label10; TLabel *Label12; TLabel *Label11; TImage *Image7; TLabel *Linea; TLabel *nlinea; TMainMenu *MainMenu; TMenuItem *mnuprogramas; TMenuItem *mnuopciones; TMenuItem *mnued; TMenuItem *mnuens; TMenuItem *mnulnk; TMenuItem *mnusim; TMenuItem *mnucom; TMenuItem *mnuruta; TMenuItem *mnusalir; TListBox *EnsErr; TMenuItem *Proyecto1; TEdit *Prj_asm; TEdit *Prj_obj; TLabel *Label13; TLabel *Label14; TImage *Image9; TButton *Prj_add; TImage *Image10; TListBox *Prj_list; TImage *Image12; TEdit *Prj_s28;

Page 87: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

88

TEdit *Prj_map; TLabel *Label15; TLabel *Label16; TButton *Prj_del; TImage *Image13; TButton *Prj_delall; TImage *Image14; TEdit *Prj_dir; TLabel *Label17; TPanel *Prj_panel; TBitBtn *Prj_BLnk; TBitBtn *Prj_BEns; TBitBtn *Prj_BSave; TBitBtn *Prj_BOpen; TBitBtn *BEditor; TBitBtn *BPag_Ens; TBitBtn *BPag_Lnk; TBitBtn *BPag_Sim; TBitBtn *BPag_Com; TBitBtn *BPag_Prj; TRichEdit *Prj_Mensajes; TEdit *Prj_prj; TLabel *Label18; TPanel *PanelEns; TEdit *asm_edit; TLabel *Label1; TImage *Arrow1; TButton *Ens_button; TImage *Arrow2; TImage *Arrow3; TEdit *lst_edit; TEdit *obj_edit; TLabel *Label2; TLabel *Label3; TPanel *PanelLnk; TEdit *obj_lnk; TEdit *obj_direcc; TLabel *Label7; TLabel *Label6; TImage *Arrow4; TButton *Button_add; TImage *Arrow6; TListBox *Lista_arch; TImage *Arrow7; TButton *lin_button; TImage *Arrow8; TEdit *s28_edit; TLabel *Label4; TLabel *Label5; TEdit *map_edit; TImage *Arrow10; TButton *Button_del; TButton *Button_All; TImage *Image6; TLabel *Label8;

Page 88: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

89

void __fastcall Ens_buttonClick(TObject *Sender); void __fastcall lin_buttonClick(TObject *Sender); void __fastcall Button_addClick(TObject *Sender); void __fastcall BEditorClick(TObject *Sender); void __fastcall BPag_EnsClick(TObject *Sender); void __fastcall FormCreate(TObject *Sender); void __fastcall BPag_LnkClick(TObject *Sender); void __fastcall asm_editChange(TObject *Sender); void __fastcall Button_delClick(TObject *Sender); void __fastcall Button_AllClick(TObject *Sender); void __fastcall BSaveClick(TObject *Sender); void __fastcall BOpenClick(TObject *Sender); void __fastcall BNewClick(TObject *Sender); void __fastcall BCloseClick(TObject *Sender); void __fastcall BColorClick(TObject *Sender); void __fastcall BPrintClick(TObject *Sender); void __fastcall FormResize(TObject *Sender); void __fastcall s28_editChange(TObject *Sender); void __fastcall BPag_SimClick(TObject *Sender); void __fastcall BPag_ComClick(TObject *Sender); void __fastcall mnusalirClick(TObject *Sender); void __fastcall mnurutaClick(TObject *Sender); void __fastcall EnsErrDblClick(TObject *Sender); void __fastcall BPag_PrjClick(TObject *Sender); void __fastcall Prj_asmChange(TObject *Sender); void __fastcall Prj_delClick(TObject *Sender); void __fastcall Prj_delallClick(TObject *Sender); void __fastcall Prj_addClick(TObject *Sender); void __fastcall Prj_s28Change(TObject *Sender); void __fastcall Prj_BSaveClick(TObject *Sender); void __fastcall Prj_BOpenClick(TObject *Sender); void __fastcall Prj_BEnsClick(TObject *Sender); void __fastcall Prj_BLnkClick(TObject *Sender); private: // User declarations void arg_lnk(int&,char *arg[]); void arg_lnk(char *arg[]); void OpenButton(); void SaveButton(); TList *Lista_Ed; public: // User declarations __fastcall TInterf_form(TComponent* Owner); __fastcall ~TInterf_form(); };

Código 30

Page 89: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

90

TInterf_form es una clase descendiente de la clase TForm y es la más importante del proyecto. Se trata del formulario principal. Cuando el usuario abre el fichero ejecutable del proyecto, el programa automáticamente crea un objeto de la clase TInterf_form, que no será destruido hasta el final del programa. La sección __published en la definición de la clase contiene los IDE-managed Components, es decir, componentes de la VCL (Visual Component Library). La palabra clave __published indica que los componentes de la sección serán mostrados en la herramienta Object Inspector. En esta sección se encuentran las declaraciones de los punteros a los componentes visuales que deben ser creados al inicio del programa, además de las declaraciones de los eventos y métodos relacionados con esos componentes. Las funciones member son declaradas en esta sección también. La sección private contiene la declaración de las funciones solamente accesibles desde las funciones member (miembro) y friend (amiga). Estas funciones y variables son inaccesibles directamente por el usuario u otras clases del proyecto. En la sección public se encuentran el constructor y el destructor de la clase.

La clase TInterf_form es accedida desde los ficheros siguientes: Principal.cpp RutaDlg.cpp Proj.cpp

b) Class TEditASM

TEditASM es la clase con la que trabaja el programa Editor. El constructor del

formulario principal crea una lista de la clase TList. Este tipo de objetos almacenan un array de punteros y suele ser usado para gestionar una lista de objetos. El editor tiene la capacidad de trabajar con múltiples documentos simultáneamente y, por ello, se

class TEditASM { private: void TestLinea(int); public: TEditASM(TPageControl*); ~TEditASM(); TRichEdit *Edit; TTabSheet *Hoja;

void EditColor(); void CursorPoint(); void __fastcall EditKey(TObject *Sender, WORD &Key,

TShiftState Shift); void __fastcall EditMouse(TObject *Sender, TMouseButton

Button, TShiftState Shift, int X, int Y); };

Código 31

Page 90: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

91

necesita el objeto TList. Cada objeto de la clase TEditASM creado se introduce en la lista de objetos y se recupera cuando el programa lo considera preciso.

Un objeto de la clase TEditASM está formado por, entre otras cosas, un objeto de la

clase TRichEdit y un objeto de la clase TTabSheet. El primer objeto consiste en un editor de texto medianamente complejo que contiene el texto del documento en la propiedad Text y ofrece la posibilidad de modificar las propiedades visuales del componente con relativa facilidad. El segundo objeto es un componente visual con forma de pestaña tipo Windows que está relacionado con el objeto TRichEdit. Las pestañas de todos los objetos de la TList se vinculan a un objeto de las clase TPageControl que administra las páginas del editor y, en este caso, administra los documentos. Este objeto contiene múltiples páginas solapadas que el usuario selecciona mediante una simple acción del mouse sobre la pestaña relacionada con la página deseada.

La definición de la clase TEditASM se divide en dos secciones diferentes. La

sección public contiene las declaraciones del constructor y destructor de la clase, los punteros a los objetos TRichEdit y TTabSheet, y las declaraciones de las funciones públicas, es decir, accesibles desde el exterior de la clase. En la sección private, en cambio, se encuentra la declaración de las funciones privadas, es decir, de las únicamente accesibles desde el interior de la clase.

La clase TEditASM es accedida desde los ficheros siguientes: Principal.cpp

Edit.cpp

c) Class TPrjClass

TPrjClass es la clase con la que trabaja la página Proyecto. La utilidad de la clase es

la de almacenar y administrar los datos introducidos por el usuario en el panel de edición de proyectos.

class TPrjClass { private: public: TPrjClass(TComponent* Owner); ~TPrjClass(); char *elems[30]; int n_elems; AnsiString s28_file; AnsiString map_file; AnsiString prj_file; void Guardar(); void Cargar(); void Ensamblar(); void Linkar(); };

Código 32

Page 91: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

92

La definición de la clase TPrjClass se realiza íntegramente en la sección public. En esta lista se encuentran la declaración del constructor y del destructor de la clase, los punteros a los campos que almacenan la información y la declaración de las funciones públicas de la clase. Las tres variables AnsiString contienen los nombres de los ficheros de salida del proyecto (s28, map, prj) y la variable entera contiene el número de ficheros fuente. El array de 30 punteros a carácter sirve para acceder a las cadenas de caracteres que almacenan los datos de entrada del proyecto (asm, obj, dir).

La clase TPrjClass es accedida desde los ficheros siguientes: Principal.cpp

Proj.cpp

d) Class TRutaDialog

TRutaDialog es una clase descendiente de la clase TForm. Es un formulario o

ventana, aunque no se trata del formulario principal de la aplicación. El componente visual del objeto facilita al usuario la posibilidad de cambiar la Ruta de Usuario de una forma sencilla. El programa se encarga internamente de editar y actualizar el Registro de Windows. Básicamente, un objeto de la clase TRutaDialog es un diálogo compuesto por un objeto TComboBox, una etiqueta TLabel y objetos de la clase TButton.

La definición de la clase TRutaDialog se estructura como en el caso de la clase

TInterf_form. La declaración de los IDE-Managed Components se encuentran en la sección __published. En la sección public se declara el constructor y el destructor de la clase.

La clase TRutaDialog es accedida desde los ficheros siguientes: Principal.cpp RutaDlg.cpp

class TRutaDialog : public TForm { __published: // IDE-managed Components TComboBox *RutaCombo; TLabel *RutaLabel; TButton *RutaBOk; TButton *RutaBCancel; void __fastcall RutaBOkClick(TObject *Sender); void __fastcall RutaBCancelClick(TObject *Sender); private: // User declarations public: // User declarations __fastcall TRutaDialog(TComponent* Owner); }; Código 33

Page 92: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

93

e) struct arbol

Estructura utilizada en la DLL ensamblador. Varios objetos de este tipo forman

una estructura de árbol binario. Este árbol contiene todos los símbolos (etiquetas y macros) contenidos en el código fuente de una forma ordenada y con sus datos personales, permite un acceso relativamente rápido a un elemento determinado y permite un control de los posibles errores.

f) struct arbolm

Estructura utilizada en la DLL ensamblador. Varios objetos de este tipo forman

una estructura de árbol binario. Este árbol contiene los objetos macro definidos en el código fuente de una forma ordenada y con sus datos personales, permite un acceso relativamente rápido a un elemento determinado y permite un control de los posibles errores.

g) struct arbolink

struct arbol {

struct arbol *arbol_der; struct arbol *arbol_izq; char label[16]; int valor; int tipodevariable; };

struct arbolm {

struct arbolm *arbol_der; struct arbolm *arbol_izq; char label[16]; AnsiString text; int llamadas; int argumentos; };

struct arbolink {

struct arbolink *arbol_der; struct arbolink *arbol_izq; char label[16]; int valor; int tipodevariable;

};

Código 34

Código 35

Código 36

Page 93: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

94

Se trata de una estructura no utilizada por la DLL linkador ni por ningún

programa. Definida en la DLL linkador.

h) struct etiqueta

Estructura utilizada en la DLL linkador. Varios objetos de este tipo forman una

estructura de árbol binario. Este árbol contiene todas las etiquetas listadas en los ficheros objeto de una forma ordenada y con sus datos personales, permite un acceso relativamente rápido a un elemento determinado y permite un control de los posibles errores.

i) struct lista

Estructura utilizada en la DLL linkador. Varios objetos de este tipo forman una

estructura de lista ordenada. Esta lista contiene los objetos fichero pasados como argumento a la DLL de una forma ordenada y con sus datos personales. Esta estructura es también utilizada para hacer un tratamiento de los segmentos de código en un mismo fichero objeto.

struct etiqueta {

struct etiqueta *derecha; struct etiqueta *izquierda; char valor[9]; char nombre[20];

};

struct lista {

struct lista *siguiente; char fichero[120]; int origen; int offset; int minimo; int reubicable; int longitud; int segmento; };

Código 37

Código 38

Page 94: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

95

2.2.6.4 Descripción de las funciones: a) Interface.exe

Principal.cpp

__fastcall TInterf_form(TComponent* Owner)

Constructor de la clase TInterf_form. Se ejecuta cuando se crea el formulario principal del proyecto, es decir, al inicio del programa.

o Crea un objeto TList. Se trata de una lista de objetos utilizada por el programa Editor para administrar y almacenar los diferentes documentos abiertos simultáneamente.

o Limita el tamaño mínimo del formulario principal. o Actualiza el tamaño y posición de los componentes visuales en

función del tamaño del formulario principal. o Recupera el path de usuario del Registro de Windows.

__fastcall ~TInterf_form()

Destructor de la clase TInterf_form. Se ejecuta cuando se destruye el formulario principal del proyecto, es decir, al final del programa.

o Elimina con delete los objetos apuntados por los punteros de la lista de objetos y el objeto TList.

void __fastcall FormCreate(TObject *Sender)

Código ejecutado cuando el formulario principal es creado por primera vez. Establece la pantalla de inicio como página activa.

void __fastcall FormResize(TObject *Sender)

Código ejecutado cuando el formulario principal cambia de tamaño. o Limita el tamaño mínimo del formulario principal. o Actualiza el tamaño y posición de los componentes visuales en

función del tamaño del formulario principal.

void __fastcall BEditorClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BEditor. Establece la página de editor como página activa.

void __fastcall BPag_EnsClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BPag_Ens. Establece la página de ensamblador como página activa.

Page 95: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

96

void __fastcall BPag_LnkClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BPag_Lnk. Establece la página de linkador como página activa.

void __fastcall BPag_SimClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BPag_Sim. Ejecuta el programa simulador.

void __fastcall BPag_ComClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BPag_Com. Ejecuta el programa comunicador.

void __fastcall BPag_PrjClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BPag_Prj. Establece la página de proyecto como página activa.

void __fastcall Ens_buttonClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Ens_button. Ensambla el fichero fuente.

o Prepara los nombres de los ficheros fuente, objeto y listado. o Llama a la función principal de la DLL ensamblador. o Trata las posibles excepciones mostrando los mensajes y errores por

pantalla.

void __fastcall asm_editChange(TObject *Sender)

Código ejecutado cuando el usuario cambia la propiedad Text del objeto asm_edit. Copia el contenido en los objetos obj_edit y lst_edit.

void __fastcall EnsErrDblClick(TObject *Sender)

Código ejecutado cuando el usuario acciona doblemente el mouse sobre el objeto EnsErr de la clase TListBox. Resalta el error en el programa editor.

o Aisla las variables nombre de fichero y número de línea de la cadena de caracteres.

o Recupera el objeto TEditASM de la lista de documentos del editor. o Carga el fichero en caso de no encontrarse en la lista. o Resalta la línea determinada.

void __fastcall lin_buttonClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón lin_button. Linka los ficheros objeto.

o Prepara los argumentos: ruta de usuario y array de 20 ficheros objeto. o Llama a la función principal de la DLL linkador.

Page 96: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

97

o Trata las posibles excepciones mostrando los mensajes y errores por pantalla.

o Elimina el array de punteros.

void arg_lnk(int&,char *arg[])

Código llamado al inicio de la función lin_buttonClick(...). Crea el array de punteros a carácter.

void arg_lnk(char *arg[])

Código llamado al final de la función lin_buttonClick(...). Elimina el array de punteros a carácter con delete.

void __fastcall Button_addClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Button_add. Añade una línea al objeto TListBox de la página del linkador. El formato de la línea es: nombre_obj@dir

void __fastcall Button_delClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Button_del. Elimina la línea seleccionada del objeto TListBox de la página del linkador.

void __fastcall Button_AllClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Button_All. Elimina todo el contenido del objeto TListBox de la página del linkador.

void __fastcall s28_editChange(TObject *Sender)

Código ejecutado cuando el usuario cambia la propiedad Text del objeto s28_edit. Copia el contenido en el objeto map_edit.

void __fastcall BSaveClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BSave. Llama a la función SaveButton( ).

void SaveButton()

Código llamado desde la función BSaveClick(...). Guarda el contenido de el documento activo en un archivo de texto.

o Recupera el objeto TEditASM de la lista de objetos del editor. o Ejecuta el SaveDialog. o Abre el fichero especificado por el usuario y vuelca el contenido del

documento en el fichero.

Page 97: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

98

void __fastcall BOpenClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BOpen. Llama a la función OpenButton( ).

void OpenButton()

Código llamado desde la función BOpenClick(...). Escribe el contenido de un archivo de texto en el documento especificado por el usuario.

o Ejecuta el OpenDialog. o Crea el objeto TEditASM. o Abre el fichero especificado por el usuario y vuelca el contenido en

el documento creado.

void __fastcall BNewClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BNew. Crea un nuevo documento en el programa editor, es decir, crea un nuevo objeto TEditASM.

void __fastcall BCloseClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BClose. Cierra el documento activo del programa editor.

o Recupera el objeto TEditASM de la lista de objetos del editor. o Permite guardar el documento en caso de que haya modificado su

contenido tras el último almacenamiento. o Elimina el objeto TEditASM con delete y reagrupa el objeto TList

con el método Pack( ).

void __fastcall BColorClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BColor. Llama a la función EditColor( ).

void __fastcall BPrintClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón BPrint. Imprime el documento activo del programa editor.

o Recupera el objeto TEditASM de la lista de objetos del editor. o Ejecuta el PrintDialog. o Prepara impresión e imprime.

void __fastcall mnusalirClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre la opción del menú mnusalir. Cierra el programa.

void __fastcall mnurutaClick(TObject *Sender)

Page 98: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

99

Código ejecutado cuando el usuario acciona el mouse sobre la opción del menú mnuruta. Hace visible el diálogo de ruta de usuario.

void __fastcall Prj_asmChange(TObject *Sender)

Código ejecutado cuando el usuario cambia la propiedad Text del objeto Prj_asm. Copia el contenido en el objeto Prj_obj.

void __fastcall Prj_s28Change(TObject *Sender)

Código ejecutado cuando el usuario cambia la propiedad Text del objeto Prj_s28. Copia el contenido en el objeto Prj_map.

void __fastcall Prj_delClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_del. Elimina la línea seleccionada del objeto TListBox de la página de proyecto.

void __fastcall Prj_delallClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_delall. Elimina todo el contenido del objeto TListBox de la página de proyecto.

void __fastcall Prj_addClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_add. Añade una línea al objeto TListBox de la página del linkador. El formato de la línea es: nombre_asm nombre_obj dir

void __fastcall Prj_BSaveClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_BSave en el panel de acción de la página de proyecto.

o Crea un objeto de la clase TPrjClass con new. o Llama al método Guardar( ) de la clase. o Elimina el objeto con delete.

void __fastcall Prj_BOpenClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_BOpen en el panel de acción de la página de proyecto.

o Crea un objeto de la clase TPrjClass con new. o Llama al método Abrir( ) de la clase. o Elimina el objeto con delete.

void __fastcall Prj_BEnsClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_BEns en el panel de acción de la página de proyecto.

o Crea un objeto de la clase TPrjClass con new.

Page 99: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

100

o Llama al método Ensamblar( ) de la clase. o Elimina el objeto con delete.

void __fastcall Prj_BLnkClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón Prj_BLnk en el panel de acción de la página de proyecto.

o Crea un objeto de la clase TPrjClass con new. o Llama al método Linkar( ) de la clase. o Elimina el objeto con delete.

Edit.cpp TEditASM(TPageControl*)

Constructor de la clase TEditASM. Se ejecuta cuando se crea un nuevo documento de editor.

o Crea los objetos TTabSheet y TRichEdit. o Inicializa las propiedades principales.

~TEditASM()

Destructor de la clase TEditASM. Se ejecuta cuando se elimina un documento de editor.

o Elimina los objetos TTabSheet y TRichEdit.

void EditColor()

Función que da formato de estilo y color al texto del documento seleccionado.

o Inicializa las propiedades (fuente y color) del texto. o Llama a la función TestLinea(int) para cada línea de texto.

void TestLinea(int)

Función llamada por EditColor( ). Trata el formato de las líneas de texto individualmente.

o Recorre la línea hasta encontrar el primer carácter útil. o En caso de ser un comentario (* ;) se pone la línea en color clBlue. o En caso contrario, se recorre la línea en busca de palabras clave del

ensamblador y se da un formato en fsBold. o La última palabra debe ser tratada de forma especial.

void CursorPoint()

Función llamada por EditKey( ). Crea un objeto de la clase TPunto y lo actualiza con el punto donde se encuentra el cursor en ese preciso instante.

Page 100: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

101

void __fastcall EditKey(TObject *Sender, WORD &Key, TShiftState

Shift)

Código ejecutado cuando el usuario acciona una tecla cualquiera sobre el el objeto TRichEdit del editor. Llama a la función CursorPoint( ).

void __fastcall EditMouse(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

Código ejecutado cuando el usuario acciona un botón con el mouse sobre el el objeto TRichEdit del editor. Llama a la función CursorPoint( ).

Proj.cpp TPrjClass(TComponent* Owner)

Constructor de la clase TPrjClass. Se ejecuta cuando se crea un nuevo documento de editor. Función vacía de contenido.

~TPrjClass()

Destructor de la clase TPrjClass. Se ejecuta cuando se elimina un documento de editor. Función vacía de contenido.

void Guardar()

Función llamada por Prj_BSaveClick( ). Guarda los datos de proyecto introducidos por el usuario en el panel de edición en un fichero de proyecto.

o Introduce los datos del panel de edición en los campos del objeto TPrjClass creado en la función antecesora.

o Prepara una variable AnsiString con los datos dispuestos en un formato determinado.

o Crea el fichero de proyecto en modo escritura y vuelca el contenido de la variable en su interior.

o Visualiza mensaje en ventana de visualización y cierra el fichero.

void Cargar()

Función llamada por Prj_BOpenClick( ). Guarda los datos de proyecto introducidos por el usuario en el panel de edición en un fichero de proyecto.

o Llama a la función LimpiaPantalla( ). o Abre el fichero de proyecto especificado en modo lectura. o Actualiza los campos de los componentes del panel de edición con

los datos del fichero de proyecto. o Visualiza mensaje en ventana de visualización y cierra el fichero.

Page 101: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

102

void Ensamblar()

Función llamada por Prj_BEnsClick( ). Ensambla los ficheros fuente del proyecto en los ficheros objeto especificados en su creación.

o Llama al método Cargar( ) de la clase TPrjClass. o Introduce los datos del panel de edición en los campos del objeto

TPrjClass creado en la función antecesora. o Para cada pareja de ficheros fuente/objeto:

a) Se preparan los nombres de los ficheros. b) Se llama a la función principal de la DLL ensamblador

con el método try. c) Se tratan las posibles excepciones con el método catch. Se

introduce un mensaje informativo del proceso y los errores en color clRed.

o Elimina con delete los objetos creados con new.

void Linkar()

Función llamada por Prj_BLnkClick( ). Linka los ficheros objeto del proyecto en los fichero de salida s28 y map especificados en su creación.

o Llama al método Cargar( ) de la clase TPrjClass. o Introduce los datos del panel de edición en los campos del objeto

TPrjClass creado en la función antecesora. o Prepara el array de argumentos (objeto y dirección) de la DLL

linkador. El formato utilizado es: objeto@dirección. o Llama a la función principal de la DLL linkador con el método try. o Trata las posibles excepciones con el método catch. Se introduce un

mensaje informativo del proceso y los errores cometidos.

void LimpiarPantalla()

Función llamada por los métodos de la clase TPrjClass. Elimina el contenido de los componentes del panel de edición y del objeto TRichEdit de la ventana de visualización.

RutaDlg.cpp

__fastcall TRutaDialog(TComponent* Owner)

Constructor de la clase TRutaDialog. Se ejecuta cuando se crea formulario diálogo de ruta de usuario.

o Inicializa las propiedades de los componentes del formulario.

void __fastcall RutaBOkClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón RutaBOk en el diálogo de ruta de usuario. Guarda el nuevo path en el registro de Windows y en la memoria del objeto TComboBox.

Page 102: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

103

o Crea un objeto de la clase TRegistry. o Actualiza el registro con los nuevos valores introducidos por el

usuario con el método try. o Uso del método __finally para eliminar el objeto con delete. Ejecuta

este código cuando acabe el try (con excepciones o no). o Guarda path en memoria de TComboBox. o Actualiza los directorios de los diálogos del editor.

void __fastcall RutaBCancelClick(TObject *Sender)

Código ejecutado cuando el usuario acciona el mouse sobre el botón RutaBCancel en el diálogo de ruta de usuario. Restaura el path correcto en el TComboBox.

o Crea un objeto de la clase TRegistry. o Recupera el path del registro de Windows con el méetodo try. o Elimina el objeto con el método __finally.

Page 103: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

104

b) Ensdll.dll

Ens68k.cpp

EXPORT_IMPORT int Ens68K(char*,char*,char*)

Función principal de la DLL ensamblador. Se trata de un programa que ensambla un fichero fuente en tres pasadas: pasada cero, primera y segunda pasada. Tiene como argumentos punteros a las cadenas de caracteres que contienen los nombres de los ficheros fuente, objeto y listado. En la pasada cero el programa se encarga de tratar las definiciones de macro y expandir las llamadas a macro. En la primera pasada el programa llena la tabla de símbolos y calcula la longitud de cada una de las instrucciones mientras detecta posibles errores de sintaxis o “labels” mal situadas o incorrectas. En la segunda pasada se realiza la codificación de las instrucciones. Como la tabla de símbolos está completa, se resuelven las llamadas a las etiquetas. Si se da el caso de que las etiquetas que no existan, éstas se considerarán externas al módulo y se prepararán para resolverse en el linkador. En esta segunda pasada se procede al tratamiento de las directivas. Es prácticamente igual que en la primera pasada, con la salvedad de que ahora se graban en el fichero objeto. Esqueleto de la función:

o Inicializaciones y apertura de ficheros. o PASADA CERO (recorre las líneas del código fuente hasta encontrar

el end ): a) Llama a la función pasada_macros( ). b) Trata los posibles errores cometidos. c) Guarda código expandido en fichero temporal.

o PRIMERA PASADA (recorre las líneas del código fuente hasta

encontrar el end ): a) Llama a la función decodifica( ). b) Trata los posibles errores cometidos.

o SEGUNDA PASADA (recorre las líneas del código fuente hasta

encontrar el end ): a) Llama a la función decodifica( ). b) Prepara y escribe línea de código en fichero listado. c) Tratamiento de las directivas DS y DC. d) Prepara y escribe línea ensamblada (símbolos) en ficheros

listado y objeto. e) Fin ficheros listado y objeto, escribe tabla de símbolos y

cierra ficheros.

Page 104: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

105

f) Si errores: borra fichero objeto y lanza excepción ENS1. Si no errores: lanza excepción ENS0.

static int lee_linea(char *s,FILE *ff)

Función llamada desde Ens68K(...) del fichero ens68k.cpp. Lee una línea del fichero especificado no importando si la línea acaba en \n o si acaba en \r\n dependiendo del editor que se haya utilizado para escribir el fichero fuente. Parámetros: char *s - Puntero al string donde la función escribirá la línea

leída. FILE *ff – Puntero al fichero de donde tiene que leer la línea. Retorno: Devuelve un 1 si la función se ha ejecutado correctamente

y un cero si se ha llegado al final de fichero.

static int trans(char *,char *,int *)

Función que coge un string que serán los parámetros de una directiva del tipo DC y los analiza devolviendo otra cadena que será una serie de dígitos hexadecimales equivalentes a la cadena de entrada. Parámetros: char *entrada - Puntero al string conteniendo los parámetros

de la directiva tipo DC. char *salida - Puntero a un string que contendrá el valor

hexadecimal equivalente al string entrada. int *error - Puntero a un entero que contendrá el número de

error cometido o cero si no se ha cometido ningún error .

Retorno: Devuelve el número de valores contenidos en el string de entrada.

static void mostrar_pantalla_ayuda(void)

char *treutabs(char *,char *)

Función que sustituye el símbolo tabulador ‘\t’ por ocho espacios en blanco para evitar caracteres extraños.

void ini()

Función de inicialización llamada desde Ens68K(...) cada vez que se ejecuta el programa DLL.

Las funciones siguientes preparan y presentan los mensajes que se generan en la DLL ensamblador y que deben presentarse en el programa interface o ser escritos en el fichero listado:

Page 105: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

106

EXPORT_IMPORT char* Ens68K_Mensaje()

Función que puede ser llamada desde fuera de la DLL. Devuelve un string que contiene todos los mensajes informativos presentados durante la ejecución de la DLL.

EXPORT_IMPORT char* Ens68K_MensajeErr()

Función que puede ser llamada desde fuera de la DLL. Devuelve un string que contiene todos los mensajes de error presentados durante la ejecución de la DLL.

void Mensaje(char*)

Función que añade un mensaje informativo nuevo al string que contiene todos los mensajes informativos presentados durante la ejecución de la DLL.

void MensajeErr(char*)

Función que añade un mensaje de error nuevo al string que contiene todos los mensajes error presentados durante la ejecución de la DLL.

void flMens(char*)

Función similar a Mensaje(char*) pero que presenta los mensajes con un formato especial para el fichero listado.

void flErr(char*)

Función similar a MensajeErr(char*) pero que presenta los mensajes con un formato especial para el fichero listado.

void flWrite()

Función que escribe el contenido de los strings que contienen los mensajes de información y los mensajes de error en el fichero listado.

Arboles.cpp

struct arbol *buscar_rama (struct arbol *a,char *label)

Función que busca dentro de una estructura de árbol binario, que contiene los símbolos del programa (etiquetas y macros), una determinada etiqueta devolviendo un puntero a la rama que se está buscando. Se trata de una función recursiva. Es llamada cada vez que se requiere la recuperación del valor de una etiqueta. Parámetros: struct arbol *a - Puntero al árbol de etiquetas.

Page 106: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

107

char *label - Puntero a un string que contiene la etiqueta que se está buscando.

Retorno: Devuelve un puntero con la dirección de la rama que

se está buscando.

struct arbol *insarbol(struct arbol *r,struct arbol *a,char *label,

int *error,int dato,int tipodevariable)

Función que inserta dentro de una estructura de árbol binario, que contiene los símbolos del programa, una determinada etiqueta devolviendo un puntero a la raiz del árbol. Se trata de una función recursiva. (alfabéticamente) Parámetros: struct arbol *r - Puntero al árbol de etiquetas. struct arbol *a - Puntero a la rama que se quiere insertar. char *label - Puntero a un string que contiene la etiqueta que

se desea insertar. int *error - Puntero a una variable que contendrá el tipo de

error cometido. Será 0 si no hay ningún error. long int dato - Valor de la etiqueta.(valor de contador PC)

int tipodevariable - Tipo de etiqueta con uno de los siguientes valores posibles:

0-Local absoluta 1-Local reubicable 2-Externa 3-Global no inicializada 4-Global absoluta 5-Global reubicable Retorno: Devuelve un puntero con la dirección de la rama que se está

buscando.

void listar_arbol (struct arbol *a,int)

Función que inserta dentro de una estructura de árbol binario, que contiene las etiquetas del programa, una determinada etiqueta devolviendo un puntero a la raiz del árbol. Es una función recursiva. Parámetros: struct arbol *a - Puntero al árbol de etiquetas. int i - Variable que indica el destino del listado.Puede tomar

los valores: 1: fichero objeto 2: fichero de listado

void eliminar_rama(struct arbol *,char *)

Page 107: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

108

Función que elimina de una estructura de árbol binario que contiene las etiquetas del programa una determinada etiqueta. Esta función es llamada por las funciones equ, high y low del módulo tabla.cpp cuando no se puede resolver el valor de una etiqueta. Parametros: struct arbol a - Puntero al árbol de etiquetas. char *label - Puntero a un string que contiene la etiqueta que

se desea eliminar.

void eliminar_arbol (struct arbol *a)

Función que elimina una estructura de árbol binario. Se trata de una función recursiva. Parámetros: struct arbol *a - Puntero al árbol de etiquetas.

Las siguientes funciones son similares a las anteriormente descritas. Los argumentos son otro tipo de estructura en árbol binario, y el tratamiento de los campos de los objetos del árbol es diferente.

struct arbolm *buscar_rama (struct arbolm *a,char *label)

struct arbolm *insarbol(struct arbolm *r,struct arbolm *a,char

*label,int *error)

void listar_arbol (struct arbolm *a,int)

void eliminar_rama(struct arbolm *,char *)

void eliminar_arbol (struct arbolm *a)

Tabla.cpp

int decodifica(char *,char *)

Esta función es un ensamblador de líneas. El primer argumento de la función es un string de entrada que contiene la línea de código que se debe ensamblar. El segundo es un string que contendrá la línea ensamblada a la salida de la función. Devuelve el error cometido como resultado de la función. La función decidifica trabaja de forma diferente para cada pasada del ensamblador. En la pasada cero la función no es llamada en ningún momento. En las dos pasadas siguientes el ensamblador llama a la función para cada línea de código desde la función Ens68K( ).

Page 108: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

109

El esquema de funcionamiento de la función en la primera pasada es el siguiente:

o Recorre string de entrada y comprueba si se trata de una línea de comentario. Si es un comentario, la función acaba. En caso contrario, sigue con la ejecución.

o Llama a función coger_palabra( ). La función coge la primera palabra de la línea. Comprueba errores.

o Si se trata de una etiqueta: a) Llama a la función ins_arbol( ). La función inserta la

etiqueta en una estructura en árbol binario de símbolos. b) Llama a la función coge_palabra( ). La función coge la

palabra siguiente a la etiqueta. o Identifica el nemónico y consulta en tablas la longitud de la

instrucción para incrementar el contador y poder dar valores a las etiquetas encontradas.

El esquema de funcionamiento de la función en la segunda pasada es el siguiente:

o Recorre string de entrada y comprueba si se trata de una línea de comentario. Si es un comentario, la función acaba. En caso contrario, sigue con la ejecución.

o Llama a función coger_palabra( ). La función coge la primera palabra de la línea. Comprueba errores.

o Si se trata de una etiqueta: a) Llama a la función ins_arbol( ). La función inserta la

etiqueta en una estructura en árbol binario de símbolos. b) Llama a la función coge_palabra( ). La función coge la

palabra siguiente a la etiqueta. o Identifica el nemónico y consulta en tablas la longitud, el número de

operandos y el valor de la instrucción para poder realizar un ensamblado específico de la instrucción.

o Si el número de operandos es uno o dos, llama a la función cogeyanal y comprueba los errores cometidos. La función analiza el primer operando de la instrucción.

o Si el número de operandos es dos, repite la operación anterior con el segundo operando de la instrucción. Comprueba errores de número de operandos.

o Llama a la función que corresponda con el nemónico identificado (consulta tablas). Esta función se encarga de ensamblar la instrucción consultando los datos de los operandos analizados.

int pasada_macros(char *)

Page 109: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

110

Esta función trata las definiciones y las llamadas a macro. El argumento de la función es un string de entrada que contiene la línea de código que se debe tratar. Devuelve el error cometido como resultado de la función.

o Recorre string de entrada y comprueba si se trata de una línea de comentario. Si es un comentario, la función acaba. En caso contrario, sigue con la ejecución.

o Llama a función coger_palabra( ). La función coge la primera palabra de la línea. Comprueba errores.

o Si se trata de una etiqueta: a) Llama a la función coge_palabra( ). La función coge la

palabra siguiente a la etiqueta. o Identifica el nemónico. o Si el nemónico se corresponde con macro, endm o callm realiza el

tratamiento personalizado siguiente: a) macro: inicializa array de argumentos e inserta el nombre

de la macro en el árbol binario de símbolos con la función insarbol (arbol *...).

b) endm: recupera el objeto arbolm del árbol binario macros y comprueba los errores de formato del array de booleanos y el número de argumentos de la macro.

c) callm: recupera el objeto arbolm del árbol binario macros y trata la sustitución de los argumentos y de las etiquetas internas a la macro que empiezan por @.

o Si no se corresponde y nos encontramos dentro de la definición de

una macro: a) Reconoce los argumentos en la definición y actualiza el

array de booleanos. b) Actualiza el campo Texto del objeto macro.

o En cambio, si se trata de código normal: a) Copia la línea de código en la variable AnsiString que contiene el código fuente con las llamadas a macro expandidas correctamente.

static int:

tipo1(void),add(void),adda(void),addi(void),addq(void),and(void),

andi(void),asr(void),bra(void),bchg(void),chk(void),neg(void),

cmp(void),cmpm(void),nbcd(void),endd(void),eor(void),equ(void),

exg(void),ext(void),exter(void),glob(void),jmp(void),lea(void),

link(void),move(void),movea(void),movem(void),movep(void),

moveq(void),page(void),nada(void),or(void),org(void),rel(void),

Page 110: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

111

stop(void),sub(void),swap(void),title(void),trap(void),unlk(voi

abso(void),dc(void),ds(void),dbcc(void),scc(void),high(void),

low(void),macro(void),callm(void),endm(void)

Funciones que son llamadas al final de la función decodifica mediante el uso de la función procesar(...). Cada una de las funciones trata al nemónico correspondiente en el lenguaje ensamblador.

procesar(int (*f)())

Función que tiene como argumento el puntero a una función de la lista de funciones de los nemónicos. Esta función es simplemente utilizada para marcar el rumbo del programa.

static char* String_Hex(int,int)

int buscar_tabla(void)

Función que busca en la tabla de instrucciones el nemónico correspondiente a un numero dado.

static void stcat(void)

static void invertir (char *)

Función que invierte la máscara de registros en los direccionamientos en que es necesaria esta inversión.

static int mascara(char *,char *linea)

Función que crea la máscara de registros en la instrucción movem y devuelve si ha habido algún error 35 que es el error en la lista de registros.

static int sp(int)

static void opp_a_op(void)

Función que actualiza el valor de los operandos, dándoles los valores que hayan sido introducidos en el programa en ensamblador.

Page 111: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

112

Errores.cpp

void error (int,int,char *)

Función que se encarga de las del tratamiento de los errores encontrados durante el proceso de ensamblado. Puede ser llamada desde cualquier punto del programa ensamblador. El esquema de funcionamiento es el siguiente:

o Preparación del mensaje de error generado con un formato normalizado.

o Incremento de la variable global errores, que contabiliza el número de errores cometidos.

o Llama a las funciones MensajeErr( ) y flErr( ) que generan y almacenan los mensajes de error en variables AnsiString con un formato adecuado.

Parámetros: int tipo – variable entera que contiene el tipo de error

cometido. Existen 40 tipos diferentes de error diferentes.

int n_linea – variable entera que contiene el número de línea en que se ha cometido el error.

char *linea – variable string que contiene la línea de código original donde se ha cometido el error.

Func.cpp

char *coger_palabra(char *,char *,int *)

Función que coge la primera palabra de un string. Parámetros: char *line – puntero que apunta al string que contiene la línea

entera a la entrada. A la salida contendrá la línea a partir de la palabra siguiente.

char *palabra – puntero que apunta al string que contendrá la primera palabra de la línea.

int *label – puntero que apunta al entero que indicará si palabra es una etiqueta o no.

Retorno: Devuelve puntero al string line.

char *cogeyanal(char *,int *,int *,int *)

Función que devuelve como resultado un puntero al próximo carácter después del operando. Parámetros: char *line – puntero que apunta al string que contiene la línea

entera a la entrada. A la salida contendrá la línea a partir de la palabra siguiente.

int *err – puntero que apunta a un entero que contendrá el tipo

Page 112: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

113

de error cometido en la función. int *externo – puntero que apunta a una variable entera que

nos indicará si se trata de una etiqueta externa o no. Considera externas las etiquetas que no han podido ser resueltas durante el proceso.

int *aa – puntero que apunta a una variable entera que indicará el tipo de direccionamiento que utiliza el operando.

El tipo de direccionamiento puede ser:

1 = Registro direcciones 2 = Ind registro e índice 3 = Inmediato 4 = Registro Indirecto 5 = Predecremento 6 = Postincremento 7 = Registro datos 8 = Relativo al PC 9 = Relativo al PC con índice 10= Registro Ind. con offset 11= Dirección absoluta 12= CCR 13= SR 14= USP (+error =8)

Funciones varias de menor interés:

int tipo2( int,int,char *,char *)

int tipo3( int,int,char *)

int masde4bits( int)

int masde8bits( int)

int masde16bits( int)

int esta_en (char,char *s)

int hexdec(char *,int *)

int bindec(char *,int *)

static struct operando registro (char *,int)

Parser.cpp

static void coger_expresion( int *)

Función llamada para resolver una expresión. Es llamada por la función hallar_valor que inicializa el parser y lo prepara para funcionar correctamente. Parámetros: int *resultado - contiene el resultado de evaluar la expresión

Page 113: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

114

contenida en la variable global p.

static void nivel1(int *)

static void nivel2(int *)

static void nivel3(int *)

static void nivel4(int *)

static void nivel5(int *)

static void nivel6(int *)

Funciones que evalúan trozos de la expresión a evaluar teniendo en cuenta los niveles de prioridad algebraicos. Parámetros: int *resultado - contiene el resultado de evaluar la

expresión contenida en la variable global p.

static void primitiva(int *)

Función que utiliza las variables globales tipo_termino y termino para hallar el valor de termino. La variable tipo_termino debe ser o variable o número, en caso contrario hay un error de sintaxis en la expresión. Parámetros: int *resultado - Puntero a la variable que contendrá el

valor de término.

static void arit (char ,int *,int *)

Función que realiza una operación especificada en la variable o sobre los términos r y h . Esta operación debe ser una de las operaciones válidas implementadas en este parser. Parámetros: char o - En esta variable se debe especificar la operación a

realizar entre los dos términos. Debe tener uno de los siguientes valores:

+ , - , * , / , & , ^ , | , < ¢ > int *r - Primer término de la operación .En este término

quedará el resultado de la operación. int *h - Segundo término de la expresión.

static void unitario (char, int *)

Función que se utiliza para implementar el NOT y el cambio de signo. Parámetros: char o - En esta variable se debe especificar la operación a

realizar entre los dos términos. Debe tener uno de los siguientes valores: - ¢ !

int *r - Primer término de la operación. En este término quedará el resultado de la operación.

Page 114: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

115

static void coger_termino(void)

Función que se encarga de extraer uno a uno los términos que forman la expresión a evaluar. Extrae los términos de la expresión almacenada en p y los coloca en termino.

static esdelimitador(char)

Función que nos devuelve un 1 si el carácter que pasado como argumento es un delimitador y un 0 en caso contrario. Parámetros: char c - carácter a verificar .

static int valor(char *)

Función que halla el valor de un símbolo y el tipo de símbolo de que se trata. Parámetros: char *puntero - Puntero al string que contiene el nombre del

símbolo. Retorno: Devuelve el valor del símbolo .

int hallar_valor (char *palabra,int longitud,int *err,

int *reubicable,int *segunda_pasada)

Esta función es la función principal del parser ya que se trata de la función a la que se llama para resolver una expresión desde el exterior de este módulo. Se encarga de llamar a las distintas funciones del parser y de devolver el valor, los mensajes y los errores. Parámetros: char *palabra - Puntero al string que contiene la expresión a

evaluar. int longitud - Longitud de la expresión a evaluar. Esta

longitud es necesaria ya que palabra puede ser más larga y contener más caracteres de los que se desea evaluar.

int *err - Variable que contendrá el error cometido. int *reubicable - En esta variable se indica si el resultado es

reubicable o absoluto. int *externo - Aquí se indica si en la expresión hay algún

símbolo externo. Retorno: Devuelve el resultado de evaluar la expresión.

Page 115: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

116

c) Lnkdll.dll

Linker.cpp

EXPORT_IMPORT int Lnk68K(int,char **,char*,char*,char*)

Función principal de la DLL linkador. Se trata de un programa que linka una lista de ficheros objeto en una serie de pasos concretos. Parámetros: int n_objs - entero que contiene el número de ficheros objeto

contenidos en el array. char **array_objs - puntero a un array de cadenas de

caracteres que contienen el nombre de un fichero objeto y la dirección de memoria donde deben ser ensamblados (opcional).

char *fich_s28 – puntero al string que contiene el nombre del fichero de salida s28.

char *fich_map – puntero al string que contiene el nombre del fichero de salida map.

char *path – puntero al string que contiene la ruta de usuario. Esqueleto de la función:

o Para todos los ficheros objeto y si no se comete ningún error: a) Llama a la función cogerfichero( ). Esta función abre el

fichero especificado y comprueba una serie de posibles errores. Si existe un error se sale del bucle, en caso contrario sigue con la ejecución.

b) Crea un objeto struct lista. Se trata de un objeto que contiene la información necesaria sobre un fichero objeto. Varios objetos interconectados forman una estructura en lista ordenada.

c) Actualiza los campos del objeto creado con los datos recuperados del fichero objeto.

d) Si el fichero es reubicable, llama a la función cogerposicion( ). Esta función recupera la posición de memoria introducida por el usuario. En caso contrario considera al fichero absoluto.

e) Realiza un tratamiento de los segmentos mediante un bucle en el que se crea un nuevo objeto struct lista para cada segmento de código y se actualizan los campos con los datos necesarios.

o Llama a la función cogerfichero para los ficheros s28 y map. o Realiza una primera pasada por los ficheros objeto para colocar los

ficheros absolutos.

Page 116: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

117

o Realiza una segunda pasada para colocar los relativos o reubicables. o Recoge todas las etiquetas globales y locales, asigna un valor

absoluto a las etiquetas reubicables, verifica que no exista una repetición de etiquetas globales y recoge las etiquetas externas sin resolverlas.

o Verifica que todas las etiquetas externas tengan un emparejamiento con alguna etiqueta global de un fichero diferente.

o Realiza una lectura fichero a fichero mientras sustituye las etiquetas no resueltas en el ensamblador. Al mismo tiempo va creando el fichero de salida s28.

Las cuatro funciones siguientes preparan y presentan los mensajes que se generan en la DLL linkador y que deben presentarse en el programa interface:

EXPORT_IMPORT char* Lnk68K_Mensaje()

Función que puede ser llamada desde fuera de la DLL. Devuelve un string que contiene todos los mensajes informativos presentados durante la ejecución de la DLL.

EXPORT_IMPORT char* Lnk68K_MensajeErr()

Función que puede ser llamada desde fuera de la DLL. Devuelve un string que contiene todos los mensajes de error presentados durante la ejecución de la DLL.

void Mensaje(char*)

Función que añade un mensaje informativo nuevo al string que contiene todos los mensajes informativos presentados durante la ejecución de la DLL.

void MensajeErr(char*)

Función que añade un mensaje de error nuevo al string que contiene todos los mensajes error presentados durante la ejecución de la DLL.

static int cogerfichero(char *,int,int,char**,char*,char*,char*)

Función que realiza diversas tareas relacionadas con los ficheros de entrada y salida de la DLL en función de la variable entera tipo. Parámetros: char *f – puntero a un string que contendrá a la salida el

nombre del fichero abierto. int tipo – entero que contiene el tipo de fichero a comprobar.

si tipo=0à comprueba todos los ficheros y que no se repitan.

si tipo=3à f=fich_s28 y lo comprueba.

Page 117: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

118

si tipo=4à f=fich_map y lo comprueba.

int n_objs – entero que contiene el número de ficheros objeto del array.

char **array_objs – puntero a un array de punteros a strings que contienen el nombre de un fichero objeto y la dirección donde debe ser ensamblado (opcional).

char *fich_s28 – string que contiene el nombre del fichero de salida s28.

char *fich_map – string que contiene el nombre del fichero de salida map.

char *path – string que contiene la ruta de usuario. Retorno: Devuelve 1 si todo funciona correctamente y 0 en caso de

errores.

static void insertarabs(struct lista *)

static void insertarreu(struct lista *)

static void listar(struct lista *)

Función que imprime la lista de ficheros objeto y segmentos dentro del fichero map con un formato específico.

static void listar_arbol (struct etiqueta *)

Función que imprime la estructura de árbol binario que contiene objetos struct etiqueta dentro del fichero map.

static void comprobar_externas(struct etiqueta *)

Función que comprueba que todas las etiquetas externas tengan emparejamiento con una etiqueta global de otro fichero objeto.

static void s28(char *)

static void volcars28(void)

static void nexit(int,char *)

static void sexit(void)

static int buscarlista(struct lista *,char *)

Page 118: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

119

Función recursiva que busca un determinado fichero en una lista ordenada de objetos struct lista.

static int insertar_etiqueta(struct etiqueta **,char *,char *)

Función que inserta un objeto struct etiqueta en una estructura de árbol binario. Actualiza los campos nombre y valor del objeto.

static int checksum(char*)

static int cogerposicion(char**)

Función que consigue la posición de memoria en caso de que el fichero objeto sea reubicable.

static struct etiqueta *buscar_etiqueta(struct etiqueta *,char *)

static int esta_en (char,char *)

int hex_dec(char *)

Función que convierte una expresión hexadecimal en una cifra decimal.

int lee_linea(char *,FILE *)

Parserl.cpp

int hallar_valor (char *puntero,int *)

Esta función es la función principal del parser ya que se trata de la función a la que se llama para resolver una expresión desde el exterior de este módulo. Se encarga de llamar a las distintas funciones del parser y de devolver el valor, los mensajes y los errores. Parámetros: char *palabra - Puntero al string que contiene la expresión a

evaluar. int *err - Variable que contendrá el error cometido.

Retorno: Devuelve el resultado de evaluar la expresión.

int buscar_etiqueta_global(struct etiqueta *,char *)

Función que realiza una búsqueda de una determinada etiqueta global en una estructura de árbol binario.

struct etiqueta *buscar_etiqueta_local(struct etiqueta *,char *)

Page 119: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

120

Función que realiza una búsqueda de una determinada etiqueta local en una estructura de árbol binario.

static void coger_expresion(int *)

Función llamada para resolver una expresión. Es llamada por la función hallar_valor que inicializa el parser y lo prepara para funcionar correctamente. Parámetros: int *resultado - contiene el resultado de evaluar la expresión

contenida en la variable global p.

static void nivel1( int *)

static void nivel2( int *)

static void nivel3( int *)

static void nivel4( int *)

static void nivel5( int *)

static void nivel6( int *)

Funciones que evalúan trozos de la expresión a evaluar teniendo en cuenta los niveles de prioridad algebraicos. Parámetros: int *resultado - contiene el resultado de evaluar la

expresión contenida en la variable global p.

static void primitiva( int *)

Función que utiliza las variables globales tipo_token y token para hallar el valor de token. La variable tipo_token debe ser o variable o número, en caso contrario hay un error de sintaxis en la expresión. Parámetros: int *resultado - Puntero a la variable que contendrá el

valor de token.

static void arit (char , int *, int *)

Función que realiza una operación especificada en la variable o sobre los términos r y h . Esta operación debe ser una de las operaciones válidas implementadas en este parser. Parámetros: char o - En esta variable se debe especificar la operación a

realizar entre los dos términos. Debe tener uno de los siguientes valores:

+ , - , * , / , & , ^ , | , < ¢ > int *r - Primer término de la operación .En este término

quedará el resultado de la operación.

Page 120: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

121

int *h - Segundo término de la expresión.

static void unitario (char, int *)

Función que se utiliza para implementar el NOT y el cambio de signo. Parámetros: char o - En esta variable se debe especificar la operación a

realizar entre los dos términos. Debe tener uno de los siguientes valores: - ¢ !

int *r - Primer término de la operación. En este término quedará el resultado de la operación.

static void coger_token(void)

Función que se encarga de extraer uno a uno los términos que forman la expresión a evaluar. Extrae los términos de la expresión almacenada en p y los coloca en token.

static esdelimitador(char)

Función que nos devuelve un 1 si el carácter que pasado como argumento es un delimitador y un 0 en caso contrario. Parámetros: char c - carácter a verificar .

static int valor(char *)

Función que halla el valor de un símbolo y el tipo de símbolo de que se trata. Parámetros: char *puntero - Puntero al string que contiene el nombre del

símbolo. Retorno: Devuelve el valor del símbolo .

Page 121: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

122

3 CONCLUSIONES

La realización del presente proyecto era necesaria desde un punto de vista de compatibilidad con la mayoría de computadoras, puesto que la gran mayoría utilizan en la actualidad sistemas operativos tipo Windows de Microsft en sus diferentes versiones. El programa del proyecto es portable y funciona sobre cualquier plataforma Windows. Otra ventaja a tener en cuenta es que al ser Windows un sistema operativo multitarea, se pueden tener múltiples tareas en activo además del presente programa. El programa del proyecto integra en el interface principal de la aplicación los programas editor, ensamblador, linkador, simulador y programa de comunicaciones, siendo los dos últimos programas externos al proyecto. La aplicación ha sido diseñada en una estructura con programa principal, llamadas a DLL y llamadas a ficheros ejecutables. El esqueleto de la aplicación es el siguiente:

Interface (Editor+Plataforma) àSimulador (exe)

àComunicaciones (exe)

⇔Ensamblador (dll)

⇔Linkador (dll)

Figura 17 – Esqueleto de la aplicación

Todos los programas de la aplicación han sido diseñados para trabajar con la ruta de usuario almacenada en el registro de Windows. El tamaño del path ha sido limitado a 100 caracteres.

Se procede a continuación a detallar las capacidades y las limitaciones de los programas que integran el presente proyecto:

Page 122: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

123

a) Editor:

El programa ha sido desarrollado como un editor de texto especial para código fuente. Soporta cualquier formato de fichero de texto, aunque propone algunos formatos predeterminados (txt, asm, obj, lst).

El programa editor ha sido creado como una herramienta de tratamiento de

código fuente basada en la simplicidad y la facilidad de manejo. Por lo tanto, contiene las opciones básicas de un editor de texto como Nuevo, Abrir, Guardar y Cerrar. Mediante la acción en los botones respectivos a las opciones anteriores, el programa es capaz de trabajar con múltiples documentos al mismo tiempo, alternando entre ellos con una simple acción del mouse en las pestañas en la parte inferior.

El usuario del programa puede cometer un grave error cerrando un

documento sin guardarlo en memoria previamente. Este despiste supondría la pérdida de la información no almacenada en memoria. Se ha previsto el posible error presentando el diálogo guardar automáticamente cuando el usuario trata de cerrar un documento modificado y no guardado.

El programa incluye las herramientas Imprimir y Arreglar. La herramienta

Imprimir presenta la información contenida en el documento mediante los métodos de la función Printer(). Ésta función global comunica a las aplicaciones de Windows con el software relacionado a la impresora, es decir, con los drivers. Los controladores de la impresora no reconocen los símbolos de tabulación ni retorno de carro como lo hacen los editores de texto convencionales. La solución adoptada ha sido tratar el texto para la impresión línea a línea. El programa contabiliza el número de líneas recorridas (introduciendo saltos de página cuando sea necesario), recorre el texto en busca de símbolos de tabulación (que sustituye por los caracteres correspondientes) y añade las líneas tratadas al documento de impresión. Cuando el programa no encuentra más líneas en el texto, se llama a la función Printer( )àEndDoc( ), que indica el final de la configuración de impresión y envía el documento a la impresora. La capacidad máxima de una hoja imprimida son 60 líneas de código. El programa solamente imprimirá los 77 primeros caracteres de cada línea. En caso que una línea supere la longitud máxima, la línea se cortará y la información sobrante no se imprimirá. La herramienta Arreglar da un formato específico al texto contenido en el documento. Trata al código fuente de una forma personalizada. Esta herramienta se activa automáticamente cuando el usuario acciona el mouse sobre los botones Abrir, Guardar o Arreglar. El programa inicializa algunas propiedades del objeto TRichEdit para tratar el texto. Un bucle recorre el texto línea por línea y llama a la función TestLinea. Se trata de una función que mediante un largo y

Page 123: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

124

complejo proceso pone en negrita las palabras clave del lenguaje ensamblador y pone en color azul los comentarios. En este punto se identifica una de las carencias de escasa importancia del programa editor. El tratamiento del formato del texto debería ser instantáneo, es decir, que el programa debería dar un formato a las palabras clave y comentarios al mismo tiempo que el usuario escribe el texto. Existen dos métodos diferentes para realizar el tratamiento instantáneo, aunque ambos tienen inconveniencias para la finalidad del presente proyecto:

- Realizar un recorrido de todo el texto cada vez que el usuario oprime una tecla. El programa identifica todas las palabras del texto individualmente y las compara con las palabras clave del ensamblador contenidas en una tabla (pone en negrita). El programa identifica los comentarios y los visualiza en color azul. Un recorrido del texto en cada tecleo del usuario no permite una visibilidad correcta del texto para documentos de tamaño medio y grande. Una posible solución basada en el recorrido del texto es imponer un período de refresco constante, es decir, se puede efectuar un recorrido cada 5 segundos. Se trata de una solución poco elegante y de una relativa complejidad.

- Comprobar las palabras anterior y posterior al cursor en cada tecleo del usuario. Se trata de una solución demasiado compleja para la importancia de la herramienta Arreglar en el programa.

b) Ensamblador:

Este programa ensambla un fichero fuente (asm) en los ficheros de salida objeto (obj) y listado (lst). El fichero objeto contiene las instrucciones ensambladas en código máquina encabezadas con datos generales del código. El fichero listado contiene un resumen completo del proceso de ensamblado. No existe una limitación real en la longitud de los nombres de los ficheros implicados. Se recomienda el uso de cadenas de 12 caracteres como máximo.

El ensamblador permite el uso de macros en el código fuente. Para ello se ha

programado una tercera pasada (la pasada cero) que trata las definiciones de macro y las llamadas a macro. Se almacenan las macros definidas en un árbol binario y se expanden con los valores adecuados cada vez que son llamadas. A continuación se presenta una lista de las limitaciones más importantes en el uso de macros (explicadas en apartado macros):

• Anidamiento de macros no permitido: El programa ensamblador trata las expansiones de código de las macros en la pasada cero. En el caso de que se tratara de una macro anidada (es decir, que tuviera llamadas a macro en su interior), las macros anidadas (hijas) no serían expandidas. Este fenómeno ocurre puesto que la pasada cero expande el código de la

Page 124: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

125

macro madre y no comprueba la aparición de nuevas macros. Una posible solución a este problema es la creación de un bucle de pasada cero, es decir, que se ejecute la pasada inicial en múltiples ocasiones hasta que el programa no encuentre ninguna llamada a macro. Sin embargo, esta solución complica la programación excesivamente sin ser un punto importante el anidamiento de macros en el laboratorio de DEEEA.

• Definición al inicio: Cuando el programa encuentra una llamada a

macro, éste busca el objeto macro en el árbol binario de símbolos y macros. En caso de no encontrar el objeto lanza un mensaje de error. Por esta razón, la definición de una macro determinada debe situarse antes de las llamadas a la macro. Se aconseja la definición de todas las macros del programa en el encabezamiento del fichero fuente.

• Número máximo de argumentos pasados a una macro limitado a 99.

• El programa ensamblador limita la longitud de las etiquetas en 8

caracteres. Sin embargo, el uso de labels inside en las macros (explicado en apartado macros) limita el tamaño de estas etiquetas interiores a 6 caracteres.

• Los mensajes de error de la ventana de errores en el ensamblador tienen

un formato de fuente normal, cuando el color de los errores debería ser presentado en rojo. No se ha implementado este detalle puesto que se ha utilizado un objeto de la clase TListBox para gestionar los mensajes de error. Este tipo de objetos no permite la modificación de la fuente de las cadenas de caracteres que contiene. Se ha utilizado este componente para implementar la herramienta de localizar un error determinado en el editor con un simple doble-click en el mensaje de error desde la ventana de ensamblador.

c) Linkador:

Este programa linka un conjunto de ficheros objeto (obj) en los ficheros de

salida para la máquina (s28) y mapa (map). El fichero objeto contiene las instrucciones ensambladas en código máquina de cada fichero fuente encabezadas por los datos generales del código (número de segmentos, código absoluto/relativo...). El fichero s28 es el fichero final del proceso y contiene el conjunto de ficheros objetos enlazados (linkados) y colocados en una posición de memoria determinada. El fichero map contiene un resumen de los segmentos de código y un listado de las etiquetas del programa. No existe una limitación real en la longitud de los nombres de los ficheros implicados. Se recomienda el uso de cadenas de 12 caracteres como máximo.

Page 125: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

126

Existe una limitación en el número de ficheros objeto linkados en un mismo

proyecto. Se pueden linkar 20 ficheros objeto como máximo en un fichero s28. Esto ocurre porque el programa prepara un array de punteros a carácter, es decir, de cadenas de caracteres. Éste array se pasa como argumento a la DLL linkador, y un argumento debe estar totalmente definido.

Los programas ensamblador y linkador ofrecen al usuario (programador del

microcontrolador) la posibilidad de crear código absoluto o reubicable mediante el uso de las directivas de ensamblador absolute o relative respectivamente. El entorno ofrece las siguientes posibilidades:

a) Código absoluto con posición predeterminada: el código contiene la directiva absolute acompañada de la directiva org/origin. Las etiquetas se han compilado de forma absoluta en el ensamblador. El programa hace caso omiso al campo @ introducido por el usuario. b) Código absoluto sin posición predeterminada: el código contiene la directiva absolute pero no aparece la directiva org/origin. Combinación imposible. c) Código reubicable con posición predeterminada: el código contiene la directiva relative seguida de la palabra clave org/origin. Combinación imposible. d) Código reubicable sin posición predeterminada con campo @: el programa ha compilado las etiquetas del fichero fuente de forma relativa, es decir, en función del inicio del programa. El linkador toma el campo @ como dirección de inicio del programa. e) Código reubicable sin posición predeterminada sin campo @: el programa ha compilado las etiquetas del fichero fuente de forma relativa, es decir, en función del inicio del programa. El linkador debe buscar una sector de memoria libre donde ubicar el código ensamblado. Busca la dirección de inicio del programa. Esta posibilidad del linkador no se ha implementado correctamente, es decir, no puede ser utilizada por el usuario.

Inicialmente, el último punto no fue implementado correctamente en el

programa linkador original. La limitada utilidad de la combinación para los objetivos de los laboratorios del DEEEA y la innecesaria complicación del proyecto para su implementación han sido las razones más importantes por las que no se han solucionado los problemas relacionados con este punto.

Page 126: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

127

d) Procesador de proyectos:

Esta herramienta integrada en el paquete de programación permite el tratamiento de un fichero de proyecto. El ensamblado y linkado de este fichero provocan el ensamblado de todos los ficheros fuente que componen el proyecto y el linkado de suss respectivos ficheros objeto.

El procesador de proyectos no presenta ninguna limitación adicional en el

linkado de ficheros objeto, sin embargo el número de ficheros fuente que componen el proyecto está limitado a 20, provocando un error de linkado en caso de ser el número superior.

Page 127: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

128

4 PLIEGO DE CONDICIONES

4.1. CONDICIONES GENERALES

· El presente pliego de condiciones tiene como objetivo definir a la empresa programadora el alcance del trabajo y la ejecución cualitativa del mismo. · El trabajo informática consistirá en la creación del programa y todas las pruebas oportunas para asegurar la fiabilidad del mismo. · El alcance del trabajo de las empresa Programadora incluye el diseño y preparación de todo el material necesario para la adquisición e instalación del programa. 4.1.2. REGLAMENTOS Y NORMAS. Todas las unidades del programa se ejecutarán cumpliendo las prescripciones

indicadas en los Reglamentos y Normas Técnicas de obligado cumplimiento para este tipo de instalaciones, tanto de ámbito nacional, autonómico como municipal, así como, todas las otras que se establezcan en la Memoria Descriptiva.

Se adaptarán además, a las presentes condiciones particulares que complementarán las

indicadas por los Reglamentos y Normas citadas. 4.1.3. EJECUCION DEL PROGRAMA. 4.1.3.1. COMIENZO: La Empresa Programadora comenzará a crear el programa en el termino que figura en

el contrato establecido con la Empresa Usuaria, o en su defecto a los quince días de la adjudicación definitiva o la firma del contrato.

la Empresa Programadora está obligada a notificar por escrito o personalmente en

forma directa a la Empresa Usuaria la fecha de comienzo de la realización del Programa. 4.1.3.2. PLAZO DE EJECUCIÓN: El programa se ejecutará en el terminio que se estipule en el contrato suscrito con la Empresa Usuaria o en su defecto en el que figure en las condiciones de este pliego. Cuando la Empresa Programadora, de acuerdo, con alguno de los extremos contenidos

en el presente Pliego de Condiciones, o bien en el contrato establecido con la Empresa Usuaria, solicite una inspección para poder realizar algún trabajo ulterior que esté

Page 128: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

129

condicionado por la misma, vendrá obligada a tener preparada para dicha inspección, una cantidad de obra que corresponda a un ritmo normal de trabajo.

Cuando el ritmo de trabajo establecido por el Contratista, no sea normal, o bien a

petición de una de las partes, se podrá convenir una programación de inspecciones obligatorias de acuerdo con el plan de obra.

4.1.4. INTERPRETACIÓN Y DESARROLLO DEL PROGRAMA. La interpretación técnica del Programa, corresponde al Técnico Director. La Empresa

Programadora está obligada a someter a éste a cualquier duda, aclaración o contradicción que surja durante la ejecución de¡ Programa por causa de una mala interpretación, o circunstancias ajenas, siempre con la suficiente antelación en función de la importancia del asunto.

La Empresa Programadora se hace responsable de cualquier error de la ejecución

motivada por la omisión de ésta obligación y consecuentemente deberá rehacer a su costa los trabajos que correspondan a la correcta interpretación del Proyecto.

La Empresa Programadora está obligada realizar todo cuanto se necesario para la

buena ejecución del Programa, aún cuando no se halle explícitamente expresado en el Pliego de Condiciones o en los documentos del Proyecto.

La Empresa Programadora notificará por escrito o personalmente en forma directa al

Técnico Director y con suficiente antelación las fechas en que quedarán preparadas para inspección, cada una de las partes de¡ Programa para las cuales se ha indicado la necesidad o conveniencia de las mismas.

4.1.5. TRABAJOS COMPLEMENTARIOS. La Empresa Programadora tiene la obligación de realizar todos los trabajos

complementarios que sean indispensables para ejecutar cualquier parte del Programa especificadas en cualquiera de los documentos del Proyecto, aunque en el, no figuren explícitamente mencionadas dichos trabajos complementarios. Todo ello sin variación del importe contratado.

4.1.6. MODIFICACIONES. La Empresa Programadora está obligada a realizar los trabajos que se le encarguen

resultantes de modificaciones del Programa, tanto en aumento como disminución o

Page 129: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

130

simplemente variaciones, siempre y cuando el importe de las mismas no altere en más o menos de un 25% del valor contratado.

La valoración de las mismas se hará de acuerdo, con los valores establecidos en el

presupuesto entregado por la Empresa Programadora y que ha sido tomado como base del contrato. El Técnico Director del Programa está facultado para introducir las modificaciones de acuerdo con su criterio, en cualquier parte del Programa, durante la creación, siempre que cumplan las condiciones técnicas referidas en el Proyecto y de modo que ello no varíe el importe total del Programa.

4.1.7. PROGRAMA DEFECTUOSO. Cuando la Empresa Programadora halle cualquier parte del Programa defectuosa que

no se ajuste a lo especificado en el Proyecto o en este Pliego de Condiciones, el Técnico Director podrá aceptarlo o rechazarlo; en el primer caso, éste fijará el precio que crea justo con arreglo a las diferencias que hubiera, estando obligada la Empresa Programadora a aceptar dicha valoración, en el otro caso, se reconstruirá a expensas de la Empresa Programadora la parte mal ejecutada sin que ello sea motivo de reclamación económica o de ampliación del plazo de ejecución.

4.1.8. MEDIOS AUXILIARES Serán de la Empresa Programadora todos los medios y máquinas auxiliares que sean

necesarias para la ejecución del Programa. 4.1.9. CONSERVACIÓN DEL PROGRAMA. Es obligación de la Empresa Programadora la conservación en perfecto estado del

programa hasta la fecha de recepción definitiva por la Empresa Usuaria, y corren a su cargo los gastos derivados de ello.

4.1.10. RECEPCIÓN DEL PROGRAMA. 4.1.10.1. RECEPCIÓN PROVISIONAL: Una vez terminado el Programa, tendrá lugar la recepción provisional y para ello se

practicará en ellas un detenido reconocimiento por el Técnico Director y la Empresa Usuaria en presencia de la Empresa Programadora, levantando acta y empezando a correr desde ese día el plazo de garantía si se halla en estado de ser admitido.

De no ser admitido se hará constar en el acta y se darán instrucciones a la Empresa

Programadora para subsanar los defectos observados, fijándose un plazo para ello, expirando el cual se procederá a un nuevo reconocimiento a fin de proceder a la recepción provisional.

Page 130: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

131

4.1.10.2. LICENCIA Y DERECHOS. Una vez efectuada la recepción provisional se le entregará a la Empresa Usuaria una

licencia de derecho de uso del programa, una copia del Programa y un Manual de Instalación y Uso. Esta licencia da derecho a instalar el programa en un ordenador. Por cada licencia de derecho de uso que se disponga, sólo puede haber una copia en uso, es decir instalada en un ordenador.

No se podrá copiar, instalar en otro ordenador, ejecutar en público o aiq ' uilar la copia entregada del programa sin la previa autorización de la Empresa Programadora. Si se quiere instalar el Programa en otro ordenador se tendrá que desinstalar previamente del primero.

El Programa solo se puede vender, tal cual, sin modificarlo, completamente con la

licencia de derecho de uso del Programa, la copia del Programa y el Manual de Instalación y Uso.

4.1.10.3. PLAZO DE GARANTÍA. El plazo de garantía será como mínimo de un año, contado desde la fecha de la

recepción provisional, o bien el que se establezca en el contrato también contado desde la misma fecha. Durante este período queda a cargo de la Empresa Programadora la conservación del Programa y el arreglo de los errores observados.

4.1.10.4. RECEPCIÓN DEFINITIVA. Se realizará después de transcurrido el plazo de garantía de igual forma que la

provisional. A partir de esta fecha cesará la obligación de la Empresa Programadora de conservar y reparar a su cargo los defectos observados.

4.1.11. CONTRATACIÓN DE LA EMPRESA PROGRAMADORA. 4.1.1 1.1. MODO DE CONTRATACIÓN. El conjunto del Programa lo realizará la empresa escogida por concurso-subasta. 4.1.11.2. PRESENTACIÓN. Las empresas seleccionadas para dicho concurso deberán presentar sus proyectos en

sobre lacrado, antes del 15 de Febrero de 2002 en el domicilio de la Empresa Usuaria.

Page 131: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

132

4.1.11.3. SELECCIÓN. La empresa escogida será anunciada la semana siguiente a la conclusión del plazo de

entrega. Dicha empresa será escogida de mutuo acuerdo entre la Empresa Usuaria y el Director Técnico, sin posible reclamación por parte de las otras empresas concursantes.

4.1.12. FIANZA. En el contrato se establecerá la fianza que la Empresa Programadora deberá depositar

en garantía del cumplimiento de¡ mismo, o, se convendrá una retención sobre los pagos realizados a cuenta de Programa realizado.

De no estipularse la fianza en el contrato se entiende que se adopta como garantía una

retención del 5% sobre los pagos a cuenta citados. En el caso de que la Empresa Programadora se negase a hacer por su cuenta los

trabajos para ultimar el Programa en las condiciones contratadas, o a atender la garantía, la Empresa Usuaria podrá ordenar ejecutarlas a un tercero, abonando su importe con cargo a la retención o fianza, sin perjuicio de las acciones legales a que tenga derecho la Empresa Usuaria si el importe de la fianza no bastase.

La fianza retenida se abonará a la Empresa Programadora en un plazo no superior a

treinta días una vez firmada el acta de recepción definitiva del Programa.

4.2 CONDICIONES ECONÓMICAS

4.2.1. ABONO DEL PROGRAMA. En el contrato se deberá fijar detalladamente la forma y plazos que se abonarán las

partes realizadas del Programa. Las liquidaciones parciales que puedan establecerse tendrán carácter de documentos provisionales a buena cuenta, sujetos a las certificaciones que resulten de la liquidación final. No suponiendo, dichas liquidaciones, aprobación ni recepción del trabajo que comprenden.

Terminado el Programa se procederá a la liquidación final que se efectuará de acuerdo

con los criterios establecidos en el contrato. 4.2.2. PRECIOS. La Empresa Programadora presentará, al formalizarse el contrato, relación de los

precios de las unidades del Programa que integran el proyecto, los cuales de ser aceptados tendrán valor contractual y se aplicará a las posibles variaciones que puedan haber.

Page 132: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

133

Estos precios unitarios, se entiende que comprenden la ejecución total de la unidad del

Programa, incluyendo todos los trabajos aún los complementarios y los materiales así como la parte proporcional de imposición fiscal, las cargas laborales y otros gastos repercutibles.

En caso de tener que realizarse unidades de Programa no previstas en el proyecto, se

fijará su precio entre el Técnico Director y la Empresa Programadora antes de iniciar el Programa y se presentará a la Empresa Usuaria para su aceptación o no.

4.2.3. REVISIÓN DE PRECIOS. En el contrato se establecerá si la Empresa Programadora tiene derecho a revisión de

precios y la fórmula a aplicar para. calcularla. En defecto de esta última, se aplicará a juicio del Técnico Director alguno de los criterios oficiales aceptados.

4.2.4. PENALIZACIONES. Por retraso en los plazos de entrega de¡ Programa, se podrán establecer tablas de

penalización cuyas cuantías y demoras se fijarán en el contrato. 4.2.5. CONTRATO. El contrato se formalizará mediante documento privado, que podrá elevarse a escritura

pública a petición de cualquiera de las partes. Comprenderá la adquisición de todos los materiales, transporte, mano de obra, medios auxiliares para la ejecución del Programa proyectado en el plazo estipulado, así como la reconstrucción de las unidades defectuosas, la realización de las partes complementarias y las derivadas de las modificaciones que se introduzcan durante la ejecución, éstas últimas en los términos previstos.

La totalidad de los documentos que componen el Proyecto Técnico del Programa serán

incorporados al contrato y tanto el contratista como la Empresa Usuaria deberá firmarlos en testimonio de que los conocen y aceptan.

4.2.6. RESPONSABILIDADES. La Empresa Programadora es la responsable de la ejecución del Programa en las

condiciones establecidas en el proyecto y en el contrato. Como consecuencia de ello vendrá obligado a la eliminación de lo mal ejecutado y a su reconstrucción correctamente sin que sirva de excusa el que el Técnico Director haya examinado y reconocido el Programa.

La Empresa Programadora es la única responsable de todas las contravenciones que

ella o su personal cometan durante la ejecución del Programa u operaciones relacionadas

Page 133: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

134

con el mismo. También es responsable de los daños que por errores, inexperiencia o empleo de métodos inadecuados se produzcan en la Empresa Usuaria.

la Empresa Programadora es la única responsable del incumplimiento de las

disposiciones vigentes en la materia laboral respecto de su personal. 4.2.7. RESCISIÓN DEL CONTRATO 4.2.7.1. CAUSAS DE RESCISIÓN. Se consideraran causas suficientes para la rescisión del contrato las siguientes: · Primero: Muerte o incapacitación de La Empresa Programadora. · Segunda: La quiebra de la Empresa Programadora. · Tercera: Modificación del proyecto cuando produzca alteración en más o menos 25% del valor contratado. · Cuarta: Modificación de las unidades de Programa en número superior al 40% del original. · Quinta : La no iniciación de la programación en el plazo estipulado cuando sea por causas ajenas a la Empresa Programadora. · Sexta : La suspensión de la programación ya iniciada siempre que el plazo de suspensión sea mayor de seis meses. · Séptima: Incumplimiento de las condiciones del Contrato cuando implique mala fe. · Octava : Terminación del plazo de ejecución del Programa sin haberse llegado a completar éste. · Novena : Actuación de mala fe en la ejecución de los trabajos. · Décima: Destajar o subcontratar la totalidad o parte del Programa a terceros sin la autorización del Técnico Director y la Empresa Usuaria. 4.2.8. LIQUIDACIÓN EN EL CASO DE RESCISIÓN DEL CONTRATO. Siempre que se rescinda el Contrato por causas anteriores o bien por acuerdo de ambas

partes, se abonará a la Empresa Programadora las unidades de Programa ya terminadas. Cuando se rescinda el contrato llevará implícito la retención de la fianza para obtener

los posibles gastos de conservación de el período de garantía y los derivados del mantenimiento hasta la fecha de nueva adjudicación.

Page 134: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

135

4.3 CONDICIONES FACULTATIVAS

4.3.1. PERSONAL. La Empresa Programadora tendrá al frente de la realización del Programa un

encargado con autoridad sobre los demás operarios y conocimientos acreditados y suficientes para la ejecución del Programa.

El encargado recibirá, cumplirá y transmitirá las instrucciones y ordenes del Técnico

Director de la obra. La Empresa Programadora tendrá el número y clase de operarios que haga falta para el

volumen y naturaleza de los trabajos que se realicen, los cuales serán de reconocida aptitud y experimentados en el oficio. La Empresa Programadora estará obligada a separar de la programación, a aquel personal que a juicio del Técnico Director no cumpla con sus obligaciones, realice el trabajo defectuosamente, bien por falta de conocimientos o por obrar de mala fe.

4.4 CONDICIONES TÉCNICAS

4.4.1. REQUERIMIENTOS DE HARDWARE Para que el Programa pueda funcionar con cierta agilidad se aconseja tener como

mínimo el siguiente Hardware: PC 486 con coprocessador a 66 Mhz como mínimo 8 Mb de RAM como mínimo 3 Mb

de espacio libre en el disco duro. Ratón Microsoft o compatible.

Monitor SVGA con una resolución de 800 * 600 píxeles como mínimo.

4.4.2. REQUERIMIENTOS DE SOFTWARE Para que pueda funcionar el Programa se tendrá que tener instalado en el ordenador

como mínimo el Software siguiente con sus respectivas licencias. · Microsoft Windows 95 o posterior.

Page 135: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

136

5 ANEXOS

5.1 CÓDIGO DEL PROGRAMA

Page 136: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

ANEXO 1:

CÓDIGO DEL PROGRAMA

Page 137: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

2

INDICE DE FICHEROS DE CÓDIGO:

Interfens.exe ............................................................................................................................3

Interfens.cpp.......................................................................................................................3 Principal.cpp ......................................................................................................................4 Principal.h ........................................................................................................................13 Edit.cpp ............................................................................................................................16 edit.h .................................................................................................................................19 RutaDlg.cpp .....................................................................................................................20

ensdll.dll.................................................................................................................................21

ensdll.bpf..........................................................................................................................21 ensdll.cpp .........................................................................................................................21 ensdll.h .............................................................................................................................22 ens68k.cpp........................................................................................................................23 ENS.h ...............................................................................................................................36 macros.h ...........................................................................................................................37 tabla.cpp ...........................................................................................................................38 arboles.cpp .......................................................................................................................60 func.cpp............................................................................................................................65 errores.cpp........................................................................................................................77 parser.cpp .........................................................................................................................79

lnkdll.dll.................................................................................................................................86

lnkdll.bpf..........................................................................................................................86 Lnkdll.cpp ........................................................................................................................86 lnkdll.h..............................................................................................................................86 linker.cpp..........................................................................................................................87 linker.h............................................................................................................................100 parserl.cpp......................................................................................................................101

Page 138: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

3

Interfens.exe

Interfens.cpp //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop USERES("interfens.res"); USEFORM("Principal.cpp", Interf_form); USELIB("lnkdll.lib"); USELIB("ensdll.lib"); USEUNIT("edit.cpp"); USEFORM("RutaDlg.cpp", RutaDialog); //--------------------------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { try { Application->Initialize(); Application->CreateForm(__classid(TInterf_form), &Interf_form); Application->CreateForm(__classid(TRutaDialog), &RutaDialog); Application->Run(); } catch (Exception &exception) { Application->ShowException(&exception); } return 0; } //---------------------------------------------------------------------------

Page 139: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

4

Principal.cpp //----------------------------------------------------------------------- #include <vcl.h> #include <stdio.h> #include <process.h> #include <errno.h> #include <dir.h> #pragma hdrstop #pragma package(smart_init) #pragma resource "*.dfm" //----------------------------------------------------------------------- #include "..\Interface\RutaDlg.h" #include "..\Interface\Principal.h" #include "..\Ensamblador\ensdll.h" #include "..\Linkador\lnkdll.h" #include "..\Interface\edit.h" //----------------------------------------------------------------------- TInterf_form *Interf_form; TEditASM *editasm; AnsiString Ruta; int flag=0; //----------------------------------------------------------------------- // FUNCIONES DE INTERF_FORM ----------------------------- //----------------------------------------------------------------------- //Contructor. Inicio programa. Crea una lista para el editor. __fastcall TInterf_form::TInterf_form(TComponent* Owner) : TForm(Owner) { Lista_Ed=new TList(); //TAMAÑOS Y CONFIGURACIONES Interf_form->Linea->Left=Interf_form->PanelB->Width+Interf_form->Panel_CtrlEd->Width-65; Interf_form->nlinea->Left=Interf_form->PanelB->Width+Interf_form->Panel_CtrlEd->Width-15; Interf_form->LnkMns->Left=20; Interf_form->LnkErr->Left=20; Interf_form->LnkMns->Top=Interf_form->Paginas->Height*1/3-30; Interf_form->LnkErr->Top=Interf_form->Paginas->Height*2/3-15; Interf_form->LnkMns->Width=Interf_form->Paginas->Width-40; Interf_form->LnkErr->Width=Interf_form->Paginas->Width-40; Interf_form->LnkMns->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->LnkErr->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->EnsMns->Left=20; Interf_form->EnsErr->Left=20; Interf_form->EnsMns->Top=Interf_form->Paginas->Height*1/3-30; Interf_form->EnsErr->Top=Interf_form->Paginas->Height*2/3-15; Interf_form->EnsMns->Width=Interf_form->Paginas->Width-40; Interf_form->EnsErr->Width=Interf_form->Paginas->Width-40; Interf_form->EnsMns->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->EnsErr->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->Label9->Top=Interf_form->LnkMns->Top-15; Interf_form->Label10->Top=Interf_form->LnkErr->Top-15; Interf_form->Label9->Left=Interf_form->LnkMns->Left+Interf_form->LnkMns->Width-150; Interf_form->Label10->Left=Interf_form->LnkErr->Left+Interf_form->LnkErr->Width-135; Interf_form->Label11->Top=Interf_form->EnsMns->Top-15; Interf_form->Label12->Top=Interf_form->EnsErr->Top-15; Interf_form->Label11->Left=Interf_form->EnsMns->Left+Interf_form->LnkMns->Width-185; Interf_form->Label12->Left=Interf_form->EnsErr->Left+Interf_form->LnkErr->Width-170; //Cargar el path de usuario del registro o guardar el path por defecto (1a vez) TRegistry *Registro = new TRegistry; try

Page 140: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

5

{ Registro->RootKey = HKEY_CURRENT_USER; Registro->OpenKey("\\SOFTWARE\\TM683",true); if (!Registro->ValueExists("Ruta")) //no existe --> crea y guarda ruta por defecto en

registro { Ruta="c:\\TM683\\Usuario\\"; Registro->WriteString("Ruta",Ruta); } else //existe { Ruta=Registro->ReadString("Ruta"); } } __finally //al acabar pasa por aqui (con/sin excep's) { delete Registro; } //Actualizar los directorios de OpenDialog y SaveDialog (editor) OpenDialog->InitialDir=Ruta; SaveDialog->InitialDir=Ruta; } //--------------------------------------------------------------------------- //Destructor. Fin programa. Elimina la lista (libera memoria) __fastcall TInterf_form::~TInterf_form() { int j; for(j=0; j<Lista_Ed->Count; j++) delete Lista_Ed->Items[j]; delete Lista_Ed; } //--------------------------------------------------------------------------- //Pagina de presentacion al entrar en programa void __fastcall TInterf_form::FormCreate(TObject *Sender) { Paginas->PageIndex=0; } //--------------------------------------------------------------------------- //Modifica dimensiones cuando hacemos resize de la ventana principal. void __fastcall TInterf_form::FormResize(TObject *Sender) { Interf_form->Linea->Left=Interf_form->PanelB->Width+Interf_form->Panel_CtrlEd->Width-65; Interf_form->nlinea->Left=Interf_form->PanelB->Width+Interf_form->Panel_CtrlEd->Width-15; Interf_form->LnkMns->Left=20; Interf_form->LnkErr->Left=20; Interf_form->LnkMns->Top=Interf_form->Paginas->Height*1/3-30; Interf_form->LnkErr->Top=Interf_form->Paginas->Height*2/3-15; Interf_form->LnkMns->Width=Interf_form->Paginas->Width-40; Interf_form->LnkErr->Width=Interf_form->Paginas->Width-40; Interf_form->LnkMns->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->LnkErr->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->EnsMns->Left=20; Interf_form->EnsErr->Left=20; Interf_form->EnsMns->Top=Interf_form->Paginas->Height*1/3-30; Interf_form->EnsErr->Top=Interf_form->Paginas->Height*2/3-15; Interf_form->EnsMns->Width=Interf_form->Paginas->Width-40; Interf_form->EnsErr->Width=Interf_form->Paginas->Width-40; Interf_form->EnsMns->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->EnsErr->Height=(Interf_form->Paginas->Height/3)-20; Interf_form->Label9->Top=Interf_form->LnkMns->Top-15; Interf_form->Label10->Top=Interf_form->LnkErr->Top-15; Interf_form->Label9->Left=Interf_form->LnkMns->Left+Interf_form->LnkMns->Width-150; Interf_form->Label10->Left=Interf_form->LnkErr->Left+Interf_form->LnkErr->Width-135; Interf_form->Label11->Top=Interf_form->EnsMns->Top-15; Interf_form->Label12->Top=Interf_form->EnsErr->Top-15; Interf_form->Label11->Left=Interf_form->EnsMns->Left+Interf_form->LnkMns->Width-185; Interf_form->Label12->Left=Interf_form->EnsErr->Left+Interf_form->LnkErr->Width-170;

Page 141: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

6

} //--------------------------------------------------------------------------- //Click en boton BEditorClick. Presenta la pagina del editor. void __fastcall TInterf_form::BEditorClick(TObject *Sender) { Paginas->PageIndex=1; } //--------------------------------------------------------------------------- //Click en boton BPag_EnsClick. Presenta la pagina del ensamblador. void __fastcall TInterf_form::BPag_EnsClick(TObject *Sender) { Paginas->PageIndex=2; } //--------------------------------------------------------------------------- //Click en boton BPag_LnkClick. Presenta la pagina del linkador. void __fastcall TInterf_form::BPag_LnkClick(TObject *Sender) { Paginas->PageIndex=3; } //--------------------------------------------------------------------------- //Click en boton BPag_SimClick. Ejecuta el programa Simulador. void __fastcall TInterf_form::BPag_SimClick(TObject *Sender) { spawnlp(P_WAIT,"..\\Interface\\Programs\\Simulador.exe","..\\Interface\\Programs\\Simulador.exe",NULL); } //--------------------------------------------------------------------------- //Click en boton BPag_ComClick. Ejecuta el programa Comunicador. void __fastcall TInterf_form::BPag_ComClick(TObject *Sender) { spawnlp(P_WAIT,"..\\Interface\\Programs\\WinItf68K.exe","..\\Interface\\Programs\\WinItf68K.exe",NULL); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // FUNCIONES DE ENSAMBLADOR --------------------------------- //--------------------------------------------------------------------------- //Click sobre boton ensamblar. Funcion principal de ensamblador. //Toma nombres de archivos y envia a DLL ensamblador. Al final, presenta los errores. void __fastcall TInterf_form::Ens_buttonClick(TObject *Sender) { flag=0; char *aux1=new char[100]; strcpy(aux1,Ruta.c_str()); char *aux2=new char[100]; strcpy(aux2,Ruta.c_str()); char *aux3=new char[100]; strcpy(aux3,Ruta.c_str()); AnsiString &edit1=Interf_form->asm_edit->Text; char *fich_asm=new char[edit1.Length()+1]; strcpy(fich_asm,edit1.c_str()); fich_asm=strcat(aux1,fich_asm); AnsiString &edit2=Interf_form->obj_edit->Text; char *fich_obj=new char[edit2.Length()+1]; strcpy(fich_obj,edit2.c_str()); fich_obj=strcat(aux2,fich_obj); AnsiString &edit3=Interf_form->lst_edit->Text; char *fich_lst=new char[edit3.Length()+1]; strcpy(fich_lst,edit3.c_str()); fich_lst=strcat(aux3,fich_lst); try { Ens68K(fich_asm,fich_obj,fich_lst); } catch(...)

Page 142: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

7

{ AnsiString msgErrAnsi,msgErrLine; int pos=0; char *msg=Ens68K_Mensaje(); Interf_form->EnsMns->Text=msg; char *msgErr=Ens68K_MensajeErr(); msgErrAnsi.printf("%s",msgErr); pos=msgErrAnsi.Pos('\n'); while (pos>1) { msgErrLine=msgErrAnsi.SubString(1,pos-1); msgErrAnsi.Delete(1,pos); EnsErr->Items->Add(msgErrLine); pos=msgErrAnsi.Pos('\n'); } } } //--------------------------------------------------------------------------- //Copia nombres de archivos. void __fastcall TInterf_form::asm_editChange(TObject *Sender) { obj_edit->Text=asm_edit->Text; lst_edit->Text=asm_edit->Text; } //--------------------------------------------------------------------------- //Va al editor y selecciona la linea correspondiente del fichero correspondiente void __fastcall TInterf_form::EnsErrDblClick(TObject *Sender) { int i=EnsErr->ItemIndex; if (i<=EnsErr->Items->Count) { AnsiString line1=EnsErr->Items->Strings[i]; AnsiString numstring=line1; numstring.Delete(1,14); numstring.Delete(6,1000); int num=numstring.ToInt(); AnsiString filestring=line1; filestring.Delete(1,24); int j=filestring.AnsiPos("'"); filestring.Delete(j,1000); j=line1.AnsiPos(">>>"); line1.Delete(1,j+3); j=line1.AnsiPos("\t"); line1.Delete(j,1000); while(line1[line1.Length()]==' ') line1.SetLength(line1.Length()-1); //si archivo no abierto-->abrir AnsiString filestr=filestring; int i=filestr.LastDelimiter("\\"); filestr.Delete(1,i); int found=0; i=0; while((!found)&&(i<Lista_Ed->Count)) { editasm=(TEditASM*)Lista_Ed->Items[i]; if(filestr.AnsiCompareIC(editasm->Hoja->Caption)==0) found++; else { i++; } } //abrir if(!found) { FILE *file; char caracter;

Page 143: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

8

AnsiString line; Paginas->PageIndex=1; editasm=new TEditASM (Ed_Pags); Ed_Pags->ActivePage=editasm->Hoja; Lista_Ed->Add(editasm); AnsiString &a=filestring; char *fname=new char[a.Length()+1]; strcpy(fname,a.c_str()); file=fopen(fname,"r"); if(file!=NULL) { caracter=fgetc(file); while(caracter!=EOF) { line=""; while ((caracter!='\n')&&(caracter!=EOF)) //recorre lineas fichero { line+=caracter; caracter=fgetc(file); } editasm->Edit->Lines->Add(line); caracter=fgetc(file); } fclose(file); int b=a.LastDelimiter("\\:" ); //no pone la ruta en la pestaña editasm->Hoja->Caption=a.c_str()+b; editasm->EditColor(); } } else //archivo ya abierto { editasm=(TEditASM*)Lista_Ed->Items[i]; Paginas->PageIndex=1; Ed_Pags->ActivePage=editasm->Hoja; } //seleccionamos la linea determinada AnsiString Texto=editasm->Edit->Text; int a=1; char caracter1=' '; for(int i=1;i<num;i++) { while(caracter1!='\n') { caracter1=Texto[a]; a++; } caracter1=Texto[a]; } editasm->Edit->SelStart=a; a=0; while(caracter1!='\n') { caracter1=Texto[editasm->Edit->SelStart+a]; a++; } editasm->Edit->SelLength=a-1; nlinea->Caption=num; } } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // FUNCIONES DE LINKADOR --------------------------------- //--------------------------------------------------------------------------- //Click sobre boton linkar. Funcion principal de linkador. //Toma nombres de archivos, prepara array y envia a DLL linkador. Al final, presenta los errores. void __fastcall TInterf_form::lin_buttonClick(TObject *Sender) { int n_objs,a;

Page 144: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

9

char *array_objs[20]; char *path=new char[100]; strcpy(path,Ruta.c_str()); if(Lista_arch->Items->Count) { Interf_form->LnkMns->Clear(); Interf_form->LnkErr->Clear(); for (a=0;a<20;a++) array_objs[a]=NULL; arg_lnk(n_objs,array_objs); //mando puntero a int try{ Lnk68K(n_objs,array_objs,Interf_form->s28_edit->Text.c_str(),Interf_form->map_edit->Text.c_str(),path); //2:puntero a array de punteros(cadenas) } catch(...) { char *msg=Lnk68K_Mensaje(); Interf_form->LnkMns->Text=msg; char *msgErr=Lnk68K_MensajeErr(); Interf_form->LnkErr->Text=msgErr; } arg_lnk(array_objs); } } //--------------------------------------------------------------------------- //Crea array con los archivos a linkar. void TInterf_form::arg_lnk(int &i,char *array_objs[]) { i=0; while(i<Interf_form->Lista_arch->Items->Count) { AnsiString &file=Interf_form->Lista_arch->Items->Strings[i]; char *copia=new char[file.Length()+1]; strcpy(copia,file.c_str()); array_objs[i]=copia; i=i+1; } } //--------------------------------------------------------------------------- //Elimina el array de argumentos del linkador. void TInterf_form::arg_lnk(char *array_objs[]) { int j=0; while(array_objs[j]!=NULL) delete array_objs[j++]; } //--------------------------------------------------------------------------- //Click en boton AddClick. Añade archivo a lista de OBJ's. void __fastcall TInterf_form::Button_addClick(TObject *Sender) { AnsiString linea; if(Interf_form->obj_lnk->Text.Length()!=0) { if(Interf_form->obj_lnk->Text[1]!=' ') { if(Interf_form->obj_direcc->Text.Length()==0) linea=Interf_form->obj_lnk->Text; else { long int posi; sscanf(Interf_form->obj_direcc->Text.c_str(),"%lx",&posi); linea=Interf_form->obj_lnk->Text+AnsiString("@")+AnsiString::IntToHex(posi,6); } Interf_form->Lista_arch->Items->Add(linea); } } Interf_form->obj_lnk->Clear(); Interf_form->obj_direcc->Clear();

Page 145: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

10

Interf_form->obj_lnk->SetFocus(); } //--------------------------------------------------------------------------- //Elimina archivo seleccionado de lista. void __fastcall TInterf_form::Button_delClick(TObject *Sender) { int i; if((Lista_arch->Items->Count)&&(Lista_arch->ItemIndex!=-1)) { for (i=0;i<=Lista_arch->Items->Count;i++) { if (Lista_arch->Selected[i]) Lista_arch->Items->Delete(i); } } } //--------------------------------------------------------------------------- //Elimina TODOS los archivos de la lista. void __fastcall TInterf_form::Button_AllClick(TObject *Sender) { Lista_arch->Clear(); } //--------------------------------------------------------------------------- //Copia nombres de archivos. void __fastcall TInterf_form::s28_editChange(TObject *Sender) { map_edit->Text=s28_edit->Text; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // FUNCIONES DE EDITOR --------------------------------- //--------------------------------------------------------------------------- //Boton Save. Guarda la pagina del editor en un archivo. void __fastcall TInterf_form::BSaveClick(TObject *Sender) { int i; FILE *file; if (Lista_Ed->Count) //existe editor { int p=Ed_Pags->ActivePage->PageIndex; editasm=(TEditASM*)Lista_Ed->Items[p]; //p:pagina, hemos guardado en lista:pagina,editor,pagina,editor... editasm->Edit->PlainText=true; //quita colores y demas q no soporta un txt if(SaveDialog->Execute()) { AnsiString &a=SaveDialog->FileName; if (!a.AnsiPos(".")) { switch(SaveDialog->FilterIndex) { case 1: a+=".txt";break; case 2: a+=".asm";break; case 3: a+=".obj";break; case 4: a+=".lst";break; } } char *fname=new char[a.Length()+1]; strcpy(fname,a.c_str()); file=fopen(fname,"w"); for(i=0;i<=editasm->Edit->Lines->Count;i++) //recorre lineas { AnsiString &s=editasm->Edit->Lines->Strings[i]; char *line=new char[s.Length()+1]; strcpy(line,s.c_str()); fprintf(file,"%s\n",line); } fclose(file);

Page 146: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

11

int b=a.LastDelimiter("\\:" ); editasm->Hoja->Caption=a.c_str()+b; editasm->Edit->PlainText=false; //restaura caracteristicas de richedit editasm->Edit->SelStart=0; editasm->Edit->SelLength=editasm->Edit->Text.Length(); editasm->Edit->SelAttributes->Color=clBlack; editasm->Edit->SelAttributes->Style=TFontStyles(); editasm->EditColor(); nlinea->Caption="0"; } } } //--------------------------------------------------------------------------- //Boton Open. Abre un archivo en una pagina de editor. /*Crea una nueva pagina (con su richedit), abre el archivo indicado y pone el nombre en la pestaña. */ void __fastcall TInterf_form::BOpenClick(TObject *Sender) { OpenButton(); } void TInterf_form::OpenButton() { FILE *file; char caracter; AnsiString line; if (OpenDialog->Execute()) { editasm=new TEditASM (Ed_Pags); Ed_Pags->ActivePage=editasm->Hoja; Lista_Ed->Add(editasm); AnsiString &a=OpenDialog->FileName; char *fname=new char[a.Length()+1]; strcpy(fname,a.c_str()); file=fopen(fname,"r"); caracter=fgetc(file); while(caracter!=EOF) { line=""; while ((caracter!='\n')&&(caracter!=EOF)) //recorre lineas fichero { line+=caracter; caracter=fgetc(file); } editasm->Edit->Lines->Add(line); caracter=fgetc(file); } fclose(file); int b=a.LastDelimiter("\\:" ); //no pone la ruta en la pestaña editasm->Hoja->Caption=a.c_str()+b; editasm->EditColor(); nlinea->Caption="0"; } } //--------------------------------------------------------------------------- //Boton Nuevo. Crea una pagina de editor en blanco. void __fastcall TInterf_form::BNewClick(TObject *Sender) { editasm=new TEditASM(Ed_Pags); //Constructor en edit.h Ed_Pags->ActivePage=editasm->Hoja; Lista_Ed->Add(editasm); nlinea->Caption="0"; } //--------------------------------------------------------------------------- //Boton Cerrar. Cierra la pagina del editor.

Page 147: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

12

void __fastcall TInterf_form::BCloseClick(TObject *Sender) { if (Lista_Ed->Count) //existe editor { int p=Ed_Pags->ActivePage->PageIndex; delete (TEditASM*)Lista_Ed->Items[p]; Lista_Ed->Delete(p); //count-- Lista_Ed->Pack(); Lista_Ed->Capacity=Lista_Ed->Count; nlinea->Caption="0"; //p:pagina, hemos guardado en lista:pagina,editor,pagina,editor... } } //--------------------------------------------------------------------------- //Boton Arreglar. Pasa el testeador de texto (arregla las negritas y los comentarios) void __fastcall TInterf_form::BColorClick(TObject *Sender) { if(Lista_Ed->Count) editasm->EditColor(); } //--------------------------------------------------------------------------- //Boton Imprimir. void __fastcall TInterf_form::BPrintClick(TObject *Sender) { if(Lista_Ed->Count) { int p=Ed_Pags->ActivePage->PageIndex; editasm=(TEditASM*)Lista_Ed->Items[p]; editasm->Edit->PlainText=true; //quita colores y demas q no soporta un txt PrintDialog->Execute(); Printer()->BeginDoc(); Printer()->Canvas->Font->Name="Courier New"; Printer()->Canvas->Font->Size=12; int i,j=0; //linea, pagina AnsiString Pag; Pag=IntToStr(Printer()->PageNumber); Printer()->Canvas->TextOutA(2500,62*100,Pag.c_str()); for(i=0;i<=editasm->Edit->Lines->Count;i++) //recorre lineas { j++; if (j>60) { j=1; Printer()->NewPage(); Pag=IntToStr(Printer()->PageNumber); Printer()->Canvas->TextOutA(2500,62*100,Pag.c_str()); } AnsiString &s=editasm->Edit->Lines->Strings[i]; int a=s.AnsiPos("\t"); while (a) { s.Delete(a,1); s.Insert(" ",a); a=s.AnsiPos("\t"); } char *line=new char[s.Length()+1]; strcpy(line,s.c_str()); Printer()->Canvas->TextOutA(100,j*100,line); } Printer()->EndDoc(); editasm->Edit->PlainText=false; } } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // FUNCIONES DE MENU --------------------------------- //--------------------------------------------------------------------------- // // Click en opción Salir.

Page 148: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

13

void __fastcall TInterf_form::mnusalirClick(TObject *Sender) { exit(0); } //--------------------------------------------------------------------------- // Click en opción Ruta de Usuario. Abre dialogo de ruta de usuario. void __fastcall TInterf_form::mnurutaClick(TObject *Sender) { RutaDialog->Visible=True; Interf_form->Enabled=False; } //---------------------------------------------------------------------------

Principal.h #ifndef PrincipalH #define PrincipalH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ComCtrls.hpp> #include <ExtCtrls.hpp> #include <Dialogs.hpp> #include <Buttons.hpp> #include <Tabs.hpp> #include <OleCtnrs.hpp> #include <Graphics.hpp> #include <jpeg.hpp> #include <Registry.hpp> #include <Menus.hpp> #include <vcl\printers.hpp> //--------------------------------------------------------------------------- class TInterf_form : public TForm { __published: // IDE-managed Components TPanel *PanelPant; TPanel *PanelB; TButton *BEditor; TButton *BPag_Ens; TButton *BPag_Lnk; TOpenDialog *OpenDialog; TSaveDialog *SaveDialog; TPrintDialog *PrintDialog; TNotebook *Paginas; TLabel *Label8; TPanel *Ed_Panel; TLabel *Label1; TLabel *Label2; TLabel *Label3; TButton *Ens_button; TEdit *asm_edit; TEdit *obj_edit; TEdit *lst_edit; TRichEdit *EnsMns; TLabel *Label4; TLabel *Label5; TLabel *Label6; TLabel *Label7; TButton *lin_button; TListBox *Lista_arch; TEdit *s28_edit; TEdit *map_edit; TEdit *obj_lnk; TButton *Button_add; TEdit *obj_direcc; TRichEdit *LnkMns; TRichEdit *LnkErr; TButton *Button_del;

Page 149: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

14

TButton *Button_All; TPanel *Panel_CtrlEd; TBitBtn *BSave; TBitBtn *BOpen; TBitBtn *BNew; TPageControl *Ed_Pags; TBitBtn *BClose; TBitBtn *BColor;

TBitBtn *BPrint; TImage *Image1; TImage *Image3;

TImage *Image2; TImage *Image4; TImage *Image5; TLabel *Label9; TLabel *Label10; TLabel *Label12; TLabel *Label11; TImage *Arrow1; TImage *Arrow2; TImage *Arrow3;

TImage *Arrow4; TImage *Arrow6; TImage *Arrow7; TImage *Arrow8; TImage *Arrow10; TImage *Image6; TImage *Image7; TButton *BPag_Sim; TButton *BPag_Com; TLabel *Linea; TLabel *nlinea; TMainMenu *MainMenu; TMenuItem *mnuprogramas; TMenuItem *mnuopciones; TMenuItem *mnued; TMenuItem *mnuens; TMenuItem *mnulnk; TMenuItem *mnusim; TMenuItem *mnucom; TMenuItem *mnuruta; TMenuItem *mnusalir; TListBox *EnsErr; void __fastcall Ens_buttonClick(TObject *Sender); void __fastcall lin_buttonClick(TObject *Sender); void __fastcall Button_addClick(TObject *Sender); void __fastcall BEditorClick(TObject *Sender); void __fastcall BPag_EnsClick(TObject *Sender); void __fastcall FormCreate(TObject *Sender); void __fastcall BPag_LnkClick(TObject *Sender); void __fastcall asm_editChange(TObject *Sender); void __fastcall Button_delClick(TObject *Sender); void __fastcall Button_AllClick(TObject *Sender); void __fastcall BSaveClick(TObject *Sender); void __fastcall BOpenClick(TObject *Sender); void __fastcall BNewClick(TObject *Sender);

void __fastcall BCloseClick(TObject *Sender); void __fastcall BColorClick(TObject *Sender); void __fastcall BPrintClick(TObject *Sender); void __fastcall FormResize(TObject *Sender); void __fastcall s28_editChange(TObject *Sender); void __fastcall BPag_SimClick(TObject *Sender); void __fastcall BPag_ComClick(TObject *Sender); void __fastcall mnusalirClick(TObject *Sender); void __fastcall mnurutaClick(TObject *Sender); void __fastcall EnsErrDblClick(TObject *Sender); private: // User declarations void arg_lnk(int&,char *arg[]); void arg_lnk(char *arg[]);

Page 150: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

15

void OpenButton(); TList *Lista_Ed; public: // User declarations __fastcall TInterf_form(TComponent* Owner); __fastcall ~TInterf_form(); }; extern PACKAGE TInterf_form *Interf_form; #endif

Page 151: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

16

Edit.cpp //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #pragma package(smart_init) //--------------------------------------------------------------------------- #include "..\Interface\edit.h" #include "..\Interface\Principal.h" #include "..\Interface\RutaDlg.h" //--------------------------------------------------------------------------- //Constructor de Editor (clase TEditASM). TEditASM::TEditASM(TPageControl *Ed_Pags) { static int docs=0; TTabSheet *hoja=new TTabSheet(this); TRichEdit *edit=new TRichEdit(this); edit->OnKeyUp = EditKey; edit->OnMouseDown = EditMouse; edit->Parent=hoja; edit->Align=alClient; edit->WantTabs=True; edit->ScrollBars=ssBoth; edit->MaxLength=0; hoja->PageControl=Ed_Pags; hoja->Caption="SinNombre"+AnsiString(docs++); hoja->Font->Name="Courier New"; Edit=edit; Hoja=hoja; } //--------------------------------------------------------------------------- //Destructor de Editor (clase TEditASM). TEditASM::~TEditASM() {

delete Edit; delete Hoja;

} //--------------------------------------------------------------------------- //Trata los textos del editor y da formato (color, estilo...). Llama a TestLinea(int). void TEditASM::EditColor(void) { int Pos; Pos=Edit->SelStart; //guarda posicion cursor Edit->SelStart=0; Edit->SelLength=Edit->Text.Length(); Edit->SelAttributes->Style=TFontStyles(); Edit->SelAttributes->Color=clBlack; Edit->SelStart=Pos; for(int i=1;i<=Edit->Lines->Count;i++) //trata las lineas { TestLinea(i); //trata la linea i Edit->SelStart+=2; //pasa a linea siguiente (desde \n) } Edit->SelStart=Pos; //restaura posicion cursor } //--------------------------------------------------------------------------- //Llamado por EditColor(). Trata las lineas una a una. void TEditASM::TestLinea(int linea) { int Start,Long; AnsiString palabra; int comentario=0,Vacia=0; if(linea==1) Edit->SelStart=0; Edit->SelLength=1; if(Edit->SelLength==0) Vacia++; while((Edit->SelLength!=0)&&(!Vacia))

Page 152: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

17

{ Long=0; while((Edit->SelText==" ")||(Edit->SelText=="\t")||(Edit->SelText==".")||(Edit-

>SelText==",")) { Edit->SelStart++; Edit->SelLength=1; } if((Edit->SelText==";")||(Edit->SelText=="*")) //COMENTARIO (;...) { int Change=0,Anterior; comentario=1; while(!Change) { Anterior=Edit->SelLength; Edit->SelLength++; if(Anterior==Edit->SelLength) Change=1; //final de linea } Edit->SelAttributes->Color=clBlue; } else //NO COMENTARIO { Start=Edit->SelStart; while((Edit->SelText!="\t")&&(Edit->SelText!=";")&&(Edit->SelText!=".")&&(Edit-

>SelText!=" ")&&(Edit->SelText!=",")&&(Edit->SelLength!=0)) { Edit->SelStart++; Edit->SelLength=1; Long++; } if((Edit->SelText=="\t")||(Edit->SelText==";")||(Edit->SelText==".")||(Edit-

>SelText==" ")||(Edit->SelText==",")) { Edit->SelStart=Start; Edit->SelLength=Long; int j=0,Found=0; palabra=tabla_instrucciones[j]; while((palabra!="XXX")&&(Found==0)) { if(Edit->SelText.AnsiCompareIC(palabra)==0) { Found=1; Edit->SelAttributes->Style=TFontStyles()<< fsBold; //negrita } j++; palabra=tabla_instrucciones[j]; } } } Edit->SelStart+=Edit->SelLength; Edit->SelLength=1; } if((!comentario)&&(!Vacia)) //final de linea y no comentario (tratar ultima palabra) { Edit->SelStart=Start; Edit->SelLength=Long; int j=0,Found=0; palabra=tabla_instrucciones[j]; while((palabra!="XXX")&&(Found==0)) { if(Edit->SelText.AnsiCompareIC(palabra)==0) { Found=1; Edit->SelAttributes->Style=TFontStyles()<< fsBold; //negrita } j++; palabra=tabla_instrucciones[j];

Page 153: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

18

} Edit->SelStart+=Edit->SelLength; Edit->SelLength=1; } Edit->SelAttributes->Style=TFontStyles(); //siguiente palabra en formato normal } //--------------------------------------------------------------------------- //Actualiza el campo linea del Editor. void TEditASM::CursorPoint() { TPoint Punto; Punto=Edit->CaretPos; Interf_form->nlinea->Caption=Punto.y+1; } //--------------------------------------------------------------------------- void __fastcall TEditASM::EditKey(TObject *Sender, WORD &Key, TShiftState Shift) { CursorPoint(); } //--------------------------------------------------------------------------- void __fastcall TEditASM::EditMouse(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if(Button==mbLeft) CursorPoint(); }

Page 154: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

19

edit.h //--------------------------------------------------------------------------- #ifndef editH #define editH //--------------------------------------------------------------------------- #include <ComCtrls.hpp> //--------------------------------------------------------------------------- class TEditASM { private: void TestLinea(int); public: TEditASM(TPageControl*); ~TEditASM(); TRichEdit *Edit; TTabSheet *Hoja; void EditColor(); void CursorPoint(); void __fastcall EditKey(TObject *Sender, WORD &Key, TShiftState Shift); void __fastcall EditMouse(TObject *Sender, TMouseButton Button, TShiftState Shift, int

X, int Y); };

//--------------------------------------------------------------------------- static char *tabla_instrucciones[]={ "ABCD" , "ABSOLUTE", "ADD" , "ADDA" , "ADDI" , "ADDQ" , "ADDX" , "AND" , "ANDI" , "ASL" , "ASR" , "BCC" , "BCHG" , "BCLR" , "BCS" , "BEQ" , "BGE" , "BGT" , "BHI" , "BHS" , "BLE" , "BLO" , "BLS" , "BLT" , "BMI" , "BNE" , "BPL" , "BRA" , "BSET" , "BSR" , "BTST" , "BVC" , "BVS" , "BYTE" , "CHK" , "CLR" , "CMP" , "CMPA" , "CMPI" , "CMPM" , "DB" , "DBCC" , "DBCS" , "DBEQ" , "DBF" , "DBGE" , "DBGT" , "DBHI" , "DBHS" , "DBLE" , "DBLO" , "DBLS" , "DBLT" , "DBMI" , "DBNE" , "DBPL" , "DBRA" , "DBT" , "DBVC" , "DBVS" , "DC" , "DIVS" , "DIVU" , "DL" , "DS" , "DW" , "EJECT", "END" , "EOR" , "EORI" , "EQU" , "EQUAL", "EXG" , "EXT" , "EXTERN", "EXTERNAL","GLOBAL", "HIGH" , "ILLEGAL", "JMP" , "JSR" , "LEA" , "LINK" , "LONG" , "LOW" , "LSL" , "LSR" , "MOVE" , "MOVEA", "MOVEM", "MOVEP", "MOVEQ", "MULS" , "MULU" , "NBCD" , "NEG" , "NEGX" , "NOP" , "NOT" , "OR" , "ORG" , "ORI" , "ORIGIN", "PAGE" , "PEA" , "PUBLIC", "RELATIVE", "RESET", "ROL" , "ROR" , "ROXL" , "ROXR" , "RTE" , "RTR" , "RTS" , "SBCD" , "SCC" , "SCS" , "SEQ" , "SF" , "SGE" , "SGT" , "SHI" , "SHS" , "SLE" , "SLO" , "SLS" , "SLT" , "SMI" , "SNE" , "SPL" , "ST" , "STOP" , "SUB" , "SUBA" , "SUBI" , "SUBQ" , "SUBX" , "SVC" , "SVS" , "SWAP" , "TAS" , "TITLE", "TRAP" , "TRAPV", "TST" , "UNLK" , "WORD" , "XXX" }; #endif

Page 155: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

20

RutaDlg.cpp //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "RutaDlg.h" #include "..\Interface\Principal.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TRutaDialog *RutaDialog; extern AnsiString Ruta; //--------------------------------------------------------------------------- // Constructor de la ventana. Actualiza ComboBox con ruta actual. __fastcall TRutaDialog::TRutaDialog(TComponent* Owner) : TForm(Owner) { RutaDialog->RutaCombo->Text=Ruta; RutaCombo->Items->Add(Ruta); } //--------------------------------------------------------------------------- // Click en boton Ok. Guarda nueva ruta en registro y en memoria de ComboBox void __fastcall TRutaDialog::RutaBOkClick(TObject *Sender) { //guarda el registro con el nuevo valor TRegistry *Registro = new TRegistry; Ruta=RutaDialog->RutaCombo->Text; try { Registro->RootKey = HKEY_CURRENT_USER; Registro->OpenKey("\\SOFTWARE\\TM683",true); Registro->WriteString("Ruta",Ruta); } __finally //pasa con o sin excepciones { delete Registro; } //combo memoriza las rutas RutaCombo->Items->Add(Ruta); //actualiza directorios de dialogos de editor Interf_form->OpenDialog->InitialDir=Ruta; Interf_form->SaveDialog->InitialDir=Ruta; //actualiza ventanas RutaDialog->Hide(); Interf_form->Enabled=True; } //--------------------------------------------------------------------------- // Click en boton Cancel. Restaura ruta correcta en ComboBox y sale void __fastcall TRutaDialog::RutaBCancelClick(TObject *Sender) { //pone la ruta correcta en el campo texto del combo box (para futuro) TRegistry *Registro = new TRegistry; try { Registro->RootKey = HKEY_CURRENT_USER; Registro->OpenKey("\\SOFTWARE\\TM683",true); RutaCombo->Text=Registro->ReadString("Ruta"); } __finally //al acabar pasa por aqui (con/sin excep's) { delete Registro; } //prepara ventanas RutaDialog->Hide(); Interf_form->Enabled=True; } //---------------------------------------------------------------------------

Page 156: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

21

ensdll.dll

ensdll.bpf USEUNIT("ensdll.cpp"); USEUNIT("ENS68K.Cpp"); USEUNIT("ERRORES.Cpp"); USEUNIT("FUNC.Cpp"); USEUNIT("PARSER.Cpp"); USEUNIT("ARBOLES.Cpp"); USEUNIT("TABLA.Cpp"); //--------------------------------------------------------------------------- This file is used by the project manager only and should be treated like the project file DllEntryPoint

ensdll.cpp //--------------------------------------------------------------------------- #include <vcl.h> #include <windows.h> #pragma hdrstop //--------------------------------------------------------------------------- // Important note about DLL memory management when your DLL uses the // static version of the RunTime Library: // // If your DLL exports any functions that pass String objects (or structs/ // classes containing nested Strings) as parameter or function results, // you will need to add the library MEMMGR.LIB to both the DLL project and // any other projects that use the DLL. You will also need to use MEMMGR.LIB // if any other projects which use the DLL will be performing new or delete // operations on any non-TObject-derived classes which are exported from the // DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling // EXE's to use the BORLNDMM.DLL as their memory manager. In these cases, // the file BORLNDMM.DLL should be deployed along with your DLL. // // To avoid using BORLNDMM.DLL, pass string information using "char *" or // ShortString parameters. // // If your DLL uses the dynamic version of the RTL, you do not need to // explicitly add MEMMGR.LIB as this will be done implicitly for you //--------------------------------------------------------------------------- #include "ensdll.h" #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //---------------------------------------------------------------------------

Page 157: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

22

ensdll.h //--------------------------------------------------------------------------- #ifndef ensdllH #define ensdllH #ifdef __DLL__ #define EXPORT_IMPORT __declspec(dllexport) #else #define EXPORT_IMPORT __declspec(dllimport) #endif EXPORT_IMPORT int Ens68K(char*,char*,char*); EXPORT_IMPORT char* Ens68K_Mensaje(); EXPORT_IMPORT char* Ens68K_MensajeErr(); #endif

Page 158: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

23

ens68k.cpp /***************************************************************************/ /* MODULO ENS68K.C PERTENECIENTE AL PROGRAMA ENSAMBLADOR ENS68K */ /* */ /* */ /* Este módulo es el módulo principal del programa.Contiene la in- */ /* terface de usuario y las llamadas a los demas m¢dulos. */ /* */ /***************************************************************************/ #include <vcl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <conio.h> #include "..\Ensamblador\ens.h" #include "..\Ensamblador\macros.h" #include "..\Ensamblador\ensdll.h" /*----------VARIABLES GLOBALES-----------*/ char aux_str[1024]; AnsiString Mensajes_ens; AnsiString Mensajes_ensErr; AnsiString Mensajes_fl; char *fichero; int ErrPos,CodPos=1; int in_macro=0; //informa si estamos dentro de una definicion de macro char *FListado; struct arbol *raiz; /*Puntero al arbol de etiquetas*/ struct arbol *raizm; /*Puntero al arbol de etiquetas*/ int errores=0; /*Nos indica si han habido errores en la compilacion*/ int segunda_pasada; /* Indica en que pasada estamos */ int ultima_pasada; int tamdef; /* Tama¤o de la directiva define */ int directiva=0; /* Indica si se ensambla una directiva define */ int pantalla=0; /* Flag de ensamblado en pantalla */ int solo_errores=0; /* Flag de solo mostrar errores */ int codigoreub=1; /* Indica si el codigo es absoluto o reubicable */ int end=0; /* Indica si se ha leido la directiva end */ FILE *ff,*fd,*fl,*fs; /* Ficheros de entrada y salidas */ long int origen=0; /* Origen (absoluto) Offset (reubicable) */ long int contador; /* Posicion dentro del codigo */ char *instruccion; /* Indica la posicion de la instruccion */ int num_seg=0; /* Numero de segmentos del programa */ struct seg segmento[20]; /* Informacion de segmentos del programa */ AnsiString fsString; /*----------VARIABLES EXTERNES -----------*/ extern int lin_no_util; char *mensaje_ens68k[]={ /*0*/ " MACROENSAMBLADOR CRUZADO PARA 68000 ", /*1*/ "", /*2*/ "Fichero fuente", /*3*/ "Fichero objeto", /*4*/ "Opciones (P=Pantalla D=Disco I=Impresora E=S¢lo errores)", /*5*/ "Parametros incorrectos", /*6*/ "Fichero de listado", /*7*/ "\r\nEl fichero fuente %s no existe\r\n\n", /*8*/ "\r\nError al crear el fichero objeto %s\r\n\n", /*9*/ "\r\nError al crear el fichero de listado %s\r\n\n", /*10*/ "PRIMERA PASADA", /*11*/ "Linea", /*12*/ "Lineas ensambladas", /*13*/ "SEGUNDA PASADA",

Page 159: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

24

/*14*/ "Errores", /*15*/ "TABLA DE SIMBOLOS", /*16*/ "Pagina", /*17*/ "", /*18*/ "Memoria insuficiente", /*19*/ "I", /* Impresora */ /*20*/ "P", /* Pantalla */ /*21*/ "Derechos Reservados", }; /* Prototipos de las funciones estaticas */ static int lee_linea(char *s,FILE *ff); static int trans(char *,char *,int *); static void mostrar_pantalla_ayuda(void); char *treutabs(char *,char *); //elimina TABs void ini(); /*---------PROGRAMA PRINCIPAL-----------*/ int Ens68K(char *ffuente,char *fdestino, char* flistado) { fichero=""; if (!strchr(ffuente+2,'.')) //busca '.' en la cadena f y retorna la @ donde se encuentra strcat (ffuente,".asm"); if (!strchr(fdestino+2,'.')) strcat (fdestino,".obj"); if (!strchr(flistado+2,'.')) strcat (flistado,".lst"); fichero=ffuente; FListado=flistado; ini(); register int b,c; int i=0; char nombre[40],impr[10],*com,*com3,com2[200]; int err,r,ext,mayor; long int l; char s[0x100],ens[5],enss[18],ensss[18],ensss2[18],ensss3[18]; char sin[0x100]; char *ensam,formato[50],ensamblado[30]; char v2[9],v[9]; long int contador2; sprintf(aux_str," %s \n",mensaje_ens68k[0]); //titulo programa Mensaje(aux_str); raiz=NULL; raizm=NULL; /* Abrir los distintos ficheros*/ if ((ff=fopen(ffuente,"rb"))==NULL) { sprintf(aux_str,mensaje_ens68k[7],ffuente); Mensaje(aux_str); goto fin; //SALIDA } if ((fs=fopen("..\\usuario\\xxx.xxx","w+"))==NULL) //arch privado del programa { goto fin; //SALIDA } remove(fdestino); if ((fd=fopen(fdestino,"w"))==NULL) { sprintf(aux_str,mensaje_ens68k[8],fdestino); Mensaje(aux_str); goto fin; //SALIDA } if(flistado!=NULL) { remove(flistado); if ((fl=fopen(flistado,"w+"))==NULL) {

Page 160: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

25

sprintf(aux_str,mensaje_ens68k[9],flistado); Mensaje(aux_str); goto fin; //SALIDA } } sprintf(aux_str,"\t%s\n\n",mensaje_ens68k[0]); flMens(aux_str); /* Mostrar los nombres de los distintos ficheros que se utilizan */ if(flistado!=NULL) { sprintf(aux_str,"\t\t%-18s: %s\n",mensaje_ens68k[2],strupr(ffuente)); flMens(aux_str); sprintf(aux_str,"\t\t%-18s: %s\n",mensaje_ens68k[3],strupr(fdestino)); flMens(aux_str); sprintf(aux_str,"\t\t%-18s: %s\n",mensaje_ens68k[6],strupr(flistado)); flMens(aux_str); } /* PASADA CERO POR EL ENSAMBLADOR.EL PROGRAMA SE ENCARGA DE LLENAR LA TABLA DE MACROS Y DE CREAR UN ARCHIVO PRIVADO DEL PROGRAMA EN EL QUE SE SUSTITUYEN LAS LLAMADAS A MACRO POR EL CODIGO PERTINENTE*/ fsString=""; segunda_pasada=0; ultima_pasada=0; while (lee_linea(s,ff) && !end) { int err_aux; err_aux=pasada_macros(s); //Tratador de macros err=err_aux; if (err) /*Tratamiento de errores en pasada cero*/ { error(err,0,s); } } //while if(in_macro) error(40,0,"MACRO"); fprintf(fs,"%s",fsString.c_str()); rewind(fs); rewind(ff); /* PRIMERA PASADA POR EL ENSAMBLADOR.EL PROGRAMA SE ENCARGA DE LLENAR LA TABLA DE SIMBOLOS CALCULANDO LA LONGITUD DE CADA UNA DE LAS INS- TRUCCIONES Y DETECTANDO ASI ALGUNOS ERRORES DE SINTAXIS Y LA PRESEN- CIA DE ETIQUETAS INCORRECTAS O REPETIDAS. */ /* Mensajes introductorios en pantalla y fich.listado */ sprintf(aux_str,"%s:\n",mensaje_ens68k[10]); Mensaje(aux_str); if(flistado!=NULL) { sprintf(aux_str,"\n\nERRORES:\n\n"); flMens(aux_str); } ErrPos=Mensajes_fl.Length(); if(flistado!=NULL) { sprintf(aux_str,"\n\nCODIGO:\n\n"); flMens(aux_str); } CodPos=Mensajes_fl.Length(); /*Inicializaciones*/ contador=0; //Contador Programa i=1; //Linea segunda_pasada=1; //Primera pasada /*Analisis linea a linea*/ while (lee_linea(s,fs) && !end) { *ensamblado = '\0';

Page 161: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

26

contador2=contador; int err_aux; err_aux=decodifica(s,ensamblado); //Ensamblador de lineas err=err_aux; if(!lin_no_util) //Contador par (si es necesario) { if ((!directiva && (contador2 & 1)) || (directiva && (contador2 & 1) && (tamdef !=

1))) { contador2++; contador = contador2; } } if(directiva==3) directiva=0; /*Tratamiento de errores en primera pasada*/ if (err) { //NO PONER ERROR EN 1a PASADA!!! error(err,i,s); } else //No error en linea pero puede ser directiva { if (directiva) { com=instruccion; while (isspace(*(++com))); while (*(++com) && !isspace(*com)); while (*com && isspace(*(++com))); if (*com=='*' || *com==';') *com=0; if (directiva==2) /* Directiva del tipo DS */ { ext=0; /* Hallar el numero de posiciones a reservar */ if (*com==0) l=1; else { for (c=1;com[c] != 0 && !isspace(com[c]);c++); l=hallar_valor(com,c,&err,&r,&ext); } /* Incrementar el contador */ if (!err) { contador += l*tamdef; if (contador & 1) contador++; } } //if(2) if (directiva==1) /* Directiva del tipo DC */ { if (*com==0) strcpy(com,"0"); c=trans(com,com2,&err); /*Hallar longitud de los argumentos*/ if (!err) contador+=c*tamdef; /*Incrementar el contador de programa*/ } } //if(directiva) } //else directiva=0; i++; } //while rewind(ff); rewind(fs); /* Grabar cabecera del fichero OBJ conteniendo lo siguientes campos : - Si el código es absoluto o reubicable - Número total de segmentos - Longitud y origen de cada uno de los segmentos - Listado de las etiquetas - el signo ; para indicar final de la cabecera */ if (!errores) { int i; segmento[num_seg].final=contador;

Page 162: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

27

fprintf(fd,"%d\n%d\n",codigoreub,++num_seg); for (i=0;i<num_seg;i++) fprintf(fd,"%ld\n%ld\n",segmento[i].final-segmento[i].origen,segmento[i].origen); listar_arbol(raiz,1); fprintf(fd,";\n"); } if (!end) error(9,9999,"END"); else { sprintf(aux_str," %s: %d",mensaje_ens68k[12],--i); Mensaje(aux_str); } /* SEGUNDA PASADA.EN ESTA SEGUNDA PASADA SE REALIZA LA CODIFICACION DE LAS INSTRUCCIONES.AL ESTAR LA TABLA DE SIMBOLOS LLENA SE RESUELVEN TODAS LAS LLAMADAS A ETIQUETAS,Y LAS ETIQUETAS NO EXISTENTES SE CONSIDERA- RAN EXTERNAS AL MODULO Y SE PREPARARAN PARA RESOLVERSE EN EL LINKER. */ sprintf(aux_str,"\n\n%s:\n",mensaje_ens68k[13]); Mensaje(aux_str); /*Inicializaciones*/ contador=0; //contador i=1; //linea end=0; segunda_pasada=2; ultima_pasada=1; /*Analisis linea a linea*/ while (lee_linea(s,fs) && !end) { ensam=ensamblado; *ensamblado = '\0'; contador2=contador; int err_aux; err_aux=decodifica(s,ensamblado); //ensamblador de lineas err=err_aux; strcpy(formato," : %4s %4s %4s :\n"); if(!lin_no_util) //Contador par (si necesario) { if ((!directiva && (contador2 & 1)) || (directiva && (contador2 & 1) && (tamdef !=

1))) { if (!solo_errores) { if(flistado!=NULL) { sprintf(aux_str,formato,"00 "," "," "); flMens(aux_str); } fprintf(fd,"%s","00\0"); } contador2++; contador = contador2; } }//if(!noutil) if(directiva==3) directiva=0; /*Mostrar lineas en fichero .lst*/ sprintf(v,"%08lX",contador2); strcpy(v2,v); v2[4]=0; if (!solo_errores) { if (flistado!=NULL) { sprintf(aux_str,"%-4d: %4s %4s : ",i,v2,v+4); flMens(aux_str); } }

Page 163: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

28

/* Tratamiento de las directivas.Es exactamente igual a la de la primera pasada, pero ahora se deben grabar en el fichero OBJ y ademas se deben preparar para su presentaci¢n en pantalla y en el fichero de listado */ b=0; if (!err && directiva) { if (!solo_errores) { if (flistado!=NULL) { sprintf(aux_str," : %s\n",s); flMens(aux_str); } } com=instruccion; while (isspace(*(++com))); while (*(++com) && !isspace(*com)); while (*com && isspace(*(++com))); if (*com=='*' || *com==';') *com=0; if (directiva==2) /* Directiva del tipo DS */ { ext=0; if (*com==0) l=1; else { for (c=1;com[c] != 0 && !isspace(com[c]);c++); l=hallar_valor(com,c,&err,&r,&ext); } if (!err) { if (ext) err=32; /* No puede ser externo */ else if (r) err=20; /* ni reubicable */ } contador += l*tamdef; if (contador & 1) { contador++; l++; } for (b=1;b<=l*tamdef;b++) fprintf(fd,"%s","00\0"); }//if(2) if (directiva==1) /* Directiva del tipo DC */ { if (*com==0) strcpy(com,"0"); c=trans(com,com2,&err); if (!err) { contador += c*tamdef; /* Formato de presentaci¢n de las directivas */ strcpy(formato," : %4s %4s %4s :\n"); ensss[0]=0; for (b=0;b<c;b++) { com3=com2+b*tamdef*2; *enss=*com3++; *(enss+1)=*com3++; com=enss+2; for (r=1;r<tamdef;r++) { *com++=*com3++; *com++=*com3++; } *com=0; /*Agrupacion de valores*/ strcat(ensss,enss); mayor=0; if (strlen(ensss) > 12) mayor=1; if (strlen(ensss) >= 12 )

Page 164: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

29

{ ensss[12]=0; strcpy(ensss3,ensss+8); ensss[8]=0; strcpy(ensss2,ensss+4); ensss[4]=0; if (!solo_errores) { if (flistado!=NULL) { sprintf(aux_str,formato,ensss,ensss2,ensss3); flMens(aux_str); } } ensss[0]=0; if (mayor) strcpy(ensss,enss+4); } if (!solo_errores) { fprintf(fd,"%s",enss); } } //for if (c&1) //nºcaracteres impar (añadimos 00) { strcat(ensss,"00"); fprintf(fd,"%s","00\0"); contador++; } if (strlen(ensss)) { while (strlen(ensss) < 12) strcat(ensss," "); strcpy(ensss3,ensss+8); ensss[8]=0; strcpy(ensss2,ensss+4); ensss[4]=0; if (!solo_errores) { if (flistado!=NULL) { sprintf(aux_str,formato,ensss,ensss2,ensss3); flMens(aux_str); } } } //if } //if(!err) } //if(directiva==1) } //if (directiva) /*Tratamiento de errores*/ if (err) { treutabs(sin,s); if (flistado!=NULL) { error(err,i,s); sprintf(aux_str," : %s\n",s); flMens(aux_str); } } //if(err) if (!directiva && !err) //no directiva DS o DC --> fichero .LST { strncpy(ens,ensamblado,4); ens[4]='\0'; /* En este bucle se va presentando la instrucci¢n ensamblada de 4 en 4 caracteres hexadecimales(words) hasta que se haya completado la instrucci¢n.Esta instrucci¢n puede tener una longitud de 1 a 5 words. El formato de presentaci¢n es el siguiente : Linea : Posici¢n : XXXX XXXX XXXX :linea ensamblada XXXX XXXX */

Page 165: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

30

while (*ensam != '\0') { if (!solo_errores) { switch (b) { case 0 : case 1 : strcpy(formato,"%-4s "); break; case 2 : strcpy(formato,"%-4s : %s\n"); break; case 3 : strcpy(formato," : %-4s "); break; case 4 : strcpy(formato,"%-4s\n"); break; } //switch if (b==2) { if (flistado!=NULL) { sprintf(aux_str,formato,ens,s); flMens(aux_str); } } else { if (flistado!=NULL) { sprintf(aux_str,formato,ens); flMens(aux_str); } } b++; } //if(!solo_errores) fprintf(fd,"%4s",ens); ensam +=4; strncpy(ens,ensam,4); ens[4]='\0'; } //while if (!solo_errores) { switch(b) { case 0: strcpy(formato," : %s\n"); break; case 1: strcpy(formato," : %s\n"); break; case 2 : strcpy(formato," : %s\n"); break; case 4 : strcpy(formato,"\n"); break; } //switch if (b != 3 && b !=5) { if (flistado!=NULL) { sprintf(aux_str,formato,s); flMens(aux_str); } } } //if(!solo_errores) } //if(!directiva&&!err) directiva=0;

Page 166: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

31

i++; } //while (general 2a pasada) fprintf(fd,"LLLL"); //Fin de .OBJ /*Mostrar resumen del proceso*/ sprintf(aux_str," %s: %d\n\n\n***%s: %d",mensaje_ens68k[12],--

i,mensaje_ens68k[14],errores); Mensaje(aux_str); if(flistado!=NULL) { sprintf(aux_str,"\n\n\n %s: %5d\n %s:

%d\n",mensaje_ens68k[12],i,mensaje_ens68k[14],errores); flMens(aux_str); } /*Mostrar en .lst la Tabla de Simbolos*/ sprintf(aux_str,"\f\n\n\n\nTABLA DE SIMBOLOS:\n"); flMens(aux_str); if (flistado!=NULL) { listar_arbol(raiz,2); sprintf(aux_str,"\f"); flMens(aux_str); } fin: fclose(ff); fclose(fs); remove("..\\usuario\\xxx.xxx"); fclose(fd); if (flistado!=NULL) { flWrite(); fclose(fl); } if (errores) { remove(fdestino); throw "ENS1";//lanza excep.(final de programa con errores) } throw "ENS0";//exit(0); lanza excep. (final de programa sin errores) } /*=========================================================================*/ /* Funci¢n : lee_linea Descripci¢n : Esta funci¢n nos lee una linea del fichero que especifi- quemos no importando si la linea caba en \n o si acaba en \r\n dependiendo del editor que se haya utilizado para escribir el fichero fuente. Par metros : char *s - Puntero al string en donde la funci¢n escribir la linea leida. FILE *ff - Especifica de que fichero debemos leer la linea Retorno : Devuelve un 1 si la funci¢n se ha ejecutado correctamente y un cero si se ha llegado al final de fichero. */ /*=========================================================================*/ static int lee_linea(char *s,FILE *ff) { register int n,c; char *cs; n=255; //255 caracteres/linea (max) cs=s; *cs='\0'; while (--n >0 && (c=getc(ff)) != EOF && c != '\x1A') { if ((*cs=c)=='\n' ) break;

Page 167: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

32

if ((*cs=='\r')) { getc(ff); break; } cs++; } *cs='\0'; return (((c==EOF || c=='\x1A') && cs==s) ? 0 : 1); } /*=========================================================================*/ /* Funci¢n : trans Descripci¢n : Esta funci¢n nos coge un string que seran los parametros de una directiva del tipo DC y nos los analiza devolviendo otra cadena que ser una serie de d¡gitos hexadecimales equivalentes a la cadena de entrada. Par metros : char *entrada - Puntero al string conteniendo los par me- tros de la directiva tipo DC. char *salida - Puntero a un string que contendr el valor hexadecimal equivalente al string entrada . int *error - Puntero a un entero que contendr el n£mero de error cometido o cero si no se ha cometido ning£n error . Retorno : Devuelve el n£mero de valores contenidos en el string entrada. */ /*=========================================================================*/ static int trans (char *entrada,char *salida,int *error) { int l=0; long int val; int lon; char *e,enss[9],*s; int r,ext=0; s=salida; do { if (*entrada=='\'') //string entre ' ' { entrada++; a: while (*entrada !='\'') //no final string { b: sprintf(enss,"%04X",*entrada++); e=enss+2; r=tamdef; while (r>1) //Añade 0's hasta longitud correcta { *s++='0'; *s++='0'; r--; } *s++=*e++; *s++=*e++; l++; if (*entrada==0) //final sin ' { *error=10; return 0; } }//while entrada++; if (*entrada =='\'') goto b; //otro string if (*entrada !=0 && *entrada != ',' && !isspace(*entrada)) { *error=7; //falta ',' entre operandos return 0;

Page 168: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

33

} }//if else //valor { lon=0; e=entrada; while (*e != ',' && !isspace (*e) && *e != 0 ) { e++; lon++; } val=hallar_valor(entrada,lon,error,&r,&ext); entrada=e; if (*error) return 0; if (r) { *error=20; //valor reubicable return 0; } if (ext) { *error=32; //externo return 0; } sprintf(enss,"%08lX",val); //valor --> hexa r=4; e=enss; while (r>tamdef) { e++; e++; r--; } while (r) { *s++=*e++; *s++=*e++; r--; } l++; }//else } while (*entrada++==','); //do *s=0; return l; /* Devolver la cantidad de valores extraidos */ } /*========================================================================= Funci¢ : treutabs Descripci¢ : Substitueix TABs per vuit espais per evitar cracters estranys als 'old_cprintf'. No modifica 's' per evitar alterar les funcions que utilitzen punters sobre 's'. =========================================================================*/ char *treutabs(char *sin,char *s) { int i,j,k; for(j=k=0;s[j]!='\0';) { if(s[j]!='\t') sin[k++]=s[j++]; else { for(i=0;i<4;i++) sin[k++]=' '; ++j; } } sin[k]='\0'; return(sin); } /*=========================================================================

Page 169: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

34

Funci¢ : ini Descripci¢ : funcion inicializacion cada vez que se ejecuta el main =========================================================================*/ void ini() { errores=0; directiva=0; pantalla=0; solo_errores=0; codigoreub=1; end=0; origen=0; num_seg=0; } //========================================================================= // Las funciones siguientes preparan y presentan los mensajes que se generan // en las DLL's y deben presentarse en el programa principal. //========================================================================= void Mensaje(char *aux_str) { Mensajes_ens+=aux_str; Mensajes_ens+='\n'; *(aux_str)='\0'; } char* Ens68K_Mensaje() { char *Auxiliar; Mensajes_ens+="\n\n"; Auxiliar=Mensajes_ens.c_str(); Mensajes_ens=""; return Auxiliar; } void MensajeErr(char *aux_str) { Mensajes_ensErr+=aux_str; Mensajes_ensErr+='\n'; *(aux_str)='\0'; } char* Ens68K_MensajeErr() { char *Auxiliar; Mensajes_ensErr+="\n\n\n\n\n"; Auxiliar=Mensajes_ensErr.c_str(); Mensajes_ensErr=""; return Auxiliar; } void flMens(char *aux_str) { AnsiString text; int Longitud; Longitud=text.printf("%s",aux_str); Mensajes_fl.Insert(text,CodPos); CodPos+=Longitud; } void flErr(char *aux_str) { AnsiString text; int Longitud; Longitud=text.printf("%s",aux_str); Mensajes_fl.Insert(text,ErrPos); ErrPos+=Longitud; CodPos+=Longitud; }

Page 170: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

35

void flWrite() { char *Auxiliar; Mensajes_fl+="\n\n"; Auxiliar=Mensajes_fl.c_str(); Mensajes_fl=""; fprintf(fl,"%s",Auxiliar); } /*====================== FIN DEL MODULO ENS68K.C ==========================*/

Page 171: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

36

ENS.h //--------------------------------------------------------------------------- #ifndef ensH #define ensH //--------------------------------------------------------------------------- /* arboles.cpp */ #define NE 35 /* nombre de missatges error */ #define LPAG 60 /* long. de pagina de llistat */ struct arbol

{ struct arbol *arbol_der; /* Direccion del arbol de la derecha */ struct arbol *arbol_izq; /* Direccion del arbol de la izquierda */ char label[16]; int valor; int tipodevariable; //0-Local absoluta 1-Local reubicable 2-Externa //3-Global no inicializada 4-Global absoluta //5-Global reubicable 6-Macro } ; struct arbol *buscar_rama (struct arbol *a,char *label); struct arbol *insarbol(struct arbol *r,struct arbol *a,char *label, int *error,int dato,int tipodevariable); void listar_arbol (struct arbol *a,int); void eliminar_rama(struct arbol *,char *); /* funciones.cpp */ char *coger_palabra(char *,char *,int *); char *cogeyanal(char *,int *,int *,int *); int tipo2( int,int,char *,char *); int tipo3( int,int,char *); int masde4bits( int); int masde8bits( int); int masde16bits( int); int esta_en (char,char *s); int hexdec(char *,int *); int bindec(char *,int *); /* parser.cpp */ int hallar_valor (char *palabra,int longitud,int *err, int *reubicable,int *segunda_pasada); void error (int,int,char *); int decodifica(char *,char *); struct operando

{ int op; int datos; int tamano;

}; struct seg

{ int origen; int final;

} ; procesar(int (*f)()); void Mensaje(char*); void MensajeErr(char*); void flMens(char*); void flErr(char*); void flWrite(); extern char aux_str[1024]; extern int ErrPos,CodPos; extern char *fichero; extern int in_macro; #endif

Page 172: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

37

macros.h //--------------------------------------------------------------------------- #ifndef macrosH #define macrosH //--------------------------------------------------------------------------- #include <vcl.h> /* macros.cpp */ struct arbolm { struct arbolm *arbol_der; /* Direccion del arbol de la derecha */ struct arbolm *arbol_izq; /* Direccion del arbol de la izquierda */ char label[16]; AnsiString text; int llamadas; int argumentos; }; struct arbolm *buscar_rama (struct arbolm *a,char *label); struct arbolm *insarbol(struct arbolm *r,struct arbolm *a,char *label, int *error); void listar_arbol (struct arbolm *a,int); void eliminar_rama(struct arbolm *,char *); int pasada_macros(char *); #endif

Page 173: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

38

tabla.cpp /***************************************************************************/ /* MODULO TABLA.C PERTENECIENTE AL PROGRAMA ENSAMBLADOR ENS68K */ /* */ /* */ /* Este módulo contiene el ensamblador de lineas y las tablas que */ /* utiliza éste conteniendo los nombres de los nemotécnicos , y otros */ /* valores necesarios para el ensamblado . */ /***************************************************************************/ /* Declaración de cabeceras */ #include <stdio.h> #include <string.h> #include <ctype.h> #include "..\Ensamblador\ens.h" #include "..\Ensamblador\macros.h" #define RETURN(a) return ultima_pasada ? a:0 #define ERROR if (err) return(err) #define NEM_INCORR 1 /* Nemotecnico incorrecto */ #define DIR_INCORR 8 /* Direccionamiento incorrecto */ #define TAM_INCORR 18 /* Tama¤o incorrecto */ #define NUMERO_NEMOT 147 /* N£mero de nemot‚cnicos implementados */ #define POS_MOVE 87 /* Posici¢n de MOVE dentro de la tabla */ /* Prototipos de las funciones est ticas */ static char* String_Hex(int,int); static int tipo1(void),add(void),adda(void),addi(void),addq(void),and(void), andi(void),asr(void),bra(void),bchg(void),chk(void),neg(void), cmp(void),cmpm(void),nbcd(void),endd(void),eor(void),equ(void), exg(void),ext(void),exter(void),glob(void),jmp(void),lea(void), link(void),move(void),movea(void),movem(void),movep(void), moveq(void),page(void),nada(void),or(void),org(void),rel(void), stop(void),sub(void),swap(void),title(void),trap(void),unlk(void), abso(void),dc(void),ds(void),dbcc(void),scc(void),high(void),low(void), macro(void),callm(void),endm(void); int buscar_tabla(void); static void stcat(void); static void invertir (char *); static int mascara(char *,char *linea); static int sp(int); static void opp_a_op(void); /* Declaraci¢n de las tablas */ static char *tabla_instrucciones[]={ "ABCD" , "ABSOLUTE", "ADD" , "ADDA" , "ADDI" , "ADDQ" , "ADDX" , "AND" , "ANDI" , "ASL" , "ASR" , "BCC" , "BCHG" , "BCLR" , "BCS" , "BEQ" , "BGE" , "BGT" , "BHI" , "BHS" , "BLE" , "BLO" , "BLS" , "BLT" , "BMI" , "BNE" , "BPL" , "BRA" , "BSET" , "BSR" , "BTST" , "BVC" , "BVS" , "BYTE" , "CALLM", "CHK" , "CLR" , "CMP" , "CMPA" , "CMPI" , "CMPM" , "DB" , "DBCC" , "DBCS" , "DBEQ" , "DBF" , "DBGE" , "DBGT" , "DBHI" , "DBHS" , "DBLE" , "DBLO" , "DBLS" , "DBLT" , "DBMI" , "DBNE" , "DBPL" , "DBRA" , "DBT" , "DBVC" , "DBVS" , "DC" , "DIVS" , "DIVU" , "DL" , "DS" , "DW" , "EJECT", "END" , "ENDM" , "EOR" , "EORI" , "EQU" , "EQUAL", "EXG" , "EXT" , "EXTERN", "EXTERNAL","GLOBAL", "HIGH" , "ILLEGAL", "JMP" , "JSR" , "LEA" , "LINK" , "LONG" , "LOW" , "LSL" , "LSR" , "MACRO", "MOVE" , "MOVEA", "MOVEM", "MOVEP", "MOVEQ", "MULS" , "MULU" , "NBCD" , "NEG" , "NEGX" , "NOP" , "NOT" , "OR" , "ORG" , "ORI" , "ORIGIN", "PAGE" , "PEA" , "PUBLIC", "RELATIVE", "RESET", "ROL" , "ROR" , "ROXL" , "ROXR" , "RTE" , "RTR" , "RTS" , "SBCD" , "SCC" , "SCS" , "SEQ" , "SF" ,

Page 174: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

39

"SGE" , "SGT" , "SHI" , "SHS" , "SLE" , "SLO" , "SLS" , "SLT" , "SMI" , "SNE" , "SPL" , "ST" , "STOP" , "SUB" , "SUBA" , "SUBI" , "SUBQ" , "SUBX" , "SVC" , "SVS" , "SWAP" , "TAS" , "TITLE", "TRAP" , "TRAPV", "TST" , "UNLK" , "WORD" }; static int tabla_tamanos[]= {

1 , 14, 7 , 6 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 13, 5 , 5 , 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 5 , 13, 5 , 13, 13, 1 , 14, 2, 7 , 7 , 6 , 7 , 7 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 7 , 2 , 2 , 4 , 7 , 2 , 14, 2 , 14, 7 , 7 , 14, 14, 4 , 6 , 14, 14, 14, 14, 14, 2 , 2 , 6 , 2 , 4 , 14, 7 , 7 , 14, 7 , 6 , 6 , 6 , 4 , 2 , 2 , 1 , 7 , 7 , 14, 7 , 7 , 2 , 7 , 2 , 2 , 4 , 2 , 2 , 14, 7 , 7 , 7 , 7 , 14, 14, 14, 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 14, 7 , 6 , 7 , 7 , 7 , 1 , 1 , 2 , 1 , 14, 14, 14, 7 , 2 , 2 }; static int tabla_valores[]={ 49408, 0, 53248, 53248, 1536, 20480, 53504, 49152, 512, -1, -2, 100, 64, 128, 101, 103, 108, 110, 98, 100, 111, 101, 99, 109, 107, 102, 106, 96, 192, 97, 0, 104, 105, 0, 0, 16768, 16896, 45056, 45056, 3072, 45312, 0, 21704, 21960, 22472, 20936, 23752, 24264, 21192, 21704, 24520, 21960, 21448, 24008, 23496, 22216, 23240, 20936, 20680, 22728, 22984, 0, 33216, 32960, 0, 0, 0, 0, 0, 0, 320, 2560, 0, 0, 49408, 18432, 0, 0, 0, 0, 19196, 20160, 20096, 16832, 20048, 0, 0, -3, -4, 0, 0, 8256, 0, 264, 0, 49600, 49344, 18432, 17408, 16384, 20081, 17920, 32768, 0, 0, 0, 0, 18496,

0, 0, 20080, -5, -7, -6, -8, 20083, 20087, 20085, 33024, 21696, 21952, 22464, 20928, 23744, 24256, 21184, 21696, 24512, 21952, 21440, 24000, 23488, 22208, 23232, 20672, 20082, 36864, 36864, 1024, 20736, 37120, 22720, 22976,

Page 175: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

40

18496, 19136, 0, 20032, 20086, 18944, 20056, 0 }; static int ((*tabla_funciones[])())={ (int(*)()) tipo1, (int(*)()) abso , (int(*)()) add , (int(*)()) adda , (int(*)()) addi , (int(*)()) addq , (int(*)()) tipo1, (int(*)()) and , (int(*)()) andi , (int(*)()) asr , (int(*)()) asr , (int(*)()) bra , (int(*)()) bchg , (int(*)()) bchg , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bra , (int(*)()) bchg , (int(*)()) bra , (int(*)()) bchg , (int(*)()) bra , (int(*)()) bra , (int(*)()) dc , (int(*)()) callm, (int(*)()) chk , (int(*)()) neg , (int(*)()) cmp , (int(*)()) adda , (int(*)()) addi , (int(*)()) cmpm , (int(*)()) dc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dbcc , (int(*)()) dc , (int(*)()) chk , (int(*)()) chk , (int(*)()) dc , (int(*)()) ds , (int(*)()) dc , (int(*)()) page , (int(*)()) endd , (int(*)()) endm , (int(*)()) eor , (int(*)()) andi , (int(*)()) equ , (int(*)()) equ , (int(*)()) exg , (int(*)()) ext , (int(*)()) exter, (int(*)()) exter, (int(*)()) glob , (int(*)()) high , (int(*)()) nada , (int(*)()) jmp , (int(*)()) jmp , (int(*)()) lea , (int(*)()) link , (int(*)()) dc , (int(*)()) low , (int(*)()) asr , (int(*)()) asr , (int(*)()) macro, (int(*)()) move , (int(*)()) movea, (int(*)()) movem, (int(*)()) movep, (int(*)()) moveq, (int(*)()) chk , (int(*)()) chk , (int(*)()) nbcd , (int(*)()) neg , (int(*)()) neg , (int(*)()) nada , (int(*)()) neg , (int(*)()) or , (int(*)()) org , (int(*)()) andi , (int(*)()) org , (int(*)()) page , (int(*)()) jmp , (int(*)()) glob , (int(*)()) rel , (int(*)()) nada , (int(*)()) asr , (int(*)()) asr , (int(*)()) asr , (int(*)()) asr , (int(*)()) nada , (int(*)()) nada , (int(*)()) nada , (int(*)()) tipo1, (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) scc , (int(*)()) stop , (int(*)()) sub , (int(*)()) adda , (int(*)()) addi , (int(*)()) addq , (int(*)()) tipo1, (int(*)()) scc , (int(*)()) scc , (int(*)()) swap , (int(*)()) nbcd , (int(*)()) title, (int(*)()) trap , (int(*)()) nada , (int(*)()) neg , (int(*)()) unlk , (int(*)()) dc }; static int tabla_operandos[]={ 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 3, 1, 2, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 3, 0, 0, 0, 2, 2, 1, 1, 2, 1, 3, 3, 3, 1, 0, 1, 1, 2, 2, 3, 1, 2, 2, 0, 2, 2, 3, 2, 2, 2, 2, 1, 1, 1, 0, 1, 2, 1, 2, 1, 0, 1, 3, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 3, 1, 0, 1, 1, 3

Page 176: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

41

}; static int tabla_longitudes[]={ 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 2, 0, 2, 0 }; /* Declaraci¢n de variables externas */ extern int tamdef; /* Tama¤o de la directiva */ extern int directiva; /* Flag de directiva */ extern struct arbol *raiz; /* Puntero al arbol de etiquetas */ extern struct arbolm *raizm; extern int codigoreub; /* Indica si el codigo es absoluto o reubicable */ extern int end; /* Indica si se ha leido la directiva end */ extern int segunda_pasada; /* Primera pasada =0 Segunda pasada =1 */ extern int ultima_pasada; extern int origen; /* Origen del programa (ORG) */ extern int contador; /* Numero de linea */ extern char *instruccion; /* Puntero al inicio de la instruccion */ extern int num_seg; /* Numero de segmentos del programa */ extern struct seg segmento[20]; /* Informacion de segmentos del programa */ extern FILE *fd; /* Fichero OBJ */ extern AnsiString fsString; /* Declaraci¢n de variables globales */ struct operando opp1,opp2,opp3; struct operando op1,op2,op3,op4; /*Variables globales para pasar operandos */ int tipo; /* y el direccionamiento */ int size; /* Tama¤o de la instruccion */ int externo,externo2; char oper[60],oper1[60]; int lin_no_util; /* Declaraci¢n de variables est ticas */ static int err=0,aa,bb; static int valor; static char etiqueta[16],palabra[30]; static char *line; static int aux; static char *ensamblado; /*=========================================================================*/ /* La funci¢n decodifica es un ensamblador de lineas.Nos devuelve el error cometido como resultado de la funci¢n y en ensamblado nos de- vuelve la linea ensamblada.En la variable global segunda_pasada debemos

Page 177: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

42

especificar en que pasada estamos. */ /*=========================================================================*/ int decodifica(char *s,char *e) { int label=0,pos; int t,coment=0; lin_no_util=0; /* per defecte, l¡nia £til - A.Mas (5/4/90) */ ensamblado=e; externo=0; externo2=0; *ensamblado='\0'; aux=0; line=s; while (*line && isspace(*line)) line++; if (esta_en(*line,"*;")) /* Se considera comentario si empieza con * o ; */ coment=1; line=s; if (!coment && *line) { *palabra=*line; instruccion=line; line=coger_palabra(line,palabra,&label); if (size == 32 && segunda_pasada==1) return 2; if (size == 8 && !((*palabra=='b' || *palabra=='B') && strlen(palabra)==3) && segunda_pasada==1) return 2; if (label==1) /* si ‚s etiqueta... */ { if (segunda_pasada==1) { err=0; strcpy(etiqueta,palabra); etiqueta[15]='\0'; if (!raiz) raiz=insarbol(raiz,raiz,etiqueta,&err,contador,codigoreub); else insarbol(raiz,raiz,etiqueta,&err,contador,codigoreub); if (err) return err; } *palabra='\0'; instruccion=line; line=coger_palabra(line,palabra,&label); if (size == 5 && segunda_pasada==1) return 2; } if (*palabra != '\0') { pos=buscar_tabla(); if (pos==-1) RETURN (NEM_INCORR); //Aqui faltaria calcular el tamaño de la macro (bytes) y sumar al contador if (tabla_longitudes[pos]) { contador += tabla_longitudes[pos]; if (segunda_pasada==1) return 0; } t=tabla_tamanos[pos]; if (size == 16) { if (t==13) size=2; /* Branch */ else if (2 & t) size=2; else if (4 & t) size=4; else size=1; } else { if (t==14) RETURN (TAM_INCORR); if (!(size & t)) RETURN (TAM_INCORR); } valor=tabla_valores[pos]; if (tabla_operandos[pos]>0 && tabla_operandos[pos]<3) {

Page 178: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

43

line=cogeyanal(line,&err,&externo,&aa); if (!(pos==POS_MOVE && aa==14 && err==8)) ERROR; opp_a_op(); } if (tabla_operandos[pos]==2) { if (tabla_valores[pos]<0 && !(*line && !isspace(*line))) aux=1; else { line=cogeyanal(line,&err,&externo2,&bb); if (!(pos==POS_MOVE && bb==14 && err==8)) ERROR; } } if (tabla_operandos[pos] == 2 || tabla_operandos[pos] == 1) if (*line && !isspace(*line)) RETURN(5); /*Demasiados operandos*/ int (*funcion)()=tabla_funciones[pos]; t=procesar(funcion); return t; } lin_no_util=0; } else lin_no_util=1; return 0; } int buscar_tabla() { register int limite_sup=NUMERO_NEMOT+2; register int limite_inf=0; register int i; int a; for (;;) { i=(limite_sup+limite_inf)/2; if (!(a=stricmp(palabra,tabla_instrucciones[i]))) return i; if (a>0) limite_inf=i+1; else limite_sup=i-1; if (limite_inf >= limite_sup) return (stricmp(palabra,tabla_instrucciones[limite_sup])) ? -1 : limite_sup; } } procesar(int (*f) ()) { return (*f)(); } tipo1() { if (size != 1) valor += (size<<5); if (aa != bb || (aa != 1 && aa != 5)) return DIR_INCORR; valor += op1.op+(opp1.op<<9); if (aa==5) valor +=8; return sp(valor); } /***************************************************************************/ add() { if (aa>11) RETURN(DIR_INCORR); if (aa==3) { valor=1536; return addi(); } if (bb==7) return adda(); if (aa!=1 && bb!=1 ) RETURN (DIR_INCORR); switch (bb) { case 1: if (size != 1) valor += (size<<5);

Page 179: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

44

valor += opp1.op<<9; err = tipo2(valor,aa,ensamblado,oper1); break; default: if (size==2) valor +=64; else if (size==4) valor +=128; if (bb!=2 && bb!=4 && bb!=5 && bb!=6 && bb!=10 && bb!=11) RETURN(DIR_INCORR); valor += 256+(op1.op<<9); opp_a_op(); err = tipo2(valor,bb,ensamblado,oper); } RETURN (err); } /***************************************************************************/ adda() { if (aa > 11 || bb != 7) RETURN(DIR_INCORR); if (size == 1) RETURN(TAM_INCORR); if (size == 4) valor += 256; valor += 192+(opp1.op<<9); err = tipo2(valor,aa,ensamblado,oper1); RETURN (err); } /***************************************************************************/ addi() { op4=op1; if (aa !=3 || bb==3 || bb==7 || bb==8 || bb==9 || bb>11) RETURN(DIR_INCORR); if (size != 1) valor += (size<<5); err = tipo3(valor,bb,ensamblado); RETURN (err); } /***************************************************************************/ addq() { if (aa != 3 || bb==3 || bb==8 || bb==9 || bb==12 || bb==13) RETURN(DIR_INCORR); if (op1.op>8 || op1.op<=0) RETURN(28); /* Valor incorrecto */ if (op1.op != 8) valor += op1.op<<9; if (size != 1) valor += (size<<5); opp_a_op(); if (err = tipo2(valor,bb,ensamblado,oper)) return err; } /***************************************************************************/ and() { if (aa==3) { valor=(valor==49152) ? 512:0; return andi(); } if ((aa !=1 && bb !=1) || aa==7) RETURN(DIR_INCORR); if (aa==1) { if (bb==3 || bb==7 || bb==8 || bb==9 || bb>11) RETURN(DIR_INCORR); if (bb==1) goto dd; if (size == 2) valor +=64; else if (size == 4) valor +=128; valor += 256+((op1.op)<<9); opp_a_op(); err = tipo2(valor,bb,ensamblado,oper); RETURN (err); } else { if (aa>11) RETURN(DIR_INCORR); dd: if (size != 1) valor += (size<<5); valor += (opp1.op)<<9; err = tipo2(valor,aa,ensamblado,oper1);

Page 180: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

45

RETURN (err); } } /***************************************************************************/ andi() { if (aa != 3) RETURN(DIR_INCORR); op4=op1; if (bb>11) { contador +=4; if (segunda_pasada==1) return 0; if (bb==12) { if (size == 4) return TAM_INCORR; if (masde8bits(op4.op)) return 28; /* Mas de 8 bits */ valor+=60; } else if (bb==13) { if (size != 2) return TAM_INCORR; if (masde16bits(op4.op)) return 28; /* Mas de 16 bits */ valor+=124; } else return (DIR_INCORR); stcat(); return 0; } if (size != 1) valor += (size<<5); if (bb==3 || bb==7 || bb==8 || bb==9 || bb>11) RETURN(DIR_INCORR); err = tipo3(valor,bb,ensamblado); RETURN (err); } /***************************************************************************/ void stcat() { if (op4.op >= 0) sprintf(ensamblado,"%04lX%04lX",valor,op4.op); else { char temp[9]; sprintf(temp,"%04lX\0",op4.op); sprintf(ensamblado,"%04lX%s",valor,temp+4); } } /***************************************************************************/ asr() { int rot1,rot2; switch (valor) { case -1: rot1=rot2=256; break; case -2: rot1=rot2=0; break; case -3: rot1=768; rot2=264; break; case -4: rot1=512; rot2=8; break; case -5: rot1=1792; rot2=280; break; case -6: rot1=1280; rot2=272; break; case -7: rot1=1536; rot2=24; break; case -8: rot1=1024; rot2=16;

Page 181: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

46

} if (aux==1) { if (size != 2) RETURN(TAM_INCORR); valor=57536+rot1; if (aa!=2 && aa!=4 && aa!=5 && aa!=6 && aa!=10 && aa!=11) RETURN(DIR_INCORR); err = tipo2(valor,aa,ensamblado,oper); RETURN (err); } contador+=2; if (segunda_pasada==1) return 0; if (bb != 1) return DIR_INCORR; valor=opp1.op; if (size != 1) valor += (size<<5); switch (aa) { case 1 : valor += 57376+rot2+(op1.op<<9); break; case 3 : if (op1.op>8 || op1.op<=0) return 28; /*Valor incorrecto */ valor += 57344+rot2; if (op1.op != 8) valor += (op1.op<<9); break; default : return DIR_INCORR; } return sp(valor); } /***************************************************************************/ bra() { struct arbol *r; char ensamblado2[15]; sprintf(ensamblado,"%02X",valor); r=buscar_rama(raiz,oper); if (r==NULL) externo=1; if (size==1) size=8; if (segunda_pasada==1) { contador+=4; if (size == 8) contador -=2; if (externo) return 0; valor = r->valor-contador+2; if ((valor<0 && valor>-128) && size == 2) contador -=2; return 0; } else { contador+=4; if (externo) return(16); /* No existe esta etiqueta */ valor = r->valor-contador+2; if (size == 8) contador -=2; if (valor>32767 || valor<-32767) return(26); /*Desp.demasiado grande */ if ((valor<0 && valor>-128) && size == 2) contador -=2; else if ((valor>127 || valor<-128) && size == 8) return(26); /*Desplazamiento demasiado grande */ } if (r->tipodevariable==2 || r->tipodevariable==3) RETURN(16); /* Variable no definida */ if ((valor<0 && valor>-128 && size==2) || size == 8) { sprintf(ensamblado2,"%s",String_Hex(valor,8)); //BUG corregido strcat(ensamblado,ensamblado2); if(valor==0) RETURN(29); /*No se puede hacer branch*/ } else {

Page 182: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

47

sprintf(ensamblado2,"00%s",String_Hex(valor,16)); //BUG corregido strcat(ensamblado,ensamblado2); } return 0; } /***************************************************************************/ bchg() { op4=op1; if (!valor) { if (bb==7 || bb>11) RETURN(DIR_INCORR); } else if (bb==3 || bb==7 || bb==8 || bb==9 || bb>11) RETURN(DIR_INCORR); if (aa==1) { valor += 256+(op4.op<<9); size=4; opp_a_op(); err = tipo2(valor,bb,ensamblado,oper); RETURN (err); } if (aa==3) { if (externo) RETURN(32); /* No es posible etiqueta externa */ valor += 2048; if (bb==1 || bb==7) { if (op4.op>=32 || op4.op<0) RETURN(28); /* Valor incorrecto */ } else if (op4.op>=8 || op4.op<0) RETURN(28); /* Valor incorrecto */ size=2; err = tipo3(valor,bb,ensamblado); RETURN (err); } RETURN(DIR_INCORR); } /***************************************************************************/ chk() { if (bb != 1 || aa==7 || aa>11) RETURN(DIR_INCORR); valor += (opp1.op)<<9; err = tipo2(valor,aa,ensamblado,oper1); RETURN (err); } /***************************************************************************/ neg() { if (size != 1) valor += (size<<5); return nbcd(); } /***************************************************************************/ nbcd() { if (aa==3 || aa==7 || aa==8 || aa==9 || aa>11) RETURN(DIR_INCORR); err = tipo2(valor,aa,ensamblado,oper); RETURN (err); } /***************************************************************************/ cmp() { if (aa==3) { valor=3072; return addi(); } if (bb !=1 || aa>11) RETURN(DIR_INCORR); if (bb==7) return adda(); if (size != 1) valor += (size<<5); valor += (opp1.op)<<9; err = tipo2(valor,aa,ensamblado,oper1);

Page 183: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

48

RETURN (err); } /***************************************************************************/ cmpm() { if (size == 2) valor += 64; else if (size == 4) valor +=128; if (aa != 6 || bb != 6) RETURN(DIR_INCORR); return sp(valor+(opp1.op<<9)+8+op1.op); } /***************************************************************************/ endd() { directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=2; /* assegurar que alinei PC */ end=1; return 0; } /***************************************************************************/ eor() { if (aa==3) { valor=2560; return andi(); } if (size==1) valor=256; else if (size==4) valor=384; if (aa != 1 || bb==3 || bb==7 || bb==8 || bb==9 || bb>11) RETURN(DIR_INCORR); valor +=45056+(op1.op<<9); opp_a_op(); err = tipo2(valor,bb,ensamblado,oper); RETURN (err); } /***************************************************************************/ equ() { int reubicable=1; struct arbol *r; directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ if (segunda_pasada==2) return 0; if (*etiqueta=='\0') return 6; else { if (externo || ( aa != 11 && aa != 8)) { eliminar_rama(raiz,etiqueta); return 30; /*No se puede resolver la etiqueta */ } if (aa==11) reubicable=0; r=buscar_rama(raiz,etiqueta); switch (r->tipodevariable) { case 0: case 1: r->tipodevariable = reubicable; break; case 4: case 5: r->tipodevariable = reubicable+4; break; case 2: return 12; /* No se puede redefinir una var exter*/ } r->valor=op1.op; } return 0; } /***************************************************************************/ high() { struct arbol *r;

Page 184: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

49

if (segunda_pasada==2) return 0; if (*etiqueta=='\0') return 6; else { if (externo || aa != 11 ) { eliminar_rama(raiz,etiqueta); return 30; /*No se puede resolver la etiqueta */ } r=buscar_rama(raiz,etiqueta); switch (r->tipodevariable) { case 0: case 1: r->tipodevariable = 0; break; case 4: case 5: r->tipodevariable = 4; break; case 2: return 12; /* No se puede redefinir una var exter*/ } r->valor=op1.op >> 16; } return 0; } /***************************************************************************/ low() { struct arbol *r; if (segunda_pasada==2) return 0; if (*etiqueta=='\0') return 6; else { if (externo || aa != 11 ) { eliminar_rama(raiz,etiqueta); return 30; /*No se puede resolver la etiqueta */ } r=buscar_rama(raiz,etiqueta); switch (r->tipodevariable) { case 0: case 1: r->tipodevariable = 0; break; case 4: case 5: r->tipodevariable = 4; break; case 2: return 12; /* No se puede redefinir una var exter*/ } r->valor=op1.op & 0xFFFF; } return 0; } /***************************************************************************/ exg() { if ((aa != 1 && aa !=7) || (bb != 1 && bb != 7 )) return (DIR_INCORR); if (aa==7) { valor +=op1.op+(opp1.op<<9)+72; if (bb!=7) valor += 64; } else { valor +=opp1.op+(op1.op<<9)+64; if (bb!=1) valor += 72; } return sp(valor); } /***************************************************************************/ ext() {

Page 185: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

50

if (size==2) valor +=128; else if (size==4) valor +=192; if ( aa != 1 ) return DIR_INCORR; return sp(valor+op1.op); } /***************************************************************************/ exter() { register int i; directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ if (segunda_pasada==2) return 0; while (*line != '\0' && *line !=' ') { i=0; while (*line != '\0' && *line !=',' && *line !=' '&&*line!='\t') etiqueta[i++]=*line++; //guarda en etiqueta el nombre etiqueta[i]='\0'; //acaba en \0 la etiqueta etiqueta[15]='\0'; //limita etiqueta a 15 caracteres if (*line==',') *line++; if (!raiz) raiz=insarbol(raiz,raiz,etiqueta,&err,contador,2+aux); else insarbol(raiz,raiz,etiqueta,&err,contador,2+aux); } ERROR; return 0; } /***************************************************************************/ glob() { directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ aux=1; return exter(); } /***************************************************************************/ jmp() { if (aa!=2 && aa!=4 && aa!=8 && aa!=9 && aa!=10 && aa!=11) RETURN(DIR_INCORR); err = tipo2(valor,aa,ensamblado,oper); RETURN (err); } /***************************************************************************/ lea() { if ((aa!=2 && aa!=4 && aa!=8 && aa!=9 && aa!=10 && aa!=11) || bb!=7) RETURN(DIR_INCORR); valor += (opp1.op)<<9; err = tipo2(valor,aa,ensamblado,oper1); RETURN (err); } /***************************************************************************/ link() { if (aa != 7 || bb != 3) return DIR_INCORR; valor += op1.op; if (masde16bits(opp1.op)) return 28; /* Valor demasiado grande */ op4.op=opp1.op; stcat(); return 0; } /***************************************************************************/ move() { int cont; char *linea,ensamblado3[21],ensamblado2[15]; int valor2,valor3,valor4; int size2; linea=line; cont=contador; if (aa==12) RETURN(DIR_INCORR);

Page 186: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

51

if (aa==13) { if (size==1 || size==4) RETURN(TAM_INCORR); if (bb==3 || bb==7 || bb==8 || bb==9 || bb>11) RETURN(DIR_INCORR); valor=16576; opp_a_op(); err = tipo2(valor,bb,ensamblado,oper); RETURN (err); } if (aa==14) { if (size==1) RETURN(TAM_INCORR); if (bb!=7) RETURN(DIR_INCORR); contador +=2; return sp(20072+opp1.op); } if (size==1 && aa==7) RETURN(TAM_INCORR); if (bb == 7 ) { if (size==1) RETURN(TAM_INCORR); contador=cont; line=linea; valor=8256; return movea(); } size2=size; if (err = tipo2(valor,aa,ensamblado,oper1)) RETURN(err); if (bb==3 || bb==8 || bb==9) RETURN(DIR_INCORR); if (bb==14) { if (aa !=7 ) RETURN(DIR_INCORR); if (size2==1) RETURN(TAM_INCORR); sprintf(ensamblado,"%04X",20064+opp1.op); contador=cont+2; return 0; } if (bb==13) valor=18112; if (bb==12) valor=17600; if (bb==13 || bb==12) if (aa==7) RETURN(DIR_INCORR); else { if (size2 != 2) RETURN(TAM_INCORR); contador=cont; err = tipo2(valor,aa,ensamblado,oper1); /*Posible error*/ RETURN (err); } strcpy(ensamblado2,ensamblado); ensamblado2[4]='\0'; valor4=hexdec(ensamblado2,&err); ERROR; strcpy(ensamblado2,ensamblado+4); opp_a_op(); if (size==4) valor4+=4096; else if (size==2) valor4+=8192; if (err=tipo2(valor,bb,ensamblado,oper)) RETURN(err); strcpy(ensamblado3,ensamblado); ensamblado3[4]='\0'; valor=hexdec(ensamblado3,&err); ERROR; valor3=(valor&7)<<9; valor2=((valor&63)-(valor&7))<<3; valor=valor2+valor3+valor4+4096; sprintf(ensamblado3,"%04lX%s",valor,ensamblado2); strcat (ensamblado3,ensamblado+4); strcpy (ensamblado ,ensamblado3); contador -=2; return 0; } /***************************************************************************/ movea()

Page 187: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

52

{ if (aa>11 || bb != 7 ) RETURN(DIR_INCORR); if (size==2) valor +=4096; valor += (opp1.op)<<9; err = tipo2(valor,aa,ensamblado,oper1); RETURN (err); } /***************************************************************************/ movem() { char ensamblado3[21],ensamblado2[15]; if (size==4) valor=64; if (!(err=mascara(ensamblado2,line))) { while (*line != ',' && *line != '\0') line++; line++; valor+=18560; line=cogeyanal(line,&err,&externo2,&bb); ERROR; if (bb !=2 && bb !=4 && bb !=5 && bb !=10 && bb!=11 ) RETURN(DIR_INCORR); opp_a_op(); if (err=tipo2(valor,bb,ensamblado,oper1)) RETURN(err); contador += 2; if (bb==5) invertir(ensamblado2); } else { line=cogeyanal(line,&err,&externo,&aa); opp_a_op(); if (err=mascara(ensamblado2,line)) RETURN(err); valor+=19584; if (aa !=2 && aa !=4 && aa !=6 && aa !=10 && aa!=11 && aa !=8 && aa !=9 ) RETURN(DIR_INCORR); if (err=tipo2(valor,aa,ensamblado,oper)) RETURN(err); contador += 2; while (*line != ',' && *line != '\0') line++; } strcpy(ensamblado3,ensamblado+4); ensamblado[4]=0; strcat(ensamblado,ensamblado2); strcat(ensamblado,ensamblado3); return 0; } /* Invierte la mascara de registros en los direccionamientos en que es necesaria esta inversion */ static void invertir (char *linea) { register int j=0; char *l,c,*m; static char conv[17] = {"084C2A6E195D3B7F"}; m=linea; l=linea+3; for (j=0;j<=1;j++) { c=*linea; *(linea++)=*l; *(l--)=c; } for (j=0;j<4;j++) { c=toupper(m[j]); if (c>64) c -= 55; else c -=48; m[j]= conv[c]; } } /* Crea la mascara de registros en la instruccion MOVEM y devuelve si ha habido algun error 35 que es el error en la lista de registros */ static int mascara(char *masc,char *linea)

Page 188: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

53

{ unsigned int m=0,n,n1; int c; m: if (*linea=='a' || *linea=='A') n=256; else if (*linea=='d' || *linea=='D') n=1; else return 25; if (!isdigit(c=*(++linea))) return 25; if (c>55 || c<48 ) return 25; n = n << (c-48); m += n; linea++; if (*linea++=='/') goto m; if (!isspace(*(linea-1)) && *(linea-1) != '\0' && *(linea-1) !=',') { if (*(linea-1)=='-') { if ((*linea=='a' || *linea=='A') && n>=256) n1=256; else if ((*linea=='d' || *linea=='D') && n<256) n1=1; else return 25; if (!isdigit(c=*(++linea))) return 25; if (c>55 || c<48 ) return 25; n1 = n1 << (c-48); if (n1<n) return 25; m += n1; for (n=n<<1;n1>n;n=n<<1) m += n; linea++; linea++; } else return 25; } if (*(linea-1)=='/') goto m; if (isspace(*(linea-1)) || *(linea-1) == '\0' || *(linea-1) ==',') { sprintf(masc,"%04X",m); return 0; } return 25; } /***************************************************************************/ movep() { op4=op1; if (size == 4) valor = 328; if (aa == 1 && bb==10) { valor += opp2.op+(op1.op<<9)+128; op4.op=opp1.op; } else if (aa== 10 && bb== 1) { valor += op2.op+(opp1.op<<9); } else return DIR_INCORR; if (masde16bits(op4.op)) return 28; stcat(); return 0; } /***************************************************************************/ moveq() { if (aa != 3 || bb !=1) return DIR_INCORR; if (masde8bits(op1.op)) return 28; if (op1.op>=0) valor = 28672+op1.op; else valor=28800-op1.op; return sp(valor+(opp1.op<<9)); } /***************************************************************************/ nada() { return sp(valor); }

Page 189: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

54

/***************************************************************************/ or() { if (aa==3) { valor=0; return andi(); } return and(); } /***************************************************************************/ org() { int c; directiva=3; tamdef=1; c=(contador); if (c && codigoreub) RETURN(27); if (aa != 11) RETURN(DIR_INCORR); origen=op1.op; if (segunda_pasada==1) { if (c) { num_seg++; if (num_seg == 20) return 35; /* limit max. num. segments de codi */ segmento[num_seg].origen=origen; if(contador & 1) ++contador; /* alinear final segm. A.Mas(5/4/90) */ segmento[num_seg-1].final=contador; } else segmento[num_seg].origen=origen; } else if (c) fprintf(fd,"LLLL"); contador=op1.op; return 0; } /***************************************************************************/ page() { directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ return 0; } /***************************************************************************/ rel() { directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ if (contador) RETURN(27); /* Esta directiva debe estar al principio */ codigoreub=1; return 0; } /***************************************************************************/ abso() { directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ if (contador) RETURN(27); /* Esta directiva debe estar al principio */ codigoreub=0; return 0; } /***************************************************************************/ stop() { if (aa != 3) return DIR_INCORR; if (masde16bits(op1.op)) return 28; /* Mas de 16 bits */ op4.op=op1.op; stcat(); return 0; } /***************************************************************************/

Page 190: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

55

sub() { if (aa>11) RETURN(DIR_INCORR); if (aa==3) { valor=1024; return addi(); } return add(); } /***************************************************************************/ swap() { if (aa !=1) return DIR_INCORR; return sp(valor+op1.op); } /***************************************************************************/ title() { directiva=3; /* difer. s'instruc. - A.Mas (5/4/90) */ tamdef=1; /* assegurar que NO alinei PC */ return 0; } /***************************************************************************/ trap() { if (aa != 3) return DIR_INCORR; if (masde4bits(op1.op)) return 28; /* Mas de 4 bits */ return sp(valor+op1.op); } /***************************************************************************/ unlk() { if (aa != 7) return DIR_INCORR; return sp(valor+op1.op); } /***************************************************************************/ sp(int v) { sprintf(ensamblado,"%04X",v); return 0; } /***************************************************************************/ ds() { directiva=2; tamdef=size; return 0; } /***************************************************************************/ dc() { directiva=1; tamdef=size; return 0; } /***************************************************************************/ dw() { directiva=1; tamdef=2; return 0; } /***************************************************************************/ dl() { directiva=1; tamdef=4; return 0; } /***************************************************************************/

Page 191: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

56

dbcc() { struct arbol *r; char ensamblado2[15]; if (aa !=1) return DIR_INCORR; sprintf(ensamblado2,"%04X",valor+op1.op); r=buscar_rama(raiz,oper); if (r==NULL) return 16; /* No existe esta etiqueta */ valor = r->valor-contador+2; if (valor>32767 || valor<-32767)

return 26; /*Desplazamiento demasiado grande */ if (r->tipodevariable==2 || r->tipodevariable==3) return 16; /* Variable no definida */ sprintf(ensamblado,"%s%s",ensamblado2,String_Hex(valor,16)); // sprintf(ensamblado,"%s%04X",ensamblado2,valor); //BUG: El problema es que

valor 32bits se escriben los 32bits return 0; } /***************************************************************************/ scc() { sprintf(ensamblado,"%04X",valor); return nbcd(); } /***************************************************************************/ void opp_a_op() { op1=opp1; op2=opp2; op3=opp3; } /***************************************************************************/ char* String_Hex(int val32bits,int bits) { static char hex[50]; //Podrían ser 35=32+2(0x)+1(\0) sprintf(hex,"%8X",val32bits); return hex+(8-bits/4); } /*=========================================================================*/ /*=========================================================================*/ /* FUNCIONES DE IMPLEMENTACION DE LAS MACROS */ /*=========================================================================*/ /*=========================================================================*/ int pasada_macros(char *s) { static AnsiString etim; static int argum_array[99]; //trata aparicion de argumentos en definicion macro—

>errores // \1 \2 \3 ... \99 int coment=0,t,labelin=0; int label=0,pos; etiqueta[0]='\0'; line=s; while (*line && isspace(*line)) line++; if (esta_en(*line,"*;")) /* Se considera comentario si empieza con * o ; */ coment=1; line=s; if (!coment && *line) { *palabra=*line; line=coger_palabra(line,palabra,&label); labelin=label; if (label==1) /* si ‚s etiqueta... */ { strcpy(etiqueta,palabra); etiqueta[15]='\0';

Page 192: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

57

*palabra='\0'; line=coger_palabra(line,palabra,&label); } if (*palabra != '\0') { pos=buscar_tabla(); if ((pos==89)||(pos==69)||(pos==34)) //macro=89, endm=69, callm=34 { if (pos==89) //MACRO { for (int i=0;i<99;i++) argum_array[i]=0; /*Introducimos la macro en el arbol de simbolos con tipo macro*/ etim=etiqueta; if (!raiz) raiz=insarbol(raiz,raiz,etiqueta,&err,0,6); else insarbol(raiz,raiz,etiqueta,&err,0,6); if (err) return err; } if (pos==69) //ENDM { struct arbolm *r; AnsiString Texto; Texto.printf(";******** ENDM ********"); r=buscar_rama(raizm,etim.c_str()); r->text+=Texto; r->text+="\n"; /*Comprobamos errores en array de booleanos y numero de argumentos*/ int j=0,i=0; while((argum_array[j])&&(j<99)) { i++; j++; } if(j==99) r->argumentos=98; else { while((!argum_array[j])&&(j<99)) j++; if(j==99) r->argumentos=i; else return 37; //error sintaxis macro } } if (pos==34) //CALLM NAME ARGS { struct arbolm *r; AnsiString Texto; line=coger_palabra(line,palabra,&label); //etiqueta:etiq r=buscar_rama(raizm,palabra); //palabra: macroname r->llamadas++; //line: " argumentos" Texto.printf("%s",r->text.c_str()); if (etiqueta[0]!='\0') { AnsiString EtiString; EtiString.printf("%s",etiqueta); int i=Texto.AnsiPos("*****\n"); Texto.Insert(EtiString,i+6); } /*TRATAMIENTO DE LOS ARGUMENTOS DE LA MACRO*/ while(isspace(*line)) line++; int n_argument=0; while((*line)&&(!isspace(*line))&&(*line!='\0')&&(*line!='\n')&&(*line!='\t')) { AnsiString argument,nargument;

Page 193: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

58

while((*line!=',')&&(!isspace(*line))&&(*line!='\0')&&(*line!='\n')&&(*line!='\t')) { argument+=*line++; } if(*line==',')line++; n_argument++; //tratar argumento nargument.printf("\\%d",n_argument); int i=Texto.AnsiPos(nargument); while (i) { Texto.Delete(i,nargument.Length()); Texto.Insert(argument,i); i=Texto.AnsiPos(nargument); } argument=""; } /*TRATAMIENTO DE LA ETIQUETAS INTERNAS DE LA MACRO que empiezan con @*/ int i=Texto.AnsiPos("@"); while (i) { Texto.Delete(i,1); int j=0; while(!esta_en(Texto[i+j]," ,+*-/()&!|~^<>\t\n")) { j++; } Texto.Insert(r->llamadas,i+j); i=Texto.AnsiPos("@"); } fsString+=Texto; //tratamiento de errores en numero de argumentos pasados if (n_argument!=r->argumentos) return 39; }//if(CALLM) int (*funcion)()=tabla_funciones[pos]; t=procesar(funcion); return t; }//if(MACRO,ENDM,CALLM) /*TRATAMIENTO DEL TEXTO DE LA MACRO EN SU DEFINICION*/ else if (in_macro) { struct arbolm *r; AnsiString Texto; /*Reconoce los argumentos y actualiza el array de booleanos*/ AnsiString Aux_Texto,Aux_Num; Texto.printf("%s",s); Aux_Texto=Texto; int i=Aux_Texto.AnsiPos("\\"); while (i) { Aux_Texto.Delete(1,i); int j=1; Aux_Num=Aux_Texto.SubString(1,j); while(esta_en(Aux_Num[j],"0123456789")) { j++; Aux_Num=Aux_Texto.SubString(1,j); if (Aux_Num.Length()!=j) { Aux_Num+=","; } } Aux_Num.Delete(j,1); j=Aux_Num.ToInt(); if (--j<99) argum_array[j]=argum_array[j]|1; else return 37; //error sintaxis macro

Page 194: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

59

i=Aux_Texto.AnsiPos("\\"); } /*Actualiza el campo texto de las macros*/ r=buscar_rama(raizm,etim.c_str()); r->text+=Texto; r->text+="\n"; }//else if(in_macro) else //codigo normal { fsString+=s; fsString+="\n"; }//else (codigo normal) }//if(palabra) }//if(...) return 0; } /*=========================================================================*/ macro() { if (!in_macro) { in_macro=1; //trata de forma especial las lineas hasta encontrar ENDM /*Introducimos la macro en el arbol de macros*/ if (segunda_pasada==0) { err=0; if (!raizm) raizm=insarbol(raizm,raizm,etiqueta,&err); else insarbol(raizm,raizm,etiqueta,&err); if (err) return err; } return 0; } else { return 37; //ERROR de sintaxis en macro } return 0; } /*=========================================================================*/ callm() { if (!in_macro) { //hacemos } else { return 38; //ERROR no puede aparecer en definicion de macro } return 0; } /*=========================================================================*/ endm() { if (in_macro) { in_macro=0; } else { return 37; //ERROR de sintaxis en macro } return 0; }

Page 195: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

60

arboles.cpp /***************************************************************************/ /* MODULO ARBOLES.C PERTENECIENTE AL PROGRAMA ENSAMBLADOR ENS68K */ /* */ /* */ /* Este m¢dulo contiene las funciones de manejo de rboles binarios */ /* utilizados en este ensamblador para almacenar y recuperar las eti- */ /* quetas , sus valores y el tipo de etiqueta que es. */ /* */ /***************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <alloc.h> #include <ctype.h> #include <string.h> #include <conio.h> #include "..\Ensamblador\ens.h" #include "..\Ensamblador\macros.h" /* Declaraci¢n de variables externas */ extern char *mensaje_ens68k[]; // Matriz de mensajes generales extern FILE *fd,*fl; // Punteros a los ficheros .obj y .lst static char ti[][25]={ "LOCAL ABSOLUTA", "LOCAL REUBICABLE", "EXTERNA", "GLOBAL NO INICIALIZADA", "GLOBAL ABSOLUTA", "GLOBAL REUBICABLE", "MACRO", }; /*=========================================================================*/ /* Funci¢n : buscar_rama Descripci¢n : Esta funci¢n nos busca dentro de una estructura de arbol binario en que tendremos las etiquetas del programa una determinada etiqueta devolviendonos un puntero a la rama que estamos buscando.Es una funci¢n recursiva.Esta funci¢n es llamada cada vez que es necesario recuperar el valor de una etiqueta. Parametros : struct arbol *a - Puntero al arbol de etiquetas. char *label - Puntero a un string conteniendo la etiqueta que estamos buscando. Retorno : Nos devuelve un puntero con la direcci¢n de la rama que estamos buscando. */ /*=========================================================================*/ struct arbol *buscar_rama(struct arbol *a,char *label) { register int c; if (!a) return NULL; if (!(c=strcmp(label,a->label))) return a; return buscar_rama((c>0) ? a->arbol_der : a->arbol_izq,label); } /*=========================================================================*/ /* Funci¢n : eliminar_rama Descripci¢n : Esta funci¢n nos elimina de una estructura de arbol binario en que tendremos las etiquetas del programa una determinada etiqueta.Esta funci¢n es llamada por las funciones equ , high y low del m¢dulo TABLA.C cuando no se puede resolver

Page 196: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

61

el valor de una etiqueta. Parametros : struct arbol a - Puntero al arbol de etiquetas. char *label - Puntero a un string conteniendo la etiqueta que deseamos eliminar. */ /*=========================================================================*/ void eliminar_rama(struct arbol *a,char *label) { register int c; struct arbol *b; if (!a) return ; if (!(c=strcmp(label,a->label))) { free(a); a=NULL; } else if (c>0) { b=a->arbol_der; if (!stricmp(label,b->label)) { free(b); a->arbol_der=NULL; return; } eliminar_rama(a->arbol_der,label); } else { b=a->arbol_izq; if (!stricmp(label,b->label)) { free(b); a->arbol_izq=NULL; return; } eliminar_rama(a->arbol_izq,label); } } /*=========================================================================*/ /* Funci¢n : ins_arbol Descripci¢n : Esta funci¢n nos inserta dentro de una estructura de arbol binario en que tendremos las etiquetas del programa una determinada etiqueta devolviendonos un puntero a la raiz del arbol.Es una funci¢n recursiva. (alfabéticamente) Parametros : struct arbol *r - Puntero al arbol de etiquetas. struct arbol *a - Puntero a la rama que queremos insertar. char *label - Puntero a un string conteniendo la etiqueta que deseamos insertar. int *error - Puntero a una variable que contendra el tipo de error cometido.Sera 0 si no hay ningun error. long int dato - Valor de la etiqueta.(valor de contador PC) int tipodevariable - Tipo de etiqueta con uno de los siguientes valores posibles: 0-Local absoluta 1-Local reubicable 2-Externa 3-Global no inicializada 4-Global absoluta 5-Global reubicable Retorno : Nos devuelve un puntero con la direccion de la rama que estamos buscando. */ /*=========================================================================*/ struct arbol *insarbol(struct arbol *r,struct arbol *a,char *label,int *error,int dato,int tipodevariable)

Page 197: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

62

{ register int c; char *k; k=label; //guardas nombre de etiqueta if (!a) { if(*k<33 || esta_en(*k,"0123456789+-*/&!|~^><()$%")) { *error=10; /* Etiqueta no v lida */ return r; /* por caracter inicial */ } while (*k != '\0') { if(*k<33 || esta_en(*k,"+-*/()&!|~^<>")) { *error=10; /* Etiqueta no valida */ return r; /* por caracter intermedio */ } k++; } a=(struct arbol *) malloc(sizeof(struct arbol)); if (!a) { sprintf(aux_str,"\n%s\n",mensaje_ens68k[18]); /* Memoria insuficiente */ Mensaje(aux_str); throw "ENS1"; //provoca una excepcion en win si no se ha terminado el prog

correctamente } a->arbol_izq=NULL; a->arbol_der=NULL; strcpy(a->label,label); a->valor=dato; a->tipodevariable=tipodevariable; if (!r) return a; c=strcmp(label,r->label); if (c>0) r->arbol_der=a; if (c<0) r->arbol_izq=a; return a; } c=strcmp(label,a->label); if(!c) { if (a->tipodevariable == 2) { if (tipodevariable == 3) { *error=11; /* Declarar global una externa */ return r; } *error=12; /*No se puede dar valor a una externa */ return r; } if (a->tipodevariable == 3) { if (tipodevariable == 2) { *error=11; /* Declarar externa una global */ return r; } a->tipodevariable=4+tipodevariable; a->valor=dato; return r; } *error=3; return r; } else insarbol(a,(c>0) ? a->arbol_der : a->arbol_izq,label,error,dato,tipodevariable); } /*=========================================================================*/

Page 198: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

63

/* Funci¢n : listar_arbol Descripci¢n : Esta funci¢n nos inserta dentro de una estructura de arbol binario en que tendremos las etiquetas del programa una determinada etiqueta devolviendonos un puntero a la raiz del arbol.Es una funci¢n recursiva. Parametros : struct arbol *a - Puntero al rbol de etiquetas. int i - Variable que nos indica el destino del listado.Puede tomar los valores : 1: fichero objeto 2: fichero de listado */ /*=========================================================================*/ void listar_arbol (struct arbol *a,int i) { char v[9],v2[9]; if (!a) return; listar_arbol (a->arbol_izq,i); sprintf(v,"%08lX",a->valor); strcpy(v2,v); v2[4]=0; if (i==1) if (a->tipodevariable !=3) fprintf(fd,"%-15s %8s %d\n",a->label,v,a->tipodevariable); if (i==2) { sprintf(aux_str,"%-15s : %4s %4s : %s\n",a->label,v2,v+4,ti[a->tipodevariable]); flMens(aux_str); } listar_arbol (a->arbol_der,i); } /*=========================================================================*/ /*=========================================================================*/ /*=========================================================================*/ /* FUNCIONES DE IMPLEMENTACION DE MACROS */ /*=========================================================================*/ /* Funci¢n : ins_arbol Descripci¢n : Esta funci¢n nos inserta dentro de una estructura de arbol binario en que tendremos las macros del programa una determinada macro devolviendonos un puntero a la raiz del arbol.Es una funci¢n recursiva. (alfabéticamente) Parametros : struct arbolm *r - Puntero al arbol de macros. struct arbolm *a - Puntero a la rama que queremos insertar. char *label - Puntero a un string conteniendo el nombre de la macro que deseamos insertar. int *error - Puntero a una variable que contendra el tipo de error cometido.Sera 0 si no hay ningun error. Retorno : Nos devuelve un puntero con la direccion de la rama que estamos buscando. */ /*=========================================================================*/ struct arbolm *insarbol(struct arbolm *r,struct arbolm *a,char *label,int *error) { register int c; char *k; k=label; //guardas nombre de etiqueta if (!a) { if(*k<33 || esta_en(*k,"0123456789+-*/&!|~^><()$%")) { *error=10; /* Etiqueta no v lida */ return r; /* por caracter inicial */ } while (*k != '\0') { if(*k<33 || esta_en(*k,"+-*/()&!|~^<>")) { *error=10; /* Etiqueta no valida */

Page 199: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

64

return r; /* por caracter intermedio */ } k++; } a=(struct arbolm *) malloc(sizeof(struct arbolm)); if (!a) { sprintf(aux_str,"\nMemoria insuficiente\n"); /* Memoria insuficiente */ Mensaje(aux_str); throw "ENS1"; //provoca una excepcion en win si no se ha terminado el prog

correctamente } a->arbol_izq=NULL; a->arbol_der=NULL; strcpy(a->label,label); a->text.printf(";***** MACRO: %s *****\n",label); a->llamadas=0; a->argumentos=0; if (!r) return a; c=strcmp(label,r->label); if (c>0) r->arbol_der=a; if (c<0) r->arbol_izq=a; return a; } c=strcmp(label,a->label); if(!c) //si iguales { *error=3; return r; } else insarbol(a,(c>0) ? a->arbol_der : a->arbol_izq,label,error); } /*=========================================================================*/ /* Funci¢n : buscar_rama Descripci¢n : Esta funci¢n nos busca dentro de una estructura de arbol binario en que tendremos las macro del programa una determinada macro devolviendonos un puntero a la rama que estamos buscando.Es una funci¢n recursiva.Esta funci¢n es llamada cada vez que es necesario recuperar el valor de una etiqueta. Parametros : struct arbolm *a - Puntero al arbol de etiquetas. char *label - Puntero a un string conteniendo la etiqueta que estamos buscando. Retorno : Nos devuelve un puntero con la direcci¢n de la rama que estamos buscando. */ /*=========================================================================*/ struct arbolm *buscar_rama(struct arbolm *a,char *label) { register int c; if (!a) return NULL; if (!(c=strcmp(label,a->label))) return a; return buscar_rama((c>0) ? a->arbol_der : a->arbol_izq,label); } /*===================== FIN DEL MODULO ARBOLES.C ==========================*/

Page 200: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

65

func.cpp /***************************************************************************/ /* MODULO FUNC.C PERTENECIENTE AL PROGRAMA ENSAMBLADOR ENS68K */ /* */ /* */ /* Este m¢dulo contiene una serie de funciones de apoyo para el */ /* ensamblador de lineas , para extraer operandos , nemot‚cnicos y */ /* para descifrar los operandos y codificarlos. */ /***************************************************************************/ /* Declaraci¢n de cabeceras */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "..\Ensamblador\ens.h" /* Prototipos de las funciones est ticas */ static struct operando registro (char *,int); /* Declaraci¢n de variables externas */ extern struct operando op1,op2,op3,op4; extern struct operando opp1,opp2,opp3,opp4; extern int tipo; /* y el direccionamiento */ extern int externo,externo2; extern int segunda_pasada; /* Flag de n£mero de pasada */ extern FILE *fd; /* Fichero OBJ */ extern char oper[60],oper1[60]; extern int size; /* Tama¤o de la instrucci¢n */ extern int contador; /* Contador de programa */ /*=========================================================================*/ // Funcion: coger_palabra // palabra: primera palabra de una linea (etiqueta o nemónico) // linea: puntero q apunta a la 1ª palabra tras nemonico (parámetros) // label: etiqueta o nemonico // size: =1(.B) =2(.W) =4(.L) =8(.S) =32(.?) =16(sin '.') // Limitacion de que una etiqueta no debe llevar ningun punto. /*=========================================================================*/ char *coger_palabra(char *line,char *palabra,int *label) { *label=1; /*Eliminar espacios anteriores*/ while (isspace(*line)) { line++; *label=0; } *palabra=*line++; /*Coger palabra*/ while (!isspace(*line) && *line ) *++palabra=*line++; /*Comprobacion de si es etiqueta*/ if (*palabra== ':') { *label=1; *palabra='\0'; } else *++palabra='\0'; size=16; /*Si es una etiqueta finalizar la funci¢n */ if (*label) return line; /*Averiguar el tamano de la instruccion*/ if (*(palabra-2) == '.') {

Page 201: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

66

*(palabra-2)=0; switch (toupper(*(--palabra))) { case 'B' : size=1; break; case 'W' : size=2; break; case 'L' : size=4; break; case 'S' : size=8; break; default : size=32; } } /*-----Hacer que line apunte a la proxima palabra de la linea-----*/ while (isspace(*line)) line++; return line; } /*=========================================================================*/ /* La funci¢n cogeyanal nos devuelve como resultado un apuntador al proximo caracter despues del operando y en err el error cometido. En operando nos quedara el operando que andamos buscando. En aa nos quedara el tipo de direccionamiento que utiliza. El tipo de direccionamiento es: 1 = Registro direcciones 2 = Ind registro e indice 3 = Inmediato 4 = Registro Indirecto 5 = Predecremento 6 = Postincremento 7 = Registro datos 8 = Relativo al PC 9 = Relativo al PC con indice 10= Registro Ind. con offset 11= Direccion absoluta 12= CCR 13= SR 14= USP (+error =8) */ /*=========================================================================*/ char *cogeyanal(char *line, int *err,int *externo,int *aa) { int parentesis=0; char *operando; int reubicable=0; char *s,*c,*fin; *err=0; strcpy(oper1,oper); operando=oper; tipo=0; *operando='\0'; if (*line=='\0') { *err=5; // No hay operando return line; } //Comprobar parentesis balanceados while (!isspace(*line) && *line && *line !=',') { if (*line=='(') { parentesis++; tipo=1;

Page 202: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

67

} if (*line==')') parentesis--; if (parentesis<0) { *err= 4; return line; } *operando++=*line++; } *operando='\0'; if (*line==',') { if (!parentesis) ++line; else { if (parentesis>1) { *err=4; //2 parentesis abiertos return line; } *operando++=*line++; tipo=2; while (!isspace(*line) && *line !='\0' && *line !=',') { if (*line=='(') parentesis++; if (*line==')') parentesis--; if (parentesis>1) { *err=4; //2 parentesis abiertos return line; } if (parentesis<0) { *err=4; //demasiados parentesis cerrados return line; } *operando++=*line++; } if (*line==',' && parentesis>0) { *err=7; return line; } if (*line ) line++; } } if (parentesis) { *err=4; // Parentesis no balanceados return line; } *operando='\0'; s=c=oper; while (*++s ); fin=s; if (tipo==2) //d8(An,Ri) o d8(PC,Ri) { while (*c++ != ','); if(*--s != ')') { *err=7; //Error de sintaxis return line; } opp3=registro(c,s-c); if (!(opp3.tamano)) { *err=17; //Operando no es un registro return line; } if (opp3.tamano==1)

Page 203: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

68

{ *err=18; //Tamano no puede ser byte return line; } c--; s=c; while (*--c != '(' ); c++; opp2=registro(c,s-c); if (!(opp2.tamano)) { if ((*c=='P' || *c=='p') && (*(c+1)=='c' || *(c+1)=='C')) { *aa=9; opp2=opp3; } else { *err=17 ; //Operando no es un registro return line; } } else { if (opp2.datos) { *err=19 ; //Registro de datos (no direcciones) return line; } if (opp2.tamano==1 || opp2.tamano==2) { *err=18 ; //Tamano incorrecto return line; } *aa=2; } c--; opp1.op=hallar_valor(oper,c-oper,err,&reubicable,externo); if (*err) return line; if (reubicable) { *err=20; //NO puede ser reubicable return line; } if (*aa==9) opp1.op +=contador; return line; } if (*oper=='#') //Inmediato { c++; opp1.op=hallar_valor(c,s-c,err,&reubicable,externo); if (*err) return line; if (reubicable) { *err=20; // NO puede ser reubicable return line; } *aa=3; return line; } switch (s-oper) { case 2: // An o Dn if (!stricmp(oper,"SR")) { *aa=13; return line; } opp1=registro(oper,2); if (opp1.tamano)

Page 204: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

69

{ if (!opp1.datos) *aa=7; else *aa=1; return line; } break; case 3: if (!stricmp(oper,"CCR")) { *aa=12; return line; } if (!stricmp(oper,"USP")) { *aa=14; *err=8; return line; } break; case 5: // -(An) o (An)+ opp1=registro(oper+2,2); if (*oper == '-' && *(oper+1)=='(' && *(oper+4)==')'&& (opp1.tamano)) { if (opp1.datos) *err=21; *aa=5; return line; } opp1=registro(oper+1,2); if (*oper == '(' && *(oper+3)==')' && *(oper+4)=='+'&& (opp1.tamano)) { if (opp1.datos) *err=21; *aa=6; return line; } break; case 4: // (An) o An.b o Dn.b opp1=registro(oper,4); if (opp1.tamano) { if (!opp1.datos) *aa=7; else *aa=1; return line; } if (*oper =='(') { opp1=registro(oper+1,2); if (opp1.tamano) { if (*(oper+3)==')') { if (opp1.datos) *err=22; *aa=4; return line; } *err=7; return line; } } break; case 6: // (An.b) if (*oper =='(') { opp1=registro(oper+1,4); if (opp1.tamano) { if (*(oper+5)==')') { if (opp1.datos) *err=22; *aa=4; return line; }

Page 205: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

70

*err=7; return line; } } break; case 7: // -(An.b) o (An.b)+ opp1=registro(oper+2,4); if (*oper == '-' && *(oper+1)=='(' && *(oper+6)==')'&& (opp1.tamano)) { if (opp1.datos) *err=21; *aa=5; return line; } opp1=registro(oper+1,4); if (*oper == '(' && *(oper+5)==')' && *(oper+6)=='+'&& (opp1.tamano)) { if (opp1.datos) *err=21; *aa=6; return line; } break; } if (*--s==')') { c=s; while (*--c != '(' ); if (c != oper) { c++; opp2=registro(c,s-c); if (opp2.tamano || /* RSYMB(Ri) o d16(An) o d16(PC) */ ((*c=='P'||*c=='p') && (*(c+1)=='c'||*(c+1)=='C'))) { --c; opp1.op=hallar_valor(oper,c-oper,err,&reubicable,externo); if (*err) return line; if (*externo) { *err=32; return line; } if (opp2.tamano==1) { *err=18; // Tamano incorrecto return line; } if (reubicable ) { if (opp2.tamano) { *aa=9; return line; } *err=20; // NO puede ser reubicable return line; } if (!opp2.tamano) { *aa=8; opp1.op +=contador; return line; } if (opp2.datos) *err=23; if (opp2.tamano==2) *err=18; // Tamano incorrecto *aa=10; return line; } } } opp1.op=hallar_valor(oper,fin-oper,err,&reubicable,externo); if (reubicable) *aa=8;

Page 206: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

71

else *aa=11; return line; } /*******************************************************************************/ static struct operando registro (char *reg,int l) { struct operando r; if (l==2 && toupper(*reg)=='S' && toupper(*(reg+1))=='P') { r.datos=0; r.op=7; r.tamano=4; return r; } r.tamano=0; r.op=0; if (l != 2 && l != 4 ) return r; switch (toupper(*reg)) { case 'A' : r.datos=0;break; case 'D' : r.datos=1;break; default : return r; } if (!isdigit(*++reg)) return r; if ((r.op = atoi(reg)) >7) return r; if (r.op <0) return r; if (l==2) { r.tamano=4; return r; } if (*++reg != '.') return r; switch (toupper(*++reg)) { case 'W' : r.tamano=2;break; case 'B' : r.tamano=1;break; case 'L' : r.tamano=3; } return r; } /*******************************************************************************/ int tipo2(int valor,int aa,char *ensamblado,char *operando) { char ensamblado2[10],*ensam; switch (aa) { case 1 : valor += op1.op; sprintf(ensamblado,"%04X",valor); contador += 2; break; case 7 : valor += op1.op+8; sprintf(ensamblado,"%04X",valor); contador += 2; break; case 4 : valor += op1.op+16; sprintf(ensamblado,"%04X",valor); contador += 2; break; case 5 : valor += op1.op+32; sprintf(ensamblado,"%04X",valor); contador += 2; break; case 6 : valor += op1.op+24;

Page 207: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

72

sprintf(ensamblado,"%04X",valor); contador += 2; break; case 10 : valor += op2.op+40; sprintf(ensamblado,"%04X",valor); if (masde16bits(op1.op)) return 26; sprintf(ensamblado2,"%04X",op1.op); if (op1.op<0) strcpy(ensamblado2,ensamblado2+4); strcat(ensamblado,ensamblado2); contador += 4; break; case 2 : valor += op2.op+48; sprintf(ensamblado,"%04X",valor); if (!op3.datos) valor=32768; else valor=0; valor += op3.op<<12; if (op3.tamano==3) valor += 2048; if (masde8bits(op1.op)) return 26; valor += op1.op; if (op1.op<0) valor-=65280; //0xFF00 sprintf(ensamblado2,"%04X",valor); strcat(ensamblado,ensamblado2); contador += 4; break; case 11 : if(externo) //simepre .L { valor +=57; sprintf(ensamblado,"%04X",valor); sprintf(ensamblado2,"%08X",0); if (segunda_pasada==2) fprintf(fd,"KKKK\n%s\n",operando); contador += 6; } else { valor += 57; /* fer (Adr.L) */ sprintf(ensamblado,"%04X",valor); sprintf(ensamblado2,"%08lX",op1.op); contador += 6; } strcat(ensamblado,ensamblado2); break; case 9 : valor += 59; sprintf(ensamblado,"%04X",valor); if (!op2.datos) valor=128; else valor=0; valor += op2.op<<4; if (op2.tamano==3) valor += 8; sprintf(ensamblado2,"%02X",valor); strcat(ensamblado,ensamblado2); valor = op1.op-contador-2; if (valor>127 || valor<-128) return 26; //Desplazam demasiado grande sprintf(ensamblado2,"%02X",valor); ensam=ensamblado2; if (valor<0) ensam+=2; strcat(ensamblado,ensam); contador += 4; break; case 8 : valor += 58; sprintf(ensamblado,"%04X",valor); valor=op1.op-contador-2;

Page 208: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

73

if (valor>32767 || valor<-32768) /*Despl demas grande */ { if(segunda_pasada==2) return 26; /* error real a la 2a

passada */ else valor &= 0xffff; } sprintf(ensamblado2,"%04X",valor); strcat(ensamblado,ensamblado2); contador += 4; break; case 3 : valor += 60; sprintf(ensamblado,"%04X",valor); if (((size==2) && masde16bits(op1.op)) || ((size==1) && masde8bits (op1.op))) return 28; if (size==4) { if (externo) { op1.op=0; if (segunda_pasada==2) fprintf(fd,"KKKK\n%s\n",operando+1); } sprintf(ensamblado2,"%08lX",op1.op); contador += 6; } else { contador +=4; if (externo==1) return 33; if (masde16bits(op1.op)) return 18; /* Tama¤o incorrecto*/ sprintf(ensamblado2,"%04X",op1.op); } strcat(ensamblado,ensamblado2); break; } return 0; } /*******************************************************************************/ int tipo3(int valor,int aa,char *ensamblado) { char ensamblado2[10]; if (externo) { if (size !=4) return 33; //.L if (segunda_pasada==2) fprintf(fd,"KKKK\n%s\n",oper1+1); op4.op=0; } switch (aa) { case 1 : valor += opp1.op; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=6; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 4; } strcat(ensamblado,ensamblado2); break; case 7 :

Page 209: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

74

valor += opp1.op+8; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=6; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 4; } strcat(ensamblado,ensamblado2); break; case 4 : valor += opp1.op+16; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=6; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 4; } strcat(ensamblado,ensamblado2); break; case 5 : valor += opp1.op+32; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=6; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 4; } strcat(ensamblado,ensamblado2); break; case 6 : valor += opp1.op+24; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=6; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 4;

Page 210: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

75

} strcat(ensamblado,ensamblado2); break; case 10 : valor += opp2.op+40; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=8; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 6; } strcat(ensamblado,ensamblado2); if (masde16bits(opp1.op)) return 28; sprintf(ensamblado2,"%04X",opp1.op); strcat(ensamblado,ensamblado2); break; case 2 : valor += opp2.op+48; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=8; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 6; } strcat(ensamblado,ensamblado2); if (!opp3.datos) valor=32768; else valor=0; valor += opp3.op<<12; if (opp3.tamano==3) valor += 2048; if (masde8bits(opp1.op)) return 28; valor += opp1.op; sprintf(ensamblado2,"%04X",valor); strcat(ensamblado,ensamblado2); break; case 11 : valor += 57; sprintf(ensamblado,"%04X",valor); if (size==4) { sprintf(ensamblado2,"%08lX",op4.op); contador+=10; } else { if (size==1 && masde8bits(op4.op)) return 28; /* Valor demas.grande */ else if (masde16bits(op4.op)) return 28; sprintf(ensamblado2,"%04X",op4.op); contador += 8; } strcat(ensamblado,ensamblado2); if (externo2)

Page 211: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

76

{ if (segunda_pasada==2) fprintf(fd,"KKKK\n%s\n",oper); opp1.op=0; } sprintf(ensamblado2,"%08lX",opp1.op); strcat(ensamblado,ensamblado2); break; } return 0; } /*******************************************************************************/ int masde4bits( int a) { return (a>15 || a<-8) ? 1:0; } /*******************************************************************************/ int masde8bits(int a) { return (a>255 || a<-128) ? 1:0; } /*******************************************************************************/ int masde16bits(int a) { return (a>65535 || a<-32768) ? 1:0; } /*******************************************************************************/ int esta_en (char c,char *s) { while (*s) if (*s++==c) return 1; return 0; } /*******************************************************************************/ int hexdec(char *expresion,int *err) { register int i; int a=0,v=0; int c; for (i=strlen(expresion)-1;i>=0; i--) { if (isxdigit(c=toupper(expresion[i]))) { if (c>64) a+=(c-55)<<v; else a+=(c-48)<<v; v += 4; } else if (i==0 && c=='-') a=-a; else *err=31; } return a; } /*******************************************************************************/ int bindec(char *expresion,int *err) { register int i; int a=0,v=0; int c; for (i=strlen(expresion)-1;i>=0; i--) { c=expresion[i]; if (c=='0'|| c=='1') { a+=(c-48)<<v; v++; } else if (i==0 && c=='-') a=-a; else *err=31; } return a; }

Page 212: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

77

errores.cpp /***************************************************************************/ /* MODULO ERRORES.C PERTENECIENTE AL PROGRAMA ENSAMBLADOR ENS68K */ /* */ /* */ /* Este m¢dulo contiene los mensajes de error del ensamblador as¡ */ /* como la funci¢n que se encarga de presentar estos mensajes por la */ /* pantalla y por el fichero de listado e impresora . */ /* */ /***************************************************************************/ /* Declaraci¢n de cabeceras */ #include <vcl.h> #include <stdio.h> #include <conio.h> #include <ctype.h> #include "..\Ensamblador\ens.h" /* Declaraci¢n de variables externas */ extern char *FListado; extern FILE *fl; /* Puntero del fichero de listado */ extern int errores; /* N£mero total de errores cometidos */ static char *terror[]={ /*0*/ "", /*1*/ "Nemotecnico incorrecto", "Extension de la instruccion incorrecta", "Etiqueta repetida", "Parentesis no balanceados", /*5*/ "Numero de operandos incorrecto", "Falta etiqueta", "Error de sintaxis", "Tipo de direccionamiento no valido", "Programa no terminado con END", /*10*/ "Etiqueta no valida", "Etiqueta ya declarada", "Se da valor a una etiqueta externa", "Operacion ilegal : Absoluto-Reubicable", "Operacion ilegal : Reubicable+Reubicable", /*15*/ "Operacion ilegal : Multiplicacion o Division de Reubicable", "Etiqueta no definida", "Se esperaba un registro", "Tamaño incorrecto", "Registro debe ser de direcciones no de datos", /*20*/ "No puede ser reubicable", "En predecremento y postincremento, registros de direcciones", "En direccionamientos indirectos, registros de direcciones", "Registro debe ser de direcciones", "Division por cero", /*25*/ "Error en la lista de registros", "Desplazamiento demasiado grande", "Esta directiva debe estar al principio del programa", "Valor incorrecto", "'Branch short' a la siguiente instruccion", /*30*/ "No se puede resolver la etiqueta", "Valor hexadecimal incorrecto", "No es posible una etiqueta externa", "Tamaño debe ser LONG para etiquetas externas", "Instruccion no ensamblable directamente",/* Solo Enslinea */ /*35*/ "Numero maximo de segmentos sobrepasado", "Error en el uso de la directiva", "Error de sintaxis en la definicion de una macro", "No puede aparecer en la definicion de una macro", "Número de parámetros de la macro incorrectos", /*40*/ "Definición de macro no terminada con ENDM", };

Page 213: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

78

/*=========================================================================*/ /* Funci¢n : error Descripci¢n : Esta funci¢n se llama cada vez que el ensamblador encuen- tra un error y nos muestra una descripci¢n del error come- tido por la pantalla.Si se esta ensamblando en la impre- sora o estamos generando un fichero de listado tambien grabara el error en el fichero pertinente.Cada vez que se llama a esta funci¢n se incrementa la variable global errores que contiene el numero total de errores cometidos durante el ensamblado. Parametros : tipo - Numero del error cometido. */ /*=========================================================================*/ void error(int tipo,int n_linea,char *linea) { AnsiString line;int pos=0; while((*linea)&&(isspace(*linea))) linea++; line=linea; line.Delete(line.Pos(";"),1000); while(line[line.Length()]==' ') line.Delete(line.Length(),1); line.SetLength(25); //eliminar tabs para formato de lista pos=line.Pos('\t'); while (pos!=0) { line.Delete(pos,1); line.Insert(" ",pos); pos=line.Pos('\t'); } linea=line.c_str(); errores++; sprintf(aux_str," * Linea: %.5d en '%s' \t>>>%-35s

\t>>>%s",n_linea,fichero,linea,terror[tipo]); MensajeErr(aux_str); if (FListado!=NULL) { sprintf(aux_str," * Linea: %.5d en '%s' >>> %-35s >>>

%s\n",n_linea,fichero,linea,terror[tipo]); flErr(aux_str); } } /*===================== FIN DEL MODULO ERRORES.C ==========================*/

Page 214: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

79

parser.cpp /***************************************************************************/ /* MODULO PARSER.C PERTENECIENTE AL PROGRAMA ENSAMBLADOR ENS68K */ /* */ /* */ /* Este m¢dulo contiene un parser del tipo recursivo descendente */ /* para descifrar y evaluar expresiones matem ticas y l¢gicas con n£- */ /* meros en binario , decimal y hexadecimal as¡ como con etiquetas */ /* previamente definidas. */ /***************************************************************************/ /* Declaraci¢n de cabeceras */ #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <setjmp.h> #include "..\Ensamblador\ens.h" #define DELIMITADOR 1 #define VARIABLE 2 #define NUMERO 3 /* Declaraci¢n de variables externas */ extern int segunda_pasada; /* Indica si estamos en la segunda pasada */ extern int codigoreub; /* Indica si el codigo es reubicable */ extern struct arbol *raiz; /* Puntero al rbol de etiquetas */ /* Declaraci¢n de variables globales est ticas */ static jmp_buf ebuf; /* Puntero a la zona del programa donde debe saltar cuando se ha cometido un error */ static char p[256]; /* Matriz que contendr la expresi¢n a evaluar */ static char *prog; /* Puntero a una posici¢n de la expresi¢n */ static char termino[80]; /* Matriz donde se guardar n los terminos */ char tipo_termino; /* Tipo del termino */ static int reub,reub2; /* Se utilizan para comprobar si una expresi¢n es absoluta o reubicable */ static int segpasadaparser; /* Indica si el PARSER no puede evaluar una expresi¢n en esta pasada */ /* Prototipos de las funciones utilizadas solo en este m¢dulo */ static void coger_expresion( int *); static void nivel1(int *); static void nivel2(int *); static void nivel3(int *); static void nivel4(int *); static void nivel5(int *); static void nivel6(int *); static void primitiva(int *); static void arit (char ,int *,int *); static void unitario (char, int *); static void coger_termino(void); static esdelimitador(char); static int valor(char *); /*=========================================================================*/ /* Funci¢n : coger_expresion Descripci¢n : Esta es la funci¢n a la que se llama para resolver una expresi¢n.Es llamada por la funci¢n hallar_valor que inicializa el PARSER y lo prepara para funcionar correc- tamente. Par metros : long int *resultado - Contendr el resultado de evaluar la expresi¢n contenida en la varia- ble global p. */ /*=========================================================================*/ static void coger_expresion(int *resultado) {

Page 215: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

80

coger_termino(); if (!*termino) longjmp(ebuf,7); nivel1(resultado); } /*=========================================================================*/ /* Funciones : nivel1 a nivel6 Descripci¢n : Estas funciones eval£an trozos de la expresi¢n a evaluar teniendo en cuenta los niveles de prioridad del lgebra. Para comprender su funcionamiento remitirse a las expli- caciones dadas en el cap¡tulo 4 del proyecto. Par metros : long int *resultado - Contendr el resultado de evaluar la expresi¢n contenida en la varia- ble global p. */ /*=========================================================================*/ /* OR (|) y XOR (^) */ static void nivel1(int *resultado) { register char op; int hold; nivel2(resultado); while ((op = *termino) == '|' || op == '^') { coger_termino(); nivel2(&hold); arit(op,resultado,&hold); } } /* AND & */ static void nivel2(int *resultado) { register char op; int hold; nivel3(resultado); while ((op = *termino) == '&' ) { coger_termino(); nivel3(&hold); arit(op,resultado,&hold); } } /* Sumar o restar dos terminos */ static void nivel3(int *resultado) { register char op; int hold; nivel4(resultado); while ((op = *termino) == '+' || op == '-') { coger_termino(); nivel4(&hold); arit(op,resultado,&hold); } } /* Multiplicar o dividir SHIFT IZQ (<) Y DER (>) */ static void nivel4(int *resultado) { register char op; int hold; nivel5(resultado); while((op = *termino) == '*' || op == '/'|| op == '<'|| op == '>') { coger_termino(); nivel5(&hold); arit (op,resultado,&hold); } }

Page 216: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

81

/* + o - unitario y NOT (!) */ static void nivel5(int *resultado) { register char op; op=0; if((tipo_termino == DELIMITADOR) && *termino == '+' || *termino == '-'|| *termino == '!') { op = *termino; coger_termino(); } nivel6(resultado); if (op) unitario(op,resultado); } /* Expresion con par‚ntesis */ static void nivel6(int *resultado) { if ((*termino == '(') && (tipo_termino == DELIMITADOR)) { coger_termino(); nivel1(resultado); if(*termino != ')') longjmp(ebuf,4); coger_termino(); } else primitiva(resultado); } /*=========================================================================*/ /* Funci¢n : primitiva Descripci¢n : Esta funci¢n utiliza las variables globales tipo_termino y termino para hallar el valor de termino.La variable tipo_termino debe ser o VARIABLE o NUMERO , sino es as¡ hay un error de sintaxis en la expresi¢n. Par metros : long int *resultado - Puntero a la variable que contendr el valor de termino. */ /*=========================================================================*/ static void primitiva(int *resultado) { char prueba[15]; int errorparser=0; switch(tipo_termino) { case VARIABLE: *resultado=valor(termino); coger_termino(); return; case NUMERO: if (*termino == '$') /* Numero hexadecimal */ *resultado = hexdec (termino+1,&errorparser); else if (*termino == '%') /* Numero binario */ *resultado = bindec (termino+1,&errorparser); else /* Numero decimal */ { *resultado=atol(termino); ltoa(*resultado,prueba,10); if (strcmp(prueba,termino)) errorparser=28; } if (errorparser) longjmp(ebuf,errorparser); reub2=0; coger_termino(); return; default: longjmp(ebuf,7); } }

Page 217: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

82

/*=========================================================================*/ /* Funci¢n : arit Descripci¢n : Esta funci¢n realiza una operaci¢n especificada en la variable o sobre los t‚rminos r y h . Esta operaci¢n debe ser una de las operaciones v ildas implementadas en este PARSER. Par metros : char o - En esta variable se debe especificar la ope- raci¢n a realizar entre los dos t‚rminos. Debe tener uno de los siguientes valores : + , - , * , / , & , ^ , | , < ¢ > . long int *r - Primer t‚rmino de la operaci¢n .En este t‚rmino quedar el resultado de la operaci¢n. long int *h - Segundo t‚rmino de la expresi¢n. */ /*=========================================================================*/ static void arit (char o,int *r,int *h) { switch(o) { case '-': if (reub2) reub = !reub; else if (reub) longjmp(ebuf,13); /* absoluto-reubicable es ilegal */ *r -= *h; break; case '+': if (reub2) { if (reub) longjmp(ebuf,14); /* Reubicable+reubicable es ilegal*/ reub=1; } *r += *h; break; case '*': if (reub2) longjmp(ebuf,15); /* reubicable* todo es ilegal */ if (reub) longjmp(ebuf,15); /* absoluto*reubicable es ilegal */ *r *= *h; break; case '/': if (!*h) longjmp(ebuf,24); /* Division por cero */ if (reub2) longjmp(ebuf,15); /* reubicable/ todo es ilegal */ if (reub) longjmp(ebuf,15); /* absoluto/reubicable es ilegal */ *r /= (*h); break; case '^': if (reub2 ^ reub) longjmp(ebuf,14); /* Deben ser del mismo tipo */ *r = *r ^ *h; break; case '|': if (reub2 ^ reub) longjmp(ebuf,14); /* Deben ser del mismo tipo */ *r = *r | *h; break; case '&': if (reub2 ^ reub) longjmp(ebuf,14); /* Deben ser del mismo tipo */ *r = *r & *h; break; case '>': if (reub2 ^ reub) longjmp(ebuf,14); /* Deben ser del mismo tipo */ *r = *r >> *h; break; case '<': if (reub2 ^ reub) longjmp(ebuf,14); /* Deben ser del mismo tipo */ *r = *r << *h; break; } reub2=reub; } /*=========================================================================*/ /* Funci¢n : unitario Descripci¢n : Esta funci¢n se utiliza para implementar el NOT y el

Page 218: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

83

cambio de signo. Parametros : char o - En esta variable se debe especificar la ope- raci¢n a realizar entre los dos t‚rminos. Debe tener uno de los siguientes valores : - ¢ ! . long int *r - Primer termino de la operaci¢n .En este termino quedara el resultado de la operaci¢n. */ /*=========================================================================*/ static void unitario (char o,int *r) { if(o=='-') *r = -(*r); if(o=='!') *r = ~(*r); } /*=========================================================================*/ /* Funci¢n : coger_termino Descripci¢n : Esta funci¢n se encarga de extraer uno a uno los t‚rminos que forman la expresi¢n a evaluar.Extrae los t‚rminos de la expresi¢n almacenada en p y los coloca en termino. */ /*=========================================================================*/ static void coger_termino() { register char *temp; /* Puntero temporal */ tipo_termino=0; temp=termino; while(isspace(*prog)) ++prog; /* Elimina los espacios anteriores */ if(esta_en(*prog,"+-*/()<>&|^!")) { tipo_termino = DELIMITADOR; *temp++ = *prog++; } else if(!isdigit(*prog) && *prog !='$' && *prog !='%') { while(!esdelimitador(*prog)) *temp++ = *prog++; tipo_termino = VARIABLE; } else { if ((*prog=='$' || *prog =='%') && *(prog+1)=='-') { *temp++ = *prog++; *temp++ = *prog++; } while(!esdelimitador(*prog)) *temp++ = *prog++; tipo_termino = NUMERO; } *temp = '\0'; } /*=========================================================================*/ /* Funci¢n : esdelimitador Descripci¢n : Esta funci¢n nos devuelve un 1 si el caracter que le pasamos es un delimitador y un 0 si no lo es . Par metros : char c - caracter a verificar . */ /*=========================================================================*/ static esdelimitador(char c) { return (esta_en(c," +-*/()<>&|^!") || c==9 || c=='\r' || !c) ? 1:0; } /*=========================================================================*/ /* Funci¢n : hallar_valor Descripci¢n : Esta funcion es la funcion principal del PARSER ya que es la funcion a la cual llamamos para resolver una expresion desde el exterior de este modulo.Se encarga de llamar a las distintas funciones del PARSER y de devolvernos el

Page 219: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

84

valor , los mensajes y errores. Parametros : char *palabra - Puntero al string que contendra la expre- sion a evaluar. int longitud - Longitud de la expresion a evaluar.Esta longitud es necesaria ya que palabra puede ser mas larga y contener mas carac- teres de los que queremos evaluar. int *err - Variable en donde pondremos el error cometido. int *reubicable - En esta variable se indica si el resul- tado es reubicable o absoluto. int *externo - Aqui se indica si en la expresion hay algun simbolo externo. Retorno : devuelve el resultado de evaluar la expresion. */ /*=========================================================================*/ int hallar_valor (char *palabra,int longitud,int *err,int *reubicable,int *externo) { int resultado; reub=0; reub2=0; segpasadaparser=0; /* Se pone en p la expresi¢n a evaluar */ prog=p; strncpy (prog,palabra,longitud); prog[longitud]='\0'; if (!*prog) { *err=7; return 0; } *err=setjmp(ebuf); /* El programa continua aqui cuando se comete un error */ if (!*err) coger_expresion(&resultado); *externo += segpasadaparser; *reubicable=reub2; return resultado; } /*=========================================================================*/ /* Funci¢n : valor Descripci¢n : Esta funci¢n nos halla el valor de un s¡mbolo y el tipo de s¡mbolo que es . Par metros : char *puntero - Puntero al string que contendr el nombre del s¡mbolo. Retorno : Nos devuelve el valor del s¡mbolo . */ /*=========================================================================*/ static int valor (char *puntero) { struct arbol *r; r=buscar_rama(raiz,puntero); if (r != NULL) { reub=reub2; switch (r->tipodevariable) { case 0 : reub2=0; break; case 1 : reub2=1; break; case 2 : reub2=0; segpasadaparser=1; break; case 3 : if(segunda_pasada==2) longjmp(ebuf,16); /* Variable no definida */ break; case 4 : reub2=0; break;

Page 220: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

85

case 5 : reub2=1; break; } return r->valor; } if (segunda_pasada==2) longjmp(ebuf,16); /* Variable no definida */ reub2=0; if (codigoreub) reub2=1; return 0; } /*====================== FIN DEL MODULO PARSER.C ==========================*/

Page 221: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

86

lnkdll.dll

lnkdll.bpf USEUNIT("lnkdll.cpp"); USEUNIT("Parserl.cpp"); USEUNIT("Linker.cpp"); //--------------------------------------------------------------------------- This file is used by the project manager only and should be treated like the project file DllEntryPoint

Lnkdll.cpp //--------------------------------------------------------------------------- #include <vcl.h> #include <windows.h> #pragma hdrstop //--------------------------------------------------------------------------- // Important note about DLL memory management when your DLL uses the // static version of the RunTime Library: // // If your DLL exports any functions that pass String objects (or structs/ // classes containing nested Strings) as parameter or function results, // you will need to add the library MEMMGR.LIB to both the DLL project and // any other projects that use the DLL. You will also need to use MEMMGR.LIB // if any other projects which use the DLL will be performing new or delete // operations on any non-TObject-derived classes which are exported from the // DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling // EXE's to use the BORLNDMM.DLL as their memory manager. In these cases, // the file BORLNDMM.DLL should be deployed along with your DLL. // // To avoid using BORLNDMM.DLL, pass string information using "char *" or // ShortString parameters. // // If your DLL uses the dynamic version of the RTL, you do not need to // explicitly add MEMMGR.LIB as this will be done implicitly for you //--------------------------------------------------------------------------- #include "lnkdll.h" #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //---------------------------------------------------------------------------

lnkdll.h //--------------------------------------------------------------------------- #ifndef lnkdllH #define lnkdllH #ifdef __DLL__ #define EXPORT_IMPORT __declspec(dllexport) #else #define EXPORT_IMPORT __declspec(dllimport) #endif EXPORT_IMPORT int Lnk68K(int,char **,char*,char*,char*); EXPORT_IMPORT char* Lnk68K_Mensaje(); EXPORT_IMPORT char* Lnk68K_MensajeErr(); #endif

Page 222: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

87

linker.cpp /////////////////////////////////////////////////////////////////////////////// ///////////////////////LIBRERIAS Y ARCHIVOS DE CABECERA//////////////////////// /////////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <string.h> #include <stdlib.h> #include <conio.h> #include <ctype.h> #include "..\Linkador\linker.h" #include "..\Linkador\lnkdll.h" #include <vcl.h> char aux_str[1024]; AnsiString Mensajes_lnk; AnsiString Mensajes_lnkErr; /////////////////////////////////////////////////////////////////////////////// //////////////////////////////VARIABLES GLOBALES/////////////////////////////// /////////////////////////////////////////////////////////////////////////////// struct lista *ficheros = NULL; struct lista *ultimo = NULL; struct lista *fichord = NULL; struct etiqueta *etiquetas = NULL; struct etiqueta *externas = NULL; int ls28=0; char cadenas28[90]; int direccion,lineass28=0; FILE *ff,*fd; FILE *fm; int error=0; int modulo; int indice_obj; //me ayuda a tratar con el array de ficheros en cogerfichero() /////////////////////////////////////////////////////////////////////////////// //////////////////////////////DECLARACION DE FUNCIONES//////////////////////// /////////////////////////////////////////////////////////////////////////////// static void insertarabs(struct lista *); static void insertarreu(struct lista *); static void listar(struct lista *); static void listar_arbol (struct etiqueta *); static void comprobar_externas(struct etiqueta *); static void s28(char *); static void volcars28(void); static void nexit(int,char *); static void sexit(void); static int cogerfichero(char *,int,int,char**,char*,char*,char*); static int buscarlista(struct lista *,char *); char *fichero; static int insertar_etiqueta(struct etiqueta **,char *,char *); static int checksum(char*); static int cogerposicion(char**); static struct etiqueta *buscar_etiqueta(struct etiqueta *,char *); int hex_dec(char *); /////////////////////////////////////////////////////////////////////////////// //////////////////////////////MENSAJES POR PANTALLA//////////////////////////// /////////////////////////////////////////////////////////////////////////////// char nul[1]=""; /* string buit per mis. sortida */ #define NM 22 /* N£mero de mensajes */ char *mensaje_linker[]={ /*0*/ " LINKER PARA 68000 (FORMATO MOTOROLA S28) ", /*1*/ "", /*2*/ " Posicion : ", /*3*/ "Nombre del fichero", /*4*/ "Memoria insuficiente", /*5*/ "Fichero destino", /*6*/ "Fichero mapa ", /*7*/ "Etiqueta global '%s' declarada en dos modulos",

Page 223: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

88

/*8*/ "No se puede evaluar la expresion '%s'", /*9*/ "LISTADO DE ETIQUETAS", /*10*/ "Tipo Modulo Etiqueta Valor", /*11*/ "Errores", /*12*/ "Error al abrir el fichero", /*13*/ "Fichero objeto '%s' repetido", /*14*/ "El fichero objeto '%s' no existe", /*15*/ "Error : Segmentos de programa solapados", /*16*/ "Modulo Nombre Segmento Inicio Fin", /*17*/ "LOCAL ", /*18*/ "GLOBAL", /*19*/ "Etiqueta externa no resuelta", /*20*/ "Formato del fichero '%s' incorrecto", /*21*/ "Derechos Reservados", }; /////////////////////////////////////////////////////////////////////////////// //////////////////////////////PROGRAMA PRINCIPAL/////////////////////////////// /////////////////////////////////////////////////////////////////////////////// int Lnk68K(int n_objs,char **array_objs,char *fich_s28,char *fich_map,char *path) { register int i=0,a; char fichero[60]; int pos; struct lista *el,*elant,*elant2; char etiqueta[20],valor[9],valor2[9],et[20],eti[20]; int tipo,segunda=0; int err=0; int ultimo_abs=-2; int num_seg,seg; indice_obj=0; elant=NULL; *cadenas28=0; sprintf(aux_str," %s \n",mensaje_linker[0]); Mensaje(aux_str); do //mientras no haya error al abrir ficheros { a=cogerfichero(fichero,0,n_objs,array_objs,fich_s28,fich_map,path); if (a) //NO ERROR ABRIR FICHERO { struct lista *elemento; //elemento es un puntero a structuras tipo lista elemento=(struct lista *) malloc (sizeof(struct lista)); if (!elemento) { nexit(4, nul); //error mem insuficiente } elemento->siguiente=NULL; //el componente siguiente del objeto elemento se

inicializa a 0, es decir, 0 es la primera @ del 1er elemento del fich.

strcpy(elemento->fichero,fichero); //copia el nombre de nuestro fich. a elemento fscanf(ff,"%d\n%d\n%ld\n%ld\n",&elemento->reubicable,&num_seg,&elemento-

>longitud,&elemento->origen);//del obj elemento->offset=0; elemento->segmento=seg=1; if (elemento->reubicable) //mira si elem es reubicable { pos=cogerposicion(array_objs); //coge pos de mem si es reubicable if (pos != -1) ultimo_abs=pos; elemento->offset=elemento->origen; elemento->origen = pos; elemento->minimo = ultimo_abs; } else ultimo_abs=elemento->origen; if (ultimo) { ultimo->siguiente=elemento; ultimo=elemento;

Page 224: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

89

} else ficheros=ultimo=elemento; while (--num_seg) { struct lista *elemento2; elemento2=(struct lista *) malloc (sizeof(struct lista)); if (!elemento2) { nexit(4, nul); } elemento2->siguiente=NULL; strcpy(elemento2->fichero,fichero); elemento2->reubicable=0; fscanf(ff,"%ld\n%ld\n", &elemento2->longitud,&elemento2->origen); elemento2->offset=0; elemento2->segmento=++seg; ultimo_abs=elemento2->origen; ultimo->siguiente=elemento2; ultimo=elemento2; }//while }//if(a) } while (a); //mientras no haya error al abrir el fich. o la long. // de cadena sea diferente de 0 estaremos en este bucle if (!ficheros) sexit(); //lista de OBJ's vacia if (!cogerfichero(fichero,3,n_objs,array_objs,fich_s28,fich_map,path)) sexit(); if (!cogerfichero(fichero,4,n_objs,array_objs,fich_s28,fich_map,path)) sexit(); /* PRIMERA PASADA POR LOS FICHEROS PARA COLOCAR LOS ABSOLUTOS */ el=ficheros; while (el) { if (!el->reubicable) { if (el==ficheros) ficheros=el->siguiente; else elant->siguiente=el->siguiente; elant2=el->siguiente; el->siguiente=NULL; insertarabs(el); el=elant2; } else { elant=el; el=elant->siguiente; } }//while ultimo=elant; /* SEGUNDA PASADA POR LOS FICHEROS PARA COLOCAR LOS REUBICABLES */ el=ficheros; while (el) { elant=el->siguiente; el->siguiente=NULL; insertarreu(el); el=elant; } /* COGER TODAS LAS ETIQUETAS GLOBALES Y LOCALES ASIGNANDO VALOR ABSOLUTO A LAS ETIQUETAS REUBICABLES Y VERIFICANDO QUE NO HAYA REPETICION DE ETIQUETAS GLOBALES Y POR OTRO LADO COGER TAMBIEN LAS EXTERNAS */ el=fichord; a=0; while (el) { a++; if (el->segmento==1) { fclose(ff); ff=fopen(el->fichero,"rb"); fscanf(ff,"%d\n%d\n",&pos,&num_seg);

Page 225: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

90

for (seg=0;seg<num_seg;seg++) fscanf(ff,"%ld\%ld\n",&pos,&pos); fscanf(ff,"%s",etiqueta); while (*etiqueta != ';') { fscanf(ff,"%s %d",valor,&tipo); switch(tipo) { case 1: sprintf(valor,"%08lX",hex_dec(valor)+el->origen); case 0: sprintf(et,"L%02d%s",a,etiqueta); insertar_etiqueta(&etiquetas,et,valor); break; case 2: sprintf(et,"%02d%s",a,etiqueta); insertar_etiqueta(&externas,et,valor); break; case 5: sprintf(valor,"%08lX",hex_dec(valor)+el->origen); case 4: sprintf(et,"G%02d%s",a,etiqueta); if (buscar_etiqueta_global(etiquetas,etiqueta)) { sprintf(aux_str,mensaje_linker[7],etiqueta); //mens MensajeErr(aux_str); error++; } else (insertar_etiqueta(&etiquetas,et,valor)); break; default : nexit(20,el->fichero); }//switch fscanf(ff,"%s",etiqueta); }//while }//if el=el->siguiente; }//while if (error) { ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; sprintf(aux_str,"\n\n\tProceso detenido por detección de errores"); Mensaje(aux_str); throw "ENS1"; } /* VERIFICAR QUE TODAS LAS ETIQUETAS EXTERNAS ESTAN EMPAREJADAS CON UNA ETIQUETA GLOBAL */ comprobar_externas(externas); if (error) { ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; sprintf(aux_str,"\n\n\tProceso detenido por detección de errores"); Mensaje(aux_str); throw "ENS1"; } /* LEER FICHERO A FICHERO SUSTITUYENDO ETIQUETAS NO RESUELTAS EN EL ENSAMBLADOR Y CREANDO EL FICHERO DE DESTINO EN FORMATO S28 */ el=fichord; a=0; while (el) {

Page 226: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

91

direccion=el->origen+el->offset; a++; modulo=a; fclose(ff); ff=fopen(el->fichero,"rb"); fscanf(ff,"%d\n%d\n",&pos,&pos); for (seg=0;seg<num_seg;seg++) fscanf(ff,"%ld\%ld\n",&pos,&pos); fscanf(ff,"%s",etiqueta); while (*etiqueta != ';') { fscanf(ff,"%s %d",valor,&tipo); fscanf(ff,"%s",etiqueta); } if (el->segmento != 1 ) { int i; for (i=1;i<el->segmento;i++) { while (getc(ff) != 'L'); getc(ff);getc(ff);getc(ff); } }//if fscanf(ff,"%4s",eti); while (*eti !='L') { if (*eti=='K') { /* Sustitucion de etiqueta no evaluada en el ensamblador */ fscanf(ff,"\n%s\n",fichero); /* Evaluar expresion */ sprintf(valor,"%08lX",hallar_valor(fichero,&err)); if (err) { sprintf(aux_str,mensaje_linker[8],fichero);//mens MensajeErr(aux_str); error++; } fscanf(ff,"%4s",eti); if (*eti=='K') { /* Sustitucion de 2¦ etiqueta no evaluada en el ensamblador */ fscanf(ff,"\n%s\n",fichero); /* Evaluar expresion */ sprintf(valor2,"%08lX",hallar_valor(fichero,&err)); if (err) { sprintf(aux_str,mensaje_linker[8],fichero);//mens MensajeErr(aux_str); error++; } segunda=1; fscanf(ff,"%4s",eti); }//if(K) /* Busqueda de la cadena de 8 ceros */ a: while (strcmp(eti,"0000")) { s28(eti); fscanf(ff,"%4s",eti); } fscanf(ff,"%4s",eti); if (strcmp(eti,"0000")) { s28("0000"); goto a; } sprintf(eti,"%8s",valor); strcpy(et,eti); et[4]=0; s28(et); s28(eti+4);

Page 227: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

92

if (segunda) { segunda=0; fscanf(ff,"%4s",eti); strcpy(valor,valor2); goto a; } }//if(K) else s28(eti); fscanf(ff,"%4s",eti); }//while (L) volcars28(); /* Busqueda del pr¢ximo fichero */ el=el->siguiente; }//while (el) fprintf(fd,"S804000000FB\n"); fclose(fd); listar(fichord); fprintf(fm,"\n\n\n %s \n",mensaje_linker[9]); fprintf(fm,"%s\n",mensaje_linker[10]); fprintf(fm,"==================================================\n"); listar_arbol(etiquetas); fclose(fm); sprintf(aux_str,"%s = %d",mensaje_linker[11],error);//error Mensaje(aux_str); ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; throw "ENS0"; } /*==================================================================================== ************************************************************************************** ====================================================================================== int cogerfichero (char *f,int tipo,char **array_objs,int n_objs,char *fich_s28,char *fich_map,char *path) si (tipo==0) comprueba que todos los ficheros ok y no repetidos si (tipo==3) f=fich_s28 y comprueba si (tipo==4) f=fich_map y comprueba array_objs,n_objs,fich_s28,fich_map--->datos entrada de interface (formulario) path ---> ruta de usuario cargada del registro de Windows devuelve 1 si todo correcto devuelve 0 si error apertura ficheros ====================================================================================== ************************************************************************************** ====================================================================================*/ int cogerfichero(char *f,int tipo,int n_objs,char **array_objs,char *fich_s28,char *fich_map,char *path) { AnsiString todo; //contendrá una linea de la listbox AnsiString dato; //conendrá el nombre del fichero obj register int i=0; //contiene el num de caract de la cadena de caract q compone nuestro

fich char ch,k[60]; for(;;) { todo=""; dato=""; switch (tipo) { //dependiendo del tipo cogemos el nombre del fich y lo copiamos

case 0: //.OBJ if (!(n_objs-indice_obj)) //si hemos tratado todos los ficheros obj

Page 228: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

93

*f=0; else { todo+=array_objs[indice_obj]; int pos_arroba=todo.AnsiPos("@"); //contiene pos@ dentro de AnsiString if (!pos_arroba) dato=todo; else dato=todo.SubString(1,pos_arroba-1); dato=dato.Insert(path,1); strcpy(f,dato.c_str()); indice_obj++; } break; case 3: //.S28 dato+=fich_s28; dato=dato.Insert(path,1); strcpy(f,dato.c_str()); break; case 4: //.MAP dato+=fich_map; dato=dato.Insert(path,1); strcpy(f,dato.c_str()); break; }//switch i=strlen(f); //retorna el numero de caracteres de la cadena if (i==0) break; //salir del bucle infinito (si *f=0) if (tipo==3) //fich_S28 { if (!strchr(f+3,'.')) //busca '.' en la cadena f y retorna la @ donde se encuentra strcat (f,".s28"); if ((fd=fopen(f,"w"))==NULL) //si error apertura fichero { putchar(7); sprintf(aux_str,"%s '%s' ",mensaje_linker[12],f); Mensaje(aux_str); i=0; } else return 1; //si (!error_apertura) }//if(3) else if (tipo==4) //fich_MAP { if (!strchr(f+3,'.')) strcat (f,".map"); //si no hay punto le añade .MAP if ((fm=fopen(f,"w"))==NULL) //si error apertura fich { putchar(7); sprintf(aux_str,"%s '%s' ",mensaje_linker[12],f); Mensaje(aux_str); i=0; } else return 1; //si (!error_apertura) }//if(4) else //tipo 0 es OBJ { if (!strchr(f+3,'.')) strcat (f,".obj"); //si no hay '.' le pone .OBJ if (buscarlista(ficheros,f)) //si está en lista de ficheros OBJ tratados { sprintf(aux_str,mensaje_linker[13],f);//indica q fich obj esta repetido Mensaje(aux_str); i=0; } else //si no lo hemos tratado todavia { if ((ff=fopen(f,"rb"))==NULL) //error apertura fich { sprintf(aux_str,mensaje_linker[14],f); Mensaje(aux_str); i=0; } else //no error return 1; }

Page 229: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

94

} //else OBJ }//for(;;) bucle infinito if (tipo==3) //fich_s28 { strcpy(k,ficheros->fichero); k[strlen(k)-3]=0; strcat(k,"s28\0"); if ((fd=fopen(k,"w"))==NULL) //error apertura fich { sprintf(aux_str,"%s '%s' ",mensaje_linker[12],k);//mens Mensaje(aux_str); } else return 1; //no error apertura fich } if (tipo==4) //fich_map { strcpy(k,ficheros->fichero); k[strlen(k)-3]=0; strcat(k,"map\0"); if ((fm=fopen(k,"w"))==NULL) //error apertura fich { sprintf(aux_str,"%s '%s' ",mensaje_linker[12],k);//mens Mensaje(aux_str); } else return 1; //no error apertura fich } return 0; //si ha habido error apertura fich } /*================================================================== ******************************************************************** ==================================================================== int cogerposicion (char **array_objs) consigue posicion de mem si fich reubicable ==================================================================== ******************************************************************** ====================================================================*/ int cogerposicion(char **array_objs) { AnsiString todo; //contendrá linea entera de listbox AnsiString dato; //contendra la @mem int aux; //recorrer arrays todo+=array_objs[indice_obj-1]; int posarroba=todo.AnsiPos("@"); //miro donde esta @ if(posarroba==0) //si no esta es q el fich no es reubic { AnsiString msg="Fichero '"+todo+"' no es reubicable"; sprintf(aux_str,msg.c_str());//error Mensaje(aux_str); ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; throw "LINK3"; } //si no es reub lanzo excep. int longdato=todo.Length()-posarroba; //si si es reub miro long del substring //a conseguir dato=todo.SubString(posarroba+1,longdato); //tiene lo posterior a @ int pos; sscanf(dato.c_str(),"%lx",&pos); //pasa @.... a entero return pos; } /**********************************************************************/ int hex_dec(char *expresion) //pasa de hex a dec { register int i; int a=0,v=0; int c;

Page 230: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

95

for (i=strlen(expresion)-1;i>=0; i--) { if (isxdigit(c=toupper(expresion[i]))) { if (c>64) a+=(c-55)<<v; else a+=(c-48)<<v; v += 4; } else if (i==0 && c=='-') a=-a; } return a; } /**********************************************************************/ int buscarlista(struct lista *lista,char *fichero) { if (lista==NULL) return 0; if (!strcmp(lista->fichero,fichero)) return 1; return buscarlista(lista->siguiente,fichero); //recurs. busca toda la lista } /**********************************************************************/ void insertarabs(struct lista *e) { struct lista *a,*b; e->longitud += e->origen+e->offset-1; if (!fichord) { e->siguiente=NULL; fichord=e; return; } a=fichord; b=NULL; while(a) { if (a->origen > e->longitud) { if (a==fichord) { fichord=e; fichord->siguiente=a; return; } b->siguiente=e; e->siguiente=a; return; } if (a->longitud >= e->origen) { nexit(15, nul); } if (!a->siguiente) { a->siguiente=e; e->siguiente=NULL; return; } b=a; a=a->siguiente; } } /**********************************************************************/ void insertarreu(struct lista *e) { struct lista *a,*b; int f; if (e->origen >=0) { insertarabs(e); return;

Page 231: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

96

} e->longitud += e->offset; if (!fichord) { fichord=e; e->origen=0; e->longitud -= 1; e->siguiente=NULL; return; } a=fichord; f=-1; /* f guarda donde acaba el ultimo */ b=NULL; while(a) { if (( e->minimo < f) && (a->origen - f > e->longitud) ) { e->siguiente=a; if (a==fichord) fichord=e; else b->siguiente=e; e->origen=f+1; e->longitud += e->origen-1; return; } b=a; f=a->longitud; if (a->siguiente==NULL) { a->siguiente=e; e->origen=f+1; e->longitud += e->origen-1; e->siguiente=NULL; return; } a=a->siguiente; } } /**********************************************************************/ void listar(struct lista *l) { register int a=0; fprintf (fm,"\n %s\n",mensaje_linker[16]); fprintf (fm,"========================================================================\n"); while (l) { a++; fprintf(fm," %02d %-34s %2d %08lX %08lX\n", a,l->fichero,l->segmento,l->origen,l->longitud); l=l->siguiente; } } /**********************************************************************/ int insertar_etiqueta(struct etiqueta **r,char *etiqueta,char *valor) { register int c; struct etiqueta *a,*b; a=(struct etiqueta *) malloc(sizeof(struct etiqueta)); if (!a) { printf(mensaje_linker[4]); ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; throw "ENS0";

Page 232: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

97

} a->derecha=NULL; a->izquierda=NULL; strcpy(a->nombre,etiqueta); strcpy(a->valor,valor); if (!*r) { *r=a; return 0; } b=*r; while(b) { c=strcmp(etiqueta,b->nombre); if (c==0) return 1; else if (c>0) { if (b->derecha==NULL) { b->derecha=a; return 0; } b=b->derecha; } else { if (b->izquierda==NULL) { b->izquierda=a; return 0; } b=b->izquierda; } } } /**********************************************************************/ void listar_arbol (struct etiqueta *a) { if (!a) return; listar_arbol (a->izquierda); switch (*(a->nombre)) { case 'L' : fprintf (fm,"%s",mensaje_linker[17]); break; case 'G' : fprintf (fm,"%s",mensaje_linker[18]); break; } fprintf(fm," %c%c ",*(a->nombre+1),*(a->nombre+2)); fprintf(fm,"%-20s %s\n",(a->nombre+3),a->valor); listar_arbol (a->derecha); } /**********************************************************************/ void comprobar_externas (struct etiqueta *a) { char *e; if (!a) return; comprobar_externas (a->izquierda); e=a->nombre; while (isdigit(*e)) e++; if (buscar_etiqueta_global(etiquetas,e)==NULL) { error=1; sprintf(aux_str,"%-15s : %s",e,mensaje_linker[19]);//mens MensajeErr(aux_str); } comprobar_externas (a->derecha);

Page 233: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

98

} /**********************************************************************/ struct etiqueta *buscar_etiqueta(struct etiqueta *a,char *etiqueta) { register int c; char *l; if (!a) return NULL; l=a->nombre+1; while (isdigit(*l)) l++; c=strcmp(etiqueta,l); if (c==0) return a; if (c>0) return buscar_etiqueta(a->derecha,etiqueta); return buscar_etiqueta(a->izquierda,etiqueta); } /**********************************************************************/ int esta_en (char c,char *s) { while (*s) if (*s++==c) return 1; return 0; } /**********************************************************************/ void s28(char *s) { strcat(cadenas28,s); ls28 += 2; if (ls28==16) volcars28(); } /**********************************************************************/ void volcars28() { int chksum; char cadenas282[60]; ls28+=4; sprintf(cadenas282,"%02X%06lX%s",ls28,direccion,cadenas28); chksum=checksum(cadenas282); fprintf(fd,"S2%s%02X\n",cadenas282,chksum); direccion +=ls28-4; ls28=0; *cadenas28=0; lineass28++; } /**********************************************************************/ int checksum(char *a) { int chksum=0,valor; while (*a) { sscanf(a,"%2x",&valor); chksum += valor; a+=2; } return 255-chksum&255; } /**********************************************************************/ void nexit(int ne, char mis[]) { if(strlen(mis)) { sprintf(aux_str,mensaje_linker[ne], mis);//mens Mensaje(aux_str); } else {

Page 234: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

99

sprintf(aux_str,mensaje_linker[ne]);//mens Mensaje(aux_str); } ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; throw "ENS1"; //provoca excep si ha habido errores durante la ejecucion } /**********************************************************************/ void sexit() { ficheros=NULL; ultimo=NULL; fichord=NULL; etiquetas=NULL; externas=NULL; sprintf(aux_str,"\n\n\tProceso detenido por detección de errores"); Mensaje(aux_str); throw "ENS2"; } /**********************************************************************/ void Mensaje(char *aux_str) { Mensajes_lnk+=aux_str; Mensajes_lnk+='\n'; *(aux_str)='\0'; } /**********************************************************************/ char* Lnk68K_Mensaje() { char *Auxiliar; Mensajes_lnk+="\n\n\a\a\a"; Auxiliar=Mensajes_lnk.c_str(); Mensajes_lnk=""; return Auxiliar; } /**********************************************************************/ void MensajeErr(char *aux_str) { Mensajes_lnkErr+=aux_str; Mensajes_lnkErr+='\n'; *(aux_str)='\0'; } /**********************************************************************/ char* Lnk68K_MensajeErr() { char *Auxiliar; Mensajes_lnkErr+="\n\n\a\a\a"; Auxiliar=Mensajes_lnkErr.c_str(); Mensajes_lnkErr=""; return Auxiliar; }

Page 235: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

100

linker.h #define ATNO 0x02 /* atributos de color utilizados */ #define ATRES 0x0F #define ATERR 0x0C struct arbolink

{ struct arbolink *arbol_der; /* Direcci¢n del rbol de la derecha */ struct arbolink *arbol_izq; /* Direcci¢n del rbol de la izquierda */ char label[16]; int valor;

int tipodevariable; } ;

struct etiqueta

{ struct etiqueta *derecha; struct etiqueta *izquierda; char valor[9]; char nombre[20];

}; struct lista

{ struct lista *siguiente; /* Direcci¢n del siguiente elemento */ char fichero[60]; /* Nombre del fichero */ int origen; /* Origen absoluto */ int offset; /* Offset reubicable */ int minimo; /* Direccion minima fichero reubicable */ int reubicable; /* =1 (reubicable) =0 (absoluto) */ int longitud; /* Longitud en bytes del segmento */ int segmento; /* Numero de segmento */ } ; int hallar_valor (char *puntero,int *); int lee_linea(char *,FILE *); int hex_dec(char *); int buscar_etiqueta_global(struct etiqueta *,char *); extern char aux_str[1024]; void Mensaje(char*); void MensajeErr(char*);

Page 236: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

101

parserl.cpp //LIBRERIAS #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include "..\Linkador\linker.h" #define DELIMITADOR 1 #define VARIABLE 2 #define NUMERO 3 extern struct etiqueta *etiquetas; extern int modulo; struct etiqueta *r; struct etiqueta *buscar_etiqueta_local(struct etiqueta *,char *); char p[256]; char *prog; char token[80]; char tipo_token; int reub,reub2; int errorparser; //FUNCIONES static void coger_expresion(int *); static void nivel1( int *); static void nivel2( int *); static void nivel3( int *); static void nivel4( int *); static void nivel5( int *); static void nivel6( int *); static void primitiva( int *); static void arit (char , int *, int *); static void unitario (char, int *); static void coger_token(void); static esdelimitador(char); static int valor(char *); static int esta_en (char,char *); /*********************************************************/ static void coger_expresion( int *resultado) { coger_token(); if (!*token) { errorparser=7; return; } nivel1(resultado); } /*********************************************************/ /* OR (|) y XOR (^) */ static void nivel1( int *resultado) { register char op; int hold; nivel2(resultado); while ((op = *token) == '|' || op == '^') { coger_token(); nivel2(&hold); arit(op,resultado,&hold); } } /* AND & */

Page 237: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

102

static void nivel2( int *resultado) { register char op; int hold; nivel3(resultado); while ((op = *token) == '&' ) { coger_token();

nivel3(&hold); arit(op,resultado,&hold); } } /* Sumar o restar dos terminos */ static void nivel3( int *resultado) { register char op; int hold; nivel4(resultado); while ((op = *token) == '+' || op == '-') { coger_token(); nivel4(&hold); arit(op,resultado,&hold); } } /* Multiplicar o dividir SHIFT IZQ (<) Y DER (>) */ static void nivel4( int *resultado) { register char op; int hold; nivel5(resultado); while((op = *token) == '*' || op == '/'|| op == '<'|| op == '>') { coger_token(); nivel5(&hold); arit (op,resultado,&hold); } } /* + o - unitario y NOT (!) */ static void nivel5( int *resultado) { register char op; op=0; if((tipo_token == DELIMITADOR) && *token == '+' || *token == '-'|| *token == '!') { op = *token; coger_token(); } nivel6(resultado); if (op) unitario(op,resultado); } /* Expresi¢n con par‚ntesis */ static void nivel6( int *resultado) { if ((*token == '(') && (tipo_token == DELIMITADOR)) { coger_token(); nivel1(resultado); if(*token != ')') errorparser=4; coger_token(); } else

Page 238: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

103

primitiva(resultado); } static void primitiva( int *resultado) { char prueba[15]; switch(tipo_token) { case VARIABLE: *resultado=valor(token); coger_token(); return; case NUMERO: if (*token == '$') *resultado = hex_dec (token+1); else { *resultado=atol(token); ltoa(*resultado,prueba,10); if (strcmp(prueba,token)) errorparser=28; } reub2=0; coger_token(); return; default: errorparser=7; } } void arit (char o,int *r,int*h) {

switch(o) { case '-': if (reub2) reub = !reub; else { if (reub) errorparser=13; /* abs-reub es ilegal */ else reub=0; } *r -= *h; break; case '+': *r += *h; if (reub2) { if (reub) errorparser=14; /* Reub + reub es ilegal*/ else reub=1; } break; case '*': *r *= *h; if (reub2) errorparser=15; /* reubicable* todo es ilegal */ else { if (reub) errorparser=15; /* abs*reub es ilegal */ else reub=0; } break; case '/': if (!*h) errorparser=36; /* Division por cero */ else *r /= (*h); if (reub2) errorparser=15; /* reubicable/ todo es ilegal */ else { if (reub) errorparser=15; /* abs/reub es ilegal */ else reub=0; } break; case '^': *r = *r ^ *h; if (reub2 ^ reub) errorparser=14; /* Deben ser del mismo tipo */

Page 239: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

104

break; case '|': *r = *r | *h; if (reub2 ^ reub) errorparser=14; /* Deben ser del mismo tipo */ break; case '&': *r = *r & *h; if (reub2 ^ reub) errorparser=14; /* Deben ser del mismo tipo */ break; case '>': *r = *r >> *h; if (reub2 ^ reub) errorparser=14; /* Deben ser del mismo tipo */ break; case '<': *r = *r << *h; if (reub2 ^ reub) errorparser=14; /* Deben ser del mismo tipo */ break; } reub2=reub; } static void unitario (char o,int *r) { if(o=='-') *r = -(*r); if(o=='!') *r = ~(*r); } static void coger_token() { register char *temp; tipo_token=0; temp=token; while(isspace(*prog)) ++prog; if(esta_en(*prog,"+-*/()<>&|^!")) { tipo_token = DELIMITADOR; *temp++ = *prog++; } else if(!isdigit(*prog) && *prog !='$') { while(!esdelimitador(*prog)) *temp++ = *prog++; tipo_token = VARIABLE; } else { while(!esdelimitador(*prog)) *temp++ = *prog++; tipo_token = NUMERO; } *temp = '\0'; } static esdelimitador(char c) { if (esta_en(c," +-*/()<>&|^!") || c==9 || c=='\r' || c==0) return 1; return 0; } int hallar_valor (char *palabra,int *err) { int resultado; reub=0; reub2=0; errorparser=0; prog=p; strcpy (prog,palabra); if (!*prog)

Page 240: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

105

{ *err=7; return 0; } coger_expresion(&resultado); *err=errorparser; return resultado; } int valor (char *puntero) { char e[60]; sprintf(e,"L%02d%s",modulo,puntero); r=buscar_etiqueta_local(etiquetas,e); if (r!=NULL) { reub=reub2; reub2=0; } else buscar_etiqueta_global(etiquetas,puntero); if (r!=NULL) return hex_dec(r->valor); errorparser=16; return 0; } struct etiqueta *buscar_etiqueta_local(struct etiqueta *a,char *etiqueta) { register int c; if (!a) return NULL; c=strcmp(etiqueta,a->nombre); if (c==0) return a; if (c>0) return buscar_etiqueta_local(a->derecha,etiqueta); return buscar_etiqueta_local(a->izquierda,etiqueta); } int buscar_etiqueta_global(struct etiqueta *a,char *etiqueta) { char *e; if (!a) return NULL; if(buscar_etiqueta_global (a->izquierda,etiqueta)) return 1; if (*a->nombre=='G') { e=a->nombre+1; while (isdigit(*e)) e++; if (!strcmp(e,etiqueta)) { r=a; return 1; } } if(buscar_etiqueta_global (a->derecha,etiqueta)) return 1; return 0; } int esta_en (char c,char *s) { while (*s) if (*s++==c) return 1; return 0; }

Page 241: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

ANEXO 2:

MANUAL DE USUARIO

Page 242: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

MANUAL DE USUARIO DEL PROGRAMA

La aplicación se inicia ejecutando el archivo interfens.exe del directorio “...\Macro_ensamblador\”. Se crea en pantalla el formulario principal:

Figura 1 - Página inicial del programa

El formulario está dividido en 3 partes diferentes: el menú principal, el frame de selección y el frame de visualización. El menú principal se subdivide de la siguiente manera:

Menú à Programas àEditor àEnsamblador

àLinkador àSimulador àComunicaciones àProyecto àOpciones àRuta de Usuario àSalir

Page 243: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

• El submenú programas resume el frame de selección en una lista sin imágenes. El interface llama al subprograma seleccionado cuando el usuario acciona el mouse sobre un elemento submenú.

• La opción Ruta de Usuario abre un formulario diálogo para que el usuario

especifique la ruta (o directorio) de trabajo de todos los programas. Dicha información se almacena en la base de datos Registry de Windows. Esto ocurre cuando el usuario acciona el mouse sobre el botón Ok del formulario. En caso contrario se mantiene la información contenida en el registro. Se recomienda el uso del Explorador de Windows para copiar la ruta en el diálogo sin cometer errores.

Figura 2 – Formulario de Ruta de Usuario

• La opción Salir cierra la aplicación.

El frame de selección nos permite seleccionar cuál de los 6 subprogramas deseamos

utilizar. El editor, el ensamblador, el linkador y el procesador de proyectos son programas integrados en el formulario principal, es decir, aparecen en el frame de visualización cuando son seleccionados. El simulador y el programa de comunicaciones son aplicaciones externas que pueden ser llamadas por el interface principal y aparecen en formularios diferentes.

Page 244: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

1 Editor:

El editor es un programa diseñado para el tratamiento de los ficheros específicos de la programación del MC68000. Utiliza un formato personalizado en la edición de los ficheros fuente asm y los ficheros listado lst. El programa trabaja con la ruta de usuario almacenada en el registro de Windows. El aspecto visual del editor es el siguiente:

Figura 3 – Página del editor

La pantalla del editor se subdivide en 3 partes diferentes: el menú de opciones, la hoja de edición y la barra de pestañas.

• El menú de opciones es una barra con 6 botones y un label que indica en qué línea del documento se encuentra el cursor. Cada botón representa una acción básica en el editor:

a) Nuevo Documento: crea una nueva hoja en blanco y su respectiva pestaña.

El nombre por defecto es SinNombre#. b) Abrir Documento: presenta un diálogo que permite al usuario especificar

el archivo. Se permite abrir ficheros con cualquier extensión, sin embargo

Page 245: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

existe una lista de extensiones predeterminadas: txt, asm, obj y lst. El editor crea una nueva hoja donde aparece el texto contenido en el fichero especificado. El editor da un formato determinado al texto de la hoja seleccionada.

c) Guardar Documento: presenta un diálogo que permite al usuario

especificar el nombre y ruta del archivo. Se permite guardar ficheros con cualquier extensión, sin embargo existe una lista de extensiones predeterminadas: txt, asm, obj y lst. El editor da un formato determinado al texto de la hoja seleccionada.

d) Cerrar Documento: se cierra la hoja de texto seleccionada y su

correspondiente pestaña. Antes de cerrar nos permite guardar el documento si ha sido modificado tras el último almacenamiento.

e) Formato: da un formato determinado al texto de la hoja seleccionada. El

formato se resume en poner los comentarios en color azul y las palabras clave del lenguaje en negrita.

f) Imprimir: presenta un diálogo que permite al usuario seleccionar la

impresora, el número de copias... Imprime el documento según las propiedades especificadas.

• La hoja de edición es la parte donde se visualiza y edita el texto.

• La barra de pestañas nos permite seleccionar la hoja activa cuando tenemos

múltiples hojas abiertas en el mismo momento. El texto interno especifica el nombre del archivo relacionado con dicha pestaña.

Page 246: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

2 Ensamblador:

El ensamblador es el programa encargado de compilar los ficheros fuente asm (que contienen el código del programa) en los ficheros objeto obj. Éstos últimos contienen un encabezamiento informativo para el programa linkador, además del código del programa en formato código máquina. El ensamblador trabaja con la ruta de usuario especificada en el registro de Windows. El aspecto visual del ensamblador es el siguiente:

Figura 4 – Página del ensamblador

El ensamblador tiene un entorno de usuario muy sencillo. El usuario introduce los nombres de los ficheros fuente, objeto y listado, y acciona el botón Ensamblar. El fichero fuente debe existir en la carpeta de usuario. Los ficheros objeto y listado serán borrados en caso de existir o creados en caso contrario. Si el código fuente no contiene errores y se ensambla correctamente, el fichero objeto es actualizado con los datos pertinentes. En caso contrario el archivo es eliminado. El fichero listado es meramente informativo, y existirá en caso de ensamblado correcto o con errores. Si el usuario omite la extensión de los ficheros el programa los añade internamente sin errores. En el caso de que el usuario haga un double-click sobre una de las líneas de error presentadas en la ventana de errores de ensamblador, el programa visualiza la página de

Page 247: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

editor. A su vez, el editor abre el fichero listado y resalta la línea relacionados con el error de ensamblado seleccionado. Lista de posibles mensajes presentados por el ensamblador:

"Nemotecnico incorrecto" "Extension de la instruccion incorrecta" "Etiqueta repetida" "Parentesis no balanceados" "Numero de operandos incorrecto" "Falta etiqueta" "Error de sintaxis" "Tipo de direccionamiento no valido" "Programa no terminado con END" "Etiqueta no valida" "Etiqueta ya declarada" "Se da valor a una etiqueta externa" "Operacion ilegal : Absoluto-Reubicable" "Operacion ilegal : Reubicable+Reubicable" "Operacion ilegal : Multiplicacion o Division de Reubicable" "Etiqueta no definida" "Se esperaba un registro" "Tamaño incorrecto" "Registro debe ser de direcciones no de datos" "No puede ser reubicable" "En predecremento y postincremento, registros de direcciones" "En direccionamientos indirectos, registros de direcciones" "Registro debe ser de direcciones" "Division por cero" "Error en la lista de registros" "Desplazamiento demasiado grande" "Esta directiva debe estar al principio del programa" "Valor incorrecto" "Branch short a la siguiente instruccion" "No se puede resolver la etiqueta" "Valor hexadecimal incorrecto" "No es posible una etiqueta externa" "Tamaño debe ser LONG para etiquetas externas" "Instruccion no ensamblable directamente" "Numero maximo de segmentos sobrepasado" "Error en el uso de la directiva" "Error de sintaxis en la definicion de una macro" "No puede aparecer en la definicion de una macro" "Número de parámetros de la macro incorrectos" "Definición de macro no terminada con ENDM"

Page 248: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

3 Linkador: El linkador es el programa encargado de enlazar todos los ficheros objeto obj que componen el programa en un mismo archivo s28. Este último fichero contiene una línea de datos por cada segmento de programa. Cada línea comienza por un pequeño encabezamiento informativo y continúa con el código máquina compilado. El linkador trabaja con la ruta de usuario especificada en el registro de Windows. El aspecto visual del linkador es el siguiente:

Figura 5 – Página del linkador

El entorno de usuario del programa linkador es algo más complejo. Sin embargo se simplifica bastante el proceso con el aspecto visual desarrollado. El usuario debe introducir parejas de datos en una lista. Estas parejas son formadas por el nombre de un fichero objeto y una dirección de memoria (opcional) en formato hexadecimal. Cinco casos son los posibles en este punto:

a) Código absoluto con posición predeterminada: el código contiene la directiva absolute acompañada de la directiva org/origin. Las etiquetas se han compilado de forma absoluta en el ensamblador. El programa hace caso omiso al campo @ introducido por el usuario.

Page 249: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

b) Código absoluto sin posición predeterminada: el código contiene la directiva absolute pero no aparece la directiva org/origin. Combinación imposible.

c) Código reubicable (relativo) con posición predeterminada: el código contiene la directiva relative seguida de la palabra clave org/origin. Combinación imposible. El fichero se compila como absoluto en la dirección indicada, pero el linkador detecta un error determinando que el fichero no es relativo. d) Código reubicable (relativo) sin posición predeterminada con campo @: el programa ha compilado las etiquetas del fichero fuente de forma relativa, es decir, en función del inicio del programa. El linkador toma el campo @ como dirección de inicio del programa. e) Código reubicable (relativo) sin posición predeterminada: el programa ha compilado las etiquetas del fichero fuente de forma relativa, es decir, en función del inicio del programa. El linkador debe buscar una sector de memoria libre donde ubicar el código ensamblado. Busca la dirección de inicio del programa. Esta posibilidad del linkador no se ha implementado correctamente, es decir, no puede ser utilizada por el usuario.

Cuando el usuario acciona el botón Linkar, el programa prepara los argumentos

necesarios y llama a la función principal de la DLL, que linka de todos los ficheros objeto pasados como argumento. Tras este proceso, el programa principal presenta los mensajes informativos y los errores en las ventanas de visualización de la página linkador. Un double-click del usuario sobre alguna de las líneas de error del linkador no tiene ningún efecto. Lista de posibles mensajes presentados por el linkador:

"Nombre del fichero" "Memoria insuficiente" "Fichero destino" "Fichero mapa " "Etiqueta global '%s' declarada en dos modulos" "No se puede evaluar la expresion '%s'" "LISTADO DE ETIQUETAS" "Tipo Modulo Etiqueta Valor" "Error al abrir el fichero" "Fichero objeto '%s' repetido" "El fichero objeto '%s' no existe" "Error : Segmentos de programa solapados" "Modulo Nombre Segmento Inicio Fin" "LOCAL " "GLOBAL" "Etiqueta externa no resuelta" "Formato del fichero '%s' incorrecto"

Page 250: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

4 Simulador:

Se trata de un programa externo al formulario principal y al proyecto. El interface simplemente llama al fichero ejecutable del programa simulador y lo visualiza en un nuevo formulario. Sirve para simular el funcionamiento del programa sin necesidad de una conexión real al 68K de Motorola.

Figura 6 – Programa simulador

Page 251: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

5 Programa de comunicaciones:

Se trata de un programa externo al formulario principal y al proyecto. El interface simplemente llama al fichero ejecutable del programa comunicador y lo visualiza en un nuevo formulario. Sirve para trabajar con el 68K de Motorola y precisa de una conexión real.

Figura 7 – Programa ITF68K

Page 252: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

6 Procesador de Proyectos:

El procesador de proyectos es una utilidad que permite al usuario un sencillo y rápido tratamiento de proyectos extensos, es decir, formados por múltiples ficheros. Mediante unas simples indicaciones es posible crear un fichero de proyecto (.prj) que permite el ensamblado y el linkado de todos los ficheros fuente con dos simples acciones del ratón. El aspecto visual de la página proyecto es el siguiente:

La página de proyecto está dividida en tres partes importantes: el panel de edición

(parte superior de la página), el panel de acción (botones intermedios) y la ventana de visualización (parte inferior de la página).

El panel de edición resume la entrada de las páginas ensamblador y linkador en un mismo panel. El componente más importante de este panel es la lista situada en el centro del panel. Un proyecto está formado por una lista de x ficheros fuente (asm) que son compilados en sus respectivos x ficheros objeto (obj) en la posición de memoria especificada por el usuario o el código. Los tres campos mencionados son representados por los tres objetos de edición de texto situados a la izquierda de la lista. El formato visual de la lista es el siguente:

Page 253: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

Figura 8 – Detalle del objeto TListBox de entrada

La acción del mouse sobre el botón con el texto Añadir creará una línea con el

formato anterior, con la única condición de que los objetos de edición contengan un valor diferente a nulo (el campo dirección de memoria es opcional). Los botones Borrar y Borrar Lista tienen el mismo modo de funcionamiento que sus equivalentes en la página linkador. Los objetos de edición situados a la derecha de la lista corresponden a los nombres de los ficheros de salida de la DLL linkador (s28 y map). Estos componentes deben tener algún valor diferente a nulo para proceder a ensamblar y/o linkar el fichero proyecto.

El panel de acción es un objeto que engloba las funciones principales de la página

proyecto. Se compone de cuatro botones y de un objeto de edición de texto. Este último componente contiene el nombre del fichero proyecto (prj) sobre el que repercuten las acciones realizadas por el usuario. Los cuatro botones corresponden a las siguientes funciones:

a) Guardar Proyecto b) Cargar Proyecto c) Ensamblar Proyecto d) Linkar Proyecto

Page 254: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

a) Guardar Proyecto:

La función guardar tiene como objetivo tomar los datos que el usuario ha introducido en los componentes del panel de edición y crear un fichero de proyecto (prj) con un formato determinado. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

b) Cargar Proyecto:

La función cargar tiene como objetivo recuperar los datos que el usuario ha almacenado en un fichero de proyecto (prj) y actualizar con esa información los componentes del panel de edición. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

Inicialmente, el programa borra el contenido de los componentes de edición del

panel, limpia el contenido de la ventana de visualización y vacía la lista del panel de edición. Posteriormente, el programa abre el fichero de proyecto especificado en el objeto de edición del panel de acción.

Se realiza una comprobación de la extensión del fichero en prevención de posibles errores del usuario. En el caso de que el fichero de proyecto especificado no exista, el programa presenta el mensaje de error pertinente por la ventana de visualización. En caso contrario se procede con la ejecución del resto del código de la función.

En caso de correcta apertura del fichero de proyecto, el programa actualiza los campos de los componentes del panel de edición con los datos del fichero de proyecto. El puntero de fichero recorre el contenido del archivo secuencialmente de inicio a fin. En función de la línea en que se encuentre y mediante el uso de una estructura de tipo switch el programa se encarga de actualizar el campo del componente determinado. Alcanzado el símbolo EOF (end of file) por el puntero de fichero, el programa presenta el mensaje pertinente por la ventana de visualización y cierra el fichero de proyecto.

proyecto1.prj proyecto1.s28 proyecto1.map 6 file1 file1 024000 file2 file2 024500 file3 file3 025000 file4 file4 025500 file_libs file_libs 030000 file_end file_end 040000

Figura 9 – Detalle del formato de un fichero de proyecto

Page 255: Desarrollo de un paquete de programación del MC68000 …deeea.urv.cat/public/PROPOSTES/pub/pdf/622pub.pdf · 1.3 ANTECEDENTES ... pero finalmente se ha optado por el C++ Builder

c) Ensamblar Proyecto:

La función ensamblar tiene como objetivo recuperar los datos que el usuario ha almacenado en un fichero de proyecto (prj), actualizar con esa información los componentes del panel de edición y ensamblar los ficheros fuente en los ficheros objeto especificados por el usuario. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

Inicialmente, el programa borra el contenido de los componentes de edición del

panel, limpia el contenido de la ventana de visualización y vacía la lista del panel de edición. Posteriormente, el programa abre el fichero de proyecto especificado en el objeto de edición del panel de acción y procede al tratamiento de las líneas de datos del fichero.

Una vez tratadas todas las cadenas de caracteres y ensamblados todos los ficheros

fuente del proyecto, el programa termina la ejecución de la función liberando con la palabra clave delete todas las zonas de memoria reservadas con new.

d) Linkar Proyecto:

La función linkar tiene como objetivo recuperar los datos que el usuario ha

almacenado en un fichero de proyecto (prj), actualizar con esa información los componentes del panel de edición y linkar los ficheros objeto en los ficheros s28 y map especificados por el usuario. Al finalizar el proceso se mostrarán los mensajes pertinentes por la ventana de visualización.

Inicialmente, el programa actualiza los objetos de edición del panel de edición,

limpia el contenido de la ventana de visualización y actualiza la lista con los datos contenidos en el fichero de proyecto especificado en el panel de acción. Recuérdese que una de las limitaciones del programa linkador es que el número máximo de ficheros objeto que pueden componer un proyecto es 20. Limitación también aplicable a los ficheros de proyecto.

Posteriormente, el programa procede a preparar el argumento principal de la DLL

linkador: un array de 20 punteros a carácter. Cada pointer apunta al inicio de una cadena de caracteres que contiene el nombre de un fichero objeto y la dirección en un formato específico. El formato de la cadena es el siguiente:

“ruta_usuario+nombre_obj+@+dir_memoria”

La ruta de usuario se obtiene del registro de Windows como se ha explicado en

apartados posteriores. El símbolo @ seguido de la dirección de memoria en hexadecimal es de carácter opcional, es decir, solamente aparecerá en caso que el usuario especifique una dirección de memoria durante la creación del proyecto. La extensión de los ficheros objeto será tratada en el interior de la DLL. El programa llama a la función principal de la DLL linkador y presenta en todos los casos los errores cometidos.