Programar extensiones para el BASIC
Moderador: Sir Cilve Sinclair
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Programar extensiones para el BASIC
¿Conocéis algún libro (escaneado), tutorial, web, etc. que enseñe cómo escribir extensiones al BASIC del Spectrum? Es decir, cómo hacer para poder escribir extensiones que permitan escribir comandos BASIC "extendidos" tales como LOAD %"programa" o cosas así.
Sé que todo comienza por trapear la RST 8, lo que implica usar una ROM alternativa que se mapee cuando ocurra esto. ¿Y después? He leído hace tiempo sobre usar ciertas rutinas de la ROM para ir parseando la línea de comandos, meter en pila los valores según sean numéricos, alfanuméricos, etc. pero lo tengo todo muy difuso y es por lo que estoy buscando esta información.
También sé que se usa el área de canales, para que cuando se hace OPEN # se asigna un nuevo canal, y con él, las direcciones de lectura y escritura para ese canal, pero no sé qué más hace falta para poder usarlos. Es decir, no sé qué argumentos se espera que recojan esas rutinas de lectura/escritura y qué deben devolver.
Gracias
Sé que todo comienza por trapear la RST 8, lo que implica usar una ROM alternativa que se mapee cuando ocurra esto. ¿Y después? He leído hace tiempo sobre usar ciertas rutinas de la ROM para ir parseando la línea de comandos, meter en pila los valores según sean numéricos, alfanuméricos, etc. pero lo tengo todo muy difuso y es por lo que estoy buscando esta información.
También sé que se usa el área de canales, para que cuando se hace OPEN # se asigna un nuevo canal, y con él, las direcciones de lectura y escritura para ese canal, pero no sé qué más hace falta para poder usarlos. Es decir, no sé qué argumentos se espera que recojan esas rutinas de lectura/escritura y qué deben devolver.
Gracias
Web: ZX Projects | Twitter: @zxprojects
- na_th_an
- Nonamed
- Mensajes: 1889
- Registrado: Lun May 07, 2007 10:16 am
- Ubicación: Andalucía
Re: Programar extensiones para el BASIC
Mira esta página y las siguientes: http://microhobby.speccy.cz/mhf/MHEs4/mhes4_45.jpg
Aquí se proponen comandos para extender el BASIC, y además se explica cómo se añaden.
Aquí se proponen comandos para extender el BASIC, y además se explica cómo se añaden.
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
- Rafa
- Jack The Nipper
- Mensajes: 181
- Registrado: Lun May 07, 2007 11:59 am
Re: Programar extensiones para el BASIC
Esto está bien, pero veo más fácil hacer esto:
100 RANDOMIZE USR 64000: REM &MOVESPRITE(10,0)
La rutina ubicada en 64000 leería qué instrucción hay detrás del REM, y saltar a la correspondiente dirección donde estaría ubicada la rutina correspondiente. Además como los números y/o cadenas se almacenan detrás de un REM como modo texto, no haría falta usar el calculador de la ROM, ni números en coma flotante. Esto yo lo veo más rápido y valdría para los Spectrums originales.
La información de referencia para saber cómo "incrustar" nuevos comandos utilizando el editor de la ROM en "la Enciclopedia" del Spectrum está en el libro "The Complete Rom Dissassembly". Es increíble las virguerías que hizo tio Clive para meter todo el sistema operativo del Spectrum en sólo 16K, para ahorrar costes. Pero vamos, todo se basa en el uso del Stack y saber exactamente cúal es el último valor introducido en el stack.
Están los canales, el calculador de la ROM (lento y lioso), la configuración de pantalla, ...
100 RANDOMIZE USR 64000: REM &MOVESPRITE(10,0)
La rutina ubicada en 64000 leería qué instrucción hay detrás del REM, y saltar a la correspondiente dirección donde estaría ubicada la rutina correspondiente. Además como los números y/o cadenas se almacenan detrás de un REM como modo texto, no haría falta usar el calculador de la ROM, ni números en coma flotante. Esto yo lo veo más rápido y valdría para los Spectrums originales.
La información de referencia para saber cómo "incrustar" nuevos comandos utilizando el editor de la ROM en "la Enciclopedia" del Spectrum está en el libro "The Complete Rom Dissassembly". Es increíble las virguerías que hizo tio Clive para meter todo el sistema operativo del Spectrum en sólo 16K, para ahorrar costes. Pero vamos, todo se basa en el uso del Stack y saber exactamente cúal es el último valor introducido en el stack.
Están los canales, el calculador de la ROM (lento y lioso), la configuración de pantalla, ...
RANDOMIZE USR 0
-
- Nonamed
- Mensajes: 1067
- Registrado: Lun May 07, 2007 10:06 pm
Re: Programar extensiones para el BASIC
@Rafa:Esto yo lo veo más rápido y valdría para los Spectrums originales.
¿Que quiere decir spectrums originales? El método descrito en la microhobby funciona lógicamente en un spectrum sin modificar, no entiendo lo que quieres decir con esto
Por otra parte veo mucho más legible y cómodo el método descrito en la microhobby, amén de que los programas ocuparían menos, ya que con tu método cualquier comando tiene que ir precedido de un randomize usr <dirección> y luego un REM, si es un programa largo con muchas líneas y muchas llamadas a las extensiones del basic quedaría el programa super ilegible y realmente largo.
¿Que quiere decir spectrums originales? El método descrito en la microhobby funciona lógicamente en un spectrum sin modificar, no entiendo lo que quieres decir con esto
Por otra parte veo mucho más legible y cómodo el método descrito en la microhobby, amén de que los programas ocuparían menos, ya que con tu método cualquier comando tiene que ir precedido de un randomize usr <dirección> y luego un REM, si es un programa largo con muchas líneas y muchas llamadas a las extensiones del basic quedaría el programa super ilegible y realmente largo.
Un saludo,
Gandulf
Gandulf
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
Rafa escribió:100 RANDOMIZE USR 64000: REM &MOVESPRITE(10,0)
La rutina ubicada en 64000 leería qué instrucción hay detrás del REM, y saltar a la correspondiente dirección donde estaría ubicada la rutina correspondiente. Además como los números y/o cadenas se almacenan detrás de un REM como modo texto, no haría falta usar el calculador de la ROM, ni números en coma flotante. Esto yo lo veo más rápido y valdría para los Spectrums originales.
El método de Microhobby, como señala Gandulf, funciona sin problemas en los Spectrums originales, además de ser más legible. Pero es que además, la presunta ventaja de tener todo el comando almacenado como "sólo texto" se torna un gran inconveniente cuando lo que necesitas es, de hecho, que el calculador de la ROM use su evaluador de expresiones para que puedas usar cosas como MOVESPRITE(fila+2*x,col+y)
De todas formas, lo que quería conocer es el mecanismo para acceder desde el ejecutor de BASIC a la línea actual y, bueno, lo que es el parser, ya que esto es para escribir una rutina que estaría en una shadow-ROM al estilo del interface 1, que se paginara automáticamente al ejecutarse un RST 8. Los nuevos comandos que quisiera implementar quiero que estén disponibles tanto desde BASIC como desde C/M usando hooks al estilo del mencionado Interface 1.
Por cierto: me da a mi que el artículo de Microhobby se basa en una rutina que no ha escrito el que ha hecho el artículo: el código fuente no está para nada documentado, no hay etiquetas en las subrutinas que llaman a la ROM, y las etiquetas de saltos son sospechosamente "automáticas", como BUCLE1, BUCLE2, DATA1, DATA2... Vamos, que parece que tenían el código objeto, lo han desensamblado así como han podido, y en el artículo sólo hablan muy claramente de cómo se actualiza la variable del sistema de marras (23613), pero muy poco sobre cómo funciona el parseo interno de las nuevas instrucciones; señal de que no han estudiado ese código a fondo, o ni siquiera se han molestado en ello.
Rafa escribió:Están los canales, el calculador de la ROM (lento y lioso), la configuración de pantalla, ...
Lento quizás, pero.... ¿lioso? No es más que un intérprete de FORTH. Es muy versátil, la verdad, y de hecho, el coprocesador matemáticos de los PC's usa un método similar.
Y sí que el Complete Spectrum..... es LA referencia, pero eso te vale cuando ya sabes dónde mirar, y qué ejecutar, y necesitas algún detalle. De otra forma, yo al menos me pierdo con las rutinas del ejecutivo BASIC. Supongo que será cuestión de leérselo más detenidamente.
Si tengo tiempo, me imprimo una copia, la encuaderno, y me la voy leyendo
Web: ZX Projects | Twitter: @zxprojects
- Rafa
- Jack The Nipper
- Mensajes: 181
- Registrado: Lun May 07, 2007 11:59 am
Re: Programar extensiones para el BASIC
Gracias por decirme que sí a un punto... de verdad, estoy adulado.
Creo que fuiste tú quien dijo que " lo que implica usar una ROM alternativa que se mapee". ¿Y eso de mapear una ROM alternativa sirve para un Spectrum original normal (no emulador)?
Para acceder a una línea determinada y ejecutarla, hay que pokear en las variables de sistema que llevan el número de línea actual y el número de sentencia dentro de la línea. Después yo saltaría a la dirección donde empieza el GOTO en la ROM, seteando el bit 5 de FLAGSX para que ejecute y no edite. Creo que es así. Bien enfocado con un solo CALL puedes ejecutar (si quieres) una sola línea, porque al encontrar el retorno de carro o fin de línea, retorna.
EL tema del evaluador de expresiones, usa preferencias, prevee paréntesis, de verdad, yo he estudiado la rutina (se llama SCANNING, dirección hex 24BF), para mí es un prodigio de la sintetización en programación y prevee todos los casos posibles. En el libro explican que sólo tiene un fallo, y es que la rutina se encuentre con el número -65536 (tio Clive lo arregló con otra rutina aparte).
Yo tengo el libro en formato original (en inglés) y de verdad tendrás lectura para meses, tratando de comprender los métodos que usa, todo en aras en ahorro de memoria (aunque al final le sobra poco más de 1K).
Si pudiera comprender el funcionamiento de SCANNING, de ahí al compilador Basic perfecto un paso. Velocidad casi C/M, el consumo de memoria muy pequeño... pero sobre todo la velocidad.
mcleod_ideafix escribió:El método de Microhobby, como señala Gandulf, funciona sin problemas en los Spectrums originales, además de ser más legible
Creo que fuiste tú quien dijo que " lo que implica usar una ROM alternativa que se mapee". ¿Y eso de mapear una ROM alternativa sirve para un Spectrum original normal (no emulador)?
Para acceder a una línea determinada y ejecutarla, hay que pokear en las variables de sistema que llevan el número de línea actual y el número de sentencia dentro de la línea. Después yo saltaría a la dirección donde empieza el GOTO en la ROM, seteando el bit 5 de FLAGSX para que ejecute y no edite. Creo que es así. Bien enfocado con un solo CALL puedes ejecutar (si quieres) una sola línea, porque al encontrar el retorno de carro o fin de línea, retorna.
EL tema del evaluador de expresiones, usa preferencias, prevee paréntesis, de verdad, yo he estudiado la rutina (se llama SCANNING, dirección hex 24BF), para mí es un prodigio de la sintetización en programación y prevee todos los casos posibles. En el libro explican que sólo tiene un fallo, y es que la rutina se encuentre con el número -65536 (tio Clive lo arregló con otra rutina aparte).
Yo tengo el libro en formato original (en inglés) y de verdad tendrás lectura para meses, tratando de comprender los métodos que usa, todo en aras en ahorro de memoria (aunque al final le sobra poco más de 1K).
Si pudiera comprender el funcionamiento de SCANNING, de ahí al compilador Basic perfecto un paso. Velocidad casi C/M, el consumo de memoria muy pequeño... pero sobre todo la velocidad.
RANDOMIZE USR 0
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
Rafa escribió:Gracias por decirme que sí a un punto... de verdad, estoy adulado.mcleod_ideafix escribió:El método de Microhobby, como señala Gandulf, funciona sin problemas en los Spectrums originales, además de ser más legible
Creo que fuiste tú quien dijo que " lo que implica usar una ROM alternativa que se mapee". ¿Y eso de mapear una ROM alternativa sirve para un Spectrum original normal (no emulador)?
Sí, porque lo que quiero hacer es un programa, pero que se ejecutará no como la rutina de Microhobby, sino como parte de un firmware para DivIDE, y éste mapea su ROM cuando se ejecuta una RST 8, lo mismo que el Interface 1. Por eso pensé que "todo" empezaba por ahí, por RST 8. El artículo de Microhobby aporta un enfoque que desconocía: usar ERR SP para alterar la dirección a ejecutar cuando ocurre un error.
Mapear una ROM alternativa (o una ROM shadow, como quieras llamarlo) se lleva haciendo en el Spectrum desde la aparición del Interface 1. En mi caso, como digo, usaré el DivIDE.
mcleod_ideafix escribió:EL tema del evaluador de expresiones, usa preferencias, prevee paréntesis, de verdad, yo he estudiado la rutina (se llama SCANNING, dirección hex 24BF), para mí es un prodigio de la sintetización en programación y prevee todos los casos posibles. En el libro explican que sólo tiene un fallo, y es que la rutina se encuentre con el número -65536 (tio Clive lo arregló con otra rutina aparte).
Yo tengo el libro en formato original (en inglés) y de verdad tendrás lectura para meses, tratando de comprender los métodos que usa, todo en aras en ahorro de memoria (aunque al final le sobra poco más de 1K).
Yo también he llegado a SCANNING traceando el código de la ROM. De todas formas, sospecho que no hará falta usarla "a pelo". Hay unas rutinas, mencionadas en las tablas de comandos, que me permiten, dependiendo de la clase de comando que sea, hacer chequeos de sintaxis y demás. De todas formas, si hay que mirarse SCANNING, pues se mira
mcleod_ideafix escribió:Si pudiera comprender el funcionamiento de SCANNING, de ahí al compilador Basic perfecto un paso. Velocidad casi C/M, el consumo de memoria muy pequeño... pero sobre todo la velocidad.
En un compilador no te vale el evaluador de expresiones del Spectrum, ya que la gracia de la compilación es realizar esa evaluación en tiempo de compilación, y generar código máquina con las instrucciones necesarias para remedar esa expresión. Te sale más a cuenta escribir un evaluador de expresiones para compilador desde 0, usando lex, yacc, etc.
Web: ZX Projects | Twitter: @zxprojects
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
Bueno, pues esta es mi primera tontería con SCANNING
La expresión tiene ya añadidos los números en notación de "coma flotante escondida" que usa el Spectrum, es decir, justo después de cada literal numérico se almacena el 14 (indicativo de "número") seguidos de los 5 bytes que codifican un número en el Spectrum, sea real o entero. En este caso, los números son enteros, lo que simplifica la codificación
Esto de añadir la versión "escondida" del número dentro de la expresión lo realiza automáticamente la rutina SCANNING cuando se ejecuta en modo "chequeo de sintaxis". Esto lo hace la ROM del Spectrum cuando tecleamos una línea de programa y pulsamos ENTER. Así, cuando esa línea se ejecuta, no hay que volver a generar el número en notación de coma flotante cada vez, sino que se coge la versión que dejó allí "preparada" el chequeador de sintaxis. De esto se encarga una parte de SCANNING, la rutina S-DECIMAL:
Por tanto, para poder saltarnos la fase de chequeo de sintaxis, y dado que SCANNING necesita esa representación interna, la he añadido "a pelo" en la expresión, que pasa de ser 16+16 a ser 16(version interna de 16)+16(version interna de 16), es decir:
Y por último, uso el 13 y el 128 para indicar fin de expresión (creo que bastaría con uno de los dos).
SCANNING, como usa el calculador de la ROM, deja su resultado en lo alto del stack. Aquí estoy asumiendo que dicho resultado va a ser numérico (esto se comprueba con el bit 6 de FLAGS, que si es 1 significa que el resultado es numérico, y si es 0, es alfanumérico). Entonces, sólo me falta hacer algo con ese resultado, por ejemplo, imprimirlo con PRINT-FP.
Me queda cambiar el programa para que chequee sintaxis y evalue la expresión, así puedo codificar la expresión de la forma habitual: "16+16" por ejemplo. Miraré a ver cómo se ejecuta la función VAL, que tiene toda la pinta de ser lo que necesito He intentado hacerlo tal cual, chequeando la sintaxis de la expresión, pero parece que la rutinilla que inserta el número "escondido" no funciona bien si la expresión está más allá de STKEND, ya que hace uso de MAKE-ROOM y otras, que sólo funcionan bien (eso parece) en zonas de memoria por debajo de STKEND.
Es por esto de la necesidad de chequear la sintaxis, que no convendría usar lo de "RAND USR 64000: REM sentencia nueva", ya que esa sentencia nueva tendría que ser chequeada en sintaxis y evaluada cada vez que se ejecutara, en lugar de sólo evaluarse.
NOTA: ¿será posible? ¿¿Pues no acabo de descubrir que las variables en BASIC pueden contener espacios??
Vamos, que un LET esto es una variable = 4 funciona!! y el correspondiente PRINT esto es una variable también funciona. Ahora acabo de comprobar que realmente esto se dice en el apéndice C del manual de BASIC, si bien lo que dice expresamente es que los espacios en blanco se ignoran cuando se crea la variable, o cuando se usa. O sea, que realmente PRINT estoesunavariable también funciona. Curioso
Código: Seleccionar todo
PRINT_FP equ 2de3h
SCANNING equ 24fbh
CHAN_OPEN equ 1601h
org 32768
Main proc
ld hl,(5c5dh) ;guardo CD_ADD
push hl ;en pila, para restaurarlo después
ld hl,Expresion
ld (5c5dh),hl ;apunto CH_ADD a mi expresión a evaluar
set 7,(iy+1) ;FLAGS en modo ejecución (evaluación)
call SCANNING
ld a,2
call CHAN_OPEN ;abrir canal S para imprimir
call PRINT_FP ;imprimimos el resultado
pop hl
ld (5c5dh),hl ;restauramos CH_ADD
ret
endp
Expresion db "16",14,0,0,16,0,0,"+16",14,0,0,16,0,0,13,128
end Main
La expresión tiene ya añadidos los números en notación de "coma flotante escondida" que usa el Spectrum, es decir, justo después de cada literal numérico se almacena el 14 (indicativo de "número") seguidos de los 5 bytes que codifican un número en el Spectrum, sea real o entero. En este caso, los números son enteros, lo que simplifica la codificación
Esto de añadir la versión "escondida" del número dentro de la expresión lo realiza automáticamente la rutina SCANNING cuando se ejecuta en modo "chequeo de sintaxis". Esto lo hace la ROM del Spectrum cuando tecleamos una línea de programa y pulsamos ENTER. Así, cuando esa línea se ejecuta, no hay que volver a generar el número en notación de coma flotante cada vez, sino que se coge la versión que dejó allí "preparada" el chequeador de sintaxis. De esto se encarga una parte de SCANNING, la rutina S-DECIMAL:
Código: Seleccionar todo
; This important routine is called during runtime and from LINE-SCAN
; when a BASIC line is checked for syntax. It is this routine that
; inserts, during syntax checking, the invisible floating point numbers
; after the numeric expression. During runtime it just picks these
; numbers up. It also handles BIN format numbers.
; ->
;; S-BIN
;; S-DECIMAL
Por tanto, para poder saltarnos la fase de chequeo de sintaxis, y dado que SCANNING necesita esa representación interna, la he añadido "a pelo" en la expresión, que pasa de ser 16+16 a ser 16(version interna de 16)+16(version interna de 16), es decir:
Código: Seleccionar todo
Expresion db "16",14,0,0,16,0,0,"+16",14,0,0,16,0,0,13,128
Y por último, uso el 13 y el 128 para indicar fin de expresión (creo que bastaría con uno de los dos).
SCANNING, como usa el calculador de la ROM, deja su resultado en lo alto del stack. Aquí estoy asumiendo que dicho resultado va a ser numérico (esto se comprueba con el bit 6 de FLAGS, que si es 1 significa que el resultado es numérico, y si es 0, es alfanumérico). Entonces, sólo me falta hacer algo con ese resultado, por ejemplo, imprimirlo con PRINT-FP.
Me queda cambiar el programa para que chequee sintaxis y evalue la expresión, así puedo codificar la expresión de la forma habitual: "16+16" por ejemplo. Miraré a ver cómo se ejecuta la función VAL, que tiene toda la pinta de ser lo que necesito He intentado hacerlo tal cual, chequeando la sintaxis de la expresión, pero parece que la rutinilla que inserta el número "escondido" no funciona bien si la expresión está más allá de STKEND, ya que hace uso de MAKE-ROOM y otras, que sólo funcionan bien (eso parece) en zonas de memoria por debajo de STKEND.
Es por esto de la necesidad de chequear la sintaxis, que no convendría usar lo de "RAND USR 64000: REM sentencia nueva", ya que esa sentencia nueva tendría que ser chequeada en sintaxis y evaluada cada vez que se ejecutara, en lugar de sólo evaluarse.
NOTA: ¿será posible? ¿¿Pues no acabo de descubrir que las variables en BASIC pueden contener espacios??
Código: Seleccionar todo
; -----------------
; THE 'LET' COMMAND
; -----------------
; Sinclair BASIC adheres to the ANSI-78 standard and a LET is required in
; assignments e.g. LET a = 1 : LET h$ = "hat".
;
; Long names may contain spaces but not colour controls (when assigned).
; a substring can appear to the left of the equals sign.
Vamos, que un LET esto es una variable = 4 funciona!! y el correspondiente PRINT esto es una variable también funciona. Ahora acabo de comprobar que realmente esto se dice en el apéndice C del manual de BASIC, si bien lo que dice expresamente es que los espacios en blanco se ignoran cuando se crea la variable, o cuando se usa. O sea, que realmente PRINT estoesunavariable también funciona. Curioso
Web: ZX Projects | Twitter: @zxprojects
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
Segunda tontería con SCANNING:
Ahora sí: la expresión se copia al área de trabajo, se chequea en sintaxis y se evalúa. Lo bueno de esto es que la primera parte, el chequeo de sintaxis (lo que está enmarcado entre líneas), sólo necesito hacerlo una vez. Después de eso, puedo evaluar la expresión cuantas veces quiera. Si en la expresión hay variables, pues tendré un valor distinto en función del valor de esas variables. A ver si tengo un ratito más y hago otro ejemplo más elaborado...
Código: Seleccionar todo
PRINT_FP equ 2de3h
SCANNING equ 24fbh
CHAN_OPEN equ 1601h
CH_ADD equ 5c5dh
org 32768
Main proc
ld hl,(CH_ADD) ;guardo CD_ADD
push hl ;en pila, para restaurarlo después
;------------------------------------------------------------------------------
ld bc,LongExpr
rst 30h ;abro un hueco en el área de trabajo. Inicio del hueco abierto en DE
ld (CH_ADD),de ;apunto CH_ADD a la expresion, que copiaré al hueco abierto
push de ;Guardo la dirección de inicio al hueco
ld hl,Expresion ;Copio mi expresión...
ldir ;...al hueco abierto en el área de trabajo
res 7,(iy+1) ;primero señalizamos que queremos chequear la sintaxis
call SCANNING ;llamada a scanning para chequear sintaxis y construir los valores ocultos en punto flotante.
pop hl ;recuperamos el puntero al inicio al hueco (expresión ya chequeada en sintaxis)
;------------------------------------------------------------------------------
ld (CH_ADD),hl ;apunto CH_ADD a mi expresión a evaluar
set 7,(iy+1) ;ya está chequeado, ahora ponemos FLAGS en modo ejecución (evaluación)
call SCANNING ;evaluo la expresión: resultado en el stack del calculador
ld a,2
call CHAN_OPEN ;abrir canal S para imprimir
call PRINT_FP ;imprimimos lo que haya en la cima del stack del calculador.
pop hl
ld (5c5dh),hl ;restauramos CH_ADD
ret
endp
Expresion db "1+2*3/4",13
LongExpr equ $-Expresion
end Main
Ahora sí: la expresión se copia al área de trabajo, se chequea en sintaxis y se evalúa. Lo bueno de esto es que la primera parte, el chequeo de sintaxis (lo que está enmarcado entre líneas), sólo necesito hacerlo una vez. Después de eso, puedo evaluar la expresión cuantas veces quiera. Si en la expresión hay variables, pues tendré un valor distinto en función del valor de esas variables. A ver si tengo un ratito más y hago otro ejemplo más elaborado...
Web: ZX Projects | Twitter: @zxprojects
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
Y tercera tontería con SCANNING
Bueno, no sirve de mucho, excepto para probar lo obvio, que el C/M es más rápido que el BASIC, aunque el 90% del tiempo de ejecución se realiza en las mismas rutinas de la ROM que se usan durante la interpretación del BASIC.
Un pequeño benchmark podría ser éste:
Cuyo resultado es:
Los casi dos segundos que se ganan son porque en C/M no se pierde tiempo interpretando el bucle, y la expresión no tiene que buscar el valor de ninguna variable durante su evaluación, sino que lo parcheo directamente en el número "escondido" que SCANNING genera para el 0 que aparece en la expresión: al ser un entero positivo que cabe en un byte, el parcheo es directamente al byte menos significativo de la representación en complemento a 2 del número en cuestión.
Supón que PLOT no existiera en el BASIC del Spectrum y quisiéramos incluirla con algo así:
Como lo que hay tras el REM no se evalua en sintaxis, en ejecución habría que usar SCANNING dos veces con cada expresión: una para chequearla en sintaxis y generar los números "escondidos" en el área de trabajo, y otra para la evaluación, propiamente dicha. ¡Sería casi el doble de lenta!
Código: Seleccionar todo
;Rutinas ROM
PRINT_FP equ 2de3h
SCANNING equ 24fbh
CHAN_OPEN equ 1601h
CLS equ 0d6bh
PLOT_CB equ 22e5h
STK_TO_A equ 2314h
;Variables del sistema
CH_ADD equ 5c5dh
;Tokens para la expresión
SIN equ 178
org 32768
Main proc
ld hl,(CH_ADD) ;guardo CD_ADD
push hl ;en pila, para restaurarlo después
ld bc,LongExpr
rst 30h ;abro un hueco en el área de trabajo. Inicio del hueco abierto en DE
ld (CH_ADD),de ;apunto CH_ADD a la expresion, que copiaré al hueco abierto
push de ;Guardo la dirección de inicio al hueco
ld hl,Expresion ;Copio mi expresión...
ldir ;...al hueco abierto en el área de trabajo
res 7,(iy+1) ;primero señalizamos que queremos chequear la sintaxis
call SCANNING ;llamada a scanning para chequear sintaxis y construir los valores ocultos en punto flotante.
pop hl ;recuperamos el puntero al inicio al hueco (expresión ya chequeada en sintaxis)
ld de,ExpresionCheq ;Este bucle copia la expresión chequeada desde el área de trabajo hasta ExpresionCheq, hasta encontrar un retorno de carro
BucCopia ld a,(hl)
ld (de),a
inc hl
inc de
cp 13
jr nz,BucCopia
call CLS
set 7,(iy+1) ;ya está chequeado, ahora ponemos FLAGS en modo ejecución (evaluación)
ld c,0 ;C será la coordenada X, desde 0 a 255
BucPlot push bc
ld ix,ExpresionCheq
ld (ix+24),c ;Aquí parcheamos la expresión para que el 0 se convierta en el valor de C
ld (CH_ADD),ix ;apunto CH_ADD a mi expresión a evaluar
call SCANNING ;evaluo la expresión: resultado en el stack del calculador
call STK_TO_A ;resultado a A
pop bc
ld b,a ;que es nuestra coordenada Y
push bc
call PLOT_CB ;punto el puntito en coordenadas C,B
pop bc
inc c
jr nz,BucPlot
pop hl
ld (5c5dh),hl ;restauramos CH_ADD
ret
endp
Expresion db "88+80*",SIN,"(0*0.02463994238)",13
LongExpr equ $-Expresion
ExpresionCheq ds 128 ;128 bytes para guardar la expresión ya chequeada en sintaxis
end Main
Bueno, no sirve de mucho, excepto para probar lo obvio, que el C/M es más rápido que el BASIC, aunque el 90% del tiempo de ejecución se realiza en las mismas rutinas de la ROM que se usan durante la interpretación del BASIC.
Un pequeño benchmark podría ser éste:
Cuyo resultado es:
Los casi dos segundos que se ganan son porque en C/M no se pierde tiempo interpretando el bucle, y la expresión no tiene que buscar el valor de ninguna variable durante su evaluación, sino que lo parcheo directamente en el número "escondido" que SCANNING genera para el 0 que aparece en la expresión: al ser un entero positivo que cabe en un byte, el parcheo es directamente al byte menos significativo de la representación en complemento a 2 del número en cuestión.
Supón que PLOT no existiera en el BASIC del Spectrum y quisiéramos incluirla con algo así:
Código: Seleccionar todo
RANDOMIZE USR 64000: REM PLOT n,88+80*SIN (n*0.02463994238)
Como lo que hay tras el REM no se evalua en sintaxis, en ejecución habría que usar SCANNING dos veces con cada expresión: una para chequearla en sintaxis y generar los números "escondidos" en el área de trabajo, y otra para la evaluación, propiamente dicha. ¡Sería casi el doble de lenta!
Web: ZX Projects | Twitter: @zxprojects
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
Y ya, la prueba definitiva.
Usando el método de Rafa, que ciertamente es el más sencillo de implementar, he hecho como si no existiera la orden PLOT en BASIC, y la he implementado así:
Donde a,b son los dos parámetros del PLOT, que por supuesto, pueden ser cualesquiera dos expresiones numéricas.
Este es el código. Como REM no chequea sintaxis, he de hacerlo en tiempo de ejecución, llamando a EXPT_2NUM dos veces. EXPT_2NUM es una rutina de la ROM que se encarga de comprobar (en modo chequeo de sintaxis) o evaluar (en modo ejecución) un bloque de dos parámetros numéricos separados por una coma.
Para ello, copio el bloque de parámetros a un área del espacio de trabajo. Podría hacer el chequeo en la misma línea del programa, pero eso significaría que la siguiente vez que pasara por ahí, el chequeo de sintaxis fallaría, al encontrarse los números ocultos que se pusieron la primera vez (NOTA MENTAL: esto me da una idea para mejorar el algoritmo, dejando una marca para indicar que ya he chequeado la sintaxis).
Después de copiar al área de trabajo, es ahí donde hago primero el chequeo sintáctico y luego la evaluación de parámetros. Recojo los resultados usando STACK_TO_BC y seguidamente, llamada a PLOT para pintar el puntito.
El benchmark para comprobar la velocidad de ejecución de este "comando extendido", respecto del original, es éste:
Y los resultados:
Donde se observa que la penalidad por tener que chequear sintaxis en tiempo de ejecución hace que la versión con REM tarde 1,6 veces más tiempo que la original.
Ah! Como imaginaba al empezar a leer el desensamble de la ROM, no es necesario, en la mayoría de los casos, llamar directamente a SCANNING, sino que puedo usar las rutinillas auxiliares como EXPT_2NUM se encargan de llamar a SCANNING todas las veces que haga falta y además chequear que los parámetros están separados por coma, etc.
Voy a probar con la modificación para que chequee la sintaxis sólo una vez, a ver si me sale...
Pues va a ser que no me sale: parece que al editor del BASIC, y al propio intérprete, no le gusta nada que dentro del texto del REM haya cosas no legibles. En fin, luego probaré la versión que realmente quiero hacer, sin el REM.
Usando el método de Rafa, que ciertamente es el más sencillo de implementar, he hecho como si no existiera la orden PLOT en BASIC, y la he implementado así:
Código: Seleccionar todo
RANDOMIZE USR 64000: REM: PLOT a,b
Donde a,b son los dos parámetros del PLOT, que por supuesto, pueden ser cualesquiera dos expresiones numéricas.
Este es el código. Como REM no chequea sintaxis, he de hacerlo en tiempo de ejecución, llamando a EXPT_2NUM dos veces. EXPT_2NUM es una rutina de la ROM que se encarga de comprobar (en modo chequeo de sintaxis) o evaluar (en modo ejecución) un bloque de dos parámetros numéricos separados por una coma.
Para ello, copio el bloque de parámetros a un área del espacio de trabajo. Podría hacer el chequeo en la misma línea del programa, pero eso significaría que la siguiente vez que pasara por ahí, el chequeo de sintaxis fallaría, al encontrarse los números ocultos que se pusieron la primera vez (NOTA MENTAL: esto me da una idea para mejorar el algoritmo, dejando una marca para indicar que ya he chequeado la sintaxis).
Después de copiar al área de trabajo, es ahí donde hago primero el chequeo sintáctico y luego la evaluación de parámetros. Recojo los resultados usando STACK_TO_BC y seguidamente, llamada a PLOT para pintar el puntito.
Código: Seleccionar todo
;Implementación de nuevos comandos usando REM
;Rutinas ROM
SCANNING equ 24fbh
EXPT_2NUM equ 1c7ah
PLOT_CB equ 22e5h
STK_TO_A equ 2314h
STK_TO_BC equ 2307h
;Variables del sistema
CH_ADD equ 5c5dh
;Tokens
REM equ 234
PLOT equ 246
org 64000
Main proc
ld hl,(CH_ADD) ;Guardamos CH_ADD
push hl
rst 18h ;token/carácter presente
cp ":" ;Deben ser los dos puntitos
jr nz,Fin ;Si no, fuera
rst 20h
cp REM ;El próximo debe ser un REM
jr nz,Fin
rst 20h
cp ":" ;El próximo, otros dos puntitos
jr nz,Fin
rst 20h ;Y el próximo ya es nuestro comando!!!
cp PLOT ;Aquí habría que preguntar cuál de ellos es, pero como sólo tenemos uno...
jr nz,Fin ;...si no es ese, pues nada, no se hace nada.
rst 20h ;Apuntamos al bloque de parámetros
;Procesamiento del comando PLOT. Necesitamos dos parámetros numéricos separados por coma.
push hl ;Guardamos inicio del bloque de parámetros
ld bc,0
;Miramos cuánto ocupan los dos parámetros (hasta encontrar un retorno de carro o un ":")
CheckLong ld a,(hl)
inc bc
inc hl
cp 13
jr z,FinLong
cp ":"
jr z,FinLong
jr CheckLong
FinLong rst 30h ;Abro un hueco en el espacio de trabajo para los parámetros. Inicio del hueco en DE
pop hl
push de ;Guardo inicio del bloque de par. en el área de trabajo
ldir ;Copio bloque de parámetros
pop de
push de
ld (CH_ADD),de ;CH_ADD apunta a nuestro bloque de parámetros copiado al espacio de trabajo
res 7,(iy+1) ;Señalamos que vamos a chequear sintaxis
call EXPT_2NUM ;Chequeamos sintaxis de dos parámetros numéricos separados por una coma
pop de
ld (CH_ADD),de ;restauramos CH_ADD de nuevo al principio de nuestros dos parámetros
set 7,(iy+1) ;Señalamos que vamos a evaluar las dos expresiones
call EXPT_2NUM ;Evaluamos las dos expresiones, dejando el resultado en las dos últimas posiciones del stack
call STK_TO_BC ;Los dos resultados numéricos, a BC
call PLOT_CB ;y hacemos el PLOT
Fin pop hl
ld (CH_ADD),hl
ret
endp
end
El benchmark para comprobar la velocidad de ejecución de este "comando extendido", respecto del original, es éste:
Y los resultados:
Donde se observa que la penalidad por tener que chequear sintaxis en tiempo de ejecución hace que la versión con REM tarde 1,6 veces más tiempo que la original.
Ah! Como imaginaba al empezar a leer el desensamble de la ROM, no es necesario, en la mayoría de los casos, llamar directamente a SCANNING, sino que puedo usar las rutinillas auxiliares como EXPT_2NUM se encargan de llamar a SCANNING todas las veces que haga falta y además chequear que los parámetros están separados por coma, etc.
Voy a probar con la modificación para que chequee la sintaxis sólo una vez, a ver si me sale...
Pues va a ser que no me sale: parece que al editor del BASIC, y al propio intérprete, no le gusta nada que dentro del texto del REM haya cosas no legibles. En fin, luego probaré la versión que realmente quiero hacer, sin el REM.
Web: ZX Projects | Twitter: @zxprojects
- Rafa
- Jack The Nipper
- Mensajes: 181
- Registrado: Lun May 07, 2007 11:59 am
Re: Programar extensiones para el BASIC
Para no gastar tiempo en chequear sintaxis, lo mejor es no hacer un chequeo de sintaxis, o sea PRESUPONER que va a estar bien tecleado
RANDOMIZE USR 0
- mcleod_ideafix
- Johnny Jones
- Mensajes: 3985
- Registrado: Vie Sep 21, 2007 1:26 am
- Ubicación: Jerez de la Frontera
- Contactar:
Re: Programar extensiones para el BASIC
No es suficiente. El chequeo de sintaxis además construye la versión "escondida" de cada número que aparece en la expresión, y que necesita el evaluador (lee el post "primera tontería con SCANNING"), con lo que sigue siendo necesario... a menos que en tu expresión no haya ni una sola constante, sino que todo sean variables, o bien que a mano calcules los valores "escondidos", que es lo que hago precisamente en lo que llamo "tontería 1 con SCANNING".
Lo malo es que ese precálculo "a mano" de los números escondidos hay que hacerlo antes o después, y si no se hace cuando la línea se añade al programa BASIC (lo habitual), entonces habrá que hacerlo cuando se ejecute (que es lo que tengo que hacer en la última versión del programa).
Lo malo es que ese precálculo "a mano" de los números escondidos hay que hacerlo antes o después, y si no se hace cuando la línea se añade al programa BASIC (lo habitual), entonces habrá que hacerlo cuando se ejecute (que es lo que tengo que hacer en la última versión del programa).
Web: ZX Projects | Twitter: @zxprojects
- winston
- Sabreman
- Mensajes: 469
- Registrado: Mar Ago 19, 2008 4:17 pm
- Ubicación: Isla de Man
- Contactar:
Re: Programar extensiones para el BASIC
mcleod_ideafix escribió:Sí, porque lo que quiero hacer es un programa, pero que se ejecutará no como la rutina de Microhobby, sino como parte de un firmware para DivIDE, y éste mapea su ROM cuando se ejecuta una RST 8, lo mismo que el Interface 1.
Ya he hecho esto para el Spectranet. Aquí está el codigo fuente que puede ser modificado para otro hardware:
http://spectrum.alioth.net/svn/filedeta ... icextn.asm
Esta página muestra cómo puedes usar (en inglés)
http://spectrum.alioth.net/doc/index.ph ... Tutorial_6
...incluyedo cómo analizar sintácticamente los variables etc.
Lo he hecho con mucha ayuda desde el "Complete Shadow ROM Disassembly" para el Interface 1, y ayuda de Garry Lancaster, quien explicó el evaluador de expresiones.
¿Quién está conectado?
Usuarios navegando por este Foro: Ahrefs [Bot] y 23 invitados