K-Assembler para ZX-81

Foro dedicado a la programación en todo tipo de sistemas clásicos.
dancresp
Amiga 1200
Amiga 1200
Mensajes: 1393
Registrado: 23 Dic 2008, 17:53
Sistema Favorito: MSX
primer_sistema: ZX81
Primera consola: Atari 2600
Gracias dadas: 3 veces
Gracias recibidas: 20 veces

K-Assembler para ZX-81

Mensajepor dancresp » 03 Abr 2014, 13:03

screen_1.gif
screen_1.gif (4.74 KiB) Visto 3966 veces


EL PROGRAMA
Este programa es un sencillo pero efectivo ensamblador de 375 de los 697 mnemotécnicos del microprocesador Z80.

Por evidentes motivos de memoria, el ensamblador se limita a mostrar por pantalla los códigos, en formato decimal, del mnemotécnico introducido. Este proceso no afecta a la memoria RAM.

El ensamblador reconoce, parcialmente, las siguientes 20 instrucciones:
LD, ADD, ADC, SUB, SBC, AND, XOR, OR, CP, INC, DEC, BIT, RES, SET, PUSH, POP, RL, RR, SLA y SRA.


Limitaciones del ensamblador:
- No ensambla mnemotécnicos con valores numéricos como parámetros, excepto para BIT, RES y SET.
- No ensambla mnemotécnicos con registros dobles (16 bits) como BC, DE y HL excepto el (HL) y en PUSH y POP.
- No ensambla mnemotécnicos con IX, IY, R ó I.
- No se comprueba que la instrucción introducida sea correcta. El resultado puede ser erróneo o provocar un error.
- Solo se comprueban las dos primeras letras del nombre de las instrucciones.
- Solo se comprueba la primera letra de los registros, excepto si empieza por paréntesis que se considera (HL).
- La instrucción ADC se debe introducir como AC para diferenciarla de ADD, por el motivo de las dos letras.
- En las instrucciones BIT, RES y SET se debe cambiar el orden de los parámetros. Primero el registro y después el bit.

El resultado se muestra en pantalla en un par de segundos y queda listo para introducir otro mnemotécnico.

Ejemplos:
ADD A,D : 130
LD A,H : 124
PUSH HL : 229
BIT E,6 : 203 115

Descargar el juego en formato ".Z81" (Snapshot del EightyOne):
K-Assembler.rar
(1.03 KiB) Descargado 291 veces


BLOQUES
He dividido el listado en 5 bloques:

- Inicializar variables principales.
- Procesador de la línea de entrada.
- Identificador de instrucciones.
- Identificador de parámetros.
- Ensamblado de la línea.


COMO FUNCIONA
A continuación detallo, línea por línea, el funcionamiento del programa.

Se utilizan las siguientes variables:
U – Variable que contiene el valor “1”.
I – Variable usada como contador de parámetros.
F – Variable para bucles, o identificador del segundo registro de la instrucción a ensamblar.
O – Variable usada para guardar el identificador de la instrucción a ensamblar.
R – Variable usada para guardar el identificador del primer registro de la instrucción a ensamblar.
A$ - Variable donde se guarda la línea que se ha de procesar.
W$ - Variable donde se guarda el parámetro a procesar.

2 – Guardamos el valor 1 en la variable “U”. Se usará a lo largo del programa y permite ahorrar memoria.
4 – Guardamos el 0 en la variable “I”. Se usa como contador de parámetros.
8 – Introducir en A$ la instrucción a ensamblar.
10 - Se borra la pantalla para ahorrar memoria.
12 - Mostramos en pantalla el mnemotécnico a ensamblar.
14 – Inicio del bucle que analiza la línea de entrada.
16 - Si en una posición de la línea se encuentra un punto o una coma se salta a la línea 20.
18 – Si el bucle no ha llegado al final vuelve a la línea 14.
20 - Guardamos en W$ el valor de A$ hasta el espacio, más un espacio.
22 - Guardamos en A$ desde después del espacio hasta el final de la línea de entrada.
24 - Incrementamos el contador de parámetros (I).
26 - Si I es mayor de 1 salta a la línea 38.
28 - Iniciamos un bucle que identificará la instrucción a ensamblar.
30 – Se comparan los dos primeros caracteres de W$ con la lista de instrucciones aceptadas, y si coincide salta a 34.
32 – Si el bucle no ha llegado al final vuelve a la línea 28.
34 - Guardamos en (O) el número de instrucción que se ha encontrado.
36 - Saltar a la línea 14 para seguir procesando la línea de entrada.
38 - Iniciamos un bucle que identificará el registro usado.
40 - Comparamos el primer carácter de W$ con la lista de registros aceptados, y si coincide salta a la línea 44.
42 – Si el bucle no ha llegado al final vuelve a la línea 38.
44 - Si el contador de parámetros es igual a 2 guardamos el valor de (F) en la variable de registro (R).
46 - Si I es menor de 3 salta a la línea 14 para seguir procesando la línea de entrada.
48 - Si W$ está vacío se iguala la variable (F) a variable de registro (R).
49 – Simula un ON GOTO saltando a una línea múltiplo de 50 del número de instrucción correspondiente guardada en (O).
50 - Fórmula para calcular el código de la instrucción "LD". Se imprime el resultado.
52 - Volver al inicio del programa.
450 - Fórmula para calcular el código de "ADD", "ADC", "SUB", "SBC", "AND", "XOR", "OR" y "CP". Se imprime el resultado.
452 - Volver al inicio del programa.
550 - Fórmula para calcular el código "INC" y "DEC". Se imprime el resultado.
552 - Volver al inicio del programa.
700 - Fórmula para calcular el código "BIT", "RES" y "SET". Se imprime el resultado.
702 - Volver al inicio del programa.
800 - Fórmula para calcular el código "PUSH" y "POP". Se imprime el resultado.
802 - Volver al inicio del programa.
1000 - Fórmula para calcular el código "RL", "RR", "SLA" y "SRA". Se imprime el resultado.
9000 - Volver al inicio del programa.


EL PROGRAMA
listado.gif
listado.gif (4.77 KiB) Visto 3966 veces


APUNTES FINALES
Finalizado el proyecto del intérprete de FORTH en 1K, seguía teniendo en mente el programa “Trans-Compilador 1K” del número 30 de la revista “El Ordenador Personal” (página 135). Es un sencillo compilador que pasa de BASIC a CM, con muchas limitaciones. Satisfecho con el intérprete, quería llegar más lejos. Así que cogí una lista de mnemotécnicos del Z80 y la empecé a analizar. El resultado es este ensamblador.

Al analizar las listas se puede comprobar que, en general, hay unas secuencias y relaciones de códigos de instrucciones según los registros o instrucciones usados. Analizando cada grupo de instrucciones puedes encontrar una fórmula que genera el código correcto de una gran parte de los mnemotécnicos de una instrucción.


Metiendo un ensamblador en 626 bytes y 36 líneas de código BASIC
Una vez más ha sido un trabajo digno de un relojero suizo el conseguir hacer que funcione con las limitadas capacidades del ZX-81 básico. Y aquí ha estado la gracia.

Como siempre, lo primero ha sido introducir una línea con la que voy controlando la memoria que ocupa el programa:
9999 PRINT (PEEK VAL"16396"+VAL"256"*PEEK VAL"16397")-VAL"16509"
Esta línea ocupa 43 bytes, que ganaré al borrarla al finalizar el desarrollo del programa.

He usado los trucos habituales del ZX-81 para ahorrar memoria en el uso de valores numéricos. Así, "NOT PI" es 0, uso de VAL, y como el valor 1 se usa varias veces he asignado ese valor a la variable "U" mediante "SGN PI". He prescindido de CODE para dejar el programa más comprensible, aunque habría conseguido ahorrar unos 12 bytes.

La primera parte del programa ha consistido en hacer el procesador de la línea de entrada. Me he basado en el del intérprete de FORTH aunque en este caso lo he podido simplificar bastante.

La segunda parte ha consistido en identificar los distintos parámetros de la línea y asignarles un valor numérico. Primero para la instrucción, el segundo para el registro y el tercero para un registro o valor numérico.

Para la instrucción me limito a comparar las dos primeras letras del nombre. En una máquina con más memoria se debería ampliar esto porque en este caso me ha limitado el número de instrucciones a reconocer. Lo mismo pasa con el nombre del registro, ya que solo comparo la primera letra, y también limita el ensamblador. Pero con 1K no había otra opción.

La tercera parte empieza con el GOTO de la línea 49, que se encarga de saltar a una línea múltiplo de 50 en función del código de la instrucción. Afortunadamente el BASIC de los SINCLAIR permite esto, y simplifica mucho el código.

Las instrucciones se han numerado de la siguiente forma:
LD (1) - ADD (2) - ADC (3) - SUB (4) - SBC (5) - AND (6) - XOR (7) - OR (8) - CP (9) - INC (10)
DEC (11) - BIT (12) – RES (13) – SET (14) – PUSH (15) – POP (16) – RL (17) – RR (18) - SLA (19) y SRA (20)

Las instrucciones se han agrupado en 6 grupos según la fórmula a aplicar:
1) LD
2) ADD, ADC, SUB, SBC, AND, XOR, OR, CP
3) INC, DEC
4) BIT, RES, SET
5) PUSH, POP
6) RL, RR, SLA, SRA

Los registros se han numerado de la siguiente forma:
B (0) - C (1) - D (2) - E (3) - H (4) - L (5) – (HL) (6) y A (7)

Como el BASIC de los SINCLAIR permite saltar a una línea que no existe, he hecho que la fórmula este en la línea del identificador de instrucción más alto de cada grupo de instrucciones, multiplicado por 50. Así, la fórmula de LD está en la línea 50, la fórmula del grupo 2 (ADD, ADC, etc.) está en la línea 450 (CP = 9*50), etc. Y como no hay que almacenar nada vuelvo al principio del programa con un RUN al finalizar el proceso de ensamblado.

Esta versión del ensamblador es muy simple por una cuestión de memoria, pero el programa está estructurado para que cada instrucción tenga 50 números de línea a su disposición para introducir el código que haga falta para poder tratar los distintos mnemotécnicos de las instrucciones del Z80.


Buscando fórmulas
Analizando la tabla de la instrucción LD de transferencias de 8 bits se puede ver que los códigos están comprendidos entre 40h (64) y 79h (127).

Sin título-1.gif
Sin título-1.gif (15.77 KiB) Visto 3966 veces

Empieza en la columna “B” y acaba en la columna “A”, y cada fila que bajamos se incrementa en 8.A partir de la codificación de registros que he usado, con la fórmula: “64 + 8 * IDreg1 + IDreg2” de la línea 50 del programa podemos ensamblar fácilmente 63 de los 132 mnemotécnicos distintos de la instrucción LD
Para poder ensamblar el resto hace falta más código, aunque en general siempre siguen unos patrones definidos.


Analizando la tabla de las instrucciones “BIT”, “RES” y “SET” se puede ver que los códigos están comprendidos entre 40h (64) y FFh (255) con un CBh (203) delante.

Sin título-2.gif
Sin título-2.gif (46.42 KiB) Visto 3966 veces

Al igual que con la instrucción LD, empieza en la columna “B” y acaba en la columna “A”, y cada fila que bajamos se incrementa en 8.Con la fórmula: “64 * (IDinstruccion - 11) + IDbit * 8 + Idreg1” de la línea 700 del programa podemos ensamblar 192 de los 240 mnemotécnicos de estas instrucciones.

Este mismo criterio lo he seguido en otras tablas de instrucciones hasta conseguir ensamblar 375 de los 697 mnemotécnicos.


Para terminar
Me quedo con la ganas de seguir el proyecto en una máquina más rápida y con más memoria, porque con un poco más de código se puede conseguir ensamblar la mayor parte de los mnemotécnicos del Z80. También se podría incluir un editor para poder usarlo como un ensamblador más “profesional”.

Con todo, el ensamblado funciona perfectamente y es bastante rápido. Así que... Prueba superada ¡!!


Os invito a probarlo.

screen_2.gif
screen_2.gif (4.72 KiB) Visto 3966 veces

screen_3.gif
screen_3.gif (4.73 KiB) Visto 3966 veces
Buscando la IP de la W.O.P.R.

Avatar de Usuario
zitror
Amiga 2500
Amiga 2500
Mensajes: 5349
Registrado: 02 Jul 2006, 00:16
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
Ubicación: El interior de un Z80
Gracias dadas: 248 veces
Gracias recibidas: 104 veces
Contactar:

Re: K-Assembler para ZX-81

Mensajepor zitror » 03 Abr 2014, 22:49

Impecable =D>

Al Twitter de ZDP de cabeza.

Salu2 ;)
(C) 1.982 Sinclair Research Ltd

La buhardilla de Zitror

Avatar de Usuario
bitvision
Dragon 32
Dragon 32
Mensajes: 23
Registrado: 15 Mar 2014, 02:21
Sistema Favorito: MSX
primer_sistema: MSX
consola_favorita: Nintendo SNES
Primera consola: Nintendo SNES
Ubicación: Farnborough, Hampshire, UK
Gracias recibidas: 1 vez

Re: K-Assembler para ZX-81

Mensajepor bitvision » 04 Abr 2014, 00:11

Peazo curro te has metido y menudo post.


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados