CURSO DE DESPROTECCIÓN DE PROGRAMAS
CAPITULO 2
0.SOLUCIONES EJERCICIOS TEMA 1.
1.
Slot 0 – Dato &B 00 00 00 00 = 0
Slot 1 – Dato &B 01 01 01 01 = 85
Slot 2 – Dato &B 10 10 10 10 = 170
Slot 3 – Dato &B 11 11 11 11 = 255
2.
a) &B 10 11 11 10 = 190
b) &B XX 01 11 01 = ¿?
3. Puede significar que nuestro ordenador es un SONY por lo que lleva un programa en la ROM (una Agenda, programa de gestión, etc.). Lo que sin duda significa esta configuración de memoria es que el Slot 0 tan sólo contiene 16 kbs de RAM.
4. Quedarán libres para el BASIC, para almacenar programas, poco más de 12 kbs de memoria (16 kbs de RAM menos los 4 kbs que ocupan la RAM del Sistema).
5. Obviamente no lo colocaremos nunca en esas páginas del Slot 3 (páginas 0 y 1). La explicación de este hecho es compleja (es necesario saber Código Máquina o al menos tener algunos conceptos adquiridos como PC = Contador de Programa, microprocesador y otros.). Una explicación simplista podría ser la de decir que el Z80 no puede desactivar la página donde se encuentra el programa que se está ejecutando porque si lo hiciésemos sucedería que durante unos microsegundos, como mínimo, el Z80 no sabría que hacer a continuación (pues virtualmente no existe programa para él durante ese tiempo), lo que haría que el ordenador se bloqueara (ya que el programa que se estaba ejecutando está ahora en una zona de memoria desactivada).
NO hagáis mucho caso de esta explicación pues como digo, la realidad dista bastante de ser tan simple….
6. Si los 4 Slots primarios están llenos de RAM, nuestro MSX tendrá 256 kbs de memoria (esto es sólo una suposición, no os olvidéis nunca del BASIC y del S.O. que son imprescindibles).
Según lo aquí explicado, lo más simple, no sería posible tener Slots de más de 64 kbs porque hemos dicho que un Slot contiene “SIEMPRE” cuatro páginas de memoria de 16 kbs. Esta afirmación no es cierta puesto que un Slot puede tener más de 4 páginas de memoria de 16 kbs, aunque sólo pueda tener cuatro páginas activadas a la vez (esto ocurre en los MSX2 en los que las páginas de memoria de algunos Slots están ampliadas). Esto significa que dichas páginas se configuran a si mismas como si fuesen auténticos Slots (se les denominan SubSLOTS), y se subdividen a su vez en otras 4 sub-páginas. Así por ejemplo, la página 0 del Slot 0 puede ser un subslot y contener las subpáginas 0-0, 0-1, 0-2 y 0-3.
El mecanismo de funcionamiento de estos subslots me es desconocido por carecer del equipo necesario para poder estudiarlo, es decir, que como no tengo un MSX-2 no sé como funcionan. De cualquier forma, debe operar de un modo similar a lo aquí explicado….
7. Deduciré algo tan simple, como el hecho de que mi ordenador no dispone de más cantidad de memoria RAM que la que se encuentra activada con el BASIC (no puede por tanto tener 64 kbs), lo que significa que dispongo de un ordenador de 16 ó 32 kbs.
8. Estos programas son necesarios porque el programa a cargar en la memoria deberá desactivar y activar páginas de memoria según lo necesite para su almacenamiento y posterior ejecución, por lo tanto necesitará saber en todo momento dónde hay la suficiente RAM para su almacenamiento.
Los datos ROM/RAM y TODO RAM se almacenan en posiciones fijas de la memoria porque tras cargar cada bloque de datos va a ser necesario “echar mano” de ellos para activar-desactivar las páginas de memoria adecuadas. El programador sabe que es preferible analizar una sóla vez la memoria, guardando los resultados obtenidos de ese análisis, que tener que analizarla cada vez que un bloque de datos es cargado, para así almacenarlo.
9. Es poco probable que ésto ocurra, a no ser que tengamos un MSX-2, puesto que supone un despilfarro hacer un ordenador con tres Slots a “medias”, es decir, es más rentable incorporar Slots completos de 64 kbs de RAM que colocar en nuestro MSX dos Slots (el 1 y el 3 en nuestro ejemplo), que sólo dispongan de 32 kbs de RAM, que estén “a medias”.
Para comprender perfectamente lo expuesto deberíais hacer el gráfico de la memoria de vuestro MSX (¡Si!, ese gráfico de bloques del que tanto hemos hablado), y colocar en su lugar correspondiente tanto la RAM como la ROM de este ejemplo. Cuando lo veas dibujado, seguro que comprendes inmediatamente a que me refiero cuando hablo de Slots “a medias” y de lo “extraño” que parece… No obstante, que no sea probable no significa que no sea posible, es más, en muchos ordenadores MSX-1 el Slot 0 es un Slot “a medias”, (cosa que resulta obvia si has comprendido todo lo dicho anteriormente).
10. La memoria para el BASIC consta de 32 kbs de RAM, en teoría, pero como sabemos unos 4 kbs son necesarios para el S.O. (RAM del Sistema), con lo cual nos quedamos con los 28 kbs típicos del BASIC. A esos 28.815 bytes free deberás restarle otros 4 kbs aproximadamente, que son los que se necesitan para manejar la unidad de discos, con lo que nos quedaremos con unos penosos 24 kbs para el BASIC. Esta, y no otra, es la razón por la que ciertos programas BASIC e incluso programas CM no cargan o no lo hacen correctamente cuando ¡¡¡¡tenemos la unidad de discos conectada!!!! (se sobreentiende que los cargamos de cinta, of course).
NOTA: Estos ejercicios son meramente orientativos, y sus soluciones no tienen porque ser únicas ni exactas. Es sabido que en Informática existen casi infinitas formas de resolver un mismo problema (sobre todo en Programación). No os extrañe que vuestras soluciones no sean iguales a las que yo os propongo… conformáos con que se parezcan un poquito, tan sólo un poquito. ¡Y no olvidéis LA PRÁCTICA!, que es como verdaderamente se aprende.
1.LAS HERRAMIENTAS BÁSICAS.
Teniendo presente que todo lo que voy a explicar a continuación estará referido a la desprotección de programas en cinta, podemos afirmar que el equipo mínimo necesario para realizar tal labor consta de:
-Programa Ensamblador/Desensamblador. Puede utilizarse cualquiera con un mínimo de calidad, aunque yo utilizo y recomiendo el GEN/MON de HISOFT.
-Uno o varios Analizadores de Slots de los que se conozca mínimamente su funcionamiento. Aunque utilizo y recomiendo el de GREMLIN GRAPHICS, por su compatibilidad casi total (aunque podéis utilizar cualquiera).
-Un ordenador MSX con al menos 64 kbs de memoria RAM. En realidad podemos desproteger programas con menos memoria, pero sucede que después no podríamos probarlos… (captáis la lógica, ¿no?).
-Por último, necesitaréis un copión de cinta o un lector de cabeceras para leer las direcciones de Inicio, Final y Ejecución del programa cargador. Obviamente, también necesitaremos un casete (grabadora).
Nota: En este caso yo, José Manuel, estoy haciendo como os recuerdo una transcripción del Curso Original. En el Curso Original se recomienda el uso del Gen/Mon pero personalmente considero más práctico el uso del RSC II, cuyo manejo me parece más fácil. No obstante podéis usar el que queráis.
2.BLOAD”CAS:”, R
Todos hemos utilizado miles de veces esta instrucción del BASIC MSX. Si nos remitimos a nuestro manual del BASIC podremos leer lo siguiente:
“BLOAD (Binary Load), carga programas de Lenguaje Máquina, o los carga y los ejecuta….”.
Todos sabemos lo que hace, pero nos hemos preguntado alguna vez ¿cómo lo hace…?. Es decir, como sabemos el BASIC no es más que un Interprete entre el humano y la máquina (lo único que es capaz de entender nuestro MSX en última instancia es CM). Así pues las instrucciones BASIC son codificadas por el Interprete BASIC en grupos de instrucciones CM mucho más sencillas, que son las que “entiende” y ejecuta el Z80A.
Alguno estará pensando que vamos a adentrarnos en complicadísimas explicaciones sobre el CM… Despejad esos pensamientos de vuestras calenturientas mentes porque de momento, no nos interesa conocer como funciona a fondo nuestro MSX. Nos conformaremos con tener una levísima idea de cómo almacena habitualmente nuestro MSX la información en casete….
3.CÓMO SE ALMACENAN LOS DATOS EN EL CASETE.
a) El primer pitido que se escucha es el denominado HEADER. Su función es la de advertir al ordenador acerca de la velocidad de grabación del bloque de datos que se va a cargar (1.200 ó 2.400 baudios).
b) A continuación viene un grupo de 16 bytes llamado LEADER, que indica al ordenador el tipo de fichero que se va a cargar y su nombre.
Este Leader puede tener más de 16 bytes, aunque en los bloques grabados con BSAVE, CSAVE, y SAVE nunca va a superar los 16 bytes. Supongo que los creadores del BASIC MSX decidirían, por conveniencia, que el Leader comprensible para el BASIC tuviera siempre 16 bytes. Así pues, tendremos los siguientes TIPOS DE LEADER:
1. El Leader Normal de un programa grabado con BSAVE sería algo así:
DO DO DO DO DO DO DO DO DO DO 41 42 43 44 45 46
– Los 10 primeros bytes, cuyo contenido HA DE SER EL MISMO, sirven para informar al ordenador (vía Interprete BASIC, de que se trata de un bloque de datos BINARIOS (DO), y en definitiva que deber cargarse con la instrucción Basic BLOAD.
– Los 6 últimos bytes son el nombre del programa (ABCDEF en este ejemplo).
2. El Leader Normal de un programa grabado con SAVE sería algo así:
EA EA EA EA EA EA EA EA EA EA 41 42 43 44 45 46
En los ficheros de datos grabados con SAVE tenemos que:
-los 10 primeros bytes contienen el dato “EA”.
-los 6 últimos bytes como en el primer caso, son el nombre del programa (ABCDEF).
3. El Leader Normal de un programa grabado con CSAVE sería algo así:
D3 D3 D3 D3 D3 D3 D3 D3 D3 D3 41 42 43 44 45 46
En los ficheros de datos grabados con CSAVE tenemos que:
-los 10 primeros bytes contienen el dato “D3”.
-los 6 últimos bytes como en el primer caso, son el nombre del programa (ABCDEF).
Nuestro MSX BASIC, como sabemos, sólo posee 3 instrucciones distintas de carga de bloques de datos desde el casete (MERGE, no puede considerarse una instrucción autónoma puesto que no es más que un LOAD con verificación posterior). Aparte quedan los archivos de datos que podamos crear con OPEN, que por el momento no nos interesan.
De la configuración del LEADER, y de su utilidad y funcionamiento surgen multitud de dudas y cuestiones confusas… De todas ellas, las que más atraerá nuestra atención es la siguiente: ¿Qué sucederá si cambiamos alguno de los 10 primeros bytes del LEADER….?. Imaginemos por ejemplo un Leader como éste:
DO DO FF FF FF FF FF FF FF FF 00 00 00 00 00 00
Ante semejante “cacaomaravillao” de bytes sin sentido, nuestro estricto MSX-BASIC no puede más que pedir auxilio desesperadamente, es decir, que el BASIC NO SERÁ CAPAZ DE RECONOCER SEMEJANTE LEADER y por tanto al no reconocerlo como uno de los posibles casos típicos (DO, D3, y EA), para los que está programado a responder, simplemente ignorará este programa. Tanto rollo para decir que si la configuración del Leader varía lo más mínimo, nuestro BASIC NO será capaz de cargar ese programa (estamos hablando ¡¡¡DESDE EL BASIC naturalmente!!!).
Por cierto, para los despistadillos recuerdo que los últimos 6 bytes del Leader SI podrán tomar distintos valores (ya que son ¡¡¡el Nombre del Programa!!!). Los que no pueden alterarse, son los 10 primeros, ¿ok?.
Lógicamente, más de uno se habrá dado cuenta de que si al cambiar el LEADER lo que hacemos es que el programa no pueda ser cargado desde el BASIC, entonces no hemos hecho otra cosa que no sea proteger dicho programa. Un PROGRAMA PROTEGIDO es por tanto, todo aquel que no puede ser cargado directamente desde y en BASIC MSX.
De está definición simplista y de “mi cosecha”, se sigue que el DESPROTEGER UN PROGRAMA, para nosotros, no es mas que hacer que un programa protegido pueda ser cargado desde y en BASIC-MSX.
Esta técnica de proteger los programas alterando su Leader no es muy utilizada, tal vez por lo sencillo que resulta el desproteger estos programas. Mucho más habitual es prescindir totalmente del Leader, es decir, ¡quitarlo de en medio!, ¡darle el pasaporte!, ¡tirarlo a los tiburones del Hudson!….
c) Por último, tras el Leader, hay un segundo grupo de datos precedidos por una especie de HEADER (¿Se ha perdido alguien?). Este segundo grupo de datos (Segundo Leader) varía dependiendo del tipo de fichero que se está cargando, es decir, si es del tipo DO, D3 ó EA.
Para los Ficheros Binarios, que son los que realmente nos interesan, este “Segundo Leader”, por llamarlo de algún modo, está formado por 6 bytes que corresponden a:
Es evidente, que este segundo Leader es distinto para cada programa, puesto que cada programa puede tener una dirección de Inicio, Fin o Ejecución distinta. Lo importante no es el dato en si, si no la forma en como se organizan esos datos. El siguiente esquema, muestra la Organización Secuencial de los Datos en el Casete:
Cualquier alteración de los LEADER supone, en último término, ¡¡¡PROTEGER EL PROGRAMA Y QUE EL BASIC NO SEA CAPAZ DE CARGARLO!!! 😉
4.UN POQUITO DE CÓDIGO MÁQUINA.
Lamentándolo mucho, creo que ha llegado el momento de que aprehendais algo de CM. Es inevitable…, ¡debe ser así…!.
A) LOS REGISTROS DEL Z80.
Los registros son unos dispositivos de metál-óxido-semiconductor que constituyen la forma de memoria más rápida existente (se encuentran en el interior del microprocesador Z80 lógicamente). Los registros internos están habitualmente etiquetados de 0 a n, y su función no está definida de antemano (por eso se dice que son Registros de Propósito General). Pueden contener cualquier dato utilizado por el programa.
Estos Registros de Propósito General, suelen utilizarse para almacenar datos de 8 bits (un byte, o sea, cantidades numéricas comprendidas entre 0 y 255). En algunos microprocesadores, como el Z80, pueden manipularse dos de estos registros simultaneamente, que llamaremos “Registros Apareados”, y que permiten el almacenamiento de magnitudes, datos o direcciones, de 16 bits (desde 0 a 65.535).
Los Registros de Propósito General de 8 bits que tenemos en el Z80 se denominan:
B, C, D, E, H y L.
El Z80 dispone de dos bancos de datos (ver esquema de registros). Es decir, de dos grupos idénticos de seis registros cada uno. En un momento determinado, sólo pueden usarse seis registros, pero hay instrucciones especiales CM para intercambiar sus contenidos entre los dos grupos. Por tanto, uno de ellos se comporta como Memoria Interna, mientras que el otro funciona como Bloque de Registros.
Para evitar confusiones, supondremos que sólo hay seis Registros de Trabajo –> B, C, D, E, H y L e ignoraremos al Segundo Grupo: B’, C’, D’, E’, H’, y L’.
Otra particularidad de estos registros es que, además de ser registros generales de 8 bits, se pueden agrupar en pares de Registros Apareados: BC, DE y HL. Así pues, los contenidos de B y C, por ejemplo, pueden contener datos de 8 bits, que unidos formen una dirección de memoria de 16 bits o un dato de 16 bits. Gracias a ello, los seis registros de este grupo pueden usarse tanto para almacenar datos de 8 bits como para guardar apuntadores de 16 bits para el direccionamiento de la memoria.
Otro grupo de registros, presentes en todos los microprocesadores, son los Registros de Direcciones “Puros”. En el Z80 hay, como en todo microprocesador:
– Un Contador de Programa, PC, que contiene la dirección de la instrucción que ha de ejecutase a continuación.
– Un Puntero de Pila, SP, que señala la parte superior de la pila en la memoria. (En el Z80, señala la última entrada real en la pila. Cabe mencionar además, que la pila crece “hacia abajo”, es decir, hacia direcciones de memoria más bajas).
En el Z80 existen también unos registros especiales, denominados Registros Índices que son: IX e IY. Su funcionamiento y direccionamiento es muy particular, y bastante complejo. Nos bastará con conocer su existencia y saber que se trata de registros de 16 bits que se utilizan para las instrucciones indexadas (para la indexación en general).
Para finalizar este apartado, nos queda ocuparnos de un registro fundamental en todo microprocesador: El Acumulador. En el Z80 tenemos:
– A el Acumulador Principal,
– A’ el Acumulador Secundario (normalmente inactivo).
Junto al acumulador aparece un Registro de Estado denominado F (y también tenemos el F’), en el que se encuentran las famosas “banderas”. (Este registro de estado, no es directamente modificable por el usuario, sino que va siendo modificado por el propio programa debido a las situaciones “especiales” que en el programa se den). La función de las banderas del registro F se explicará más adelante.
Nota: Para simplificar las cosas supondremos siempre, salvo que se diga lo contrario, que sólo disponemos de los registros: B, C, D, E, H, L, A y SP.
B) LA PILA:
Una Pila es lo que formalmente se llama una estructura de datos del tipo LIFO (Last In First Out), (es decir el Último en Entrar el Primero en Salir). Está formada por un conjunto de posiciones de memoria adscritos a dicha estructura de datos. Su característica esencial es que se trata de una estructura cronológica: el primero de los elementos introducidos en la pila ocupa siempre el fondo de la misma, mientras que la introducción más reciente está siempre en su parte superior.
Su organización es comparable a la del portabandejas de la barra de una hamburguesería: las bandejas se apilan sobre una base que se hunde en el pozo de la barra conforme aumenta el peso, se colocan y se cogen por arriba, de manera que las últimas en llegar al montón son siempre las primeras en salir de él.
La pila en el Z80 sólo es accesible mediante 2 instrucciones:
– Push: Guardar una dirección o dato de 16 bits en la dirección apuntada por el puntero SP (Puntero de la Pila, en inglés Stack Pointer)
– Pop: Extraer una dirección o dato de 16 bits de la dirección apuntada por el puntero SP.
En definitiva, lo que hacen respectivamente cada una de estas instrucciones respectivamente es: Guardar un elemento en la pila y Extraer un elemento de la pila.
El Puntero de la Pila (SP) se incrementa o decrementa automáticamente tras ejecutar
estas dos instrucciones, de modo que siempre ha de estar apuntando a la última entrada
realizada.
Existen también otras instrucciones para extraer elementos de la pila (que de momento no nos interesan). La pila es necesaria para aplicar tres recursos de programación:
– Subrutinas.
– Interrupciones.
– Almacenamiento Temporal de Datos (¡¡¡que es lo que a nosotros nos interesa!!!).
La PILA, se crea en el Z80 de la siguiente forma:
-dentro del MicroProcesador se reserva un Registro (el SP) para almacenar el puntero de la pila, es decir, la dirección de su elemento superior (o a veces, la dirección de su elemento superior mas uno).
– a continuación se crea la pila como una zona de la memoria; de esta forma bastan los 16 bits que ocupa el puntero para señalar cualquier posición de la pila.
El interés que para nosotros tiene la Pila es que puede ser fácilmente “relocalizada”, es decir, que su posición dentro de la memoria puede cambiar con sólo cambiar la dirección contenida en el puntero de la pila (SP). Esta relocalización la llevan a cabo casi siempre todos los programas comerciales y es fundamental tenerla en cuenta a la hora de desprotegerlos (porque el BASIC, como todo programa, tiene su propia pila alojada en unas direcciones de memoria fijas, a partir de &hF000, y si alteramos la pila desde CM y luego queremos volver al BASIC, ¡¡¡el ordenador se quedará bloqueado!!!).
C) LAS BANDERAS o REGISTROS DE ESTADO (F):
El Registro de Estado es un registro de 8 bits, cuya función es la de “llevar la cuenta” de las situaciones excepcionales que se dan en el interior del microprocesador. El contenido del Registro de Estado puede verificarse mediante instrucciones especiales o leerse mediante otras instrucciones. Las instrucciones condicionales provocan la ejecución de un nuevo programa (o el salto a otra parte del programa) en función del valor de uno de los bits del Registro de Estado. Los bits del referido Registro de Estado reciben los nombres de:
S, Z, H, P/V, N y C
(Ojo, ¡¡¡no confundir la Bandera H y C con los Registros del mismo nombre!!!!).
Las Banderas, que son cada uno de los Bits del Registro de Estado F, que más vamos a utilizar y que por lo tanto más nos interesan son dos: C y Z.
1. Acarreo ( C ) : El Bit de Acarreo o Bandera de Acarreo desempeña una función doble:
– en primer lugar indica si una operación de suma o resta ha dado lugar a un acarreo (llevarse uno).
– en segundo lugar, es el noveno bit de las instrucciones de desplazamiento y rotación.
Son muchas las instrucciones que modifican el estado de este bit (0 ó 1), pero en general se puede decir que todas las operaciones aritméticas lo igualan a 0 ó 1.
2. Cero ( Z ): El Bit de Cero o Bandera de Cero se utiliza para verificar si es cero el valor de un byte que se ha calculado o que se está transfiriendo. También se usa en instrucciones de comparación, para señalar la coincidencia, y en algunas otras funciones.
-si se produce una operación con resultado 0 o si se transfiere un dato y el byte vale 0, el bit Z se fijará a 1
-en caso contrario se fijará al valor 0.
(También desempeña otras muchas funciones…….) 😉
5.INSTRUCCIONES DEL Z80.
Las instrucciones que vamos a examinar son las que nos serán necesarias en un futuro (sólo veremos las IMPRESCINDIBLES!!!). Son las siguientes:
- DI: Desconecta las interrupciones automáticas del Lenguaje Máquina. Debéis utilizarla siempre antes de conmutar páginas de la memoria o Slots (es recomendable). Una explicación medianamente “buena” de esta instrucción ocuparía unos 20 ó 30 folios…
- PUSH XX: Introduce el par de registros XX en la pila. XX puede ser: SP, BC, DE, HL, AF, IX e IY. El contenido de cualquiera de estos registros se guarda en la pila y el puntero de la pila (SP) se decrementa en dos direcciones (2 bytes). Olvidad la explicación “técnica” y recordad que esta instrucción sirve para GUARDAR DATOS EN LA PILA. Como el número de registros en CM es muy limitado es necesaria una zona de la memoria (la PILA), en la que se guarden temporalmente diversos datos y direcciones, ya que los registros están siempre ocupados (¡NO pueden utilizarse los registros como si de simples variables Basic se tratara!)
- POP XX: Extrae de la pila el par de registros XX. El contenido de la posición de memoria direccionada por el puntero de la pila (SP) se carga en el par de registros XX y a continuación se incrementa en dos bytes dicho puntero. Esta instrucción hace exactamente lo contrario que PUSH, es decir, nos devuelve el valor que habíamos guardado en la pila en el par de registros XX. Nos servirá para “SACAR” VALORES PREVIAMENTE GUARDADOS EN LA PILA.
- INC X o XX o ….: Incrementa en una unidad el contenido del registro X (que puede ser A, B, C, D, E, H y L) o del par de registros XX. Imaginemos el siguiente ejemplo:
1. HL = 255 —> LD HL, 255
2. HL = HL + 1 —> INC HL
3. HL = 256 —> HL = 256
- DEC X o XX o …: Decrementa el contenido del registro X o de el par de registros XX.
Hace exactamente lo contrario que INC como habréis notado…
XX <— XX – 1
- JP DIR o CC, DIR o …:
· JP DIR salta a la posición de memoria especificada por DIR, es decir, la ejecución del programa “salta” a dicha posición de memoria (viene a ser como un GOTO, para que nos entendamos…).
· JP CC, DIR salta, transfiere la ejecución del programa, a la posición de memoria especificada por DIR sí y sólo sí se satisface previamente la condición CC. Sólo si se produce la condición se da el salto. Las condiciones que pueden verificarse para realizar los saltos son las conocidas banderas (C, Z, S, P/V, etc…). Ved el siguiente ejemplo:
1. LD BD, 2 —> B = 2
2. DEC B —> B = B – 1 : B = 1
3. JP Z, BASIC —> Ir al BASIC si B = 0 . (NO se cumple!!!)
4. DEC B —> B = B – 1: B = 0
5. JP Z, BASIC —> Ir al BASIC si B = 0. (Se cumple)
(A la izquierda tenéis el Código Real, y a la derecha los comentarios a éste complejísimo Programa… )
- CALL XX o CC, XX o ….: La ejecución del programa salta a la dirección de memoria XX (o bien salta a la dirección de memoria XX si se satisface la condición CC). La ejecución del programa continúa por la nueva dirección XX hasta que se encuentra la instrucción RET o RET CC momento en el cual, la ejecución retorna a la dirección de memoria posterior a la que contenía la instrucción CALL. ¿Lo habéis leído todo bien….?. ¿Si…?. ¡Pues ya lo estáis olvidando…!. Esta instrucción viene a funcionar de modo similar a GOSUB y RETURN del BASIC (¡mentira podrida!, pero como no quiero explicaros a fondo como funciona, otras 20 hojitas de nada, ¡con eso vais de pique!…….).
- RET o RET CC: Retorno de una Subrutina, o retorno Condicional de una Subrutina. Para volver al BASIC desde el CM debéis utilizar al final de vuestros programas esta instrucción, cuyo “formato” o byte que la representa es &hC9 (ó 201 en decimal).
Fijaos en el esquema y entenderéis, o eso espero, su funcionamiento básico:
- IN r, ( C ): Carga el registro r (A, B, C, D, E, H y L) a partir del puerto C. Se lee el dispositivo periférico direccionado por el contenido del registro C y el resultado se carga en el registro especificado. Consultad la instrucción IN de vuestro manual BASIC (¡¡¡que es casi idéntica!!!). Consultad también de vuestro manual la asignación de puertos de entrada y salida (al final del manual, si es que viene…).
Ejemplo:
IN B, (&hA8) —-> B = contenido del puerto &hA8, es decir, la asignación de las páginas de memoria (Slots).
- OUT ( C ), r: Si IN sirve para leer el contenido del puerto C, ¿OUT servirá para…?.¡Premio!, para enviar un dato a dicho puerto. Técnicamente se dice que sirve para dar salida al contenido del registro r a través del puerto C: el contenido del registro de 8 bits especificado se lleva al dispositivo periférico direccionado por el contenido del registro C. El registro r puede ser: A, B, C, D, E, H y L.
Consultad de nuevo en vuestro manual de BASIC: la función OUT del BASIC y la del CM son casi idénticas. A nosotros esta instrucción nos va a servir para activar la configuración de memoria TODO RAM y la configuración ROM/RAM.
- LD destino, origen: El contenido de la dirección, registro o dato de origen se carga en la dirección o registro de destino. Fijáos en los ejemplos (hay multitud de instrucciones “variantes” de LD).
1. LD A, 201 —-> A = 201
2. LD A, B —-> A se carga con el contenido de B. (B no se modifica).
3. LD HL, 500 —> HL = 500
4. LD HL, (DIR) —> HL = contenido de la dirección de memoria DIR.
5. LD (DIR), HL —> En la dirección de memoria DIR se introduce el valor de HL.
6. LD A, (DIR) —> A = contenido de la dirección de memoria DIR.
7. LD (DIR), A —> En la dirección de memoria DIR se introduce el valor contenido en A.
Y podría seguir, y seguir…, y ahora no llenaría 20 hojas, ¡tendría que escribir más de 100!. De forma genérica se puede resumir:
LD DD, (NN) LD R, N
LD (NN), DD LD R, R
LD DD, NN LD (BC), A
LD NN, DD LD (DE), A
LD (HL), n LD (HL), A
…. … …. …
Donde DD sería un registro de 16 bits (HL, DE, BC…), NN sería una dirección de memoria o un dato de 16 bits (de 0 a 65.535 en ambos casos), R sería un registro de 8 bits (A, B, C, D, E, H y L) y N sería un dato numérico de 8 bits, un byte de 0 a 255…
Esta instrucción es fundamental en CM, y creo que es la que más se utiliza, ya que es la más abundante (hay más de 50 LDs distintos). Más adelante la trataremos en diversos ejemplos.
Tras haber leído todo esto estoy seguro de que tenéis un cacao mental que es demasiado… Código Máquina, lo que se dice Código Máquina no tenéis ni pajoletera idea, ¡pero os ha quedado un dolor de cabeza que da gusto…! (“No hay mal que por bien no venga…”, je, je, je…)
6.LOS EJERCICIOS.
Dada la importancia de este tema, y su CONSABIDA DIFICULTAD, convendría que realizaseis los siguientes ejercicios (una vez que hayáis leído y comprendido todo lo anterior, ¡¡¡eh!!!). En esta ocasión los ejercicios son MUY IMPORTANTES (como importantísimo sería que cogierais un ensamblador, GEN, RSC/RSC II, asMSX, … y fueseis practicando “en vivo”; o también que le echaseis un vistazo al libro CM que tenéis sujetando la pata coja de la cama, por ejemplo…
1. ¿A qué tipo de programa corresponde este LEADER y cual es el nombre del programa?.
DO DO DO DO DO DO DO DO DO DO 53 4F 46 54
2. ¿A qué tipo de programa corresponde el siguiente LEADER y cual es el nombre del programa?. (Fíjate bien!!!)
EA EA EA EA EA EA EA EA EA EB 00 00 00 00 00 00
3. En vistas del siguiente LEADER: ¿Cuáles son las direcciones de Inicio, Fin y Ejecución del programa?
00 88 00 C8 00 88 (nota: ¡¡¡todos los números están en hexadecimal!!!)
4. ¿Es posible que un programa con un nombre de más de 6 caracteres cargase desde el BASIC (con CLOAD, LOAD O BLOAD)?.
5. ¿Cuáles son los Registros de Propósito General que posee el procesador del MSX?¿Cuáles son los Registros Apareados que se pueden formar?.
¿Es el Registro IX un registro de 8 bits?.
¿El registro A es de 8 bits o de 16 bits?.
6. ¿Puede un registro de 16 bits cargarse con un dato de 8 bits?.
¿Puede un registro de 8 bits cargarse con un dato de 16 bits?.
7. ¿Podré introducir el valor 67.000 en el registro HL?. ¿Y el valor 35.500 en el registro A?. ¿Y en el B?.
8. ¿Qué sucederá si cargo en el Puntero de la Pila el valor 45.000 (la dirección 45.000 para ser más exactos)? (¡¡¡Esta pregunta tiene mucha miga…!!!)
9. ¿Qué significa LIFO?. ¿Qué es una PILA?. (¡¡¡las de corriente no valen!!!) 😦
10. Haz lo siguiente:
B = 245
C = 28
A = 25.000
A = (contenido de la dirección 34.000)
HL = 4.500
DE = 25
A = (contenido de HL)
HL = contenido de la dirección DIR
Carga en la dirección genérica DIR el valor 500
Carga en DIR el valor de BC
11. Haz lo siguiente:
B = 77
Réstale 4
Comprueba si es 0 y si no lo es salta a BASIC
12. Haz lo siguiente:
B = 201
C = B
Guarda BC en la PILA
Lee el contenido del puerto &hA8 (asignación de la memoria) y después guárdalo en el registro E.
Extrae BC de la PILA.
Envía el contenido de B y C al puerto &h99.
13. Si el registro B contiene 255 y lo incrementamos en una unidad, ¿qué sucederá con el valor contenido en ese registro?. (esto nos es fácil de responder… y os adelante que la respuesta ¡¡¡NO ES QUE EL ORDENADOR SE BLOQUEA!!!)
Nota: Cuando digo “haz lo siguiente”, me refiero a que debéis hacer un pequeño programa en CM que realice las operaciones que os indico. Por ejemplo, si os digo que hagáis:
E = 4
Incrementar E
D = 248
Decrementar D
Deberíais hacer lo siguiente:
LD E, 4 –—> E = 4
INC E —-> E = E + 1 ; E = 5
LD D, 248 —-> D = 248
DEC D —-> D = D – 1 ; D = 247
(¡¡¡Lo que va en “azul” son las instrucciones CM, y lo de “negro” los “comentarios” de lo que hacen dichas instrucciones!!!) 😉
P.D. En primer lugar, quiero realizar una aclaración de suma importancia…
Este curso fue creado originalmente por FRANCISCO FUENTES LORENZO. El formato original del mismo son fotocopias escritas a máquina, y que yo he intentado pasar a Pdf para luego aplicarle soft de OCR, pero viendo los desastrosos resultados he optado por teclearlo todo letrita a letrita en formato WORD, respetando fielmente el original….
Para cualquier aclaración, comentario, sugerencia, etc, etc… no dudéis en escribirme. Me gustaría que todo aquel que tenga conocimientos sobre el tema, y pueda contribuir a mejorar este curso, ampliarlo, corregirlo, etc, que se anime y me escriba. También me gustaría me escribierais para darme vuestra opinión sobre el mismo, si lo habéis leído, y tenéis intención de seguirlo, etc, etc, etc… Y aprovecho, aún a riesgo de ser pesado que por favor, todos los que tengaís material MSX por ahí que pueda resultar interesante para el resto de Usuarios (Libros, Documentación Técnica, etc, etc, …) o si sabeis de alquien que lo tenga, que lo escaneéis y lo paséis a pdf para compartirlo con el resto y preservarlo para que todo ese valioso material no desaparezca con el paso del tiempo!!!).
Gracias al Paco y al Robsy por animarme a llevar a cabo esta iniciativa, y a Karloch por darle difusión (en un primer momento), así como a Konamito posteriormente. Y gracias, mil veces gracias al Paco que casualidades de la vida nos hemos vuelto a “encontrar” después de mucho, mucho, muuuuchoooooo tiempo…
Gracias y mil veces gracias Paco por tus cartas, los juegos que gracias a ti conseguí, las dudas que me resolviste, tu infinita paciencia y por haber escrito este Curso en su día ”exclusivamente para mi”… (ja, ja, ja… quien te iba a decir esto por aquel entonces, ¿eh?).
Va por ti, MAESTRO…!!! 😉 😉 😉
Por si alguien me quiere contactar os dejo mi cuenta de GMAIL —> josemanuel74
MATERIAL COMPLEMENTARIO:
Os dejo aquí varios enlaces con diverso material para que os «entretengáis». Por si alguien necesita y/o tiene curiosidad por algún Libro de BASIC os dejo 2 Libros de Sony (uno para MSX-1 y otro para MSX-2)
También os dejo varios Libros de Lenguaje Máquina. Al final de estos Libros suele venir una Tabla-Resumen con los nemónicos de las Instrucciones Ensamblador del Z80. Quizás os resulte útil imprimirlas y tenerlas a mano para «consultas rápidas».
Os dejo también varios Ensambladores/Desensambladores para MSX (con sus respectivos Manuales), así como otro Ensamblador para PC.
¡¡¡A disfrutarlo..!!! 😉
- LIBROS:
– Libro de BASIC – MSX-1, de Sony.
– Libro de BASIC – MSX-2, de Sony.
– Lenguaje Máquina para MSX, Joe Prichard.
– Programacion del Z80 (Rodnay Zaks) (2ª reimpresión, 1990).
– “Easy Ensambler“. Curso de Ensamblador de Konamiman.
– Y si lo que queréis es un Tutorial Paso a Paso, eminentemente práctico y usando las Herramientas más actuales de cara a facilitarle la vida al Programador os dejo el Tutorial de Pepe Vila. Es un Tutorial de Iniciación al Ensamblador MSX para lo cual usa el Ensamblador “AsMSX” de Eduardo Robsy. Es un potente Ensamblador que os facilitará mucho la tarea.
Creo que la Web original del Autor está KO. No obstante os dejo en ese enlace el Contenido de todo el Curso ya descargado y recopilado, incluyendo el Entorno de Desarrollo:
- ENSAMBLADORES:
– Para los que quieran trabajar en Ensamblador y usar un Desensamblador en un MSX real os dejo el RSC-II junto con su Manual. El RSC-2 es un Ensamblador-Desensamblador bastante decente y que en su día fue publicado por la Revista MSX-CLUB.
– Otro Ensamblador/Desensamblador para usar desde el MSX. En este caso se trata del Ensamblador/Desensamblador GEN/MON de HiSoft.
– Si lo que quieres es Programar en Ensamblador pero con las Comodidades de hacerlo desde un PC existe un potente Ensamblador llamado AsMSX v.0.15a programador por Eduardo Robsy. Este es el Ensamblador que se usa para programar en el Tutorial de Pepe Vila.
Si te quieres bajar el Contenido de este Capítulo del Curso en PDF puedes hacerlo desde AQUÍ.
Pingback: Analizando el oscilograma del Manic miner – MSX