Tachibana
Language: English

Group 2 — Console Official

2,0 Write Character · 2,1 Read Character · 2,2 Console Status · 2,3 Read Line · 2,4 Define Hotkey · 2,5 Define Character · 2,6 Write Character · 2,7 Set Cursor Pos · 2,8 List Hotkeys · 2,9 Screen Size · 2,10 Insert Line · 2,11 Delete Line · 2,12 Clear Screen · 2,13 Cursor Position · 2,14 Clear Region · 2,15 Set Text Color · 2,16 Cursor Inverse · 2,17 Tab() implementation · 2,18 Read Ink/Paper Colours · 2,19 Show/Hide Cursor Reversing · 2,20 Console Debug Echo · 2,21 Set Console Font · 2,22 Get Media Key · 2,23 Get Lock Keys

2,0 Write Character Official

Writes a character at the cursor position. Duplicate of function 2,6, kept for backward compatibility.

Inputs
BytesTypeMeaning
P0charthe character (or a control code, see 2,6)

Outputs: none.

Prefer function 2,6, which does the same.

Firmware documentation text

Console out (duplicate of Function 6 for backward compatibility).

C (llvm-mos)
/* Écrire un texte caractère par caractère (groupe 2, fonction 0). */
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

int main(void) {
    const char *texte = "Bonjour\r";
    while (*texte) {
        libre();
        ControlPort.params[0] = *texte++;
        api(2, 0);                              /* Write Character */
    }
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
Mad Pascal
// Écrire un texte caractère par caractère (groupe 2, fonction 0).
program ecrire0;
uses crt, neo6502;
var texte: string[16];
    i: byte;
begin
  texte := 'Bonjour';
  for i := 1 to length(texte) do
  begin
    NeoWaitMessage;
    NeoMessage.params[0] := ord(texte[i]);
    NeoSendMessage(2, 0);                       // Write Character
  end;
  NeoWaitMessage;
  NeoMessage.params[0] := 13;                   // retour à la ligne
  NeoSendMessage(2, 0);
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
NeoBASIC
10 ' Ecrire un texte caractere par caractere (groupe 2, fonction 0)
20 t$ = "Bonjour" + chr$(13)
30 for i = 1 to len(t$)
40 while peek($ff00) : wend
50 poke $ff04, asc(mid$(t$, i, 1)) : poke $ff01, 0 : poke $ff00, 2
60 next i
70 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
65C02 assembly (64tass)
; Écrire un texte caractère par caractère (groupe 2, fonction 0).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  ldx #0
_suiv:  lda texte,x
        beq _fin
        jsr WaitMessage
        sta ControlPort+4          ; P0 : le caractère
        phx
        lda #2
        ldx #0                     ; fonction 0 : Write Character
        jsr appel
        plx
        inx
        bne _suiv
_fin:   rts

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

texte:  .text "Bonjour", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour

2,1 Read Character Official

Removes the oldest key press from the keyboard queue and gives its ASCII code; 0 if the queue is empty.

Inputs: none.

Outputs
BytesTypeMeaning
P0charASCII code of the key, 0 if none

Meant for text input. For a game, read the key state (1,2 or 7,1): the queue does not tell whether a key is still held. In NeoBASIC, inkey$() makes the same call.

NeoBASIC keywords that make this call: inkey$()

Firmware documentation text

Read and remove a key press from the keyboard queue into Parameter:0. This is the ASCII value of the keystroke. If there are no key presses in the queue, Parameter:0 will be zero.

Note that this Function is best for text input, but not for games. Function 7,1 is more optimal for games, as this only detects key presses, you cannot check whether the key is currently down or not.

C (llvm-mos)
/* Attendre une touche et l'afficher (groupe 2, fonction 1). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    char c;
    printf("Appuyez sur une touche\n");
    while ((c = neo_console_read_char()) == 0)  /* 0 : file vide */
        ;
    printf("Touche : %c\n", c);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Touche : A
Mad Pascal
// Attendre une touche et l'afficher (groupe 2, fonction 1).
program lecture;
uses crt, neo6502;
var c: byte;
begin
  writeln('Appuyez sur une touche');
  repeat
    NeoSendMessage(2, 1);                       // Read Character
    NeoWaitMessage;
    c := NeoMessage.params[0];
  until c <> 0;                                 // 0 : file vide
  writeln('Touche : ', chr(c));
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Touche : A
NeoBASIC
10 ' Attendre une touche et l'afficher (groupe 2, fonction 1)
20 print "Appuyez sur une touche"
30 repeat : k$ = inkey$() : until k$ <> ""
40 print "Touche : ";k$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Touche : A
65C02 assembly (64tass)
; Attendre une touche et l'afficher (groupe 2, 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:  lda #<invite
        ldx #>invite
        jsr ecrire
_att:   jsr WaitMessage
        lda #2
        ldx #1                     ; fonction 1 : Read Character
        jsr appel
        lda ControlPort+4          ; P0 : la touche, 0 si aucune
        beq _att
        pha
        lda #<message
        ldx #>message
        jsr ecrire
        pla
        jsr WriteCharacter
        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

invite:  .text "Appuyez sur une touche", 13, 0
message: .text "Touche : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Touche : A

2,2 Console Status Official

Tells whether the keyboard queue is empty, without removing anything from it.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8$FF if the queue is empty, 0 if a key is waiting

Mind the sense: $FF means "nothing to read".

Firmware documentation text

Check to see if the keyboard queue is empty. If it is, Parameter:0 will be $FF, otherwise it will be $00

C (llvm-mos)
/* Attendre qu'une touche soit dans la file, sans la retirer (groupe 2, fonction 2). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    printf("Appuyez sur une touche\n");
    while (neo_console_status() == 0xFF)        /* $FF : file vide */
        ;
    printf("Une touche attend\n");
    neo_console_read_char();                    /* la retirer de la file */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Une touche attend
Mad Pascal
// Attendre qu'une touche soit dans la file, sans la retirer (groupe 2, fonction 2).
program statut;
uses crt, neo6502;
begin
  writeln('Appuyez sur une touche');
  repeat
    NeoSendMessage(2, 2);                       // Console Status
    NeoWaitMessage;
  until NeoMessage.params[0] <> $FF;            // $FF : file vide
  writeln('Une touche attend');
  NeoSendMessage(2, 1);                         // la retirer de la file
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Une touche attend
NeoBASIC
10 ' Attendre qu'une touche soit dans la file, sans la retirer (groupe 2, fonction 2)
20 print "Appuyez sur une touche"
30 repeat
40 while peek($ff00) : wend
50 poke $ff01, 2 : poke $ff00, 2
60 while peek($ff00) : wend : v = peek($ff04)
70 until v <> 255
80 print "Une touche attend"
90 k$ = inkey$()
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Une touche attend
A
65C02 assembly (64tass)
; Attendre qu'une touche soit dans la file, sans la retirer (groupe 2, 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

start:  lda #<invite
        ldx #>invite
        jsr ecrire
_att:   jsr WaitMessage
        lda #2
        ldx #2                     ; fonction 2 : Console Status
        jsr appel
        lda ControlPort+4          ; $FF : file vide
        cmp #$FF
        beq _att
        lda #<message
        ldx #>message
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #1                     ; retirer la touche (2,1)
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

invite:  .text "Appuyez sur une touche", 13, 0
message: .text "Une touche attend", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Appuyez sur une touche
Une touche attend

2,3 Read Line Official

Reads back the text of the screen line where the cursor is (a logical line, possibly spanning several screen lines), then moves the cursor to the start of the next line.

Inputs
BytesTypeMeaning
P0-P1addraddress of a 256-byte buffer that receives the line (length, then text)
Outputs
BytesTypeMeaning
tamponstringthe line, without trailing spaces

Nothing is awaited from the keyboard: the function reads what is already displayed. This is how a full-screen editor gets the line on which Enter was pressed. For real input, the kernel offers ReadLine ($FFEB).

Firmware documentation text

Input the current line below the cursor into Parameters:0,1 as a length-prefixed string; and move the cursor to the line below. Handles multiple-line input.

C (llvm-mos)
/* Relire une ligne déjà affichée à l'écran (groupe 2, fonction 3). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

static uint8_t tampon[256];                     /* longueur, puis le texte */

int main(void) {
    printf("Bonjour tout le monde\n");
    libre();
    api(2, 13);                                 /* Cursor Position */
    uint8_t y = ControlPort.params[1];
    libre();
    ControlPort.params[0] = 0;                  /* remonter sur la ligne affichée */
    ControlPort.params[1] = y - 1;
    api(2, 7);                                  /* Set Cursor Pos */
    libre();
    ControlPort.params[0] = (uint16_t)tampon & 0xFF;
    ControlPort.params[1] = (uint16_t)tampon >> 8;
    api(2, 3);                                  /* Read Line */
    printf("Relu : %.*s\n", tampon[0], tampon + 1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour tout le monde
Relu : Bonjour tout le monde
Mad Pascal
// Relire une ligne déjà affichée à l'écran (groupe 2, fonction 3).
program relire;
uses crt, neo6502;
var tampon: string[255];                        // longueur, puis le texte
    x, y: byte;
begin
  writeln('Bonjour tout le monde');
  NeoGetCursorPos(x, y);
  NeoWaitMessage;
  NeoMessage.params[0] := 0;                    // remonter sur la ligne affichée
  NeoMessage.params[1] := y - 1;
  NeoSendMessage(2, 7);                         // Set Cursor Pos
  NeoWaitMessage;
  wordParams[0] := word(@tampon);
  NeoSendMessage(2, 3);                         // Read Line
  NeoWaitMessage;
  writeln('Relu : ', tampon);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour tout le monde
Relu : Bonjour tout le monde
NeoBASIC
10 ' Relire une ligne deja affichee a l'ecran (groupe 2, fonction 3)
20 a = alloc(256)
30 print "Bonjour tout le monde"
40 while peek($ff00) : wend
50 poke $ff01, 13 : poke $ff00, 2
60 while peek($ff00) : wend : y = peek($ff05)
70 poke $ff04, 0 : poke $ff05, y - 1 : poke $ff01, 7 : poke $ff00, 2
80 while peek($ff00) : wend
90 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff01, 3 : poke $ff00, 2
100 while peek($ff00) : wend
110 r$ = "" : for i = 1 to peek(a) : r$ = r$ + chr$(peek(a + i)) : next i
120 print "Relu : ";r$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour tout le monde
Relu : Bonjour tout le monde
65C02 assembly (64tass)
; Relire une ligne déjà affichée à l'écran (groupe 2, fonction 3).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<ligne
        ldx #>ligne
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #13                    ; Cursor Position
        jsr appel
        ldy ControlPort+5          ; ligne du curseur
        dey                        ; remonter sur la ligne affichée
        jsr WaitMessage
        stz ControlPort+4
        sty ControlPort+5
        lda #2
        ldx #7                     ; Set Cursor Pos
        jsr appel
        jsr WaitMessage
        lda #<tampon
        sta ControlPort+4          ; P0-P1 : tampon de 256 octets
        lda #>tampon
        sta ControlPort+5
        lda #2
        ldx #3                     ; fonction 3 : Read Line
        jsr appel
        lda #<relu
        ldx #>relu
        jsr ecrire
        ldx #0
_txt:   cpx tampon                 ; longueur
        beq _fin
        lda tampon+1,x
        jsr WriteCharacter
        inx
        bne _txt
_fin:   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

ligne:  .text "Bonjour tout le monde", 13, 0
relu:   .text "Relu : ", 0
tampon: .fill 256
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour tout le monde
Relu : Bonjour tout le monde

2,4 Define Hotkey Official

Assigns a text to a function key F1 to F10: pressing the key types it as if from the keyboard.

Inputs
BytesTypeMeaning
P0uint8key number, 1 (F1) to 10 (F10)
P2-P3addraddress of the text, length-prefixed

Outputs: none.

F11 and F12 cannot be defined. The text address is at P2-P3 (P1 is not used). In NeoBASIC, fkey n, "text" makes the same call. In Mad Pascal 1.7.8, NeoDefineHotkey stores the address at P0-P1, overwriting the key number: the call fails (error 1); the example makes the call directly.

NeoBASIC keywords that make this call: fkey

Firmware documentation text

Define the function key F1..F10 specified in Parameter:0 as 1..10 to emit the length-prefixed string stored at the memory location specified in Parameters:2,3.

F11 and F12 cannot currently be defined.

C (llvm-mos)
/* Associer un texte à la touche F1, puis lister les touches (groupe 2, fonctions 4 et 8). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_console_define_hotkey(1, "Bonjour");    /* F1 */
    neo_console_list_hotkeys();                 /* 2,8 : afficher les définitions */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Bonjour"
F8  : ""
Mad Pascal
// Associer un texte à la touche F1, puis lister les touches (groupe 2, fonctions 4 et 8).
// NeoDefineHotkey (Mad Pascal 1.7.8) range l'adresse en P0-P1 et écrase la touche : appel direct.
program hotkey;
uses crt, neo6502;
var texte: string[32];                          // chaîne Pascal : longueur puis texte
begin
  texte := 'Bonjour';
  NeoWaitMessage;
  NeoMessage.params[0] := 1;                    // P0 : F1
  wordParams[1] := word(@texte);                // P2-P3 : adresse du texte
  NeoSendMessage(2, 4);                         // Define Hotkey
  NeoWaitMessage;
  NeoShowHotkeys;                               // 2,8 : afficher les définitions
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Bonjour"
F8  : ""
NeoBASIC
10 ' Associer un texte a la touche F1, puis lister les touches (groupe 2, fonctions 4 et 8)
20 fkey 1, "Bonjour"
30 fkey
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Bonjour"
65C02 assembly (64tass)
; Associer un texte à la touche F1, puis lister les touches (groupe 2, fonctions 4 et 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
        lda #1
        sta ControlPort+4          ; P0 : F1
        lda #<texte
        sta ControlPort+6          ; P2-P3 : adresse du texte
        lda #>texte
        sta ControlPort+7
        lda #2
        ldx #4                     ; fonction 4 : Define Hotkey
        jsr appel
        jsr WaitMessage
        lda #2
        ldx #8                     ; fonction 8 : List Hotkeys
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

texte:  .byte 7                    ; longueur
        .text "Bonjour"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Bonjour"
F8  : ""

2,5 Define Character Official

Redraws one of the characters 192 to 255 of the font, row by row (6 columns × 7 rows).

Inputs
BytesTypeMeaning
P0uint8character code (192 to 255)
P1-P77 × uint8the 7 rows of the bitmap, top to bottom; bits 0 to 5 = columns

Outputs: none.

Redefined characters stay until reset. In NeoBASIC, defchr c, r1, …, r7 makes the same call.

NeoBASIC keywords that make this call: defchr

Firmware documentation text

Define a font character specified in Parameter:0 within the range of 192..255. Fill bits 0..5 (columns) of Parameters:1..7 (rows) with the character bitmap.

C (llvm-mos)
/* Dessiner un visage souriant dans le caractère 192 (groupe 2, fonction 5). */
#include <stdio.h>
#include <neo/api.h>

static const uint8_t visage[7] = { 0x1E, 0x21, 0x2D, 0x21, 0x2D, 0x33, 0x1E };   /* bits 0-5 */

int main(void) {
    neo_console_define_char(192, visage);
    printf("Caractere 192 redefini : %c\n", 192);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Caractere 192 redefini : .
Mad Pascal
// Dessiner un visage souriant dans le caractère 192 (groupe 2, fonction 5).
program defchar;
uses crt, neo6502;
const visage: array[0..6] of byte = ($1E, $21, $2D, $21, $2D, $33, $1E);   // bits 0-5
begin
  NeoSetChar(192, @visage);
  NeoWaitMessage;
  writeln('Caractere 192 redefini : ', chr(192));
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Caractere 192 redefini : .
NeoBASIC
10 ' Dessiner un visage souriant dans le caractere 192 (groupe 2, fonction 5)
20 defchr 192, $1e, $21, $2d, $21, $2d, $33, $1e
30 print "Caractere 192 redefini : ";chr$(192)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Caractere 192 redefini : .
65C02 assembly (64tass)
; Dessiner un visage souriant dans le caractère 192 (groupe 2, fonction 5).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #192
        sta ControlPort+4          ; P0 : le caractère
        ldx #6
_copie: lda visage,x               ; P1-P7 : les 7 lignes
        sta ControlPort+5,x
        dex
        bpl _copie
        lda #2
        ldx #5                     ; fonction 5 : Define Character
        jsr appel
        lda #<message
        ldx #>message
        jsr ecrire
        lda #192
        jsr WriteCharacter
        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

visage:  .byte $1E, $21, $2D, $21, $2D, $33, $1E
message: .text "Caractere 192 redefini : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Caractere 192 redefini : .

2,6 Write Character Official

Writes a character, or performs a control code, at the cursor position.

Inputs
BytesTypeMeaning
P0char32-126 and $A0-$FF: displayed character; $80-$8F: text colour; $90-$9F: background colour; control codes: 8 backspace, 9 tab, 10 line feed, 12 clear screen, 13 carriage return, 20 home, 1/4/19/23 cursor left/right/down/up, 24 invert the character under the cursor, 26 delete

Outputs: none.

This is the kernel routine WriteCharacter ($FFF1); the codes come from CONWrite in the firmware.

Firmware documentation text

Write the character specified in Parameter:0 to the console at the cursor position. Refer to Section "Console Codes" for details.

C (llvm-mos)
/* Écrire un texte, en changeant la couleur (groupe 2, fonction 6). */
#include <neo/api.h>

int main(void) {
    const char *texte = "\x83" "Bonjour" "\x87" "\r";   /* $83 : couleur 3, $87 : couleur 7 */
    while (*texte)
        neo_console_write_char(*texte++);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
Mad Pascal
// Écrire un texte, en changeant la couleur (groupe 2, fonction 6).
program ecrire6;
uses crt, neo6502;
var texte: string[16];
    i: byte;
begin
  texte := #$83'Bonjour'#$87#13;               // $83 : couleur 3, $87 : couleur 7, retour à la ligne
  for i := 1 to length(texte) do
  begin
    NeoWaitMessage;
    NeoMessage.params[0] := ord(texte[i]);
    NeoSendMessage(2, 6);                       // Write Character
  end;
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
NeoBASIC
10 ' Ecrire un texte, en changeant la couleur (groupe 2, fonction 6)
20 t$ = chr$($83) + "Bonjour" + chr$($87) + chr$(13) : ' $83 : couleur 3, $87 : couleur 7
30 for i = 1 to len(t$)
40 while peek($ff00) : wend
50 poke $ff04, asc(mid$(t$, i, 1)) : poke $ff01, 6 : poke $ff00, 2
60 next i
70 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
65C02 assembly (64tass)
; Écrire un texte, en changeant la couleur (groupe 2, 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:  ldx #0
_suiv:  lda texte,x
        beq _fin
        jsr WaitMessage
        sta ControlPort+4          ; P0 : caractère ou code
        phx
        lda #2
        ldx #6                     ; fonction 6 : Write Character
        jsr appel
        plx
        inx
        bne _suiv
_fin:   rts

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

texte:  .byte $83                  ; couleur 3
        .text "Bonjour"
        .byte $87, 13, 0           ; couleur 7, retour à la ligne
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour

2,7 Set Cursor Pos Official

Moves the cursor to a screen cell (column, row).

Inputs
BytesTypeMeaning
P0uint8column (0 = left)
P1uint8row (0 = top)

Outputs: none.

In NeoBASIC, cursor x, y makes the same call. The screen size is given by 2,9.

NeoBASIC keywords that make this call: cursor

Firmware documentation text

Move the cursor to the screen character cell Parameter:0 (X), Parameter:1 (Y).

C (llvm-mos)
/* Écrire en colonne 10 de la ligne suivante (groupe 2, fonction 7). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    uint8_t x, y;
    neo_console_cursor_pos(&x, &y);             /* 2,13 : où est le curseur */
    neo_console_set_cursor_pos(10, y);          /* colonne 10, même ligne */
    printf("Ici\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
          Ici
Mad Pascal
// Écrire en colonne 10 de la ligne courante (groupe 2, fonction 7).
program curseur;
uses crt, neo6502;
var x, y: byte;
begin
  NeoGetCursorPos(x, y);                        // 2,13 : où est le curseur
  NeoWaitMessage;
  NeoMessage.params[0] := 10;                   // colonne
  NeoMessage.params[1] := y;                    // ligne
  NeoSendMessage(2, 7);                         // Set Cursor Pos
  NeoWaitMessage;
  writeln('Ici');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
          Ici
NeoBASIC
10 ' Ecrire en colonne 10 de la ligne courante (groupe 2, fonction 7)
20 while peek($ff00) : wend
30 poke $ff01, 13 : poke $ff00, 2
40 while peek($ff00) : wend : y = peek($ff05)
50 cursor 10, y
60 print "Ici"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
          Ici
65C02 assembly (64tass)
; Écrire en colonne 10 de la ligne courante (groupe 2, 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
        lda #2
        ldx #13                    ; Cursor Position
        jsr appel
        ldy ControlPort+5          ; ligne actuelle
        jsr WaitMessage
        lda #10
        sta ControlPort+4          ; P0 : colonne 10
        sty ControlPort+5          ; P1 : même ligne
        lda #2
        ldx #7                     ; fonction 7 : Set Cursor Pos
        jsr appel
        lda #<ici
        ldx #>ici
        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

ici:    .text "Ici", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
          Ici

2,8 List Hotkeys Official

Displays the texts assigned to the function keys (see 2,4).

Inputs: none.

Outputs: none.

In NeoBASIC, fkey without arguments makes the same call.

NeoBASIC keywords that make this call: fkey

Firmware documentation text

Display the current function key definitions.

C (llvm-mos)
/* Lister les touches de fonction après avoir défini F1 (groupe 2, fonction 8). */
#include <neo/api.h>

int main(void) {
    neo_console_define_hotkey(1, "Liste");      /* 2,4 */
    neo_console_list_hotkeys();                 /* List Hotkeys */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Liste"
F8  : ""
Mad Pascal
// Lister les touches de fonction après avoir défini F1 (groupe 2, fonction 8).
program listkeys;
uses crt, neo6502;
var texte: string[16];
begin
  texte := 'Liste';
  NeoWaitMessage;
  NeoMessage.params[0] := 1;                    // 2,4 : F1 ...
  wordParams[1] := word(@texte);                // ... texte en P2-P3
  NeoSendMessage(2, 4);
  NeoWaitMessage;
  NeoShowHotkeys;                               // List Hotkeys
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Liste"
F8  : ""
NeoBASIC
10 ' Lister les touches de fonction apres avoir defini F1 (groupe 2, fonction 8)
20 fkey 1, "Liste"
30 while peek($ff00) : wend
40 poke $ff01, 8 : poke $ff00, 2
50 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Liste"
65C02 assembly (64tass)
; Lister les touches de fonction après avoir défini F1 (groupe 2, 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
        lda #1
        sta ControlPort+4          ; F1
        lda #<texte
        sta ControlPort+6
        lda #>texte
        sta ControlPort+7
        lda #2
        ldx #4                     ; 2,4 : Define Hotkey
        jsr appel
        jsr WaitMessage
        lda #2
        ldx #8                     ; fonction 8 : List Hotkeys
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

texte:  .byte 5
        .text "Liste"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
F1  : "Liste"
F8  : ""

2,9 Screen Size Official

Gives the console size in characters.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8height (number of rows)
P1uint8width (number of columns)

Mind the order: the height comes first. The size depends on the video mode (5,9).

Firmware documentation text

Returns the console size in characters, in Parameter:0 (height) and Parameter:1 (width).

C (llvm-mos)
/* Taille de la console (groupe 2, fonction 9). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    uint8_t largeur, hauteur;
    neo_console_screen_size(&largeur, &hauteur);
    printf("Console : %u colonnes, %u lignes\n", largeur, hauteur);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Console : 53 colonnes, 30 lignes
Mad Pascal
// Taille de la console (groupe 2, fonction 9).
program taille;
uses crt, neo6502;
var hauteur, largeur: byte;
begin
  NeoGetScreenSize(hauteur, largeur);
  writeln('Console : ', largeur, ' colonnes, ', hauteur, ' lignes');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Console : 30 colonnes, 53 lignes
NeoBASIC
10 ' Taille de la console (groupe 2, fonction 9)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 9 : poke $ff00, 2
50 while peek($ff00) : wend : h = peek($ff04) : l = peek($ff05)
60 print "Console : ";l;" colonnes, ";h;" lignes"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Console : 30 colonnes, 53 lignes
65C02 assembly (64tass)
; Taille de la console (groupe 2, 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:  jsr WaitMessage
        lda #2
        ldx #9                     ; fonction 9 : Screen Size
        jsr appel
        lda ControlPort+4          ; P0 : hauteur
        sta hauteur
        lda ControlPort+5          ; P1 : largeur
        sta largeur
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda largeur
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda hauteur
        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

hauteur: .byte 0
largeur: .byte 0
m1:      .text "Console : ", 0
m2:      .text " colonnes, ", 0
m3:      .text " lignes", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Console : 30 colonnes, 53 lignes

2,10 Insert Line Official

Inserts a blank line at the given row; the following rows move down, the last row of the screen is lost.

Inputs
BytesTypeMeaning
P0uint8row number (0 = top)

Outputs: none.

A console support function (the editor uses it); the firmware documentation advises against using it directly.

Firmware documentation text

This is a support function which inserts a blank line in the console and should not be used.

C (llvm-mos)
/* Insérer une ligne vide entre A et B (groupe 2, fonction 10). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

int main(void) {
    libre();
    api(2, 12);                                 /* écran vide : les lignes sont en haut */
    printf("Ligne A\nLigne B\nLigne C\n");
    libre();
    api(2, 13);                                 /* Cursor Position */
    uint8_t y = ControlPort.params[1];          /* ligne sous « Ligne C » */
    libre();
    ControlPort.params[0] = y - 2;              /* la ligne de « Ligne B » */
    api(2, 10);                                 /* Insert Line */
    libre();
    ControlPort.params[0] = 0;
    ControlPort.params[1] = y + 1;              /* sous les lignes décalées */
    api(2, 7);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A

Ligne B
Ligne C
Mad Pascal
// Insérer une ligne vide entre A et B (groupe 2, fonction 10).
program insline;
uses crt, neo6502;
var x, y: byte;
begin
  NeoSendMessage(2, 12);                        // écran vide : les lignes sont en haut
  NeoWaitMessage;
  writeln('Ligne A'); writeln('Ligne B'); writeln('Ligne C');
  NeoGetCursorPos(x, y);                        // ligne sous « Ligne C »
  NeoWaitMessage;
  NeoMessage.params[0] := y - 2;                // la ligne de « Ligne B »
  NeoSendMessage(2, 10);                        // Insert Line
  NeoWaitMessage;
  NeoMessage.params[0] := 0;
  NeoMessage.params[1] := y + 1;                // sous les lignes décalées
  NeoSendMessage(2, 7);
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A

Ligne B
Ligne C
NeoBASIC
10 ' Inserer une ligne vide entre A et B (groupe 2, fonction 10)
15 while peek($ff00) : wend : poke $ff01, 12 : poke $ff00, 2 : ' ecran vide
20 print "Ligne A" : print "Ligne B" : print "Ligne C"
30 while peek($ff00) : wend
40 poke $ff01, 13 : poke $ff00, 2
50 while peek($ff00) : wend : y = peek($ff05)
60 poke $ff04, y - 2 : poke $ff01, 10 : poke $ff00, 2
70 while peek($ff00) : wend
80 cursor 0, y + 1
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A

Ligne B
Ligne C
65C02 assembly (64tass)
; Insérer une ligne vide entre A et B (groupe 2, 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
        lda #2
        ldx #12                    ; écran vide : les lignes sont en haut
        jsr appel
        lda #<lignes
        ldx #>lignes
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #13                    ; Cursor Position
        jsr appel
        lda ControlPort+5          ; ligne sous « Ligne C »
        sta posy
        jsr WaitMessage
        sec
        sbc #2
        sta ControlPort+4          ; P0 : la ligne de « Ligne B »
        lda #2
        ldx #10                    ; fonction 10 : Insert Line
        jsr appel
        jsr WaitMessage
        stz ControlPort+4
        lda posy
        inc a
        sta ControlPort+5          ; sous les lignes décalées
        lda #2
        ldx #7
        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

posy:   .byte 0
lignes: .text "Ligne A", 13, "Ligne B", 13, "Ligne C", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A

Ligne B
Ligne C

2,11 Delete Line Official

Deletes the given row; the following rows move up, a blank row appears at the bottom of the screen.

Inputs
BytesTypeMeaning
P0uint8row number (0 = top)

Outputs: none.

A console support function (the editor uses it); the firmware documentation advises against using it directly.

Firmware documentation text

This is a support function which deletes a line in the console and should not be used.

C (llvm-mos)
/* Supprimer la ligne « Ligne B » (groupe 2, fonction 11). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

int main(void) {
    libre();
    api(2, 12);                                 /* écran vide : les lignes sont en haut */
    printf("Ligne A\nLigne B\nLigne C\n");
    libre();
    api(2, 13);                                 /* Cursor Position */
    uint8_t y = ControlPort.params[1];
    libre();
    ControlPort.params[0] = y - 2;              /* la ligne de « Ligne B » */
    api(2, 11);                                 /* Delete Line */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A
Ligne C
Mad Pascal
// Supprimer la ligne « Ligne B » (groupe 2, fonction 11).
program delline;
uses crt, neo6502;
var x, y: byte;
begin
  NeoSendMessage(2, 12);                        // écran vide : les lignes sont en haut
  NeoWaitMessage;
  writeln('Ligne A'); writeln('Ligne B'); writeln('Ligne C');
  NeoGetCursorPos(x, y);
  NeoWaitMessage;
  NeoMessage.params[0] := y - 2;                // la ligne de « Ligne B »
  NeoSendMessage(2, 11);                        // Delete Line
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A
Ligne C
NeoBASIC
10 ' Supprimer la ligne "Ligne B" (groupe 2, fonction 11)
15 while peek($ff00) : wend : poke $ff01, 12 : poke $ff00, 2 : ' ecran vide
20 print "Ligne A" : print "Ligne B" : print "Ligne C"
30 while peek($ff00) : wend
40 poke $ff01, 13 : poke $ff00, 2
50 while peek($ff00) : wend : y = peek($ff05)
60 poke $ff04, y - 2 : poke $ff01, 11 : poke $ff00, 2
70 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A
Ligne C
65C02 assembly (64tass)
; Supprimer la ligne « Ligne B » (groupe 2, fonction 11).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #2
        ldx #12                    ; écran vide : les lignes sont en haut
        jsr appel
        lda #<lignes
        ldx #>lignes
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #13                    ; Cursor Position
        jsr appel
        lda ControlPort+5
        jsr WaitMessage
        sec
        sbc #2
        sta ControlPort+4          ; P0 : la ligne de « Ligne B »
        lda #2
        ldx #11                    ; fonction 11 : Delete Line
        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

lignes: .text "Ligne A", 13, "Ligne B", 13, "Ligne C", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ligne A
Ligne C

2,12 Clear Screen Official

Clears the console screen and puts the cursor back at the top left.

Inputs: none.

Outputs: none.

Control code 12 sent through 2,6 has the same effect. Cursor visibility (2,19) is restored.

Firmware documentation text

Clears the screen.

C (llvm-mos)
/* Effacer l'écran (groupe 2, fonction 12). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    printf("Ce texte va disparaitre\n");
    neo_console_clear_screen();
    printf("Ecran efface\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecran efface
Mad Pascal
// Effacer l'écran (groupe 2, fonction 12).
program cls;
uses crt, neo6502;
begin
  writeln('Ce texte va disparaitre');
  NeoSendMessage(2, 12);                        // Clear Screen
  NeoWaitMessage;
  writeln('Ecran efface');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecran efface
NeoBASIC
10 ' Effacer l'ecran (groupe 2, fonction 12)
20 print "Ce texte va disparaitre"
30 while peek($ff00) : wend
40 poke $ff01, 12 : poke $ff00, 2
50 while peek($ff00) : wend
60 print "Ecran efface"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecran efface
65C02 assembly (64tass)
; Effacer l'écran (groupe 2, fonction 12).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<avant
        ldx #>avant
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #12                    ; fonction 12 : Clear Screen
        jsr appel
        lda #<apres
        ldx #>apres
        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

avant:  .text "Ce texte va disparaitre", 13, 0
apres:  .text "Ecran efface", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ecran efface

2,13 Cursor Position Official

Gives the cursor position (column, row).

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8column
P1uint8row

NeoBASIC keywords that make this call: print

Firmware documentation text

Returns the current screen character cell of the cursor in Parameter:0 (X), Parameter:1 (Y).

C (llvm-mos)
/* Position du curseur après un texte de 7 caractères (groupe 2, fonction 13). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    uint8_t x, y;
    printf("Bonjour");                          /* 7 caractères, sans retour à la ligne */
    neo_console_cursor_pos(&x, &y);
    printf("\nCurseur : colonne %u, ligne %u\n", x, y);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
Curseur : colonne 7, ligne 27
Mad Pascal
// Position du curseur après un texte de 7 caractères (groupe 2, fonction 13).
program position;
uses crt, neo6502;
var x, y: byte;
begin
  write('Bonjour');                             // 7 caractères, sans retour à la ligne
  NeoGetCursorPos(x, y);
  writeln;
  writeln('Curseur : colonne ', x, ', ligne ', y);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
Curseur : colonne 7, ligne 27
NeoBASIC
10 ' Position du curseur apres un texte de 7 caracteres (groupe 2, fonction 13)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 print "Bonjour";
40 while peek($ff00) : wend
50 poke $ff01, 13 : poke $ff00, 2
60 while peek($ff00) : wend : x = peek($ff04) : y = peek($ff05)
70 print
80 print "Curseur : colonne ";x;", ligne ";y
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
Curseur : colonne 7, ligne 29
65C02 assembly (64tass)
; Position du curseur après un texte de 7 caractères (groupe 2, 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:  lda #<texte
        ldx #>texte
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #13                    ; fonction 13 : Cursor Position
        jsr appel
        lda ControlPort+4          ; recopier avant d'afficher
        sta posx
        lda ControlPort+5
        sta posy
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda posx
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda posy
        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

posx:   .byte 0
posy:   .byte 0
texte:  .text "Bonjour", 0
m1:     .text 13, "Curseur : colonne ", 0
m2:     .text ", ligne ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bonjour
Curseur : colonne 7, ligne 27

2,14 Clear Region Official

Clears a rectangle of the screen, bounds included.

Inputs
BytesTypeMeaning
P0uint8start column
P1uint8start row
P2uint8end column (included)
P3uint8end row (included)

Outputs: none.

Bounds are clipped to the screen; the rectangle is filled with spaces in the current colours.

Firmware documentation text

Erase all characters within the rectangular region specified in Parameters:0,1 (begin X,Y) and Parameters:2,3 (end X,Y).

C (llvm-mos)
/* Creuser les colonnes 2 à 5 de trois lignes (groupe 2, fonction 14). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    uint8_t x, y;
    printf("XXXXXXXXXX\nXXXXXXXXXX\nXXXXXXXXXX\n");
    neo_console_cursor_pos(&x, &y);
    neo_console_clear_region(2, y - 3, 5, y - 1);   /* colonnes 2 à 5 comprises */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
XX    XXXX
XX    XXXX
XX    XXXX
Mad Pascal
// Creuser les colonnes 2 à 5 de trois lignes (groupe 2, fonction 14).
program region;
uses crt, neo6502;
var x, y: byte;
begin
  writeln('XXXXXXXXXX'); writeln('XXXXXXXXXX'); writeln('XXXXXXXXXX');
  NeoGetCursorPos(x, y);
  NeoClearRegion(2, y - 3, 5, y - 1);           // colonnes 2 à 5 comprises
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
XX    XXXX
XX    XXXX
XX    XXXX
NeoBASIC
10 ' Creuser les colonnes 2 a 5 de trois lignes (groupe 2, fonction 14)
20 for i = 1 to 3 : print "XXXXXXXXXX" : next i
30 while peek($ff00) : wend
40 poke $ff01, 13 : poke $ff00, 2
50 while peek($ff00) : wend : y = peek($ff05)
60 poke $ff04, 2 : poke $ff05, y - 3 : poke $ff06, 5 : poke $ff07, y - 1 : poke $ff01, 14 : poke $ff00, 2
70 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
XX    XXXX
XX    XXXX
XX    XXXX
65C02 assembly (64tass)
; Creuser les colonnes 2 à 5 de trois lignes (groupe 2, 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 #<lignes
        ldx #>lignes
        jsr ecrire
        jsr WaitMessage
        lda #2
        ldx #13                    ; Cursor Position
        jsr appel
        ldy ControlPort+5          ; ligne sous le bloc
        jsr WaitMessage
        lda #2
        sta ControlPort+4          ; P0 : colonne 2
        tya
        sec
        sbc #3
        sta ControlPort+5          ; P1 : première ligne du bloc
        lda #5
        sta ControlPort+6          ; P2 : colonne 5 (comprise)
        dey
        sty ControlPort+7          ; P3 : dernière ligne du bloc
        lda #2
        ldx #14                    ; fonction 14 : Clear Region
        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

lignes: .text "XXXXXXXXXX", 13, "XXXXXXXXXX", 13, "XXXXXXXXXX", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
XX    XXXX
XX    XXXX
XX    XXXX

2,15 Set Text Color Official

Selects the text and background colours for the characters written afterwards.

Inputs
BytesTypeMeaning
P0uint8text colour (0 to 15)
P1uint8background colour (0 to 15)

Outputs: none.

Codes $80-$8F and $90-$9F written through 2,6 do the same, character by character. 2,18 reads the current colours back, to restore them.

Firmware documentation text

Sets the foreground colour to Parameter:0 and the background colour to Parameter:1.

C (llvm-mos)
/* Écrire en couleur, puis rétablir les couleurs (groupe 2, fonctions 15 et 18). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    uint8_t encre, papier;
    neo_console_get_text_color(&encre, &papier);  /* 2,18 : couleurs en cours */
    neo_console_set_text_color(3, 1);             /* texte 3 sur fond 1 */
    printf("Texte en couleur");
    neo_console_set_text_color(encre, papier);    /* rétablir */
    printf("\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Texte en couleur
Mad Pascal
// Écrire en couleur, puis rétablir les couleurs (groupe 2, fonctions 15 et 18).
program couleur;
uses crt, neo6502;
var encre, papier: byte;
begin
  NeoSendMessage(2, 18);                        // Read Ink/Paper Colours
  NeoWaitMessage;
  encre := NeoMessage.params[0];
  papier := NeoMessage.params[1];
  NeoSetTextColor(3, 1);                        // texte 3 sur fond 1
  NeoWaitMessage;
  write('Texte en couleur');
  NeoSetTextColor(encre, papier);               // rétablir
  NeoWaitMessage;
  writeln;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Texte en couleur
NeoBASIC
10 ' Ecrire en couleur, puis retablir les couleurs (groupe 2, fonctions 15 et 18)
20 while peek($ff00) : wend
30 poke $ff01, 18 : poke $ff00, 2
40 while peek($ff00) : wend : e = peek($ff04) : p = peek($ff05)
50 poke $ff04, 3 : poke $ff05, 1 : poke $ff01, 15 : poke $ff00, 2
60 while peek($ff00) : wend
70 print "Texte en couleur";
80 while peek($ff00) : wend
90 poke $ff04, e : poke $ff05, p : poke $ff01, 15 : poke $ff00, 2
100 while peek($ff00) : wend
110 print
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Texte en couleur
65C02 assembly (64tass)
; Écrire en couleur, puis rétablir les couleurs (groupe 2, fonctions 15 et 18).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #2
        ldx #18                    ; 2,18 : couleurs en cours
        jsr appel
        lda ControlPort+4
        sta encre
        lda ControlPort+5
        sta papier
        jsr WaitMessage
        lda #3
        sta ControlPort+4          ; P0 : texte 3
        lda #1
        sta ControlPort+5          ; P1 : fond 1
        lda #2
        ldx #15                    ; fonction 15 : Set Text Color
        jsr appel
        lda #<texte
        ldx #>texte
        jsr ecrire
        jsr WaitMessage
        lda encre                  ; rétablir
        sta ControlPort+4
        lda papier
        sta ControlPort+5
        lda #2
        ldx #15
        jsr appel
        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

encre:  .byte 0
papier: .byte 0
texte:  .text "Texte en couleur", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Texte en couleur

2,16 Cursor Inverse Official

Swaps the colours (text and background) of the cursor cell; a second call restores them.

Inputs: none.

Outputs: none.

A support function (cursor blinking); the firmware documentation advises against using it.

Firmware documentation text

Toggles the cursor colour between normal and inverse (ie: swaps FG and BG colors). This should not be used.

C (llvm-mos)
/* Inverser la case du curseur, puis la rétablir (groupe 2, fonction 16). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

int main(void) {
    libre();
    api(2, 16);                                 /* Cursor Inverse */
    libre();
    api(2, 16);                                 /* et retour */
    printf("Case du curseur inversee deux fois\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Case du curseur inversee deux fois
Mad Pascal
// Inverser la case du curseur, puis la rétablir (groupe 2, fonction 16).
program inverse;
uses crt, neo6502;
begin
  NeoCursorInverse;                             // Cursor Inverse
  NeoWaitMessage;
  NeoCursorInverse;                             // et retour
  NeoWaitMessage;
  writeln('Case du curseur inversee deux fois');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Case du curseur inversee deux fois
NeoBASIC
10 ' Inverser la case du curseur, puis la retablir (groupe 2, fonction 16)
20 for i = 1 to 2
30 while peek($ff00) : wend
40 poke $ff01, 16 : poke $ff00, 2
50 next i
60 while peek($ff00) : wend
70 print "Case du curseur inversee deux fois"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Case du curseur inversee deux fois
65C02 assembly (64tass)
; Inverser la case du curseur, puis la rétablir (groupe 2, 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
        lda #2
        ldx #16                    ; fonction 16 : Cursor Inverse
        jsr appel
        jsr WaitMessage
        lda #2
        ldx #16                    ; et retour
        jsr appel
        lda #<texte
        ldx #>texte
        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

texte:  .text "Case du curseur inversee deux fois", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Case du curseur inversee deux fois

2,17 Tab() implementation Official

Writes spaces until the cursor reaches the given column (used by NeoBASIC tab()).

Inputs
BytesTypeMeaning
P0uint8column to reach

Outputs: none.

If the cursor is already beyond, nothing is written. In NeoBASIC, tab(n) inside a print makes the same call.

NeoBASIC keywords that make this call: tab()

Firmware documentation text

Internal helper.

C (llvm-mos)
/* Aligner B en colonne 10 (groupe 2, fonction 17). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

int main(void) {
    printf("A");
    libre();
    ControlPort.params[0] = 10;                 /* colonne à atteindre */
    api(2, 17);                                 /* Tab */
    printf("B\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
A         B
Mad Pascal
// Aligner B en colonne 10 (groupe 2, fonction 17).
program tab;
uses crt, neo6502;
begin
  write('A');
  NeoWaitMessage;
  NeoMessage.params[0] := 10;                   // colonne à atteindre
  NeoSendMessage(2, 17);                        // Tab
  NeoWaitMessage;
  writeln('B');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
A         B
NeoBASIC
10 ' Aligner B en colonne 10 (groupe 2, fonction 17)
20 print "A";tab(10);"B"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
A         B
65C02 assembly (64tass)
; Aligner B en colonne 10 (groupe 2, fonction 17).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #'A'
        jsr WriteCharacter
        jsr WaitMessage
        lda #10
        sta ControlPort+4          ; P0 : colonne à atteindre
        lda #2
        ldx #17                    ; fonction 17 : Tab
        jsr appel
        lda #'B'
        jsr WriteCharacter
        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
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
A         B

2,18 Read Ink/Paper Colours Official

Gives the current text (ink) and background (paper) colours.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8text colour
P1uint8background colour
Firmware documentation text

Read the ink/paper colours into Param[0] and Param[1]

C (llvm-mos)
/* Couleurs en cours (groupe 2, fonction 18). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    uint8_t encre, papier;
    neo_console_get_text_color(&encre, &papier);
    printf("Encre : %u, papier : %u\n", encre, papier);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Encre : 2, papier : 0
Mad Pascal
// Couleurs en cours (groupe 2, fonction 18).
program couleurs;
uses crt, neo6502;
var encre, papier: byte;
begin
  NeoSendMessage(2, 18);                        // Read Ink/Paper Colours
  NeoWaitMessage;
  encre := NeoMessage.params[0];
  papier := NeoMessage.params[1];
  writeln('Encre : ', encre, ', papier : ', papier);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Encre : 2, papier : 0
NeoBASIC
10 ' Couleurs en cours (groupe 2, fonction 18)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 18 : poke $ff00, 2
50 while peek($ff00) : wend : e = peek($ff04) : p = peek($ff05)
60 print "Encre : ";e;", papier : ";p
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Encre : 2, papier : 0
65C02 assembly (64tass)
; Couleurs en cours (groupe 2, fonction 18).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #2
        ldx #18                    ; fonction 18 : Read Ink/Paper Colours
        jsr appel
        lda ControlPort+4
        sta encre
        lda ControlPort+5
        sta papier
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda encre
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda papier
        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

encre:  .byte 0
papier: .byte 0
m1:     .text "Encre : ", 0
m2:     .text ", papier : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Encre : 2, papier : 0

2,19 Show/Hide Cursor Reversing Official

Shows or hides the blinking cursor.

Inputs
BytesTypeMeaning
P0uint8non zero: visible, 0: hidden

Outputs: none.

Clearing the screen (2,12) makes the cursor visible again.

Firmware documentation text

Set the cursor visibility to Param[0]. This is reset by clearing the screen.

C (llvm-mos)
/* Cacher le curseur, puis le réafficher (groupe 2, fonction 19). */
#include <stdio.h>
#include <neo/api.h>

int main(void) {
    neo_console_set_cursor_visibility(0);       /* caché */
    neo_console_set_cursor_visibility(1);       /* visible */
    printf("Curseur cache puis reaffiche\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Curseur cache puis reaffiche
Mad Pascal
// Cacher le curseur, puis le réafficher (groupe 2, fonction 19).
program visibilite;
uses crt, neo6502;

procedure curseur(visible: byte);
begin
  NeoWaitMessage;
  NeoMessage.params[0] := visible;
  NeoSendMessage(2, 19);                        // Show/Hide Cursor
  NeoWaitMessage;
end;

begin
  curseur(0);
  curseur(1);
  writeln('Curseur cache puis reaffiche');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Curseur cache puis reaffiche
NeoBASIC
10 ' Cacher le curseur, puis le reafficher (groupe 2, fonction 19)
20 for v = 0 to 1
30 while peek($ff00) : wend
40 poke $ff04, v : poke $ff01, 19 : poke $ff00, 2
50 next v
60 while peek($ff00) : wend
70 print "Curseur cache puis reaffiche"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Curseur cache puis reaffiche
65C02 assembly (64tass)
; Cacher le curseur, puis le réafficher (groupe 2, fonction 19).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #0                     ; caché
        jsr visible
        lda #1                     ; visible
        jsr visible
        lda #<texte
        ldx #>texte
        jmp ecrire

visible:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0 : visibilité
        lda #2
        ldx #19                    ; fonction 19 : Show/Hide Cursor
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

texte:  .text "Curseur cache puis reaffiche", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Curseur cache puis reaffiche

2,20 Console Debug Echo Trinity

Copies everything written to the console to the debug port (the GP28/GP29 UART on the board): a PC can thus capture the screen text.

Inputs
BytesTypeMeaning
P0uint80: off; 1: printable characters and Enter (as CR LF); 2: also characters $A0-$FF

Outputs: none.

In the emulators, the echo goes to stderr.

Firmware documentation text

Parameter:0 non zero : every printable character written to the console (and Enter, as CR LF) is also sent to the debug port (UART GP28/GP29 on the board, stderr in the emulators) ; 2 also forwards the characters $A0-$FF. 0 stops the echo. Lets a PC capture the screen text of a real board over the serial link (Trinity T-20, F-92 of the fork).

C (llvm-mos)
/* Recopier la console vers le port de débogage le temps d'une ligne (groupe 2, fonction 20). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

static void echo(uint8_t mode) {
    libre();
    ControlPort.params[0] = mode;
    api(2, 20);                                 /* Console Debug Echo */
}

int main(void) {
    echo(1);
    printf("Ce texte part aussi sur le port de debogage\n");
    echo(0);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ce texte part aussi sur le port de debogage
Mad Pascal
// Recopier la console vers le port de débogage le temps d'une ligne (groupe 2, fonction 20).
program echo;
uses crt, neo6502;

procedure echo(mode: byte);
begin
  NeoWaitMessage;
  NeoMessage.params[0] := mode;
  NeoSendMessage(2, 20);                        // Console Debug Echo
  NeoWaitMessage;
end;

begin
  echo(1);
  writeln('Ce texte part aussi sur le port de debogage');
  echo(0);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ce texte part aussi sur le port de debogage
NeoBASIC
10 ' Recopier la console vers le port de debogage le temps d'une ligne (groupe 2, fonction 20)
20 while peek($ff00) : wend
30 poke $ff04, 1 : poke $ff01, 20 : poke $ff00, 2
40 while peek($ff00) : wend
50 print "Ce texte part aussi sur le port de debogage"
60 while peek($ff00) : wend
70 poke $ff04, 0 : poke $ff01, 20 : poke $ff00, 2
80 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ce texte part aussi sur le port de debogage
65C02 assembly (64tass)
; Recopier la console vers le port de débogage le temps d'une ligne (groupe 2, 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:  lda #1
        jsr echo
        lda #<texte
        ldx #>texte
        jsr ecrire
        lda #0
echo:   pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0 : mode d'écho
        lda #2
        ldx #20                    ; fonction 20 : Console Debug Echo
        jmp appel

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

texte:  .text "Ce texte part aussi sur le port de debogage", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Ce texte part aussi sur le port de debogage

2,21 Set Console Font Trinity

Replaces the console font for characters $20-$7F with a font in RAM; address 0 restores the built-in font.

Inputs
BytesTypeMeaning
P0-P1addr96 glyphs of 8 bytes (one byte per row, bit 7 = leftmost pixel), $20 to $7F; 0: built-in font
P2-P3addr96 glyphs of 14 bytes for the 9×14 cells of Hercules mode (1); 0: keep the built-in 8×14 font
Outputs
BytesTypeMeaning
erreuruint8non zero if the glyphs would run past the end of memory

The font is read in place at every repaint, with no copy: keep it intact while it is selected. The whole console is repainted. A mode change (5,9) or a reset restores the built-in font. Characters $A0-$BF (Latin-1 symbols) and $C0-$FF (2,5) are unchanged.

Firmware documentation text

Selects the font used by the console for the characters $20-$7F (Trinity T-20, F-95 of the fork). On input:

Parameters:0,1 is the address, in 6502 RAM, of 96 glyphs of 8 bytes (one byte per row, bit 7 = leftmost pixel ; the console draws the 6 leftmost columns in 6x8 cells and all 8 in 8x8 cells), in ASCII order from $20 to $7F ; $0000 restores the built in font.

Parameters:2,3 is likewise the address of 96 glyphs of 14 bytes (8 columns) used by the 9x14 cells of the Hercules mode 1 ; $0000 keeps the built in 8x14 font. Each address is checked and applied on its own.

The glyphs are read in place at every repaint (no copy) : the program must keep them intact while the font is selected. The whole console is repainted. Characters $A0-$BF keep the built in Latin-1 symbols and $C0-$FF the user defined characters (Function 2,5 ; Latin-1 letters by default). The built in font is restored by a mode change (5,9) and at reset. Sets the error flag if the glyphs would run past the end of memory.

C (llvm-mos)
/* Remplacer la police par des cadres, puis rétablir l'originale (groupe 2, fonction 21). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

static uint8_t police[96 * 8];                  /* 96 caractères de 8 lignes */

static void choisir(uint16_t adresse) {
    libre();
    ControlPort.params[0] = adresse & 0xFF;
    ControlPort.params[1] = adresse >> 8;
    ControlPort.params[2] = 0;                  /* mode Hercules : police intégrée */
    ControlPort.params[3] = 0;
    api(2, 21);                                 /* Set Console Font */
}

int main(void) {
    static const uint8_t cadre[8] = { 0x00, 0xFC, 0x84, 0x84, 0x84, 0x84, 0xFC, 0x00 };
    for (unsigned i = 0; i < sizeof police; i++)
        police[i] = cadre[i % 8];
    choisir((uint16_t)police);
    printf("Police remplacee\n");
    choisir(0);                                 /* police intégrée */
    printf("Police d'origine\n");
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Police remplacee
Police d'origine
Mad Pascal
// Remplacer la police par des cadres, puis rétablir l'originale (groupe 2, fonction 21).
program police;
uses crt, neo6502;
const cadre: array[0..7] of byte = ($00, $FC, $84, $84, $84, $84, $FC, $00);
var fonte: array[0..767] of byte;               // 96 caractères de 8 lignes
    i: word;

procedure choisir(adresse: word);
begin
  NeoWaitMessage;
  wordParams[0] := adresse;
  wordParams[1] := 0;                           // mode Hercules : police intégrée
  NeoSendMessage(2, 21);                        // Set Console Font
  NeoWaitMessage;
end;

begin
  for i := 0 to 767 do fonte[i] := cadre[i and 7];
  choisir(word(@fonte));
  writeln('Police remplacee');
  choisir(0);                                   // police intégrée
  writeln('Police d''origine');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Police remplacee
Police d'origine
NeoBASIC
10 ' Remplacer la police par des cadres, puis retablir l'originale (groupe 2, fonction 21)
20 a = alloc(768)
30 for i = 0 to 95 : for r = 0 to 7 : read v : poke a + i * 8 + r, v : next r : restore : next i
40 data 0, $fc, $84, $84, $84, $84, $fc, 0
50 while peek($ff00) : wend
60 poke $ff04, a & 255 : poke $ff05, a >> 8 : poke $ff06, 0 : poke $ff07, 0 : poke $ff01, 21 : poke $ff00, 2
70 while peek($ff00) : wend
80 print "Police remplacee"
90 while peek($ff00) : wend
100 poke $ff04, 0 : poke $ff05, 0 : poke $ff06, 0 : poke $ff07, 0 : poke $ff01, 21 : poke $ff00, 2
110 while peek($ff00) : wend
120 print "Police d'origine"
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Police remplacee
Police d'origine
65C02 assembly (64tass)
; Remplacer la police par des cadres, puis rétablir l'originale (groupe 2, 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

POLICE = $4000                     ; 96 caractères de 8 lignes = 768 octets

start:  lda #<POLICE               ; remplir la police : le même cadre partout
        sta ptr
        lda #>POLICE
        sta ptr+1
        ldx #96
_car:   ldy #7
_lig:   lda cadre,y
        sta (ptr),y
        dey
        bpl _lig
        clc
        lda ptr
        adc #8
        sta ptr
        bcc _s
        inc ptr+1
_s:     dex
        bne _car
        lda #<POLICE
        ldx #>POLICE
        jsr choisir
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda #0                     ; police intégrée
        tax
        jsr choisir
        lda #<m2
        ldx #>m2
        jmp ecrire

; A/X = adresse de la police (0 : intégrée).
choisir:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0-P1 : police 8×8
        stx ControlPort+5
        stz ControlPort+6          ; P2-P3 : 0, police Hercules intégrée
        stz ControlPort+7
        lda #2
        ldx #21                    ; fonction 21 : Set Console Font
        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

cadre:  .byte $00, $FC, $84, $84, $84, $84, $FC, $00
m1:     .text "Police remplacee", 13, 0
m2:     .text "Police d'origine", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Police remplacee
Police d'origine

2,22 Get Media Key Trinity

Gives the last multimedia key of the USB keyboard (volume, play, next track…) and the system keys, then clears them.

Inputs: none.

Outputs
BytesTypeMeaning
P0-P1uint16Consumer Control usage (HID page $0C): $00E9 volume up, $00EA volume down, $00E2 mute, $00CD play/pause, $00B5 next, $00B6 previous, $0223 home…; 0: nothing
P2uint8system keys: bit 0 sleep, bit 1 power, bit 2 wake

Both values are cleared by the call: a program polls it. Keyboards expose these keys on a second HID interface, which the firmware claims from the gamepad manager.

Firmware documentation text

Returns the last media key pressed on the USB keyboard in Parameters:0,1 (Consumer Control usage, HID usage page $0C : $00E9 volume up, $00EA volume down, $00E2 mute, $00CD play/pause, $00B5 next, $00B6 previous, $0223 home...) and the system keys in Parameter:2 (bit 0 sleep, bit 1 power, bit 2 wake). Both are cleared by this call, so a program polls it ; 0 means nothing pressed since the last call. Keyboards expose these keys on a second HID interface without boot protocol, which the firmware claims from the gamepad manager (Trinity T-39).

C (llvm-mos)
/* Dernière touche multimédia (groupe 2, fonction 22). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

int main(void) {
    libre();
    api(2, 22);                                 /* Get Media Key */
    uint16_t touche = ControlPort.params[0] | (ControlPort.params[1] << 8);
    uint8_t systeme = ControlPort.params[2];
    printf("Touche multimedia : %u, systeme : %u\n", touche, systeme);   /* 0 : rien */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Touche multimedia : 0, systeme : 0
Mad Pascal
// Dernière touche multimédia (groupe 2, fonction 22).
program media;
uses crt, neo6502;
var touche: word;
    systeme: byte;
begin
  NeoSendMessage(2, 22);                        // Get Media Key
  NeoWaitMessage;
  touche := wordParams[0];
  systeme := NeoMessage.params[2];
  writeln('Touche multimedia : ', touche, ', systeme : ', systeme);   // 0 : rien
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Touche multimedia : 0, systeme : 0
NeoBASIC
10 ' Derniere touche multimedia (groupe 2, fonction 22)
20 ' lire les resultats dans des variables juste apres l'appel, avant tout calcul : print et * reutilisent la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 22 : poke $ff00, 2
50 while peek($ff00) : wend : t0 = peek($ff04) : t1 = peek($ff05) : s = peek($ff06) : t = t0 + 256 * t1
60 print "Touche multimedia : ";t;", systeme : ";s
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Touche multimedia : 0, systeme : 0
65C02 assembly (64tass)
; Dernière touche multimédia (groupe 2, fonction 22) : affiche l'octet de poids faible.
        .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 #2
        ldx #22                    ; fonction 22 : Get Media Key
        jsr appel
        lda ControlPort+4          ; P0 : code (poids faible)
        sta touche
        lda ControlPort+6          ; P2 : touches système
        sta systeme
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda touche
        jsr decimal
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda systeme
        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

touche:  .byte 0
systeme: .byte 0
m1:      .text "Touche multimedia : ", 0
m2:      .text ", systeme : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Touche multimedia : 0, systeme : 0

2,23 Get Lock Keys Trinity

Gives the state of the USB keyboard lock keys: Num Lock, Caps Lock, Scroll Lock.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8bit 0 Num Lock, bit 1 Caps Lock, bit 2 Scroll Lock

The firmware toggles these states on each press and lights the keyboard LEDs. Caps Lock swaps the case of letters only; Num Lock gives the keypad its figures; Scroll Lock is only a state, free for the program. Num Lock starts off.

Firmware documentation text

Returns in Parameter:0 the state of the lock keys of the USB keyboard : bit 0 Num Lock, bit 1 Caps Lock, bit 2 Scroll Lock (Trinity T-40). The firmware toggles them on each press and lights the matching LEDs on the keyboard, which the upstream never did. They also drive how keys are read (Trinity T-41) : Caps Lock swaps the case of the letters only, Num Lock gives the numeric keypad its figures (off : the navigation keys printed on the keys). Scroll Lock is only a state and a LED, for the program to use as it likes. Num Lock starts off.

C (llvm-mos)
/* État des touches de verrouillage (groupe 2, fonction 23). */
#include <stdio.h>
#include <neo6502.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}

static const char *oui_non(uint8_t b) { return b ? "oui" : "non"; }

int main(void) {
    libre();
    api(2, 23);                                 /* Get Lock Keys */
    uint8_t v = ControlPort.params[0];
    printf("Verr. Num : %s, Verr. Maj : %s, Arret defil : %s\n",
           oui_non(v & 1), oui_non(v & 2), oui_non(v & 4));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Verr. Num : non, Verr. Maj : non, Arret defil : non
Mad Pascal
// État des touches de verrouillage (groupe 2, fonction 23).
program verrous;
uses crt, neo6502;
var v: byte;

function oui_non(b: byte): string;
begin
  if b <> 0 then result := 'oui' else result := 'non';
end;

begin
  NeoSendMessage(2, 23);                        // Get Lock Keys
  NeoWaitMessage;
  v := NeoMessage.params[0];
  writeln('Verr. Num : ', oui_non(v and 1), ', Verr. Maj : ', oui_non(v and 2),
          ', Arret defil : ', oui_non(v and 4));
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Verr. Num : non, Verr. Maj : non, Arret defil : non
NeoBASIC
10 ' Etat des touches de verrouillage (groupe 2, fonction 23)
20 ' lire les resultats dans des variables juste apres l'appel : print reutilise la boite aux lettres
30 while peek($ff00) : wend
40 poke $ff01, 23 : poke $ff00, 2
50 while peek($ff00) : wend : v = peek($ff04)
60 n$ = "non" : m$ = "non" : d$ = "non"
70 if v & 1 then n$ = "oui"
80 if v & 2 then m$ = "oui"
90 if v & 4 then d$ = "oui"
100 print "Verr. Num : ";n$;", Verr. Maj : ";m$;", Arret defil : ";d$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Verr. Num : non, Verr. Maj : non, Arret defil : non
65C02 assembly (64tass)
; État des touches de verrouillage (groupe 2, fonction 23).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #2
        ldx #23                    ; fonction 23 : Get Lock Keys
        jsr appel
        lda ControlPort+4          ; bit 0 Num, bit 1 Maj, bit 2 Défil
        sta etat
        lda #<m1
        ldx #>m1
        jsr ecrire
        lda #1
        jsr oui_non
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda #2
        jsr oui_non
        lda #<m3
        ldx #>m3
        jsr ecrire
        lda #4
        jsr oui_non
        lda #13
        jmp WriteCharacter

oui_non:
        and etat
        beq _non
        lda #<oui
        ldx #>oui
        jmp ecrire
_non:   lda #<non
        ldx #>non
        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

etat:   .byte 0
m1:     .text "Verr. Num : ", 0
m2:     .text ", Verr. Maj : ", 0
m3:     .text ", Arret defil : ", 0
oui:    .text "oui", 0
non:    .text "non", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Verr. Num : non, Verr. Maj : non, Arret defil : non

← The Neo6502 API