viernes, 27 de noviembre de 2015

De BASIC a código máquina sin dolor, parte II

He estado probando diversos compiladores a Mcode (código máquina) aparte del ya mencionado Softek "FP" Full Compiler en la entrada "De BASIC a código máquina sin dolor". 

De las varias opciones con las que me he peleado (literal), os propongo como otra opción muy válida para pasar vuestros desarrollos BASIC a código máquina, el compilador "HiSoft BASIC" de Cameron Hayne y publicado en 1986 por HiSoft.

Este compilador soporta los modelos ZX Spectrum, ZX Spectrum +, ZX Spectrum 128 y ZX Spectrum Plus 2. 

Para usarlo en los ZX Spectrum +2A/B/3 deberéis usar el modo 48k. El cargador de 128 utiliza comandos CAT y nomenclatura de archivos que los 2A/B no entienden. 

En las versiones de 128k soportadas, solo ocupa 500 bytes de RAM de usuario, por lo que nos deja hasta 40k para nuestro programa BASIC. 

Estoy trabajando en una versión que cargue en los modelos +2A/B, dado que no hay una versión en cinta para ellos. Si hay una versión en disco para la el ZX Spectrum +3. 

Hay otra versión depurada por Zeljko Juric también disponible.

En general es un compilador muy robusto. Tiene varias particularidades muy buenas, como la de poder "mezclar" código máquina de una compilación con otra (al estilo de librerías o módulos) además de soportar básicamente todos los comandos de BASIC, incluyendo matrices de hasta 2 niveles (A(x,y)). Puedes definir renglones / áreas de compilación a Mcode y dejar bloques de BASIC libres. Esto es muy útil para los comandos no soportados desde el compilado. También es posible compilar por separado los segmentos DATA grandes que tengamos y "pegarlos" al código máquina principal del programa.

Los comandos no soportados, los podemos usar directamente con BASIC, yendo y viniendo del código máquina.

La versión que he utilizado es la 1.1.

La cinta viene con dos caras. Cara A para el 48k y cara B para los 128k soportados.

Hay un montón de ejemplos en la cinta y el manual de uso está muy bien; explica todo con detalle, da ejemplos y tiene un capítulo dedicado a tips para mejorar el rendimiento del código máquina generado por el compilador.

Otra funcionalidad muy curiosa, es la posibilidad de investigar las variables de nuestro programa, con el comando *T.

El propio compilador propone fijar un tipo de datos para la(s) variable(s) (con una directiva especial en una linea REM) , y así obtener un compilado aún más rápido y pequeño.

Soporta funciones de usuario, GOTO/GOSUB calculados, operaciones de floating point y otra gran cantidad de cosas.

El compilado contiene todo lo necesario para que el programa sea independiente (todos los run-time necesarios).

En las pruebas realizadas hasta ahora, con proyectos que tengo en curso, el resultado  (y la estabilidad) ha sido mejor que el obtenido con el compilador Softket "FP" Full Compiler.


miércoles, 25 de noviembre de 2015

Jugando a los Sprites, III. ¡Laser Basic!

Tanto en Jugando a los Sprites episodio I como en Jugando a los Sprites episodio II vemos visto las carencias y dificultades de trabajar con los gráficos en sprites desde BASIC y hemos definido un par de trucos / mecanismos para mejorar tanto el rendimiento como el uso de dichos sprites. 

Las técnicas descritas en el episodio I y en el episodio II son válidas para hacer bastantes cosas. Todo dependerá de la complejidad del proyecto en el que nos embarquemos. 

Por suerte, la compañía Oasis Software en el año 1986 sacó al mercado una extensión del BASIC llamada Laser Basic enfocada completamente a la programación con gráficos y sprites desde BASIC.

 Resumiendo mucho las capacidades de esta extensión de BASIC, podemos decir que: 

  • Gestiona hasta 256 sprites de cualquier tamaño.
  • Se pueden definir ventanas de pantalla y operar con ellas.
  • Se pueden realizar movimientos en pantalla tanto de los sprites como de las zonas definidas como ventanas, junto con sus atributos de pixeles, de forma muy sencilla.
  • Animaciones 
  • Optimizaciones para que el rendimiento sea bueno. 
  • Editor de Sprites avanzado. 
  • Gestión de colisión de sprites en pantalla. 
  • Toolkit para el BASIC.
  • Definición de procedimientos / funciones complejas.


Es decir, que nos brinda todo lo necesario para desarrollar "en serio" aplicaciones y juegos, con una calidad gráfica alta. 

Claro, necesitamos cargado en memoria del Spectrum, el código máquina del Laser Basic para que todo funcione. 

¿Es esto un problema?. 

Pues no, dado que tenemos el Laser Compiler que nos permite pasar nuestros desarrollos a código máquina, añadiendo todo lo necesario del Laser Basic para que el aplicativo sea completamente independiente y distribuirle.. 

¿Conclusión?.

Porque reinventar la rueda, cuando Laser Basic y Laser Compiler nos da (casi) todo lo que necesitamos para embarcarnos, por ejemplo, en el desarrollo de juegos usando solo BASIC?. 

Y ya para los sibaritas y  puristas Oasis Software lo condimentó todo con Laser Genius, un editor ensamblador/Mcode. 

He creado un Zip con todo juntito, junto con los manuales,para facilitar las cosas. 
Lo puedes descargar aquí

Ser buenos/buenas. 





lunes, 23 de noviembre de 2015

Jugando a los Sprites, episodio II.

En Jugando a los Sprites Episodio I vimos como se pinta un OVNI de 16x16 en pantalla usando escrituras directas a la memoria de vídeo.

Para ello usamos un array con las direcciones de memoria, y una rutina de pintado haciendo POKE. Ambas en su versión "bucle" y en su versión "directa", para obtener un mejor rendimiento.

Aún así, el resultado es lento  (aunque siempre lo podemos mejorar compilando el código BASIC a código máquina).

Bueno, usando UDG's podemos hacer exactamente lo mismo, y el resultado es mucho más rápido al ejecutar. Otra ventaja, es que nos queda un código mucho más pequeño, que eso teniendo solo 48k, siempre se agradece.

Esta vez, pintamos el OVNI directamente en bits.

270 REM *El Ovni en Binario
280 DATA BIN 00000111,BIN 11100000
290 DATA BIN 00001000,BIN 00010000
300 DATA BIN 00010000,BIN 00001000
310 DATA BIN 00100011,BIN 11000100
320 DATA BIN 01000011,BIN 11000010
330 DATA BIN 10000000,BIN 00000001
340 DATA BIN 10000000,BIN 00000001
350 DATA BIN 11111111,BIN 11111111
360 DATA BIN 11111111,BIN 11111111
370 DATA BIN 11111111,BIN 11111111
380 DATA BIN 10000000,BIN 00000001
339 DATA BIN 01000011,BIN 11000010
400 DATA BIN 00100011,BIN 11000100
410 DATA BIN 00010000,BIN 00001000
420 DATA BIN 00001000,BIN 00010000
430 DATA BIN 00000111,BIN 11100000
He aquí los cuatro cuadros de 8x8, que vamos a usar en 4 UDG's, de la A a la D (UDG-A,UDG-B,UDG-C y UDG-D).

Si quitas las instrucciones (DATA y BIN) ves perfectamente el OVNI pintado en 0 y 1.

Lo podíamos haber organizado de otra forma, pero parece natural poner los 4 cuadrantes seguidos, de derecha a izquierda y de arriba a abajo. 

Ahora los cargamos en los UDG. Primero los cuadrantes de arriba (A y B) y luego los de abajo (C y D).

160 REM *Cargamos nuestro srpite 16x16
170 RESTORE 280
180 FOR I=0 TO 7
190 READ A: READ B
200 POKE USR "A"+I,A: POKE USR "B"+I,B
210 NEXT I
220 FOR I=0 TO 7
230 READ A: READ B
240 POKE USR "C"+I,A: POKE USR "D"+I,B
250 NEXT I
¡Ya los tenemos listos para usar !.

La rutina que los usa, dadas unas coordenadas X e Y y la posición anterior.

120  REM *Esta es nuestra rutina de dibujo
130  PRINT AT (PY),(PX+1);CHR$ 32:
        PRINT AT (PY+1),(Px+1);CHR$ 32:
PRINT AT POSY,POSX+1;CHR$ 145:
PRINT AT (POSY+1),(POSX+1);CHR$ 147:
PRINT AT PY,PX;CHR$ 32:
PRINT AT (PY+1),(PX);CHR$ 32:
PRINT AT POSY,POSX;CHR$ 144:
PRINT AT (POSY+1),POSX;CHR$ 146
140 LET PX=POSX: LET pY=POSY
150  RETURN 
Usamos CHR$ 32 para "borrar" (espacio en blanco) y los CHR$ 144,145,146 y 147 correspondientes a UDG-A,UDG-B,UDG-C y UDG-D.

Se borran los dos cuadrantes de la derecha primero (arriba y abajo), se pintan los nuevos en la nueva posición y luego se hace lo mismo con los otros dos cuadrantes. Lo he hecho así, pero se pueden borrar todos primero, o los de la izquierda, o como más nos guste.

El programa esta vez, lo mueve directamente 10 posiciones a la derecha. El rendimiento es bueno y el "parpadeo" lo podemos disimular / ajustar al gusto, cambiando el orden en el cual borramos y volvemos a pintar. 















Aunque solo tengamos del UDG-A al UDG-U, y para un sprite de 16x16 gastemos 4, hay maneras de tener muchos más, solo hay que tener imaginación ;). 

Podemos guardar en memoria tile-sets y asignarlos a los UDG cuando los queramos usar. Así, no tenemos limitación ninguna. 

Esta vez el programa es más corto. De todas formas, puedes descargarlo de aquí o descargarlo en formato TAP.

10 REM *Jugando a los Sprites 2*
15 CLS
20 LET POSX=1
30 LET POSY=1
40 LET PX=1
50 LET PY=1
60 GO SUB 160
70 GO SUB 130
80 INPUT "Vamos a moverlo o salir (q/Q)";z$
90 IF z$="q" OR z$="Q" THEN GO TO 440
100 FOR I=0 TO 10:
LET POSX=POSX+1:
GO SUB 120:
NEXT I
110 GO TO 440
120 REM *Esta es nuestra rutina de dibujo
130 PRINT AT (PY),(PX+1);CHR$ 32:
PRINT AT (PY+1),(Px+1);CHR$ 32:
PRINT AT POSY,POSX+1;CHR$ 145:
PRINT AT (POSY+1),(POSX+1);CHR$ 147:
PRINT AT PY,PX;CHR$ 32:
PRINT AT (PY+1),(PX);CHR$ 32:
PRINT AT POSY,POSX;CHR$ 144:
PRINT AT (POSY+1),POSX;CHR$ 146
140 LET PX=POSX: LET pY=POSY
150 RETURN
160 REM *Cargamos nuestro srpite 16x16
170 RESTORE 280
180 FOR I=0 TO 7
190 READ A: READ B
200 POKE USR "A"+I,A: POKE USR "B"+I,B
210 NEXT I
220 FOR I=0 TO 7
230 READ A: READ B
240 POKE USR "C"+I,A: POKE USR "D"+I,B
250 NEXT I
260 RETURN
270 REM *El Ovni en Binario
280 DATA BIN 00000111,BIN 11100000
290 DATA BIN 00001000,BIN 00010000
300 DATA BIN 00010000,BIN 00001000
310 DATA BIN 00100011,BIN 11000100
320 DATA BIN 01000011,BIN 11000010
330 DATA BIN 10000000,BIN 00000001
340 DATA BIN 10000000,BIN 00000001
350 DATA BIN 11111111,BIN 11111111
360 DATA BIN 11111111,BIN 11111111
370 DATA BIN 11111111,BIN 11111111
380 DATA BIN 10000000,BIN 00000001
390 DATA BIN 01000011,BIN 11000010
400 DATA BIN 00100011,BIN 11000100
410 DATA BIN 00010000,BIN 00001000
420 DATA BIN 00001000,BIN 00010000
430 DATA BIN 00000111,BIN 11100000
440 REM *Final del programa



Jugando a los Sprites, episodio I.

Es sabido que el ZX Spectrum no tiene soporte hardware para gestionar sprites. Sus homónimos como el Commodore 64 y el MSX sí que tienen soporte tanto a nivel de hardware como de BASIC, para los sprites. 

Después de haber leído una estupenda publicación de Tero Heikkinen en su blog Old Machinery sobre sprites en el ZX me he animado a aplicar varios de los conceptos que Tero explica, única y exclusivamente al BASIC y añadir un par de cosas mi propia cosecha.

La idea es ejemplificar tanto lo malo como lo bueno que tenemos al tratar de usar / crear sprites en el propio Spectrum, desde BASIC.

Para usar sprites de 8x8 , podemos usar directamente los UDG desde BASIC. Fácil, sencillo de usar y con un rendimiento bueno. 

Hay que tener en cuenta que el Spectrum está enfocado a usar caracteres de 8x8, por lo que la ordenación en memoria es un poco extraña. Para no entrar en muchos tecnicismos, vamos a decir que las posiciones en memoria de la pantalla, coinciden con determinadas columnas de pixeles, como se ve en la imagen a continuación: 

















Para no liarnos mucho, podemos usar un algoritmo que nos de, las 176 posiciones (valores) que nos interesan; lo vemos más adelante. 

Bueno, yo quería pintar un OVNI en pantalla, así que haciendo un poco de trampa, usando el editor del BasinC he pintado un OVNI de 16x16.



















Luego, lo he exportado en valores decimales al BASIC. 

1020 REM *Datos del sprite 16x16 en decimal(4 cuadriculas de 8)
1030 DATA 7,224,7,224,8,16,19,200
1040 DATA 35,196,64,2,159,249,255,255
1050 DATA 255,255,159,249,64,2,35,196
1060 DATA 19,200,8,16,7,224,7,224

Ahora, vamos a hacer el pintado en 2 pasos:

1) Las posiciones de memoria válidas en una variable, para calcularlas o cargarlas una única vez.

2) Asignamos coordenadas X e Y, donde queremos pintar y llamamos al pintado. 

Las posiciones de memoria.

En la publicación de Tero, se calcula las posiciones en función ya de unas determinadas coordenadas en pantalla que quiere usar. Yo, simplemente, y por tener luego los valores "fijos", he dejado el cálculo en el programa de ejemplo. 

Acordaros que la 1ra posición de memoria para el pintado en pantalla es 16384.

490 REM * Para calcular los valores del POKE
500 FOR Y=0 TO 175
510 LET BLOCK=INT (Y/64)
520 LET CROW=INT (Y/8)
530 LET YR=Y-(CROW*8)
540 LET CROW=CROW-(BLOCK*8)
550 LET ADD=(16384+(BLOCK*2048))+(CROW*32)+(YR*256)
560 LET A(Y+1)=ADD
570 NEXT Y

Este bucle es costoso para el Spectrum. Siendo un poco listos, incluimos en el programa un segmento DATA con los 176 valores, que siempre irá mucho más rápido hacer un READ que el cálculo completo. 

1080 REM *Datos de los POKE calcualdos, 176 valores posibles*
1090 DATA 16384,16640,16896,17152,17408,17664,17920,18176,16416,16672,16928,17184,17440,17696
1100 DATA .................
¿ Y por que hacemos esto?. Bueno, porque luego vamos a usar nuestra super rutina de pintado en pantalla, asignando las coordenadas X e Y que queremos y llamándola. 

370 PRINT AT 19,1;"Con bucle"
380 FOR I=0 TO 15
390 POKE A(I+(POSY))+(POSX),0: POKE A(I+(POSY))+(POSX)+1,0
400 NEXT I
410 LET PV=POSY+DVER
420 LET PH=POSX+DHOZ
430 FOR I=0 TO 15
440 READ L: READ R
450 POKE A(I+(PV))+(PH),L
460 POKE A(I+(PV))+((PH)+1),R
470 NEXT I

La primera parte de la rutina, "borra" de pantalla lo anterior (la posicion anterior del OVNI). La segunda parte, dadas unas nuevas coordenadas, pinta el OVNI.

Como los bucles son más lentos que las instrucciones directas, y como sabemos que solo son 16 instrucciones (nuestro sprite es de 16x16) podemos sustituir el bucle por instrucciones directas, tratando de ganarle algo al rendimiento. 

Es decir, que puedes hacer los 16 POKE en 16 instrucciones diferentes, y ganar algo.

READ L
READ R
POKE A(0+(PV))+(PH),L: POKE A(0+(PV))+((PH)+1),R
READ L
READ R
POKE A(1+(PV))+(PH),L: POKE A(1+(PV))+((PH)+1),R
Así, del 0 al 15.

En el código fuente más abajo, tienes todo. 

La verdad, es que el resultado es chulo, pero más lento que el caballo del malo. ¿Como solucionar este problema de rendimiento?. Bueno, yo me he liado la manta a la cabeza y he compilado el código BASIC a código máquina y ahora sí soy un panda FELIZ. 

En el episodio II, haremos lo mismo, usando UDG y veremos si nos hace falta código máquina o no ;). 

Ah, casi se me olvidaba. Aquí os dejo un fichero TAP con el programa.

Tambíen te puedes descargar el código BASIC.















jueves, 19 de noviembre de 2015

¡ Como me gustan los UDG !

No hay nada mas 8 bit, que usar gráficos de 8 bits :D

El Spectrum nos deja usar su concepto de User Defined Grahpics (UDG) para hacer cosas muy chulas.

Tenemos desde el UDG-A hasta el UDG-U para cargar nuestros diseños usando una plantilla de 8x8 bits.

Con el método CHR$ podemos imprimir en pantalla desde la "A" (144) hasta la "U" (154), conteniendo nuestros propios caracteres.

Vamos a pintar un reloj.

Para ello, como no podía ser de otra manera, lo vamos a diseñar usando 0 y 1.

1000 DATA BIN 00011000
1010 DATA BIN 00011000
1020 DATA BIN 00100100
1030 DATA BIN 01011010
1040 DATA BIN 00100100
1070 DATA BIN 00011000
1080 DATA BIN 00011000
1090 DATA BIN 00000000
Parece nada, ¿verdad?. Pues ya verás que chulo queda. 


















La instrucción POKE USR, nos permite cargar desde la UDG-A hasta la UDG-U nuestros diseños, para luego usarlos con CHR$.

Este programa, lee el diseño, lo asigna al carácter 144 (UDG-A) y luego lo usa con un PRINT. 

Algo muy interesante, es que además, podemos usar INK, PAPER, FLASH y todas las zarandajas que nos permite el BASIC.

10 REM *Usando UDG de 1 caracter (8x8)
20 CLS : PRINT "Dos relojes": PRINT : RESTORE 1000
30 FOR I=0 TO 7
40 READ B
50 POKE USR "A"+I,B
60 NEXT I
70 PRINT CHR$ 144;" "; INK 3; FLASH 1;CHR$ 144; INK 8
80 INPUT "Pulsa para terminar";z$: GO TO 9000
1000 DATA BIN 00011000
1010 DATA BIN 00011000
1020 DATA BIN 00100100
1030 DATA BIN 01011010
1040 DATA BIN 00100100
1070 DATA BIN 00011000
1080 DATA BIN 00011000
1090 DATA BIN 00000000
9000 FLASH 0: PRINT AT 19,1;"Termine"

El reloj de la derecha, está parpadeando aunque aquí no lo veamos (hemos usado FLASH 1). 

Para usar nuestro reloj, es tan fácil como escribir PRINT CHR$ 144 en nuestro Spectrum.

Si haces un NEW, para escribir un programa nuevo, el gráfico permanecerá en memoria.



miércoles, 18 de noviembre de 2015

Haciendo uso (correcto) del Joystick desde BASIC. ZX Interface II.

¿Que sería de nuestros Spectrum sin un Joystick? 

Pues una fuente de frustración en muchos juegos y situaciones. 

Vamos a ver como hacer un uso efectivo de la entrada del Joystick desde el código BASIC. 

La mágica función INKEY$ nos deja leer las entradas del teclado y del mando en "tiempo real", pero, tiene un problema: 

¿Como identificamos que la palanca se ha girado a la derecha y que le hemos dado a disparar, a la vez?. 

Pues no podemos. 

Para hacer las cosas bien, tenemos que leer de los puertos del mando, directamente. Para ello, asignamos el valor del puerto del mando, a una variable usando IN. 

LET a = IN 61438
¿Sencillo, verdad?. Bueno tiene truco. 

La variable contendrá un valor numérico que representa una secuencia de bits. 

Dicha secuencia, tiene la información real de lo que ha pasado.

  • bit 0 : disparo 
  • bit 1 : arriba 
  • bit 2 : abajo
  • bit 3 : derecha 
  • bit 4 : izquierda 

Ah, otra cosa : 

  • El mando "1", se lee con IN 61438. 
  • El mando "2", se lee con IN 63486.

Como un ejemplo vale más que mil palabras, he aquí un sencillo programa de dibujo, que hace uso de lo que hemos explicado arriba.

1 REM  * Programa de dibujo *
5 CLS
10 REM *Posicion inicial en pantalla *
15 LET x=0: LET y=80
17 PRINT AT 19,1;"Pulsa Q para salir"
20 GO SUB 1000: REM * nos vamos a leer el puerto del mando 1*
30 IF disp=1 THEN PLOT x,y
40 GO TO 20
1000 IF INKEY$="Q" OR INKEY$="q" THEN GO TO 2000
1005 LET a=IN 61438
1010 IF a>127 THEN LET a=a-128
1020 IF a>63 THEN LET a=a-64
1030 IF a>31 THEN LET a=a-32
1040 IF a>15 THEN LET a=a-16: IF x<255 THEN LET x=x+1
1050 IF a>7 THEN LET a=a-8:     IF x>0 THEN LET x=x-1
1060 IF a>3 THEN LET a=a-4:     IF y<175 THEN LET y=y+1
1070 IF a>1 THEN LET a=a-2:     IF y<>0 THEN LET y=y-1
1080 LET disp=a
1090 RETURN
2000 CLS : PRINT AT 1,1;"Bye"
Si pulsas disparar, dejará de pintar, aunque se seguirá moviendo el cursor (invisible). 

Las mates son fáciles, vamos comprobando el valor de a, y vamos restando para sacar los valores de los bits que nos interesan. 

En la imagen, se ven las lineas rectas, porque he emulado la entrada del mando usando las teclas del teclado. 

No hay nada mejor que el olor a código por la mañana ;). 




















martes, 17 de noviembre de 2015

¡Centremos el texto, en pantalla!


He aquí una pequeña función para centrar el texto en pantalla, de manera muy sencilla.

10 CLS
20 REM * Centramos el texto en pantalla *
30 LET m$="Estoy centrado"
40 PRINT AT 1,FN c(m$);m$
50 LET m$="pero que muy centrado"
60 PRINT AT 3,FN c(m$);m$
90 REM * Funcion de centrado *
100 DEF FN c(m$)=INT ((32-LEN m$)/2)

He aquí lo importante :

40 PRINT AT 1,FN c(m$);m$
Llamada a la función con la cadena m$, que nos devuelve la posición que necesitamos para centrar el texto.
100 DEF FN c(m$)=INT ((32-LEN m$)/2)

Bueno, bonito y barato.


De BASIC a código máquina sin dolor


Pues he aquí, de las muchas opciones de compiladores de BASIC a código máquina, la que encuentro más sencilla de usar, y que menos complicaciones presenta. 

El susodicho compilador es el "Softek FP Full Compiler".

Pero ojo, que no lo usaremos en su versión "estándar", sino en la versión "debugged" realizada por Zeljko Juric en 1988

Este compilador, es muy sencillo de usar y en su versión depurada, además de tener varios fallos corregidos y optimizaciones realizadas, viene con el programa "FPLINK", el cual nos permitirá "linkar" nuestro código máquina con el "run time" del compilador. 

De esta forma, nuestro programa BASIC, una vez pasado a código máquina y "linkado", será independiente y lo podremos distribuir sin el compilador.


Seguro que hay mejores compiladores (seguro vamos, por que lo he mirado), pero he aqui las principales ventajas de este: 

  1. Soporta operaciones de Floating Point.
  2. Aunque tiene (pocas) directivas de compilación, no es necesario usarlas. Vamos, que es cargar el código BASIC y ponerte a compilar, sin más. 
  3. Funciona con el editor BASIC 128. Los muchos otros que he probado, te revierten al modo de edición del 48k. 
  4. Carga bastante rápido desde la cinta. (Si, yo soy de esos, trabajo con cintas). 
  5. Deja bastante memoria libre RAM para trabajar. 


Tiene inconvenientes como que no le gustan las funciones de usuario. 



lunes, 16 de noviembre de 2015

Detectar tipo Spectrum (128k/48k)

Hola.

Pequeña utilidad que nos da la información de que tipo de Spectrum es.

Detecta:

  1. Spectrum 48k.
  2. Spectrum 128k.
  3. Spectrum 128k en modo 48k. 


Bueno, bonito y barato.

10 CLS
20 IF (PEEK 75)<>110 THEN GO TO 90
40 LET x=INT (PEEK 23611/16)
50 LET y=128: LET z=128
60 IF x/2=INT (x/2) THEN LET z=48
70 PRINT AT 2,1;"Spectrum 128k ";"Modo/Mode ";z
80 GO TO 100
90 PRINT AT 2,1;"Spectrum 48k"
100 REM *Final



¿Cuanta memoria queda ?

Lastima que en nuestro querido Spectrum, no tenemos un comando BASIC que nos de la memoria libre que nos queda. 

Bueno, como no me gustan los toolkit de BASIC que lo traen (no encuentro ninguno compatible con el editor de los 128k), aquí tenéis como se calcula. 

PRINT AT 1,1;"Mem:";INT ((65535-USR 7962)/1024);"K"
Es decir, que USR 7962 nos da la utilizada hasta el momento. Dividimos entre 1024 la resta del total (65535) y lo redondeamos a un numero bonito.















Ahh, casi se me olvida. Podemos ponerlo en una bonita función de usuario,
para que quede mejor el código.

10 CLS
20 REM * Memoria libre *
100 PRINT AT 1,1;"Mem :";FN m();"k"
110 REM * Queda mas bonito *
200 DEF FN m()=INT ((65535-USR 7962)/1024

Recordar que hay compiladores a código máquina a los que no les gustan las funciones de usuario, y que, menos llamadas es mejor rendimiento en el Speccy ;)



Que usar para programar BASIC del Spectrum en tu PC.

Buena pregunta.

Hay opciones, pero yo uso BasinC 1.69.

Tiene casi todo lo necesario, es sencillo de usar , ayuda incorporada tanto del programa como del BASIC y gestor de cinta(s).

De la pagina del autor:

"Basin is a zx spectrum emulator combined developing environment for sinclair basic developers."

Está basado en un trabajo anterior de Paul Dunn, y funciona muy bien.

Lo puedes encontrar en la pagina de Ardan Erdikmen.