Apple-1 monitor para ZX-81

dancresp
Mensajes: 4991
Registrado: 13 Nov 2010 02:08
Agradecido : 14 veces
Agradecimiento recibido: 83 veces

Apple-1 monitor para ZX-81

Mensajepor dancresp » 29 Nov 2016 23:52

Apple1_Screen_2.gif
Apple1_Screen_2.gif (77.72 KiB) Visto 624 veces


UN POCO DE HISTORIA
El Apple-1 fue uno de los primeros ordenadores personales, y el primero en combinar la placa base con una conexión para un teclado y un monitor externos, en unos tiempos en que los ordenadores se relacionaban con un panel lleno de luces e interruptores. Esto lo hizo innovador para su tiempo. Fue diseñado y construido a mano por Steve Wozniak, originalmente para su uso personal. Su amigo Steve Jobs tuvo la idea de vender el ordenador.

Fue el primer producto de Apple, presentado en abril de 1976 en el Homebrew Computer Club en Palo Alto, California.

Algunos de los asistentes estaban seguros de que la máquina no era más que un terminal portátil, conectado por una línea de teléfono a un mainframe oculto en alguna parte. Más tarde, durante la demostración de productos, el Apple-1 causó sensación entre los otros distribuidores presentes.

Apple_I.jpg
Apple_I.jpg (34.22 KiB) Visto 624 veces


Su sistema operativo ocupa 256 bytes, alojados en la zona final de la memoria RAM ($FF00-$FFFF), y contenidos en dos chips PROM de 256 bytes x 4 bits cada uno. Gracias a él podemos leer o modificar la memoria y ejecutar programas.

monitor_1.gif
monitor_1.gif (36.98 KiB) Visto 624 veces


EL PROGRAMA
Este proyecto ha consistido en reproducir en un ZX-81 un programa monitor que funcione igual y ocupe lo mismo que el original del Apple-I.

Para ello hay que cargar el programa y pulsar RUN. En este momento la pantalla queda en blanco a la espera de que se entre los comandos y se pulse "Enter".

Las líneas pueden tener hasta 28 caracteres, lo que permite introducir un dirección de 4 dígitos y 8 valores de 2 dígitos separados por un espacio.

La versión distribuida es para un equipo con 1 KB y hace volcados de la memoria en 4 columnas, pero si se dispone de un equipo con más memoria se puede introducir POKE 16530,8 para tener volcados de 8 columnas.

Descargar el programe en formato ".P":
Apple-1_monitor.rar
(497 Bytes) Descargado 28 veces


Comandos del monitor
El programa monitor dispone únicamente de 4 comandos que nos permiten indicar una dirección por defecto o "dirección activa", volcar el contenido de la memoria por pantalla, introducir valores en la memoria o ejecutar el código introducido.

Dirección_Memoria
Al introducir una dirección de memoria y pulsar "ENTER" el sistema nos mostrará el contenido de la dirección indicada. Esta dirección se guarda como "dirección activa".

.
Formato: Dirección_Ini.Direccion_Fin

El punto provoca un volcado de memoria desde la dirección inicial hasta la dirección final. La dirección inicial queda como la "dirección activa".

:
Formato: [Dirección_Ini]:Valor_1 Valor_2 Valor_3 ...

Los dos puntos indican que los valores introducidos a continuación se han de ir guardando en la memoria a partir de la dirección indicada. Cada valor debe ir separado del siguiente por un espacio. La dirección inicial es opcional ya que por defecto coge la "dirección activa". La última dirección de memoria usada queda como la "dirección activa".

R
Formato: [Dirección]R

El comando “R” provoca que se ejecute desde la dirección indicada. La dirección activa es opcional ya que por defecto coge la "dirección activa".


Mapa de memoria
El programa monitor ocupa 256 bytes y usa los 33 bytes del búffer de la impresora como búffer de entrada y para almacenar un par de valores que se usan para que funcione correctamente.

16444 ($403C) - 16471 ($4057): Bloque de 28 bytes usado como búffer de entrada de comandos.
16473 ($4059) - 16475 ($405B): Bloque de 3 bytes para datos del monitor.
16514 ($4082) - 16769 ($4181): Bloque de 256 bytes que contiene el programa monitor.
16770 ($4182) - 16833 ($41C1): Bloque de 64 bytes disponibles para el usuario.

A partir de la dirección 16834 ($41C2) se encuentra la memoria de vídeo, que crece a medida que se va llenando la pantalla, y puede ser modificada desde el propio monitor.

Del bloque de los 64 bytes disponibles, una parte corresponden a la línea 2 que contiene un REM y un texto, y el resto a la línea 10, que contiene la llamada USR al propio programa monitor. Si se usa esta parte y se vuelve al BASIC por algún error, la línea estará corrupta.


Ejemplo de funcionamiento
Para ver como funciona el monitor, muestro un ejemplo con el que podremos entrar valores en la memoria, verificar su contenido y ejecutar el programa entrado. Este programa muestra el texto contenido en el REM de la línea 2.

El programa es este:

Código: Seleccionar todo

0E27      LD C,39
218841   LD HL,16776
7E      NEXT   LD A,(HL)
D7      RST $10
23      INC HL
0D      DEC C
20FA      JR NZ,NEXT
C9      RET


Se debe introducir tal como indica en la imagen.

Ejemplo.gif
Ejemplo.gif (27.23 KiB) Visto 624 veces


Pasos seguidos:
1.- Primero se introducen los valores a partir de $41B0.
2.- Se vuelca el contenido de la memoria para revisar errores.
3.- Se ejecuta el código introducido.


Precauciones
En general el programa monitor funciona sin ningún problema, pero hay un par de temas a tener en cuenta.

1.- Si se pulsan letras, números y caracteres normales todo funciona bien, pero si se pulsa una tecla correspondiente a un comando o "Rubout", al menos el emulador se vuelve loco. Esto no lo he probado en el ZX-81 real.

2.- Si se introduce una rutina y se ejecuta e imprime algo en pantalla que ocupa más de una línea, mi rutina de control no la contabilizará y al llegar al final de la pantalla provocará un error 5. Si no se ha corrompido la línea del USR, se puede volver a entrar al monitor con RUN sin perder el contenido introducido.


Diferencias con el monitor del Apple-I
En general el funcionamiento es idéntico al del Apple-I, pero por temas de hardware y supongo que por diferencias entre el código máquina del Z80 y el 6502, hay algunas diferencias que comento a continuación.

- El Apple-I dispone de 40 caracteres por línea y 24 filas, y aquí solo hay disponibles 32 caracteres por línea y 21 filas.
- No aparece un cursor, ya que en el Apple-I tanto la entrada como salida de datos se gestiona por hardware. No he tenido más memoria para implementarlo.
- El volcado de memoria del Apple-I muestra 8 bytes por línea. En la versión 1K se ha reducido a 4 bytes por línea, pero con un POKE se puede hacer cambiar a 8 bytes en sistemas con más memoria.
- La línea de entrada se limita a 28 caracteres. En Apple-I permite hasta 255.
- No se pueden borrar caracteres introducidos. Aunque en el original si se permite pero no se ve reflejado en pantalla, en esta versión no se puede hacer. Al pulsar "Enter" se ejecutará hasta encontrar un dato erróneo.
- Las direcciones de memoria se deben introducir con 4 dígitos hexadecimales y los datos con 2 dígitos, rellenando con 0 por la izquierda. En el original no es necesario.
- Al finalizar la ejecución de un comando el Apple-I realiza un salto de línea más en pantalla que esta versión.

Imagen

LISTADO
El programa monitor se ha programado íntegramente en ensamblador de Z80.

Descargar código fuente en formato ".txt":
Apple-1_Source.rar
(3.11 KiB) Descargado 18 veces


Código: Seleccionar todo

[font=Courier New]
       ***************************************************************************************************
       *                            INICIO DEL PROGRAMA MONITOR                              *
       ***************************************************************************************************
      ORG 16514

CSR_Y   DB en 16473                  ; Fila en pantalla
DIRINI   DW en 16474                  ; Dirección inicial
      
       ***************************************************************************************************
       PRTHEX - 16514 (#4082) - 15 bytes
       Imprime en formato hexadecimal un valor de 8 bits indicado en el registro A.
       ***************************************************************************************************
PRTHEX   LD B,A            47         ; Guarda valor de A en B
      RRCA            0F         ; Rota bits a la derecha
      RRCA            0F         ; Rota bits a la derecha
      RRCA            0F         ; Rota bits a la derecha
      RRCA            0F         ; Rota bits a la derecha
      CALL PRTHJ1         CD8B40      ; Llama a la parte que imprime el dígito en hexadecimal
      LD A,B            78         ; Recuperar el valor inicial de A, guardado en B
PRTHJ1   AND 15            E60F      ; Se anulan los 4 bits más altos, quedando un valor entre 0 y 15
      ADD 28            C61C      ; Se suma 28 para que coincida con su CHR$
      RST $10            D7         ; Llama a la rutina PRINT de la ROM
      RET               C9         ; Final de la subrutina

       ***************************************************************************************************
       DUMP - 16529 (#4091) - 36 bytes
       Hace un volcado en formato hexadecimal de los bytes comprendidos entre las direcciones HL y DE.
       Cada linea empieza mostrando la dirección y a continuación tantas columnas como indique C.
       ***************************************************************************************************
DUMP   LD C,4            0E04      ; Carga en C el número de columnas del DUMP.
      LD A,H            7C         ; Carga en A el byte alto de la dirección inicial
      CALL PRTHEX         CD8240      ; Llamada a la rutina PRTHEX
      LD A,L            7D         ; Carga en A el byte bajo de la dirección inicial
      CALL PRTHEX         CD8240      ; Llamada a la rutina PRTHEX
      LD A,14            3E0E      ; Carga en A el código CHR$ de los dos puntos ":"
      RST $10            D7         ; Se llama a la rutina PRINT de la ROM
      SUB A            97         ; Pone a 0 el registro A, para que quede como el CHR$ del espacio " "
      RST $10            D7         ; Se llama a la rutina PRINT de la ROM
DUMPJ1   LD A,(HL)         7E         ; Carga en A el valor de la dirección inicial
      CALL PRTHEX         CD8240      ; Llamada a la rutina PRTHEX
      SUB A            97         ; Pone A a 0 restando su valor a si mismo
      RST $10            D7         ; Se llama a la rutina PRINT de la ROM
      INC HL            23         ; Incrementa el valor de la dirección inicial
      SCF               37         ; Pone el flag Carry a 1
      PUSH HL            E5         ; Guarda en el stack el registro HL
      SBC HL,DE         ED52      ; Resta a HL el valor de DE
      POP HL            E1         ; Recupera del stack el registro HL
      RET NC            D0         ; Retorna si el flag Carry está a 1, cuando DE>HL
      DEC C            0D         ; Decrementa en uno el registro C
      JR NZ,DUMPJ1      20F0      ; Si el registro C>0 salta a DUMPJ1
      CALL CR+LF         CD3C41      ; Llamada a rutina que controla el salto de linea
      JR DUMP            18DC      ; Salta al principio de la subrutina

       ***************************************************************************************************
       NUMBER - 16565 (#40B5) - 34 bytes
       Verifica si dos caracteres del búffer de entrada contienen un valor hexadecimal válido.
       La dirección actual del búffer de entrada debe estar en el registro HL.
       Si el valor es correcto se guarda en A y pone C a 1. Si es incorrecto pone C a 0.
       ***************************************************************************************************
NUMBER   LD C,0            0E00      ; Pone el registro C a 0.
      LD A,(HL)         7E         ; Carga en A el valor del carácter de la linea
      CP 28            FE1C      ; Compara A con 28
      RET C            D8         ; Si A<28 (CHR$ "0") sale de la subrutina con C=0
      CP 44            FE2C      ; Compara A con 44
      RET NC            D0         ; Si A>=44 (CHR$ "G") sale de la subrutina con C=0
      SUB 28            D61C      ; Resta 28 a A para que coincida con un CHR$ válido en hexadecimal
      RLCA            07         ; Rota bits a la izquierda
      RLCA            07         ; Rota bits a la izquierda
      RLCA            07         ; Rota bits a la izquierda
      RLCA            07         ; Rota bits a la izquierda
      AND 240            E6F0      ; Se anulan los 4 bits más bajos
      LD B,A            47         ; Guarda el valor de A en B
      INC HL            23         ; Incrementa el puntero al búffer de entrada, guardado en HL
      LD A,(HL)         7E         ; Carga en A el valor del búffer de entrada
      CP 28            FE1C      ; Compara A con 28
      RET C            D8         ; Si A<28 (CHR$ "0") sale de la subrutina con C=0
      CP 44            FE2C      ; Compara A con 44
      RET NC            D0         ; Si A>=44 (CHR$ "G") sale de la subrutina con C=0
      SUB 28            D61C      ; Resta 28 a A
      AND 15            E60F      ; Anula los 4 bits más altos
      ADD B            80         ; Suma a A el valor de B
      INC C            0C         ; Incrementa C en 1 para ponerlo a 1
      INC HL            23         ; Incrementa la dirección del búffer de entrada
      RET               C9         ; Final de la subrutina

       ***************************************************************************************************
       WORD - 16599 (#40D7) - 14 bytes
       Verifica si cuatro caracteres del búffer de entrada contienen un valor hexadecimal válido.
       La dirección actual del búffer de entrada debe estar en el registro HL.
       Si el valor es correcto se guarda en DE y pone C a 1. Si es incorrecto pone C a 0.
       ***************************************************************************************************
WORD   CALL NUMBER         CDB540      ; Llama a la rutina que verifica dos dígitos hexadecimales
      LD D,A            57         ; Guarda en D el resultado devuelvo en A
      LD A,C            79         ; Carga en A el registro C, que indica si el valor es correcto
      CP 0            FE00      ; Compara A con 0
      RET Z            C8         ; Sale de la subrutina si el código hexadecimal no es válido
      CALL NUMBER         CDB540      ; Llama a la rutina que verifica dos dígitos hexadecimales
      LD E,A            5F         ; Guarda en E el resultado devuelto en A
      LD A,C            79         ; Carga en A el registro C, que indica si el valor es correcto
      RET               C9         ; Final de la subrutina

       ***************************************************************************************************
       PARSER - 16613 (#40E5) - 87 bytes
       Analiza la linea de entrada y va ejecutando los comandos que identifica.
       Si hay algún comando incorrecto finaliza el análisis.
       ***************************************************************************************************
PARSER   CALL WORD         CDD740      ; Llama a la subrutina WORD para analizar los primeros 4 caracteres
      CP 1            FE01      ; Compara el valor de A con 1
      LD A,(HL)         7E         ; Carga en A el carácter del búffer de entrada
        JR Z,PARSJ2         2809        ; Saltar a PARSJ2 si es un número
PARSJ1  CP 14  - ":"        FE0E        ; Compara A con 14, que es el CHR$ de los ":"
      JR Z,PARSJ4         2826      ; Salta a PARSJ4 si son los dos puntos
        CP 55  - "R"        FE37        ; Compara A con 55, que es el CHR$ de "R"
      JR Z,PARSJ7         283E      ; Salta a PARSJ7 si es la letra "R"
        RET                 C9          ; Final de la subrutina

PARSJ2   LD (16474),DE      ED535A40   ; Guarda como "dirección inicial" el valor de DE
      CP 0   - " "      FE00      ; Compara A con 0, que es el CHR$ de espacio
      JR Z,PARSJ3         280B      ; Salta a PARSJ3 si hay un espacio
      CP 27  - "."      FE1B      ; Compara A con 27, que es el CHR$ del "."
      JR NZ,PARSJ1      20EB      ; Salta a PARSJ1 si no es un punto
      INC HL            23         ; Incrementa la dirección del búffer de entrada
      CALL WORD         CDD740      ; Llama a la subrutina WORD para analizar los siguientes 4 caracteres
      CP 0            FE00      ; Compara el valor de A con 0
      RET Z            C8         ; Final de la subrutina si no es un valor hexadecimal de 16 bits
PARSJ3   PUSH HL            E5         ; Guarda HL en el stack
      LD HL,(16474)      2A5A40      ; Carga en HL el valor de "dirección inicial"
      CALL DUMP         CD9140      ; Llama a la rutina DUMP
      POP HL            E1         ; Recupera del stack el registro HL
      INC HL            23         ; Incrementa la dirección del búffer de entrada
      CALL CR+LF         CD3C41      ; Llama a la rutina CR+LF para saltar de linea
      JR PARSER         18CE      ; Salta a PARSER para seguir analizando el búffer de entrada
      
PARSJ4  INC HL            23         ; Incrementa la dirección del búffer de entrada
      CALL NUMBER         CDB540      ; Llama a NUMBER para ver si es un valor hexadecimal de 8 bits
      LD D,A            57         ; Carga en D el valor de A
      LD A,C            79         ; Carga en A el valor de C
      CP 1            FE01      ; Compara A con 1
      JR Z,PARSJ6         2806      ; Salta a PARSJ6 si el valor hexadecimal es correcto
PARSJ5   LD DE,(16474)      ED5B5A40   ; Carga en DE el valor de "dirección inicial"
      JR PARSJ3         18E2      ; Salta a PARSJ3 para mostrar la "dirección inicial" y su valor
PARSJ6   PUSH HL            E5         ; Guarda HL en el stack
      LD HL,(16474)      2A5A40      ; Carga en HL el valor de la "dirección inicial"
      LD (HL),D         72         ; Guarda en la "dirección inicial" el valor de D
      INC HL            23         ; Incrementa el valor de la "dirección inicial"
      LD (16474),HL      225A40      ; Guarda el valor de la "dirección inicial"
      POP HL            E1         ; Recupera del stack el valor de HL
      JR PARSJ4         18E4      ; Salta a PARSJ4 para seguir analizando el búffer de entrada
      
PARSJ7   LD HL,(16474)      2A5A40      ; Carga en HL el valor de la "dirección inicial"
      LD (16698),HL      223A41      ; Guarda en la posición 16705 el valor de HL
      CALL <16698>      CD0000      ; Hace un CALL al valor de la dirección de HL

       ***************************************************************************************************
       CR+LF - 16700 (#413C) - 20 bytes
       Hace un salto de linea en pantalla y si se ha llegado a la fila 21 hace un Scroll del contenido.
       ***************************************************************************************************
CR+LF   LD A,118         3E76      ; Carga en A el código de salto de linea
      RST $10            D7         ; Llama a la rutina PRINT de la ROM
      EXX               D9         ; Guarda los registros en los registros alternativos
      LD HL,16473         215940      ; Carga en HL la dirección donde se guarda la fila de pantalla
      LD A,(HL)         7E         ; Carga en A el valor de la fila
      CP 21            FE15      ; Compara A con 21
      JR Z,SCROJ1         2803      ; Si la fila es 21 salta a SCROJ1
      INC (HL)         34         ; Incrementa la fila
      EXX               D9         ; Recupera los registros de los registros alternativos
      RET               C9         ; Final de la subrutina
SCROJ1   CALL 3086         CD0E0C      ; Llama a la rutina SCROLL de la ROM
      EXX               D9         ; Recupera los registros de los registros alternativos
      RET               C9         ; Final de la subrutina
      
       ***************************************************************************************************
       INPUT - 16720 (#4150) - 50 bytes
       Entrada de la linea de comandos por teclado.
       Se usa HL como puntero al búffer, delay en la lectura de teclas y para controlar la longitud de
       la linea de entrada.
       ***************************************************************************************************
INPUT   LD HL,16444         213C40      ; Carga en HL la dirección de inicio del búffer de entrada
      PUSH HL            E5         ; Guarda HL en el stack

INPUJ1   PUSH HL            E5         ; Guarda HL en el stack
INPUJ2   DEC HL            2B         ; Decrementa el valor de HL. Inicio de un delay del teclado.
      LD A,H            7C         ; Carga en A el valor de L
      RRA               1F         ; Rota a la derecha el registro A
      OR L            B5         ; Hace un OR con el valor de H
      JR NZ,INPUJ2      20FA      ; Salta a INPUJ2 si no es 0

INPUJ3   CALL 699         CDBB02      ; Llama a la rutina KEYBOARD de la ROM
      LD B,H            44         ; Carga en B el valor de H
      LD C,L            4D         ; Carga en C el valor de L
      LD D,C            51         ; Carga en D el valor de C
      INC D            14         ; Incrementa D para que afecte al flag Z
      JR Z,INPUJ3         28F7      ; Si es 0 salta a INPUJ3 porque no se ha pulsado ninguna tecla
      CALL 1981         CDBD07      ; Llama a la rutina DECODE de la ROM
      LD A,(HL)         7E         ; Carga en A la tecla pulsada en formato CHR$
      POP HL            E1         ; Recupera del stack el valor de HL
      LD (HL),A         77         ; Guarda la tecla pulsada en la posición del búffer de entrada
      CP 118            FE76      ; Compara A con 118, que es el código de "Enter" (o salto de linea)
      JR Z,INPUJ4         2807      ; Si se ha pulsado "Enter" salta a INPUJ4
      RST $10            D7         ; Llama a la rutina PRINT de la ROM
      INC HL            23         ; Incrementa la posición del búffer de entrada, guardada en HL
      LD A,L            7D         ; Carga en A el valor de L. Controlamos el número de caracteres.
      CP 89            FE59      ; Compara A con 89 para calcular el número de caracteres
      JR NZ,INPUJ1      20DF      ; Si el búffer no tiene 24 caracteres salta a INPUJ1
INPUJ4   SUB A               97          ; Pone a 0 el registro A, para que quede como el CHR$ del espacio " "
        LD (HL),A           77          ; Guarda el valor de A en la posición del búffer de entrada
        INC HL              23          ; Incrementa la posición del búffer de entrada, guardada en HL
        LD (HL),A           77          ; Guarda el valor de A en la posición del búffer de entrada
        CALL CR+LF         CD3C41      ; Llama a la rutina que hace un salto de linea en pantalla
      POP HL            E1         ; Recupera del stack el valor de HL
      CALL PARSER         CDE540      ; Llama a la rutina que analiza la linea de comandos
      JR INPUT         18CE      ; Salta a INPUT para entrar una nueva linea de comandos
[/font]


APUNTES FINALES
Hasta finales del año 2015, el ordenador Apple-I era un perfecto desconocido para mi. Sabía de su existencia y de cómo cotizaba, pero no tenía ni idea de su funcionamiento ni de sus características técnicas. Así que decidí hacer un análisis mediante el emulador “Pome1. Me quedé maravillado.

A parte de todo el trabajo técnico desarrollado por Steve Wozniak, un auténtico “crack”, y su simpático BASIC de 4 KB, lo que más me llamó la atención fue que su sencillo sistema operativo solo ocupa 256 bytes. Es muy básico, pero es sencillo de usar y perfectamente funcional.


El reto
A mi, que me va esto de intentar hacer desarrollos en el mínimo espacio posible, me pareció un reto de lo más interesante.

Y para intentar reproducir en lo posible las penurias que en su día debió sentir el gran Steve Wozniak, el programa ocupa lo mismo que el original y el ensamblado se ha hecho a mano, con papel, bolígrafo y una tabla de mnemotécnicos del Z80. Todo esto teniendo en cuenta que nunca había programado nada en ensamblador en el ZX-81, excepto alguna sencilla rutina hace más de 30 años.

En este punto ha empezado una auténtica pesadilla, que me ha ocupado mi tiempo libre durante casi una semana. Si, es quizás el desarrollo más pequeño al que he dedicado más tiempo. Cualquier optimización en el código ha supuesto tener que revisar todos los saltos y llamadas del programa, y volver a introducir total o parcialmente todos los valores hexadecimales. Y todo en un equipo con 1 KB, que iba mostrando errores de memoria cada dos por tres.

Los efectos secundarios han sido similares a los que se tiene cuando juegas mucho al Tetris, solo que en lugar de ver fichas cayendo, veía líneas con mnemotécnicos, incluso paseando entre viñedos... o mientras dormía. Realmente agotador.

Afortunadamente el emulador “EightyOne” me ha facilitado algunas cosas, pudiendo grabar snapshots antes de ejecutar el programa y usando su depurador para averiguar el porque de algunos fallos en su funcionamiento.


El desarrollo
Todo el proceso de desarrollo ha consistido en programar una rutina en papel, ensamblarla a mano, probarla y si funcionaba, intentar optimizarla al máximo y escribirla en el editor Notepad++ para tenerlo “en bonito”.

La primera rutina consistió en mostrar el valor del registro A en formato hexadecimal. Conseguido, me animó a programar la rutina del volcado, que al igual que la anterior, funcionaron casi a la primera. Al llegar a la rutina que controla la fila en la que estamos printando en pantalla llegó el primer problema con la rutina de SCROLL, que no funcionaba. Para no encallarme la deje para algo posterior, siendo al final un problema al contar los bytes a saltar por un salto relativo.

A partir de aquí, la cosa se fue acelerando y la memoria llenando, dando como resultado las rutinas que convertían los valores hexadecimales en valores numéricos, ya fueran de 2 o 4 dígitos, en un proceso inverso al primero que desarrollé.

Mediante un programa en BASIC introducía comandos en el búffer de la impresora y desarrollé una primera versión de la rutina que interpretaba los comandos, y funcionó bastante bien a la primera, pero después a sufrido varias modificaciones. La última de ellas me llevó a reescribir gran parte al conseguir varios bytes optimizando el código.

Y para terminar dejé la rutina que permite la entrada de comandos, ya que entre otras cosas no tenía ni idea de cómo acceder al teclado, cosa que fue más simple de lo que me esperaba, pero que por problemas de espacio me dio muchos dolores de cabeza.

Sea como sea, al final el programa funciona y básicamente tiene un funcionamiento igual al monitor original del Apple-I.

Y como residuos quedan multitud de hojas llenas de rutinas escritas en bolígrafo, y muchas, muchas correcciones.

Borrador_1.jpg
Borrador_1.jpg (19.48 KiB) Visto 624 veces


Que se queda en el tintero
Me habría gustado incorporar un cursor, poder limitar los caracteres a entrar y poder corregir los errores en la entrada.
También me habría gustado poder añadir algún salto de línea más al ejecutar un comando y acelerar un poco la velocidad del teclado.


Para terminar
La experiencia ha sido agotadora, pero en el fondo he disfrutado como un loco. Y si bien me he quedado descansado al finalizar el desarrollo, mucho me temo que será el primero de otros programas en ensamblador.

El programa monitor se ha desarrollado íntegramente en el emulador “EightyOne” de Windows, y posteriormente lo he podido usar sin problema en un ZX-81 real y en el core del ZX-81 del ZX-UNO.


Os invito a probarlo.
Adjuntos
monitores.gif
monitores.gif (32.73 KiB) Visto 290 veces

Radastan
Mensajes: 101
Registrado: 09 Sep 2016 11:32
Agradecido : 5 veces
Agradecimiento recibido: 8 veces

Re: Apple-1 monitor para ZX-81

Mensajepor Radastan » 30 Nov 2016 12:10

- plas - plas - plas - plas - plas - plas - plas - plas -

¡Bravo! Me encantan estos pequeños proyectos, te hacen ver los ordenadores de 8 bits de otra forma.

Avatar de Usuario
wilco2009
Mensajes: 1630
Registrado: 07 Ene 2013 16:48
Ubicación: Valencia
Agradecido : 39 veces
Agradecimiento recibido: 88 veces

Re: Apple-1 monitor para ZX-81

Mensajepor wilco2009 » 30 Nov 2016 12:14

En dos palabras, IM PRESIONANTE.

¡Estupendo trabajo!
"Nada viaja a mayor velocidad que luz con la posible excepción de las malas noticias las cuales obedecen a sus propias leyes."

Douglas Adams. Guía de autoestopista galáctico.

Avatar de Usuario
Chema
Mensajes: 1514
Registrado: 21 Jun 2012 20:13
Ubicación: Gijón
Agradecido : 408 veces
Agradecimiento recibido: 180 veces
Contactar:

Re: Apple-1 monitor para ZX-81

Mensajepor Chema » 30 Nov 2016 16:38

Increíble! Enhorabuena!

Avatar de Usuario
eltargui
Mensajes: 197
Registrado: 06 Feb 2014 18:38
Agradecido : 20 veces
Agradecimiento recibido: 23 veces

Re: Apple-1 monitor para ZX-81

Mensajepor eltargui » 30 Nov 2016 20:42

Anda, y esa dedicatoria!!!.....no me habia dado cuenta. Y con Steve Wozniak.. -shock
Me sobreestimas. Me queda mucho para poder hacer algo parecido a los programas que tu haces, si es que alguna vez llego.

Muchas gracias por el mensaje y por tus aportaciones. Desde luego me anima a seguir descubriendo cosas de esta pequeña gran maquina -drinks

dancresp
Mensajes: 4991
Registrado: 13 Nov 2010 02:08
Agradecido : 14 veces
Agradecimiento recibido: 83 veces

Re: Apple-1 monitor para ZX-81

Mensajepor dancresp » 30 Nov 2016 23:13

eltargui escribió:Anda, y esa dedicatoria!!!...

Bueno, eres de estos nombres que se asocian a un sistema, como chema o silicebit al Oric, floppysoftware al PCW o pser1 al Dragon, entre otros, así que... merecida.

Al resto, gracias !!! -drinks

Avatar de Usuario
apple2man
Mensajes: 257
Registrado: 03 Jun 2011 13:53
Agradecimiento recibido: 4 veces

Re: Apple-1 monitor para ZX-81

Mensajepor apple2man » 02 Dic 2016 17:12

Me ha encantado este trabajo, un reto terrible!! Has buscado rizar el rizo.

Una preguntilla me viene a la cabeza. Cuando pasas código del 6502 al Z80, la tendencia en referencia a lo que ocupa ¿es a crecer o a decrecer?
Dicho de otra manera:
Para hacer lo mismo ¿crees que se necesita menos código en el Z80? indudablemente tiene instrucciones más poderosas.

¿Cuál ha sido tu experiencia al respecto?

Un abrazo!

Avatar de Usuario
Chema
Mensajes: 1514
Registrado: 21 Jun 2012 20:13
Ubicación: Gijón
Agradecido : 408 veces
Agradecimiento recibido: 180 veces
Contactar:

Re: Apple-1 monitor para ZX-81

Mensajepor Chema » 02 Dic 2016 20:51

En mi experiencia el código 6502 es siempre más grande que el equivalente en z80, pero imagino que aquí habrá que tener en cuenta las peculiaridades del zx81, que desconozco, pero me suena que hay que hacerlo todo muy a mano.

Que nos ilumine dancresp :)

dancresp
Mensajes: 4991
Registrado: 13 Nov 2010 02:08
Agradecido : 14 veces
Agradecimiento recibido: 83 veces

Re: Apple-1 monitor para ZX-81

Mensajepor dancresp » 03 Dic 2016 00:53

apple2man escribió:Una preguntilla me viene a la cabeza. Cuando pasas código del 6502 al Z80, la tendencia en referencia a lo que ocupa ¿es a crecer o a decrecer?
Dicho de otra manera:
Para hacer lo mismo ¿crees que se necesita menos código en el Z80? indudablemente tiene instrucciones más poderosas.

He realizado este proyecto sin consultar para nada el código original en 6502, ya que es un código máquina que "casi" desconozco, a pesar de haber programado un ensamblador para él en el Oric.

Mediante el emulador de Apple-I "pome1" probé como funcionaba y me he limitado a hacer un programa que funcionara igual, y sobretodo, ocupara lo mismo.

A pesar de mis limitados conocimientos en 6502, si que tengo el convencimiento de que el Z80 tiene un juego de instrucciones bastante más potente, en general, y yo diría que en menos líneas haces más. Cosa que no quiere decir que ocupe menos.

De todas formas, el hardware del Apple-I simplifica bastante la programación del monitor ya que para leer el teclado simplemente hay que consultar una posición de memoria, y en mi versión la rutina es más compleja, y para poner un carácter en pantalla en el Apple-I simplemente hay que hacer un POKE, aunque en el ZX-81, gracias al RST $10 la cosa es incluso más simple, pero he tenido que controlar el scroll cuando el Apple-I lo hace solo. Así que ahora mismo no hay una equivalencia.

Lo que si tengo en mente es adaptar el código fuente original del Apple-I en un equipo con un 6502, porque creo que es transportable en un 90% o más.
Ya os contaré...


Volver a “Sinclair ZX80/81”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado