EL PROGRAMA
Ya está disponible para el sistema Kenbak-1S el clásico juego “Catch the Mole”, consistente en este caso en pulsar rápidamente la tecla con el número mostrado en el display. Los números están comprendidos entre el 1 y el 9.
Cada ronda se compone de 15 números, y superada la ronda se disminuye el tiempo disponible para pulsar la tecla. Con cada acierto se obtiene un punto y con cada fallo se pierde una de las tres vidas disponibles, indicadas en el lado derecho del display mediante unas barras horizontales.
Al perder todas las vidas se muestra la puntuación. Pulsa “B” para salir del juego o cualquier otra tecla para jugar una nueva partida.
El juego está programado en el lenguaje máquina del Kenbak-1 original, pero incorpora unas instrucciones CALL no disponibles en el equipo original, con lo que el juego solo funciona en este sistema.
El listado que se muestra a continuación se ha programado usando la base decimal, pero se ha codificado en octal, que es la forma habitual para programar el Kenbak-1.
Este juego viene preinstalado en el Kenbak-1S, con lo que se muestra el código fuente a modo informativo.
Para cargar elprograma en la memoria:
704D (Carga el programa preinstalado 4)
Para ejecutar el programa:
4D (Ejecuta a partir de la dirección 4)
Para detener el programa pulsa “B” [BREAK].
Descargar el código fuente y el código ensamblado:
LISTADO
Código fuente ensamblado
Código: Seleccionar todo
KENBAK-1S Assembler v1.00
(c) Scainet Soft, 2024
-PASS 1:
LINE : ADDRESS : LABEL
-----------------------------------
0004 : 004 (004) : INIT
0010 : 013 (011) : START
0014 : 017 (015) : RSTART
0031 : 044 (036) : LOOP
0043 : 065 (053) : PRESS
0053 : 103 (067) : CHECK
0057 : 107 (071) : FAIL
0064 : 117 (079) : HIT
0074 : 134 (092) : LEVEL
0083 : 151 (105) : END
0091 : 162 (114) : VARINI
0099 : 170 (120) : LIVES
0102 : 366 (246) : NUMERO
0103 : 367 (247) : ENEMIGO
0104 : 370 (248) : PUNTOS
0105 : 371 (249) : VIDAS
0106 : 372 (250) : RETRASO
0107 : 373 (251) : PANTALLA
-PASS 2:
LINE : ADDRESS : CODE : LABEL INST. PARAMETERS
----------------------------------------------------------------------------------------------------
0001 : 003 (003) : 004 : ORG 4
0002 :
0003 : ; Inicializar variables y display
0004 : 004 (004) : 023 162 : INIT LOAD A,VARINI
0005 : 006 (006) : 123 006 : LOAD B,6
0006 : 010 (008) : 223 370 : LOAD X,PUNTOS
0007 : 012 (010) : 300 : CALL COPYMEM
0008 :
0009 : ; Inicializar los enemigos restantes del nivel
0010 : 013 (011) : 023 017 : START LOAD A,15
0011 : 015 (013) : 034 367 : STORE A,(ENEMIGO)
0012 :
0013 : ; Calcular Char del número de vidas y mostrar display
0014 : 017 (015) : 224 371 : RSTART LOAD X,(VIDAS)
0015 : 021 (017) : 026 170 : LOAD A,(LIVES+X)
0016 : 023 (019) : 034 376 : STORE A,(254)
0017 : 025 (021) : 023 052 : LOAD A,42
0018 : 027 (023) : 034 374 : STORE A,(252)
0019 : 031 (025) : 223 373 : LOAD X,PANTALLA
0020 : 033 (027) : 210 : CALL PRTBUFX
0021 :
0022 : ; Pausa y decidir si ha finalizado el juego
0023 : 034 (028) : 023 372 : LOAD A,250
0024 : 036 (030) : 040 : CALL PAUSE
0025 : 037 (031) : 040 : CALL PAUSE
0026 :
0027 : 040 (032) : 024 371 : LOAD A,(VIDAS)
0028 : 042 (034) : 044 151 : JPZ A,END
0029 :
0030 : ; Calcular número de enemigo aleatorio entre 1 y 9
0031 : 044 (036) : 023 011 : LOOP LOAD A,9
0032 : 046 (038) : 120 : CALL RANDOM
0033 : 047 (039) : 034 366 : STORE A,(NUMERO)
0034 : 051 (041) : 034 374 : STORE A,(252)
0035 : 053 (043) : 223 373 : LOAD X,251
0036 : 055 (045) : 210 : CALL PRTBUFX
0037 : 056 (046) : 023 027 : LOAD A,23
0038 : 060 (048) : 050 : CALL PLAYNOTE
0039 :
0040 : ; Bucle esperando la pulsación de una tecla
0041 : 061 (049) : 124 372 : LOAD B,(RETRASO)
0042 : 063 (051) : 103 016 : ADD B,14
0043 : 065 (053) : 010 : PRESS CALL INKEY
0044 : 066 (054) : 372 000 : SKIP 1,7,(REGA)
0045 : 070 (056) : 344 103 : JP CHECK
0046 : 072 (058) : 023 005 : LOAD A,5
0047 : 074 (060) : 040 : CALL PAUSE
0048 : 075 (061) : 113 001 : SUB B,1
0049 : 077 (063) : 143 065 : JPNZ B,PRESS
0050 : 101 (065) : 023 377 : LOAD A,255
0051 :
0052 : ; Comprobar si se ha acertado el número
0053 : 103 (067) : 014 366 : CHECK SUB A,(NUMERO)
0054 : 105 (069) : 044 117 : JPZ A,HIT
0055 :
0056 : ; Restar una vida
0057 : 107 (071) : 023 371 : FAIL LOAD A,VIDAS
0058 : 111 (073) : 320 : CALL MEMDEC
0059 : 112 (074) : 023 033 : LOAD A,27
0060 : 114 (076) : 050 : CALL PLAYNOTE
0061 : 115 (077) : 344 017 : JP RSTART
0062 :
0063 : ; Restar un enemigo y sumar un punto
0064 : 117 (079) : 023 370 : HIT LOAD A,PUNTOS
0065 : 121 (081) : 310 : CALL MEMINC
0066 : 122 (082) : 023 367 : LOAD A,ENEMIGO
0067 : 124 (084) : 320 : CALL MEMDEC
0068 : 125 (085) : 023 031 : LOAD A,25
0069 : 127 (087) : 050 : CALL PLAYNOTE
0070 : 130 (088) : 024 367 : LOAD A,(ENEMIGO)
0071 : 132 (090) : 043 044 : JPNZ A,LOOP
0072 :
0073 : ; Se supera el nivel
0074 : 134 (092) : 023 017 : LEVEL LOAD A,15
0075 : 136 (094) : 050 : CALL PLAYNOTE
0076 : 137 (095) : 024 372 : LOAD A,(RETRASO)
0077 : 141 (097) : 044 013 : JPZ A,START
0078 : 143 (099) : 013 001 : SUB A,1
0079 : 145 (101) : 034 372 : STORE A,(RETRASO)
0080 : 147 (103) : 344 013 : JP START
0081 :
0082 : ; Final del juego
0083 : 151 (105) : 023 016 : END LOAD A,14
0084 : 153 (107) : 050 : CALL PLAYNOTE
0085 : 154 (108) : 024 370 : LOAD A,(PUNTOS)
0086 : 156 (110) : 220 : CALL PRTBYTE
0087 : 157 (111) : 020 : CALL PRESSKEY
0088 : 160 (112) : 344 004 : JP INIT
0089 :
0090 : ; Definir buffer con los valores iniciales de las variables
0091 : 162 (114) : 000 003 : VARINI DB 0,3
0092 : 164 (116) : 012 : DB 10
0093 :
0094 : ; Definir buffer con el contenido inicial del display
0095 : 165 (117) : 053 052 : DB 43,42
0096 : 167 (119) : 053 : DB 43
0097 :
0098 : ; Definir Buffer con los chars del número de vidas
0099 : 170 (120) : 052 054 : LIVES DB 42,44
0100 : 172 (122) : 055 063 : DB 45,51
0101 :
0102 : : : ALIAS NUMERO,246
0103 : : : ALIAS ENEMIGO,247
0104 : : : ALIAS PUNTOS,248
0105 : : : ALIAS VIDAS,249
0106 : : : ALIAS RETRASO,250
0107 : : : ALIAS PANTALLA,251
-SIZE: 120 BYTES
APUNTES FINALES
Este el el proyecto más especial de mi vida. A lo largo de 42 años he desarrollado más de 200 programas, pero es la primera vez que programo un juego en un ordenador diseñado por mi.
El equipo
Este equipo es 100% compatible con el Kenbak-1 original y los 8 LEDs disponibles nos permiten ver los resultados como en un Kenbak-1.
El equipo dispone de 256 bytes y el mapeado de la memoria es igual al del equipo original. De esta forma, las direcciones 000-003 contienen los registros A, B, X y P, respectivamente. Las direcciones 128-131 contienen el contenido de los 8 LEDs y los flags de los registro A, B y X. La dirección 255 contiene el valor del buffer del teclado. Lo habitual es usar la dirección 4 como primer byte del programa.
Esta distrubibución de la memoria es un problema ya que si el programa es muy largo, se debe partir en 2 partes para no “pisar” los bytes 128-131.
El programa ocupa un total de 120 bytes, usando 7 bytes más en la zona final de la memoria para almacenar ciertos valores.
Diferencias entre el Kenbak-1 y el Kenbak-1S
Una de las diferencias es el modo de entrada de los programas, mediante un teclado con 16 teclas. En el Kenbak-1 original los programas se introducen en binario, teniendo que pulsar “STORE” para almacenar un byte y a continuación pulsar la tecla “CLEAR” para inicializar la nueva entrada. Moverse por la memoria para ver su contenido tampoco es especialmente cómodo.
En este equipo las entradas se realizan introduciendo los bytes en octal o decimal, y se puede navegar por la memoria de una forma más rápida y cómoda mediante las teclas “*”, “#” y “A”.
La segunda diferencia que salta a la vista es la presencia de un display de 4 dígitos al que se puede acceder mediante la codificación de unas instrucciones exclusivas de este equipo. Cada una de estas intrucciones, llamadas CALL, acceden a unas rutinas que permiten el acceso al display, lectura del teclado, acceso al sonido y otras funciones que nos simplifican la programación y nos permiten ahorrar muchos bytes. Por ejemplo, con CALL RANDOM (120) deja en el registro A un número aleatorio entre 1 y el valor del registro A.
Otra diferencia es que el Kanbak-1S incorpora un buzzer con el que podemos reproducir sonidos y notas musicales. Hay dos rutinas CALL para reproducir la nota o frecuencia almacenada en el registro A durante B milisegundos.
El Kenbak-1S permite grabar y cargar hasta 4 programas de 256 bytes de la memoria EEPROM disponible en la placa del Arduino Nano. También permite formatear esta memoria. De forma nativa, el equipo se proporciona con 12 programas más o menos complejos, a modo de ejemplo de funcionamiento.
Para ayudar a la depuración de programas, el Kenbak-1 incorpora un debug por el puerto USB del Arduino Nano. De esta forma podemos ver la línea en ejecución, con su mnemotécnico correspondiente y el valor de los distintos registros en octal y decimal. La ejecución en modo debug ralentiza la ejecución del programa. Se recomienda usar el programa PuTTY para acceder al debug.
En breve publicaré un post detallando todas las características de este equipo.
El juego
Este es mi primer juego y la verdad es que es bastante complejo programar con el código máquina del Kenbak-1 y después codificarlo en octal. En breve publicaré un ensamblador adaptado a las características de este equipo, especialmente por el tema de las rutinas CALL. Este ensamblador es un programa en C que funciona a partir del ensamblador que incorpora la versión Kenbak-8801.
Por el resto, el uso de las rutinas CALL ha permitido simplificar mucho el código, ya que obtener un número realmente aleatorio ocupa solo 3 bytes y se devuelve en el registro A. En el equipo original se debería programar una rutina específica para ello.
Con otras rutinas podemos leer el teclado, ya sea capturando la pulsación de una tecla, o esperando a que se pulse. En ambos casos esta acción solo requiere de un byte y el resultado se devuelve en el registro A.
El sonido permite reproducir una nota con 5 bytes si queremos especificar la duración, o solo 3 si queremos una duración de 100 ms o 200 ms, añadiendo 10 o 20 al número de nota. Hay un total de 14 notas disponibles.
Para el display tenemos varias rutinas que permiten mostrar valores numéricos o usar un buffer de 4 bytes donde almacenamos los caracteres que se han de mostrar.
Al final, el juego funciona perfectamente, teniendo una dificultad bastante alta, pero no imposible. Se puede modificar la dificultad modificando un par devalores del programa.
¿Y como se juega a este juego?
Pues aquí está la gracia !!!
Estoy preparando el diseño de la placa para hacer una tirada para que todo el que quiera tener este equipo pueda tenerlo a precio de coste, que no debería ser muy alto. Estoy hablando de unos 25€/30€, si no menos.
En breve publicaré un post para que las personas interesadas en el equipo lo puedan pedir.
Pues nada más, solo me queda…
Invitaros a probarlo… cuando podáis
Aparece un 4. Pulsa la tecla rápidamente !!!
Ahora aparece un 9, pero ya hemos perdido una vida.
Fin de partida. Hemos conseguido 37 puntos.