Jupiter Ace: Keybeep

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Jupiter Ace: Keybeep

Mensajepor Elurdio » 09 Jun 2022 23:20

En el hilo Jupiter Ace Interrupción Modo 2, hice una rutina que aprovecha la interrupción modo 2 del JA para emitir un pitido al pulsar una tecla.

Era una versión sencilla que NO me dejó contento pues adolece de dos defectos:

  • Se da el caso que, a veces, tras pulsar una tecla y sonar el pitido, no se escribe el carácter correspondiente en el búfer de entrada.
  • No pita cuando la tecla se auto-repite al mantenerla pulsada.

Tras mirarme a fondo el desensamblado de la ROM del "JA archive" en la parte correspondiente a este tema (*), he rehecho la rutina y ahora sí que funciona bien:

  • Al pulsar una tecla solo pita si el carácter es enviado al búfer de entrada.
  • Al repetirse automáticamente una tecla pulsada, también pita a cada repetición

Teniendo en cuenta que esta rutina (bueno, una versión que se ha perdido y que no sé qué hacía exactamente, ni como lo hacía) se hizo en su día como una ayuda a la escritura decidí añadir un sonido diferente si está pulsada la tecla Shift/Symbol.

Al ser el teclado del Jupiter Ace bastante "tosco" (**) lo normal era escribir mirando el teclado. Tenías que levantar la vista a menudo para comprobar que realmente se había escrito lo que pretendías. Con esta rutina "deberías" tener una confirmación sonora de que la pulsación ha sido hecha correctamente. De ahí lo de los dos beeps, para poder confirmar de oído si la tecla Shift/Symbol se pulsó correctamente junto con la tecla en cuestión.

Pero la cosa no va muy fina en este caso, por lo que solo ponga las versiones con un único beep. Las de dos beeps diferentes me las guardo en el cajón hasta que solucione el problema (***)

He hecho dos versiones separadas en función del modo de trabajar de la interrupción modo 2: Una usa $nn20 y la otra $nnFF. La primera es la oficial del Jupiter Ace. La segunda es la que usan muchos emuladores y algunos clones (como el Minstrel4):

Keybeep1 ($nn20) la he probado en EightyOne 1.28 y 1.24
Keybeep2 ($nnFF) la he probado en EightyOne 1.23 , en el ZEsarUX 10.1 y en SpudAce 1.02

Funciona bastante bien en general (a veces se le va un poco la pinza con los beeps...).

Instalación

Ejecutar (por separado):

KBLIMIT
PUTKB

OJO: Se han de ejecutar por separado:

KBLIMIT <ENTER> PUTKB <ENTER>

pues KBLIMIT ejecuta un QUIT internamente que borra el búffer de entrada, perdiéndose todas las palabras que le siguen.

Una vez instalada se pueden borrar las tres palabras que la componen: KBLIMIT, KBPUT y KBCODE.

ADVERTENCIA: Dado que esta rutina usa el modo 2 de interrupción, NO es compatible con ninguna rutina que haga uso del mismo, como por ejemplo el Copiador de Búfer.

(*) Concretamente la rutina que se encarga de escribir el carácter correspondiente a la pulsación de una tecla en el búfer de entrada.

(**) Esto es lo que he visto por internet. Aunque en su día, como ya comenté, estuve toda una tarde en la tienda del distribuidor del Jupiter Ace probando uno, el que usé tenía acoplado un teclado externo bastante bueno y no llegué a "catar" el teclado original.

(***) En cuanto a lo del sonido diferente cuando se pulsa una tecla junto con la tecla Shift o Symbol, va bien siempre que se haga así, o sea, que se pulsen dos teclas. Lo digo porque mucho emuladores asignan a una sola tecla la función de una combinación de Shift/Symbol + tecla. En estos casos, puede fallar y dar el otro sonido.

Así, en el EightyOne v 1.28, hay varias teclas que responden a lo que en el JA serían dos. Por ejemplo la tecla <Delete> del teclado estándar (Borrar) funciona como el <Shift+cero> del JA. Si usamos la tecla <Delete> rápidamente, puede fallar y sonar el beep normal. Si usamos <Shift+cero> no hay problema. Lo mismo con otros casos como:

<.> equivale a <Symbol+M>
<-> equivale a <Symbol+J>
<`> equivale a <Symbol+O>
etc.

En definitiva, es de esperar que estas versiones con dos beeps funcionen bien en un JA real o en clones físicos. También en emuladores siempre y cuando NO se usen las teclas que realizan un <shift/symbol+tecla> con una sola pulsación.

Tengo una solución pensada, pero lo dejo para más adelante por tediosa.

Código Fuente: (keybeep1)

Código: Seleccionar todo

; Interrupt mode 2: At each interrupt executes the routine whose
; address is the one stored at memory address $nn20 where $nn is the value
; of the I register.

; Keyboard key press detection:

; From what I understand it seems that:
;       a) A key is considered pressed after it has been held down for 2 interrupts.
;       b) A key held down for 32 interrupts starts repeating.
;       c) Once the repetition starts, the key repeats every 4 interrupts.
;       d) All countings are hold in JA's system variable KEYCNT.


                .LIST
KEYCOD          .EQU    $3C26                   ; ASCII last key pressed  (JA's System Variable)
KEYCNT          .EQU    $3C27                   ; Counter for key pressed (JA's System Variable)
DELAY           .EQU    $0BC9                   ; BEEP DELAY SUBROUTINE (JA's ROM)
FORTH           .EQU    $140                    ; Addres original interrupt routine of the JA. (avoiding repeat what
                                                ; alreay have been done before (save registers, dissabling interrupt..)
ORIGIN          .EQU    $FF20                   ; Address where the program is to be loaded

                .ORG    ORIGIN
               
VECTOR:         .WORD   0                       ; Space to store the Interrupt vector.
FIRST:          LD      H,VECTOR / $100         ; Store in Vector ($nn20) the value of LINICIO (vector to the routine)
                LD      L,VECTOR % $100         ; to be executed at each interrupt). This routine begins at "LINICIO"   
                LD      (HL),LINICIO % $100     
                INC     HL
                LD      (HL),LINICIO / $100
               
                LD      A,VECTOR / $100         ; Set I register to $nn and interrupt mode 2 is activated.
                LD      I,A                     
                DI
                IM      2                       
                EI
               
                JP      (IY)                    ; Back to Forth
               
LINICIO:        PUSH    AF                      ; Save registers (DI is executed by interrupt itself)
                EX      AF,AF'                  ; After our interrupt routine is finished the program jumps to the
                PUSH    AF                      ; original JA's interrupt routine that, when terminated, will restore
                PUSH    BC                      ; interrupts and and saved registers.
                PUSH    DE
                PUSH    HL
               
                ;------------------------------
;               BEGINNING INTERRUPT ROUTINE
                ;------------------------------
               
                LD      HL,(KEYCOD)             ; L = KEYCOD
                                                ; H = KEYCNT
               
                ; If KEYCOD <> 0 and KEYCNT = 30 -> BEEP (the key is considered as being pressed for the first time)
               
                LD      A,L
                OR      A
                JP      Z,NEXT1                 ; KEYCOD = 0 -> jump NEXT1
               
                LD      A,H
                CP      30
                JP      Z,BEEP                  ; KEYCNT = 30 -> Beep
               
                ; If KEYCCOD <>0 and KEYCNT = 1  -> BEEP (the key is repeating)
               
                CP      1
                JP      Z,BEEP                  ; If KEYCNT = 1 -> Beep
               
NEXT1:         
                JP      FORTH
               
BEEP:   
                LD      HL,$012C                ; HL = pitch for BEEP                                   
                LD      DE,$C                   ; DE = Duration for BEEP
                                                ; These data correspond to 50 12 BEEP in FORTH
               
                ;------------------------------- This code is copied and adapted from Ace's ROM BEEP Word code
                ;                                (it has been neccesary in order to avoid the BEEP's breaking
                ;                                when SPACE key is pressed)
               
LOOP1:          LD      A,$7F                   ; place $7FFE on address bus and read
                IN      A,($FE)                 ; from port, pushing the loudspeaker
                                                ; diaphragm in.

                CALL    DELAY                   ; routine delay_HL

                DEC     DE                      ; decrement counter.

                LD      A,D                     ; all even addresses are reserved for
                                                ; Jupiter Ace so any value does for the
                                                ; high order byte. $FE is low value.

                OUT     ($FE),A                 ; push the loudspeaker diaphragm out.

                CALL    DELAY                   ; routine delay_HL

                OR      E                       ; test for counter DE reaching zero.
                JP      NZ,LOOP1                ; loop back if not.

                JP      FORTH                   
               
                ;------------------------------
;               END INTERRUPT ROUTINE
                ;------------------------------
               
;================================================ This block of code is OPTIONAL
                                                ; It can be accesed with a INTER1 CALL from Forth
                                               
INTER1:         DI                              ; Activate Interrupt Mode 1.
                IM      1
                EI
               
                JP      (IY)                    ; Back to Forth
                .END


Código Fuente: (keybeep2)

Código: Seleccionar todo

; Alternative Address version: Here we use $nnFF instead of $nn20 so it is compatible with many emulators and clones
;                              that do not follow the JA standard

; Interrupt mode 2: At each interrupt executes the routine whose address is the one stored
; at memory address $nnFF where $nn is the value of the I register.

; Keyboard key press detection:

; From what I understand it seems that:
;       a) A key is considered pressed after it has been held down for 2 interrupts.
;       b) A key held down for 32 interrupts starts repeating.
;       c) Once the repetition starts, the key repeats every 4 interrupts.
;       d) All countings are hold in JA's system variable KEYCNT.


                .LIST
KEYCOD          .EQU    $3C26                   ; ASCII last key pressed  (JA's System Variable)
KEYCNT          .EQU    $3C27                   ; Counter for key pressed (JA's System Variable)
DELAY           .EQU    $0BC9                   ; BEEP DELAY SUBROUTINE (JA's ROM)
FORTH           .EQU    $140                    ; Addres original interrupt routine of the JA. (avoiding repeat what
                                                ; alreay have been done before (save registers, dissabling interrupt..)
ORIGIN          .EQU    $FEFF                   ; Address where the program is to be loaded

                .ORG    ORIGIN
               
VECTOR:         .WORD   0                       ; Space to store the Interrupt vector.
FIRST:          LD      H,VECTOR / $100         ; Store in Vector ($nnFF) the value of LINICIO (vector to the routine)
                LD      L,VECTOR % $100         ; to be executed at each interrupt). This routine begins at "LINICIO"   
                LD      (HL),LINICIO % $100     
                INC     HL
                LD      (HL),LINICIO / $100
               
                LD      A,VECTOR / $100         ; Set I register to $nn and interrupt mode 2 is activated.
                LD      I,A                     
                DI
                IM      2                       
                EI
               
                JP      (IY)                    ; Back to Forth
               
LINICIO:        PUSH    AF                      ; Save registers (DI is executed by interrupt itself)
                EX      AF,AF'                  ; After our interrupt routine is finished the program jumps to the
                PUSH    AF                      ; original JA's interrupt routine that, when terminated, will restore
                PUSH    BC                      ; interrupts and and saved registers.
                PUSH    DE
                PUSH    HL
               
                ;------------------------------
;               BEGINNING INTERRUPT ROUTINE
                ;------------------------------
               
                LD      HL,(KEYCOD)             ; L = KEYCOD
                                                ; H = KEYCNT
               
                ; If KEYCOD <> 0 and KEYCNT = 30 -> BEEP (the key is considered as being pressed for the first time)
               
                LD      A,L
                OR      A
                JP      Z,NEXT1                 ; KEYCOD = 0 -> jump NEXT1
               
                LD      A,H
                CP      30
                JP      Z,BEEP                  ; KEYCNT = 30 -> Beep
               
                ; If KEYCCOD <>0 and KEYCNT = 1  -> BEEP (the key is repeating)
               
                CP      1
                JP      Z,BEEP                  ; If KEYCNT = 1 -> Beep
               
NEXT1:         
                JP      FORTH
               
BEEP:           
                LD      HL,$012C                ; HL = pitch for BEEP                                   
                LD      DE,$C                   ; DE = Duration for BEEP
                                                ; These data correspond to 50 12 BEEP in FORTH
               
                ;------------------------------- This code is copied and adapted from Ace's ROM BEEP Word code
                ;                                (it has been neccesary in order to avoid the BEEP's breaking
                ;                                when SPACE key is pressed)
               
LOOP1:          LD      A,$7F                   ; place $7FFE on address bus and read
                IN      A,($FE)                 ; from port, pushing the loudspeaker
                                                ; diaphragm in.

                CALL    DELAY                   ; routine delay_HL

                DEC     DE                      ; decrement counter.

                LD      A,D                     ; all even addresses are reserved for
                                                ; Jupiter Ace so any value does for the
                                                ; high order byte. $FE is low value.

                OUT     ($FE),A                 ; push the loudspeaker diaphragm out.

                CALL    DELAY                   ; routine delay_HL

                OR      E                       ; test for counter DE reaching zero.
                JP      NZ,LOOP1                ; loop back if not.

                JP      FORTH                   
               
                ;------------------------------
;               END INTERRUPT ROUTINE
                ;------------------------------
               
;================================================ This block of code is OPTIONAL
                                                ; It can be accesed with a INTER1 CALL from Forth
                                               
INTER1:         DI                              ; Activate Interrupt Mode 1.
                IM      1
                EI
               
                JP      (IY)                    ; Back to Forth
                .END


keybeeb.TZX
(706 Bytes) Descargado 10 veces

Volver a “Jupiter Ace”

¿Quién está conectado?

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