Groupe 13 — Éditeur Officiel
13,1 Initialise Editor · 13,2 Reenter the Editor
Le firmware contient un éditeur plein écran, une ligne de texte par ligne d'écran, celui que NeoBASIC emploie pour ses programmes. Il ne sait rien du document édité : il demande au programme ce qu'il lui faut par des rappels. 13,1 le démarre, puis le programme appelle 13,2 en boucle ; chaque appel rend en P0 un code de rappel, auquel le programme répond avant de rappeler 13,2.
Codes de rappel : 0 fin de l'édition (Échap) ; 1 donner le nombre de lignes en P0-P1 ; 2 donner la ligne dont le numéro est en P1-P2 (à partir de 1), en mettant en P0-P1 l'adresse d'un tampon qui la contient (octet de longueur, puis texte) ; 3 donner une touche en P0 (0 : aucune) ; 4 la ligne dont le numéro est en P1-P2 a changé, le tampon de la ligne éditée contient son nouveau texte ; 5 insérer une ligne vide et 6 supprimer la ligne, numéro en P1-P2 ; $FF rien à faire, rappeler 13,2.
Touches reconnues, en plus des caractères : gauche Ctrl+A, droite Ctrl+D, haut Ctrl+W, bas Ctrl+S, début Ctrl+T, fin Ctrl+G, tabulation, retour arrière, suppression Ctrl+Z, Entrée, page haut Ctrl+R et bas Ctrl+F, insérer une ligne Ctrl+P, supprimer la ligne Ctrl+Q, Échap pour sortir. Les exemples tirent leurs touches d'une liste ; un vrai programme lit le clavier (2,1).
13,1 Initialise Editor Officiel
Démarre une session de l'éditeur plein écran ; rend le premier rappel (1 : combien de lignes ?).
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse d'une ligne d'état (octet de longueur, puis texte) affichée en haut de l'écran, ou 0 |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | premier rappel : 1 |
L'exemple mène une session complète sur un document de trois lignes et relève les rappels : 1 (nombre de lignes), 2 trois fois pour afficher les lignes, 2 encore pour la ligne à éditer, 3 pour une touche (Échap), puis 0. Les $FF (rien à faire) ne sont pas comptés. NeoBASIC n'a pas de mot-clé pour cet appel ; son éditeur de programmes s'en sert.
Texte de la documentation du firmware (anglais)
Initialises the editor
C (llvm-mos)
/* Suivre les rappels d'une session d'édition courte (groupe 13, fonction 1). */
#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)
;
}
/* Le document édité : trois lignes, chaînes précédées de leur longueur (le format de l'éditeur). */
static uint8_t doc[3][41] = {"\x02Un", "\x04" "Deux", "\x05Trois"};
static uint8_t tampon[256]; /* ligne échangée avec l'éditeur */
static uint8_t touches[] = {0x1B}; /* Échap tout de suite (au lieu du clavier, 2,1) */
static uint8_t t;
/* Répond au rappel code, puis relance l'éditeur (13,2) ; rend le rappel suivant. */
static uint8_t repondre(uint8_t code) {
uint16_t n = ControlPort.params[1] | ControlPort.params[2] << 8; /* numéro de ligne (codes 2 et 4) */
libre();
if (code == 1) { /* combien de lignes ? */
ControlPort.params[0] = 3;
ControlPort.params[1] = 0;
} else if (code == 2) { /* la ligne n (à partir de 1), dans un tampon */
uint8_t *l = n <= 3 ? doc[n - 1] : (uint8_t *)""; /* après la fin : ligne vide */
for (uint8_t i = 0; i <= l[0]; i++)
tampon[i] = l[i];
ControlPort.params[0] = (uint16_t)tampon & 0xFF;
ControlPort.params[1] = (uint16_t)tampon >> 8;
} else if (code == 3) { /* une touche (0 : aucune) */
ControlPort.params[0] = t < sizeof touches ? touches[t++] : 0x1B;
} else if (code == 4 && n <= 3) { /* la ligne n a changé : le tampon la contient */
for (uint8_t i = 0; i <= tampon[0] && i < 41; i++)
doc[n - 1][i] = tampon[i];
}
api(13, 2); /* Reenter the Editor */
return ControlPort.params[0];
}
static uint8_t demarrer(void) { /* 13,1 : sans ligne d'état (P0-P1 = 0) */
libre();
ControlPort.params[0] = 0;
ControlPort.params[1] = 0;
api(13, 1); /* Initialise Editor */
return ControlPort.params[0];
}
int main(void) {
uint8_t vus[16], nv = 0;
uint8_t code = demarrer();
while (1) {
if (code != 0xFF && nv < sizeof vus)
vus[nv++] = code; /* $FF : pas de rappel, on relance seulement */
if (code == 0) /* fin de l'édition */
break;
code = repondre(code);
}
printf("Rappels :");
for (uint8_t i = 0; i < nv; i++)
printf(" %u", vus[i]);
printf("\n");
return 0;
}Rappels : 1 2 2 2 2 3 0Mad Pascal
// Suivre les rappels d'une session d'édition courte (groupe 13, fonction 1).
program editeur1;
uses crt, neo6502;
const NT = 1;
touches: array[0..1] of byte = (27, 27); // Échap tout de suite (au lieu du clavier, 2,1)
var doc: array[0..2, 0..40] of byte; // le document : longueur, puis texte (le format de l'éditeur)
tampon: array[0..255] of byte; // ligne échangée avec l'éditeur
t: byte;
// Répond au rappel code, puis relance l'éditeur (13,2) ; rend le rappel suivant.
function repondre(code: byte): byte;
var n: word;
i, k: byte;
begin
n := NeoMessage.params[1] + NeoMessage.params[2] shl 8; // numéro de ligne (codes 2 et 4)
NeoWaitMessage;
if code = 1 then // combien de lignes ?
wordParams[0] := 3
else if code = 2 then begin // la ligne n (à partir de 1), dans un tampon
tampon[0] := 0; // après la fin : ligne vide
if n <= 3 then
for i := 0 to doc[n - 1, 0] do tampon[i] := doc[n - 1, i];
wordParams[0] := word(@tampon);
end else if code = 3 then begin // une touche (0 : aucune)
if t < NT then begin NeoMessage.params[0] := touches[t]; inc(t); end
else NeoMessage.params[0] := $1B;
end else if (code = 4) and (n <= 3) then begin // la ligne n a changé : le tampon la contient
k := tampon[0];
if k > 40 then k := 40; // copie bornée à la taille d'une ligne du document
doc[n - 1, 0] := k;
for i := 1 to k do doc[n - 1, i] := tampon[i];
end;
NeoReenterEditor; // Reenter the Editor
NeoWaitMessage;
result := NeoMessage.params[0];
end;
function demarrer: byte; // 13,1 : sans ligne d'état (P0-P1 = 0)
begin
NeoWaitMessage;
wordParams[0] := 0;
NeoInitEditor; // Initialise Editor
NeoWaitMessage;
result := NeoMessage.params[0];
end;
procedure ligne(i: byte; s: string); // range s dans la ligne i du document
var j: byte;
begin
doc[i, 0] := length(s);
for j := 1 to length(s) do doc[i, j] := ord(s[j]);
end;
procedure document;
begin
ligne(0, 'Un');
ligne(1, 'Deux');
ligne(2, 'Trois');
t := 0;
end;
var vus: array[0..15] of byte;
nv, code, i: byte;
begin
document;
nv := 0;
code := demarrer;
while true do begin
if (code <> $FF) and (nv < 16) then begin // $FF : pas de rappel, on relance seulement
vus[nv] := code;
inc(nv);
end;
if code = 0 then break; // fin de l'édition
code := repondre(code);
end;
write('Rappels :');
for i := 0 to nv - 1 do write(' ', vus[i]);
writeln;
end.Rappels : 1 2 2 2 2 3 0NeoBASIC
10 ' Suivre les rappels d'une session d'edition courte (groupe 13, fonction 1)
20 d = alloc(123) : t = alloc(256) : ' document (3 lignes : longueur, puis texte) et tampon d'echange
30 i = 0 : l$ = "Un" : gosub 1400 : i = 1 : l$ = "Deux" : gosub 1400 : i = 2 : l$ = "Trois" : gosub 1400
40 kk = alloc(1) : poke kk, 27 : nt = 1 : q = 0 : ' touches : Echap tout de suite (au lieu du clavier, 2,1)
50 while peek($ff00) : wend : doke $ff04, 0 : poke $ff01, 1 : poke $ff00, 13 : ' Initialise Editor, sans ligne d'etat
60 while peek($ff00) : wend : c = peek($ff04)
70 r$ = "Rappels :"
80 while c <> 0
90 if c <> 255 then r$ = r$ + " " + str$(c) : ' 255 : pas de rappel, on relance seulement
100 n = deek($ff05) : gosub 1000
110 wend
120 print r$;" 0"
130 end
1000 ' repond au rappel c, relance l'editeur (13,2) ; rappel suivant dans c
1010 while peek($ff00) : wend
1020 if c = 1 then doke $ff04, 3 : ' combien de lignes ?
1030 if c = 2 then gosub 1200 : doke $ff04, t : ' la ligne n, dans le tampon t
1040 if c = 3 then poke $ff04, 27 : if q < nt then poke $ff04, peek(kk + q) : q = q + 1 : ' une touche
1050 if c = 4 then gosub 1300 : ' la ligne n a change : le tampon la contient
1060 while peek($ff00) : wend : poke $ff01, 2 : poke $ff00, 13 : ' Reenter the Editor
1070 while peek($ff00) : wend : c = peek($ff04)
1080 return
1200 ' ligne n du document (41 octets par ligne en d) vers le tampon t ; apres la fin : ligne vide
1210 poke t, 0 : if n > 3 then return
1220 a = d + (n - 1) * 41 : for j = 0 to peek(a) : poke t + j, peek(a + j) : next j
1230 return
1300 ' tampon t vers la ligne n du document, borne a 40 caracteres
1310 if n > 3 then return
1320 m = peek(t) : if m > 40 then m = 40
1330 a = d + (n - 1) * 41 : poke a, m : for j = 1 to m : poke a + j, peek(t + j) : next j
1340 return
1400 ' range l$ dans la ligne i du document
1410 a = d + i * 41 : poke a, len(l$) : for j = 1 to len(l$) : poke a + j, asc(mid$(l$, j, 1)) : next j
1420 returnRappels : 1 2 2 2 2 3 0Assembleur 65C02 (64tass)
; Suivre les rappels d'une session d'édition courte (groupe 13, 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
NT = 1
start: jsr demarrer
_b: cmp #$FF ; $FF : pas de rappel, on relance seulement
beq _r
ldx nv
sta vus,x
inc nv
cmp #0 ; fin de l'édition
beq _fin
_r: jsr repondre
bra _b
_fin: lda #<t0
ldx #>t0
jsr ecrire
ldx #0
_a: lda #' '
jsr WriteCharacter
lda vus,x
jsr decimal
inx
cpx nv
bne _a
lda #13
jmp WriteCharacter
touches: .byte $1B ; Échap tout de suite (au lieu du clavier, 2,1)
t0: .text "Rappels :", 0
nv: .byte 0
vus: .fill 16
; Démarre l'éditeur (13,1) sans ligne d'état (P0-P1 = 0) ; premier rappel dans A.
demarrer:
jsr WaitMessage
stz ControlPort+4
stz ControlPort+5
lda #13
ldx #1 ; 13,1 : Initialise Editor
jsr appel
lda ControlPort+4
rts
; Répond au rappel A, puis relance l'éditeur (13,2) ; rappel suivant dans A.
repondre:
sta code
lda ControlPort+5 ; numéro de ligne (codes 2 et 4), P1-P2
sta nl
lda ControlPort+6
sta nh
jsr WaitMessage
lda code
cmp #1
bne _c2
lda #3 ; combien de lignes ? 3
sta ControlPort+4
stz ControlPort+5
bra _relance
_c2: cmp #2
bne _c3
stz tampon ; après la fin : ligne vide
jsr adresse ; ligne n : adresse dans ptr, C = 1 si n hors du document
bcs _t
lda (ptr) ; longueur + 1 octets à copier
tay
_copie: lda (ptr),y
sta tampon,y
dey
bpl _copie
_t: lda #<tampon ; P0-P1 : adresse du tampon
sta ControlPort+4
lda #>tampon
sta ControlPort+5
bra _relance
_c3: cmp #3
bne _c4
lda #$1B ; au-delà de la liste : Échap
ldx t
cpx #NT
bcs _k
lda touches,x
inc t
_k: sta ControlPort+4 ; P0 : la touche
bra _relance
_c4: cmp #4
bne _relance
jsr adresse ; la ligne n a changé : le tampon la contient
bcs _relance
lda tampon
cmp #41
bcc _lg
lda #40 ; copie bornée à 40 caractères
_lg: tay
sta (ptr)
_rg: cpy #0
beq _relance
lda tampon,y
sta (ptr),y
dey
bra _rg
_relance:
lda #13
ldx #2 ; 13,2 : Reenter the Editor
jsr appel
lda ControlPort+4
rts
; Adresse de la ligne n (nl, nh) du document dans ptr ; C = 1 si n n'est pas 1, 2 ou 3.
adresse:
lda nh
bne _hors
ldx nl
beq _hors
cpx #4
bcs _hors
dex
txa
asl a
tax
lda lignes,x
sta ptr
lda lignes+1,x
sta ptr+1
clc
rts
_hors: sec
rts
code: .byte 0
nl: .byte 0
nh: .byte 0
t: .byte 0
lignes: .word doc0, doc1, doc2
doc0: .byte 2
.text "Un"
.fill 38
doc1: .byte 4
.text "Deux"
.fill 36
doc2: .byte 5
.text "Trois"
.fill 35
tampon: .fill 256 ; ligne échangée avec l'éditeur (longueur, puis texte)
; 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
blk = $82
diviseur: .byte 0
fin: .byte 0Rappels : 1 2 2 2 2 3 013,2 Reenter the Editor Officiel
Relance l'éditeur après la réponse du programme à un rappel ; rend le rappel suivant.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | uint16 | réponse au rappel précédent : nombre de lignes (1), adresse du tampon (2), touche en P0 (3) |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | rappel suivant (voir l'introduction) |
P1-P2 | uint16 | numéro de ligne, pour les rappels 2, 4, 5 et 6 |
Le tampon donné pour la ligne éditée doit pouvoir recevoir 256 octets : l'éditeur y réécrit la ligne quand elle a changé (rappel 4), avant de passer à une autre ligne ou de sortir. Le curseur peut aller une ligne après la fin du document : le programme doit alors fournir une ligne vide et, si elle change, l'ajouter. À la sortie, l'éditeur efface l'écran. L'exemple édite « Un », « Deux », « Trois » avec les touches X, bas, Fin, !, Échap : deux lignes sont rangées. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Re-enters the system editor. Returns the function required for call out, the editors sort of 'call backs' - see editor specification.
C (llvm-mos)
/* Éditer un petit document avec l'éditeur du firmware (groupe 13, fonction 2). */
#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)
;
}
/* Le document édité : trois lignes, chaînes précédées de leur longueur (le format de l'éditeur). */
static uint8_t doc[3][41] = {"\x02Un", "\x04" "Deux", "\x05Trois"};
static uint8_t tampon[256]; /* ligne échangée avec l'éditeur */
static uint8_t touches[] = {'X', 0x13, 0x07, '!', 0x1B}; /* X, bas, Fin, !, Échap (au lieu du clavier, 2,1) */
static uint8_t t;
/* Répond au rappel code, puis relance l'éditeur (13,2) ; rend le rappel suivant. */
static uint8_t repondre(uint8_t code) {
uint16_t n = ControlPort.params[1] | ControlPort.params[2] << 8; /* numéro de ligne (codes 2 et 4) */
libre();
if (code == 1) { /* combien de lignes ? */
ControlPort.params[0] = 3;
ControlPort.params[1] = 0;
} else if (code == 2) { /* la ligne n (à partir de 1), dans un tampon */
uint8_t *l = n <= 3 ? doc[n - 1] : (uint8_t *)""; /* après la fin : ligne vide */
for (uint8_t i = 0; i <= l[0]; i++)
tampon[i] = l[i];
ControlPort.params[0] = (uint16_t)tampon & 0xFF;
ControlPort.params[1] = (uint16_t)tampon >> 8;
} else if (code == 3) { /* une touche (0 : aucune) */
ControlPort.params[0] = t < sizeof touches ? touches[t++] : 0x1B;
} else if (code == 4 && n <= 3) { /* la ligne n a changé : le tampon la contient */
for (uint8_t i = 0; i <= tampon[0] && i < 41; i++)
doc[n - 1][i] = tampon[i];
}
api(13, 2); /* Reenter the Editor */
return ControlPort.params[0];
}
static uint8_t demarrer(void) { /* 13,1 : sans ligne d'état (P0-P1 = 0) */
libre();
ControlPort.params[0] = 0;
ControlPort.params[1] = 0;
api(13, 1); /* Initialise Editor */
return ControlPort.params[0];
}
int main(void) {
uint8_t ranges = 0;
uint8_t code = demarrer(); /* 13,1 */
while (code != 0) { /* 0 : l'utilisateur a quitté (Échap) */
if (code == 4)
ranges++;
code = repondre(code); /* 13,2 */
}
for (uint8_t i = 0; i < 3; i++) {
doc[i][doc[i][0] + 1] = 0;
printf("Ligne %u : %s\n", i + 1, (char *)doc[i] + 1);
}
printf("Lignes rangees : %u\n", ranges);
return 0;
}Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2Mad Pascal
// Éditer un petit document avec l'éditeur du firmware (groupe 13, fonction 2).
program editeur2;
uses crt, neo6502;
const NT = 5;
touches: array[0..NT - 1] of byte = (ord('X'), $13, $07, ord('!'), 27); // X, bas, Fin, !, Échap (au lieu du clavier, 2,1)
var doc: array[0..2, 0..40] of byte; // le document : longueur, puis texte (le format de l'éditeur)
tampon: array[0..255] of byte; // ligne échangée avec l'éditeur
t: byte;
// Répond au rappel code, puis relance l'éditeur (13,2) ; rend le rappel suivant.
function repondre(code: byte): byte;
var n: word;
i, k: byte;
begin
n := NeoMessage.params[1] + NeoMessage.params[2] shl 8; // numéro de ligne (codes 2 et 4)
NeoWaitMessage;
if code = 1 then // combien de lignes ?
wordParams[0] := 3
else if code = 2 then begin // la ligne n (à partir de 1), dans un tampon
tampon[0] := 0; // après la fin : ligne vide
if n <= 3 then
for i := 0 to doc[n - 1, 0] do tampon[i] := doc[n - 1, i];
wordParams[0] := word(@tampon);
end else if code = 3 then begin // une touche (0 : aucune)
if t < NT then begin NeoMessage.params[0] := touches[t]; inc(t); end
else NeoMessage.params[0] := $1B;
end else if (code = 4) and (n <= 3) then begin // la ligne n a changé : le tampon la contient
k := tampon[0];
if k > 40 then k := 40; // copie bornée à la taille d'une ligne du document
doc[n - 1, 0] := k;
for i := 1 to k do doc[n - 1, i] := tampon[i];
end;
NeoReenterEditor; // Reenter the Editor
NeoWaitMessage;
result := NeoMessage.params[0];
end;
function demarrer: byte; // 13,1 : sans ligne d'état (P0-P1 = 0)
begin
NeoWaitMessage;
wordParams[0] := 0;
NeoInitEditor; // Initialise Editor
NeoWaitMessage;
result := NeoMessage.params[0];
end;
procedure ligne(i: byte; s: string); // range s dans la ligne i du document
var j: byte;
begin
doc[i, 0] := length(s);
for j := 1 to length(s) do doc[i, j] := ord(s[j]);
end;
procedure document;
begin
ligne(0, 'Un');
ligne(1, 'Deux');
ligne(2, 'Trois');
t := 0;
end;
var ranges, code, i, k: byte;
begin
document;
ranges := 0;
code := demarrer; // 13,1
while code <> 0 do begin // 0 : l'utilisateur a quitté (Échap)
if code = 4 then inc(ranges);
code := repondre(code); // 13,2
end;
for i := 0 to 2 do begin
write('Ligne ', i + 1, ' : ');
for k := 1 to doc[i, 0] do write(chr(doc[i, k]));
writeln;
end;
writeln('Lignes rangees : ', ranges);
end.Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2NeoBASIC
10 ' Editer un petit document avec l'editeur du firmware (groupe 13, fonction 2)
20 d = alloc(123) : t = alloc(256) : ' document (3 lignes : longueur, puis texte) et tampon d'echange
30 i = 0 : l$ = "Un" : gosub 1400 : i = 1 : l$ = "Deux" : gosub 1400 : i = 2 : l$ = "Trois" : gosub 1400
40 kk = alloc(5) : poke kk, asc("X") : poke kk + 1, $13 : poke kk + 2, $07 : poke kk + 3, asc("!") : poke kk + 4, 27
50 nt = 5 : q = 0 : ' touches : X, bas, Fin, !, Echap (au lieu du clavier, 2,1)
60 while peek($ff00) : wend : doke $ff04, 0 : poke $ff01, 1 : poke $ff00, 13 : ' 13,1
70 while peek($ff00) : wend : c = peek($ff04) : r = 0
80 while c <> 0 : ' 0 : l'utilisateur a quitte (Echap)
90 n = deek($ff05) : ' numero de ligne (codes 2 et 4), lu avant tout calcul
100 if c = 4 then r = r + 1
110 gosub 1000
120 wend
130 for i = 0 to 2 : s$ = "" : a = d + i * 41 : for j = 1 to peek(a) : s$ = s$ + chr$(peek(a + j)) : next j
140 print "Ligne ";i + 1;" : ";s$ : next i
150 print "Lignes rangees : ";r
160 end
1000 ' repond au rappel c, relance l'editeur (13,2) ; rappel suivant dans c
1010 while peek($ff00) : wend
1020 if c = 1 then doke $ff04, 3 : ' combien de lignes ?
1030 if c = 2 then gosub 1200 : doke $ff04, t : ' la ligne n, dans le tampon t
1040 if c = 3 then poke $ff04, 27 : if q < nt then poke $ff04, peek(kk + q) : q = q + 1 : ' une touche
1050 if c = 4 then gosub 1300 : ' la ligne n a change : le tampon la contient
1060 while peek($ff00) : wend : poke $ff01, 2 : poke $ff00, 13 : ' Reenter the Editor
1070 while peek($ff00) : wend : c = peek($ff04)
1080 return
1200 ' ligne n du document (41 octets par ligne en d) vers le tampon t ; apres la fin : ligne vide
1210 poke t, 0 : if n > 3 then return
1220 a = d + (n - 1) * 41 : for j = 0 to peek(a) : poke t + j, peek(a + j) : next j
1230 return
1300 ' tampon t vers la ligne n du document, borne a 40 caracteres
1310 if n > 3 then return
1320 m = peek(t) : if m > 40 then m = 40
1330 a = d + (n - 1) * 41 : poke a, m : for j = 1 to m : poke a + j, peek(t + j) : next j
1340 return
1400 ' range l$ dans la ligne i du document
1410 a = d + i * 41 : poke a, len(l$) : for j = 1 to len(l$) : poke a + j, asc(mid$(l$, j, 1)) : next j
1420 returnLigne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2Assembleur 65C02 (64tass)
; Éditer un petit document avec l'éditeur du firmware (groupe 13, fonction 2).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
NT = 5
start: jsr demarrer ; 13,1
_b: cmp #0 ; 0 : l'utilisateur a quitté (Échap)
beq _fin
cmp #4
bne _r
inc ranges
_r: jsr repondre ; 13,2
bra _b
_fin: ldx #0
_l: phx
lda #<t0
ldx #>t0
jsr ecrire
pla
pha
inc a
jsr decimal ; numéro de ligne
lda #<t1
ldx #>t1
jsr ecrire
pla
pha
asl a
tax
lda lignes,x
sta ptr
lda lignes+1,x
sta ptr+1
lda (ptr) ; longueur de la ligne
sta nb
ldy #1
_c: cpy nb
beq _d
bcs _nl
_d: lda (ptr),y
jsr WriteCharacter
iny
bra _c
_nl: lda #13
jsr WriteCharacter
plx
inx
cpx #3
bne _l
lda #<t2
ldx #>t2
jsr ecrire
lda ranges
jsr decimal
lda #13
jmp WriteCharacter
touches: .byte 'X', $13, $07, '!', $1B ; X, bas, Fin, !, Échap (au lieu du clavier, 2,1)
t0: .text "Ligne ", 0
t1: .text " : ", 0
t2: .text "Lignes rangees : ", 0
ranges: .byte 0
nb: .byte 0
; Démarre l'éditeur (13,1) sans ligne d'état (P0-P1 = 0) ; premier rappel dans A.
demarrer:
jsr WaitMessage
stz ControlPort+4
stz ControlPort+5
lda #13
ldx #1 ; 13,1 : Initialise Editor
jsr appel
lda ControlPort+4
rts
; Répond au rappel A, puis relance l'éditeur (13,2) ; rappel suivant dans A.
repondre:
sta code
lda ControlPort+5 ; numéro de ligne (codes 2 et 4), P1-P2
sta nl
lda ControlPort+6
sta nh
jsr WaitMessage
lda code
cmp #1
bne _c2
lda #3 ; combien de lignes ? 3
sta ControlPort+4
stz ControlPort+5
bra _relance
_c2: cmp #2
bne _c3
stz tampon ; après la fin : ligne vide
jsr adresse ; ligne n : adresse dans ptr, C = 1 si n hors du document
bcs _t
lda (ptr) ; longueur + 1 octets à copier
tay
_copie: lda (ptr),y
sta tampon,y
dey
bpl _copie
_t: lda #<tampon ; P0-P1 : adresse du tampon
sta ControlPort+4
lda #>tampon
sta ControlPort+5
bra _relance
_c3: cmp #3
bne _c4
lda #$1B ; au-delà de la liste : Échap
ldx t
cpx #NT
bcs _k
lda touches,x
inc t
_k: sta ControlPort+4 ; P0 : la touche
bra _relance
_c4: cmp #4
bne _relance
jsr adresse ; la ligne n a changé : le tampon la contient
bcs _relance
lda tampon
cmp #41
bcc _lg
lda #40 ; copie bornée à 40 caractères
_lg: tay
sta (ptr)
_rg: cpy #0
beq _relance
lda tampon,y
sta (ptr),y
dey
bra _rg
_relance:
lda #13
ldx #2 ; 13,2 : Reenter the Editor
jsr appel
lda ControlPort+4
rts
; Adresse de la ligne n (nl, nh) du document dans ptr ; C = 1 si n n'est pas 1, 2 ou 3.
adresse:
lda nh
bne _hors
ldx nl
beq _hors
cpx #4
bcs _hors
dex
txa
asl a
tax
lda lignes,x
sta ptr
lda lignes+1,x
sta ptr+1
clc
rts
_hors: sec
rts
code: .byte 0
nl: .byte 0
nh: .byte 0
t: .byte 0
lignes: .word doc0, doc1, doc2
doc0: .byte 2
.text "Un"
.fill 38
doc1: .byte 4
.text "Deux"
.fill 36
doc2: .byte 5
.text "Trois"
.fill 35
tampon: .fill 256 ; ligne échangée avec l'éditeur (longueur, puis texte)
; 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
blk = $82
diviseur: .byte 0
fin: .byte 0Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2