Group 33 — Event Manager 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
The event manager of the Trinity toolbox stores keyboard, mouse and timers in a single queue, polled by 33,2. Types: 1 key down, 2 key up, 3 auto key, 4 mouse down, 5 mouse up, 6 mouse move (consecutive moves are merged), 7 wheel, 8 timer, 9 window update (group 34), 10 window activation.
An EventRecord is 8 bytes in 6502 RAM: type, message, message2, modifiers, X and Y (16 bits). Masks have bit n-1 for type n: 1 for key presses, $10 for button releases, $80 for timers; 0 means all types.
The examples receive keys typed or clicks of the mouse emulated by the bench, wait a little with 1,1, then read the queue.
33,1 Init Events Trinity
Starts the event manager with an empty queue: keyboard, mouse and timer events are stored in it.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | uint16 | types to collect (bit n-1 for type n, 0 = all) |
Outputs: none.
Only the types in the mask enter the queue: with mask 1, the example only gets the two key presses of "ab", not their releases. Calling 33,1 again empties the queue. The keyboard queue of group 2 still receives the keys: the examples empty it before returning. 1,0 (DSP Reset) and 32,19 (Toolbox Reset) stop the manager. NeoBASIC has no keyword for this call.
Firmware documentation text
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 : 065C02 assembly (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
Removes the oldest queued event of a requested type and writes it into an EventRecord.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the EventRecord (8 bytes) |
P2-P3 | uint16 | type mask (0 = all) |
| Bytes | Type | Meaning |
|---|---|---|
P4 | uint8 | 1 if an event is returned, 0 for a null event (type 0, with the mouse position) |
erreur | uint8 | non zero if the address is bad |
For a key, message is the ASCII code and message2 the key code: "a" gives 97 and 4, "B" gives 66, 5 and modifiers 2 (Shift). Due timers come first. There is no blocking wait: the queue is polled in a loop. NeoBASIC has no keyword for this call.
Firmware documentation text
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 065C02 assembly (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
Counts the queued events of a requested type, without removing them.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | uint16 | type mask (bit n-1 for type n, 0 = all) |
| Bytes | Type | Meaning |
|---|---|---|
P2 | uint8 | number of events |
The example waits for two button releases (type 5), then counts. For a button, message2 is the button that changed, with bit 7 set for a double click: the second, quick click gives 129. On the bench, each button change also comes with a move (type 6): the example therefore counts with masks. NeoBASIC has no keyword for this call.
Firmware documentation text
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 : 12965C02 assembly (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
Discards the queued events of a requested type.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | uint16 | type mask (bit n-1 for type n, 0 = all) |
Outputs: none.
"abc" gives 6 events: 3 key presses, 3 releases. Mask 2 discards the releases, mask 0 everything else. In NeoBASIC, the queue also gets the release of the Enter key that started `run`: 7 events at the start. NeoBASIC has no keyword for this call.
Firmware documentation text
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 : 065C02 assembly (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
Programs a timer that posts an event at regular intervals.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | timer number (0 to 3) |
P1-P2 | uint16 | period in 10 ms ticks (0 stops it) |
Outputs: none.
The timer event (type 8) carries its number in message. Events are only created when the queue is polled, at most one per timer per poll. The example waits for three events of timer 2, stops it, then checks that no more come. NeoBASIC has no keyword for this call.
Firmware documentation text
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 : 065C02 assembly (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
Returns the number of queued events and tells whether events were lost because the queue was full.
Inputs: none.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | number of queued events |
P1 | uint8 | 1 if events were lost since the last call (cleared by the call) |
The bench types 16 keys, that is 32 events, without the program reading the queue. It keeps 31 and reports the loss; the Trinity documentation announces a queue of 32 records. The second read shows the flag cleared. NeoBASIC has no keyword for this call.
Firmware documentation text
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 : 065C02 assembly (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