Tachibana
Language: English

Group 3 — File I/O Official

3,1 List Directory · 3,2 Load File · 3,3 Store File · 3,4 File Open · 3,5 File Close · 3,6 File Seek · 3,7 File Tell · 3,8 File Read · 3,9 File Write · 3,10 File Size · 3,11 File Set Size · 3,12 File Rename · 3,13 File Delete · 3,14 Create Directory · 3,15 Change Directory · 3,16 File Stat · 3,17 Open Directory · 3,18 Read Directory · 3,19 Close Directory · 3,20 Copy File · 3,21 Set file attributes · 3,22 Check End of File. · 3,23 Get Current Working Directory. · 3,24 Volume Info · 3,25 Select Volume · 3,26 Get Current Volume · 3,27 File Read Paged · 3,28 File Read Background · 3,29 Last Entry Date Time · 3,32 List Filtered

3,1 List Directory Official

Displays the file listing of the current directory.

Inputs: none.

Outputs: none.

In NeoBASIC, cat makes the same call; cat "text" filters (3,32).

Firmware documentation text

Display the file listing of the present directory.

C (llvm-mos)
/* Lister le répertoire courant (groupe 3, fonction 1). */
#include <neo/api.h>

int main(void) {
    neo_file_list_directory();
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
PROG.NEO                        43 bytes.
Mad Pascal
// Lister le répertoire courant (groupe 3, fonction 1).
program liste;
uses crt, neo6502;
begin
  NeoShowDir;                                   // List Directory
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
PROG.NEO                        132 bytes.
NeoBASIC
10 ' Lister le repertoire courant (groupe 3, fonction 1)
20 cat
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
prog.bas                        321 bytes.
boot                            <Dir>
65C02 assembly (64tass)
; Lister le répertoire courant (groupe 3, fonction 1).
        .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 #3
        ldx #1                     ; fonction 1 : List Directory
        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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
PROG.NEO                        106 bytes.

3,2 Load File Official

Loads a whole file into memory at the given address; address $FFFF loads it into graphics memory (sprites, tiles, images).

Inputs
BytesTypeMeaning
P0-P1addraddress of the file name (length-prefixed)
P2-P3addrdestination address, or $FFFF for graphics memory
Outputs
BytesTypeMeaning
erreuruint80 if the file was loaded (otherwise an error code, e.g. $11 file not found)

The example first creates the file with 3,3. Nothing limits the size: the file must fit at the chosen address.

Firmware documentation text

Load a file by name into memory. On input:

Parameters:0,1 points to the length-prefixed filename string; Parameters:2,3 contains the location to write the data to. If the address is $FFFF, the file will instead be loaded into the graphics working memory, used for sprites, tiles, images.

On output: Error location contains an error/status code.

C (llvm-mos)
/* Enregistrer un texte, puis le recharger (groupe 3, fonctions 3 et 2). */
#include <stdio.h>
#include <string.h>
#include <neo/api.h>

static char texte[16] = "Bonjour";
static char relu[16];

int main(void) {
    neo_file_store("salut.txt", texte, strlen(texte) + 1);   /* 3,3 : avec le zéro final */
    neo_file_load("salut.txt", relu);                      /* Load File */
    if (neo_api_error())
        printf("Erreur %u\n", neo_api_error());
    else
        printf("Charge : %s\n", relu);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Charge : Bonjour
Mad Pascal
// Enregistrer un texte, puis le recharger (groupe 3, fonctions 3 et 2).
program charger;
uses crt, neo6502;
var texte, relu: string[16];
    e: byte;
begin
  texte := 'Bonjour';
  NeoSave('salut.txt', word(@texte), length(texte) + 1);   // 3,3 : la chaîne Pascal entière
  if NeoLoad('salut.txt', word(@relu)) then             // Load File
    writeln('Charge : ', relu)
  else
  begin
    e := NeoMessage.error;                      // à lire avant writeln, qui passe par l'API
    writeln('Erreur ', e);
  end;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Charge : Bonjour
NeoBASIC
10 ' Enregistrer un texte, puis le recharger (groupe 3, fonctions 3 et 2)
20 t = alloc(16) : n$ = "Bonjour" : a = t : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 save "salut.txt", t, 8
40 r = alloc(16) : n$ = "salut.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff06, r & 255 : poke $ff07, r >> 8 : poke $ff01, 2 : poke $ff00, 3
70 while peek($ff00) : wend : e = peek($ff02)
80 s$ = "" : for i = 1 to peek(r) : s$ = s$ + chr$(peek(r + i)) : next i
90 if e = 0 then print "Charge : ";s$
100 if e <> 0 then print "Erreur ";e
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Charge : Bonjour
65C02 assembly (64tass)
; Enregistrer un texte, puis le recharger (groupe 3, fonctions 3 et 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

start:  jsr WaitMessage            ; 3,3 : créer le fichier
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<texte
        sta ControlPort+6
        lda #>texte
        sta ControlPort+7
        lda #8                     ; 7 lettres + zéro final
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : nom
        lda #>nom
        sta ControlPort+5
        lda #<relu
        sta ControlPort+6          ; P2-P3 : destination
        lda #>relu
        sta ControlPort+7
        lda #3
        ldx #2                     ; fonction 2 : Load File
        jsr appel
        lda #<m
        ldx #>m
        jsr ecrire
        lda #<relu
        ldx #>relu
        jsr ecrire
        lda #13
        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

nom:    .byte 9
        .text "salut.txt"
texte:  .text "Bonjour", 0
relu:   .fill 16
m:      .text "Charge : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Charge : Bonjour

3,3 Store File Official

Saves an area of memory to a file (created or replaced).

Inputs
BytesTypeMeaning
P0-P1addraddress of the file name (length-prefixed)
P2-P3addraddress of the data
P4-P5uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint80 if the file was written

In NeoBASIC, save "name", address, length makes the same call (save "name" alone saves the program). In C, llvm-mos neo_file_stat (compiler c798c31) returns a wrong size (0) while the firmware returns the right one in P0-P3: the example calls 3,16 directly.

Firmware documentation text

Saves data in memory to a file. On input:

Parameters:0,1 points to the length-prefixed filename string; Parameters:2,3 contains the location to read data from; Parameters:4,5 specified the number of bytes to store.

On output: Error location contains an error/status code.

C (llvm-mos)
/* Enregistrer 7 octets, puis vérifier la taille du fichier (groupe 3, fonctions 3 et 16). */
/* neo_file_stat (llvm-mos, compilateur c798c31) rend une taille fausse : 3,16 est appelé directement. */
#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 const uint8_t nom[] = "\x09" "salut.txt";      /* longueur, puis le nom */

int main(void) {
    neo_file_store("salut.txt", "Bonjour", 7);  /* Store File */
    libre();
    ControlPort.params[0] = (uint16_t)nom & 0xFF;
    ControlPort.params[1] = (uint16_t)nom >> 8;
    api(3, 16);                                 /* File Stat : taille en P0-P3 */
    uint32_t taille = ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                    | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24);
    printf("salut.txt : %lu octets\n", (unsigned long)taille);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
salut.txt : 7 octets
Mad Pascal
// Enregistrer 7 octets, puis vérifier la taille du fichier (groupe 3, fonctions 3 et 16).
program sauver;
uses crt, neo6502;
var texte, nom: string[16];
    taille: cardinal;
    attr: byte;
begin
  texte := 'Bonjour';
  NeoSave('salut.txt', word(@texte) + 1, 7);    // Store File : les 7 lettres
  nom := 'salut.txt';
  if NeoStatFile(@nom, taille, attr) then       // 3,16 : taille
    writeln('salut.txt : ', taille, ' octets');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
salut.txt : 7 octets
NeoBASIC
10 ' Enregistrer 7 octets, puis verifier la taille du fichier (groupe 3, fonctions 3 et 16)
20 t = alloc(8) : for i = 1 to 7 : poke t + i - 1, asc(mid$("Bonjour", i, 1)) : next i
30 save "salut.txt", t, 7
40 n$ = "salut.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3
70 while peek($ff00) : wend : s = peek($ff04) + 256 * peek($ff05)
80 print "salut.txt : ";s;" octets"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
salut.txt : 7 octets
65C02 assembly (64tass)
; Enregistrer 7 octets, puis vérifier la taille du fichier (groupe 3, fonctions 3 et 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:  jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : nom
        lda #>nom
        sta ControlPort+5
        lda #<texte
        sta ControlPort+6          ; P2-P3 : données
        lda #>texte
        sta ControlPort+7
        lda #7
        sta ControlPort+8          ; P4-P5 : 7 octets
        stz ControlPort+9
        lda #3
        ldx #3                     ; fonction 3 : Store File
        jsr appel
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #3
        ldx #16                    ; 3,16 : File Stat
        jsr appel
        lda ControlPort+4          ; taille (octet de poids faible)
        pha
        lda #<m1
        ldx #>m1
        jsr ecrire
        pla
        jsr decimal
        lda #<m2
        ldx #>m2
        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:    .byte 9
        .text "salut.txt"
texte:  .text "Bonjour"
m1:     .text "salut.txt : ", 0
m2:     .text " octets", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
salut.txt : 7 octets

3,4 File Open Official

Opens a file on a channel, for reading, writing, or both.

Inputs
BytesTypeMeaning
P0uint8channel number
P1-P2addraddress of the name (length-prefixed)
P3uint8mode: 0 read only, 1 write only, 2 read-write, 3 create (or truncate) then read-write
Outputs
BytesTypeMeaning
erreuruint8non zero if opening failed (missing file in modes 0 to 2, channel already open…)

Opening the same file on two channels has undefined behaviour. In NeoBASIC, open input n, "name" (mode 0) and open output n, "name" (mode 3) make the same call.

NeoBASIC keywords that make this call: open

Firmware documentation text

Opens a file into a specific channel. On input:

Parameter:0 contains the file channel to open; Parameters:1,2 points to the length-prefixed filename string; Parameter:3 contains the open mode. See below.

Valid open modes are: 0 opens the file for read-only access; 1 opens the file for write-only access; 2 opens the file for read-write access; 3 creates the file if it doesn't already exist, truncates it if it does, and opens the file for read-write access.

Modes 0 to 2 will fail if the file does not already exist. If the channel is already open, the call fails. Opening the same file more than once on different channels has undefined behaviour, and is not recommended.

C (llvm-mos)
/* Créer un fichier sur le canal 1, y écrire, le fermer (groupe 3, fonctions 4, 9 et 5). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_file_open(1, "canal.txt", NEO_FILE_CREATE);     /* File Open, mode 3 */
    if (neo_api_error()) {
        printf("Ouverture impossible\n");
        return 0;
    }
    uint32_t n = neo_file_write(1, "Bonjour", 7);       /* 3,9 */
    neo_file_close(1);                                   /* 3,5 */
    printf("Ecrit : %lu octets\n", (unsigned long)n);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrit : 7 octets
Mad Pascal
// Créer un fichier sur le canal 1, y écrire, le fermer (groupe 3, fonctions 4, 9 et 5).
program ouvrir;
uses crt, neo6502;
var nom, texte: string[16];
    n: word;
begin
  nom := 'canal.txt';
  texte := 'Bonjour';
  if not NeoOpenFile(1, @nom, 3) then           // File Open, mode 3 : créer
  begin
    writeln('Ouverture impossible');
    exit;
  end;
  n := NeoWriteFile(1, word(@texte) + 1, 7);    // 3,9
  NeoCloseFile(1);                              // 3,5
  writeln('Ecrit : ', n, ' octets');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrit : 7 octets
NeoBASIC
10 ' Creer un fichier sur le canal 1, y ecrire, le fermer (groupe 3, fonctions 4, 9 et 5)
20 n$ = "canal.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 d = alloc(8) : for i = 1 to 7 : poke d + i - 1, asc(mid$("Bonjour", i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, 3 : poke $ff01, 4 : poke $ff00, 3
60 while peek($ff00) : wend : e = peek($ff02)
70 if e then print "Ouverture impossible" : end
80 poke $ff04, 1 : poke $ff05, d & 255 : poke $ff06, d >> 8 : poke $ff07, 7 : poke $ff08, 0 : poke $ff01, 9 : poke $ff00, 3
90 while peek($ff00) : wend : n = peek($ff07) + 256 * peek($ff08)
100 close
110 print "Ecrit : ";n;" octets"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrit : 7 octets
65C02 assembly (64tass)
; Créer un fichier sur le canal 1, y écrire, le fermer (groupe 3, fonctions 4, 9 et 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
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        lda #3
        sta ControlPort+7          ; P3 : mode 3, créer
        lda #3
        ldx #4                     ; fonction 4 : File Open
        jsr appel
        lda ControlPort+2
        bne _err
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; canal 1
        lda #<texte
        sta ControlPort+5          ; P1-P2 : données
        lda #>texte
        sta ControlPort+6
        lda #7
        sta ControlPort+7          ; P3-P4 : 7 octets
        stz ControlPort+8
        lda #3
        ldx #9                     ; 3,9 : File Write
        jsr appel
        lda ControlPort+7          ; octets écrits
        sta ecrits
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        jsr appel
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda ecrits
        jsr decimal
        lda #<m2
        ldx #>m2
        jmp ecrire
_err:   lda #<err
        ldx #>err
        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

ecrits: .byte 0
nom:    .byte 9
        .text "canal.txt"
texte:  .text "Bonjour"
m1:     .text "Ecrit : ", 0
m2:     .text " octets", 13, 0
err:    .text "Ouverture impossible", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrit : 7 octets

3,5 File Close Official

Closes a channel; $FF closes every open channel.

Inputs
BytesTypeMeaning
P0uint8channel number, or $FF for all

Outputs: none.

Closing a written file flushes its buffers to disk. In NeoBASIC, close makes the same call.

NeoBASIC keywords that make this call: close

Firmware documentation text

Closes a particular channel. On input:

Parameter:0 contains the file channel to close. If this is $FF this closes all open files.

C (llvm-mos)
/* Ouvrir puis fermer le canal 1 (groupe 3, fonction 5). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_file_open(1, "vide.txt", NEO_FILE_CREATE);  /* 3,4 */
    neo_file_close(1);                              /* File Close */
    printf("Canal 1 ferme, erreur %u\n", neo_api_error());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Canal 1 ferme, erreur 0
Mad Pascal
// Ouvrir puis fermer le canal 1 (groupe 3, fonction 5).
program fermer;
uses crt, neo6502;
var nom: string[16];
    e: byte;
begin
  nom := 'vide.txt';
  NeoOpenFile(1, @nom, 3);                      // 3,4
  NeoCloseFile(1);                              // File Close
  e := NeoMessage.error;                        // à lire avant writeln, qui passe par l'API
  writeln('Canal 1 ferme, erreur ', e);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Canal 1 ferme, erreur 0
NeoBASIC
10 ' Ouvrir puis fermer le canal 1 (groupe 3, fonction 5)
20 n$ = "vide.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 m = 3 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff01, 5 : poke $ff00, 3
50 while peek($ff00) : wend : e = peek($ff02)
60 print "Canal 1 ferme, erreur ";e
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Canal 1 ferme, erreur 0
65C02 assembly (64tass)
; Ouvrir puis fermer le canal 1 (groupe 3, 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:  lda #3
        jsr ouvrir
        jsr fermer                 ; fonction 5 : File Close
        lda ControlPort+2
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

m:      .text "Canal 1 ferme, erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Canal 1 ferme, erreur 0

3,6 File Seek Official

Moves the read and write position of a channel to the chosen byte.

Inputs
BytesTypeMeaning
P0uint8channel number
P1-P4uint32position (0 = start of file)

Outputs: none.

Seeking past the end extends the file; whether the size changes at the seek or at the write is undefined.

Firmware documentation text

Seeks the file opened on a particular channel to a location. On input:

Parameter:0 contains the file channel to operate on; Parameters:1..4 contains the file location.

You can seek beyond the end of a file to extend the file. However, whether the file size changes when the seek happens, or when you perform the write is undefined behavior.

C (llvm-mos)
/* Lire l'octet en position 4 de ABCDEFGH (groupe 3, fonction 6). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char c;
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    neo_file_seek(1, 4);                        /* File Seek */
    neo_file_read(1, &c, 1);                    /* 3,8 */
    neo_file_close(1);
    printf("Octet a la position 4 : %c\n", c);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet a la position 4 : E
Mad Pascal
// Lire l'octet en position 4 de ABCDEFGH (groupe 3, fonction 6).
program seek;
uses crt, neo6502;
var texte, nom: string[16];
    c: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  NeoSeekPos(1, 4);                             // File Seek
  NeoReadFile(1, word(@c), 1);                  // 3,8
  NeoCloseFile(1);
  writeln('Octet a la position 4 : ', chr(c));
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet a la position 4 : E
NeoBASIC
10 ' Lire l'octet en position 4 de ABCDEFGH (groupe 3, fonction 6)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = alloc(4) : m = 0 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff05, 4 : poke $ff06, 0 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 6 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, 1 : poke $ff05, b & 255 : poke $ff06, b >> 8 : poke $ff07, 1 : poke $ff08, 0 : poke $ff01, 8 : poke $ff00, 3
70 while peek($ff00) : wend
80 close
90 print "Octet a la position 4 : ";chr$(peek(b))
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet a la position 4 : E
65C02 assembly (64tass)
; Lire l'octet en position 4 de ABCDEFGH (groupe 3, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #0
        jsr ouvrir                 ; lecture seule
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #4
        sta ControlPort+5          ; P1-P4 : position 4
        stz ControlPort+6
        stz ControlPort+7
        stz ControlPort+8
        lda #3
        ldx #6                     ; fonction 6 : File Seek
        jsr appel
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #<octet
        sta ControlPort+5          ; P1-P2 : destination
        lda #>octet
        sta ControlPort+6
        lda #1
        sta ControlPort+7          ; P3-P4 : 1 octet
        stz ControlPort+8
        lda #3
        ldx #8                     ; 3,8 : File Read
        jsr appel
        jsr fermer
        lda #<m
        ldx #>m
        jsr ecrire
        lda octet
        jsr WriteCharacter
        lda #13
        jmp WriteCharacter
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

octet:  .byte 0
m:      .text "Octet a la position 4 : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet a la position 4 : E

3,7 File Tell Official

Gives the read and write position of a channel.

Inputs
BytesTypeMeaning
P0uint8channel number
Outputs
BytesTypeMeaning
P1-P4uint32position
Firmware documentation text

Returns the current seek location for the file opened on a particular channel. On input:

Parameter:0 contains the file channel to operate on.

On output:

Parameters:1..4 contains the seek location within the file.

C (llvm-mos)
/* Position après avoir lu 3 octets (groupe 3, fonction 7). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char tampon[3];
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    neo_file_read(1, tampon, 3);                /* 3,8 */
    uint32_t pos = neo_file_tell(1);            /* File Tell */
    neo_file_close(1);
    printf("Position apres 3 octets lus : %lu\n", (unsigned long)pos);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Position apres 3 octets lus : 3
Mad Pascal
// Position après avoir lu 3 octets (groupe 3, fonction 7).
program tell;
uses crt, neo6502;
var texte, nom: string[16];
    tampon: array[0..2] of byte;
    pos: cardinal;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  NeoReadFile(1, word(@tampon), 3);             // 3,8
  pos := NeoTellPos(1);                         // File Tell
  NeoCloseFile(1);
  writeln('Position apres 3 octets lus : ', pos);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Position apres 3 octets lus : 3
NeoBASIC
10 ' Position apres avoir lu 3 octets (groupe 3, fonction 7)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = alloc(4) : m = 0 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff05, b & 255 : poke $ff06, b >> 8 : poke $ff07, 3 : poke $ff08, 0 : poke $ff01, 8 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, 1 : poke $ff01, 7 : poke $ff00, 3
70 while peek($ff00) : wend : p = peek($ff05) + 256 * peek($ff06)
80 close
90 print "Position apres 3 octets lus : ";p
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Position apres 3 octets lus : 3
65C02 assembly (64tass)
; Position après avoir lu 3 octets (groupe 3, 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:
        jsr WaitMessage            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #0
        jsr ouvrir
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #<tampon
        sta ControlPort+5
        lda #>tampon
        sta ControlPort+6
        lda #3
        sta ControlPort+7          ; lire 3 octets
        stz ControlPort+8
        lda #3
        ldx #8                     ; 3,8 : File Read
        jsr appel
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #3
        ldx #7                     ; fonction 7 : File Tell
        jsr appel
        lda ControlPort+5          ; P1 : position (poids faible)
        sta pos
        jsr fermer
        lda #<m
        ldx #>m
        jsr ecrire
        lda pos
        jsr decimal
        lda #13
        jmp WriteCharacter
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

tampon: .fill 3
pos:    .byte 0
m:      .text "Position apres 3 octets lus : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Position apres 3 octets lus : 3

3,8 File Read Official

Reads bytes from an open channel, from its position, into memory (or graphics memory with address $FFFF).

Inputs
BytesTypeMeaning
P0uint8channel number
P1-P2addrdestination, or $FFFF for graphics memory
P3-P4uint16number of bytes requested
Outputs
BytesTypeMeaning
P3-P4uint16number of bytes actually read (fewer at end of file)

The position advances accordingly. Asking for more than what remains is not an error: P3-P4 tells how many bytes came.

Firmware documentation text

Reads data from an opened file. On input:

Parameter:0 contains the file channel to operate on. Parameters:1,2 points to the destination in memory, or $FFFF to read into graphics memory. Parameters:3,4 contains the amount of data to read.

On output:

Parameters:3,4 is updated to contain the amount of data actually read.

Data is read from the current seek position, which is advanced after the read.

C (llvm-mos)
/* Lire tout le fichier, en demandant plus qu'il n'y a (groupe 3, fonction 8). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char tampon[21] = { 0 };
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    uint16_t n = neo_file_read(1, tampon, 20);  /* File Read : 20 demandés */
    neo_file_close(1);
    printf("Lu : %s (%u octets sur 20 demandes)\n", tampon, n);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH (8 octets sur 20 demandes)
Mad Pascal
// Lire tout le fichier, en demandant plus qu'il n'y a (groupe 3, fonction 8).
program lire;
uses crt, neo6502;
var texte, nom: string[16];
    tampon: string[20];
    n: word;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  n := NeoReadFile(1, word(@tampon) + 1, 20);   // File Read : 20 demandés
  NeoCloseFile(1);
  tampon[0] := chr(n);                          // longueur de la chaîne Pascal
  writeln('Lu : ', tampon, ' (', n, ' octets sur 20 demandes)');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH (8 octets sur 20 demandes)
NeoBASIC
10 ' Lire tout le fichier, en demandant plus qu'il n'y a (groupe 3, fonction 8)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = alloc(24) : m = 0 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff05, b & 255 : poke $ff06, b >> 8 : poke $ff07, 20 : poke $ff08, 0 : poke $ff01, 8 : poke $ff00, 3
50 while peek($ff00) : wend : n = peek($ff07) + 256 * peek($ff08)
60 close
70 s$ = "" : for i = 0 to n - 1 : s$ = s$ + chr$(peek(b + i)) : next i
80 print "Lu : ";s$;" (";n;" octets sur 20 demandes)"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH (8 octets sur 20 demandes)
65C02 assembly (64tass)
; Lire tout le fichier, en demandant plus qu'il n'y a (groupe 3, 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:
        jsr WaitMessage            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #0
        jsr ouvrir
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<tampon
        sta ControlPort+5          ; P1-P2 : destination
        lda #>tampon
        sta ControlPort+6
        lda #20
        sta ControlPort+7          ; P3-P4 : 20 octets demandés
        stz ControlPort+8
        lda #3
        ldx #8                     ; fonction 8 : File Read
        jsr appel
        lda ControlPort+7          ; octets réellement lus
        sta lus
        jsr fermer
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda #<tampon
        ldx #>tampon
        jsr ecrire
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda lus
        jsr decimal
        lda #<m3
        ldx #>m3
        jmp ecrire
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

tampon: .fill 21                   ; zéros : la chaîne lue sera terminée
lus:    .byte 0
m1:     .text "Lu : ", 0
m2:     .text " (", 0
m3:     .text " octets sur 20 demandes)", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH (8 octets sur 20 demandes)

3,9 File Write Official

Writes bytes from memory into an open channel, from its position.

Inputs
BytesTypeMeaning
P0uint8channel number
P1-P2addraddress of the data
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
P3-P4uint16number of bytes actually written

The position advances accordingly. The write may stay buffered until the channel is closed (3,5).

Firmware documentation text

Writes data to an opened file. On input:

Parameter:0 contains the file channel to operate on; Parameters:1,2 points to the data in memory; Parameters:3,4 contains the amount of data to write.

On output: Parameters:3,4 is updated to contain the amount of data actually written.

Data is written to the current seek position, which is advanced after the write.

C (llvm-mos)
/* Écrire 5 octets, fermer, vérifier la taille (groupe 3, fonction 9). */
#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 const uint8_t nom[] = "\x08" "neuf.txt";

int main(void) {
    neo_file_open(1, "neuf.txt", NEO_FILE_CREATE);
    uint32_t n = neo_file_write(1, "Salut", 5); /* File Write */
    neo_file_close(1);
    libre();
    ControlPort.params[0] = (uint16_t)nom & 0xFF;
    ControlPort.params[1] = (uint16_t)nom >> 8;
    api(3, 16);                                 /* 3,16 : taille en P0-P3 */
    printf("Ecrits : %lu, taille du fichier : %u\n", (unsigned long)n, ControlPort.params[0] | (ControlPort.params[1] << 8));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrits : 5, taille du fichier : 5
Mad Pascal
// Écrire 5 octets, fermer, vérifier la taille (groupe 3, fonction 9).
program ecrire;
uses crt, neo6502;
var nom, texte: string[16];
    n: word;
    taille: cardinal;
    attr: byte;
begin
  nom := 'neuf.txt';
  texte := 'Salut';
  NeoOpenFile(1, @nom, 3);
  n := NeoWriteFile(1, word(@texte) + 1, 5);    // File Write
  NeoCloseFile(1);
  NeoStatFile(@nom, taille, attr);              // 3,16
  writeln('Ecrits : ', n, ', taille du fichier : ', taille);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrits : 5, taille du fichier : 5
NeoBASIC
10 ' Ecrire 5 octets, fermer, verifier la taille (groupe 3, fonction 9)
20 n$ = "neuf.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 d = alloc(8) : for i = 1 to 5 : poke d + i - 1, asc(mid$("Salut", i, 1)) : next i
40 m = 3 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
50 poke $ff04, 1 : poke $ff05, d & 255 : poke $ff06, d >> 8 : poke $ff07, 5 : poke $ff08, 0 : poke $ff01, 9 : poke $ff00, 3
60 while peek($ff00) : wend : n = peek($ff07)
70 close
80 while peek($ff00) : wend
90 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3
100 while peek($ff00) : wend : t = peek($ff04)
110 print "Ecrits : ";n;", taille du fichier : ";t
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrits : 5, taille du fichier : 5
65C02 assembly (64tass)
; Écrire 5 octets, fermer, vérifier la taille (groupe 3, fonction 9).
        .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 #3
        jsr ouvrir_neuf
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<salut
        sta ControlPort+5          ; P1-P2 : données
        lda #>salut
        sta ControlPort+6
        lda #5
        sta ControlPort+7          ; P3-P4 : 5 octets
        stz ControlPort+8
        lda #3
        ldx #9                     ; fonction 9 : File Write
        jsr appel
        lda ControlPort+7
        sta ecrits
        jsr fermer
        jsr WaitMessage
        lda #<neuf
        sta ControlPort+4
        lda #>neuf
        sta ControlPort+5
        lda #3
        ldx #16                    ; 3,16 : taille
        jsr appel
        lda ControlPort+4
        sta taille
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda ecrits
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda taille
        jsr decimal
        lda #13
        jmp WriteCharacter

ouvrir_neuf:
        pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #<neuf
        sta ControlPort+5
        lda #>neuf
        sta ControlPort+6
        pla
        sta ControlPort+7
        lda #3
        ldx #4
        jmp appel
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

neuf:   .byte 8
        .text "neuf.txt"
salut:  .text "Salut"
ecrits: .byte 0
taille: .byte 0
m1:     .text "Ecrits : ", 0
m2:     .text ", taille du fichier : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecrits : 5, taille du fichier : 5

3,10 File Size Official

Gives the current size of an open file, including writes still buffered.

Inputs
BytesTypeMeaning
P0uint8channel number
Outputs
BytesTypeMeaning
P1-P4uint32size in bytes

On a file being written, 3,16 (which reads the disk) may give a different size.

Firmware documentation text

Returns the current size of an opened file. On input:

Parameter:0 contains the file channel to operate on.

On output: Parameters:1..4 contains the size of the file.

This call should be used on open files, and takes into account any buffered data which has not yet been written to disk. Consequently, this may return a different size than Function 3,16 "File Stat".

C (llvm-mos)
/* Taille d'un fichier ouvert (groupe 3, fonction 10). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    uint32_t taille = neo_file_size(1);         /* File Size */
    neo_file_close(1);
    printf("Taille du fichier ouvert : %lu\n", (unsigned long)taille);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille du fichier ouvert : 8
Mad Pascal
// Taille d'un fichier ouvert (groupe 3, fonction 10).
program taille;
uses crt, neo6502;
var texte, nom: string[16];
    t: cardinal;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  t := NeoGetFileSize(1);                       // File Size
  NeoCloseFile(1);
  writeln('Taille du fichier ouvert : ', t);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille du fichier ouvert : 8
NeoBASIC
10 ' Taille d'un fichier ouvert (groupe 3, fonction 10)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 m = 0 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff01, 10 : poke $ff00, 3
50 while peek($ff00) : wend : t = peek($ff05) + 256 * peek($ff06)
60 close
70 print "Taille du fichier ouvert : ";t
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille du fichier ouvert : 8
65C02 assembly (64tass)
; Taille d'un fichier ouvert (groupe 3, 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:
        jsr WaitMessage            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #0
        jsr ouvrir
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #3
        ldx #10                    ; fonction 10 : File Size
        jsr appel
        lda ControlPort+5          ; P1 : taille (poids faible)
        sta taille
        jsr fermer
        lda #<m
        ldx #>m
        jsr ecrire
        lda taille
        jsr decimal
        lda #13
        jmp WriteCharacter
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

taille: .byte 0
m:      .text "Taille du fichier ouvert : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille du fichier ouvert : 8

3,11 File Set Size Official

Extends or truncates an open file to the chosen size.

Inputs
BytesTypeMeaning
P0uint8channel number
P1-P4uint32new size

Outputs: none.

In Mad Pascal 1.7.8, NeoSetFileSize calls function 10 (read the size) instead of 11: the file does not change. The Pascal example makes the call directly.

Firmware documentation text

Extends or truncates an opened file to a particular size. On input:

Parameter:0 contains the file channel to operate on; Parameters:1..4 contains the new size of the file.

C (llvm-mos)
/* Tronquer ABCDEFGH à 3 octets (groupe 3, fonction 11). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ_WRITE);
    neo_file_set_size(1, 3);                    /* File Set Size */
    uint32_t taille = neo_file_size(1);         /* 3,10 */
    neo_file_close(1);
    printf("Taille apres troncature : %lu\n", (unsigned long)taille);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille apres troncature : 3
Mad Pascal
// Tronquer ABCDEFGH à 3 octets (groupe 3, fonction 11).
// NeoSetFileSize (Mad Pascal 1.7.8) appelle la fonction 10 : appel direct.
program tronquer;
uses crt, neo6502;
var texte, nom: string[16];
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 2);                      // lecture-écriture
  NeoWaitMessage;
  NeoMessage.params[0] := 1;                    // P0 : canal
  FI_offset := 3;                               // P1-P4 : nouvelle taille
  NeoSendMessage(3, 11);                        // File Set Size
  NeoWaitMessage;
  writeln('Taille apres troncature : ', NeoGetFileSize(1));
  NeoCloseFile(1);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille apres troncature : 3
NeoBASIC
10 ' Tronquer ABCDEFGH a 3 octets (groupe 3, fonction 11)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 m = 2 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff05, 3 : poke $ff06, 0 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 11 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, 1 : poke $ff01, 10 : poke $ff00, 3
70 while peek($ff00) : wend : t = peek($ff05)
80 close
90 print "Taille apres troncature : ";t
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille apres troncature : 3
65C02 assembly (64tass)
; Tronquer ABCDEFGH à 3 octets (groupe 3, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #2
        jsr ouvrir                 ; lecture-écriture
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #3
        sta ControlPort+5          ; P1-P4 : 3 octets
        stz ControlPort+6
        stz ControlPort+7
        stz ControlPort+8
        lda #3
        ldx #11                    ; fonction 11 : File Set Size
        jsr appel
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #10                    ; 3,10 : taille
        jsr appel
        lda ControlPort+5
        sta taille
        jsr fermer
        lda #<m
        ldx #>m
        jsr ecrire
        lda taille
        jsr decimal
        lda #13
        jmp WriteCharacter
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

taille: .byte 0
m:      .text "Taille apres troncature : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille apres troncature : 3

3,12 File Rename Official

Renames a file, possibly moving it to another directory.

Inputs
BytesTypeMeaning
P0-P1addraddress of the old name (length-prefixed)
P2-P3addraddress of the new name (length-prefixed)
Outputs
BytesTypeMeaning
erreuruint8non zero if the rename failed
Firmware documentation text

Renames a file. On input:

Parameters:0,1 points to the length-prefixed string for the old name; Parameters:2,3 points to the length-prefixed string for the new name.

Files may be renamed across directories.

C (llvm-mos)
/* Renommer abc.txt en xyz.txt (groupe 3, fonction 12). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_rename("abc.txt", "xyz.txt");      /* File Rename */
    printf("Renomme : abc.txt -> xyz.txt, erreur %u\n", neo_api_error());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Renomme : abc.txt -> xyz.txt, erreur 0
Mad Pascal
// Renommer abc.txt en xyz.txt (groupe 3, fonction 12).
program renommer;
uses crt, neo6502;
var texte, nom, nouveau: string[16];
    e: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  nouveau := 'xyz.txt';
  NeoRenameFile(@nom, @nouveau);                // File Rename
  e := NeoMessage.error;                        // à lire avant writeln, qui passe par l'API
  writeln('Renomme : abc.txt -> xyz.txt, erreur ', e);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Renomme : abc.txt -> xyz.txt, erreur 0
NeoBASIC
10 ' Renommer abc.txt en xyz.txt (groupe 3, fonction 12)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = a : n$ = "xyz.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, b & 255 : poke $ff05, b >> 8 : poke $ff06, a & 255 : poke $ff07, a >> 8 : poke $ff01, 12 : poke $ff00, 3
60 while peek($ff00) : wend : e = peek($ff02)
70 print "Renomme : abc.txt -> xyz.txt, erreur ";e
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Renomme : abc.txt -> xyz.txt, erreur 0
65C02 assembly (64tass)
; Renommer abc.txt en xyz.txt (groupe 3, 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:
        jsr WaitMessage            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : ancien nom
        lda #>nom
        sta ControlPort+5
        lda #<xyz
        sta ControlPort+6          ; P2-P3 : nouveau nom
        lda #>xyz
        sta ControlPort+7
        lda #3
        ldx #12                    ; fonction 12 : File Rename
        jsr appel
        lda ControlPort+2
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

xyz:    .byte 7
        .text "xyz.txt"
m:      .text "Renomme : abc.txt -> xyz.txt, erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Renomme : abc.txt -> xyz.txt, erreur 0

3,13 File Delete Official

Deletes a file, or an empty directory.

Inputs
BytesTypeMeaning
P0-P1addraddress of the name (length-prefixed)
Outputs
BytesTypeMeaning
erreuruint8non zero if the deletion failed

Deleting an open file has undefined behaviour. The example checks with 3,16 that the file is gone (error $11: file not found).

Firmware documentation text

Deletes a file or directory. On input:

Parameters:0,1 points to the length-prefixed filename string.

Deleting a file which is open has undefined behaviour. Directories may only be deleted if they are empty.

C (llvm-mos)
/* Supprimer un fichier, puis vérifier qu'il a disparu (groupe 3, fonction 13). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_file_stat_t st;
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_delete("abc.txt");                 /* File Delete */
    neo_file_stat("abc.txt", &st);              /* 3,16 : doit échouer */
    printf("Supprime, puis 3,16 donne l'erreur %u\n", neo_api_error());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Supprime, puis 3,16 donne l'erreur 17
Mad Pascal
// Supprimer un fichier, puis vérifier qu'il a disparu (groupe 3, fonction 13).
program supprimer;
uses crt, neo6502;
var texte, nom: string[16];
    e: byte;
    taille: cardinal;
    attr: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoDeleteFile(@nom);                          // File Delete
  NeoStatFile(@nom, taille, attr);              // 3,16 : doit échouer
  e := NeoMessage.error;                        // à lire avant writeln, qui passe par l'API
  writeln('Supprime, puis 3,16 donne l''erreur ', e);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Supprime, puis 3,16 donne l'erreur 17
NeoBASIC
10 ' Supprimer un fichier, puis verifier qu'il a disparu (groupe 3, fonction 13)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 while peek($ff00) : wend
40 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 13 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3
70 while peek($ff00) : wend : e = peek($ff02)
80 print "Supprime, puis 3,16 donne l'erreur ";e
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Supprime, puis 3,16 donne l'erreur 17
65C02 assembly (64tass)
; Supprimer un fichier, puis vérifier qu'il a disparu (groupe 3, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        ldx #13                    ; fonction 13 : File Delete
        jsr sur_nom
        ldx #16                    ; 3,16 : doit échouer
        jsr sur_nom
        lda ControlPort+2
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter

sur_nom:                           ; X = fonction du groupe 3, sur abc.txt
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #3
        jmp appel
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

m:      .text "Supprime, puis 3,16 donne l'erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Supprime, puis 3,16 donne l'erreur 17

3,14 Create Directory Official

Creates a directory.

Inputs
BytesTypeMeaning
P0-P1addraddress of the name (length-prefixed)
Outputs
BytesTypeMeaning
erreuruint8non zero if creation failed (directory already there, for example)

The example checks with 3,16 that the new name has the "directory" bit (bit 0 of the attributes). In C, 3,16 is called directly (llvm-mos neo_file_stat returns wrong values, see 3,16).

Firmware documentation text

Creates a new directory. On input:

Parameters:0,1 points to the length-prefixed filename string.

C (llvm-mos)
/* Créer un répertoire, puis vérifier son attribut (groupe 3, fonction 14). */
#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 const uint8_t rep[] = "\x03" "rep";

int main(void) {
    neo_file_mkdir("rep");                      /* Create Directory */
    libre();
    ControlPort.params[0] = (uint16_t)rep & 0xFF;
    ControlPort.params[1] = (uint16_t)rep >> 8;
    api(3, 16);                                 /* 3,16 : attributs en P4 */
    printf("Repertoire cree, bit repertoire : %u\n", ControlPort.params[4] & 1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire cree, bit repertoire : 1
Mad Pascal
// Créer un répertoire, puis vérifier son attribut (groupe 3, fonction 14).
program creer;
uses crt, neo6502;
var rep: string[16];
    taille: cardinal;
    attr: byte;
begin
  rep := 'rep';
  NeoCreateDirectory(@rep);                     // Create Directory
  NeoStatFile(@rep, taille, attr);              // 3,16
  writeln('Repertoire cree, bit repertoire : ', attr and FI_ATTR_DIRECTORY);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire cree, bit repertoire : 1
NeoBASIC
10 ' Creer un repertoire, puis verifier son attribut (groupe 3, fonction 14)
20 n$ = "rep" : a = alloc(8) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 while peek($ff00) : wend
40 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 14 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3
70 while peek($ff00) : wend : t = peek($ff08) & 1
80 print "Repertoire cree, bit repertoire : ";t
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire cree, bit repertoire : 1
65C02 assembly (64tass)
; Créer un répertoire, puis vérifier son attribut (groupe 3, fonction 14).
        .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 #<rep
        ldx #>rep
        ldy #14                    ; fonction 14 : Create Directory
        jsr sur_nom
        lda #<rep
        ldx #>rep
        ldy #16                    ; 3,16 : attributs en P4
        jsr sur_nom
        lda ControlPort+8
        and #1                     ; bit 0 : répertoire
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        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

rep:    .byte 3
        .text "rep"
m:      .text "Repertoire cree, bit repertoire : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire cree, bit repertoire : 1

3,15 Change Directory Official

Changes the current working directory.

Inputs
BytesTypeMeaning
P0-P1addraddress of the path (length-prefixed)
Outputs
BytesTypeMeaning
erreuruint8non zero if the directory does not exist

Names without a path in the other functions of the group then refer to this directory. ".." goes up one level.

Firmware documentation text

Changes the current working directory. On input:

Parameters:0,1 points to the length-prefixed path string.

C (llvm-mos)
/* Créer un répertoire et s'y placer (groupe 3, fonction 15). */
#include <stdio.h>
#include <neo/api.h>

static char cwd[33];

static const char *courant(void) {
    neo_file_get_cwd(cwd, 32);                  /* 3,23 : chaîne précédée de sa longueur */
    cwd[(uint8_t)cwd[0] + 1] = 0;
    return cwd + 1;
}

int main(void) {
    neo_file_mkdir("rep");                      /* 3,14 */
    neo_file_chdir("rep");                      /* Change Directory */
    printf("Repertoire courant : %s\n", courant());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /rep
Mad Pascal
// Créer un répertoire et s'y placer (groupe 3, fonction 15).
program chdir;
uses crt, neo6502;
var rep: string[16];

function courant: string;
var cwd: string[32];
begin
  NeoWaitMessage;
  wordParams[0] := word(@cwd);                  // P0-P1 : tampon
  NeoMessage.params[2] := 32;                   // P2 : longueur maximale
  NeoSendMessage(3, 23);                        // 3,23 : Get Current Working Directory
  NeoWaitMessage;
  result := cwd;
end;

begin
  rep := 'rep';
  NeoCreateDirectory(@rep);                     // 3,14
  NeoChangeDirectory(@rep);                     // Change Directory
  writeln('Repertoire courant : ', courant);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /rep
NeoBASIC
10 ' Creer un repertoire et s'y placer (groupe 3, fonction 15)
20 n$ = "rep" : a = alloc(8) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 while peek($ff00) : wend
40 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 14 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 15 : poke $ff00, 3
70 while peek($ff00) : wend
80 b = alloc(34) : poke $ff04, b & 255 : poke $ff05, b >> 8 : poke $ff06, 32 : poke $ff01, 23 : poke $ff00, 3
90 while peek($ff00) : wend : s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
100 print "Repertoire courant : ";s$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /rep
65C02 assembly (64tass)
; Créer un répertoire et s'y placer (groupe 3, fonction 15).
        .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 #<rep
        ldx #>rep
        ldy #14                    ; 3,14 : Create Directory
        jsr sur_nom
        lda #<rep
        ldx #>rep
        ldy #15                    ; fonction 15 : Change Directory
        jsr sur_nom
        jsr courant
        lda #<m
        ldx #>m
        jsr ecrire
        lda #<cwd
        ldx #>cwd
        jsr pecrire
        lda #13
        jmp WriteCharacter

; Répertoire courant dans cwd (précédé de sa longueur).
courant:
        jsr WaitMessage
        lda #<cwd
        sta ControlPort+4          ; P0-P1 : tampon
        lda #>cwd
        sta ControlPort+5
        lda #32
        sta ControlPort+6          ; P2 : longueur maximale
        lda #3
        ldx #23                    ; 3,23 : Get Current Working Directory
        jmp appel
cwd:    .fill 34

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        jmp appel

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .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

rep:    .byte 3
        .text "rep"
m:      .text "Repertoire courant : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /rep

3,16 File Stat Official

Gives the size and attributes of a file, by name.

Inputs
BytesTypeMeaning
P0-P1addraddress of the name (length-prefixed)
Outputs
BytesTypeMeaning
P0-P3uint32size in bytes
P4uint8attributes: bit 0 directory, 1 system, 2 archive, 3 read only, 4 hidden
erreuruint8non zero if the file does not exist

On a file open for writing, the size may not include what is still buffered (3,10 does). In NeoBASIC, exists("name") makes this call and returns true or false. In C, llvm-mos neo_file_stat (compiler c798c31) returns a wrong size and attributes: the example makes the call directly.

NeoBASIC keywords that make this call: exists()

Firmware documentation text

Retrieves information about a file by name. On input:

Parameters:0,1 points to the length-prefixed filename string.

Parameters:0..3 contains the length of the file; Parameter:4 contains the attributes bit-field of the file.

If the file is open for writing, this may not return the correct size due to buffered data not having been flushed to disk.

File attributes are a bitfield as follows: 0,0,0,Hidden, Read Only, Archive, System, Directory.

C (llvm-mos)
/* Taille et attributs d'un fichier (groupe 3, fonction 16). */
/* neo_file_stat (llvm-mos, compilateur c798c31) rend des valeurs fausses : appel direct. */
#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 const uint8_t nom[] = "\x07" "abc.txt";

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    libre();
    ControlPort.params[0] = (uint16_t)nom & 0xFF;   /* P0-P1 : nom */
    ControlPort.params[1] = (uint16_t)nom >> 8;
    api(3, 16);                                     /* File Stat */
    printf("abc.txt : %u octets, repertoire : %u\n",
           ControlPort.params[0] | (ControlPort.params[1] << 8), ControlPort.params[4] & 1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 8 octets, repertoire : 0
Mad Pascal
// Taille et attributs d'un fichier (groupe 3, fonction 16).
program stat;
uses crt, neo6502;
var texte, nom: string[16];
    taille: cardinal;
    attr: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoStatFile(@nom, taille, attr);              // File Stat
  writeln('abc.txt : ', taille, ' octets, repertoire : ', attr and FI_ATTR_DIRECTORY);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 8 octets, repertoire : 0
NeoBASIC
10 ' Taille et attributs d'un fichier (groupe 3, fonction 16)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 if exists("abc.txt")
40 while peek($ff00) : wend
50 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3
60 while peek($ff00) : wend : t = peek($ff04) + 256 * peek($ff05) : r = peek($ff08) & 1
70 print "abc.txt : ";t;" octets, repertoire : ";r
80 endif
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 8 octets, repertoire : 0
65C02 assembly (64tass)
; Taille et attributs d'un fichier (groupe 3, 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:
        jsr WaitMessage            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #<nom
        ldx #>nom
        ldy #16                    ; fonction 16 : File Stat
        jsr sur_nom
        lda ControlPort+4          ; P0 : taille (poids faible)
        sta taille
        lda ControlPort+8          ; P4 : attributs
        and #1
        sta dir
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda taille
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda dir
        jsr decimal
        lda #13
        jmp WriteCharacter

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

taille: .byte 0
dir:    .byte 0
m1:     .text "abc.txt : ", 0
m2:     .text " octets, repertoire : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 8 octets, repertoire : 0

3,17 Open Directory Official

Opens a directory to read its entries one by one (3,18).

Inputs
BytesTypeMeaning
P0-P1addraddress of the path (length-prefixed); "." for the current directory
Outputs
BytesTypeMeaning
erreuruint8non zero if the directory does not exist

Only one directory open at a time: opening another closes the first. An open directory may prevent its deletion; close it (3,19) after use.

Firmware documentation text

Opens a directory for enumeration. On input:

Parameters:0,1 points to the length-prefixed filename string.

Only one directory at a time may be opened. If a directory is already open when this call is made, it is automatically closed. However, an open directory may make it impossible to delete the directory; so closing the directory after use is good practice.

C (llvm-mos)
/* Lister le répertoire courant (groupe 3, fonction 17 : Open Directory). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char nom[32];
    neo_file_stat_t st;
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_opendir(".");                      /* 3,17 : Open Directory */
    for (;;) {
        nom[0] = sizeof nom - 1;                /* capacité, lue par le firmware */
        neo_file_readdir(nom, &st);             /* 3,18 : Read Directory */
        if (neo_api_error())                    /* plus d'entrée */
            break;
        printf("%s %lu\n", nom, (unsigned long)st.size);
    }
    neo_file_closedir();                        /* 3,19 : Close Directory */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 4642
Mad Pascal
// Lister le répertoire courant (groupe 3, fonction 17 : Open Directory).
program liste;
uses crt, neo6502;
var texte, nom: string[16];
    f: string[31];
    taille: cardinal;
    attr: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := '.';
  NeoOpenDirectory(@nom);                       // 3,17 : Open Directory
  repeat
    f[0] := chr(31);                            // capacité, lue par le firmware
    if not NeoReadDirectory(f, taille, attr) then break;   // 3,18 : Read Directory
    writeln(f, ' ', taille);
  until false;
  NeoCloseDirectory;                            // 3,19 : Close Directory
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 741
NeoBASIC
10 ' Lister le repertoire courant (groupe 3, fonction 17 : Open Directory).
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 n$ = "." : a = alloc(4) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 17 : poke $ff00, 3 : ' Open Directory
60 b = alloc(34) : e = 0
70 while e = 0
80 poke b, 32 : while peek($ff00) : wend : ' capacite, lue par le firmware
90 poke $ff04, b & 255 : poke $ff05, b >> 8 : poke $ff01, 18 : poke $ff00, 3 : ' Read Directory
100 while peek($ff00) : wend : e = peek($ff02) : t = peek($ff06) + 256 * peek($ff07)
110 if e = 0
120 s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
130 print s$;" ";t
140 endif
150 wend
160 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 3 : ' Close Directory
170 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
prog.bas 925
boot 0
65C02 assembly (64tass)
; Lister le répertoire courant (groupe 3, fonction 17 : Open Directory).
        .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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #<point
        ldx #>point
        ldy #17                    ; 3,17 : Open Directory
        jsr sur_nom
_suiv:  lda #32
        sta fichier                ; capacité, lue par le firmware
        lda #<fichier
        ldx #>fichier
        ldy #18                    ; 3,18 : Read Directory
        jsr sur_nom
        lda ControlPort+2
        bne _fin                   ; erreur : plus d'entrée
        lda ControlPort+6          ; P2 : taille (poids faible)
        sta taille
        lda #<fichier
        ldx #>fichier
        jsr pecrire
        lda #' '
        jsr WriteCharacter
        lda taille
        jsr decimal
        lda #13
        jsr WriteCharacter
        bra _suiv
_fin:   jsr WaitMessage
        lda #3
        ldx #19                    ; 3,19 : Close Directory
        jmp appel

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        jmp appel

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

point:  .byte 1
        .text "."
taille: .byte 0
fichier: .fill 34
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 13

3,18 Read Directory Official

Reads the next entry of the open directory: name, size, attributes.

Inputs
BytesTypeMeaning
P0-P1addraddress of the name buffer; its first byte gives its capacity
Outputs
BytesTypeMeaning
tamponstringname (length-prefixed), without path
P2-P5uint32size in bytes
P6uint8attributes, as in 3,16
erreuruint8non zero when there are no more entries

The firmware reads the buffer capacity from its first byte: it must be set before each call. With 0, the entry is consumed but the name comes back empty. This also applies to llvm-mos neo_file_readdir (the array passed must start with its capacity) and to Mad Pascal NeoReadDirectory (the current length of the string is used as capacity: an empty string gives an empty name). The examples do so.

Firmware documentation text

Reads an item from the currently open directory. On input:

Parameters:0,1 points to a length-prefixed buffer for returning the filename.

Parameters:0,1 is unchanged, but the buffer is updated to contain the length-prefixed filename (without any leading path); Parameters:2..5 contains the length of the file; Parameter:6 contains the file attributes, as described by Function 3,16 "File Stat".

If there are no more items to read, this call fails and an error is flagged.

C (llvm-mos)
/* Lister le répertoire courant (groupe 3, fonction 18 : Read Directory). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char nom[32];
    neo_file_stat_t st;
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_opendir(".");                      /* 3,17 : Open Directory */
    for (;;) {
        nom[0] = sizeof nom - 1;                /* capacité, lue par le firmware */
        neo_file_readdir(nom, &st);             /* 3,18 : Read Directory */
        if (neo_api_error())                    /* plus d'entrée */
            break;
        printf("%s %lu\n", nom, (unsigned long)st.size);
    }
    neo_file_closedir();                        /* 3,19 : Close Directory */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 4642
Mad Pascal
// Lister le répertoire courant (groupe 3, fonction 18 : Read Directory).
program liste;
uses crt, neo6502;
var texte, nom: string[16];
    f: string[31];
    taille: cardinal;
    attr: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := '.';
  NeoOpenDirectory(@nom);                       // 3,17 : Open Directory
  repeat
    f[0] := chr(31);                            // capacité, lue par le firmware
    if not NeoReadDirectory(f, taille, attr) then break;   // 3,18 : Read Directory
    writeln(f, ' ', taille);
  until false;
  NeoCloseDirectory;                            // 3,19 : Close Directory
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 741
NeoBASIC
10 ' Lister le repertoire courant (groupe 3, fonction 18 : Read Directory).
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 n$ = "." : a = alloc(4) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 17 : poke $ff00, 3 : ' Open Directory
60 b = alloc(34) : e = 0
70 while e = 0
80 poke b, 32 : while peek($ff00) : wend : ' capacite, lue par le firmware
90 poke $ff04, b & 255 : poke $ff05, b >> 8 : poke $ff01, 18 : poke $ff00, 3 : ' Read Directory
100 while peek($ff00) : wend : e = peek($ff02) : t = peek($ff06) + 256 * peek($ff07)
110 if e = 0
120 s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
130 print s$;" ";t
140 endif
150 wend
160 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 3 : ' Close Directory
170 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
prog.bas 925
boot 0
65C02 assembly (64tass)
; Lister le répertoire courant (groupe 3, fonction 18 : Read Directory).
        .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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #<point
        ldx #>point
        ldy #17                    ; 3,17 : Open Directory
        jsr sur_nom
_suiv:  lda #32
        sta fichier                ; capacité, lue par le firmware
        lda #<fichier
        ldx #>fichier
        ldy #18                    ; 3,18 : Read Directory
        jsr sur_nom
        lda ControlPort+2
        bne _fin                   ; erreur : plus d'entrée
        lda ControlPort+6          ; P2 : taille (poids faible)
        sta taille
        lda #<fichier
        ldx #>fichier
        jsr pecrire
        lda #' '
        jsr WriteCharacter
        lda taille
        jsr decimal
        lda #13
        jsr WriteCharacter
        bra _suiv
_fin:   jsr WaitMessage
        lda #3
        ldx #19                    ; 3,19 : Close Directory
        jmp appel

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        jmp appel

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

point:  .byte 1
        .text "."
taille: .byte 0
fichier: .fill 34
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 13

3,19 Close Directory Official

Closes the directory opened by 3,17.

Inputs: none.

Outputs: none.

Firmware documentation text

Closes any directory opened previously by Function 3,17 "Open Directory".

C (llvm-mos)
/* Lister le répertoire courant (groupe 3, fonction 19 : Close Directory). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char nom[32];
    neo_file_stat_t st;
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_opendir(".");                      /* 3,17 : Open Directory */
    for (;;) {
        nom[0] = sizeof nom - 1;                /* capacité, lue par le firmware */
        neo_file_readdir(nom, &st);             /* 3,18 : Read Directory */
        if (neo_api_error())                    /* plus d'entrée */
            break;
        printf("%s %lu\n", nom, (unsigned long)st.size);
    }
    neo_file_closedir();                        /* 3,19 : Close Directory */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 4642
Mad Pascal
// Lister le répertoire courant (groupe 3, fonction 19 : Close Directory).
program liste;
uses crt, neo6502;
var texte, nom: string[16];
    f: string[31];
    taille: cardinal;
    attr: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := '.';
  NeoOpenDirectory(@nom);                       // 3,17 : Open Directory
  repeat
    f[0] := chr(31);                            // capacité, lue par le firmware
    if not NeoReadDirectory(f, taille, attr) then break;   // 3,18 : Read Directory
    writeln(f, ' ', taille);
  until false;
  NeoCloseDirectory;                            // 3,19 : Close Directory
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 741
NeoBASIC
10 ' Lister le repertoire courant (groupe 3, fonction 19 : Close Directory).
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 n$ = "." : a = alloc(4) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 17 : poke $ff00, 3 : ' Open Directory
60 b = alloc(34) : e = 0
70 while e = 0
80 poke b, 32 : while peek($ff00) : wend : ' capacite, lue par le firmware
90 poke $ff04, b & 255 : poke $ff05, b >> 8 : poke $ff01, 18 : poke $ff00, 3 : ' Read Directory
100 while peek($ff00) : wend : e = peek($ff02) : t = peek($ff06) + 256 * peek($ff07)
110 if e = 0
120 s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
130 print s$;" ";t
140 endif
150 wend
160 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 3 : ' Close Directory
170 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
prog.bas 926
boot 0
65C02 assembly (64tass)
; Lister le répertoire courant (groupe 3, fonction 19 : Close Directory).
        .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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #<point
        ldx #>point
        ldy #17                    ; 3,17 : Open Directory
        jsr sur_nom
_suiv:  lda #32
        sta fichier                ; capacité, lue par le firmware
        lda #<fichier
        ldx #>fichier
        ldy #18                    ; 3,18 : Read Directory
        jsr sur_nom
        lda ControlPort+2
        bne _fin                   ; erreur : plus d'entrée
        lda ControlPort+6          ; P2 : taille (poids faible)
        sta taille
        lda #<fichier
        ldx #>fichier
        jsr pecrire
        lda #' '
        jsr WriteCharacter
        lda taille
        jsr decimal
        lda #13
        jsr WriteCharacter
        bra _suiv
_fin:   jsr WaitMessage
        lda #3
        ldx #19                    ; 3,19 : Close Directory
        jmp appel

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        jmp appel

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

point:  .byte 1
        .text "."
taille: .byte 0
fichier: .fill 34
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt 8
PROG.NEO 13

3,20 Copy File Official

Copies a file under another name.

Inputs
BytesTypeMeaning
P0-P1addraddress of the source name (length-prefixed)
P2-P3addraddress of the copy name (length-prefixed)
Outputs
BytesTypeMeaning
erreuruint8non zero if the copy failed

Files only: a directory cannot be copied.

Firmware documentation text

Copies a file. On input:

Parameters:0,1 points to the length-prefixed old filename; Parameters:2,3 points to the length-prefixed new filename.

Only single files may be copied, not directories.

C (llvm-mos)
/* Copier abc.txt, puis relire la copie (groupe 3, fonction 20). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char relu[9] = { 0 };
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_copy("abc.txt", "copie.txt");      /* Copy File */
    neo_file_load("copie.txt", relu);           /* 3,2 */
    printf("Copie : %s\n", relu);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Copie : ABCDEFGH
Mad Pascal
// Copier abc.txt, puis relire la copie (groupe 3, fonction 20).
program copier;
uses crt, neo6502;
var texte, nom, copie, relu: string[16];
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  copie := 'copie.txt';
  NeoCopyFile(@nom, @copie);                    // Copy File
  NeoLoad('copie.txt', word(@relu) + 1);        // 3,2
  relu[0] := chr(8);
  writeln('Copie : ', relu);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Copie : ABCDEFGH
NeoBASIC
10 ' Copier abc.txt, puis relire la copie (groupe 3, fonction 20)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 c = a : n$ = "copie.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
40 while peek($ff00) : wend
50 poke $ff04, c & 255 : poke $ff05, c >> 8 : poke $ff06, a & 255 : poke $ff07, a >> 8 : poke $ff01, 20 : poke $ff00, 3
60 while peek($ff00) : wend
70 r = alloc(16) : load "copie.txt", r
80 s$ = "" : for i = 0 to 7 : s$ = s$ + chr$(peek(r + i)) : next i
90 print "Copie : ";s$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Copie : ABCDEFGH
65C02 assembly (64tass)
; Copier abc.txt, puis relire la copie (groupe 3, fonction 20).
        .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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : nom d'origine
        lda #>nom
        sta ControlPort+5
        lda #<copie
        sta ControlPort+6          ; P2-P3 : nom de la copie
        lda #>copie
        sta ControlPort+7
        lda #3
        ldx #20                    ; fonction 20 : Copy File
        jsr appel
        jsr WaitMessage
        lda #<copie
        sta ControlPort+4
        lda #>copie
        sta ControlPort+5
        lda #<relu
        sta ControlPort+6          ; P2-P3 : destination
        lda #>relu
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jsr appel
        lda #<m
        ldx #>m
        jsr ecrire
        lda #<relu
        ldx #>relu
        jsr ecrire
        lda #13
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

copie:  .byte 9
        .text "copie.txt"
relu:   .fill 9                    ; zéros : la chaîne relue sera terminée
m:      .text "Copie : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Copie : ABCDEFGH

3,21 Set file attributes Official

Changes the attributes of a file (read only, hidden, archive, system).

Inputs
BytesTypeMeaning
P0-P1addraddress of the name (length-prefixed)
P2uint8attributes, as in 3,16: bit 1 system, 2 archive, 3 read only, 4 hidden
Outputs
BytesTypeMeaning
erreuruint8non zero if the file does not exist

The "directory" bit (bit 0) cannot be changed. The example makes the file read only (8) and reads its attributes back with 3,16.

Firmware documentation text

Sets the attributes for a file. On input:

Parameters:0,1 points to the length-prefixed filename; Parameter:2 is the attribute bitfield. (See Stat File for details.)

The directory bit cannot be changed. Obviously.

C (llvm-mos)
/* Mettre un fichier en lecture seule (groupe 3, fonction 21). */
#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 const uint8_t nom[] = "\x07" "abc.txt";

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_set_attr("abc.txt", NEO_FILE_ATTR_READ_ONLY);  /* Set file attributes */
    libre();
    ControlPort.params[0] = (uint16_t)nom & 0xFF;
    ControlPort.params[1] = (uint16_t)nom >> 8;
    api(3, 16);                                 /* 3,16 : attributs en P4 */
    printf("Lecture seule : %u\n", ControlPort.params[4] & NEO_FILE_ATTR_READ_ONLY);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lecture seule : 8
Mad Pascal
// Mettre un fichier en lecture seule (groupe 3, fonction 21).
program attributs;
uses crt, neo6502;
var texte, nom: string[16];
    taille: cardinal;
    attr: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  attr := FI_ATTR_READONLY;
  NeoSetAttr(@nom, attr);                       // Set file attributes
  NeoStatFile(@nom, taille, attr);              // 3,16
  writeln('Lecture seule : ', attr and FI_ATTR_READONLY);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lecture seule : 8
NeoBASIC
10 ' Mettre un fichier en lecture seule (groupe 3, fonction 21)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 while peek($ff00) : wend
40 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff06, 8 : poke $ff01, 21 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3
70 while peek($ff00) : wend : r = peek($ff08) & 8
80 print "Lecture seule : ";r
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lecture seule : 8
65C02 assembly (64tass)
; Mettre un fichier en lecture seule (groupe 3, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : nom
        lda #>nom
        sta ControlPort+5
        lda #8
        sta ControlPort+6          ; P2 : lecture seule
        lda #3
        ldx #21                    ; fonction 21 : Set file attributes
        jsr appel
        lda #<nom
        ldx #>nom
        ldy #16                    ; 3,16 : attributs en P4
        jsr sur_nom
        lda ControlPort+8
        and #8
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

m:      .text "Lecture seule : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lecture seule : 8

3,22 Check End of File. Official

Tells whether an open channel has reached the end of its file.

Inputs
BytesTypeMeaning
P0uint8channel number
Outputs
BytesTypeMeaning
P0uint8non zero at end of file

On a closed channel, the call may flag an error. In NeoBASIC, eof(n) makes the same call.

NeoBASIC keywords that make this call: eof()

Firmware documentation text

Returns the end of file status of an opened file. On input:

Parameter:0 contains the file channel to operate on.

On output: Parameter:0 is non-zero if the file is at the end of the file.

This call should be used on open files and may return an error if the file is closed.

C (llvm-mos)
/* Lire octet par octet jusqu'à la fin du fichier (groupe 3, fonction 22). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char c;
    unsigned n = 0;
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    while (!neo_file_eof(1)) {                  /* Check End of File */
        neo_file_read(1, &c, 1);
        n++;
    }
    neo_file_close(1);
    printf("%u octets lus avant la fin du fichier\n", n);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
8 octets lus avant la fin du fichier
Mad Pascal
// Lire octet par octet jusqu'à la fin du fichier (groupe 3, fonction 22).
program fin;
uses crt, neo6502;
var texte, nom: string[16];
    c: byte;
    n: word;

function fin_de_fichier(canal: byte): boolean;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := canal;
  NeoSendMessage(3, 22);                        // Check End of File
  NeoWaitMessage;
  result := NeoMessage.params[0] <> 0;
end;

begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  n := 0;
  while not fin_de_fichier(1) do
  begin
    NeoReadFile(1, word(@c), 1);
    inc(n);
  end;
  NeoCloseFile(1);
  writeln(n, ' octets lus avant la fin du fichier');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
8 octets lus avant la fin du fichier
NeoBASIC
10 ' Lire octet par octet jusqu'a la fin du fichier (groupe 3, fonction 22)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = alloc(4) : m = 0 : while peek($ff00) : wend : poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, m : poke $ff01, 4 : poke $ff00, 3 : while peek($ff00) : wend
40 n = 0
50 while eof(1) = 0
60 poke $ff04, 1 : poke $ff05, b & 255 : poke $ff06, b >> 8 : poke $ff07, 1 : poke $ff08, 0 : poke $ff01, 8 : poke $ff00, 3
70 while peek($ff00) : wend
80 n = n + 1
90 wend
100 close
110 print n;" octets lus avant la fin du fichier"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
8 octets lus avant la fin du fichier
65C02 assembly (64tass)
; Lire octet par octet jusqu'à la fin du fichier (groupe 3, fonction 22).
        .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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #0
        jsr ouvrir
_suiv:  jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #3
        ldx #22                    ; fonction 22 : Check End of File
        jsr appel
        lda ControlPort+4          ; non nul : fin
        bne _fin
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #<octet
        sta ControlPort+5
        lda #>octet
        sta ControlPort+6
        lda #1
        sta ControlPort+7
        stz ControlPort+8
        lda #3
        ldx #8                     ; lire un octet
        jsr appel
        inc compte
        bra _suiv
_fin:   jsr fermer
        lda compte
        jsr decimal
        lda #<m
        ldx #>m
        jmp ecrire
; Ouvrir abc.txt sur le canal 1 dans le mode A.
ouvrir: pha
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5          ; P1-P2 : nom
        lda #>nom
        sta ControlPort+6
        pla
        sta ControlPort+7          ; P3 : mode
        lda #3
        ldx #4                     ; 3,4 : File Open
        jmp appel

; Fermer le canal 1.
fermer: jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

octet:  .byte 0
compte: .byte 0
m:      .text " octets lus avant la fin du fichier", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
8 octets lus avant la fin du fichier

3,23 Get Current Working Directory. Changed by Trinity

Copies the path of the current working directory into a buffer.

Inputs
BytesTypeMeaning
P0-P1addraddress of the buffer
P2uint8maximum length of the path
Outputs
BytesTypeMeaning
tamponstringpath (length-prefixed)

The path comes back length-prefixed, followed by a zero on Trinity (observed). llvm-mos neo_file_get_cwd returns this buffer as is: the first byte is the length, the text starts at the second. The C example takes this into account.

Difference in Trinity — Trinity bounds the copy to the length given in P2 (T-61).

Firmware documentation text

Copies the current working directory into the String at address Parameters:0,1. which is of maximum length Parameters:2

C (llvm-mos)
/* Afficher le répertoire courant (groupe 3, fonction 23). */
#include <stdio.h>
#include <neo/api.h>

static char cwd[33];

static const char *courant(void) {
    neo_file_get_cwd(cwd, 32);                  /* 3,23 : chaîne précédée de sa longueur */
    cwd[(uint8_t)cwd[0] + 1] = 0;
    return cwd + 1;
}

int main(void) {
    printf("Repertoire courant : %s\n", courant());   /* Get Current Working Directory */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /
Mad Pascal
// Afficher le répertoire courant (groupe 3, fonction 23).
program cwd;
uses crt, neo6502;

function courant: string;
var cwd: string[32];
begin
  NeoWaitMessage;
  wordParams[0] := word(@cwd);                  // P0-P1 : tampon
  NeoMessage.params[2] := 32;                   // P2 : longueur maximale
  NeoSendMessage(3, 23);                        // 3,23 : Get Current Working Directory
  NeoWaitMessage;
  result := cwd;
end;

begin
  writeln('Repertoire courant : ', courant);   // Get Current Working Directory
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /
NeoBASIC
10 ' Afficher le repertoire courant (groupe 3, fonction 23)
20 while peek($ff00) : wend
30 b = alloc(34) : poke $ff04, b & 255 : poke $ff05, b >> 8 : poke $ff06, 32 : poke $ff01, 23 : poke $ff00, 3
40 while peek($ff00) : wend : s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
50 print "Repertoire courant : ";s$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /
65C02 assembly (64tass)
; Afficher le répertoire courant (groupe 3, 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 courant                ; fonction 23 : Get Current Working Directory
        lda #<m
        ldx #>m
        jsr ecrire
        lda #<cwd
        ldx #>cwd
        jsr pecrire
        lda #13
        jmp WriteCharacter

; Répertoire courant dans cwd (précédé de sa longueur).
courant:
        jsr WaitMessage
        lda #<cwd
        sta ControlPort+4          ; P0-P1 : tampon
        lda #>cwd
        sta ControlPort+5
        lda #32
        sta ControlPort+6          ; P2 : longueur maximale
        lda #3
        ldx #23                    ; 3,23 : Get Current Working Directory
        jmp appel
cwd:    .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .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

m:      .text "Repertoire courant : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Repertoire courant : /

3,24 Volume Info Trinity

Gives the name and state of a storage volume (USB key, SD card, host folder).

Inputs
BytesTypeMeaning
P0uint8volume number (0 to 3)
P1-P2addraddress of the name buffer; its first byte gives its capacity
Outputs
BytesTypeMeaning
tamponstringvolume name (length-prefixed)
P3uint8attributes: bit 0 present, bit 1 read only, bit 2 network
erreuruint8non zero (invalid drive) if no volume has this number

To enumerate volumes, call the function for 0 to 3. In the paths of the group, the "n:" prefix refers to volume n ("1:/games/tetris.neo"). The name depends on the medium: the example prints it as is (the bench emulator has a single volume).

Firmware documentation text

Retrieves information about a storage volume (Trinity T-18, F-102 of the fork). On input:

Parameter:0 is the volume number (0-3); Parameters:1,2 points to a length-prefixed buffer for returning the volume name.

On output, the buffer contains the length-prefixed volume name (e.g. "USB1", "SD0", "HOST") and Parameter:3 contains the volume attributes: bit 0 present, bit 1 read only, bit 2 network.

An error (Invalid Drive) is flagged if no volume with that number is mounted. Volumes are addressed in any path of this group by the prefix "n:" (e.g. "1:/games/tetris.neo"); a path without prefix refers to the current volume. Enumerate volumes by calling this function for 0 to 3.

C (llvm-mos)
/* Énumérer les volumes présents (groupe 3, fonction 24, 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)
        ;
}

static uint8_t nom[17];

int main(void) {
    for (uint8_t v = 0; v < 4; v++) {
        libre();
        nom[0] = 15;                            /* capacité */
        ControlPort.params[0] = v;              /* P0 : volume */
        ControlPort.params[1] = (uint16_t)nom & 0xFF;
        ControlPort.params[2] = (uint16_t)nom >> 8;
        api(3, 24);                             /* Volume Info */
        if (ControlPort.error)                  /* pas de volume n° v */
            continue;
        nom[nom[0] + 1] = 0;
        printf("Volume %u : %s\n", v, (char *)nom + 1);
    }
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 : HOST0
Mad Pascal
// Énumérer les volumes présents (groupe 3, fonction 24, Trinity).
program volumes;
uses crt, neo6502;
var nom: string[15];
    v: byte;
begin
  for v := 0 to 3 do
  begin
    nom[0] := chr(15);                          // capacité
    NeoWaitMessage;
    NeoMessage.params[0] := v;                  // P0 : volume
    wordxParams[0] := word(@nom);               // P1-P2 : tampon
    NeoSendMessage(3, 24);                      // Volume Info
    NeoWaitMessage;
    if NeoMessage.error = 0 then
      writeln('Volume ', v, ' : ', nom);
  end;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 : HOST0
NeoBASIC
10 ' Enumerer les volumes presents (groupe 3, fonction 24, Trinity)
20 b = alloc(18)
30 for v = 0 to 3
40 poke b, 15 : while peek($ff00) : wend
50 poke $ff04, v : poke $ff05, b & 255 : poke $ff06, b >> 8 : poke $ff01, 24 : poke $ff00, 3
60 while peek($ff00) : wend : e = peek($ff02)
70 if e = 0
80 s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
90 print "Volume ";v;" : ";s$
100 endif
110 next v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 : HOST0
65C02 assembly (64tass)
; Énumérer les volumes présents (groupe 3, fonction 24, 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:  stz vol
_suiv:  lda #15
        sta vnom                   ; capacité
        jsr WaitMessage
        lda vol
        sta ControlPort+4          ; P0 : volume
        lda #<vnom
        sta ControlPort+5          ; P1-P2 : tampon
        lda #>vnom
        sta ControlPort+6
        lda #3
        ldx #24                    ; fonction 24 : Volume Info
        jsr appel
        lda ControlPort+2
        bne _autre                 ; pas de volume de ce numéro
        lda #<m
        ldx #>m
        jsr ecrire
        lda vol
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda #<vnom
        ldx #>vnom
        jsr pecrire
        lda #13
        jsr WriteCharacter
_autre: inc vol
        lda vol
        cmp #4
        bne _suiv
        rts

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .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

vol:    .byte 0
vnom:   .fill 17
m:      .text "Volume ", 0
m2:     .text " : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 : HOST0

3,25 Select Volume Trinity

Makes a volume the current one: paths without an "n:" prefix then refer to it.

Inputs
BytesTypeMeaning
P0uint8volume number (0 to 3)
Outputs
BytesTypeMeaning
erreuruint8non zero if the volume is not mounted

Each volume keeps its own current directory. The example selects volume 0, the only one present in the bench emulator, and reads it back with 3,26.

Firmware documentation text

Makes a volume the current one (Trinity T-18, F-102 of the fork), like Function 3,15 "Change Directory" for directories: paths without a "n:" prefix then refer to it. On input:

Parameter:0 is the volume number (0-3).

An error is flagged if the volume is not mounted. Each volume keeps its own current directory.

C (llvm-mos)
/* Choisir le volume 0 (groupe 3, fonction 25, 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)
        ;
}

static uint8_t volume_courant(void) {
    libre();
    api(3, 26);                                 /* 3,26 : Get Current Volume */
    return ControlPort.params[0];
}

int main(void) {
    libre();
    ControlPort.params[0] = 0;                  /* P0 : volume */
    api(3, 25);                                 /* Select Volume */
    uint8_t e = ControlPort.error;
    printf("Volume 0 choisi, erreur %u, volume courant : %u\n", e, volume_courant());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 choisi, erreur 0, volume courant : 0
Mad Pascal
// Choisir le volume 0 (groupe 3, fonction 25, Trinity).
program choisir;
uses crt, neo6502;
var e, v: byte;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 0;                    // P0 : volume
  NeoSendMessage(3, 25);                        // Select Volume
  NeoWaitMessage;
  e := NeoMessage.error;
  NeoSendMessage(3, 26);                        // 3,26 : Get Current Volume
  NeoWaitMessage;
  v := NeoMessage.params[0];
  writeln('Volume 0 choisi, erreur ', e, ', volume courant : ', v);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 choisi, erreur 0, volume courant : 0
NeoBASIC
10 ' Choisir le volume 0 (groupe 3, fonction 25, Trinity)
20 while peek($ff00) : wend
30 poke $ff04, 0 : poke $ff01, 25 : poke $ff00, 3
40 while peek($ff00) : wend : e = peek($ff02)
50 poke $ff01, 26 : poke $ff00, 3
60 while peek($ff00) : wend : v = peek($ff04)
70 print "Volume 0 choisi, erreur ";e;", volume courant : ";v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 choisi, erreur 0, volume courant : 0
65C02 assembly (64tass)
; Choisir le volume 0 (groupe 3, fonction 25, 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
        stz ControlPort+4          ; P0 : volume 0
        lda #3
        ldx #25                    ; fonction 25 : Select Volume
        jsr appel
        lda ControlPort+2
        sta err
        lda #3
        ldx #26                    ; 3,26 : Get Current Volume
        jsr appel
        lda ControlPort+4
        sta vol
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda err
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda vol
        jsr decimal
        lda #13
        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

err:    .byte 0
vol:    .byte 0
m1:     .text "Volume 0 choisi, erreur ", 0
m2:     .text ", volume courant : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume 0 choisi, erreur 0, volume courant : 0

3,26 Get Current Volume Trinity

Gives the number of the current volume.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8current volume number (0 to 3)
Firmware documentation text

Returns the current volume number in Parameter:0 (Trinity T-18, F-102 of the fork).

C (llvm-mos)
/* Numéro du volume courant (groupe 3, fonction 26, 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(3, 26);                                 /* Get Current Volume */
    printf("Volume courant : %u\n", ControlPort.params[0]);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume courant : 0
Mad Pascal
// Numéro du volume courant (groupe 3, fonction 26, Trinity).
program volume;
uses crt, neo6502;
var v: byte;
begin
  NeoWaitMessage;
  NeoSendMessage(3, 26);                        // Get Current Volume
  NeoWaitMessage;
  v := NeoMessage.params[0];
  writeln('Volume courant : ', v);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume courant : 0
NeoBASIC
10 ' Numero du volume courant (groupe 3, fonction 26, Trinity)
20 while peek($ff00) : wend
30 poke $ff01, 26 : poke $ff00, 3
40 while peek($ff00) : wend : v = peek($ff04)
50 print "Volume courant : ";v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume courant : 0
65C02 assembly (64tass)
; Numéro du volume courant (groupe 3, fonction 26, 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 #3
        ldx #26                    ; fonction 26 : Get Current Volume
        jsr appel
        lda ControlPort+4          ; P0 : volume
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        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

m:      .text "Volume courant : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Volume courant : 0

3,27 File Read Paged Trinity

Reads an open file straight into a memory page addressed by the blitter (6502, video or graphics memory), without going through 6502 memory.

Inputs
BytesTypeMeaning
P0uint8channel number
P1uint8page: $00 6502 memory, $80 and $81 video memory, $90 graphics memory (as 12,2)
P2-P3addraddress within the page
P4-P5uint16number of bytes requested
Outputs
BytesTypeMeaning
P4-P5uint16number of bytes actually read

The range must fit in the page (otherwise: invalid parameter); no crossing from $80 to $81 in one call. Bank pages $A0-$BF are refused. A 320×240 frame is read as 65536 bytes into page $80 then 11264 into page $81. The example reads into page $00 so that the result can be printed.

Firmware documentation text

Reads data from an opened file directly into any memory the blitter can address (Trinity T-18, F-16 of the fork), avoiding a copy through 6502 RAM and Function 12,2. On input:

Parameter:0 contains the file channel to operate on. Parameter:1 is the memory page : $00 6502 RAM, $80 and $81 video RAM (line 205 onwards is in page $81), $90 graphics RAM — the same pages as Function 12,2. The bank pages $A0-$BF are refused (Invalid Parameter) : banks live in flash and are written by Function 1,22 only. Parameters:2,3 is the 16 bit address within that page. Parameters:4,5 contains the amount of data to read.

On output Parameters:4,5 is updated to contain the amount of data actually read. Data is read from the current seek position, which is advanced after the read.

The whole range must fit in the page : an Invalid Parameter error is flagged if it does not (no wrap-around, no crossing from $80 to $81 : use two calls). A full 320x240 frame is read with 65536 bytes into page $80 then 11264 bytes into page $81.

C (llvm-mos)
/* Lire un fichier par 3,27 en page $00 (groupe 3, 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)
        ;
}

static char tampon[9];

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    libre();
    ControlPort.params[0] = 1;                  /* P0 : canal */
    ControlPort.params[1] = 0x00;               /* P1 : page $00, mémoire du 6502 */
    ControlPort.params[2] = (uint16_t)tampon & 0xFF;   /* P2-P3 : adresse */
    ControlPort.params[3] = (uint16_t)tampon >> 8;
    ControlPort.params[4] = 8;                  /* P4-P5 : 8 octets */
    ControlPort.params[5] = 0;
    api(3, 27);                                 /* File Read Paged */
    uint8_t n = ControlPort.params[4];
    neo_file_close(1);
    printf("Lu par 3,27 : %s (%u octets)\n", tampon, n);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu par 3,27 : ABCDEFGH (8 octets)
Mad Pascal
// Lire un fichier par 3,27 en page $00 (groupe 3, fonction 27, Trinity).
program pagine;
uses crt, neo6502;
var texte, nom, tampon: string[16];
    n: byte;
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  NeoWaitMessage;
  NeoMessage.params[0] := 1;                    // P0 : canal
  NeoMessage.params[1] := $00;                  // P1 : page $00, mémoire du 6502
  wordParams[1] := word(@tampon) + 1;           // P2-P3 : adresse
  wordParams[2] := 8;                           // P4-P5 : 8 octets
  NeoSendMessage(3, 27);                        // File Read Paged
  NeoWaitMessage;
  n := NeoMessage.params[4];
  NeoCloseFile(1);
  tampon[0] := chr(n);
  writeln('Lu par 3,27 : ', tampon, ' (', n, ' octets)');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu par 3,27 : ABCDEFGH (8 octets)
NeoBASIC
10 ' Lire un fichier par 3,27 en page $00 (groupe 3, fonction 27, Trinity)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = alloc(16) : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, 0 : poke $ff01, 4 : poke $ff00, 3
50 while peek($ff00) : wend
60 poke $ff04, 1 : poke $ff05, 0 : poke $ff06, b & 255 : poke $ff07, b >> 8 : poke $ff08, 8 : poke $ff09, 0 : poke $ff01, 27 : poke $ff00, 3
70 while peek($ff00) : wend : n = peek($ff08)
80 close
90 s$ = "" : for i = 0 to n - 1 : s$ = s$ + chr$(peek(b + i)) : next i
100 print "Lu par 3,27 : ";s$;" (";n;" octets)"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu par 3,27 : ABCDEFGH (8 octets)
65C02 assembly (64tass)
; Lire un fichier par 3,27 en page $00 (groupe 3, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5
        lda #>nom
        sta ControlPort+6
        stz ControlPort+7          ; lecture seule
        lda #3
        ldx #4                     ; 3,4 : File Open
        jsr appel
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        stz ControlPort+5          ; P1 : page $00, mémoire du 6502
        lda #<tampon
        sta ControlPort+6          ; P2-P3 : adresse
        lda #>tampon
        sta ControlPort+7
        lda #8
        sta ControlPort+8          ; P4-P5 : 8 octets
        stz ControlPort+9
        lda #3
        ldx #27                    ; fonction 27 : File Read Paged
        jsr appel
        lda ControlPort+8
        sta lus
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        jsr appel
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda #<tampon
        ldx #>tampon
        jsr ecrire
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda lus
        jsr decimal
        lda #<m3
        ldx #>m3
        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:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

tampon: .fill 9                    ; zéros : la chaîne lue sera terminée
lus:    .byte 0
m1:     .text "Lu par 3,27 : ", 0
m2:     .text " (", 0
m3:     .text " octets)", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu par 3,27 : ABCDEFGH (8 octets)

3,28 File Read Background Trinity

Reads an open file as 3,27 does, but returns at once: the 65C02 runs on during the read, whose progress is reported by three bytes of memory.

Inputs
BytesTypeMeaning
P0uint8channel number
P1uint8page: $00 6502 memory, $80 and $81 video memory, $90 graphics memory (as 3,27)
P2-P3addraddress within the page
P4-P5uint16number of bytes requested
P6-P7addraddress of the 3 progress bytes (6502 memory)
Outputs
BytesTypeMeaning
suivi+0uint8$01 during the read, then $80 + error code ($80: success)
suivi+1-2uint16number of bytes read
erreuruint8only if the progress bytes are inside the destination or past $FF00 (nothing is read); any other problem goes through the progress byte

Poll the progress byte and touch neither it nor the destination before its bit 7 is set. An API call made meanwhile is accepted but waits for the end of the read. On the board, the 65C02 runs during the USB key transfers (about 90% of the time of a read, measured); the emulators read at once, hence a read already over on the bench. The example asks for 16 bytes of an 8 byte file (state 128, 8 bytes read), then puts the progress bytes inside the destination: refused, error 21 (invalid parameter).

Firmware documentation text

Function 3,27 without stopping the 65C02 (Trinity T-82, ADR-0002) : Parameters:0 to 5 as Function 3,27 (channel, page, address, size), Parameters:6,7 the address of 3 bytes of 6502 RAM that report the read. The call returns at once with the first byte at $01 ; the program runs on while the firmware reads, and when the read is over the first byte becomes $80 plus the error code ($80 = success, $82 = end of file...) and the next two bytes hold the number of bytes read. Poll the first byte in RAM ; do not touch it, nor the destination, before its bit 7 is set. Any API call made meanwhile is accepted but waits until the read is over. The error flag is set only when the state bytes are inside the destination or past $FF00 (nothing is read then) ; every other outcome, bad parameters included, is reported by the state byte alone, the same on the board and in the emulators. On the board the 65C02 runs while the USB key transfers (about 90% of the time of a read, measured) ; the emulators perform the read at once.

C (llvm-mos)
/* Lire un fichier sans arrêter le 65C02 (groupe 3, fonction 28, 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)
        ;
}

static char tampon[17];
static volatile uint8_t etat[3];                /* état, puis nombre d'octets lus (écrits par le firmware) */

static uint8_t lire(uint16_t cible, uint16_t suivi) {   /* 3,28 : 16 octets du canal 1 en cible ; erreur rendue */
    libre();
    ControlPort.params[0] = 1;                  /* P0 : canal */
    ControlPort.params[1] = 0x00;               /* P1 : page $00, mémoire du 6502 */
    ControlPort.params[2] = cible & 0xFF;       /* P2-P3 : adresse */
    ControlPort.params[3] = cible >> 8;
    ControlPort.params[4] = 16;                 /* P4-P5 : 16 octets demandés */
    ControlPort.params[5] = 0;
    ControlPort.params[6] = suivi & 0xFF;       /* P6-P7 : les 3 octets d'état */
    ControlPort.params[7] = suivi >> 8;
    api(3, 28);                                 /* File Read Background : rend la main tout de suite */
    return ControlPort.error;
}

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_open(1, "abc.txt", NEO_FILE_READ);
    lire((uint16_t)tampon, (uint16_t)etat);
    uint16_t tours = 0;
    while (!(etat[0] & 0x80))                   /* le programme continue pendant la lecture */
        tours++;
    printf("Lu : %s, etat %u, %u octets\n", tampon, etat[0], etat[1] | etat[2] << 8);
    printf("Suivi dans la cible : erreur %u\n", lire((uint16_t)tampon, (uint16_t)tampon + 4));
    neo_file_close(1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 21
Mad Pascal
// Lire un fichier sans arrêter le 65C02 (groupe 3, fonction 28, Trinity).
program fond;
uses crt, neo6502;
var texte, nom, tampon: string[16];
    etat: array[0..2] of byte;                  // état, puis nombre d'octets lus (écrits par le firmware)
    e: byte;
    tours: word;

function lire(cible, suivi: word): byte;        // 3,28 : 16 octets du canal 1 en cible ; erreur rendue
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 1;                    // P0 : canal
  NeoMessage.params[1] := $00;                  // P1 : page $00, mémoire du 6502
  wordParams[1] := cible;                       // P2-P3 : adresse
  wordParams[2] := 16;                          // P4-P5 : 16 octets demandés
  wordParams[3] := suivi;                       // P6-P7 : les 3 octets d'état
  NeoSendMessage(3, 28);                        // File Read Background : rend la main tout de suite
  NeoWaitMessage;
  result := NeoMessage.error;
end;

begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoOpenFile(1, @nom, 0);
  lire(word(@tampon) + 1, word(@etat));
  tours := 0;
  while etat[0] and $80 = 0 do inc(tours);      // le programme continue pendant la lecture
  tampon[0] := chr(etat[1]);
  writeln('Lu : ', tampon, ', etat ', etat[0], ', ', etat[1] + etat[2] shl 8, ' octets');
  e := lire(word(@tampon) + 1, word(@tampon) + 5);
  writeln('Suivi dans la cible : erreur ', e);
  NeoCloseFile(1);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 21
NeoBASIC
10 ' Lire un fichier sans arreter le 65C02 (groupe 3, fonction 28, Trinity)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 b = alloc(16) : s = alloc(3) : while peek($ff00) : wend
40 poke $ff04, 1 : poke $ff05, a & 255 : poke $ff06, a >> 8 : poke $ff07, 0 : poke $ff01, 4 : poke $ff00, 3
50 c = b : gosub 1000 : ' lecture, suivi en s
60 repeat : until peek(s) & $80 : ' le programme continue pendant la lecture
70 e = peek(s) : n = peek(s + 1) : ' etat, octets lus
80 s$ = "" : for i = 0 to n - 1 : s$ = s$ + chr$(peek(b + i)) : next i
90 print "Lu : ";s$;", etat ";e;", ";n;" octets"
100 s = b + 4 : gosub 1000 : print "Suivi dans la cible : erreur ";r
110 close
120 end
1000 ' 3,28 : 16 octets du canal 1 en c, 3 octets d'etat en s ; erreur dans r
1010 while peek($ff00) : wend
1020 poke $ff04, 1 : poke $ff05, 0 : doke $ff06, c : doke $ff08, 16 : doke $ff0a, s
1030 poke $ff01, 28 : poke $ff00, 3 : ' File Read Background : rend la main tout de suite
1040 while peek($ff00) : wend : r = peek($ff02)
1050 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 21
65C02 assembly (64tass)
; Lire un fichier sans arrêter le 65C02 (groupe 3, fonction 28, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        lda #<nom
        sta ControlPort+5
        lda #>nom
        sta ControlPort+6
        stz ControlPort+7          ; lecture seule
        lda #3
        ldx #4                     ; 3,4 : File Open
        jsr appel
        lda #<etat                 ; suivi hors de la cible
        ldx #>etat
        jsr lire
_att:   bit etat                   ; le programme continue pendant la lecture...
        bpl _att                   ; ... jusqu'au bit 7 de l'état
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda #<tampon
        ldx #>tampon
        jsr ecrire                 ; la cible est à zéro au-delà des 8 octets lus
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda etat
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda etat+1                 ; octets lus (poids faible)
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda #<(tampon+4)           ; suivi dans la cible : refusé
        ldx #>(tampon+4)
        jsr lire
        lda ControlPort+2
        sta err
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda err
        jsr decimal
        lda #13
        jsr WriteCharacter
        jsr WaitMessage
        lda #1
        sta ControlPort+4
        lda #3
        ldx #5                     ; 3,5 : File Close
        jmp appel

; 3,28 : 16 octets du canal 1 dans tampon, les 3 octets d'état à l'adresse A (poids faible), X (poids fort).
lire:   pha
        jsr WaitMessage
        pla
        sta ControlPort+10         ; P6-P7 : les 3 octets d'état
        stx ControlPort+11
        lda #1
        sta ControlPort+4          ; P0 : canal 1
        stz ControlPort+5          ; P1 : page $00, mémoire du 6502
        lda #<tampon
        sta ControlPort+6          ; P2-P3 : adresse
        lda #>tampon
        sta ControlPort+7
        lda #16
        sta ControlPort+8          ; P4-P5 : 16 octets demandés
        stz ControlPort+9
        lda #3
        ldx #28                    ; 3,28 : File Read Background, rend la main tout de suite
        jmp appel

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"
tampon: .fill 17                   ; zéros : la chaîne lue sera terminée
etat:   .fill 3                    ; état, puis nombre d'octets lus (écrits par le firmware)
err:    .byte 0
t0:     .text "Lu : ", 0
t1:     .text ", etat ", 0
t2:     .text ", ", 0
t3:     .text " octets", 13, 0
t4:     .text "Suivi dans la cible : erreur ", 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 21

3,29 Last Entry Date Time Trinity

Gives the date and time of the last entry read by 3,16 (File Stat) or 3,18 (Read Directory), in FAT format.

Inputs: none.

Outputs
BytesTypeMeaning
P0-P1uint16date: bits 15-9 year - 1980, 8-5 month, 4-0 day; 0 if unknown
P2-P3uint16time: bits 15-11 hour, 10-5 minutes, 4-0 seconds / 2; 0 if unknown
erreuruint81 if no entry has been read yet

P0-P3 are written in every case, error included: NeoDOS uses this to tell this firmware from an older one, which leaves them untouched (this is how DIR shows dates). In the emulators, the date is the modification time of the file on the host computer, in local time: the observed output is therefore the date of the bench run, and the checked pattern only covers the format. Seconds are even (2 s FAT precision).

Firmware documentation text

Returns the date and time of the last entry read by Function 3,16 File Stat or 3,18 Read Directory, in the FAT format (Trinity T-91) : Parameters:0,1 the date (bits 15-9 year - 1980, 8-5 month, 4-0 day), Parameters:2,3 the time (bits 15-11 hour, 10-5 minutes, 4-0 seconds / 2) ; both 0 when the date is unknown. Sets the error flag if no entry has been read yet. Parameters:0-3 are written in every case, error included (NeoDOS relies on it to tell this function from an older firmware that leaves them untouched). On the emulators the date is the host file's modification time, in local time.

C (llvm-mos)
/* Lire la date d'un fichier (groupe 3, fonction 29, 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)
        ;
}

static const uint8_t nom[] = "\x07" "abc.txt";   /* chaîne à longueur */

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    libre();
    ControlPort.params[0] = (uint16_t)nom & 0xFF;   /* P0-P1 : nom */
    ControlPort.params[1] = (uint16_t)nom >> 8;
    api(3, 16);                                 /* File Stat : l'entrée dont on veut la date */
    api(3, 29);                                 /* Last Entry Date Time */
    uint16_t d = ControlPort.params[0] | ControlPort.params[1] << 8;   /* date FAT */
    uint16_t h = ControlPort.params[2] | ControlPort.params[3] << 8;   /* heure FAT */
    printf("abc.txt : %u-%02u-%02u %02u:%02u:%02u\n",
           1980 + (d >> 9), (d >> 5) & 15, d & 31,  /* année - 1980, mois, jour */
           h >> 11, (h >> 5) & 63, (h & 31) * 2);   /* heure, minutes, secondes / 2 */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 2026-10-03 15:19:38
Mad Pascal
// Lire la date d'un fichier (groupe 3, fonction 29, Trinity).
program datefichier;
uses crt, neo6502;
var texte, nom: string[16];
    taille: cardinal;
    attr: byte;
    d, h: word;

procedure deux(n: word);                        // deux chiffres
begin
  if n < 10 then write('0');
  write(n);
end;

begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  nom := 'abc.txt';
  NeoStatFile(@nom, taille, attr);              // 3,16 : l'entrée dont on veut la date
  NeoSendMessage(3, 29);                        // Last Entry Date Time
  NeoWaitMessage;
  d := wordParams[0];                           // date FAT
  h := wordParams[1];                           // heure FAT
  write('abc.txt : ', 1980 + d shr 9, '-');     // année - 1980
  deux((d shr 5) and 15); write('-');           // mois
  deux(d and 31); write(' ');                   // jour
  deux(h shr 11); write(':');                   // heure
  deux((h shr 5) and 63); write(':');           // minutes
  deux((h and 31) * 2);                         // secondes / 2
  writeln;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 2026-10-03 15:19:36
NeoBASIC
10 ' Lire la date d'un fichier (groupe 3, fonction 29, Trinity)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 while peek($ff00) : wend
40 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 16 : poke $ff00, 3 : ' 3,16 : l'entree dont on veut la date
50 while peek($ff00) : wend
60 poke $ff01, 29 : poke $ff00, 3 : ' Last Entry Date Time
70 while peek($ff00) : wend : d = deek($ff04) : h = deek($ff06) : ' date et heure FAT, lues avant tout calcul
80 print "abc.txt : ";1980 + (d >> 9);"-";
90 n = (d >> 5) & 15 : gosub 1000 : print "-"; : n = d & 31 : gosub 1000 : print " ";
100 n = h >> 11 : gosub 1000 : print ":"; : n = (h >> 5) & 63 : gosub 1000 : print ":"; : n = (h & 31) * 2 : gosub 1000
110 print
120 end
1000 ' n sur deux chiffres
1010 if n < 10 then print "0";
1020 print n;
1030 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 2026-10-03 15:19:38
65C02 assembly (64tass)
; Lire la date d'un fichier (groupe 3, fonction 29, 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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage
        lda #<nom
        sta ControlPort+4          ; P0-P1 : nom
        lda #>nom
        sta ControlPort+5
        lda #3
        ldx #16                    ; 3,16 : File Stat, l'entrée dont on veut la date
        jsr appel
        lda #3
        ldx #29                    ; 3,29 : Last Entry Date Time
        jsr appel
        ldx #3                     ; copier date et heure avant tout affichage
_cp:    lda ControlPort+4,x
        sta date,x
        dex
        bpl _cp
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda date+1                 ; année - 1980 : bits 15-9
        lsr a
        clc
        adc #80                    ; 1980 + a = 1900 + (a + 80)
        cmp #100
        bcs _2000
        pha
        lda #19
        bra _siecle
_2000:  sbc #100
        pha
        lda #20
_siecle:
        jsr deux
        pla
        jsr deux
        lda #'-'
        jsr WriteCharacter
        lda date+1                 ; mois : bits 8-5
        lsr a
        lda date
        ror a
        lsr a
        lsr a
        lsr a
        lsr a
        jsr deux
        lda #'-'
        jsr WriteCharacter
        lda date                   ; jour : bits 4-0
        and #31
        jsr deux
        lda #' '
        jsr WriteCharacter
        lda heure+1                ; heure : bits 15-11
        lsr a
        lsr a
        lsr a
        jsr deux
        lda #':'
        jsr WriteCharacter
        lda heure+1                ; minutes : bits 10-5
        and #7
        sta tmp
        lda heure
        lsr tmp
        ror a
        lsr tmp
        ror a
        lsr tmp
        ror a
        lsr a
        lsr a
        jsr deux
        lda #':'
        jsr WriteCharacter
        lda heure                  ; secondes / 2 : bits 4-0
        and #31
        asl a
        jsr deux
        lda #13
        jmp WriteCharacter

; Affiche A (0-99) sur deux chiffres.
deux:   cmp #10
        bcs _d
        pha
        lda #'0'
        jsr WriteCharacter
        pla
_d:     jmp decimal

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"
date:   .word 0                    ; date FAT
heure:  .word 0                    ; heure FAT
tmp:    .byte 0
t0:     .text "abc.txt : ", 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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt : 2026-10-03 15:19:36

3,32 List Filtered Official

Prints the list of files in the current directory whose name contains a given text.

Inputs
BytesTypeMeaning
P0-P1addraddress of the search text (length-prefixed)

Outputs: none.

Substring search, no wildcards. In NeoBASIC, cat "text" makes the same call (cat alone makes 3,1).

Firmware documentation text

Prints a filtered file listing of the current directory to the console. On input:

Parameters:0,1 points to the filename search string.

Files will only be shown if the name contains the search string (ie: a substring match).

C (llvm-mos)
/* Lister les fichiers dont le nom contient « abc » (groupe 3, fonction 32). */
#include <neo/api.h>

int main(void) {
    neo_file_store("abc.txt", "ABCDEFGH", 8);  /* 3,3 : le fichier de l'exemple */
    neo_file_store("xyz.txt", "XYZ", 3);        /* un fichier qui ne sera pas listé */
    neo_file_list_filtered("abc");              /* List Filtered */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt                         8 bytes.
Mad Pascal
// Lister les fichiers dont le nom contient « abc » (groupe 3, fonction 32).
program filtre;
uses crt, neo6502;
var texte, filtre: string[16];
begin
  texte := 'ABCDEFGH';
  NeoSave('abc.txt', word(@texte) + 1, 8);      // 3,3 : le fichier de l'exemple
  NeoSave('xyz.txt', word(@texte) + 1, 3);      // un fichier qui ne sera pas listé
  filtre := 'abc';
  NeoSearchDir(filtre);                         // List Filtered
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt                         8 bytes.
NeoBASIC
10 ' Lister les fichiers dont le nom contient abc (groupe 3, fonction 32)
20 d = alloc(16) : for i = 1 to 8 : poke d + i - 1, 64 + i : next i : save "abc.txt", d, 8 : ' le fichier : ABCDEFGH
25 n$ = "abc.txt" : a = alloc(16) : poke a, len(n$) : for i = 1 to len(n$) : poke a + i, asc(mid$(n$, i, 1)) : next i
30 save "xyz.txt", d, 3 : ' un fichier qui ne sera pas liste
40 cat "abc"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt                         8 bytes.
65C02 assembly (64tass)
; Lister les fichiers dont le nom contient « abc » (groupe 3, fonction 32).
        .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            ; 3,3 : le fichier de l'exemple, ABCDEFGH
        lda #<nom
        sta ControlPort+4
        lda #>nom
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #8
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        jsr WaitMessage            ; un fichier qui ne sera pas listé
        lda #<xyz
        sta ControlPort+4
        lda #>xyz
        sta ControlPort+5
        lda #<abc
        sta ControlPort+6
        lda #>abc
        sta ControlPort+7
        lda #3
        sta ControlPort+8
        stz ControlPort+9
        lda #3
        ldx #3
        jsr appel
        lda #<filtre
        ldx #>filtre
        ldy #32                    ; fonction 32 : List Filtered
        jmp sur_nom

; Appel du groupe 3, fonction Y, avec en P0-P1 l'adresse du nom donnée par A (poids faible) et X.
sur_nom:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4
        stx ControlPort+5
        tya
        tax
        lda #3
        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

nom:    .byte 7
        .text "abc.txt"
abc:    .text "ABCDEFGH"

xyz:    .byte 7
        .text "xyz.txt"
filtre: .byte 3
        .text "abc"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abc.txt                         8 bytes.

← The Neo6502 API