Tachibana
Language: English

Group 13 — Editor Official

13,1 Initialise Editor · 13,2 Reenter the Editor

The firmware contains a full-screen editor, one line of text per screen line, the one NeoBASIC uses for its programs. It knows nothing of the edited document: it asks the program for what it needs through callbacks. 13,1 starts it, then the program calls 13,2 in a loop; each call returns a callback code in P0, which the program answers before calling 13,2 again.

Callback codes: 0 end of editing (Escape); 1 give the number of lines in P0-P1; 2 give the line whose number is in P1-P2 (from 1), putting in P0-P1 the address of a buffer that holds it (length byte, then text); 3 give a key in P0 (0: none); 4 the line whose number is in P1-P2 has changed, the buffer of the edited line holds its new text; 5 insert a blank line and 6 delete the line, number in P1-P2; $FF nothing to do, call 13,2 again.

Keys understood, besides characters: left Ctrl+A, right Ctrl+D, up Ctrl+W, down Ctrl+S, home Ctrl+T, end Ctrl+G, tab, backspace, delete Ctrl+Z, Enter, page up Ctrl+R and down Ctrl+F, insert a line Ctrl+P, delete the line Ctrl+Q, Escape to leave. The examples take their keys from a list; a real program reads the keyboard (2,1).

13,1 Initialise Editor Official

Starts a full-screen editor session; returns the first callback (1: how many lines?).

Inputs
BytesTypeMeaning
P0-P1addraddress of a status line (length byte, then text) shown at the top of the screen, or 0
Outputs
BytesTypeMeaning
P0uint8first callback: 1

The example runs a full session on a three-line document and records the callbacks: 1 (number of lines), 2 three times to display the lines, 2 again for the line to edit, 3 for a key (Escape), then 0. The $FF (nothing to do) are not counted. NeoBASIC has no keyword for this call; its program editor uses it.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rappels : 1 2 2 2 2 3 0
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rappels : 1 2 2 2 2 3 0
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rappels : 1 2 2 2 2 3 0
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rappels : 1 2 2 2 2 3 0

13,2 Reenter the Editor Official

Resumes the editor after the program has answered a callback; returns the next callback.

Inputs
BytesTypeMeaning
P0-P1uint16answer to the previous callback: number of lines (1), buffer address (2), key in P0 (3)
Outputs
BytesTypeMeaning
P0uint8next callback (see the introduction)
P1-P2uint16line number, for callbacks 2, 4, 5 and 6

The buffer given for the edited line must be able to receive 256 bytes: the editor writes the line back into it when it has changed (callback 4), before moving to another line or leaving. The cursor may go one line past the end of the document: the program must then give an empty line and, if it changes, append it. When leaving, the editor clears the screen. The example edits "Un", "Deux", "Trois" with the keys X, down, End, !, Escape: two lines are stored. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne 1 : XUn
Ligne 2 : Deux!
Ligne 3 : Trois
Lignes rangees : 2

← The Neo6502 API