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;
}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.PROG.NEO 132 bytes.NeoBASIC
10 ' Lister le repertoire courant (groupe 3, fonction 1)
20 catprog.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 0PROG.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).
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the file name (length-prefixed) |
P2-P3 | addr | destination address, or $FFFF for graphics memory |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | 0 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;
}Charge : BonjourMad 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.Charge : BonjourNeoBASIC
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 ";eCharge : Bonjour65C02 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 : ", 0Charge : Bonjour3,3 Store File Official
Saves an area of memory to a file (created or replaced).
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the file name (length-prefixed) |
P2-P3 | addr | address of the data |
P4-P5 | uint16 | number of bytes |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | 0 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;
}salut.txt : 7 octetsMad 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.salut.txt : 7 octetsNeoBASIC
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"salut.txt : 7 octets65C02 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, 0salut.txt : 7 octets3,4 File Open Official
Opens a file on a channel, for reading, writing, or both.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1-P2 | addr | address of the name (length-prefixed) |
P3 | uint8 | mode: 0 read only, 1 write only, 2 read-write, 3 create (or truncate) then read-write |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Ecrit : 7 octetsMad 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.Ecrit : 7 octetsNeoBASIC
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"Ecrit : 7 octets65C02 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, 0Ecrit : 7 octets3,5 File Close Official
Closes a channel; $FF closes every open channel.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel 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;
}Canal 1 ferme, erreur 0Mad 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.Canal 1 ferme, erreur 0NeoBASIC
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 ";eCanal 1 ferme, erreur 065C02 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 ", 0Canal 1 ferme, erreur 03,6 File Seek Official
Moves the read and write position of a channel to the chosen byte.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1-P4 | uint32 | position (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;
}Octet a la position 4 : EMad 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.Octet a la position 4 : ENeoBASIC
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))Octet a la position 4 : E65C02 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 : ", 0Octet a la position 4 : E3,7 File Tell Official
Gives the read and write position of a channel.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
| Bytes | Type | Meaning |
|---|---|---|
P1-P4 | uint32 | position |
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;
}Position apres 3 octets lus : 3Mad 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.Position apres 3 octets lus : 3NeoBASIC
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 : ";pPosition apres 3 octets lus : 365C02 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 : ", 0Position apres 3 octets lus : 33,8 File Read Official
Reads bytes from an open channel, from its position, into memory (or graphics memory with address $FFFF).
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1-P2 | addr | destination, or $FFFF for graphics memory |
P3-P4 | uint16 | number of bytes requested |
| Bytes | Type | Meaning |
|---|---|---|
P3-P4 | uint16 | number 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;
}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.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)"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, 0Lu : ABCDEFGH (8 octets sur 20 demandes)3,9 File Write Official
Writes bytes from memory into an open channel, from its position.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1-P2 | addr | address of the data |
P3-P4 | uint16 | number of bytes |
| Bytes | Type | Meaning |
|---|---|---|
P3-P4 | uint16 | number 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;
}Ecrits : 5, taille du fichier : 5Mad 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.Ecrits : 5, taille du fichier : 5NeoBASIC
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 : ";tEcrits : 5, taille du fichier : 565C02 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 : ", 0Ecrits : 5, taille du fichier : 53,10 File Size Official
Gives the current size of an open file, including writes still buffered.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
| Bytes | Type | Meaning |
|---|---|---|
P1-P4 | uint32 | size 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;
}Taille du fichier ouvert : 8Mad 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.Taille du fichier ouvert : 8NeoBASIC
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 : ";tTaille du fichier ouvert : 865C02 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 : ", 0Taille du fichier ouvert : 83,11 File Set Size Official
Extends or truncates an open file to the chosen size.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1-P4 | uint32 | new 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;
}Taille apres troncature : 3Mad 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.Taille apres troncature : 3NeoBASIC
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 : ";tTaille apres troncature : 365C02 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 : ", 0Taille apres troncature : 33,12 File Rename Official
Renames a file, possibly moving it to another directory.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the old name (length-prefixed) |
P2-P3 | addr | address of the new name (length-prefixed) |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Renomme : abc.txt -> xyz.txt, erreur 0Mad 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.Renomme : abc.txt -> xyz.txt, erreur 0NeoBASIC
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 ";eRenomme : abc.txt -> xyz.txt, erreur 065C02 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 ", 0Renomme : abc.txt -> xyz.txt, erreur 03,13 File Delete Official
Deletes a file, or an empty directory.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the name (length-prefixed) |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Supprime, puis 3,16 donne l'erreur 17Mad 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.Supprime, puis 3,16 donne l'erreur 17NeoBASIC
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 ";eSupprime, puis 3,16 donne l'erreur 1765C02 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 ", 0Supprime, puis 3,16 donne l'erreur 173,14 Create Directory Official
Creates a directory.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the name (length-prefixed) |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Repertoire cree, bit repertoire : 1Mad 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.Repertoire cree, bit repertoire : 1NeoBASIC
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 : ";tRepertoire cree, bit repertoire : 165C02 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 : ", 0Repertoire cree, bit repertoire : 13,15 Change Directory Official
Changes the current working directory.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the path (length-prefixed) |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Repertoire courant : /repMad 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.Repertoire courant : /repNeoBASIC
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$Repertoire courant : /rep65C02 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 : ", 0Repertoire courant : /rep3,16 File Stat Official
Gives the size and attributes of a file, by name.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the name (length-prefixed) |
| Bytes | Type | Meaning |
|---|---|---|
P0-P3 | uint32 | size in bytes |
P4 | uint8 | attributes: bit 0 directory, 1 system, 2 archive, 3 read only, 4 hidden |
erreur | uint8 | non 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;
}abc.txt : 8 octets, repertoire : 0Mad 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.abc.txt : 8 octets, repertoire : 0NeoBASIC
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 endifabc.txt : 8 octets, repertoire : 065C02 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 : ", 0abc.txt : 8 octets, repertoire : 03,17 Open Directory Official
Opens a directory to read its entries one by one (3,18).
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the path (length-prefixed); "." for the current directory |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}abc.txt 8
PROG.NEO 4642Mad 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.abc.txt 8
PROG.NEO 741NeoBASIC
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) : wendabc.txt 8
prog.bas 925
boot 065C02 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 34abc.txt 8
PROG.NEO 133,18 Read Directory Official
Reads the next entry of the open directory: name, size, attributes.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the name buffer; its first byte gives its capacity |
| Bytes | Type | Meaning |
|---|---|---|
tampon | string | name (length-prefixed), without path |
P2-P5 | uint32 | size in bytes |
P6 | uint8 | attributes, as in 3,16 |
erreur | uint8 | non 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;
}abc.txt 8
PROG.NEO 4642Mad 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.abc.txt 8
PROG.NEO 741NeoBASIC
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) : wendabc.txt 8
prog.bas 925
boot 065C02 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 34abc.txt 8
PROG.NEO 133,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;
}abc.txt 8
PROG.NEO 4642Mad 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.abc.txt 8
PROG.NEO 741NeoBASIC
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) : wendabc.txt 8
prog.bas 926
boot 065C02 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 34abc.txt 8
PROG.NEO 133,20 Copy File Official
Copies a file under another name.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the source name (length-prefixed) |
P2-P3 | addr | address of the copy name (length-prefixed) |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Copie : ABCDEFGHMad 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.Copie : ABCDEFGHNeoBASIC
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$Copie : ABCDEFGH65C02 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 : ", 0Copie : ABCDEFGH3,21 Set file attributes Official
Changes the attributes of a file (read only, hidden, archive, system).
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the name (length-prefixed) |
P2 | uint8 | attributes, as in 3,16: bit 1 system, 2 archive, 3 read only, 4 hidden |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Lecture seule : 8Mad 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.Lecture seule : 8NeoBASIC
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 : ";rLecture seule : 865C02 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 : ", 0Lecture seule : 83,22 Check End of File. Official
Tells whether an open channel has reached the end of its file.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | non 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;
}8 octets lus avant la fin du fichierMad 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.8 octets lus avant la fin du fichierNeoBASIC
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"8 octets lus avant la fin du fichier65C02 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, 08 octets lus avant la fin du fichier3,23 Get Current Working Directory. Changed by Trinity
Copies the path of the current working directory into a buffer.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address of the buffer |
P2 | uint8 | maximum length of the path |
| Bytes | Type | Meaning |
|---|---|---|
tampon | string | path (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;
}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.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$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 : ", 0Repertoire courant : /3,24 Volume Info Trinity
Gives the name and state of a storage volume (USB key, SD card, host folder).
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | volume number (0 to 3) |
P1-P2 | addr | address of the name buffer; its first byte gives its capacity |
| Bytes | Type | Meaning |
|---|---|---|
tampon | string | volume name (length-prefixed) |
P3 | uint8 | attributes: bit 0 present, bit 1 read only, bit 2 network |
erreur | uint8 | non 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;
}Volume 0 : HOST0Mad 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.Volume 0 : HOST0NeoBASIC
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 vVolume 0 : HOST065C02 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 " : ", 0Volume 0 : HOST03,25 Select Volume Trinity
Makes a volume the current one: paths without an "n:" prefix then refer to it.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | volume number (0 to 3) |
| Bytes | Type | Meaning |
|---|---|---|
erreur | uint8 | non 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;
}Volume 0 choisi, erreur 0, volume courant : 0Mad 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.Volume 0 choisi, erreur 0, volume courant : 0NeoBASIC
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 : ";vVolume 0 choisi, erreur 0, volume courant : 065C02 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 : ", 0Volume 0 choisi, erreur 0, volume courant : 03,26 Get Current Volume Trinity
Gives the number of the current volume.
Inputs: none.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | current 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;
}Volume courant : 0Mad 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.Volume courant : 0NeoBASIC
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 : ";vVolume courant : 065C02 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 : ", 0Volume courant : 03,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.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1 | uint8 | page: $00 6502 memory, $80 and $81 video memory, $90 graphics memory (as 12,2) |
P2-P3 | addr | address within the page |
P4-P5 | uint16 | number of bytes requested |
| Bytes | Type | Meaning |
|---|---|---|
P4-P5 | uint16 | number 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;
}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.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)"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, 0Lu 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.
| Bytes | Type | Meaning |
|---|---|---|
P0 | uint8 | channel number |
P1 | uint8 | page: $00 6502 memory, $80 and $81 video memory, $90 graphics memory (as 3,27) |
P2-P3 | addr | address within the page |
P4-P5 | uint16 | number of bytes requested |
P6-P7 | addr | address of the 3 progress bytes (6502 memory) |
| Bytes | Type | Meaning |
|---|---|---|
suivi+0 | uint8 | $01 during the read, then $80 + error code ($80: success) |
suivi+1-2 | uint16 | number of bytes read |
erreur | uint8 | only 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;
}Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 21Mad 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.Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 21NeoBASIC
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 returnLu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 2165C02 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 0Lu : ABCDEFGH, etat 128, 8 octets
Suivi dans la cible : erreur 213,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.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | uint16 | date: bits 15-9 year - 1980, 8-5 month, 4-0 day; 0 if unknown |
P2-P3 | uint16 | time: bits 15-11 hour, 10-5 minutes, 4-0 seconds / 2; 0 if unknown |
erreur | uint8 | 1 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;
}abc.txt : 2026-10-03 15:19:38Mad 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.abc.txt : 2026-10-03 15:19:36NeoBASIC
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 returnabc.txt : 2026-10-03 15:19:3865C02 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 0abc.txt : 2026-10-03 15:19:363,32 List Filtered Official
Prints the list of files in the current directory whose name contains a given text.
| Bytes | Type | Meaning |
|---|---|---|
P0-P1 | addr | address 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;
}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.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"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"abc.txt 8 bytes.