Proyecto de Software de Base

El objetivo del proyecto es el de escribir un ensamblador simple para el microcontrolador PIC16F84 de Microchip. El ensamblador se irá construyendo en diversas etapas. Cada etapa estará especificada en esta página y tendrá una fecha de entrega. La evaluación de la etapa se hará en base a que lo entregado satisfaga exactamente las especificaciones requeridas, es decir, ni más ni menos. Finalmente, cada una de las etapas tendrá un valor que será anunciado junto con la especificación.

Primera etapa: Ensamblador simple de un paso : 20 puntos : 2 de mayo de 2008

Deberán escribir un programa llamado unpasoZZ.c o unpasoZZ.cpp o unpasoZZ.java que lea un código fuente en ensamblador y escriba el código binario correspondiente. Como podrá ver en las páginas 35 a 42 del manual del PIC16F84, éste tiene instrucciones de 14 bits (cada una usa dos bytes en la memoria) y direcciones de 11 bits. Las instrucciones tienen cinco formatos generales (descritos en la página 35):
  1. instrucciones orientadas a bytes para registros (dos parámetros d y f),
  2. instrucciones orientadas a bits para registros (dos parámetros b y f),
  3. instrucciones de control y literales (un operando k),
  4. instrucciones de control de flujo (CALL y GOTO, un operando k) y
  5. instrucciones que no tienen parámetros (CLRW, NOP, CLRWDT, RETFIE, RETURN y SLEEP).
Los significados y longitudes de los operandos se indican en la página 35 (tabla 7-1 y figura 7-1).

El programa unpasoZZ recibirá dos parámetros fuente y binario en la línea de instrucción, donde fuente es el nombre del archivo de texto que contiene el código fuente y binario es el nombre del archivo de texto donde se escribirá el código binario. El código fuente consistirá de una sucesión de líneas de texto y terminará con el fin de archivo. Cada línea de texto podrá:
  1. Estar en blanco (los caracteres definidos por isspace).
  2. Contener además de blancos un nemónico.
  3. Contener además de blancos un nemónico separado por blancos de su parámetro numérico.
  4. Contener además de blancos un nemónico separado por blancos de su primer parámetro numérico separado por blancos de su segundo parámetro numérico.
  5. Contener además de blancos la directiva ORG separada por blancos de su parámetro numérico (nuevo valor de CONTLOC).
  6. Contener además de blancos la directiva COM separada por blancos de su parámetro alfanumérico (comentario).
  7. Contener además de blancos la directiva END.
Los nemónicos se obtendrán de los mostrados en la página 36 del manual (tabla 7-2). Los parámetros numéricos podrán aparecer escritos en octal, decimal o hexadecimal como en el lenguaje de programación C. Observe que algunos nemónicos tomarán un parámetro de 1, 3, 7, 8 u 11 bits mientras que otros no tomarán parámetros.

Si la primera instrucción del código fuente no va precedida de una directiva ORG se debe suponer que tiene la dirección 0x000 (valor original de CONTLOC). El parámetro de la directiva COM es un comentario y por lo tanto deberá de ser ignorado. La directiva END indica que el código fuente ha terminado y que las siguientes líneas deben de ser ignoradas.

Su programa deberá terminar en cuanto se lea la directiva END o se detecte el fin de archivo o el primer error. Las líneas que contienen nemónicos y que no contienen errores generarán código binario. Cada registro de datos del código binario constará de 11 bits de dirección en binario, seguidos de un espacio, seguido de los 14 bits de la instrucción en binario.

Su programa deberá detectar los siguientes tipos de errores, los cuales deberá señalar en el error estándar (stderr) junto con el número de la línea fuente donde ocurren:
  1. Instrucción desconocida.
  2. Falta parámetro.
  3. Sobra parámetro.
  4. Parámetro fuera de rango.
  5. Parámetro sin instrucción.
  6. Formato desconocido de parámetro.
Cuando se detecte un error se deberá imprimir en stderr la cadena "ERROR: ", seguida del número de línea donde ocurrió el error y seguida de una de las cadenas " INSTRUCCION", " FALTA", " SOBRA", " RANGO", " PARAMETRO" o " FORMATO" según el tipo de error.

Abajo encontrará un ejemplo del funcionamiento de este programa:

Ejemplo de entrada
Explicación del ejemplo
Ejemplo de salida
ORG 0123
ADDWF 12 1
CLRF 0x12
CLRW
BCF 012 0x3
GOTO 0123
END
Dirección de origen en octal (no genera código)
Instrucción con dos parámetros en decimal
Instrucción con parámetro en hexadecimal
Instrucción sin parámetros
Instrucción con un parámetro octal y uno hexadecimal
Instrucción con un parámetro octal
Fin del código fuente (no genera código)
00001010011 00011110001100
00001010101 00000110010010
00001010111 00000100000000
00001011001 01000110001010
00001011011 10100001010011

Segunda etapa: Ensamblador de un paso con símbolos : 20 puntos : 19 de mayo de 2008

Deberán escribir un programa llamado simbolZZ.c o simbolZZ.cpp o simbolZZ.java que lea un código fuente en ensamblador y escriba el código objeto correspondiente. El programa simbolZZ recibirá dos parámetros fuente y objeto en la línea de instrucción, donde fuente es el nombre del archivo de texto que contiene el código fuente y objeto es el nombre del archivo de texto donde se escribirá el código objeto El código fuente consistirá de una sucesión de líneas de texto y terminará con el fin de archivo. Cada línea de texto podrá:
  1. Estar en blanco (los caracteres definidos por isspace).
  2. Contener además de blancos un nemónico.
  3. Contener además de blancos un nemónico separado por blancos de su parámetro numérico.
  4. Contener además de blancos un nemónico separado por blancos de su primer parámetro numérico separado por blancos de su segundo parámetro numérico.
  5. En los tres casos anteriores podrá contener un símbolo antes de cualquier otro campo separada por blancos. A estos símbolos los llamamos etiquetas.
  6. Contener además de blancos la directiva ORG separada por blancos de su parámetro numérico (nuevo valor de CONTLOC).
  7. Contener además de blancos la directiva COM separada por blancos de su parámetro alfanumérico (comentario).
  8. Contener además de blancos un símbolo separada por blancos de la directiva EQU separada por blancos de un parámetro numérico.
  9. Contener además de blancos la directiva END.
Los parámetros numéricos podrán representarse como en la primera etapa del proyecto o como un símbolo. Todos los símbolos comenzarán con un caracter alfabético y podrán contener hasta un máximo de ocho caracteres alfanuméricos. Cuando un símbolo aparezca como parámetro su valor debió haber estado definido previamente, ya sea como etiqueta o a través de una directiva EQU.

Además de los errores detectados en la segunda etapa del proyecto, se deberán detectar los siguientes tipos de errores:
  1. Si un símbolo aparece dos veces en el lado izquierdo de una línea se está redefiniendo.
  2. Si un símbolo que no ha sido definido previamente aparece como parámetro numérico entonces es un símbolo no definido.
Cuando se detecte un error se deberá imprimir en stderr la cadena "ERROR: ", seguida del número de línea donde ocurrió el error y seguida de una de las cadenas " INSTRUCCION", " FALTA", " SOBRA", " RANGO", " PARAMETRO", " FORMATO", " REDEFINIDO" o " INDEFINIDO" según el tipo de error.

Su programa deberá terminar en cuanto se lea la directiva END o se detecte el fin de archivo o el primer error. Las líneas que contienen nemónicos y que no contienen errores generarán código objeto. El formato del código objeto está descrito en el documento Intel Hexadecimal Object File o aquí. En estos lugares se describen dos tipos de registros del formato objeto hexadecimal de 8 bits, a saber el registro de datos y el registro de fin de archivo. Cada registro de datos del código objeto será tan largo como sea posible pero nunca deberá tener una longitud mayor a 0x20.

Abajo encontrará un ejemplo del funcionamiento de este programa:

Ejemplo de entrada
Explicación del ejemplo
Ejemplo de salida
INICIO EQU 023
BIT EQU 1
ORG INICIO
AQUI ADDWF 12 BIT
CLRF AQUI
CLRW
DIEZ EQU 0xA
BCF DIEZ 0x3
GOTO INICIO
END
Definición del símbolo INICIO con un octal (no genera código)
Definición del símbolo BIT con un decimal (no genera código)
Dirección de origen símbolica (no genera código)
Instrucción con dos parámetros (uno decimal y uno simbólico) y etiqueta
Instrucción con parámetro simbólico
Instrucción sin parámetros
Definición del símbolo DIEZ con un hexadecimal (no genera código)
Instrucción con un parámetro simbólico y uno hexadecimal
Instrucción con un parámetro simbólico
Fin del código fuente (no genera código)
:0A001300078C01930100118A2813E5
:00000001FF

Explicación:

Hay 10 bytes en el campo de datos
Los datos comienzan en INICIO=023
Un registro de datos 00 y uno de fin 01
La suma del primer registro da 0x21B
Por lo que la suma de control es 0xE5

Tercera etapa: Ensamblador completo de dos pasos : 20 puntos : 9 de junio de 2008 (09:00)

Deberán escribir un programa llamado dospasosZZ.c o dospasosZZ.cpp o dospasosZZ.java que lea un código fuente en ensamblador y escriba el código objeto correspondiente. El programa dospasosZZ recibirá dos parámetros fuente y objeto en la línea de instrucción, donde fuente es el nombre del archivo de texto que contiene el código fuente y objeto es el nombre del archivo de texto donde se escribirá el código objeto. El código fuente consistirá de una sucesión de líneas de texto y terminará con el fin de archivo. Cada línea de texto podrá ser como en los 8 casos de la segunda etapa del proyecto o bien:
  1. Contener además de blancos la directiva DATA seguida de sus parámetros numéricos separados por blancos.
  2. Contener además de blancos la directiva RES separada por blancos de un parámetro numérico.
Los dos casos anteriores pueden estar precedidos por una etiqueta. El primer parámetro numérico (de 8 bits) de la directiva DATA es el número de bytes que se colocarán en el código objeto y su valor indica cuántos parámetros numéricos adicionales (de 8 bits cada uno) tiene la directiva y que deberán colocarse en el código objeto en ese orden. El parámetro numérico de la directiva RES es un número de 11 bits que se le sumará al valor actual del contador de localidades, por lo que el efecto de esta directiva es el de reservar la cantidad especificada de bytes. Observe que esta directiva no genera código objeto: el registro de texto actual debe terminar de procesarse y comenzarse uno nuevo a partir de la nueva dirección recién calculada.

Respecto a los símbolos, el último tipo de error cambia a
  1. Si un símbolo que no ha sido definido en ninguna parte del código fuente aparece como parámetro numérico entonces es un símbolo no definido.
Su programa deberá terminar en cuanto se lea la directiva END o se detecte el fin de archivo o el primer error. Las líneas que contienen nemónicos o la directiva DATA y que no contienen errores generarán código objeto. Cada registro de datos del código objeto será tan largo como sea posible pero nunca deberá tener una longitud mayor a 0x20 (que era el valor por omisión en la primera etapa del proyecto). Cuando se detecte un error se deberá imprimir en stderr la cadena "ERROR: ", seguida del número de línea donde ocurrió el error y seguida de una de las cadenas " INSTRUCCION", " FALTA", " SOBRA", " RANGO", " PARAMETRO", " FORMATO", " REDEFINIDO" o " INDEFINIDO" según el tipo de error.

Abajo encontrará un ejemplo del funcionamiento de este programa:

Ejemplo de entrada
Explicación del ejemplo
Ejemplo de salida
INICIO EQU 023
ORG INICIO
AQUI ADDWF 12 BIT
BIT EQU 1
CLRF AQUI
CLRW
BCF DIEZ 0x3
DIEZ EQU 0xA
GOTO INICIO
RES DIEZ
DATA 3 DIEZ 5 BIT
END
Definición del símbolo INICIO con un octal (no genera código)
Dirección de origen símbolica (no genera código)
Instrucción con dos parámetros (uno decimal y uno simbólico) y etiqueta
Definición del símbolo BIT con un decimal (no genera código)
Instrucción con parámetro simbólico
Instrucción sin parámetros
Instrucción con un parámetro simbólico y uno hexadecimal
Definición del símbolo DIEZ con un hexadecimal (no genera código)
Instrucción con un parámetro simbólico
Reserva de bytes (no genera código, termina el registro de texto actual)
Agregar bytes al código objeto
Fin del código fuente (no genera código)
:0A001300078C01930100118A2813E5
:030027000A0501C6
:00000001FF

Explicación:

Hay 3 bytes en el segundo campo de datos
Los datos comienzan DIEZ bytes después de
donde termina el primer campo (por RES)
Dos registros de datos 00 y uno de fin 01
La suma del segundo registro da 0x3A
Por lo que su suma de control es 0xC6