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.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | uint16 | types à 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;
}Touches enfoncees recues : 2
Apres une nouvelle initialisation : 0Mad 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.Touches enfoncees recues : 2
Apres une nouvelle initialisation : 0NeoBASIC
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 returnTouches enfoncees recues : 2
Apres une nouvelle initialisation : 0Assembleur 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 0Touches enfoncees recues : 2
Apres une nouvelle initialisation : 033,2 Get Next Event Trinity
Retire de la file le plus ancien événement d'un type demandé et l'écrit dans un EventRecord.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse de l'EventRecord (8 octets) |
P2-P3 | uint16 | masque des types (0 = tous) |
| Octets | Type | Rôle |
|---|---|---|
P4 | uint8 | 1 si un événement est rendu, 0 pour un événement nul (type 0, avec la position de la souris) |
erreur | uint8 | non 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;
}Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0Mad 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.Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0NeoBASIC
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 returnType 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 0Assembleur 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 0Type 1, caractere 97, code 4, modificateurs 0
Type 1, caractere 66, code 5, modificateurs 2
Plus de touche : rendu 0, type 033,3 Event Available Trinity
Compte les événements en file d'un type demandé, sans les retirer.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | uint16 | masque des types (bit n-1 pour le type n, 0 = tous) |
| Octets | Type | Rôle |
|---|---|---|
P2 | uint8 | nombre 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;
}Enfonces : 2, relaches : 2
Premier clic : 1, second : 129Mad 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.Enfonces : 2, relaches : 2
Premier clic : 1, second : 129NeoBASIC
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 returnEnfonces : 2, relaches : 2
Premier clic : 1, second : 129Assembleur 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 0Enfonces : 2, relaches : 2
Premier clic : 1, second : 12933,4 Flush Events Trinity
Jette les événements en file d'un type demandé.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | uint16 | masque 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;
}Avant : 6, sans relachees : 3, tout vide : 0Mad 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.Avant : 6, sans relachees : 3, tout vide : 0NeoBASIC
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 returnAvant : 7, sans relachees : 3, tout vide : 0Assembleur 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 0Avant : 6, sans relachees : 3, tout vide : 033,5 Set Timer Trinity
Programme un minuteur qui poste un événement à intervalle régulier.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du minuteur (0 à 3) |
P1-P2 | uint16 | pé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;
}Minuteur 2 : 3 evenements ; arrete : 0Mad 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.Minuteur 2 : 3 evenements ; arrete : 0NeoBASIC
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 returnMinuteur 2 : 3 evenements ; arrete : 0Assembleur 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 0Minuteur 2 : 3 evenements ; arrete : 033,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.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | nombre d'événements en file |
P1 | uint8 | 1 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;
}En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0Mad 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.En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0NeoBASIC
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 returnEn file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0Assembleur 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 0En file : 31, perdus : 1
Deuxieme lecture : 31, perdus : 0