Tachibana
Langue : français

Groupe 1 — Système Officiel

1,0 DSP Reset · 1,1 Timer · 1,2 Key Status · 1,3 Basic · 1,4 Credits · 1,5 Serial Status · 1,6 Locale · 1,7 System Reset · 1,8 MOS · 1,10 Write character to debug · 1,11 Return Version Information · 1,12 Set Interrupt Tick · 1,13 Get Interrupt Tick · 1,16 Set Frame Interrupt · 1,17 Get Frame Interrupt · 1,18 Select Bank · 1,19 Get Bank Info · 1,20 Get Date Time · 1,21 Set Date Time · 1,22 Write Bank · 1,23 Sync Clock From Modem · 1,24 Set Time Zone · 1,25 Get Time Zone · 1,26 Bank Checksum · 1,27 Apply Boot Choice

1,0 DSP Reset Modifié par Trinity

Réinitialise le système de messagerie (la boîte aux lettres) et les composants qui en dépendent. À n'utiliser qu'en cas de besoin exceptionnel.

Entrées : aucune.

Sorties : aucune.

La documentation officielle précise « normalement, ne devrait pas être utilisé ». Un programme ordinaire n'en a pas besoin. Avec Trinity, la console est effacée par l'appel : l'exemple affiche son message après.

Différence dans Trinity — Trinity en fait un reset logiciel : les états de l'API reviennent à ceux de la mise sous tension (console effacée, mode 0, palette, sprites, polices, toolbox, aucune banque de mémoire projetée, son et flux arrêtés, interruptions de tick et de trame coupées). La mémoire du 6502 est gardée, les périphériques USB restent montés ; ni logo ni bip.

Texte de la documentation du firmware (anglais)

Soft reset (Trinity T-36, ADR-0001) : puts the API states back as after power on — console cleared, mode 0, palette, sprites, fonts (2,21 built in, Latin-1 letters), toolbox (as 32,19), no memory bank mapped, sound channels and stream stopped, interrupt tick and frame interrupt off. The 6502 memory is kept, the USB devices stay mounted and the display is not restarted (unless another mode was on). No logo, no beep.

C (llvm-mos)
/* Réinitialiser le système de messagerie (groupe 1, fonction 0). */
#include <stdio.h>
#include <neo6502.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 */
        ;
}

int main(void) {
    while (ControlPort.command)        /* boîte aux lettres libre */
        ;
    api(1, 0);                         /* DSP Reset */
    printf("Messagerie reinitialisee\n");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Messagerie reinitialisee
Mad Pascal
// Réinitialiser le système de messagerie (groupe 1, fonction 0).
program dspreset;
uses crt, neo6502;
begin
  NeoSubReset;                                  // DSP Reset
  NeoWaitMessage;                               // attendre la fin de l'appel
  writeln('Messagerie reinitialisee');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Messagerie reinitialisee
NeoBASIC
10 ' Reinitialiser le systeme de messagerie (groupe 1, fonction 0)
20 while peek($ff00) : wend
30 poke $ff01, 0 : poke $ff00, 1
40 while peek($ff00) : wend
50 print "Messagerie reinitialisee"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Messagerie reinitialisee
Assembleur 65C02 (64tass)
; Réinitialiser le système de messagerie (groupe 1, fonction 0).
        .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:  jsr WaitMessage            ; boîte aux lettres libre
        lda #0
        sta ControlPort+1          ; fonction 0 : DSP Reset
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        jsr WaitMessage
        lda #<message
        sta ptr
        lda #>message
        sta ptr+1
        jmp ecrire

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

message: .text "Messagerie reinitialisee", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Messagerie reinitialisee

1,1 Timer Officiel

Lit le compteur système, qui avance de 100 unités par seconde (une unité = un centième de seconde).

Entrées : aucune.

Sorties
OctetsTypeRôle
P0-P3uint32valeur du compteur (32 bits, octet de poids faible en P0)

Pratique pour chronométrer, cadencer une animation ou attendre sans bloquer. Le compteur démarre à zéro à la mise sous tension.

Mots-clés NeoBASIC qui font cet appel : event(), time(), wait

Texte de la documentation du firmware (anglais)

Deposit the value (32-bits) of the 100Hz system timer into Parameters:0..3.

C (llvm-mos)
/* Chronométrer une boucle avec le compteur à 100 Hz (groupe 1, fonction 1). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    long debut = neo_system_timer();            /* centièmes de seconde */
    for (volatile unsigned i = 0; i < 30000; i++)
        ;
    long duree = neo_system_timer() - debut;
    printf("Boucle : %ld centiemes\n", duree);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Boucle : 14 centiemes
Mad Pascal
// Chronométrer une boucle avec le compteur à 100 Hz (groupe 1, fonction 1).
program chrono;
uses crt, neo6502;
var debut: cardinal;
    i: word;
begin
  debut := NeoGetTimer;                         // centièmes de seconde
  for i := 0 to 29999 do ;
  writeln('Boucle : ', NeoGetTimer - debut, ' centiemes');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Boucle : 8 centiemes
NeoBASIC
10 ' Chronometrer une boucle avec le compteur a 100 Hz (groupe 1, fonction 1)
20 d = time()
30 for i = 1 to 3000 : next i
40 print "Boucle : ";time() - d;" centiemes"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Boucle : 24 centiemes
Assembleur 65C02 (64tass)
; Chronométrer une boucle avec le compteur à 100 Hz (groupe 1, fonction 1).
; Affiche la durée (octet de poids faible, en décimal).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr lire_compteur
        sta debut
        ldx #0                     ; boucle d'attente : 256 x 256 tours
        ldy #0
boucle: dey
        bne boucle
        dex
        bne boucle
        jsr lire_compteur
        sec
        sbc debut                  ; durée, en centièmes
        pha
        ldx #0
texte:  lda message,x              ; "Boucle : "
        beq nombre
        jsr WriteCharacter
        inx
        bne texte
nombre: pla
        jsr decimal
        ldx #0
fin:    lda suffixe,x              ; " centiemes"
        beq retour
        jsr WriteCharacter
        inx
        bne fin
retour: rts

; Groupe 1, fonction 1 : le compteur revient dans les paramètres 0 à 3.
lire_compteur:
        jsr WaitMessage            ; boîte aux lettres libre
        lda #1
        sta ControlPort+1          ; fonction 1 : Timer
        sta ControlPort            ; groupe 1 : écrit en dernier, lance l'appel
        jsr WaitMessage            ; attendre la fin
        lda ControlPort+4          ; octet de poids faible
        rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        ldx #0                     ; x = centaines déjà affichées ?
        ldy #100
        jsr chiffre
        ldy #10
        jsr chiffre
        ora #'0'
        jmp WriteCharacter
chiffre:
        sty diviseur
        ldy #0
div:    cmp diviseur
        bcc fini
        sbc diviseur
        iny
        bne div
fini:   pha
        tya
        bne ecrire
        cpx #0
        beq saute
ecrire: ora #'0'
        jsr WriteCharacter
        ldx #1
saute:  pla
        rts

debut:    .byte 0
diviseur: .byte 0
message:  .text "Boucle : ", 0
suffixe:  .text " centiemes", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Boucle : 5 centiemes

1,2 Key Status Officiel

Indique si une touche est enfoncée, et l'état des touches de modification (Maj, Ctrl, Alt, Méta).

Entrées
OctetsTypeRôle
P0uint8code de la touche (code USB HID : 4 = A, 44 = espace, 80 = flèche gauche)
Sorties
OctetsTypeRôle
P0uint8état de la touche : $FF enfoncée, 0 relâchée
P1uint8touches de modification enfoncées (un bit chacune)

Lit l'état instantané du clavier, sans passer par la file des caractères tapés — idéal pour un jeu. En NeoBASIC, key(n) fait le même appel.

Mots-clés NeoBASIC qui font cet appel : key()

Texte de la documentation du firmware (anglais)

Deposits the state of the specified keyboard key into Parameter:0. State of keyboard modifiers (Shift/Ctrl/Alt/Meta) is returned in Parameter:1. The key which to query is specified in Parameter:0.

C (llvm-mos)
/* Savoir si la barre d'espace est enfoncée (groupe 1, fonction 2). */
#include <stdio.h>
#include <neo/api.h>

#define TOUCHE_ESPACE 44                /* code USB HID de la barre d'espace */

int main(void) {
    uint8_t etat = neo_system_key_status(TOUCHE_ESPACE);
    printf("Espace : %s\n", etat ? "enfoncee" : "relachee");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Espace : relachee
Mad Pascal
// Savoir si la barre d'espace est enfoncée (groupe 1, fonction 2).
program touche;
uses crt, neo6502;
const TOUCHE_ESPACE = 44;                       // code USB HID de la barre d'espace
begin
  if NeoIsKeyPressed(TOUCHE_ESPACE) <> 0 then
    writeln('Espace : enfoncee')
  else
    writeln('Espace : relachee');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Espace : relachee
NeoBASIC
10 ' Savoir si la barre d'espace est enfoncee (groupe 1, fonction 2)
20 ' 44 est le code USB HID de la barre d'espace
30 if key(44)
40   print "Espace : enfoncee"
50 else
60   print "Espace : relachee"
70 endif
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Espace : relachee
Assembleur 65C02 (64tass)
; Savoir si la barre d'espace est enfoncée (groupe 1, fonction 2).
        .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

TOUCHE_ESPACE = 44                 ; code USB HID de la barre d'espace

start:  jsr WaitMessage
        lda #TOUCHE_ESPACE
        sta ControlPort+4          ; P0 : la touche à interroger
        lda #2
        sta ControlPort+1          ; fonction 2 : Key Status
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        jsr WaitMessage
        lda ControlPort+4          ; P0 : $FF enfoncée, 0 relâchée
        beq relachee
        lda #<enfoncee
        ldx #>enfoncee
        bne afficher
relachee:
        lda #<txt_relachee
        ldx #>txt_relachee
afficher:
        sta ptr
        stx ptr+1
        jmp ecrire

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

enfoncee:     .text "Espace : enfoncee", 13, 0
txt_relachee: .text "Espace : relachee", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Espace : relachee

1,3 Basic Modifié par Trinity

Charge l'environnement résident et lui passe la main par un saut indirect via l'adresse 0 : NeoBASIC avec le firmware officiel, NeoDOS avec Trinity.

Entrées : aucune.

Sorties : aucune.

Sert à terminer un programme machine en rendant la main. Le programme appelant est écrasé ; rien ne s'exécute après le saut. En Mad Pascal, NeoExecuteBasic fait seulement l'appel : le saut via l'adresse 0 reste à écrire (voir l'exemple).

Différence dans Trinity — Trinity garde le numéro et le nom de la fonction, mais charge NeoDOS (environnement résident depuis Trinity 0.4.0) au lieu de NeoBASIC. NeoBASIC reste disponible par boot/neobasic.bin ou NEOBASIC.NEO. Depuis Trinity 0.16.60, 1,3 charge toujours NeoDOS : le choix du menu de démarrage est appliqué par 1,27, que le noyau appelle une fois au reset.

Texte de la documentation du firmware (anglais)

Loads the resident environment (NeoDOS on Trinity) and sets the indirect jump through address zero to start it. Since T-36 it always loads NeoDOS : the boot menu choice is applied by Function 1,27, which the kernel calls once at reset.

C (llvm-mos)
/* Rendre la main à l'environnement résident (NeoBASIC ou NeoDOS) (groupe 1, fonction 3). */
#include <stdio.h>
#include <neo6502.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 */
        ;
}

int main(void) {
    printf("Retour a l'environnement resident\n");
    while (ControlPort.command)
        ;
    api(1, 3);                                  /* charge l'environnement résident */
    __asm__ volatile ("jmp ($0000)");           /* et lui passe la main */
    return 0;                                   /* jamais atteint */
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Retour a l'environnement resident

NeoDOS version 0.32.1
(C) 2026 bmarty - Neo6502 disk operating system
Mad Pascal
// Rendre la main à l'environnement résident (NeoBASIC ou NeoDOS) (groupe 1, fonction 3).
program versresident;
uses crt, neo6502;
begin
  writeln('Retour a l''environnement resident');
  NeoExecuteBasic;                              // charge l'environnement résident (appel 1,3 seulement)
  NeoWaitMessage;
  asm
    jmp ($0000)                                 // et lui passe la main : NeoExecuteBasic ne le fait pas
  end;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Retour a l'environnement resident

NeoDOS version 0.32.1
(C) 2026 bmarty - Neo6502 disk operating system
NeoBASIC

Sans objet en NeoBASIC : Un programme BASIC n'a pas à recharger l'environnement résident : il effacerait le programme en cours.

Assembleur 65C02 (64tass)
; Rendre la main à l'environnement résident (NeoBASIC ou NeoDOS) (groupe 1, fonction 3).
        .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 #<message
        sta ptr
        lda #>message
        sta ptr+1
        jsr ecrire
        jsr WaitMessage
        lda #3
        sta ControlPort+1          ; fonction 3 : Basic
        lda #1
        sta ControlPort            ; groupe 1 : charge l'environnement résident
        jsr WaitMessage
        jmp ($0000)                ; et lui passe la main

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

message: .text "Retour a l'environnement resident", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Retour a l'environnement resident

NeoDOS version 0.32.1
(C) 2026 bmarty - Neo6502 disk operating system

1,4 Credits Officiel

Affiche la liste des contributeurs du projet Neo6502, conservée dans la mémoire flash.

Entrées : aucune.

Sorties : aucune.

Texte de la documentation du firmware (anglais)

Print the Neo6502 project contributors (stored in flash memory).

C (llvm-mos)
/* Afficher les contributeurs du Neo6502 (groupe 1, fonction 4). */
#include <neo/api.h>

int main(void) {
    neo_system_credits();
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Thanks to : Bill Auger,Wojciech Bocianski,Chris Garre
tt,David Given,Pete Gollan,Rien Matthijse,Andy McCall
,Paul Robson,Oliver Schmidt,Sascha Schneider,Veselin
Sladkov,Tsvetan Usunov
Mad Pascal
// Afficher les contributeurs du Neo6502 (groupe 1, fonction 4).
program credits;
uses crt, neo6502;
begin
  NeoCredits;
  NeoWaitMessage;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Thanks to : Bill Auger,Wojciech Bocianski,Chris Garre
tt,David Given,Pete Gollan,Rien Matthijse,Andy McCall
,Paul Robson,Oliver Schmidt,Sascha Schneider,Veselin
Sladkov,Tsvetan Usunov

                      A:\>
NeoBASIC
10 ' Afficher les contributeurs du Neo6502 (groupe 1, fonction 4)
20 while peek($ff00) : wend
30 poke $ff01, 4 : poke $ff00, 1
40 while peek($ff00) : wend
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Thanks to : Bill Auger,Wojciech Bocianski,Chris Garre
tt,David Given,Pete Gollan,Rien Matthijse,Andy McCall
,Paul Robson,Oliver Schmidt,Sascha Schneider,Veselin
Sladkov,Tsvetan Usunov
Assembleur 65C02 (64tass)
; Afficher les contributeurs du Neo6502 (groupe 1, fonction 4).
        .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:  jsr WaitMessage
        lda #4
        sta ControlPort+1          ; fonction 4 : Credits
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        jmp WaitMessage
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Thanks to : Bill Auger,Wojciech Bocianski,Chris Garre
tt,David Given,Pete Gollan,Rien Matthijse,Andy McCall
,Paul Robson,Oliver Schmidt,Sascha Schneider,Veselin
Sladkov,Tsvetan Usunov

                      A:\>

1,5 Serial Status Officiel

Vérifie le port série et, s'il fonctionne, passe en mode transfert : le Neo6502 reçoit des blocs de données envoyés par un ordinateur, jusqu'à un appui sur Échap.

Entrées : aucune.

Sorties : aucune.

Sur la carte, l'appel affiche « Serial link enabled. » et ne rend la main qu'à l'appui sur Échap. Sans port série utilisable (émulateurs), il affiche « Serial not functioning. » et rend la main aussitôt.

Texte de la documentation du firmware (anglais)

Check the serial port to see if there is a data transmission.

C (llvm-mos)
/* Passer en mode transfert série (groupe 1, fonction 5). */
#include <neo/api.h>

int main(void) {
    neo_system_serial_update();         /* sur la carte : jusqu'à l'appui sur Échap */
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Serial not functioning.
Mad Pascal
// Passer en mode transfert série (groupe 1, fonction 5).
program serie;
uses crt, neo6502;
var etat: byte;
begin
  etat := NeoCheckSerial;                       // sur la carte : jusqu'à l'appui sur Échap
  NeoWaitMessage;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Serial not functioning.
NeoBASIC
10 ' Passer en mode transfert serie (groupe 1, fonction 5)
20 while peek($ff00) : wend
30 poke $ff01, 5 : poke $ff00, 1
40 while peek($ff00) : wend
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Serial not functioning.
Assembleur 65C02 (64tass)
; Passer en mode transfert série (groupe 1, fonction 5).
        .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:  jsr WaitMessage
        lda #1
        ldx #5                     ; fonction 5 : Serial Status
        jmp appel                  ; sur la carte : jusqu'à l'appui sur Échap

; 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

; 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
diviseur: .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Serial not functioning.

1,6 Locale Officiel

Choisit la langue et la disposition du clavier, par un code de deux lettres majuscules (FR, US, DE…).

Entrées
OctetsTypeRôle
P0charpremière lettre du code (ex. $46 pour F)
P1charseconde lettre du code (ex. $52 pour R)

Sorties : aucune.

En NeoBASIC, locale "FR" fait le même appel.

Mots-clés NeoBASIC qui font cet appel : locale

Texte de la documentation du firmware (anglais)

Set the locale code specified in Parameters:0,1 as upper-case ASCII letters. Parameter:0 takes the first letter and Parameter:1 takes the second letter.

For example: French (FR) would require Parametr 0 being $46 and Parameter 1 being $52

C (llvm-mos)
/* Passer le clavier en disposition française (groupe 1, fonction 6). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_system_locale("FR");
    printf("Clavier : FR\n");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Locale is now 'fr'
Clavier : FR
Mad Pascal
// Passer le clavier en disposition française (groupe 1, fonction 6).
program locale;
uses crt, neo6502;
begin
  NeoSetLocale('FR');
  NeoWaitMessage;
  writeln('Clavier : FR');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Locale is now 'fr'
Clavier : FR
NeoBASIC
10 ' Passer le clavier en disposition francaise (groupe 1, fonction 6)
20 locale "FR"
30 print "Clavier : FR"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Locale is now 'fr'
Clavier : FR
Assembleur 65C02 (64tass)
; Passer le clavier en disposition française (groupe 1, fonction 6).
        .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:  jsr WaitMessage
        lda #'F'
        sta ControlPort+4          ; P0 : première lettre
        lda #'R'
        sta ControlPort+5          ; P1 : seconde lettre
        lda #6
        sta ControlPort+1          ; fonction 6 : Locale
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        jsr WaitMessage
        lda #<message
        sta ptr
        lda #>message
        sta ptr+1
        jmp ecrire

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

message: .text "Clavier : FR", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Locale is now 'fr'
Clavier : FR

1,7 System Reset Officiel

Redémarre toute la machine, comme une remise sous tension : le RP2040 est réinitialisé par son chien de garde, et le 65C02 avec lui.

Entrées : aucune.

Sorties : aucune.

Rien ne s'exécute après l'appel ; la mémoire du 65C02 n'est pas conservée.

Texte de la documentation du firmware (anglais)

System Reset. This is a full hardware reset. It resets the RP2040 using the Watchdog timer, and this also resets the 65C02.

C (llvm-mos)
/* Redémarrer la machine (groupe 1, fonction 7). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    printf("Redemarrage...\n");
    neo_system_reset();                 /* ne revient pas */
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Redemarrage...
Mad Pascal
// Redémarrer la machine (groupe 1, fonction 7).
program redemarre;
uses crt, neo6502;
begin
  writeln('Redemarrage...');
  NeoReset;                                     // ne revient pas
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Redemarrage...
NeoBASIC
10 ' Redemarrer la machine (groupe 1, fonction 7)
20 print "Redemarrage..."
30 while peek($ff00) : wend
40 poke $ff01, 7 : poke $ff00, 1
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Redemarrage...
Assembleur 65C02 (64tass)
; Redémarrer la machine (groupe 1, fonction 7).
        .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 #<message
        sta ptr
        lda #>message
        sta ptr+1
        jsr ecrire
        jsr WaitMessage
        lda #7
        sta ControlPort+1          ; fonction 7 : System Reset
        lda #1
        sta ControlPort            ; groupe 1 : la machine redémarre
boucle: bra boucle

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

message: .text "Redemarrage...", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Redemarrage...

1,8 MOS Officiel

Exécute une commande « étoile » du MOS, comme *cat. Commandes disponibles : cat (ou .), del, file, copy, ren, md, cd.

Entrées
OctetsTypeRôle
P0-P1addradresse de la commande : chaîne précédée de sa longueur, l'étoile initiale est facultative
Sorties
OctetsTypeRôle
erreuruint80 si la commande a réussi, 255 si elle est inconnue

Les arguments sont séparés par des espaces ; un argument contenant des espaces se met entre guillemets.

Texte de la documentation du firmware (anglais)

Do a MOS command (a '* command') these are specified in the Wiki as they will be steadily expanded.

C (llvm-mos)
/* Lister le répertoire courant avec la commande MOS *cat (groupe 1, fonction 8). */
#include <stdio.h>
#include <neo6502.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 const char commande[] = "\x04*cat";      /* longueur, puis le texte */

int main(void) {
    printf("Catalogue :\n");
    while (ControlPort.command)
        ;
    ControlPort.params[0] = (uint16_t)commande & 0xFF;
    ControlPort.params[1] = (uint16_t)commande >> 8;
    api(1, 8);                                  /* MOS */
    if (ControlPort.error)
        printf("Commande inconnue\n");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Catalogue :
PROG.NEO                        173 bytes.
Mad Pascal
// Lister le répertoire courant avec la commande MOS *cat (groupe 1, fonction 8).
program cat;
uses crt, neo6502;
var commande: string[16];
begin
  writeln('Catalogue :');
  commande := '*cat';                           // chaîne Pascal : longueur puis texte
  NeoMOS(@commande);
  NeoWaitMessage;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Catalogue :
PROG.NEO                        273 bytes.
NeoBASIC
10 ' Lister le repertoire courant avec la commande MOS *cat (groupe 1, fonction 8)
20 c$ = "*cat" : a = alloc(8) : poke a, len(c$)
30 for i = 1 to len(c$) : poke a + i, asc(mid$(c$, i, 1)) : next i
40 print "Catalogue :"
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 8 : poke $ff00, 1
70 while peek($ff00) : wend
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Catalogue :
prog.bas                        493 bytes.
boot                            <Dir>
Assembleur 65C02 (64tass)
; Lister le répertoire courant avec la commande MOS *cat (groupe 1, fonction 8).
        .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 #<titre
        sta ptr
        lda #>titre
        sta ptr+1
        jsr ecrire
        jsr WaitMessage
        lda #<commande
        sta ControlPort+4          ; P0-P1 : adresse de la commande
        lda #>commande
        sta ControlPort+5
        lda #8
        sta ControlPort+1          ; fonction 8 : MOS
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        jmp WaitMessage

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

titre:    .text "Catalogue :", 13, 0
commande: .byte 4                  ; longueur
          .text "*cat"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Catalogue :
PROG.NEO                        82 bytes.

1,10 Write character to debug Officiel

Envoie un caractère sur le port de débogage (l'UART du Pico sur la carte, la sortie d'erreur dans les émulateurs), sans toucher à l'écran.

Entrées
OctetsTypeRôle
P0charle caractère à envoyer

Sorties : aucune.

Pour tracer un programme sans perturber l'affichage.

Texte de la documentation du firmware (anglais)

Writes a single character to the debug port (the UART on the Pico, or stderr on the emulator). This allows maximum flexibility.

C (llvm-mos)
/* Écrire une trace sur le port de débogage (groupe 1, fonction 10). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    const char *trace = "Bonjour\n";
    while (*trace)
        neo_system_debug_putc(*trace++);
    printf("Trace envoyee\n");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Trace envoyee
Mad Pascal
// Écrire une trace sur le port de débogage (groupe 1, fonction 10).
program trace;
uses crt, neo6502;
var trace: string[16];
    i: byte;
begin
  trace := 'Bonjour';
  for i := 1 to length(trace) do NeoWriteDebug(ord(trace[i]));
  NeoWriteDebug(10);
  NeoWaitMessage;
  writeln('Trace envoyee');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Trace envoyee
NeoBASIC
10 ' Ecrire une trace sur le port de debogage (groupe 1, fonction 10)
20 t$ = "Bonjour"
30 for i = 1 to len(t$)
40 while peek($ff00) : wend
50 poke $ff04, asc(mid$(t$, i, 1)) : poke $ff01, 10 : poke $ff00, 1
60 next i
70 while peek($ff00) : wend
80 print "Trace envoyee"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Trace envoyee
Assembleur 65C02 (64tass)
; Écrire une trace sur le port de débogage (groupe 1, fonction 10).
        .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:  ldx #0
suivant:
        lda trace,x
        beq fini
        jsr WaitMessage
        sta ControlPort+4          ; P0 : le caractère
        lda #10
        sta ControlPort+1          ; fonction 10 : Write character to debug
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        inx
        bne suivant
fini:   jsr WaitMessage
        lda #<message
        sta ptr
        lda #>message
        sta ptr+1
        jmp ecrire

; Affiche la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

trace:   .text "Bonjour", 10, 0
message: .text "Trace envoyee", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Trace envoyee

1,11 Return Version Information Officiel

Donne la version du firmware, sous la forme majeure.mineure.correctif.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0uint8version majeure
P1uint8version mineure
P2uint8correctif

Permet à un programme de vérifier qu'il tourne sur un firmware assez récent.

Texte de la documentation du firmware (anglais)

Reads the current version Major.Minor.Patch into Parameters:0..2 These values are guaranteed to be in the range 0.255

C (llvm-mos)
/* Afficher la version du firmware (groupe 1, fonction 11). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_version_t v;
    neo_system_version(&v);
    printf("Version : %d.%d.%d\n", v.major, v.minor, v.patch);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Version : 0.16.69
Mad Pascal
// Afficher la version du firmware (groupe 1, fonction 11).
program version;
uses crt, neo6502;
var majeure, mineure, correctif: byte;
begin
  NeoSendMessage(1, 11);                        // Return Version Information
  NeoWaitMessage;
  majeure := NeoMessage.params[0];
  mineure := NeoMessage.params[1];
  correctif := NeoMessage.params[2];
  writeln('Version : ', majeure, '.', mineure, '.', correctif);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Version : 0.16.69
NeoBASIC
10 ' Afficher la version du firmware (groupe 1, fonction 11)
20 ' lire les resultats dans des variables avant tout print : print utilise aussi la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 11 : poke $ff00, 1
50 while peek($ff00) : wend : a = peek($ff04) : b = peek($ff05) : c = peek($ff06)
60 print "Version : ";a;".";b;".";c
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Version : 0.16.69
Assembleur 65C02 (64tass)
; Afficher la version du firmware (groupe 1, fonction 11).
        .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:  jsr WaitMessage
        lda #11
        sta ControlPort+1          ; fonction 11 : Return Version Information
        lda #1
        sta ControlPort            ; groupe 1 : lance l'appel
        jsr WaitMessage
        lda ControlPort+4          ; recopier P0-P2 : l'affichage réutilise la boîte aux lettres
        sta version
        lda ControlPort+5
        sta version+1
        lda ControlPort+6
        sta version+2
        lda #<message
        sta ptr
        lda #>message
        sta ptr+1
        jsr ecrire
        lda version
        jsr decimal
        lda #'.'
        jsr WriteCharacter
        lda version+1
        jsr decimal
        lda #'.'
        jsr WriteCharacter
        lda version+2
        jsr decimal
        lda #13
        jmp WriteCharacter

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        ldx #0
        ldy #100
        jsr chiffre
        ldy #10
        jsr chiffre
        ora #'0'
        jmp WriteCharacter
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 la chaîne terminée par 0 pointée par (ptr).
ecrire: ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts
ptr = $80

version:  .byte 0, 0, 0
diviseur: .byte 0
message:  .text "Version : ", 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Version : 0.16.69

1,12 Set Interrupt Tick Trinity

Déclenche une interruption périodique du 65C02 (broche IRQB) à la fréquence voulue, de 1 à 1000 Hz ; 0 l'arrête.

Entrées
OctetsTypeRôle
P0-P1uint16fréquence en Hz (1 à 1000), 0 pour arrêter

Sorties : aucune.

Installer d'abord la routine d'interruption : son adresse va en $FFFE-$FFFF (en RAM), puis CLI. La ligne IRQB reste basse jusqu'à la lecture du vecteur : la routine n'a rien à acquitter et ne peut pas être réentrée. Si le programme principal prépare lui aussi un appel, la routine qui appelle l'API doit sauver puis restaurer $FF01-$FF0B. DSP Reset (1,0) arrête le tick.

Texte de la documentation du firmware (anglais)

Starts (or stops with 0) a periodic interrupt to the 65C02 at Parameters:0,1 Hz (1..1000) on IRQB (Trinity T-14, F-60 of the fork). The interrupt vector $FFFE/$FFFF is in RAM : install a handler there first, then CLI. IRQB is held low until the 65C02 fetches the vector at $FFFF, so the handler needs no acknowledge and cannot re-enter ; with I=1 the line stays low until CLI (ticks coalesce, none is lost). An interrupt handler may call the API but must save and restore $FF01-$FF0B if the main program could be preparing a call. DSP Reset (1,0) stops the tick. First delivery on a board : to be validated (bus loop timing, see docs/BACKLOG.md T-14).

C (llvm-mos)
/* Compter les interruptions d'un tick à 100 Hz pendant une seconde (groupe 1, fonction 12). */
#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)
        ;
}

static volatile uint16_t compteur;

__attribute__((interrupt)) void tick(void) {   /* routine d'interruption (llvm-mos) */
    compteur++;
}

static void regler_tick(uint16_t hz) {
    libre();
    ControlPort.params[0] = hz & 0xFF;
    ControlPort.params[1] = hz >> 8;
    api(1, 12);                                 /* Set Interrupt Tick */
}

int main(void) {
    *(void (**)(void))0xFFFE = tick;            /* vecteur d'interruption, en RAM */
    regler_tick(100);
    __asm__ volatile ("cli");
    long debut = neo_system_timer();
    while (neo_system_timer() - debut < 100)    /* une seconde */
        ;
    __asm__ volatile ("sei");
    regler_tick(0);                             /* arrêter le tick */
    printf("Interruptions en 1 s : %u\n", compteur);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruptions en 1 s : 99
Mad Pascal
// Compter les interruptions d'un tick à 100 Hz pendant une seconde (groupe 1, fonction 12).
program tick;
uses crt, neo6502;
var compteur: word;
    vecteur: word absolute $FFFE;               // vecteur d'interruption, en RAM
    debut: cardinal;

procedure recevoir; assembler;                  // routine d'interruption : se termine par rti
asm
  inc compteur
  bne @+
  inc compteur+1
@:
  rti
end;

procedure regler_tick(hz: word);
begin
  NeoWaitMessage;
  wordParams[0] := hz;                          // P0-P1 : fréquence en Hz
  NeoSendMessage(1, 12);                        // Set Interrupt Tick
  NeoWaitMessage;
end;

begin
  compteur := 0;
  vecteur := word(@recevoir);
  regler_tick(100);
  asm
    cli
  end;
  debut := NeoGetTimer;
  repeat until NeoGetTimer - debut >= 100;      // une seconde
  asm
    sei
  end;
  regler_tick(0);                               // arrêter le tick
  writeln('Interruptions en 1 s : ', compteur);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruptions en 1 s : 99
NeoBASIC

Sans objet en NeoBASIC : Une routine d'interruption s'écrit en code machine ; NeoBASIC ne peut pas en fournir une.

Assembleur 65C02 (64tass)
; Compter les interruptions d'un tick à 100 Hz pendant une seconde (groupe 1, fonction 12).
        .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 #<tick                 ; installer la routine d'interruption
        sta $FFFE
        lda #>tick
        sta $FFFF
        jsr WaitMessage
        lda #100
        sta ControlPort+4          ; P0-P1 : 100 Hz
        stz ControlPort+5
        lda #1
        ldx #12                    ; fonction 12 : Set Interrupt Tick
        jsr appel
        cli
        jsr compteur_100hz         ; attendre une seconde (100 centièmes)
        clc
        adc #100
        sta fin
_att:   jsr compteur_100hz
        cmp fin
        bne _att
        sei
        jsr WaitMessage
        stz ControlPort+4          ; 0 : arrêter le tick
        stz ControlPort+5
        lda #1
        ldx #12
        jsr appel
        lda #<message
        ldx #>message
        jsr ecrire
        lda nombre                 ; octet de poids faible suffit ici (< 256)
        jsr decimal
        lda #13
        jmp WriteCharacter

tick:   inc nombre                 ; routine d'interruption : rien à acquitter
        rti

; Octet de poids faible du compteur à 100 Hz (groupe 1, fonction 1).
compteur_100hz:
        jsr WaitMessage
        lda #1
        tax                        ; fonction 1 : Timer
        jsr appel
        lda ControlPort+4
        rts

; 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

; 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
diviseur: .byte 0

nombre:  .byte 0
fin:     .byte 0
message: .text "Interruptions en 1 s : ", 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruptions en 1 s : 99

1,13 Get Interrupt Tick Trinity

Donne la fréquence actuelle du tick d'interruption réglé par la fonction 1,12 (0 s'il est arrêté).

Entrées : aucune.

Sorties
OctetsTypeRôle
P0-P1uint16fréquence en Hz, 0 si arrêté
Texte de la documentation du firmware (anglais)

Returns the current interrupt tick rate in Parameters:0,1 (0 = off).

C (llvm-mos)
/* Lire la fréquence du tick d'interruption (groupe 1, fonction 13). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    libre();
    api(1, 13);                                 /* Get Interrupt Tick */
    uint16_t hz = ControlPort.params[0] | (ControlPort.params[1] << 8);
    printf("Tick : %u Hz\n", hz);              /* 0 : aucun tick en cours */
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Tick : 0 Hz
Mad Pascal
// Lire la fréquence du tick d'interruption (groupe 1, fonction 13).
program gettick;
uses crt, neo6502;
var hz: word;
begin
  NeoSendMessage(1, 13);                        // Get Interrupt Tick
  NeoWaitMessage;
  hz := wordParams[0];                          // 0 : aucun tick en cours
  writeln('Tick : ', hz, ' Hz');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Tick : 0 Hz
NeoBASIC
10 ' Lire la frequence du tick d'interruption (groupe 1, fonction 13)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 13 : poke $ff00, 1
50 while peek($ff00) : wend : hz = peek($ff04) + 256 * peek($ff05)
60 print "Tick : ";hz;" Hz"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Tick : 0 Hz
Assembleur 65C02 (64tass)
; Lire la fréquence du tick d'interruption (groupe 1, fonction 13).
        .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:  jsr WaitMessage
        lda #1
        ldx #13                    ; fonction 13 : Get Interrupt Tick
        jsr appel
        lda ControlPort+4          ; P0 : poids faible (le tick est ici arrêté : 0)
        sta hz
        lda #<message
        ldx #>message
        jsr ecrire
        lda hz
        jsr decimal
        lda #<unite
        ldx #>unite
        jmp ecrire

; 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

; 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
diviseur: .byte 0

hz:      .byte 0
message: .text "Tick : ", 0
unite:   .text " Hz", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Tick : 0 Hz

1,16 Set Frame Interrupt Trinity

Déclenche une interruption du 65C02 au début de chaque image affichée (60 Hz, synchronisation verticale de la sortie DVI) ; 0 l'arrête.

Entrées
OctetsTypeRôle
P0uint8non nul : activer, 0 : arrêter

Sorties : aucune.

Même livraison que le tick (1,12) : routine en $FFFE-$FFFF, puis CLI. Tick et interruption d'image peuvent être actifs ensemble : la routine ne sait pas les distinguer (utiliser 5,37 Frame Count ou 1,1 Timer). Idéal pour animer sans scintillement.

Texte de la documentation du firmware (anglais)

Parameter:0 non zero : an interrupt is delivered to the 65C02 at the start of every displayed frame (60 Hz vertical sync of the DVI output), 0 stops it (Trinity T-14, F-10 of the fork). Same delivery as Function 1,12 : IRQB is held low until the vector fetch at $FFFF ; a frame arriving while interrupts are disabled coalesces with the next. The tick and the frame interrupt may both be on : the handler cannot tell them apart (use 5,37 Frame Count or 1,1 Timer). Stopped by DSP Reset (1,0).

C (llvm-mos)
/* Compter les images affichées en une seconde, par interruption (groupe 1, fonction 16). */
#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)
        ;
}

static volatile uint16_t images;

__attribute__((interrupt)) void image(void) {  /* une interruption par image */
    images++;
}

static void interruption_image(uint8_t active) {
    libre();
    ControlPort.params[0] = active;
    api(1, 16);                                 /* Set Frame Interrupt */
}

int main(void) {
    *(void (**)(void))0xFFFE = image;
    interruption_image(1);
    __asm__ volatile ("cli");
    long debut = neo_system_timer();
    while (neo_system_timer() - debut < 100)
        ;
    __asm__ volatile ("sei");
    interruption_image(0);
    printf("Images en 1 s : %u\n", images);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Images en 1 s : 60
Mad Pascal
// Compter les images affichées en une seconde, par interruption (groupe 1, fonction 16).
program images;
uses crt, neo6502;
var nombre: word;
    vecteur: word absolute $FFFE;
    debut: cardinal;

procedure image; assembler;                     // une interruption par image
asm
  inc nombre
  bne @+
  inc nombre+1
@:
  rti
end;

procedure interruption_image(active: byte);
begin
  NeoWaitMessage;
  NeoMessage.params[0] := active;
  NeoSendMessage(1, 16);                        // Set Frame Interrupt
  NeoWaitMessage;
end;

begin
  nombre := 0;
  vecteur := word(@image);
  interruption_image(1);
  asm
    cli
  end;
  debut := NeoGetTimer;
  repeat until NeoGetTimer - debut >= 100;
  asm
    sei
  end;
  interruption_image(0);
  writeln('Images en 1 s : ', nombre);
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Images en 1 s : 60
NeoBASIC

Sans objet en NeoBASIC : Une routine d'interruption s'écrit en code machine ; NeoBASIC ne peut pas en fournir une.

Assembleur 65C02 (64tass)
; Compter les images affichées en une seconde, par interruption (groupe 1, fonction 16).
        .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 #<image
        sta $FFFE
        lda #>image
        sta $FFFF
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : activer
        ldx #16                    ; fonction 16 : Set Frame Interrupt
        jsr appel
        cli
        jsr compteur_100hz
        clc
        adc #100
        sta fin
_att:   jsr compteur_100hz
        cmp fin
        bne _att
        sei
        jsr WaitMessage
        stz ControlPort+4          ; 0 : arrêter
        lda #1
        ldx #16
        jsr appel
        lda #<message
        ldx #>message
        jsr ecrire
        lda images
        jsr decimal
        lda #13
        jmp WriteCharacter

image:  inc images                 ; une interruption par image
        rti

compteur_100hz:
        jsr WaitMessage
        lda #1
        tax                        ; fonction 1 : Timer
        jsr appel
        lda ControlPort+4
        rts

; 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

; 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
diviseur: .byte 0

images:  .byte 0
fin:     .byte 0
message: .text "Images en 1 s : ", 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Images en 1 s : 60

1,17 Get Frame Interrupt Trinity

Indique si l'interruption d'image (fonction 1,16) est active.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0uint8non nul si active
Texte de la documentation du firmware (anglais)

Returns in Parameter:0 whether the frame interrupt (Function 1,16) is on.

C (llvm-mos)
/* Savoir si l'interruption d'image est active (groupe 1, fonction 17). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    libre();
    api(1, 17);                                 /* Get Frame Interrupt */
    printf("Interruption d'image : %s\n", ControlPort.params[0] ? "active" : "inactive");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruption d'image : inactive
Mad Pascal
// Savoir si l'interruption d'image est active (groupe 1, fonction 17).
program getframe;
uses crt, neo6502;
begin
  NeoSendMessage(1, 17);                        // Get Frame Interrupt
  NeoWaitMessage;
  if NeoMessage.params[0] <> 0 then
    writeln('Interruption d''image : active')
  else
    writeln('Interruption d''image : inactive');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruption d'image : inactive
NeoBASIC
10 ' Savoir si l'interruption d'image est active (groupe 1, fonction 17)
20 while peek($ff00) : wend
30 poke $ff01, 17 : poke $ff00, 1
40 while peek($ff00) : wend : a = peek($ff04)
50 if a
60   print "Interruption d'image : active"
70 else
80   print "Interruption d'image : inactive"
90 endif
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruption d'image : inactive
Assembleur 65C02 (64tass)
; Savoir si l'interruption d'image est active (groupe 1, fonction 17).
        .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:  jsr WaitMessage
        lda #1
        ldx #17                    ; fonction 17 : Get Frame Interrupt
        jsr appel
        lda ControlPort+4          ; P0 : non nul si active
        beq _non
        lda #<active
        ldx #>active
        jmp ecrire
_non:   lda #<inactive
        ldx #>inactive
        jmp ecrire

; 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

; 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
diviseur: .byte 0

active:   .text "Interruption d'image : active", 13, 0
inactive: .text "Interruption d'image : inactive", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Interruption d'image : inactive

1,18 Select Bank Trinity

Recopie l'une des 32 banques de 8 Ko conservées dans la flash du RP2040 dans une fenêtre de 8 Ko de la RAM du 65C02.

Entrées
OctetsTypeRôle
P0uint8numéro de banque (0 à 31) ; $FF oublie la correspondance sans toucher la fenêtre
P1-P2addradresse de la fenêtre : alignée sur une page, fin avant $FF00
Sorties
OctetsTypeRôle
erreuruint8non nul si la banque ou l'adresse est invalide

La fenêtre est une copie : la modifier ne modifie pas la banque (voir 1,22). Elle ne doit contenir ni le code qui fait l'appel, ni la pile, ni la page zéro. Une banque jamais écrite se lit $FF. Les banques sont aussi les pages $A0 à $BF du blitter (12,2), en lecture seule.

Texte de la documentation du firmware (anglais)

Memory banks in flash (Trinity T-17, from F-23 of the fork). Copies bank Parameter:0 (0-31, 8k each, kept in the RP2040 flash and read in place) into the 8k window at Parameters:1,2 of 6502 RAM : the window address is page aligned and the window ends below $FF00. The copy takes place while the 65C02 waits for the call ; the window must not hold the code executing the call, its stack or its zero page. The window is a copy : changing it does not change the bank (see Function 1,22). Bank $FF forgets the mapping and leaves the window as it is. Sets the error flag if the bank or the address is invalid. A bank never written reads as $FF. The banks are also blitter pages $A0 (bank 0) to $BF, read only, for Function 12,2 (bank to video RAM for instance).

C (llvm-mos)
/* Recopier la banque 31 dans une fenêtre de 8 Ko (groupe 1, fonction 18). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

static uint8_t fenetre[8192] __attribute__((aligned(256)));   /* alignée sur une page */

int main(void) {
    libre();
    ControlPort.params[0] = 31;                                /* banque */
    ControlPort.params[1] = (uint16_t)fenetre & 0xFF;
    ControlPort.params[2] = (uint16_t)fenetre >> 8;
    api(1, 18);                                                /* Select Bank */
    if (ControlPort.error)
        printf("Banque ou fenetre invalide\n");
    else
        printf("Banque 31 : premier octet $%02X\n", fenetre[0]);   /* $FF si jamais écrite */
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 : premier octet $FF
Mad Pascal
// Recopier la banque 31 dans une fenêtre de 8 Ko en $4000 (groupe 1, fonction 18).
program banque;
uses crt, neo6502;
var fenetre: array[0..8191] of byte absolute $4000;   // alignée sur une page
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 31;                   // banque
  NeoMessage.params[1] := lo(word(@fenetre));   // P1-P2 : fenêtre
  NeoMessage.params[2] := hi(word(@fenetre));
  NeoSendMessage(1, 18);                        // Select Bank
  NeoWaitMessage;
  if NeoMessage.error <> 0 then
    writeln('Banque ou fenetre invalide')
  else
    writeln('Banque 31 : premier octet $', HexStr(fenetre[0], 2));   // $FF si jamais écrite
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 : premier octet $FF
NeoBASIC
10 ' Recopier la banque 31 dans une fenetre de 8 Ko (groupe 1, fonction 18)
20 m = alloc(8448) : w = (m + 255) & $ff00 : ' fenetre alignee sur une page
30 while peek($ff00) : wend
40 poke $ff04, 31 : poke $ff05, w & 255 : poke $ff06, w >> 8 : poke $ff01, 18 : poke $ff00, 1
50 while peek($ff00) : wend : e = peek($ff02)
60 if e
70   print "Banque ou fenetre invalide"
80 else
90   print "Banque 31 : premier octet ";peek(w)
100 endif
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 : premier octet 255
Assembleur 65C02 (64tass)
; Recopier la banque 31 dans une fenêtre de 8 Ko en $4000 (groupe 1, fonction 18).
        .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

FENETRE = $4000                    ; alignée sur une page, loin du programme

start:  jsr WaitMessage
        lda #31
        sta ControlPort+4          ; P0 : banque 31
        lda #<FENETRE
        sta ControlPort+5          ; P1-P2 : fenêtre
        lda #>FENETRE
        sta ControlPort+6
        lda #1
        ldx #18                    ; fonction 18 : Select Bank
        jsr appel
        lda ControlPort+2          ; erreur ?
        bne _err
        lda #<message
        ldx #>message
        jsr ecrire
        lda FENETRE                ; premier octet ($FF = 255 si jamais écrite)
        jsr decimal
        lda #13
        jmp WriteCharacter
_err:   lda #<erreur
        ldx #>erreur
        jmp ecrire

; 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

; 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
diviseur: .byte 0

message: .text "Banque 31 : premier octet ", 0
erreur:  .text "Banque ou fenetre invalide", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 : premier octet 255

1,19 Get Bank Info Trinity

Donne la dernière banque sélectionnée, l'adresse de sa fenêtre, le nombre de banques et leur taille.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0uint8dernière banque sélectionnée ($FF si aucune depuis le démarrage)
P1-P2addradresse de sa fenêtre
P3uint8nombre de banques
P4-P5uint16taille d'une banque en octets
Texte de la documentation du firmware (anglais)

Returns the last bank selected in Parameter:0 ($FF if none since reset) and its window address in Parameters:1,2, the number of banks in Parameter:3 and the bank size in Parameters:4,5 (Trinity T-17).

C (llvm-mos)
/* Connaître le nombre et la taille des banques (groupe 1, fonction 19). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    libre();
    api(1, 19);                                 /* Get Bank Info */
    uint8_t nombre = ControlPort.params[3];
    uint16_t taille = ControlPort.params[4] | (ControlPort.params[5] << 8);
    printf("%u banques de %u octets\n", nombre, taille);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
32 banques de 8192 octets
Mad Pascal
// Connaître le nombre et la taille des banques (groupe 1, fonction 19).
program bankinfo;
uses crt, neo6502;
var nombre: byte;
    taille: word;
begin
  NeoSendMessage(1, 19);                        // Get Bank Info
  NeoWaitMessage;
  nombre := NeoMessage.params[3];
  taille := wordParams[2];                      // P4-P5
  writeln(nombre, ' banques de ', taille, ' octets');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
32 banques de 8192 octets
NeoBASIC
10 ' Connaitre le nombre et la taille des banques (groupe 1, fonction 19)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 19 : poke $ff00, 1
50 while peek($ff00) : wend : n = peek($ff07) : t = peek($ff08) + 256 * peek($ff09)
60 print n;" banques de ";t;" octets"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
32 banques de 8192 octets
Assembleur 65C02 (64tass)
; Connaître le nombre de banques (groupe 1, fonction 19).
        .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:  jsr WaitMessage
        lda #1
        ldx #19                    ; fonction 19 : Get Bank Info
        jsr appel
        lda ControlPort+7          ; P3 : nombre de banques
        jsr decimal
        lda #<message
        ldx #>message
        jmp ecrire

; 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

; 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
diviseur: .byte 0

message: .text " banques de 8192 octets", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
32 banques de 8192 octets

1,20 Get Date Time Trinity

Donne la date et l'heure locales (fuseau de la fonction 1,24), et d'où elles viennent.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0-P1uint16année (1970 à 2099)
P2uint8mois (1 à 12)
P3uint8jour (1 à 31)
P4uint8heure (0 à 23)
P5uint8minute
P6uint8seconde
P7uint8source : 0 non réglée (1970-01-01 + temps depuis la mise sous tension), 1 horloge logicielle (1,21), 2 horloge PCF8563 sur l'UEXT, 3 heure SNTP du modem USB (1,23)
Texte de la documentation du firmware (anglais)

Returns the date and time (Trinity T-18, F-14 of the fork), local time of the zone of Function 1,24 : Parameters:0,1 year (1970-2099), Parameter:2 month (1-12), Parameter:3 day (1-31), Parameter:4 hour (0-23), Parameter:5 minute, Parameter:6 second and Parameter:7 the source : 0 = not set (the value is then 1970-01-01 plus the time since power on), 1 = software clock set by Function 1,21 and advanced by the 100 Hz timer, 2 = PCF8563 real time clock found on the UEXT I2C bus (address $51), 3 = set from the SNTP time of the USB modem (Function 1,23 : the program asks for it, nothing is automatic, T-25).

C (llvm-mos)
/* Afficher la date et l'heure (groupe 1, fonction 20). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    libre();
    api(1, 20);                                 /* Get Date Time */
    volatile uint8_t *p = ControlPort.params;
    printf("%04u-%02u-%02u %02u:%02u:%02u (source %u)\n",
           p[0] | (p[1] << 8), p[2], p[3], p[4], p[5], p[6], p[7]);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
1970-01-01 00:00:06 (source 0)
Mad Pascal
// Afficher la date et l'heure (groupe 1, fonction 20).
program dateheure;
uses crt, neo6502;
var p: array[0..7] of byte;
    i: byte;

procedure deux(n: byte);                        // deux chiffres, avec zéro de tête
begin
  if n < 10 then write('0');
  write(n);
end;

begin
  NeoSendMessage(1, 20);                        // Get Date Time
  NeoWaitMessage;
  for i := 0 to 7 do p[i] := NeoMessage.params[i];   // recopier : l'affichage réutilise la boîte aux lettres
  write(p[0] + p[1] * 256, '-');
  deux(p[2]); write('-'); deux(p[3]); write(' ');
  deux(p[4]); write(':'); deux(p[5]); write(':'); deux(p[6]);
  writeln(' (source ', p[7], ')');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
1970-01-01 00:00:06 (source 0)
NeoBASIC
10 ' Afficher la date et l'heure (groupe 1, fonction 20)
20 ' lire les resultats dans des variables juste apres l'appel, avant tout calcul : print et * reutilisent la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 20 : poke $ff00, 1
50 while peek($ff00) : wend : a0 = peek($ff04) : a1 = peek($ff05) : mo = peek($ff06) : j = peek($ff07) : h = peek($ff08) : mi = peek($ff09) : s = peek($ff0a) : so = peek($ff0b) : a = a0 + 256 * a1
60 print a;"-";right$("0"+str$(mo),2);"-";right$("0"+str$(j),2);" ";right$("0"+str$(h),2);":";right$("0"+str$(mi),2);":";right$("0"+str$(s),2);" (source ";so;")"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
1970-01-01 00:00:09 (source 0)
Assembleur 65C02 (64tass)
; Afficher la date et l'heure (groupe 1, fonction 20) : jj/mm hh:mm:ss.
        .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:  jsr WaitMessage
        lda #1
        ldx #20                    ; fonction 20 : Get Date Time
        jsr appel
        ldx #7                     ; recopier P0-P7 : l'affichage réutilise la boîte aux lettres
_copie: lda ControlPort+4,x
        sta date,x
        dex
        bpl _copie
        lda date+3                 ; jour
        jsr deux
        lda #'/'
        jsr WriteCharacter
        lda date+2                 ; mois
        jsr deux
        lda #' '
        jsr WriteCharacter
        lda date+4                 ; heure
        jsr deux
        lda #':'
        jsr WriteCharacter
        lda date+5                 ; minute
        jsr deux
        lda #':'
        jsr WriteCharacter
        lda date+6                 ; seconde
        jsr deux
        lda #13
        jmp WriteCharacter

deux:   cmp #10                    ; deux chiffres, avec zéro de tête
        bcs _d
        pha
        lda #'0'
        jsr WriteCharacter
        pla
_d:     jmp decimal

; 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

; 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
diviseur: .byte 0

date:    .fill 8
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
01/01 00:00:06

1,21 Set Date Time Trinity

Règle la date et l'heure locales ; l'horloge PCF8563 est réglée aussi quand elle est présente.

Entrées
OctetsTypeRôle
P0-P6datemême disposition que 1,20 : année (2 octets), mois, jour, heure, minute, seconde
Sorties
OctetsTypeRôle
erreuruint8non nul si un champ est hors limites (1970-2099, jour valide du mois, heure sur 24 h)
Texte de la documentation du firmware (anglais)

Sets the date and time (Trinity T-18, F-14 of the fork), same layout as Function 1,20 (Parameter:7 ignored) : the software clock is set, and the PCF8563 too when present. Sets the error flag if a field is out of range (1970-2099, valid day of month, 24 hour time).

C (llvm-mos)
/* Régler la date et l'heure au 27 septembre 2026, 14:30:00 (groupe 1, fonction 21). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    static const uint8_t date[7] = { 2026 & 0xFF, 2026 >> 8, 9, 27, 14, 30, 0 };
    libre();
    for (uint8_t i = 0; i < 7; i++)
        ControlPort.params[i] = date[i];
    api(1, 21);                                 /* Set Date Time */
    if (ControlPort.error)
        printf("Date refusee\n");
    else
        printf("Horloge reglee : 2026-09-27 14:30\n");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Horloge reglee : 2026-09-27 14:30
Mad Pascal
// Régler la date et l'heure au 27 septembre 2026, 14:30:00 (groupe 1, fonction 21).
program setdate;
uses crt, neo6502;
begin
  NeoWaitMessage;
  wordParams[0] := 2026;                        // P0-P1 : année
  NeoMessage.params[2] := 9;                    // mois
  NeoMessage.params[3] := 27;                   // jour
  NeoMessage.params[4] := 14;                   // heure
  NeoMessage.params[5] := 30;                   // minute
  NeoMessage.params[6] := 0;                    // seconde
  NeoSendMessage(1, 21);                        // Set Date Time
  NeoWaitMessage;
  if NeoMessage.error <> 0 then
    writeln('Date refusee')
  else
    writeln('Horloge reglee : 2026-09-27 14:30');
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Horloge reglee : 2026-09-27 14:30
NeoBASIC
10 ' Regler la date et l'heure au 27 septembre 2026, 14:30:00 (groupe 1, fonction 21)
20 while peek($ff00) : wend
30 poke $ff04, 2026 & 255 : poke $ff05, 2026 >> 8 : poke $ff06, 9 : poke $ff07, 27 : poke $ff08, 14 : poke $ff09, 30 : poke $ff0a, 0 : poke $ff01, 21 : poke $ff00, 1
40 while peek($ff00) : wend : e = peek($ff02)
50 if e
60   print "Date refusee"
70 else
80   print "Horloge reglee : 2026-09-27 14:30"
90 endif
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Horloge reglee : 2026-09-27 14:30
Assembleur 65C02 (64tass)
; Régler la date et l'heure au 27 septembre 2026, 14:30:00 (groupe 1, fonction 21).
        .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:  jsr WaitMessage
        ldx #6
_copie: lda date,x                 ; P0-P6 : année, mois, jour, heure, minute, seconde
        sta ControlPort+4,x
        dex
        bpl _copie
        lda #1
        ldx #21                    ; fonction 21 : Set Date Time
        jsr appel
        lda ControlPort+2          ; erreur ?
        bne _err
        lda #<message
        ldx #>message
        jmp ecrire
_err:   lda #<refus
        ldx #>refus
        jmp ecrire

; 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

; 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
diviseur: .byte 0

date:    .word 2026
         .byte 9, 27, 14, 30, 0
message: .text "Horloge reglee : 2026-09-27 14:30", 13, 0
refus:   .text "Date refusee", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Horloge reglee : 2026-09-27 14:30

1,22 Write Bank Trinity

Écrit 8 Ko de la RAM du 65C02 dans une banque de la flash ; la banque survit aux redémarrages et aux mises à jour du firmware.

Entrées
OctetsTypeRôle
P0uint8numéro de banque (0 à 31)
P1-P2addradresse des 8 Ko à écrire (mêmes contraintes que 1,18)
Sorties
OctetsTypeRôle
erreuruint8non nul si la banque ou l'adresse est invalide, ou si la vérification échoue

Sur la carte, les secteurs de flash sont effacés puis écrits, l'affichage se fige environ 150 ms, et le contenu est vérifié. Les émulateurs gardent les banques dans le fichier banks.flash du stockage. La flash s'use : écrire une banque une fois, pas dans une boucle (1,26 aide à ne réécrire que ce qui a changé).

Texte de la documentation du firmware (anglais)

Programs bank Parameter:0 with the 8k at Parameters:1,2 of 6502 RAM (same constraints as Function 1,18) : on the board the flash sectors are erased and written, the display pauses for about 150 ms, and the content is verified ; a written bank survives resets and reflashing of the firmware (it lives in the top 256k of the flash). The emulators keep the banks in the file "banks.flash" of the storage directory. Sets the error flag if the bank or the address is invalid or the verification fails (Trinity T-17). Flash wears : write banks once, not in loops.

C (llvm-mos)
/* Écrire un texte dans la banque 31, puis le relire (groupe 1, fonctions 22 et 18). */
#include <stdio.h>
#include <string.h>
#include <neo6502.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)
        ;
}

static uint8_t tampon[8192] __attribute__((aligned(256)));

static void banque(uint8_t fonction, uint8_t numero) {
    libre();
    ControlPort.params[0] = numero;
    ControlPort.params[1] = (uint16_t)tampon & 0xFF;
    ControlPort.params[2] = (uint16_t)tampon >> 8;
    api(1, fonction);
}

int main(void) {
    memset(tampon, 0, sizeof tampon);
    strcpy((char *)tampon, "Bonjour");
    banque(22, 31);                             /* Write Bank : tampon -> banque 31 */
    if (ControlPort.error) {
        printf("Ecriture refusee\n");
        return 0;
    }
    memset(tampon, 0, sizeof tampon);           /* effacer la copie en RAM */
    banque(18, 31);                             /* Select Bank : banque 31 -> tampon */
    printf("Banque 31 relue : %s\n", (char *)tampon);
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 relue : Bonjour
Mad Pascal
// Écrire un texte dans la banque 31, puis le relire (groupe 1, fonctions 22 et 18).
program writebank;
uses crt, neo6502;
var tampon: array[0..8191] of byte absolute $4000;   // 8 Ko alignés sur une page
    texte: string[16];
    i: byte;

procedure banque(fonction: byte);
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 31;
  NeoMessage.params[1] := lo(word(@tampon));
  NeoMessage.params[2] := hi(word(@tampon));
  NeoSendMessage(1, fonction);
  NeoWaitMessage;
end;

begin
  texte := 'Bonjour';
  for i := 1 to length(texte) do tampon[i - 1] := ord(texte[i]);
  tampon[length(texte)] := 0;
  banque(22);                                   // Write Bank : tampon -> banque 31
  if NeoMessage.error <> 0 then
  begin
    writeln('Ecriture refusee');
    exit;
  end;
  tampon[0] := 0;                               // effacer la copie en RAM
  banque(18);                                   // Select Bank : banque 31 -> tampon
  write('Banque 31 relue : ');
  i := 0;
  while tampon[i] <> 0 do
  begin
    write(chr(tampon[i]));
    inc(i);
  end;
  writeln;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 relue : Bonjour
NeoBASIC
10 ' Ecrire un texte dans la banque 31, puis le relire (groupe 1, fonctions 22 et 18)
20 m = alloc(8448) : w = (m + 255) & $ff00
30 t$ = "Bonjour" : for i = 1 to len(t$) : poke w + i - 1, asc(mid$(t$, i, 1)) : next i : poke w + len(t$), 0
40 while peek($ff00) : wend
50 poke $ff04, 31 : poke $ff05, w & 255 : poke $ff06, w >> 8 : poke $ff01, 22 : poke $ff00, 1
60 while peek($ff00) : wend : e = peek($ff02)
70 if e then print "Ecriture refusee" : end
80 for i = 0 to 7 : poke w + i, 0 : next i
90 while peek($ff00) : wend
100 poke $ff04, 31 : poke $ff05, w & 255 : poke $ff06, w >> 8 : poke $ff01, 18 : poke $ff00, 1
110 while peek($ff00) : wend
120 r$ = "" : i = 0
130 while peek(w + i) : r$ = r$ + chr$(peek(w + i)) : i = i + 1 : wend
140 print "Banque 31 relue : ";r$
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 relue : Bonjour
Assembleur 65C02 (64tass)
; Écrire un texte dans la banque 31, puis le relire (groupe 1, fonctions 22 et 18).
        .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

TAMPON = $4000                     ; 8 Ko alignés sur une page

start:  ldx #0                     ; copier le texte dans le tampon
_copie: lda texte,x
        sta TAMPON,x
        beq _ecrit
        inx
        bne _copie
_ecrit: lda #22                    ; fonction 22 : Write Bank
        jsr banque
        lda ControlPort+2
        bne _err
        stz TAMPON                 ; effacer la copie en RAM
        lda #18                    ; fonction 18 : Select Bank
        jsr banque
        lda #<message
        ldx #>message
        jsr ecrire
        lda #<TAMPON               ; le texte relu depuis la banque
        ldx #>TAMPON
        jsr ecrire
        lda #13
        jmp WriteCharacter
_err:   lda #<refus
        ldx #>refus
        jmp ecrire

; A = fonction (18 ou 22), sur la banque 31 et le tampon.
banque: pha
        jsr WaitMessage
        lda #31
        sta ControlPort+4
        lda #<TAMPON
        sta ControlPort+5
        lda #>TAMPON
        sta ControlPort+6
        plx
        lda #1
        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

; 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
diviseur: .byte 0

texte:   .text "Bonjour", 0
message: .text "Banque 31 relue : ", 0
refus:   .text "Ecriture refusee", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 31 relue : Bonjour

1,23 Sync Clock From Modem Trinity

Règle la date et l'heure d'après le modem Wi-Fi USB (Pico W, Modem Wi-Fi Neo6502), qui les obtient par SNTP.

Entrées : aucune.

Sorties
OctetsTypeRôle
erreuruint80 réussi, 1 aucun modem branché, 2 modem sans heure SNTP (réponse 1970) ou muet

Envoie AT+CIPSNTPTIME? sur le lien USB et applique la réponse, en retirant le décalage du modem : l'horloge tient l'heure UTC, et 1,20 montre l'heure locale du fuseau de 1,24. Attend 2 secondes au plus ; ce qui attendait sur le lien du modem est jeté. Rien n'est automatique : c'est au programme de le demander.

Texte de la documentation du firmware (anglais)

Sets the date and time from the USB modem (Pico W, Neo6502picowifi) : sends AT+CIPSNTPTIME? on the CDC link and applies the answer ; the tz offset of the modem (AT+CIPSNTPCFG?, whole hours) is taken out so the clock holds UTC and Function 1,20 shows the local time of the zone selected by Function 1,24. Waits 2 seconds at most. Error 1 if no modem is connected, 2 if the modem has no SNTP time yet (answer 1970) or does not answer. Pending input on the modem link is discarded (Trinity T-25).

C (llvm-mos)
/* Mettre l'horloge à l'heure du modem Wi-Fi USB (groupe 1, fonction 23). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    libre();
    api(1, 23);                                 /* Sync Clock From Modem */
    switch (ControlPort.error) {
    case 0:  printf("Horloge synchronisee\n"); break;
    case 1:  printf("Pas de modem USB\n"); break;
    default: printf("Modem sans heure SNTP\n"); break;
    }
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Pas de modem USB
Mad Pascal
// Mettre l'horloge à l'heure du modem Wi-Fi USB (groupe 1, fonction 23).
program syncmodem;
uses crt, neo6502;
begin
  NeoSendMessage(1, 23);                        // Sync Clock From Modem
  NeoWaitMessage;
  case NeoMessage.error of
    0: writeln('Horloge synchronisee');
    1: writeln('Pas de modem USB');
  else
    writeln('Modem sans heure SNTP');
  end;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Pas de modem USB
NeoBASIC
10 ' Mettre l'horloge a l'heure du modem Wi-Fi USB (groupe 1, fonction 23)
20 while peek($ff00) : wend
30 poke $ff01, 23 : poke $ff00, 1
40 while peek($ff00) : wend : e = peek($ff02)
50 if e = 0 then print "Horloge synchronisee"
60 if e = 1 then print "Pas de modem USB"
70 if e > 1 then print "Modem sans heure SNTP"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Pas de modem USB
Assembleur 65C02 (64tass)
; Mettre l'horloge à l'heure du modem Wi-Fi USB (groupe 1, fonction 23).
        .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:  jsr WaitMessage
        lda #1
        ldx #23                    ; fonction 23 : Sync Clock From Modem
        jsr appel
        lda ControlPort+2          ; 0 réussi, 1 pas de modem, 2 pas d'heure
        bne _pas0
        lda #<ok
        ldx #>ok
        jmp ecrire
_pas0:  cmp #1
        bne _pas1
        lda #<sans
        ldx #>sans
        jmp ecrire
_pas1:  lda #<muet
        ldx #>muet
        jmp ecrire

; 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

; 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
diviseur: .byte 0

ok:   .text "Horloge synchronisee", 13, 0
sans: .text "Pas de modem USB", 13, 0
muet: .text "Modem sans heure SNTP", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Pas de modem USB

1,24 Set Time Zone Trinity

Choisit le fuseau horaire, par son nom (Europe/Paris, America/Montreal…) ou par un décalage fixe (UTC+2, UTC-3:30, +0530).

Entrées
OctetsTypeRôle
P0-P1addradresse du nom : chaîne précédée de sa longueur
Sorties
OctetsTypeRôle
erreuruint80 réussi, 1 nom inconnu, 2 écriture en flash échouée

L'horloge garde l'heure UTC ; 1,20, 1,21 et les dates des fichiers FAT utilisent l'heure locale du fuseau, heure d'été comprise (règles de l'Union européenne, d'Amérique du Nord, d'Australie et de Nouvelle-Zélande). Le fuseau est enregistré en flash et réappliqué à chaque démarrage.

Texte de la documentation du firmware (anglais)

Selects the time zone (Trinity T-26) from the length-prefixed name at Parameters:0,1 : an IANA style name of the built in table ("Europe/Paris", "Europe/Belgrade", "America/Montreal", "Asia/Tokyo"...) or a fixed offset ("UTC+2", "UTC-3:30", "+0530"). The clock keeps UTC ; Functions 1,20 and 1,21 and the FAT timestamps use the local time of the zone, daylight saving included (rules of the European Union, North America, Australia and New Zealand). The zone is saved in the settings sector of the flash and applied at every start up. Error 1 if the name is unknown, 2 if the flash write failed.

C (llvm-mos)
/* Choisir le fuseau horaire de Paris (groupe 1, fonction 24). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

static const char fuseau[] = "\x0C" "Europe/Paris";   /* longueur (12), puis le nom */

int main(void) {
    libre();
    ControlPort.params[0] = (uint16_t)fuseau & 0xFF;
    ControlPort.params[1] = (uint16_t)fuseau >> 8;
    api(1, 24);                                 /* Set Time Zone */
    if (ControlPort.error == 1)
        printf("Fuseau inconnu\n");
    else if (ControlPort.error)
        printf("Ecriture en flash echouee\n");
    else
        printf("Fuseau : Europe/Paris\n");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : Europe/Paris
Mad Pascal
// Choisir le fuseau horaire de Paris (groupe 1, fonction 24).
program setzone;
uses crt, neo6502;
var fuseau: string[32];                         // chaîne Pascal : longueur puis texte
begin
  fuseau := 'Europe/Paris';
  NeoWaitMessage;
  wordParams[0] := word(@fuseau);               // P0-P1 : adresse du nom
  NeoSendMessage(1, 24);                        // Set Time Zone
  NeoWaitMessage;
  case NeoMessage.error of
    0: writeln('Fuseau : ', fuseau);
    1: writeln('Fuseau inconnu');
  else
    writeln('Ecriture en flash echouee');
  end;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : Europe/Paris
NeoBASIC
10 ' Choisir le fuseau horaire de Paris (groupe 1, fonction 24)
20 z$ = "Europe/Paris" : a = alloc(16) : poke a, len(z$)
30 for i = 1 to len(z$) : poke a + i, asc(mid$(z$, i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 24 : poke $ff00, 1
60 while peek($ff00) : wend : e = peek($ff02)
70 if e = 0 then print "Fuseau : ";z$
80 if e = 1 then print "Fuseau inconnu"
90 if e = 2 then print "Ecriture en flash echouee"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : Europe/Paris
Assembleur 65C02 (64tass)
; Choisir le fuseau horaire de Paris (groupe 1, fonction 24).
        .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:  jsr WaitMessage
        lda #<fuseau
        sta ControlPort+4          ; P0-P1 : adresse du nom
        lda #>fuseau
        sta ControlPort+5
        lda #1
        ldx #24                    ; fonction 24 : Set Time Zone
        jsr appel
        lda ControlPort+2
        bne _err
        lda #<ok
        ldx #>ok
        jmp ecrire
_err:   lda #<refus
        ldx #>refus
        jmp ecrire

; 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

; 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
diviseur: .byte 0

fuseau: .byte 12                   ; longueur
        .text "Europe/Paris"
ok:     .text "Fuseau : Europe/Paris", 13, 0
refus:  .text "Fuseau refuse", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : Europe/Paris

1,25 Get Time Zone Trinity

Donne le nom du fuseau horaire en cours, son décalage par rapport à UTC et si l'heure d'été s'applique.

Entrées
OctetsTypeRôle
P0-P1addradresse d'un tampon : son premier octet donne, avant l'appel, la longueur maximale acceptée ; il reçoit ensuite la longueur du nom, suivie du nom
Sorties
OctetsTypeRôle
tamponstringnom du fuseau (« UTC » par défaut)
P2-P3int16décalage par rapport à UTC en minutes (signé, heure d'été comprise)
P4uint8non nul si l'heure d'été s'applique
Texte de la documentation du firmware (anglais)

Writes the current time zone name into the length-prefixed buffer at Parameters:0,1 ("UTC" by default), the current offset from UTC in minutes (signed, daylight saving included) in Parameters:2,3 and whether daylight saving time is in force in Parameter:4 (Trinity T-26).

C (llvm-mos)
/* Afficher le fuseau horaire en cours (groupe 1, fonction 25). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

static char nom[64];                            /* longueur, puis le nom */

int main(void) {
    nom[0] = sizeof nom - 1;                    /* capacité du tampon, lue par le firmware */
    libre();
    ControlPort.params[0] = (uint16_t)nom & 0xFF;
    ControlPort.params[1] = (uint16_t)nom >> 8;
    api(1, 25);                                 /* Get Time Zone */
    int16_t decalage = ControlPort.params[2] | (ControlPort.params[3] << 8);
    uint8_t ete = ControlPort.params[4];
    printf("Fuseau : %.*s, decalage %d min%s\n", nom[0], nom + 1, decalage, ete ? " (heure d'ete)" : "");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : UTC, decalage 0 min
Mad Pascal
// Afficher le fuseau horaire en cours (groupe 1, fonction 25).
program getzone;
uses crt, neo6502;
var nom: string[63];                            // longueur, puis le nom
    decalage: smallint;
    ete: byte;
begin
  nom[0] := chr(63);                            // capacité du tampon, lue par le firmware
  NeoWaitMessage;
  wordParams[0] := word(@nom);                  // P0-P1 : tampon qui reçoit le nom
  NeoSendMessage(1, 25);                        // Get Time Zone
  NeoWaitMessage;
  decalage := smallint(wordParams[1]);          // P2-P3 : minutes, signé
  ete := NeoMessage.params[4];
  write('Fuseau : ', nom, ', decalage ', decalage, ' min');
  if ete <> 0 then write(' (heure d''ete)');
  writeln;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : UTC, decalage 0 min
NeoBASIC
10 ' Afficher le fuseau horaire en cours (groupe 1, fonction 25)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 a = alloc(64) : poke a, 63 : ' premier octet : capacite du tampon
40 while peek($ff00) : wend
50 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 25 : poke $ff00, 1
60 while peek($ff00) : wend : d = peek($ff06) + 256 * peek($ff07) : e = peek($ff08)
70 if d > 32767 then d = d - 65536
80 n$ = "" : for i = 1 to peek(a) : n$ = n$ + chr$(peek(a + i)) : next i
90 print "Fuseau : ";n$;", decalage ";d;" min"
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : UTC, decalage 0 min
Assembleur 65C02 (64tass)
; Afficher le nom du fuseau horaire en cours (groupe 1, fonction 25).
        .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 #63
        sta nom                    ; premier octet : capacité du tampon, lue par le firmware
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : tampon qui reçoit le nom
        lda #>nom
        sta ControlPort+5
        lda #1
        ldx #25                    ; fonction 25 : Get Time Zone
        jsr appel
        lda ControlPort+6          ; P2 : décalage en minutes (poids faible)
        sta decalage
        lda #<message
        ldx #>message
        jsr ecrire
        ldx #0                     ; le nom : longueur puis caractères
_nom:   cpx nom
        beq _fin
        lda nom+1,x
        jsr WriteCharacter
        inx
        bne _nom
_fin:   lda #<suite
        ldx #>suite
        jsr ecrire
        lda decalage               ; 0 à 255 : suffit pour les fuseaux positifs de l'exemple
        jsr decimal
        lda #<unite
        ldx #>unite
        jmp ecrire

; 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

; 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
diviseur: .byte 0

nom:      .fill 64
decalage: .byte 0
message:  .text "Fuseau : ", 0
suite:    .text ", decalage ", 0
unite:    .text " min", 13, 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Fuseau : UTC, decalage 0 min

1,26 Bank Checksum Trinity

Calcule la somme de contrôle Fletcher-16 d'une banque directement dans la flash, sans la recopier en RAM.

Entrées
OctetsTypeRôle
P0uint8numéro de banque (0 à 31)
Sorties
OctetsTypeRôle
P0-P1uint16s1 = somme des 8192 octets modulo 65536
P2-P3uint16s2 = somme des valeurs successives de s1 modulo 65536
erreuruint8non nul si la banque est invalide (les paramètres valent alors 0)

Une banque jamais écrite se lit $FF : s1 = $E000. Permet de savoir quelles banques d'un cache ont changé avant de les réécrire avec 1,22, sans tout recopier.

Texte de la documentation du firmware (anglais)

Returns the Fletcher 16 checksum of bank Parameter:0 (0-31) as stored in flash, without copying it to 6502 RAM (Trinity T-81) : s1 = sum of the 8192 bytes modulo 65536 in Parameters:0,1, s2 = sum of the successive values of s1 modulo 65536 in Parameters:2,3. A bank never written reads as $FF (s1 = $E000). Sets the error flag if the bank is invalid (the parameters are then zero). The 65C02 waits for the call ; it avoids copying each bank with Function 1,18 and summing it in 6502 code to find which banks of a cache need writing with Function 1,22.

C (llvm-mos)
/* Somme de contrôle de la banque 30 (groupe 1, fonction 26). */
#include <stdio.h>
#include <neo6502.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)
        ;
}

int main(void) {
    libre();
    ControlPort.params[0] = 30;                 /* banque */
    api(1, 26);                                 /* Bank Checksum */
    uint16_t s1 = ControlPort.params[0] | (ControlPort.params[1] << 8);
    uint16_t s2 = ControlPort.params[2] | (ControlPort.params[3] << 8);
    printf("Banque 30 : s1 = $%04X, s2 = $%04X%s\n", s1, s2, s1 == 0xE000 ? " (jamais ecrite)" : "");
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 30 : s1 = $E000, s2 = $F000 (jamais ecrite)
Mad Pascal
// Somme de contrôle de la banque 30 (groupe 1, fonction 26).
program checksum;
uses crt, neo6502;
var s1, s2: word;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 30;                   // banque
  NeoSendMessage(1, 26);                        // Bank Checksum
  NeoWaitMessage;
  s1 := wordParams[0];
  s2 := wordParams[1];
  write('Banque 30 : s1 = $', HexStr(s1, 4), ', s2 = $', HexStr(s2, 4));
  if s1 = $E000 then write(' (jamais ecrite)');
  writeln;
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 30 : s1 = $E000, s2 = $F000 (jamais ecrite)
NeoBASIC
10 ' Somme de controle de la banque 30 (groupe 1, fonction 26)
20 ' lire les resultats dans des variables juste apres l'appel, avant tout calcul : print et * reutilisent la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff04, 30 : poke $ff01, 26 : poke $ff00, 1
50 while peek($ff00) : wend : b0 = peek($ff04) : b1 = peek($ff05) : b2 = peek($ff06) : b3 = peek($ff07) : s1 = b0 + 256 * b1 : s2 = b2 + 256 * b3
60 print "Banque 30 : s1 = ";s1;", s2 = ";s2
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 30 : s1 = 57344, s2 = 61440
Assembleur 65C02 (64tass)
; Somme de contrôle de la banque 30 (groupe 1, fonction 26).
        .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:  jsr WaitMessage
        lda #30
        sta ControlPort+4          ; P0 : banque
        lda #1
        ldx #26                    ; fonction 26 : Bank Checksum
        jsr appel
        lda ControlPort+5          ; s1, poids fort puis poids faible
        sta s1+1
        lda ControlPort+4
        sta s1
        lda #<message
        ldx #>message
        jsr ecrire
        lda s1+1
        jsr hexa
        lda s1
        jsr hexa
        lda #13
        jmp WriteCharacter

hexa:   pha                        ; A en deux chiffres hexadécimaux
        lsr a
        lsr a
        lsr a
        lsr a
        jsr _h
        pla
        and #$0F
_h:     cmp #10
        bcc _c
        adc #6
_c:     adc #'0'
        jmp WriteCharacter

; 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

; 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
diviseur: .byte 0

s1:      .word 0
message: .text "Banque 30 : s1 = $", 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Banque 30 : s1 = $E000

1,27 Apply Boot Choice Trinity

Applique le choix du menu de démarrage (ou de boot/auto.txt) : charge le programme choisi et rend 1, ou rend 0 s'il n'y a rien à lancer.

Entrées : aucune.

Sorties
OctetsTypeRôle
P0uint81 : programme chargé, saut via l'adresse 0 prêt ; 0 : NeoDOS choisi, rien à lancer, ou échec (un message le dit)

Le noyau l'appelle une fois au reset, puis 1,3 (NeoDOS) si elle a rendu 0. Le choix est oublié une fois appliqué : appelée par un programme, elle rend donc 0 et ne fait rien, comme le montre l'exemple. Un .bin est chargé en $0800 comme NeoBASIC ; un .neo doit avoir une adresse d'exécution.

Texte de la documentation du firmware (anglais)

Applies the choice made in the boot menu or by boot/auto.txt (Trinity T-36, ADR-0001) : loads the chosen program and sets the jump through address zero, then returns 1 in Parameter:0 ; returns 0 when NeoDOS was chosen or the program could not be started (a message says so). The choice is forgotten once applied. The kernel calls it at reset, then Function 1,3 if it returned 0.

C (llvm-mos)
/* Demander le choix du menu de démarrage, déjà appliqué (groupe 1, fonction 27, 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)
        ;
}

int main(void) {
    libre();
    api(1, 27);                                 /* Apply Boot Choice */
    printf("Choix de demarrage : %u\n", ControlPort.params[0]);   /* 0 : rien à lancer */
    return 0;
}
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Choix de demarrage : 0
Mad Pascal
// Demander le choix du menu de démarrage, déjà appliqué (groupe 1, fonction 27, Trinity).
program bootchoice;
uses crt, neo6502;
var c: byte;
begin
  NeoSendMessage(1, 27);                        // Apply Boot Choice
  NeoWaitMessage;
  c := NeoMessage.params[0];                    // lu avant writeln, qui réutilise la boîte aux lettres
  writeln('Choix de demarrage : ', c);          // 0 : rien à lancer
end.
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Choix de demarrage : 0
NeoBASIC
10 ' Demander le choix du menu de demarrage, deja applique (groupe 1, fonction 27, Trinity)
20 while peek($ff00) : wend : poke $ff01, 27 : poke $ff00, 1 : ' Apply Boot Choice
30 while peek($ff00) : wend : c = peek($ff04)
40 print "Choix de demarrage : ";c : ' 0 : rien a lancer
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Choix de demarrage : 0
Assembleur 65C02 (64tass)
; Demander le choix du menu de démarrage, déjà appliqué (groupe 1, fonction 27, 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:  jsr WaitMessage
        lda #1
        ldx #27                    ; 1,27 : Apply Boot Choice
        jsr appel
        lda ControlPort+4          ; 0 : rien à lancer
        sta choix
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda choix
        jsr decimal
        lda #13
        jmp WriteCharacter

t0:     .text "Choix de demarrage : ", 0
choix:  .byte 0

; 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

; 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
diviseur: .byte 0
Sortie observée dans l'émulateur Phosphoneo, firmware Trinity 0.16.69 :
Choix de demarrage : 0

← L'API du Neo6502