Un compilador de ZX Spectrum BASIC
Moderador: Sir Cilve Sinclair
- na_th_an
- Nonamed
- Mensajes: 1889
- Registrado: Lun May 07, 2007 10:16 am
- Ubicación: Andalucía
Re: Un compilador de ZX Spectrum BASIC
Los gráficos, pues con el maravilloso Deluxe Paint y muuucha paciencia
Por cierto, mucha suerte con el tema del doctorado. Has elegido una materia muy bonita
Por cierto, mucha suerte con el tema del doctorado. Has elegido una materia muy bonita
- Rafa
- Jack The Nipper
- Mensajes: 181
- Registrado: Lun May 07, 2007 11:59 am
Re: Un compilador de ZX Spectrum BASIC
Cuando yo entré en este hilo, en ningún momento se había hablado ni de compiladores cruzados, ni de lenguajes nuevos, ni nada por el estilo.
Pensé que se refería a un Basic que corriera en un Spectrum normal y con programas escritos en Sinclair Basic. Ese fue mi error.
Pero el rodillo ha pasado por encima de mí como si de una inquisición se tratase... ¡¡ Viva el totalitarismo !!
¡ Si es que no se puede pensar diferente a los demás !... ¡ Quién me manda !
Algún día terminaré mi proyecto (espero más opiniones que en el hilo que existe sobre Los Menús de los Spectrum de Amstrad para todos los modelos)
Pensé que se refería a un Basic que corriera en un Spectrum normal y con programas escritos en Sinclair Basic. Ese fue mi error.
Pero el rodillo ha pasado por encima de mí como si de una inquisición se tratase... ¡¡ Viva el totalitarismo !!
¡ Si es que no se puede pensar diferente a los demás !... ¡ Quién me manda !
Algún día terminaré mi proyecto (espero más opiniones que en el hilo que existe sobre Los Menús de los Spectrum de Amstrad para todos los modelos)
RANDOMIZE USR 0
-
- Sabreman
- Mensajes: 351
- Registrado: Lun May 28, 2007 9:55 am
- Ubicación: Tenerife
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
Rafa escribió:Cuando yo entré en este hilo, en ningún momento se había hablado ni de compiladores cruzados, ni de lenguajes nuevos, ni nada por el estilo.
Pensé que se refería a un Basic que corriera en un Spectrum normal y con programas escritos en Sinclair Basic. Ese fue mi error.
Cualquier aportación es buena, incluida la tuya. En el primer mensaje que puse dejaba entrever que se trataba de un compilador cruzado: Una herramienta hecha en python (luego se puede convertir a .exe, pero eso es otra historia), que funciona en un PC bajo Windows, Linux y sobre otras muchas plataformas que tengan el intérprete de Python instalado. Por otra parte, compiladores de BASIC de ZX Spectrum ya exiten (el propio de HiSoft)
Por otra parte, estamos hablando de compilación, no de intérprete de BASIC. Algunas de las ideas que tú has expuesto, son interesantes, pero sólo se aplican a intérpretes, y no a compiladores. El programa que se almacena en memoria, nunca será BASIC sino código máquina directo. Se trata de un traductor (en el PC) de BASIC (o un dialecto del mismo) del ZX a ASM para Z80 que corra en el Spectrum.
Por ejemplo: La expresión (3 + 5) / 2, la tendrías que interpretar como tú has expuesto previamente. Pero para un compilador, esa expresión siempre es constante, y se reduce directamente a 4 (lo que significa que en tiempo de ejecución nunca se harán los cálculos de suma y división). Y siempre será así.
Para variables, la expresión 2 * (3 + x) se puede traducir (si x es una variable de tipo byte) como:
Código: Seleccionar todo
LD a, (0xFEFF) ; 0xFEFF es la dirección de memoria donde se almacena X
ADD a, 3
SLR a
Que, desde luego, es mucho más eficiente que operarlo todo en punto f*llante (que es como lo llamo a veces). El punto flotante está muy bien para operaciones matemáticas precisas (sobre todo en ámbito científico), y también se contempla. Pero poder declarar, por ejemplo, que algunas variables siempre serán enteras (las operaciones no enteras se redondean por truncamiento decimal, generalmente) es mucho más eficiente.
Si te fijas, el orden de las operaciones (debido a los paréntesis) ya ha sido ordenado previamente, en la fase de compilación (antes de generar la salida ASM), y nunca más se tiene que hacer ningún tipo de análisis de sintaxis ni precedencia. Ahí es donde se ahorra tiempo. Con un intérprete, siempre que entremos en una linea BASIC se hace una comprobación sintáctica.
En cualquier caso, las opiniones, sugerencias e ideas de todo el mundo son interesantes (lo que incluye a las tuyas).
Rafa escribió:Algún día terminaré mi proyecto (espero más opiniones que en el hilo que existe sobre Los Menús de los Spectrum de Amstrad para todos los modelos)
Le echaré un vistazo. Lo cierto es que apenas he mirado el foro (siempre estaba en el grupo de noticias de usenet).
-
- Nonamed
- Mensajes: 1067
- Registrado: Lun May 07, 2007 10:06 pm
Re: Un compilador de ZX Spectrum BASIC
De la gente que va a usar este compilador, caso de que llegue a terminarse, me parece que los números reales (coma flotante) van a usarse de tarde en tarde, si es que alguna vez se usan. Yo no me preocuparía mucho por ello. En todo caso intentaría escaquearlo y pasarlo al calculador de la ROM de alguna forma, sin importar que sea lento, porque ya te digo que de los posibles usuarios de este compilador (no nos vamos a engañar, cuatro gatos) diría que todos lo usaran para juegos y no van a usar operaciones en coma flotante en la vida.
Un saludo,
Gandulf
Gandulf
- Rafa
- Jack The Nipper
- Mensajes: 181
- Registrado: Lun May 07, 2007 11:59 am
Re: Un compilador de ZX Spectrum BASIC
OK. Yo nunca he hablado de intérprete y considero un compilador de basic como una herramienta que traduce un programa basic a C.M. para que sea más rápido, y ahí es donde se pueden añadir nuevas sentencias y funciones.
Cuando digo traducir, no considero que haya que hacer ninguna comprobación sintáctica. El código generado se queda como está, una sola vez. Y al ser el código generado C.M., POR SUPUESTO que desaparecen los números de línea. Comparto 100 % tu idea del 2*(3+5) y con variables, pero lo dificil es decirle al programa:vete primero a los paréntesis, haz el cálculo y luego lo multiplicas por dos. Luego hay líneas que se complican:
10 LET A=(INT(RND*49)+1)*6 o
20 PRINT AT (N*3)+8, S-(I=1);"ODIO EL LENGUAJE C"
Si, en mi programa, soy capaz de traducir esto, lo más dificil está hecho.
Cuando digo traducir, no considero que haya que hacer ninguna comprobación sintáctica. El código generado se queda como está, una sola vez. Y al ser el código generado C.M., POR SUPUESTO que desaparecen los números de línea. Comparto 100 % tu idea del 2*(3+5) y con variables, pero lo dificil es decirle al programa:vete primero a los paréntesis, haz el cálculo y luego lo multiplicas por dos. Luego hay líneas que se complican:
10 LET A=(INT(RND*49)+1)*6 o
20 PRINT AT (N*3)+8, S-(I=1);"ODIO EL LENGUAJE C"
Si, en mi programa, soy capaz de traducir esto, lo más dificil está hecho.
RANDOMIZE USR 0
-
- Sabreman
- Mensajes: 351
- Registrado: Lun May 28, 2007 9:55 am
- Ubicación: Tenerife
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
Rafa escribió: [...]
Cuando digo traducir, no considero que haya que hacer ninguna comprobación sintáctica. El código generado se queda como está, una sola vez. Y al ser el código generado C.M., POR SUPUESTO que desaparecen los números de línea. Comparto 100 % tu idea del 2*(3+5) y con variables,
pero lo dificil es decirle al programa:vete primero a los paréntesis, haz el cálculo y luego lo multiplicas por dos.
Eso es lo que hace mi programa precisamente. Para parsear (analizar sintácticamente) una expresión matemática, se definen unas reglas gramaticales (esto es muy largo de poner aquí). Mi herramienta lo que hace es que, al definirle la gramática del BASIC (por ej. de ZX), sabe qué pasos tiene que seguir para leer esas expresiones. Para ello utiliza una pila (stack) y otras estructuras (un array de salida), donde guarda la información y la reordena de forma que sea correcta (como en el ejemplo que te puse).
Rafa escribió:Luego hay líneas que se complican:Código: Seleccionar todo
10 LET A=(INT(RND*49)+1)*6 o
20 PRINT AT (N*3)+8, S-(I=1);"ODIO EL LENGUAJE C"
Si, en mi programa, soy capaz de traducir esto, lo más dificil está hecho.
Eso ya lo entiende mi programa, por ejemplo. La cuestión que se debatió más arriba es que método de traducción es el más adecuado, puesto que se trata de un programa compilado. Por ponerlo de forma corta, para la línea 10, la expresión después del '=', produciría un esquema de traducción como este:
'(INT(RND*49)+1)*6'
1 Traducir RND (lo mete en el stack)
2 Traducir 49 (lo mete en el stack)
3 Traducir "*" (sacaría y multiplicaría los dos valores anteriores, por ej. en una calculadora de STACK, y dejaría el resultado en el stack )
4 Traducir INT (redondearía el valor del STACK)
5 Traducir 1 (lo mete en el stack)
6 Traducir '+' (Sacaría y sumaría los dos ultimos valores del stack y dejaría el resultado en el mismo)
7 Traducir 6 (mete 6 en el stack)
8 Traducir '*' (hace como en el paso 3)
La herramienta 'sabe' (porque conoce la gramática) que tiene que empezar por los paréntesis interiores, y luego ir hacia atrás. Hacer esto como tu lo planteas (y que es como lo hace el intérprete de BASIC de la ROM) es tedioso, difícil y lento para el ordenador.
Respecto a la pregunta que planteas, se sale un poco del tema aquí, ya que sería hablar de analizadores léxicos y sintácticos. Quizá podríamos hablar de eso en otro lado. En cualquier caso, analizar sintácticamente es costoso tanto en ejecución, como hacerlo a mano. Es un programa complejo (por eso me hice la herramienta). Es encomiable que la ROM del ZX lo haga (se nota que fue hecho a mano), pero también es verdad que el BASIC, por su sencillez lo permite. Hacer un analizador sintáctico de, por ejemplo, C de la misma manera que la ROM del ZX sería una locura.
-
- Sabreman
- Mensajes: 351
- Registrado: Lun May 28, 2007 9:55 am
- Ubicación: Tenerife
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
Gandulf escribió:De la gente que va a usar este compilador, caso de que llegue a terminarse, me parece que los números reales (coma flotante) van a usarse de tarde en tarde, si es que alguna vez se usan. Yo no me preocuparía mucho por ello. En todo caso intentaría escaquearlo y pasarlo al calculador de la ROM de alguna forma, sin importar que sea lento, porque ya te digo que de los posibles usuarios de este compilador (no nos vamos a engañar, cuatro gatos) diría que todos lo usaran para juegos y no van a usar operaciones en coma flotante en la vida.
Totalmente de acuerdo. Es más, ya he estado experimentando con rutinas de punto fijo de 32 bits (16 para la parte entera, 16 para la parte decimal). Me ha sorprendido saber que la PSX, gameboy y otras lo usan para dibujar gráficos a gran velocidad, y seguramente era un truco que usaban muchos programadores de ZX en aquella época y que no conocíamos. Con 32 bits de punto fijo, se pueden expresar números negativos y positivos con precisión decente para juegos. Usando el 1er bit para signo, tenemos un rango de: -32768 a 32767 en pasos de 1/65536 (.0000152587), que como se ve, son 4 decimales de precisión, aproximadamente. Es más, es relativamente sencillo de programar, e incluso se podría generalizar a precisión infinita (variable), si se quisiera. Además, he encontrado algoritmos de seno y coseno para punto fijo que usan sólo sumas, restas y desplazamientos.
Si alguien tiene python y quiere probar con punto fijo, me he hecho un programa de prueba, que muestra los resultados de algunas operaciones.
El programa tiene un fallo. El número negativo del final no sale en complemento a 2. Y eso es una duda que tengo: ¿Al hacer una resta binaria, el ZX hace automáticamente la conversión a C2? Si alguien me puede explicar un poco (ya he estado leyendo sobre Complemento a 2, y el NEG del Z80). Lo que no sé, por ejemplo, es si al hacer una resta binaria y dar resultado negativo, el numero ya está en C2 o no, etc.
- na_th_an
- Nonamed
- Mensajes: 1889
- Registrado: Lun May 07, 2007 10:16 am
- Ubicación: Andalucía
Re: Un compilador de ZX Spectrum BASIC
Exacto, la parte de la CPU de la PSX que se encargaba de hacer la transformación de texturas empleaba punto fijo por motivos de eficiencia (por eso ocurría el famoso "warping" de las texturas de los juegos de esta consola). Para juegos tiene mil aplicaciones. Yo lo suelo emplear mucho porque obtienes movimientos muy suaves (pudiendo emplear ecuaciones de movimiento normales y corrientes) sin perder demasiado tiempo.
-
- Nonamed
- Mensajes: 1221
- Registrado: Mar Abr 17, 2007 12:35 pm
- Ubicación: Valencia
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
na_th_an escribió:Exacto, la parte de la CPU de la PSX que se encargaba de hacer la transformación de texturas empleaba punto fijo por motivos de eficiencia (por eso ocurría el famoso "warping" de las texturas de los juegos de esta consola).
Cosa que, con los juegos 2D del Spectrum (y los 3D que se puedan hacer), no tiene la más mínima relevancia...
Sobre el hilo, me alegro de que Boriel mire "hacia adelante" y su propósito sea el crear un BASIC "como el del Spectrum, pero mejor". Porque para crear un BASIC como el del Spectrum, y atarnos a las mismas limitaciones, ya tenemos el MCODER o el HISOFT.
Además, haciendo eso no está cerrándose a nada, sólo está sacando adelante el subconjunto de operaciones BASIC más útil para los juegos ... nada le impide después ir agregando esas instrucciones que ha dejado atrás, si alguien encuentra que necesita alguna de ellas para usar el programa.
Eso le permitirá sacar algo usable ANTES, y extenderlo después si fuera necesario, en lugar de tardar más en hacer algo que ya tenemos con los compiladores que había en el Spectrum hace 20 años...
NoP / Compiler
- na_th_an
- Nonamed
- Mensajes: 1889
- Registrado: Lun May 07, 2007 10:16 am
- Ubicación: Andalucía
Re: Un compilador de ZX Spectrum BASIC
Exacto, no afecta para nada a juegos 2D. Phantomasa 2 por ejemplo usa punto fijo en todas las coordenadas de los sprites, y así puedo conseguir esos movimientos en curvas. Y no se nota que la precisión sea relativamente baja (1/64 de precisión estoy usando) por la "baja" resolución del Spectrum.
¡FIXED es el futuro!
¡FIXED es el futuro!
-
- Sabreman
- Mensajes: 351
- Registrado: Lun May 28, 2007 9:55 am
- Ubicación: Tenerife
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
Bueno, he estado pensando (raro en mí, por otra parte, dicen... ) una forma de programar subrutinas en básic, con variables en ámbito local. El caso es que, en el PC, el esquema típico de llamadas en un compilador C es algo así (Nota: MOV es el equivalente al LD del Z80):
LLAMADOR:
Y el código de la subrutina LLAMADA suele ser:
Ejemplos de este código se pueden ver aquí. La desventaja del esquema de llamada de C es que es el llamador el que siempre tiene que quitar los parámetros que puso del Stack. La ventaja es que permite número variables de parámetros (el llamador sabe cuántos parámetros metió en la pila antes de la llamada). Por contra, en PASCAL es siempre el llamado el que quita los parámetros de la pila y coloca allí el resultado. Este esquema es más eficiente (en tiempo y en espacio), pero no permite parámetros variables (siempre hay trucos). En cualquier caso, el ahorro de memoria es un plus, si tenemos en cuenta lo escasa que es en el ZX.
Había pensado algo así para Z80. Es obvio que "bp" se puede simular con IX. Y tenemos algo como:
SUBRUTINA LLAMADA (CALLEE)
Los parámetros se referencian con IX+n, las variables declaradas locales, con IX-n. El problema es que no podríamos declarar muchas, y dependería del tipo (nunca he hecho funciones de más de 10 parámetros, pero nunca se sabe). Los registros hl y de se pierden. El llamador tiene que haberlos guardado previamente si los necesita. Otra opción es ver el código ASM que genera le compilador de C del z80. ¿Bueno, qué pensáis?
Otros trozos de código: El punto fijo (16bit.16bit) que creo que ya lo tengo, y algún que otro más:
¿Sería interesante pasar del "print" de la ROM o no? Había pensado que, de ser así, no habría "channels" ni nada. Todo va pantalla (24 filas x 32 columnas -segun recuerdo- y punto). De resto se usaría AT, y los colores, usando las mismas variables que la ROM: DF CC o S POSN (creo recordar que es la posición en pantalla, pero no se cuál de ellas), así como ATTR T y P. Por lo visto, debido a la versatilidad de los canales, estas rutinas son bastante lentas (es relativamente sencillo hacer un print de un caracter). De hecho hay algún listado por ahí de MicroHobby con algun "procesador de pantalla".
LLAMADOR:
Código: Seleccionar todo
push <param 1>
push <param 2>
...
push <param n>
call Function:
pop <param n> |
... | ; O bien incrementa el stack N posiciones
pop <param 1> |
Y el código de la subrutina LLAMADA suele ser:
Código: Seleccionar todo
:Function
push bp
mov bp, sp
mov dx, (bp + 4) ; Operacion con el parametro 2, por ejemplo
...
pop bp ; fin de subrutina
ret
Ejemplos de este código se pueden ver aquí. La desventaja del esquema de llamada de C es que es el llamador el que siempre tiene que quitar los parámetros que puso del Stack. La ventaja es que permite número variables de parámetros (el llamador sabe cuántos parámetros metió en la pila antes de la llamada). Por contra, en PASCAL es siempre el llamado el que quita los parámetros de la pila y coloca allí el resultado. Este esquema es más eficiente (en tiempo y en espacio), pero no permite parámetros variables (siempre hay trucos). En cualquier caso, el ahorro de memoria es un plus, si tenemos en cuenta lo escasa que es en el ZX.
Había pensado algo así para Z80. Es obvio que "bp" se puede simular con IX. Y tenemos algo como:
SUBRUTINA LLAMADA (CALLEE)
Código: Seleccionar todo
:Funcion
push ix
ld ix, 0
add ix, sp ; "ld ix, sp"
ld d, (ix + 4) ; operación con el parámetro 2, por ejemplo
...
pop ix ; Comienzo del código de retorno
ex (sp), hl ; HL es la dirección de retorno
ex hl, de ; La guardamos en DE
ld hl, XX + 2 ; XX es el numero de bytes que se metió en la pila
add hl, sp
ld sp, hl ; hemos hecho SP = SP + XX + 2
ex hl, de
jp (hl) ; "Ret"
Los parámetros se referencian con IX+n, las variables declaradas locales, con IX-n. El problema es que no podríamos declarar muchas, y dependería del tipo (nunca he hecho funciones de más de 10 parámetros, pero nunca se sabe). Los registros hl y de se pierden. El llamador tiene que haberlos guardado previamente si los necesita. Otra opción es ver el código ASM que genera le compilador de C del z80. ¿Bueno, qué pensáis?
Otros trozos de código: El punto fijo (16bit.16bit) que creo que ya lo tengo, y algún que otro más:
¿Sería interesante pasar del "print" de la ROM o no? Había pensado que, de ser así, no habría "channels" ni nada. Todo va pantalla (24 filas x 32 columnas -segun recuerdo- y punto). De resto se usaría AT, y los colores, usando las mismas variables que la ROM: DF CC o S POSN (creo recordar que es la posición en pantalla, pero no se cuál de ellas), así como ATTR T y P. Por lo visto, debido a la versatilidad de los canales, estas rutinas son bastante lentas (es relativamente sencillo hacer un print de un caracter). De hecho hay algún listado por ahí de MicroHobby con algun "procesador de pantalla".
- na_th_an
- Nonamed
- Mensajes: 1889
- Registrado: Lun May 07, 2007 10:16 am
- Ubicación: Andalucía
Re: Un compilador de ZX Spectrum BASIC
Sobre las subrutinas, y que yo sepa, los compiladores de BASIC que soportan SUBs y FUNCTIONs emplean exactamente el mismo paradigma que se emplea en PASCAL. Opino que, por tradición (y coherencia), debería usarse ese método. Si estamos más o menos de acuerdo en que vamos a orientar el tema a juegos, creo que no es necesario dotar de facilidades para incluir un número de parámetros variable (al menos, ningún dialecto de BASIC que yo conozca lo permite sin artificios del tipo pasar el puntero a una estructura).
Por eso opino que deberías pasar del PRINT de la rom y de los canales. A fin de cuentas, el tema de los canales no tiene demasiada aplicación para hacer juegos. Además, podría mejorarse de forma que PRINT pudiese imprimir en cualquiera de las 24 filas sin tener que hacer de forma explícita la orientación al canal de pantalla superior (por defecto) o al de pantalla inferior (PRINT #0;). Con soportar los AT y todos los atributos de color y mezcla (OVER), y los códigos de control embebidos en las cadenas, creo que es suficiente.
A colación, creo que el compilador debería ser capaz de entender secuencias de escape para representar a esos códigos de contro embebidos y ya de paso a los carácteres gráficos. Si recuerdas, el set de carácteres del Speccy contiene códigos de control para especificar posición o color, o para hacer desplazamientos en el rango de códigos ASCII 0-31, y además tenemos que considerar los GDU y los gráficos de bloques. Propongo la siguiente sintaxis:
\XXX, con XXX un número de 0 a 255, representa a CHR$ XXX.
[XY], con X e Y pudiendo valer ., ', :, o espacio, para representar a los bloques gráficos (por ejemplo: [ ] [ '] [.'] [::] [:.],...)
[A], con A un carácter de la A a la U para representar a los GDU ([A][B][C]...).
{COMAND}, sería un atajo por si no queremos acordarnos de los códigos de los comandos de color (PAPER, INK ...) o posición (AT).
{N}, con N un número de 0 a 9, para ser usado en conjunción con el otro.
El compilador debería entender estas secuencias y codificarlas en el binario con su código ASCII correspondiente. Por ejemplo, debería poder traducir la cadena a códigos del set de carácteres del Spectrum. Y la rutina impresora, debería entenderlos y hacer los cambios de color, posición, etcétera de acuerdo a lo que va leyendo de la cadena.
Además no hay que olvidar que el set de carácteres hay que buscarlo en PEEK(23606)+256*PEEK(23607)+256 y que los UDGs hay que buscarlos en PEEK(23675)+256*PEEK(23676).
Parecen muchas cosas, pero sólo quitando el tema de los canales y la comprobación de SCROLL? ya estamos ganando muchísimo tiempo.
Por eso opino que deberías pasar del PRINT de la rom y de los canales. A fin de cuentas, el tema de los canales no tiene demasiada aplicación para hacer juegos. Además, podría mejorarse de forma que PRINT pudiese imprimir en cualquiera de las 24 filas sin tener que hacer de forma explícita la orientación al canal de pantalla superior (por defecto) o al de pantalla inferior (PRINT #0;). Con soportar los AT y todos los atributos de color y mezcla (OVER), y los códigos de control embebidos en las cadenas, creo que es suficiente.
A colación, creo que el compilador debería ser capaz de entender secuencias de escape para representar a esos códigos de contro embebidos y ya de paso a los carácteres gráficos. Si recuerdas, el set de carácteres del Speccy contiene códigos de control para especificar posición o color, o para hacer desplazamientos en el rango de códigos ASCII 0-31, y además tenemos que considerar los GDU y los gráficos de bloques. Propongo la siguiente sintaxis:
\XXX, con XXX un número de 0 a 255, representa a CHR$ XXX.
[XY], con X e Y pudiendo valer ., ', :, o espacio, para representar a los bloques gráficos (por ejemplo: [ ] [ '] [.'] [::] [:.],...)
[A], con A un carácter de la A a la U para representar a los GDU ([A][B][C]...).
{COMAND}, sería un atajo por si no queremos acordarnos de los códigos de los comandos de color (PAPER, INK ...) o posición (AT).
{N}, con N un número de 0 a 9, para ser usado en conjunción con el otro.
El compilador debería entender estas secuencias y codificarlas en el binario con su código ASCII correspondiente. Por ejemplo, debería poder traducir la cadena
Código: Seleccionar todo
"{PAPER}{1}{INK}{6}[..][..][.:][::][::][:']['']['']"
Además no hay que olvidar que el set de carácteres hay que buscarlo en PEEK(23606)+256*PEEK(23607)+256 y que los UDGs hay que buscarlos en PEEK(23675)+256*PEEK(23676).
Parecen muchas cosas, pero sólo quitando el tema de los canales y la comprobación de SCROLL? ya estamos ganando muchísimo tiempo.
-
- Sabreman
- Mensajes: 351
- Registrado: Lun May 28, 2007 9:55 am
- Ubicación: Tenerife
- Contactar:
La base, lo primero
Bueno, antes de empezar a hacer cosas más bestias, vayamos a lo más básico.
Tengo que construirme una serie de rutinas básicas antes de hacer lo demás. Esas rutinas, evidentemente, están en ASM. No conozco mucho del ASM Z80 (bueno, hice mis tonterías de pequeño, con las MicroHobby ). Así que si alguien me puede ayudar con algunas rutinas, se lo agradecería (son sencillas).
Aquí va la primera:
RUTINA que hace un NEG (complemento a 2) de un número de 32 bits apuntado por HL:
El contenido de los registros AF y AF' quedan alterado tras llamar a esta rutina.
Esta rutina es interesante para trabajar con números negativos. Los enteros de 32 bits y Punto Fijo de 32 bits se niegan de la misma manera. Así que sirve para todas ellas. Lo que hace es hallar el Complemento a 2 de la dirección de memoria apuntada por HL (los siguientes 4 bytes). Si alguien cree que se puede mejorar, pues se lo agradecería.
Otra opción es hacerlo directamente sobre los registros (se supone que es más rápido). Por ejemplo, negar el numero de 32 bits formado por HL HL' o negar HL DE. Pero no sé si se puede hacer, ni si será más eficiente.
ACTUALIZACIÓN: El archivo asm se puede ver aquí
Tengo que construirme una serie de rutinas básicas antes de hacer lo demás. Esas rutinas, evidentemente, están en ASM. No conozco mucho del ASM Z80 (bueno, hice mis tonterías de pequeño, con las MicroHobby ). Así que si alguien me puede ayudar con algunas rutinas, se lo agradecería (son sencillas).
Aquí va la primera:
RUTINA que hace un NEG (complemento a 2) de un número de 32 bits apuntado por HL:
El contenido de los registros AF y AF' quedan alterado tras llamar a esta rutina.
Código: Seleccionar todo
:NEGATE_HL ; Negates 32 bit value pointed by HL, +2, +3, +4
push hl ; Saves HL and BC
pusb bc
ld b, 4 ; Repeats 4 times
scf ; CF = 1
:C2LOOP ;
ex af, af' ; saves Carry Flag
ld a, (hl)
xor FFh ; A <- Inverted bit values at (HL)
ld c, a ; Saves A in C
ex af, af' ; Restores Carry Flag
ld a, c ; Restores A
adc a, 0 ; Adds Carry Flag
ld (hl), a ; Saves value to memory
inc hl ; Points HL to next location
djnz C2LOOP ; Repeat until ZERO
pop bc ; Restores BC and HL
pop hl
ret
Esta rutina es interesante para trabajar con números negativos. Los enteros de 32 bits y Punto Fijo de 32 bits se niegan de la misma manera. Así que sirve para todas ellas. Lo que hace es hallar el Complemento a 2 de la dirección de memoria apuntada por HL (los siguientes 4 bytes). Si alguien cree que se puede mejorar, pues se lo agradecería.
Otra opción es hacerlo directamente sobre los registros (se supone que es más rápido). Por ejemplo, negar el numero de 32 bits formado por HL HL' o negar HL DE. Pero no sé si se puede hacer, ni si será más eficiente.
ACTUALIZACIÓN: El archivo asm se puede ver aquí
Última edición por Boriel el Mar Feb 05, 2008 8:35 pm, editado 3 veces en total.
-
- Nonamed
- Mensajes: 1221
- Registrado: Mar Abr 17, 2007 12:35 pm
- Ubicación: Valencia
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
Boriel escribió:Bueno, he estado pensando (raro en mí, por otra parte, dicen... ) una forma de programar subrutinas en básic, con variables en ámbito local.
(...)
Había pensado algo así para Z80.
Hombre, es lo que se hace en el compilador Z88DK ... voy a pegar un ejemplo con varios tipos de parámetros:
Código: Seleccionar todo
//----------------------------------------------------------------------------
void Funcion1( char dato1 )
{
#asm
ld hl, 2
add hl, sp
ld a, (hl) ; A = dato1
(resto funcion)
#endasm
}
//----------------------------------------------------------------------------
void Funcion( char *puntero, int entero, char dato_a, char dato_b )
{
#asm
ld hl, 2
add hl, sp
ld a, (hl) ; a = dato_b
inc hl ; ignoramos parte alta del byte
inc hl
ld c, (hl) ; c = dato_a
inc hl ; ignoramos parte alta del byte
inc hl
ex af, af ; save A (attr) for later
ld e, (hl)
inc hl
ld d, (hl)
inc hl ; DE = entero
ld (meloguardo), de
ld e, (hl)
inc hl
ld d, (hl)
inc hl ; DE = puntero
(Aqui la funcion)
ret
.meloguardo defw 0
#endasm
}
Más o menos es lo que quieres hacer, ¿no?
Para las llamadas, sólo tendrías que pulsar en la pila los parámetros en orden inverso, y ya está. Los punteros no son más que ints 0-65535 referenciando a una posición de memoria, y los chars (aunque en tu basic yo no pondría chars, sólo ints), solo 16 bits con 0 en el byte alto y el valor en el bajo...
saludos.
PD: Recuerda popear lo que pushees
NoP / Compiler
-
- Sabreman
- Mensajes: 351
- Registrado: Lun May 28, 2007 9:55 am
- Ubicación: Tenerife
- Contactar:
Re: Un compilador de ZX Spectrum BASIC
sromero escribió: Hombre, es lo que se hace en el compilador Z88DK ... voy a pegar un ejemplo con varios tipos de parámetros:Código: Seleccionar todo
//----------------------------------------------------------------------------
void Funcion1( char dato1 )
{
#asm
ld hl, 2
add hl, sp
ld a, (hl) ; A = dato1
(resto funcion)
#endasm
}
...
O sea que usan HL. ¿Es eso más rápido que IX+n?
Por ejemplo, para 2 ó 3 parámetros:
Código: Seleccionar todo
ld a, (ix + 0)
ld c, (ix + 2)
ld de, (ix + 4) ; ¿ Esto existe?
Sé que las instrucciones con IX son más largas y más lentas. Si el esquema que has puesto es más eficiente, entonces quizá sea mejor así. Así que lo tendremos en cuenta.
sromero escribió: Más o menos es lo que quieres hacer, ¿no?
Para las llamadas, sólo tendrías que pulsar en la pila los parámetros en orden inverso, y ya está. Los punteros no son más que ints 0-65535 referenciando a una posición de memoria, y los chars (aunque en tu basic yo no pondría chars, sólo ints), solo 16 bits con 0 en el byte alto y el valor en el bajo...
saludos.
PD: Recuerda popear lo que pushees
Veo que concidimos en todo, al menos na_th, tú yo. Respecto a devolver el STACK a su estado original, si uso la forma PASCAL, lo que hago es (según el código que he puesto anteriormente), poner en HL el valor de la dirección de retorno retorno (ex (sp), hl), e incrementar el STACK tantas posiciones como bytes ha metido el llamador. Finalmente hago jp (hl) en vez de ret, y se queda todo como estaba. De esa forma la rutina es la que puede sacar los parámetros del STACK, e incluso puede devolver algun valor de retorno.
Para valores de retorno, una opción es devolverlo en una zona de memoria de 32 bits (como las variables de la ROM). Esto permite devolver punteros (16 bits más bajos), numeros enteros o punto fijo.
¿Quién está conectado?
Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 16 invitados