Tachibana
Langue : français

Groupe 33 — Gestionnaire d'événements Trinity

33,1 Init Events · 33,2 Get Next Event · 33,3 Event Available · 33,4 Flush Events · 33,5 Set Timer · 33,6 Event Status

Le gestionnaire d'événements de la boîte à outils de Trinity range clavier, souris et minuteurs dans une seule file, interrogée par 33,2. Types : 1 touche enfoncée, 2 touche relâchée, 3 répétition, 4 bouton enfoncé, 5 bouton relâché, 6 mouvement de la souris (les mouvements successifs sont fusionnés), 7 molette, 8 minuteur, 9 mise à jour d'une fenêtre (groupe 34), 10 activation d'une fenêtre.

Un EventRecord fait 8 octets en RAM du 6502 : type, message, message2, modificateurs, X et Y (16 bits). Les masques ont le bit n-1 pour le type n : 1 pour les touches enfoncées, $10 pour les boutons relâchés, $80 pour les minuteurs ; 0 veut dire tous les types.

Les exemples reçoivent des touches tapées ou des clics de la souris émulée par le banc, attendent un peu avec 1,1, puis lisent la file.

33,1 Init Events Trinity

Démarre le gestionnaire d'événements avec une file vide : clavier, souris et minuteurs y sont rangés.

Entrées
OctetsTypeRôle
P0-P1uint16types à recueillir (bit n-1 pour le type n, 0 = tous)

Sorties : aucune.

Seuls les types du masque entrent dans la file : avec le masque 1, l'exemple ne reçoit que les deux touches enfoncées de « ab », pas leurs relâchements. Rappeler 33,1 vide la file. La file du clavier du groupe 2 reçoit toujours les touches : les exemples la vident avant de rendre la main. 1,0 (DSP Reset) et 32,19 (Toolbox Reset) arrêtent le gestionnaire. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Toolbox (Trinity, T-12, ADR-01 of the fork). Starts the event manager with an empty queue : keyboard, mouse and timer events are then collected in one queue of 32 records, polled by Get Next Event. Parameters:0,1 is the mask of event types to collect (bit n-1 for type n, 0 = all). Event types : 1 key down, 2 key up, 3 auto key (repeat), 4 mouse down, 5 mouse up, 6 mouse move (consecutive moves are merged), 7 wheel, 8 timer, 9 update (message = window to redraw, see group 34), 10 activate (message = window, message2 = 1 front / 0). An EventRecord is 8 bytes in 6502 RAM : what, message, message2, modifiers, X (2), Y (2) ; message is the ASCII code for keys (0 if none), the buttons after the change for mouse down/up, the signed delta for the wheel, the timer number for timers ; message2 is the key code for keys, the button that changed for mouse down/up with bit 7 set for a double click ; modifiers are the keyboard modifiers for keys and the buttons held for mouse events ; X,Y is the mouse position when the event was posted. The keyboard queue of group 2 is unaffected. There is no blocking wait : API calls are synchronous and the hosts read their input between calls ; poll, or sleep with the interrupt tick (1,12) and WAI. The manager is stopped by DSP Reset.

C (llvm-mos)
/* Démarrer la file d'événements (groupe 33, fonction 1, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Event Manager : un EventRecord = type, message, message2, modificateurs, X, Y (8 octets). */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static uint16_t temps(void) {                   /* 1,1 : temps en centièmes de seconde (16 bits bas) */
    libre();
    api(1, 1);
    return ControlPort.params[0] | ControlPort.params[1] << 8;
}
static void attendre(uint16_t cs) {             /* laisse le temps aux touches tapées d'arriver */
    uint16_t t0 = temps();
    while (temps() - t0 < cs)
        ;
}
static void init_events(uint16_t masque) {      /* 33,1 Init Events */
    libre(); p16(0, masque); api(33, 1);
}
static uint8_t disponibles(uint16_t masque) {   /* 33,3 Event Available */
    libre(); p16(0, masque); api(33, 3);
    return ControlPort.params[2];
}
static uint8_t suivant(EventRecord *e, uint16_t masque) {   /* 33,2 Get Next Event : 1 si un événement est rendu */
    libre(); p16(0, (uint16_t)e); p16(2, masque); api(33, 2);
    return ControlPort.params[4];
}
static void vider_clavier(void) {               /* la file du clavier (groupe 2) a reçu les mêmes touches : on la vide */
    do { libre(); api(2, 1); } while (ControlPort.params[0]);
}

int main(void) {
    uint8_t n1, n2;
    init_events(1);                     /* masque : bit 0 = type 1, touche enfoncée seulement */
    attendre(100);                      /* le banc tape « ab » */
    n1 = disponibles(0);
    init_events(0);                     /* une nouvelle initialisation vide la file */
    n2 = disponibles(0);
    vider_clavier();
    printf("Touches enfoncees recues : %u\nApres une nouvelle initialisation : %u\n", n1, n2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Touches enfoncees recues : 2
Apres une nouvelle initialisation : 0
Mad Pascal
// Démarrer la file d'événements (groupe 33, fonction 1, Trinity).
program ev1;
uses crt, neo6502;
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;   // 8 octets

procedure appel(f: byte);                       // appel 33,f (paramètres déjà posés)
begin
  NeoSendMessage(33, f);
  NeoWaitMessage;
end;

procedure attendre(cs: cardinal);               // laisse le temps aux touches tapées d'arriver
var t0: cardinal;
begin
  t0 := NeoGetTimer;
  while NeoGetTimer - t0 < cs do ;
end;

procedure init_events(masque: word);            // 33,1 Init Events
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(1);
end;

function disponibles(masque: word): byte;       // 33,3 Event Available
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(3);
  result := NeoMessage.params[2];
end;

function suivant(e: pointer; masque: word): byte;   // 33,2 Get Next Event : 1 si un événement est rendu
begin
  NeoWaitMessage;
  wordParams[0] := word(e);
  wordParams[1] := masque;
  appel(2);
  result := NeoMessage.params[4];
end;

procedure vider_clavier;                        // la file du clavier (groupe 2) a reçu les mêmes touches : on la vide
begin
  repeat
    NeoSendMessage(2, 1);
    NeoWaitMessage;
  until NeoMessage.params[0] = 0;
end;

var n1, n2: byte;
begin
  init_events(1);                               // masque : bit 0 = type 1, touche enfoncée seulement
  attendre(100);                                // le banc tape « ab »
  n1 := disponibles(0);
  init_events(0);                               // une nouvelle initialisation vide la file
  n2 := disponibles(0);
  vider_clavier;
  writeln('Touches enfoncees recues : ', n1);
  writeln('Apres une nouvelle initialisation : ', n2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Touches enfoncees recues : 2
Apres une nouvelle initialisation : 0
NeoBASIC
10 ' Demarrer la file d'evenements (groupe 33, fonction 1, Trinity)
20 m = 1 : f = 1 : gosub 8000 : ' Init Events, masque : bit 0 = type 1, touche enfoncee seulement
30 cs = 100 : gosub 8200 : ' le banc tape « ab »
40 m = 0 : f = 3 : gosub 8000 : n1 = r2 : ' 33,3
50 m = 0 : f = 1 : gosub 8000 : ' une nouvelle initialisation vide la file
60 f = 3 : gosub 8000 : n2 = r2
70 gosub 8300
80 print "Touches enfoncees recues : ";n1
90 print "Apres une nouvelle initialisation : ";n2
100 end
8000 ' 33,f : P0-P1 = m ; resultat de P0 a P4 dans r0 a r4
8010 while peek($ff00) : wend : doke $ff04, m
8020 poke $ff01, f : poke $ff00, 33
8030 while peek($ff00) : wend
8040 r0 = peek($ff04) : r1 = peek($ff05) : r2 = peek($ff06) : r4 = peek($ff08)
8050 return
8100 ' 33,2 Get Next Event dans l'EventRecord e, masque m ; r4 = 1 si un evenement est rendu
8110 while peek($ff00) : wend : doke $ff04, e : doke $ff06, m : f = 2 : goto 8020
8200 ' laisse le temps aux touches tapees d'arriver : cs centiemes
8210 t0 = time()
8220 while time() - t0 < cs : wend
8230 return
8300 ' la file du clavier (groupe 2) a recu les memes touches : on la vide
8310 while inkey$() <> "" : wend
8320 return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Touches enfoncees recues : 2
Apres une nouvelle initialisation : 0
Assembleur 65C02 (64tass)
; Démarrer la file d'événements (groupe 33, fonction 1, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<100
        ldx #>100
        jsr attendre               ; le banc tape « ab »
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6
        sta n1
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+6
        sta n2
        jsr vider
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda n1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda n2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

b0:     .byte 33, 1, 2             ; Init Events, masque : bit 0 = type 1, touche enfoncée seulement
        .word 1
b1:     .byte 33, 3, 2             ; 33,3 : Event Available
        .word 0
n1:     .byte 0
b2:     .byte 33, 1, 2             ; une nouvelle initialisation vide la file
        .word 0
b3:     .byte 33, 3, 2             ; 33,3
        .word 0
n2:     .byte 0
t4:     .text "Touches enfoncees recues : ", 0
t5:     .text "Apres une nouvelle initialisation : ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Note l'instant de départ (1,1 : temps en centièmes de seconde, 16 bits bas).
depart: jsr temps
        lda tl
        sta t0
        lda th
        sta t0+1
        rts

; C = 1 si au moins A (poids faible), X (poids fort) centièmes se sont écoulés depuis depart.
ecoule: sta duree
        stx duree+1
        jsr temps
        sec
        lda tl
        sbc t0
        sta tl
        lda th
        sbc t0+1
        sta th
        lda tl
        cmp duree
        lda th
        sbc duree+1
        rts

; Attend A (poids faible), X (poids fort) centièmes : le temps aux touches tapées d'arriver.
attendre:
        pha
        phx
        jsr depart
        plx
        pla
_att:   pha
        phx
        jsr ecoule
        plx
        pla
        bcc _att
        rts

temps:  jsr WaitMessage
        lda #1
        ldx #1                     ; 1,1 : temps
        jsr appel
        lda ControlPort+4
        sta tl
        lda ControlPort+5
        sta th
        rts

; La file du clavier (groupe 2) a reçu les mêmes touches : on la vide.
vider:  jsr WaitMessage
        lda #2
        ldx #1                     ; 2,1 : lire un caractère, 0 si aucun
        jsr appel
        lda ControlPort+4
        bne vider
        rts

t0:     .word 0
tl:     .byte 0
th:     .byte 0
duree:  .word 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Touches enfoncees recues : 2
Apres une nouvelle initialisation : 0

33,2 Get Next Event Trinity

Retire de la file le plus ancien événement d'un type demandé et l'écrit dans un EventRecord.

Entrées
OctetsTypeRôle
P0-P1addradresse de l'EventRecord (8 octets)
P2-P3uint16masque des types (0 = tous)
Sorties
OctetsTypeRôle
P4uint81 si un événement est rendu, 0 pour un événement nul (type 0, avec la position de la souris)
erreuruint8non nul si l'adresse ne va pas

Pour une touche, message est le code ASCII et message2 le code de la touche : « a » donne 97 et 4, « B » donne 66, 5 et les modificateurs 2 (Maj). Les minuteurs échus passent devant. Il n'y a pas d'attente bloquante : on interroge la file en boucle. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Removes the oldest queued event whose type is in the mask Parameters:2,3 (0 = all) and writes it in the EventRecord at Parameters:0,1 ; Parameter:4 is 1 if an event was returned, 0 if a null event (type 0, with the mouse position) was written instead. Due timers post their event first. Error if the address is bad.

C (llvm-mos)
/* Lire l'événement suivant (groupe 33, fonction 2, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Event Manager : un EventRecord = type, message, message2, modificateurs, X, Y (8 octets). */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static uint16_t temps(void) {                   /* 1,1 : temps en centièmes de seconde (16 bits bas) */
    libre();
    api(1, 1);
    return ControlPort.params[0] | ControlPort.params[1] << 8;
}
static void attendre(uint16_t cs) {             /* laisse le temps aux touches tapées d'arriver */
    uint16_t t0 = temps();
    while (temps() - t0 < cs)
        ;
}
static void init_events(uint16_t masque) {      /* 33,1 Init Events */
    libre(); p16(0, masque); api(33, 1);
}
static uint8_t disponibles(uint16_t masque) {   /* 33,3 Event Available */
    libre(); p16(0, masque); api(33, 3);
    return ControlPort.params[2];
}
static uint8_t suivant(EventRecord *e, uint16_t masque) {   /* 33,2 Get Next Event : 1 si un événement est rendu */
    libre(); p16(0, (uint16_t)e); p16(2, masque); api(33, 2);
    return ControlPort.params[4];
}
static void vider_clavier(void) {               /* la file du clavier (groupe 2) a reçu les mêmes touches : on la vide */
    do { libre(); api(2, 1); } while (ControlPort.params[0]);
}

static EventRecord ev;

int main(void) {
    uint8_t i, r;
    init_events(0);
    attendre(100);                      /* le banc tape « aB » */
    for (i = 0; i < 2; i++) {
        suivant(&ev, 1);                /* masque 1 : touches enfoncées seulement */
        printf("Type %u, caractere %u, code %u, modificateurs %u\n", ev.what, ev.message, ev.message2, ev.modifiers);
    }
    r = suivant(&ev, 1);                /* plus rien : événement nul */
    vider_clavier();
    printf("Plus de touche : rendu %u, type %u\n", r, ev.what);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0
Mad Pascal
// Lire l'événement suivant (groupe 33, fonction 2, Trinity).
program ev2;
uses crt, neo6502;
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;   // 8 octets

procedure appel(f: byte);                       // appel 33,f (paramètres déjà posés)
begin
  NeoSendMessage(33, f);
  NeoWaitMessage;
end;

procedure attendre(cs: cardinal);               // laisse le temps aux touches tapées d'arriver
var t0: cardinal;
begin
  t0 := NeoGetTimer;
  while NeoGetTimer - t0 < cs do ;
end;

procedure init_events(masque: word);            // 33,1 Init Events
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(1);
end;

function disponibles(masque: word): byte;       // 33,3 Event Available
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(3);
  result := NeoMessage.params[2];
end;

function suivant(e: pointer; masque: word): byte;   // 33,2 Get Next Event : 1 si un événement est rendu
begin
  NeoWaitMessage;
  wordParams[0] := word(e);
  wordParams[1] := masque;
  appel(2);
  result := NeoMessage.params[4];
end;

procedure vider_clavier;                        // la file du clavier (groupe 2) a reçu les mêmes touches : on la vide
begin
  repeat
    NeoSendMessage(2, 1);
    NeoWaitMessage;
  until NeoMessage.params[0] = 0;
end;

var ev: EventRecord;
    i, r: byte;
begin
  init_events(0);
  attendre(100);                                // le banc tape « aB »
  for i := 1 to 2 do begin
    suivant(@ev, 1);                            // masque 1 : touches enfoncées seulement
    writeln('Type ', ev.what, ', caractere ', ev.message, ', code ', ev.message2, ', modificateurs ', ev.modifiers);
  end;
  r := suivant(@ev, 1);                         // plus rien : événement nul
  vider_clavier;
  writeln('Plus de touche : rendu ', r, ', type ', ev.what);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0
NeoBASIC
10 ' Lire l'evenement suivant (groupe 33, fonction 2, Trinity)
20 e = alloc(8) : ' EventRecord : type, message, message2, modificateurs, X, Y
30 m = 0 : f = 1 : gosub 8000 : ' 33,1
40 cs = 100 : gosub 8200 : ' le banc tape « aB »
50 for i = 1 to 2
60 m = 1 : gosub 8100 : ' Get Next Event, masque 1 : touches enfoncees seulement
70 print "Type ";peek(e);", caractere ";peek(e + 1);", code ";peek(e + 2);", modificateurs ";peek(e + 3)
80 next i
90 m = 1 : gosub 8100 : r = r4 : ' plus rien : evenement nul
100 gosub 8300
110 print "Plus de touche : rendu ";r;", type ";peek(e)
120 end
8000 ' 33,f : P0-P1 = m ; resultat de P0 a P4 dans r0 a r4
8010 while peek($ff00) : wend : doke $ff04, m
8020 poke $ff01, f : poke $ff00, 33
8030 while peek($ff00) : wend
8040 r0 = peek($ff04) : r1 = peek($ff05) : r2 = peek($ff06) : r4 = peek($ff08)
8050 return
8100 ' 33,2 Get Next Event dans l'EventRecord e, masque m ; r4 = 1 si un evenement est rendu
8110 while peek($ff00) : wend : doke $ff04, e : doke $ff06, m : f = 2 : goto 8020
8200 ' laisse le temps aux touches tapees d'arriver : cs centiemes
8210 t0 = time()
8220 while time() - t0 < cs : wend
8230 return
8300 ' la file du clavier (groupe 2) a recu les memes touches : on la vide
8310 while inkey$() <> "" : wend
8320 return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0
Assembleur 65C02 (64tass)
; Lire l'événement suivant (groupe 33, fonction 2, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<100
        ldx #>100
        jsr attendre               ; le banc tape « aB »
        lda #<b1
        ldx #>b1
        jsr envoi
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda ev
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda ev+1
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda ev+2
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda ev+3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<b6
        ldx #>b6
        jsr envoi
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda ev
        jsr decimal
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda ev+1
        jsr decimal
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda ev+2
        jsr decimal
        lda #<t10
        ldx #>t10
        jsr ecrire
        lda ev+3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<b11
        ldx #>b11
        jsr envoi
        lda ControlPort+8          ; P4 : 1 si un événement est rendu
        sta r
        jsr vider
        lda #<t12
        ldx #>t12
        jsr ecrire
        lda r
        jsr decimal
        lda #<t13
        ldx #>t13
        jsr ecrire
        lda ev
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

ev:     .fill 8                    ; EventRecord : type, message, message2, modificateurs, X, Y
b0:     .byte 33, 1, 2             ; 33,1 : Init Events
        .word 0
b1:     .byte 33, 2, 4             ; Get Next Event, masque 1 : touches enfoncées seulement
        .word ev, 1
t2:     .text "Type ", 0
t3:     .text ", caractere ", 0
t4:     .text ", code ", 0
t5:     .text ", modificateurs ", 0
b6:     .byte 33, 2, 4             ; Get Next Event, masque 1 : touches enfoncées seulement
        .word ev, 1
t7:     .text "Type ", 0
t8:     .text ", caractere ", 0
t9:     .text ", code ", 0
t10:    .text ", modificateurs ", 0
b11:    .byte 33, 2, 4             ; plus rien : événement nul
        .word ev, 1
r:      .byte 0
t12:    .text "Plus de touche : rendu ", 0
t13:    .text ", type ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Note l'instant de départ (1,1 : temps en centièmes de seconde, 16 bits bas).
depart: jsr temps
        lda tl
        sta t0
        lda th
        sta t0+1
        rts

; C = 1 si au moins A (poids faible), X (poids fort) centièmes se sont écoulés depuis depart.
ecoule: sta duree
        stx duree+1
        jsr temps
        sec
        lda tl
        sbc t0
        sta tl
        lda th
        sbc t0+1
        sta th
        lda tl
        cmp duree
        lda th
        sbc duree+1
        rts

; Attend A (poids faible), X (poids fort) centièmes : le temps aux touches tapées d'arriver.
attendre:
        pha
        phx
        jsr depart
        plx
        pla
_att:   pha
        phx
        jsr ecoule
        plx
        pla
        bcc _att
        rts

temps:  jsr WaitMessage
        lda #1
        ldx #1                     ; 1,1 : temps
        jsr appel
        lda ControlPort+4
        sta tl
        lda ControlPort+5
        sta th
        rts

; La file du clavier (groupe 2) a reçu les mêmes touches : on la vide.
vider:  jsr WaitMessage
        lda #2
        ldx #1                     ; 2,1 : lire un caractère, 0 si aucun
        jsr appel
        lda ControlPort+4
        bne vider
        rts

t0:     .word 0
tl:     .byte 0
th:     .byte 0
duree:  .word 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0

33,3 Event Available Trinity

Compte les événements en file d'un type demandé, sans les retirer.

Entrées
OctetsTypeRôle
P0-P1uint16masque des types (bit n-1 pour le type n, 0 = tous)
Sorties
OctetsTypeRôle
P2uint8nombre d'événements

L'exemple attend deux relâchements de bouton (type 5), puis compte. Pour un bouton, message2 est le bouton qui a changé, avec le bit 7 en cas de double clic : le second clic, rapide, donne 129. Au banc, chaque changement de bouton est aussi précédé d'un mouvement (type 6) : l'exemple compte donc avec des masques. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Returns in Parameter:2 the number of queued events whose type is in the mask Parameters:0,1 (0 = all).

C (llvm-mos)
/* Compter les événements en attente (groupe 33, fonction 3, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Event Manager : un EventRecord = type, message, message2, modificateurs, X, Y (8 octets). */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static uint16_t temps(void) {                   /* 1,1 : temps en centièmes de seconde (16 bits bas) */
    libre();
    api(1, 1);
    return ControlPort.params[0] | ControlPort.params[1] << 8;
}
static void attendre(uint16_t cs) {             /* laisse le temps aux touches tapées d'arriver */
    uint16_t t0 = temps();
    while (temps() - t0 < cs)
        ;
}
static void init_events(uint16_t masque) {      /* 33,1 Init Events */
    libre(); p16(0, masque); api(33, 1);
}
static uint8_t disponibles(uint16_t masque) {   /* 33,3 Event Available */
    libre(); p16(0, masque); api(33, 3);
    return ControlPort.params[2];
}
static uint8_t suivant(EventRecord *e, uint16_t masque) {   /* 33,2 Get Next Event : 1 si un événement est rendu */
    libre(); p16(0, (uint16_t)e); p16(2, masque); api(33, 2);
    return ControlPort.params[4];
}
static void vider_clavier(void) {               /* la file du clavier (groupe 2) a reçu les mêmes touches : on la vide */
    do { libre(); api(2, 1); } while (ControlPort.params[0]);
}

static EventRecord ev;

int main(void) {
    uint8_t enf, rel, b1, b2;
    uint16_t t0;
    init_events(0);
    t0 = temps();                       /* le banc clique deux fois, vite : un double clic */
    while (disponibles(0x10) < 2 && temps() - t0 < 600)   /* bit 4 : type 5, bouton relâché */
        ;
    enf = disponibles(0x08);            /* bit 3 : type 4, bouton enfoncé */
    rel = disponibles(0x10);
    suivant(&ev, 0x08);
    b1 = ev.message2;                   /* bouton qui a changé */
    suivant(&ev, 0x08);
    b2 = ev.message2;                   /* bit 7 : double clic */
    printf("Enfonces : %u, relaches : %u\nPremier clic : %u, second : %u\n", enf, rel, b1, b2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Enfonces : 2, relaches : 2
Premier clic : 1, second : 129
Mad Pascal
// Compter les événements en attente (groupe 33, fonction 3, Trinity).
program ev3;
uses crt, neo6502;
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;   // 8 octets

procedure appel(f: byte);                       // appel 33,f (paramètres déjà posés)
begin
  NeoSendMessage(33, f);
  NeoWaitMessage;
end;

procedure attendre(cs: cardinal);               // laisse le temps aux touches tapées d'arriver
var t0: cardinal;
begin
  t0 := NeoGetTimer;
  while NeoGetTimer - t0 < cs do ;
end;

procedure init_events(masque: word);            // 33,1 Init Events
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(1);
end;

function disponibles(masque: word): byte;       // 33,3 Event Available
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(3);
  result := NeoMessage.params[2];
end;

function suivant(e: pointer; masque: word): byte;   // 33,2 Get Next Event : 1 si un événement est rendu
begin
  NeoWaitMessage;
  wordParams[0] := word(e);
  wordParams[1] := masque;
  appel(2);
  result := NeoMessage.params[4];
end;

procedure vider_clavier;                        // la file du clavier (groupe 2) a reçu les mêmes touches : on la vide
begin
  repeat
    NeoSendMessage(2, 1);
    NeoWaitMessage;
  until NeoMessage.params[0] = 0;
end;

var ev: EventRecord;
    enf, rel, b1, b2: byte;
    t0: cardinal;
begin
  init_events(0);
  t0 := NeoGetTimer;                            // le banc clique deux fois, vite : un double clic
  while (disponibles($10) < 2) and (NeoGetTimer - t0 < 600) do ;   // bit 4 : type 5, bouton relâché
  enf := disponibles($08);                      // bit 3 : type 4, bouton enfoncé
  rel := disponibles($10);
  suivant(@ev, $08);
  b1 := ev.message2;                            // bouton qui a changé
  suivant(@ev, $08);
  b2 := ev.message2;                            // bit 7 : double clic
  writeln('Enfonces : ', enf, ', relaches : ', rel);
  writeln('Premier clic : ', b1, ', second : ', b2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Enfonces : 2, relaches : 2
Premier clic : 1, second : 129
NeoBASIC
10 ' Compter les evenements en attente (groupe 33, fonction 3, Trinity)
20 e = alloc(8)
30 m = 0 : f = 1 : gosub 8000 : ' 33,1
40 t1 = time() : ' le banc clique deux fois, vite : un double clic
50 m = $10 : f = 3 : gosub 8000 : ' Event Available, bit 4 : type 5, bouton relache
60 if r2 >= 2 then 70
65 if time() - t1 < 600 then 50
70 m = $08 : f = 3 : gosub 8000 : en = r2 : ' bit 3 : type 4, bouton enfonce
80 m = $10 : f = 3 : gosub 8000 : re = r2
90 m = $08 : gosub 8100 : b1 = peek(e + 2) : ' bouton qui a change
100 m = $08 : gosub 8100 : b2 = peek(e + 2) : ' bit 7 : double clic
110 print "Enfonces : ";en;", relaches : ";re
120 print "Premier clic : ";b1;", second : ";b2
130 end
8000 ' 33,f : P0-P1 = m ; resultat de P0 a P4 dans r0 a r4
8010 while peek($ff00) : wend : doke $ff04, m
8020 poke $ff01, f : poke $ff00, 33
8030 while peek($ff00) : wend
8040 r0 = peek($ff04) : r1 = peek($ff05) : r2 = peek($ff06) : r4 = peek($ff08)
8050 return
8100 ' 33,2 Get Next Event dans l'EventRecord e, masque m ; r4 = 1 si un evenement est rendu
8110 while peek($ff00) : wend : doke $ff04, e : doke $ff06, m : f = 2 : goto 8020
8200 ' laisse le temps aux touches tapees d'arriver : cs centiemes
8210 t0 = time()
8220 while time() - t0 < cs : wend
8230 return
8300 ' la file du clavier (groupe 2) a recu les memes touches : on la vide
8310 while inkey$() <> "" : wend
8320 return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Enfonces : 2, relaches : 2
Premier clic : 1, second : 129
Assembleur 65C02 (64tass)
; Compter les événements en attente (groupe 33, fonction 3, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<b0
        ldx #>b0
        jsr envoi
        jsr depart                 ; le banc clique deux fois, vite : un double clic
_att:   lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6
        cmp #2
        bcs _fin
        lda #<600
        ldx #>600
        jsr ecoule
        bcc _att
_fin:
        lda #<b2
        ldx #>b2
        jsr envoi
        lda ControlPort+6
        sta en
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+6
        sta re
        lda #<b4
        ldx #>b4
        jsr envoi
        lda ev+2                   ; bouton qui a changé
        sta b1v
        lda #<b5
        ldx #>b5
        jsr envoi
        lda ev+2                   ; bit 7 : double clic
        sta b2v
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda en
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda re
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda b1v
        jsr decimal
        lda #<t9
        ldx #>t9
        jsr ecrire
        lda b2v
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

ev:     .fill 8                    ; EventRecord : type, message, message2, modificateurs, X, Y
b0:     .byte 33, 1, 2             ; 33,1 : Init Events
        .word 0
b1:     .byte 33, 3, 2             ; Event Available, bit 4 : type 5, bouton relâché
        .word $10
b2:     .byte 33, 3, 2             ; bit 3 : type 4, bouton enfoncé
        .word $08
en:     .byte 0
b3:     .byte 33, 3, 2             ; 33,3
        .word $10
re:     .byte 0
b4:     .byte 33, 2, 4             ; 33,2 : Get Next Event
        .word ev, $08
b1v:    .byte 0
b2v:    .byte 0
b5:     .byte 33, 2, 4             ; 33,2 : Get Next Event
        .word ev, $08
t6:     .text "Enfonces : ", 0
t7:     .text ", relaches : ", 0
t8:     .text "Premier clic : ", 0
t9:     .text ", second : ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Note l'instant de départ (1,1 : temps en centièmes de seconde, 16 bits bas).
depart: jsr temps
        lda tl
        sta t0
        lda th
        sta t0+1
        rts

; C = 1 si au moins A (poids faible), X (poids fort) centièmes se sont écoulés depuis depart.
ecoule: sta duree
        stx duree+1
        jsr temps
        sec
        lda tl
        sbc t0
        sta tl
        lda th
        sbc t0+1
        sta th
        lda tl
        cmp duree
        lda th
        sbc duree+1
        rts

; Attend A (poids faible), X (poids fort) centièmes : le temps aux touches tapées d'arriver.
attendre:
        pha
        phx
        jsr depart
        plx
        pla
_att:   pha
        phx
        jsr ecoule
        plx
        pla
        bcc _att
        rts

temps:  jsr WaitMessage
        lda #1
        ldx #1                     ; 1,1 : temps
        jsr appel
        lda ControlPort+4
        sta tl
        lda ControlPort+5
        sta th
        rts

; La file du clavier (groupe 2) a reçu les mêmes touches : on la vide.
vider:  jsr WaitMessage
        lda #2
        ldx #1                     ; 2,1 : lire un caractère, 0 si aucun
        jsr appel
        lda ControlPort+4
        bne vider
        rts

t0:     .word 0
tl:     .byte 0
th:     .byte 0
duree:  .word 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Enfonces : 2, relaches : 2
Premier clic : 1, second : 129

33,4 Flush Events Trinity

Jette les événements en file d'un type demandé.

Entrées
OctetsTypeRôle
P0-P1uint16masque des types (bit n-1 pour le type n, 0 = tous)

Sorties : aucune.

« abc » donne 6 événements : 3 touches enfoncées, 3 relâchées. Le masque 2 jette les relâchements, le masque 0 tout le reste. En NeoBASIC, la file reçoit en plus le relâchement de la touche Entrée qui a lancé `run` : 7 événements au départ. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Discards the queued events whose type is in the mask Parameters:0,1 (0 = all).

C (llvm-mos)
/* Vider la file d'événements (groupe 33, fonction 4, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Event Manager : un EventRecord = type, message, message2, modificateurs, X, Y (8 octets). */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static uint16_t temps(void) {                   /* 1,1 : temps en centièmes de seconde (16 bits bas) */
    libre();
    api(1, 1);
    return ControlPort.params[0] | ControlPort.params[1] << 8;
}
static void attendre(uint16_t cs) {             /* laisse le temps aux touches tapées d'arriver */
    uint16_t t0 = temps();
    while (temps() - t0 < cs)
        ;
}
static void init_events(uint16_t masque) {      /* 33,1 Init Events */
    libre(); p16(0, masque); api(33, 1);
}
static uint8_t disponibles(uint16_t masque) {   /* 33,3 Event Available */
    libre(); p16(0, masque); api(33, 3);
    return ControlPort.params[2];
}
static uint8_t suivant(EventRecord *e, uint16_t masque) {   /* 33,2 Get Next Event : 1 si un événement est rendu */
    libre(); p16(0, (uint16_t)e); p16(2, masque); api(33, 2);
    return ControlPort.params[4];
}
static void vider_clavier(void) {               /* la file du clavier (groupe 2) a reçu les mêmes touches : on la vide */
    do { libre(); api(2, 1); } while (ControlPort.params[0]);
}

int main(void) {
    uint8_t a, b, c;
    init_events(0);
    attendre(100);                      /* le banc tape « abc » : 3 enfoncées, 3 relâchées */
    a = disponibles(0);
    libre(); p16(0, 2); api(33, 4);     /* Flush Events, masque 2 : bit 1 = type 2, touche relâchée */
    b = disponibles(0);
    libre(); p16(0, 0); api(33, 4);     /* masque 0 : tout */
    c = disponibles(0);
    vider_clavier();
    printf("Avant : %u, sans relachees : %u, tout vide : %u\n", a, b, c);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Avant : 6, sans relachees : 3, tout vide : 0
Mad Pascal
// Vider la file d'événements (groupe 33, fonction 4, Trinity).
program ev4;
uses crt, neo6502;
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;   // 8 octets

procedure appel(f: byte);                       // appel 33,f (paramètres déjà posés)
begin
  NeoSendMessage(33, f);
  NeoWaitMessage;
end;

procedure attendre(cs: cardinal);               // laisse le temps aux touches tapées d'arriver
var t0: cardinal;
begin
  t0 := NeoGetTimer;
  while NeoGetTimer - t0 < cs do ;
end;

procedure init_events(masque: word);            // 33,1 Init Events
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(1);
end;

function disponibles(masque: word): byte;       // 33,3 Event Available
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(3);
  result := NeoMessage.params[2];
end;

function suivant(e: pointer; masque: word): byte;   // 33,2 Get Next Event : 1 si un événement est rendu
begin
  NeoWaitMessage;
  wordParams[0] := word(e);
  wordParams[1] := masque;
  appel(2);
  result := NeoMessage.params[4];
end;

procedure vider_clavier;                        // la file du clavier (groupe 2) a reçu les mêmes touches : on la vide
begin
  repeat
    NeoSendMessage(2, 1);
    NeoWaitMessage;
  until NeoMessage.params[0] = 0;
end;

var a, b, c: byte;
begin
  init_events(0);
  attendre(100);                                // le banc tape « abc » : 3 enfoncées, 3 relâchées
  a := disponibles(0);
  NeoWaitMessage;
  wordParams[0] := 2;                           // Flush Events, masque 2 : bit 1 = type 2, touche relâchée
  appel(4);
  b := disponibles(0);
  NeoWaitMessage;
  wordParams[0] := 0;                           // masque 0 : tout
  appel(4);
  c := disponibles(0);
  vider_clavier;
  writeln('Avant : ', a, ', sans relachees : ', b, ', tout vide : ', c);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Avant : 6, sans relachees : 3, tout vide : 0
NeoBASIC
10 ' Vider la file d'evenements (groupe 33, fonction 4, Trinity)
20 m = 0 : f = 1 : gosub 8000 : ' 33,1
30 cs = 100 : gosub 8200 : ' le banc tape « abc » : 3 enfoncees, 3 relachees
40 m = 0 : f = 3 : gosub 8000 : a = r2
50 m = 2 : f = 4 : gosub 8000 : ' Flush Events, masque 2 : bit 1 = type 2, touche relachee
60 m = 0 : f = 3 : gosub 8000 : b = r2
70 m = 0 : f = 4 : gosub 8000 : ' masque 0 : tout
80 f = 3 : gosub 8000 : c = r2
90 gosub 8300
100 print "Avant : ";a;", sans relachees : ";b;", tout vide : ";c
110 end
8000 ' 33,f : P0-P1 = m ; resultat de P0 a P4 dans r0 a r4
8010 while peek($ff00) : wend : doke $ff04, m
8020 poke $ff01, f : poke $ff00, 33
8030 while peek($ff00) : wend
8040 r0 = peek($ff04) : r1 = peek($ff05) : r2 = peek($ff06) : r4 = peek($ff08)
8050 return
8100 ' 33,2 Get Next Event dans l'EventRecord e, masque m ; r4 = 1 si un evenement est rendu
8110 while peek($ff00) : wend : doke $ff04, e : doke $ff06, m : f = 2 : goto 8020
8200 ' laisse le temps aux touches tapees d'arriver : cs centiemes
8210 t0 = time()
8220 while time() - t0 < cs : wend
8230 return
8300 ' la file du clavier (groupe 2) a recu les memes touches : on la vide
8310 while inkey$() <> "" : wend
8320 return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Avant : 7, sans relachees : 3, tout vide : 0
Assembleur 65C02 (64tass)
; Vider la file d'événements (groupe 33, fonction 4, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<100
        ldx #>100
        jsr attendre               ; le banc tape « abc » : 3 enfoncées, 3 relâchées
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+6
        sta a
        lda #<b2
        ldx #>b2
        jsr envoi
        lda #<b3
        ldx #>b3
        jsr envoi
        lda ControlPort+6
        sta b
        lda #<b4
        ldx #>b4
        jsr envoi
        lda #<b5
        ldx #>b5
        jsr envoi
        lda ControlPort+6
        sta c
        jsr vider
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda a
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda b
        jsr decimal
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda c
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

b0:     .byte 33, 1, 2             ; 33,1 : Init Events
        .word 0
b1:     .byte 33, 3, 2             ; 33,3 : Event Available
        .word 0
a:      .byte 0
b2:     .byte 33, 4, 2             ; Flush Events, masque 2 : bit 1 = type 2, touche relâchée
        .word 2
b3:     .byte 33, 3, 2             ; 33,3
        .word 0
b:      .byte 0
b4:     .byte 33, 4, 2             ; masque 0 : tout
        .word 0
b5:     .byte 33, 3, 2             ; 33,3
        .word 0
c:      .byte 0
t6:     .text "Avant : ", 0
t7:     .text ", sans relachees : ", 0
t8:     .text ", tout vide : ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Note l'instant de départ (1,1 : temps en centièmes de seconde, 16 bits bas).
depart: jsr temps
        lda tl
        sta t0
        lda th
        sta t0+1
        rts

; C = 1 si au moins A (poids faible), X (poids fort) centièmes se sont écoulés depuis depart.
ecoule: sta duree
        stx duree+1
        jsr temps
        sec
        lda tl
        sbc t0
        sta tl
        lda th
        sbc t0+1
        sta th
        lda tl
        cmp duree
        lda th
        sbc duree+1
        rts

; Attend A (poids faible), X (poids fort) centièmes : le temps aux touches tapées d'arriver.
attendre:
        pha
        phx
        jsr depart
        plx
        pla
_att:   pha
        phx
        jsr ecoule
        plx
        pla
        bcc _att
        rts

temps:  jsr WaitMessage
        lda #1
        ldx #1                     ; 1,1 : temps
        jsr appel
        lda ControlPort+4
        sta tl
        lda ControlPort+5
        sta th
        rts

; La file du clavier (groupe 2) a reçu les mêmes touches : on la vide.
vider:  jsr WaitMessage
        lda #2
        ldx #1                     ; 2,1 : lire un caractère, 0 si aucun
        jsr appel
        lda ControlPort+4
        bne vider
        rts

t0:     .word 0
tl:     .byte 0
th:     .byte 0
duree:  .word 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Avant : 6, sans relachees : 3, tout vide : 0

33,5 Set Timer Trinity

Programme un minuteur qui poste un événement à intervalle régulier.

Entrées
OctetsTypeRôle
P0uint8numéro du minuteur (0 à 3)
P1-P2uint16période en ticks de 10 ms (0 l'arrête)

Sorties : aucune.

L'événement du minuteur (type 8) porte son numéro dans message. Les événements ne sont créés que lorsqu'on interroge la file, au plus un par minuteur et par interrogation. L'exemple attend trois événements du minuteur 2, l'arrête, puis vérifie qu'il n'en vient plus. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Programs timer Parameter:0 (0-3) to post a timer event every Parameters:1,2 ticks of 10 ms (0 stops it). Timer events are generated when the queue is polled, at most one per timer per poll.

C (llvm-mos)
/* Programmer un minuteur (groupe 33, fonction 5, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Event Manager : un EventRecord = type, message, message2, modificateurs, X, Y (8 octets). */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static uint16_t temps(void) {                   /* 1,1 : temps en centièmes de seconde (16 bits bas) */
    libre();
    api(1, 1);
    return ControlPort.params[0] | ControlPort.params[1] << 8;
}
static void attendre(uint16_t cs) {             /* laisse le temps aux touches tapées d'arriver */
    uint16_t t0 = temps();
    while (temps() - t0 < cs)
        ;
}
static void init_events(uint16_t masque) {      /* 33,1 Init Events */
    libre(); p16(0, masque); api(33, 1);
}
static uint8_t disponibles(uint16_t masque) {   /* 33,3 Event Available */
    libre(); p16(0, masque); api(33, 3);
    return ControlPort.params[2];
}
static uint8_t suivant(EventRecord *e, uint16_t masque) {   /* 33,2 Get Next Event : 1 si un événement est rendu */
    libre(); p16(0, (uint16_t)e); p16(2, masque); api(33, 2);
    return ControlPort.params[4];
}
static void vider_clavier(void) {               /* la file du clavier (groupe 2) a reçu les mêmes touches : on la vide */
    do { libre(); api(2, 1); } while (ControlPort.params[0]);
}

static EventRecord ev;

static void minuteur(uint8_t n, uint16_t ticks) {   /* 33,5 Set Timer : ticks de 10 ms, 0 l'arrête */
    libre(); ControlPort.params[0] = n; p16(1, ticks); api(33, 5);
}

int main(void) {
    uint8_t n = 0, m = 0, apres;
    init_events(0);
    minuteur(2, 10);                    /* minuteur 2 : un événement toutes les 100 ms */
    while (n < 3)
        if (suivant(&ev, 0x80)) {       /* bit 7 : type 8, minuteur */
            n++;
            m = ev.message;             /* numéro du minuteur */
        }
    minuteur(2, 0);
    attendre(50);
    apres = disponibles(0x80);
    printf("Minuteur %u : %u evenements ; arrete : %u\n", m, n, apres);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Minuteur 2 : 3 evenements ; arrete : 0
Mad Pascal
// Programmer un minuteur (groupe 33, fonction 5, Trinity).
program ev5;
uses crt, neo6502;
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;   // 8 octets

procedure appel(f: byte);                       // appel 33,f (paramètres déjà posés)
begin
  NeoSendMessage(33, f);
  NeoWaitMessage;
end;

procedure attendre(cs: cardinal);               // laisse le temps aux touches tapées d'arriver
var t0: cardinal;
begin
  t0 := NeoGetTimer;
  while NeoGetTimer - t0 < cs do ;
end;

procedure init_events(masque: word);            // 33,1 Init Events
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(1);
end;

function disponibles(masque: word): byte;       // 33,3 Event Available
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(3);
  result := NeoMessage.params[2];
end;

function suivant(e: pointer; masque: word): byte;   // 33,2 Get Next Event : 1 si un événement est rendu
begin
  NeoWaitMessage;
  wordParams[0] := word(e);
  wordParams[1] := masque;
  appel(2);
  result := NeoMessage.params[4];
end;

procedure vider_clavier;                        // la file du clavier (groupe 2) a reçu les mêmes touches : on la vide
begin
  repeat
    NeoSendMessage(2, 1);
    NeoWaitMessage;
  until NeoMessage.params[0] = 0;
end;

procedure minuteur(n: byte; ticks: word);      // 33,5 Set Timer : ticks de 10 ms, 0 l'arrête
begin
  NeoWaitMessage;
  NeoMessage.params[0] := n;
  NeoMessage.params[1] := lo(ticks);
  NeoMessage.params[2] := hi(ticks);
  appel(5);
end;

var ev: EventRecord;
    n, m, apres: byte;
begin
  n := 0;
  m := 0;
  init_events(0);
  minuteur(2, 10);                              // minuteur 2 : un événement toutes les 100 ms
  while n < 3 do
    if suivant(@ev, $80) = 1 then begin         // bit 7 : type 8, minuteur
      inc(n);
      m := ev.message;                          // numéro du minuteur
    end;
  minuteur(2, 0);
  attendre(50);
  apres := disponibles($80);
  writeln('Minuteur ', m, ' : ', n, ' evenements ; arrete : ', apres);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Minuteur 2 : 3 evenements ; arrete : 0
NeoBASIC
10 ' Programmer un minuteur (groupe 33, fonction 5, Trinity)
20 e = alloc(8) : n = 0
30 m = 0 : f = 1 : gosub 8000 : ' 33,1
40 tk = 10 : gosub 2000 : ' minuteur 2 : un evenement toutes les 100 ms
50 m = $80 : gosub 8100 : ' bit 7 : type 8, minuteur
60 if r4 = 1 then n = n + 1 : mn = peek(e + 1) : ' message : numero du minuteur
70 if n < 3 then 50
80 tk = 0 : gosub 2000
90 cs = 50 : gosub 8200
100 m = $80 : f = 3 : gosub 8000 : ap = r2
110 print "Minuteur ";mn;" : ";n;" evenements ; arrete : ";ap
120 end
2000 ' 33,5 Set Timer : minuteur 2, tk ticks de 10 ms, 0 l'arrete
2010 while peek($ff00) : wend : poke $ff04, 2 : doke $ff05, tk : f = 5 : goto 8020
8000 ' 33,f : P0-P1 = m ; resultat de P0 a P4 dans r0 a r4
8010 while peek($ff00) : wend : doke $ff04, m
8020 poke $ff01, f : poke $ff00, 33
8030 while peek($ff00) : wend
8040 r0 = peek($ff04) : r1 = peek($ff05) : r2 = peek($ff06) : r4 = peek($ff08)
8050 return
8100 ' 33,2 Get Next Event dans l'EventRecord e, masque m ; r4 = 1 si un evenement est rendu
8110 while peek($ff00) : wend : doke $ff04, e : doke $ff06, m : f = 2 : goto 8020
8200 ' laisse le temps aux touches tapees d'arriver : cs centiemes
8210 t0 = time()
8220 while time() - t0 < cs : wend
8230 return
8300 ' la file du clavier (groupe 2) a recu les memes touches : on la vide
8310 while inkey$() <> "" : wend
8320 return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Minuteur 2 : 3 evenements ; arrete : 0
Assembleur 65C02 (64tass)
; Programmer un minuteur (groupe 33, fonction 5, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<b1
        ldx #>b1
        jsr envoi
_att:   lda #<b2
        ldx #>b2
        jsr envoi
        lda ControlPort+8
        beq _att
        inc n
        lda ev+1                   ; message : numéro du minuteur
        sta mn
        lda n
        cmp #3
        bne _att
        lda #<b3
        ldx #>b3
        jsr envoi
        lda #<50
        ldx #>50
        jsr attendre
        lda #<b4
        ldx #>b4
        jsr envoi
        lda ControlPort+6
        sta ap
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda mn
        jsr decimal
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda n
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda ap
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

ev:     .fill 8                    ; EventRecord : type, message, message2, modificateurs, X, Y
n:      .byte 0
mn:     .byte 0
b0:     .byte 33, 1, 2             ; 33,1 : Init Events
        .word 0
b1:     .byte 33, 5, 3, 2          ; Set Timer : minuteur 2, toutes les 10 × 10 ms
        .word 10
b2:     .byte 33, 2, 4             ; bit 7 : type 8, minuteur
        .word ev, $80
b3:     .byte 33, 5, 3, 2          ; 0 : arrêt
        .word 0
b4:     .byte 33, 3, 2             ; 33,3 : Event Available
        .word $80
ap:     .byte 0
t5:     .text "Minuteur ", 0
t6:     .text " : ", 0
t7:     .text " evenements ; arrete : ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Note l'instant de départ (1,1 : temps en centièmes de seconde, 16 bits bas).
depart: jsr temps
        lda tl
        sta t0
        lda th
        sta t0+1
        rts

; C = 1 si au moins A (poids faible), X (poids fort) centièmes se sont écoulés depuis depart.
ecoule: sta duree
        stx duree+1
        jsr temps
        sec
        lda tl
        sbc t0
        sta tl
        lda th
        sbc t0+1
        sta th
        lda tl
        cmp duree
        lda th
        sbc duree+1
        rts

; Attend A (poids faible), X (poids fort) centièmes : le temps aux touches tapées d'arriver.
attendre:
        pha
        phx
        jsr depart
        plx
        pla
_att:   pha
        phx
        jsr ecoule
        plx
        pla
        bcc _att
        rts

temps:  jsr WaitMessage
        lda #1
        ldx #1                     ; 1,1 : temps
        jsr appel
        lda ControlPort+4
        sta tl
        lda ControlPort+5
        sta th
        rts

; La file du clavier (groupe 2) a reçu les mêmes touches : on la vide.
vider:  jsr WaitMessage
        lda #2
        ldx #1                     ; 2,1 : lire un caractère, 0 si aucun
        jsr appel
        lda ControlPort+4
        bne vider
        rts

t0:     .word 0
tl:     .byte 0
th:     .byte 0
duree:  .word 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Minuteur 2 : 3 evenements ; arrete : 0

33,6 Event Status Trinity

Rend le nombre d'événements en file et dit si des événements ont été perdus, file pleine.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0uint8nombre d'événements en file
P1uint81 si des événements ont été perdus depuis le dernier appel (remis à 0 par l'appel)

Le banc tape 16 touches, soit 32 événements, sans que le programme lise la file. Elle en garde 31 et signale la perte ; la documentation de Trinity annonce une file de 32 enregistrements. La seconde lecture montre l'indicateur remis à 0. NeoBASIC n'a pas de mot-clé pour cet appel.

Texte de la documentation du firmware (anglais)

Returns the number of queued events in Parameter:0 and, in Parameter:1, 1 if events were lost because the queue was full since the last call (the flag is then cleared).

C (llvm-mos)
/* Savoir si des événements ont été perdus (groupe 33, fonction 6, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

/* Event Manager : un EventRecord = type, message, message2, modificateurs, X, Y (8 octets). */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;

static void p16(uint8_t i, uint16_t v) {        /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}
static uint16_t temps(void) {                   /* 1,1 : temps en centièmes de seconde (16 bits bas) */
    libre();
    api(1, 1);
    return ControlPort.params[0] | ControlPort.params[1] << 8;
}
static void attendre(uint16_t cs) {             /* laisse le temps aux touches tapées d'arriver */
    uint16_t t0 = temps();
    while (temps() - t0 < cs)
        ;
}
static void init_events(uint16_t masque) {      /* 33,1 Init Events */
    libre(); p16(0, masque); api(33, 1);
}
static uint8_t disponibles(uint16_t masque) {   /* 33,3 Event Available */
    libre(); p16(0, masque); api(33, 3);
    return ControlPort.params[2];
}
static uint8_t suivant(EventRecord *e, uint16_t masque) {   /* 33,2 Get Next Event : 1 si un événement est rendu */
    libre(); p16(0, (uint16_t)e); p16(2, masque); api(33, 2);
    return ControlPort.params[4];
}
static void vider_clavier(void) {               /* la file du clavier (groupe 2) a reçu les mêmes touches : on la vide */
    do { libre(); api(2, 1); } while (ControlPort.params[0]);
}

int main(void) {
    uint8_t n1, p1, n2, p2;
    init_events(0);
    attendre(300);                      /* le banc tape 16 touches : 32 événements */
    libre(); api(33, 6);                /* Event Status */
    n1 = ControlPort.params[0];
    p1 = ControlPort.params[1];
    libre(); api(33, 6);                /* l'indicateur de perte est remis à 0 */
    n2 = ControlPort.params[0];
    p2 = ControlPort.params[1];
    init_events(0);
    vider_clavier();
    printf("En file : %u, perdus : %u\nDeuxieme lecture : %u, perdus : %u\n", n1, p1, n2, p2);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0
Mad Pascal
// Savoir si des événements ont été perdus (groupe 33, fonction 6, Trinity).
program ev6;
uses crt, neo6502;
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;   // 8 octets

procedure appel(f: byte);                       // appel 33,f (paramètres déjà posés)
begin
  NeoSendMessage(33, f);
  NeoWaitMessage;
end;

procedure attendre(cs: cardinal);               // laisse le temps aux touches tapées d'arriver
var t0: cardinal;
begin
  t0 := NeoGetTimer;
  while NeoGetTimer - t0 < cs do ;
end;

procedure init_events(masque: word);            // 33,1 Init Events
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(1);
end;

function disponibles(masque: word): byte;       // 33,3 Event Available
begin
  NeoWaitMessage;
  wordParams[0] := masque;
  appel(3);
  result := NeoMessage.params[2];
end;

function suivant(e: pointer; masque: word): byte;   // 33,2 Get Next Event : 1 si un événement est rendu
begin
  NeoWaitMessage;
  wordParams[0] := word(e);
  wordParams[1] := masque;
  appel(2);
  result := NeoMessage.params[4];
end;

procedure vider_clavier;                        // la file du clavier (groupe 2) a reçu les mêmes touches : on la vide
begin
  repeat
    NeoSendMessage(2, 1);
    NeoWaitMessage;
  until NeoMessage.params[0] = 0;
end;

var n1, p1, n2, p2: byte;
begin
  init_events(0);
  attendre(300);                                // le banc tape 16 touches : 32 événements
  NeoWaitMessage;
  appel(6);                                     // Event Status
  n1 := NeoMessage.params[0];
  p1 := NeoMessage.params[1];
  appel(6);                                     // l'indicateur de perte est remis à 0
  n2 := NeoMessage.params[0];
  p2 := NeoMessage.params[1];
  init_events(0);
  vider_clavier;
  writeln('En file : ', n1, ', perdus : ', p1);
  writeln('Deuxieme lecture : ', n2, ', perdus : ', p2);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0
NeoBASIC
10 ' Savoir si des evenements ont ete perdus (groupe 33, fonction 6, Trinity)
20 m = 0 : f = 1 : gosub 8000 : ' 33,1
30 cs = 300 : gosub 8200 : ' le banc tape 16 touches : 32 evenements
40 f = 6 : gosub 2000 : n1 = r0 : p1 = r1 : ' Event Status
50 gosub 2000 : n2 = r0 : p2 = r1 : ' l'indicateur de perte est remis a 0
60 m = 0 : f = 1 : gosub 8000
70 gosub 8300
80 print "En file : ";n1;", perdus : ";p1
90 print "Deuxieme lecture : ";n2;", perdus : ";p2
100 end
2000 ' 33,6 sans parametre
2010 while peek($ff00) : wend : f = 6 : goto 8020
8000 ' 33,f : P0-P1 = m ; resultat de P0 a P4 dans r0 a r4
8010 while peek($ff00) : wend : doke $ff04, m
8020 poke $ff01, f : poke $ff00, 33
8030 while peek($ff00) : wend
8040 r0 = peek($ff04) : r1 = peek($ff05) : r2 = peek($ff06) : r4 = peek($ff08)
8050 return
8100 ' 33,2 Get Next Event dans l'EventRecord e, masque m ; r4 = 1 si un evenement est rendu
8110 while peek($ff00) : wend : doke $ff04, e : doke $ff06, m : f = 2 : goto 8020
8200 ' laisse le temps aux touches tapees d'arriver : cs centiemes
8210 t0 = time()
8220 while time() - t0 < cs : wend
8230 return
8300 ' la file du clavier (groupe 2) a recu les memes touches : on la vide
8310 while inkey$() <> "" : wend
8320 return
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0
Assembleur 65C02 (64tass)
; Savoir si des événements ont été perdus (groupe 33, fonction 6, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<b0
        ldx #>b0
        jsr envoi
        lda #<300
        ldx #>300
        jsr attendre               ; le banc tape 16 touches : 32 événements
        lda #<b1
        ldx #>b1
        jsr envoi
        lda ControlPort+4
        sta n1
        lda ControlPort+5
        sta p1
        lda #<b2
        ldx #>b2
        jsr envoi
        lda ControlPort+4
        sta n2
        lda ControlPort+5
        sta p2
        lda #<b3
        ldx #>b3
        jsr envoi
        jsr vider
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda n1
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda p1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda n2
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda p2
        jsr decimal
        lda #13
        jsr WriteCharacter
        rts

n1:     .byte 0
p1:     .byte 0
n2:     .byte 0
p2:     .byte 0
b0:     .byte 33, 1, 2             ; 33,1 : Init Events
        .word 0
b1:     .byte 33, 6, 0             ; Event Status
b2:     .byte 33, 6, 0             ; l'indicateur de perte est remis à 0
b3:     .byte 33, 1, 2             ; 33,1
        .word 0
t4:     .text "En file : ", 0
t5:     .text ", perdus : ", 0
t6:     .text "Deuxieme lecture : ", 0
t7:     .text ", perdus : ", 0

; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi:  sta blk
        stx blk+1
        jsr WaitMessage
        ldy #2
        lda (blk),y                ; nombre de paramètres
        clc
        adc #3
        sta fin
        ldy #3
_copie: cpy fin
        beq _lance
        lda (blk),y
        sta ControlPort+1,y        ; octet 3 du bloc -> P0 ($FF04)...
        iny
        bra _copie
_lance: ldy #1
        lda (blk),y
        tax
        lda (blk)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16:  sta n16
        stx n16+1
        stz vu
        ldy #0                     ; puissance de 10 en cours : 10000, 1000, 100, 10
_p:     ldx #0                     ; chiffre
_s:     lda n16
        sec
        sbc p10l,y
        pha
        lda n16+1
        sbc p10h,y
        bcc _neg                   ; plus petit : chiffre trouvé
        sta n16+1
        pla
        sta n16
        inx
        bra _s
_neg:   pla
        txa
        ora vu
        beq _suiv                  ; pas de zéro de tête
        txa
        ora #'0'
        phy
        jsr WriteCharacter
        ply
        lda #1
        sta vu
_suiv:  iny
        cpy #4
        bne _p
        lda n16                    ; les unités, toujours
        ora #'0'
        jmp WriteCharacter
p10l:   .byte <10000, <1000, <100, <10
p10h:   .byte >10000, >1000, >100, >10
n16:    .word 0
vu:     .byte 0

; Note l'instant de départ (1,1 : temps en centièmes de seconde, 16 bits bas).
depart: jsr temps
        lda tl
        sta t0
        lda th
        sta t0+1
        rts

; C = 1 si au moins A (poids faible), X (poids fort) centièmes se sont écoulés depuis depart.
ecoule: sta duree
        stx duree+1
        jsr temps
        sec
        lda tl
        sbc t0
        sta tl
        lda th
        sbc t0+1
        sta th
        lda tl
        cmp duree
        lda th
        sbc duree+1
        rts

; Attend A (poids faible), X (poids fort) centièmes : le temps aux touches tapées d'arriver.
attendre:
        pha
        phx
        jsr depart
        plx
        pla
_att:   pha
        phx
        jsr ecoule
        plx
        pla
        bcc _att
        rts

temps:  jsr WaitMessage
        lda #1
        ldx #1                     ; 1,1 : temps
        jsr appel
        lda ControlPort+4
        sta tl
        lda ControlPort+5
        sta th
        rts

; La file du clavier (groupe 2) a reçu les mêmes touches : on la vide.
vider:  jsr WaitMessage
        lda #2
        ldx #1                     ; 2,1 : lire un caractère, 0 si aucun
        jsr appel
        lda ControlPort+4
        bne vider
        rts

t0:     .word 0
tl:     .byte 0
th:     .byte 0
duree:  .word 0

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
blk      = $82
diviseur: .byte 0
fin:     .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0

← L'API du Neo6502