Tachibana
Language: English

Group 5 — Graphics Official

5,1 Set Defaults · 5,2 Draw Line · 5,3 Draw Rectangle · 5,4 Draw Ellipse · 5,5 Draw Pixel · 5,6 Draw Text · 5,7 Draw Image · 5,8 Draw Tilemap · 5,9 Set Graphics Mode · 5,10 Get Graphics Mode · 5,11 Set Draw Page · 5,12 Set Display Page · 5,32 Set Palette · 5,33 Read Pixel · 5,34 Reset Palette · 5,35 Set Tilemap · 5,36 Read Sprite Pixel · 5,37 Frame Count · 5,38 Get Palette · 5,39 Write Pixel · 5,40 Get Late Scanlines · 5,41 Get Bus Stalls · 5,42 Get Bus Timing · 5,64 Set Color · 5,65 Set Solid Flag · 5,66 Set Draw Size · 5,67 Set Flip Bits

Group 5 draws into graphics memory: 320 × 240 pixels in mode 0, one byte per pixel naming a palette colour. Coordinates are signed 16-bit integers (P0-P1 and P2-P3 for the first point, P4-P5 and P6-P7 for the second); whatever falls off the screen is ignored.

The colour of a drawing follows the firmware rule: new pixel = (old pixel AND mask) EXCLUSIVE OR colour. 5,1 sets mask and colour together; 5,64 sets the mask to 0, so the pixel simply takes the given colour.

Images (5,7), tile maps (5,8) and sprites (group 6) are read from a separate graphics memory, filled by loading a file at address $FFFF (3,2). This file starts with a 256-byte header: byte 0 non zero, then the numbers of 16 × 16 tiles, 16 × 16 sprites and 32 × 32 sprites; the images follow, 4 bits per pixel, left pixel in the high nibble, colour 0 being transparent. The examples build such a 384-byte file: one 16 × 16 image, left half colour 2, right half colour 5.

To check what is drawn without a screenshot, each example reads pixels back with 5,33 and prints their colour. Drawings are made at the bottom of the screen, where the console has not written anything yet.

5,1 Set Defaults Official

Sets at once the drawing mask and colour, the fill flag, the size (images and text) and the flip bits.

Inputs
BytesTypeMeaning
P0uint8mask (AND) applied to the old pixel
P1uint8colour (EXCLUSIVE OR)
P2uint8fill: non zero for solid shapes (and a solid background for text and images)
P3uint8size of images and text
P4uint8flip: bit 0 horizontal, bit 1 vertical

Outputs: none.

New pixel = (old AND mask) EXCLUSIVE OR colour. With mask $FF, the colour is combined by EXCLUSIVE OR: drawing the same point twice brings it back to its original colour, as the example shows. In NeoBASIC, ink m, c (or ink c, mask 0), solid, frame and dim make this call.

Firmware documentation text

Configure the global graphics system settings. Not all parameters are relevant for all graphics commands; but all parameters will be set by this command. So mind their values. Refer to Section "Graphics Settings" for details.

The parameters are And, Or, Fill Flag, Extent, and Flip. Bit 0 of flip sets the horizontal flip, Bit 1 sets the vertical flip.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Tracer deux fois le même point en OU EXCLUSIF (groupe 5, fonction 1). */
int main(void) {
    neo_graphics_set_defaults(0xFF, 3, 0, 1, 0);   /* Set Defaults : masque $FF, couleur 3 */
    neo_graphics_draw_pixel(200, 170);          /* 5,5 */
    uint8_t a = neo_graphics_read_pixel(200, 170);
    neo_graphics_draw_pixel(200, 170);          /* même point : 3 XOR 3 = 0 */
    uint8_t b = neo_graphics_read_pixel(200, 170);
    printf("Premier trace : %u, second trace : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Premier trace : 3, second trace : 0
Mad Pascal
// Tracer deux fois le même point en OU EXCLUSIF (groupe 5, fonction 1).
program defauts;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetDefaults($FF, 3, 0, 1, 0);              // Set Defaults : masque $FF, couleur 3
  NeoDrawPixel(200, 170);                       // 5,5
  a := NeoGetPixel(200, 170);
  NeoDrawPixel(200, 170);                       // même point : 3 XOR 3 = 0
  b := NeoGetPixel(200, 170);
  writeln('Premier trace : ', a, ', second trace : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Premier trace : 3, second trace : 0
NeoBASIC
10 ' Tracer deux fois le meme point en OU EXCLUSIF (groupe 5, fonction 1)
20 plot 0,0 ink $ff,3 to 200,170 : a = point(200,170) : ' ink masque, couleur : 5,1
30 plot to 200,170 : b = point(200,170)
40 print "Premier trace : ";a;", second trace : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Premier trace : 3, second trace : 0
65C02 assembly (64tass)
; Tracer deux fois le même point en OU EXCLUSIF (groupe 5, fonction 1).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #$FF
        sta ControlPort+4          ; P0 : masque $FF
        lda #3
        sta ControlPort+5          ; P1 : couleur 3
        stz ControlPort+6          ; P2 : pas de remplissage
        lda #1
        sta ControlPort+7          ; P3 : taille 1
        stz ControlPort+8          ; P4 : pas de retournement
        ldx #1                     ; fonction 1 : Set Defaults
        jsr g5
        jsr trace
        sta a
        jsr trace                  ; même point : 3 XOR 3 = 0
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Trace le point (200, 170) par 5,5 et relit sa couleur.
trace:  lda #200
        ldy #170
        jsr point1
        ldx #5                     ; 5,5 : Draw Pixel
        jsr g5
        lda #200
        ldy #170
        jmp lire

; 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

a:      .byte 0
b:      .byte 0
t0:     .text "Premier trace : ", 0
t2:     .text ", second trace : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Premier trace : 3, second trace : 0

5,2 Draw Line Official

Draws a line between two points.

Inputs
BytesTypeMeaning
P0-P1int16first point X
P2-P3int16first point Y
P4-P5int16second point X
P6-P7int16second point Y

Outputs: none.

In NeoBASIC, line x1,y1 to x2,y2 makes this call (with ink for the colour).

Firmware documentation text

Draw a line between the screen coordinates specified in Parameters:0,1,Parameters:2,3 (begin X,Y) and Parameters:4,5,Parameters:6,7 (end X,Y).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Tracer une ligne horizontale (groupe 5, fonction 2). */
int main(void) {
    neo_graphics_set_color(3);                  /* 5,64 */
    neo_graphics_draw_line(150, 200, 250, 200); /* Draw Line */
    uint8_t a = neo_graphics_read_pixel(200, 200);
    uint8_t b = neo_graphics_read_pixel(200, 201);
    printf("Sur la ligne : %u, juste dessous : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sur la ligne : 3, juste dessous : 0
Mad Pascal
// Tracer une ligne horizontale (groupe 5, fonction 2).
program ligne;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(3);                               // 5,64
  NeoDrawLine(150, 200, 250, 200);              // Draw Line
  a := NeoGetPixel(200, 200);
  b := NeoGetPixel(200, 201);
  writeln('Sur la ligne : ', a, ', juste dessous : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sur la ligne : 3, juste dessous : 0
NeoBASIC
10 ' Tracer une ligne horizontale (groupe 5, fonction 2)
20 line 150,200 ink 3 to 250,200
30 a = point(200,200) : b = point(200,201)
40 print "Sur la ligne : ";a;", juste dessous : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sur la ligne : 3, juste dessous : 0
65C02 assembly (64tass)
; Tracer une ligne horizontale (groupe 5, 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:  jsr WaitMessage
        lda #3
        sta ControlPort+4          ; P0 : couleur 3
        ldx #64                    ; 5,64 : Set Color
        jsr g5
        lda #150
        ldy #200
        jsr point1                 ; P0-P3 : (150, 200)
        lda #250
        ldy #200
        jsr point2                 ; P4-P7 : (250, 200)
        ldx #2                     ; fonction 2 : Draw Line
        jsr g5
        lda #200
        ldy #200
        jsr lire
        sta a
        lda #200
        ldy #201
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
b:      .byte 0
t0:     .text "Sur la ligne : ", 0
t2:     .text ", juste dessous : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sur la ligne : 3, juste dessous : 0

5,3 Draw Rectangle Official

Draws a rectangle given by two opposite corners, solid or outlined depending on the fill flag.

Inputs
BytesTypeMeaning
P0-P1int16first point X
P2-P3int16first point Y
P4-P5int16second point X
P6-P7int16second point Y

Outputs: none.

Outline or solid depending on 5,65 (or 5,1). In NeoBASIC, rect x1,y1 to x2,y2 makes this call; frame and solid choose outline or solid.

Firmware documentation text

Draw a rectangle spanning the screen coordinates specified in Parameters:0,1,Parameters:2,3 (corner X,Y) and Parameters:4,5,Parameters:6,7 (opposite corner X,Y).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Tracer le contour d'un rectangle (groupe 5, fonction 3). */
int main(void) {
    neo_graphics_set_color(4);                  /* 5,64 */
    neo_graphics_set_solid_flag(0);             /* 5,65 : contour */
    neo_graphics_draw_rectangle(150, 160, 190, 200);
    uint8_t a = neo_graphics_read_pixel(150, 180);
    uint8_t b = neo_graphics_read_pixel(170, 180);
    printf("Bord : %u, centre : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bord : 4, centre : 0
Mad Pascal
// Tracer le contour d'un rectangle (groupe 5, fonction 3).
program forme3;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(4);                               // 5,64
  NeoSetSolidFlag(0);                            // 5,65 : contour
  NeoDrawRect(150, 160, 190, 200);
  a := NeoGetPixel(150, 180);
  b := NeoGetPixel(170, 180);
  writeln('Bord : ', a, ', centre : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bord : 4, centre : 0
NeoBASIC
10 ' Tracer le contour d'un rectangle (groupe 5, fonction 3)
20 rect 150,160 ink 4 frame to 190,200
30 a = point(150,180) : b = point(170,180)
40 print "Bord : ";a;", centre : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bord : 4, centre : 0
65C02 assembly (64tass)
; Tracer le contour d'un rectangle (groupe 5, 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:  jsr WaitMessage
        lda #4
        sta ControlPort+4          ; P0 : couleur 4
        ldx #64                    ; 5,64 : Set Color
        jsr g5
        lda #0
        sta ControlPort+4          ; P0 : contour
        ldx #65                    ; 5,65 : Set Solid Flag
        jsr g5
        lda #150
        ldy #160
        jsr point1
        lda #190
        ldy #200
        jsr point2
        ldx #3                     ; 5,3
        jsr g5
        lda #150
        ldy #180
        jsr lire
        sta a
        lda #170
        ldy #180
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
b:      .byte 0
t0:     .text "Bord : ", 0
t2:     .text ", centre : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Bord : 4, centre : 0

5,4 Draw Ellipse Official

Draws the ellipse inscribed in the rectangle given by two opposite corners.

Inputs
BytesTypeMeaning
P0-P1int16first point X
P2-P3int16first point Y
P4-P5int16second point X
P6-P7int16second point Y

Outputs: none.

Solid or outlined depending on the fill flag (5,65). A square gives a circle. In NeoBASIC, ellipse x1,y1 to x2,y2 makes this call.

Firmware documentation text

Draw an ellipse spanning the screen coordinates specified in Parameters:0,1,Parameters:2,3 (corner X,Y) and Parameters:4,5,Parameters:6,7 (opposite corner X,Y).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Tracer une ellipse pleine (groupe 5, fonction 4). */
int main(void) {
    neo_graphics_set_color(4);                  /* 5,64 */
    neo_graphics_set_solid_flag(1);             /* 5,65 : plein */
    neo_graphics_draw_ellipse(200, 160, 240, 200);
    uint8_t a = neo_graphics_read_pixel(220, 180);
    uint8_t b = neo_graphics_read_pixel(201, 161);
    printf("Centre : %u, coin : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Centre : 4, coin : 0
Mad Pascal
// Tracer une ellipse pleine (groupe 5, fonction 4).
program forme4;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(4);                               // 5,64
  NeoSetSolidFlag(1);                            // 5,65 : plein
  NeoDrawEllipse(200, 160, 240, 200);
  a := NeoGetPixel(220, 180);
  b := NeoGetPixel(201, 161);
  writeln('Centre : ', a, ', coin : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Centre : 4, coin : 0
NeoBASIC
10 ' Tracer une ellipse pleine (groupe 5, fonction 4)
20 ellipse 200,160 ink 4 solid to 240,200
30 a = point(220,180) : b = point(201,161)
40 print "Centre : ";a;", coin : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Centre : 4, coin : 0
65C02 assembly (64tass)
; Tracer une ellipse pleine (groupe 5, fonction 4).
        .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 #4
        sta ControlPort+4          ; P0 : couleur 4
        ldx #64                    ; 5,64 : Set Color
        jsr g5
        lda #1
        sta ControlPort+4          ; P0 : plein
        ldx #65                    ; 5,65 : Set Solid Flag
        jsr g5
        lda #200
        ldy #160
        jsr point1
        lda #240
        ldy #200
        jsr point2
        ldx #4                     ; 5,4
        jsr g5
        lda #220
        ldy #180
        jsr lire
        sta a
        lda #201
        ldy #161
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
b:      .byte 0
t0:     .text "Centre : ", 0
t2:     .text ", coin : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Centre : 4, coin : 0

5,5 Draw Pixel Official

Draws one pixel in the current colour.

Inputs
BytesTypeMeaning
P0-P1int16point X
P2-P3int16point Y

Outputs: none.

The pixel follows the mask/colour rule of 5,1; 5,39 instead writes a colour as is. In NeoBASIC, plot to x,y makes this call (plot x,y alone only moves the current point).

Firmware documentation text

Draw a single pixel at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (X,Y).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Allumer un pixel (groupe 5, fonction 5). */
int main(void) {
    neo_graphics_set_color(6);                  /* 5,64 */
    neo_graphics_draw_pixel(210, 170);          /* 5,5 : Draw Pixel */
    uint8_t a = neo_graphics_read_pixel(210, 170);   /* 5,33 */
    uint8_t b = neo_graphics_read_pixel(211, 170);
    printf("Pixel (210, 170) : %u, voisin : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
Mad Pascal
// Allumer un pixel (groupe 5, fonction 5).
program pixel5;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(6);                               // 5,64
  NeoDrawPixel(210, 170);                       // 5,5 : Draw Pixel
  a := NeoGetPixel(210, 170);                   // 5,33
  b := NeoGetPixel(211, 170);
  writeln('Pixel (210, 170) : ', a, ', voisin : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
NeoBASIC
10 ' Allumer un pixel (groupe 5, fonction 5)
20 plot 0,0 ink 6 to 210,170
30 a = point(210,170) : b = point(211,170)
40 print "Pixel (210, 170) : ";a;", voisin : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
65C02 assembly (64tass)
; Allumer un pixel (groupe 5, 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 #6
        sta ControlPort+4          ; P0 : couleur 6
        ldx #64                    ; 5,64 : Set Color
        jsr g5
        lda #210
        ldy #170
        jsr point1
        ldx #5                     ; 5,5 : Draw Pixel
        jsr g5
        lda #210
        ldy #170
        jsr lire                   ; 5,33 : Read Pixel
        sta a
        lda #211
        ldy #170
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
b:      .byte 0
t0:     .text "Pixel (210, 170) : ", 0
t2:     .text ", voisin : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0

5,6 Draw Text Official

Draws a text in graphics, at a pixel position.

Inputs
BytesTypeMeaning
P0-P1int16top left X, in pixels
P2-P3int16top left Y, in pixels
P4-P5addraddress of the text (length-prefixed)

Outputs: none.

The firmware documentation speaks of a character cell; the code (GFXScaledText) takes pixel coordinates, as the example confirms. Size (5,66), colour and solid background (5,65) apply. The example counts the lit pixels in a 14-pixel square around the letter A. In NeoBASIC, text "…" to x,y makes this call.

Firmware documentation text

Draw the length-prefixed string of text stored at the memory location specified in Parameters:4,5 at the screen character cell specified in Parameters:0,1,Parameters:2,3 (X,Y).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

static uint16_t compte(uint8_t couleur, uint8_t x0, uint8_t y0, uint8_t cote) {   /* pixels de cette couleur */
    uint16_t n = 0;
    for (uint8_t y = y0; y < y0 + cote; y++)
        for (uint8_t x = x0; x < x0 + cote; x++)
            if (neo_graphics_read_pixel(x, y) == couleur)
                n++;
    return n;
}

/* Écrire A en mode graphique et compter ses pixels (groupe 5, fonction 6). */
int main(void) {
    neo_graphics_set_color(5);
    neo_graphics_draw_text(200, 170, "A");      /* Draw Text */
    printf("Pixels du A en couleur 5 : %u\n", compte(5, 198, 168, 14));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixels du A en couleur 5 : 16
Mad Pascal
// Écrire A en mode graphique et compter ses pixels (groupe 5, fonction 6).
program texte;
uses crt, neo6502;
var s: string[4];

function compte(couleur, x0, y0, cote: byte): word;   // pixels de cette couleur
var x, y: byte;
begin
  result := 0;
  for y := y0 to y0 + cote - 1 do
    for x := x0 to x0 + cote - 1 do
      if NeoGetPixel(x, y) = couleur then inc(result);
end;

begin
  NeoSetColor(5);
  s := 'A';
  NeoDrawString(200, 170, s);                   // Draw Text
  writeln('Pixels du A en couleur 5 : ', compte(5, 198, 168, 14));
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixels du A en couleur 5 : 16
NeoBASIC
10 ' Ecrire A en mode graphique et compter ses pixels (groupe 5, fonction 6)
20 text "A" dim 1 ink 5 to 200,170
30 n = 0 : for y = 168 to 181 : for x = 198 to 211
40 if point(x,y) = 5 then n = n + 1
50 next x : next y
60 print "Pixels du A en couleur 5 : ";n
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixels du A en couleur 5 : 16
65C02 assembly (64tass)
; Écrire A en mode graphique et compter ses pixels (groupe 5, fonction 6).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #5
        sta ControlPort+4
        ldx #64                    ; 5,64 : couleur 5
        jsr g5
        lda #200
        ldy #170
        jsr point1                 ; P0-P3 : (200, 170)
        lda #<lettre
        sta ControlPort+8          ; P4-P5 : texte
        lda #>lettre
        sta ControlPort+9
        ldx #6                     ; fonction 6 : Draw Text
        jsr g5
        jsr compte
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda n
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Compte les pixels de couleur coul dans le carré (x0, y0), côté cote ; résultat dans n.
compte: stz n
        lda y0
        sta yc
_ly:    lda x0
        sta xc
_lx:    lda xc
        ldy yc
        jsr lire
        cmp coul
        bne _pas
        inc n
_pas:   inc xc
        lda xc
        sec
        sbc x0
        cmp cote
        bne _lx
        inc yc
        lda yc
        sec
        sbc y0
        cmp cote
        bne _ly
        rts
xc:     .byte 0
yc:     .byte 0
n:      .byte 0

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

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

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

ptr      = $80
diviseur: .byte 0

lettre: .byte 1
        .text "A"
coul:   .byte 5
x0:     .byte 198
y0:     .byte 168
cote:   .byte 14
t0:     .text "Pixels du A en couleur 5 : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixels du A en couleur 5 : 16

5,7 Draw Image Official

Draws an image from graphics memory (tile or sprite) at a given position.

Inputs
BytesTypeMeaning
P0-P1int16top left X
P2-P3int16top left Y
P4uint8image number: $00-$7F 16×16 tiles, $80-$BF 16×16 sprites, $C0-$FF 32×32 sprites

Outputs: none.

Size (5,66), flip (5,67) and solid background (5,65) apply; colour 0 of the image is transparent unless the background is solid. With no graphics memory loaded, nothing is drawn. In NeoBASIC, image n to x,y makes this call (image n, flip dim size to x,y).

Firmware documentation text

Draw the image with image ID in Parameter:4 at the screen coordinates Parameters:0,1,Parameters:2,3 (X,Y). The extent and flip settings influence this command.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

static uint8_t gfx[256 + 128];                  /* en-tête + une image 16x16, 4 bits par pixel */

static void images(uint8_t genre) {             /* 1 : une tuile ; 2 : un sprite 16x16 */
    gfx[0] = 1;
    gfx[genre] = 1;
    for (uint8_t y = 0; y < 16; y++)
        for (uint8_t i = 0; i < 8; i++)
            gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55;   /* gauche : couleur 2, droite : 5 */
    neo_file_store("img.gfx", gfx, sizeof gfx);
    neo_file_load("img.gfx", (void *)0xFFFF);   /* $FFFF : mémoire graphique */
}

/* Dessiner une image de la mémoire graphique (groupe 5, fonction 7). */
int main(void) {
    images(1);
    neo_graphics_set_draw_size(1);             /* 5,66 */
    neo_graphics_set_flip_bits(0);             /* 5,67 */
    neo_graphics_draw_image(200, 160, 0);         /* 5,7 : Draw Image, image 0 */
    uint8_t a = neo_graphics_read_pixel(202, 165);
    neo_graphics_set_draw_size(1);             /* 5,66 */
    neo_graphics_set_flip_bits(0);             /* 5,67 */
    neo_graphics_draw_image(200, 160, 0);         /* 5,7 : Draw Image, image 0 */
    uint8_t b = neo_graphics_read_pixel(212, 165);
    printf("Gauche : %u, droite : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Gauche : 2, droite : 5
Mad Pascal
// Dessiner une image de la mémoire graphique (groupe 5, fonction 7).
program image7;
uses crt, neo6502;
var a, b: byte;
    gfx: array[0..383] of byte;                 // en-tête + une image 16x16

procedure images(genre: byte);                  // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
  fillchar(@gfx, 384, 0);
  gfx[0] := 1;
  gfx[genre] := 1;
  for y := 0 to 15 do
    for i := 0 to 7 do
      if i < 4 then gfx[256 + y * 8 + i] := $22   // gauche : couleur 2
      else gfx[256 + y * 8 + i] := $55;         // droite : couleur 5
  NeoSave('img.gfx', word(@gfx), 384);
  NeoLoad('img.gfx', $FFFF);                    // $FFFF : mémoire graphique
end;

begin
  images(1);
  NeoSetDrawSize(1);                            // 5,66
  NeoSetFlip(0);                                // 5,67
  NeoDrawImage(200, 160, 0);                      // 5,7 : Draw Image, image 0
  a := NeoGetPixel(202, 165);
  NeoSetDrawSize(1);                            // 5,66
  NeoSetFlip(0);                                // 5,67
  NeoDrawImage(200, 160, 0);                      // 5,7 : Draw Image, image 0
  b := NeoGetPixel(212, 165);
  writeln('Gauche : ', a, ', ', 'droite : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Gauche : 2, droite : 5
NeoBASIC
10 ' Dessiner une image de la memoire graphique (groupe 5, fonction 7)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 image 0 to 200,160 : a = point(202,165)
40 image 0 to 200,160 : b = point(212,165)
50 print "Gauche : ";a; ", ";"droite : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Gauche : 2, droite : 5
65C02 assembly (64tass)
; Dessiner une image de la mémoire graphique (groupe 5, 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
        jsr images
        lda #1
        sta ControlPort+4
        ldx #66                    ; 5,66 : taille 1
        jsr g5
        lda #0
        sta ControlPort+4
        ldx #67                    ; 5,67 : retournement 0
        jsr g5
        lda #200
        ldy #160
        jsr point1
        stz ControlPort+8          ; P4 : image 0
        ldx #7                     ; 5,7 : Draw Image
        jsr g5
        lda #202
        ldy #165
        jsr lire
        sta a
        lda #1
        sta ControlPort+4
        ldx #66                    ; 5,66 : taille 1
        jsr g5
        lda #0
        sta ControlPort+4
        ldx #67                    ; 5,67 : retournement 0
        jsr g5
        lda #200
        ldy #160
        jsr point1
        stz ControlPort+8          ; P4 : image 0
        ldx #7                     ; 5,7 : Draw Image
        jsr g5
        lda #212
        ldy #165
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #<gfx
        sta ControlPort+6
        lda #>gfx
        sta ControlPort+7
        lda #<384
        sta ControlPort+8
        lda #>384
        sta ControlPort+9
        lda #3
        ldx #3                     ; 3,3 : Save File
        jsr appel
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #$FF
        sta ControlPort+6          ; $FFFF : mémoire graphique
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jmp appel
nomgfx: .byte 7
        .text "img.gfx"

; 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

gfx:    .byte 1, 1, 0, 0             ; en-tête : une tuile
        .fill 252
        .rept 16                   ; 16 lignes : gauche couleur 2, droite couleur 5
        .byte $22, $22, $22, $22, $55, $55, $55, $55
        .endrept
a:      .byte 0
b:      .byte 0
t0:     .text "Gauche : ", 0
t2:     .text ", ", 0
t3:     .text "droite : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Gauche : 2, droite : 5

5,8 Draw Tilemap Changed by Trinity

Draws the current tile map (5,35) in a screen rectangle.

Inputs
BytesTypeMeaning
P0-P1int16first point X
P2-P3int16first point Y
P4-P5int16second point X
P6-P7int16second point Y
Outputs
BytesTypeMeaning
erreuruint81 with no map, if the offset is outside the map or if the window is narrower than a tile

Tiles are 16×16 (32×32 at size 2, see 5,66), read from graphics memory. The map has two tiles 0 side by side: we read 2 (left of the first), 5 (its right), then 2 (left of the second). The window is |x2-x1| pixels wide and |y2-y1| high: the right and bottom edges are excluded. The map starts with 3 bytes (type, width, height in tiles), then one byte per tile ($F0 transparent, $F1-$FF solid colour). With type $81 instead of 1 (Trinity), a pixel of colour 0 leaves the screen as it is, and so does the part of the window beyond the map: maps can thus be drawn over each other (parallax layers). Trinity also draws maps in modes 1 and 2. In NeoBASIC, tiledraw x1,y1 to x2,y2 makes this call.

Firmware documentation text

Draw the current tilemap at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (top-left X,Y) and Parameters:4,5,Parameters:6,7 (bottom-right X,Y) using current graphics settings. The window is |x2-x1| pixels wide and |y2-y1| high : the right and bottom edges are excluded. The tilemap starts with 3 bytes : type, width, height (in tiles), then one byte per tile ($F0 transparent, $F1-$FF solid colour). Type bit 7 set ($81 rather than 1, Trinity T-92) : a pixel of colour 0 in a tile leaves the screen as it is, and so does the part of the window beyond the map, so that maps can be drawn over each other (parallax layers).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

static uint8_t gfx[256 + 128];                  /* en-tête + une image 16x16, 4 bits par pixel */

static void images(uint8_t genre) {             /* 1 : une tuile ; 2 : un sprite 16x16 */
    gfx[0] = 1;
    gfx[genre] = 1;
    for (uint8_t y = 0; y < 16; y++)
        for (uint8_t i = 0; i < 8; i++)
            gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55;   /* gauche : couleur 2, droite : 5 */
    neo_file_store("img.gfx", gfx, sizeof gfx);
    neo_file_load("img.gfx", (void *)0xFFFF);   /* $FFFF : mémoire graphique */
}

static const uint8_t carte[] = { 1, 2, 1, 0, 0 };   /* format, largeur 2, hauteur 1, tuiles 0 0 */

/* Dessiner une carte de deux tuiles (groupe 5, fonction 8). */
int main(void) {
    images(1);
    neo_graphics_set_tilemap(carte, 0, 0);      /* 5,35 */
    neo_graphics_draw_tilemap(150, 160, 182, 176);   /* 5,8 : Draw Tilemap */
    uint8_t a = neo_graphics_read_pixel(152, 165);
    uint8_t b = neo_graphics_read_pixel(160, 165);
    uint8_t c = neo_graphics_read_pixel(168, 165);
    printf("Couleurs sur la ligne : %u %u %u\n", a, b, c);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2
Mad Pascal
// Dessiner une carte de deux tuiles (groupe 5, fonction 8).
program carte8;
uses crt, neo6502;
var a, b, c: byte;
    carte: array[0..4] of byte = (1, 2, 1, 0, 0);   // format, largeur 2, hauteur 1, tuiles 0 0
    gfx: array[0..383] of byte;                 // en-tête + une image 16x16

procedure images(genre: byte);                  // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
  fillchar(@gfx, 384, 0);
  gfx[0] := 1;
  gfx[genre] := 1;
  for y := 0 to 15 do
    for i := 0 to 7 do
      if i < 4 then gfx[256 + y * 8 + i] := $22   // gauche : couleur 2
      else gfx[256 + y * 8 + i] := $55;         // droite : couleur 5
  NeoSave('img.gfx', word(@gfx), 384);
  NeoLoad('img.gfx', $FFFF);                    // $FFFF : mémoire graphique
end;

begin
  images(1);
  NeoSelectTileMap(word(@carte), 0, 0);         // 5,35
  NeoDrawTileMap(150, 160, 182, 176);           // 5,8 : Draw Tilemap
  a := NeoGetPixel(152, 165);
  b := NeoGetPixel(160, 165);
  c := NeoGetPixel(168, 165);
  writeln('Couleurs sur la ligne : ', a, ' ', b, ' ', c);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2
NeoBASIC
10 ' Dessiner une carte de deux tuiles (groupe 5, fonction 8)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 m = alloc(8) : poke m, 1 : poke m + 1, 2 : poke m + 2, 1 : poke m + 3, 0 : poke m + 4, 0 : ' carte 2 x 1
40 tilemap m, 0, 0
50 tiledraw 150,160 to 182,176
60 a = point(152,165) : b = point(160,165) : c = point(168,165)
70 print "Couleurs sur la ligne : ";a;" ";b;" ";c
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2
65C02 assembly (64tass)
; Dessiner une carte de deux tuiles (groupe 5, 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
        jsr images
        jsr WaitMessage
        lda #<carte
        sta ControlPort+4          ; P0-P1 : carte
        lda #>carte
        sta ControlPort+5
        stz ControlPort+6          ; P2-P5 : décalage (0, 0)
        stz ControlPort+7
        stz ControlPort+8
        stz ControlPort+9
        ldx #35                    ; 5,35 : Set Tilemap
        jsr g5
        lda #150
        ldy #160
        jsr point1
        lda #182
        ldy #176
        jsr point2
        ldx #8                     ; 5,8 : Draw Tilemap
        jsr g5
        lda #152
        ldy #165
        jsr lire
        sta a
        lda #160
        ldy #165
        jsr lire
        sta b
        lda #168
        ldy #165
        jsr lire
        sta c
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda c
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #<gfx
        sta ControlPort+6
        lda #>gfx
        sta ControlPort+7
        lda #<384
        sta ControlPort+8
        lda #>384
        sta ControlPort+9
        lda #3
        ldx #3                     ; 3,3 : Save File
        jsr appel
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #$FF
        sta ControlPort+6          ; $FFFF : mémoire graphique
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jmp appel
nomgfx: .byte 7
        .text "img.gfx"

; 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

gfx:    .byte 1, 1, 0, 0             ; en-tête : une tuile
        .fill 252
        .rept 16                   ; 16 lignes : gauche couleur 2, droite couleur 5
        .byte $22, $22, $22, $22, $55, $55, $55, $55
        .endrept
carte:  .byte 1, 2, 1, 0, 0         ; format, largeur 2, hauteur 1, tuiles 0 0
a:      .byte 0
b:      .byte 0
c:      .byte 0
t0:     .text "Couleurs sur la ligne : ", 0
t2:     .text " ", 0
t4:     .text " ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2

5,9 Set Graphics Mode Trinity

Selects the display mode and resets screen, palette and console.

Inputs
BytesTypeMeaning
P0uint8mode: 0 standard 320×240 in 256 colours, 1 Hercules 720×350 monochrome, 2 trial 320×240 in 16 colours
Outputs
BytesTypeMeaning
erreuruint8non zero if the mode is unknown or not supported by the hardware

Trinity only. Mode 2 is a trial (Trinity 0.16.58) that may change or go: 320×240 in 16 colours, two pixels per byte (the left one in the high 4 bits), two pages (5,11, 5,12), colours 0 to 15, 53×30 console; no sprite layer (sprites are drawn in XOR, as in mode 1). The fork's former 320×256 mode 2 has been removed. Sprites and images only exist in mode 0; tile maps are drawn in modes 1 and 2 too. The example switches to mode 2, reads its size back (5,10), then returns to mode 0; as the screen is cleared at each change, it keeps its results and prints them at the end.

Firmware documentation text

Select the display mode in Parameter:0 and reinitialise the screen, palette and console (F5 / ADR-02). 0 is the standard 320x240 256 colour mode. 1 is the Hercules mode (720x350 monochrome, 80x25 text in 9x14 cells). 2 is a TRIAL mode (Trinity T-90, study) : 320x240 in 16 colours, 4 bits per pixel, two pixels per byte, left pixel in the high nibble, two pages (5,11 / 5,12), palette entries 0-15, same display timing as mode 0 ; no sprite layer (sprites are drawn in XOR as in mode 1), console 53x30. It may change or go. (The fork's 320x256x16 mode 2 was removed on 2026-09-19.) Tilemaps are drawn in modes 1 and 2 too (packed path of 5,8). Sets the error flag if the mode is unknown or not supported by this hardware.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

static uint8_t mode, bpp, cols, lignes;
static uint16_t largeur, hauteur;

static void lire_mode(void) {                   /* 5,10 : Get Graphics Mode */
    libre();
    api(5, 10);
    mode = ControlPort.params[0];
    largeur = ControlPort.params[1] | (ControlPort.params[2] << 8);
    hauteur = ControlPort.params[3] | (ControlPort.params[4] << 8);
    bpp = ControlPort.params[5];
    cols = ControlPort.params[6];
    lignes = ControlPort.params[7];
}

static uint8_t choisir(uint8_t m) {             /* Set Graphics Mode, erreur rendue */
    libre();
    ControlPort.params[0] = m;
    api(5, 9);
    return ControlPort.error;
}

/* Changer de mode d'affichage (groupe 5, fonction 9, Trinity). */
int main(void) {
    uint8_t e2 = choisir(2);                    /* essai 320x240, 16 couleurs */
    lire_mode();                                /* 5,10 */
    uint16_t l2 = largeur, h2 = hauteur;
    uint8_t e0 = choisir(0);                    /* retour au mode standard (écran effacé) */
    lire_mode();
    printf("Mode 2 : erreur %u, %u x %u\n", e2, l2, h2);
    printf("Mode 0 : erreur %u, %u x %u\n", e0, largeur, hauteur);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240
Mad Pascal
// Changer de mode d'affichage (groupe 5, fonction 9, Trinity).
program choisirmode;
uses crt, neo6502;
var e2, e0: byte;
    largeur, hauteur, l2, h2: word;

function choisir(m: byte): byte;                // Set Graphics Mode, erreur rendue
begin
  NeoWaitMessage;
  NeoMessage.params[0] := m;
  NeoSendMessage(5, 9);
  NeoWaitMessage;
  result := NeoMessage.error;
end;

procedure lire_mode;                            // 5,10 : Get Graphics Mode
begin
  NeoSendMessage(5, 10);
  NeoWaitMessage;
  largeur := wordxParams[0];
  hauteur := wordxParams[1];
end;

begin
  e2 := choisir(2);                             // essai 320x240, 16 couleurs
  lire_mode;
  l2 := largeur;
  h2 := hauteur;
  e0 := choisir(0);                             // retour au mode standard (écran effacé)
  lire_mode;
  writeln('Mode 2 : erreur ', e2, ', ', l2, ' x ', h2);
  writeln('Mode 0 : erreur ', e0, ', ', largeur, ' x ', hauteur);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240
NeoBASIC
10 ' Changer de mode d'affichage (groupe 5, fonction 9, Trinity)
20 m = 2 : gosub 1000 : e2 = e : l2 = l : h2 = h : ' essai 320x240, 16 couleurs
30 m = 0 : gosub 1000 : ' retour au mode standard (ecran efface)
40 print "Mode 2 : erreur ";e2;", ";l2;" x ";h2
50 print "Mode 0 : erreur ";e;", ";l;" x ";h
60 end
1000 ' 5,9 : mode m, erreur dans e ; puis 5,10 : largeur l, hauteur h
1010 while peek($ff00) : wend : poke $ff04, m : poke $ff01, 9 : poke $ff00, 5
1020 while peek($ff00) : wend : e = peek($ff02)
1030 poke $ff01, 10 : poke $ff00, 5
1040 while peek($ff00) : wend : l = deek($ff05) : h = deek($ff07)
1050 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240
65C02 assembly (64tass)
; Changer de mode d'affichage (groupe 5, fonction 9, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #2                     ; essai 320x240, 16 couleurs
        jsr choisir
        sta e2
        ldy #0
        jsr taille                 ; dimensions du mode 2 en dim
        lda #0                     ; retour au mode standard (écran effacé)
        jsr choisir
        sta e0
        ldy #4
        jsr taille                 ; dimensions du mode 0 en dim+4
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e2
        jsr decimal
        ldy #0
        jsr montrer
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda e0
        jsr decimal
        ldy #4
        jmp montrer

; 5,10 : largeur et hauteur (P1-P4) copiées en dim+Y, à l'abri avant d'afficher.
taille: jsr WaitMessage
        lda #5
        ldx #10                    ; 5,10 : Get Graphics Mode
        jsr appel
        ldx #0
_copie: lda ControlPort+5,x
        sta dim,y
        iny
        inx
        cpx #4
        bne _copie
        rts

; Affiche « , largeur x hauteur » des dimensions en dim+Y, puis un retour à la ligne.
montrer:
        sty ou
        lda #<t2
        ldx #>t2
        jsr ecrire
        ldy ou
        lda dim,y                  ; largeur
        ldx dim+1,y
        jsr decimal16
        lda #<t3
        ldx #>t3
        jsr ecrire
        ldy ou
        lda dim+2,y                ; hauteur
        ldx dim+3,y
        jsr decimal16
        lda #13
        jmp WriteCharacter
ou:     .byte 0

; Mode A (5,9), erreur rendue dans A.
choisir:
        pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0 : mode
        lda #5
        ldx #9                     ; fonction 9 : Set Graphics Mode
        jsr appel
        lda ControlPort+2
        rts

; Affiche en décimal le nombre de 16 bits A (poids faible) X (poids fort), jusqu'à 999.
decimal16:
        stx fort
        ldy #0                     ; centaines
_c:     sec
        sbc #100
        pha
        lda fort
        sbc #0
        bcc _cf
        sta fort
        pla
        iny
        bra _c
_cf:    pla
        clc
        adc #100
        pha
        tya
        beq _d
        ora #'0'
        jsr WriteCharacter
        pla
        jmp decimal2
_d:     pla
        jmp decimal
decimal2:                          ; A (0-99) sur deux chiffres
        ldy #0
_dz:    cmp #10
        bcc _u
        sbc #10
        iny
        bra _dz
_u:     pha
        tya
        ora #'0'
        jsr WriteCharacter
        pla
        ora #'0'
        jmp WriteCharacter
fort:   .byte 0

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

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

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

ptr      = $80
diviseur: .byte 0

e2:     .byte 0
e0:     .byte 0
dim:    .fill 8
t0:     .text "Mode 2 : erreur ", 0
t1:     .text "Mode 0 : erreur ", 0
t2:     .text ", ", 0
t3:     .text " x ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240

5,10 Get Graphics Mode Trinity

Gives the current display mode and its dimensions.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8mode
P1-P2uint16width in pixels
P3-P4uint16height in pixels
P5uint8bits per pixel
P6-P7uint8console: columns, then rows

Trinity only. In mode 0: 320 × 240, 8 bits per pixel, 53-column by 30-row console (6 × 8 font).

Firmware documentation text

Return the current display mode in Parameter:0, the pixel width in Parameters:1,2, the pixel height in Parameters:3,4, the bits per pixel in Parameter:5 and the console size in characters in Parameters:6,7.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

static uint8_t mode, bpp, cols, lignes;
static uint16_t largeur, hauteur;

static void lire_mode(void) {                   /* 5,10 : Get Graphics Mode */
    libre();
    api(5, 10);
    mode = ControlPort.params[0];
    largeur = ControlPort.params[1] | (ControlPort.params[2] << 8);
    hauteur = ControlPort.params[3] | (ControlPort.params[4] << 8);
    bpp = ControlPort.params[5];
    cols = ControlPort.params[6];
    lignes = ControlPort.params[7];
}

/* Lire le mode d'affichage (groupe 5, fonction 10, Trinity). */
int main(void) {
    lire_mode();
    printf("Mode %u : %u x %u, %u bits, console %u x %u\n", mode, largeur, hauteur, bpp, cols, lignes);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 0 : 320 x 240, 8 bits, console 53 x 30
Mad Pascal
// Lire le mode d'affichage (groupe 5, fonction 10, Trinity).
program litmode;
uses crt, neo6502;
var mode, bpp, cols, lignes: byte;
    largeur, hauteur: word;
begin
  NeoWaitMessage;
  NeoSendMessage(5, 10);                        // Get Graphics Mode
  NeoWaitMessage;
  mode := NeoMessage.params[0];
  largeur := wordxParams[0];                    // P1-P2
  hauteur := wordxParams[1];                    // P3-P4
  bpp := NeoMessage.params[5];
  cols := NeoMessage.params[6];
  lignes := NeoMessage.params[7];
  writeln('Mode ', mode, ' : ', largeur, ' x ', hauteur, ', ', bpp, ' bits, console ', cols, ' x ', lignes);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 0 : 320 x 240, 8 bits, console 53 x 30
NeoBASIC
10 ' Lire le mode d'affichage (groupe 5, fonction 10, Trinity)
20 while peek($ff00) : wend : poke $ff01, 10 : poke $ff00, 5
30 while peek($ff00) : wend : m = peek($ff04) : l = peek($ff05) + 256 * peek($ff06) : h = peek($ff07) + 256 * peek($ff08)
40 b = peek($ff09) : c = peek($ff0a) : r = peek($ff0b)
50 print "Mode ";m;" : ";l;" x ";h;", ";b;" bits, console ";c;" x ";r
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 0 : 320 x 240, 8 bits, console 53 x 30
65C02 assembly (64tass)
; Lire le mode d'affichage (groupe 5, fonction 10, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #5
        ldx #10                    ; fonction 10 : Get Graphics Mode
        jsr appel
        ldx #7
_copie: lda ControlPort+4,x        ; P0-P7 à l'abri avant d'afficher
        sta p,x
        dex
        bpl _copie
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda p
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda p+1                    ; 320 = $0140 : poids fort 1
        ldx p+2
        jsr decimal16
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p+3
        ldx p+4
        jsr decimal16
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda p+5
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda p+6
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p+7
        jsr decimal
        lda #13
        jmp WriteCharacter

; Affiche en décimal le nombre de 16 bits A (poids faible) X (poids fort), jusqu'à 999.
decimal16:
        stx fort
        ldy #0                     ; centaines
_c:     sec
        sbc #100
        pha
        lda fort
        sbc #0
        bcc _cf
        sta fort
        pla
        iny
        bra _c
_cf:    pla
        clc
        adc #100
        pha
        tya
        beq _d
        ora #'0'
        jsr WriteCharacter
        pla
        jmp decimal2
_d:     pla
        jmp decimal
decimal2:                          ; A (0-99) sur deux chiffres
        ldy #0
_dz:    cmp #10
        bcc _u
        sbc #10
        iny
        bra _dz
_u:     pha
        tya
        ora #'0'
        jsr WriteCharacter
        pla
        ora #'0'
        jmp WriteCharacter
fort:   .byte 0

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

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

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

ptr      = $80
diviseur: .byte 0

p:      .fill 8
t0:     .text "Mode ", 0
t1:     .text " : ", 0
t2:     .text " x ", 0
t3:     .text ", ", 0
t4:     .text " bits, console ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Mode 0 : 320 x 240, 8 bits, console 53 x 30

5,11 Set Draw Page Trinity

Selects the page that the console and graphics functions draw into.

Inputs
BytesTypeMeaning
P0uint8page: 0, or 1 in modes 1 and 2
Outputs
BytesTypeMeaning
erreuruint8non zero if the page does not exist in the current mode

Trinity only. Mode 0 has one page, modes 1 and 2 (the 16 colour trial, see 5,9) have two: one is drawn while the other is shown (5,12). According to the Trinity 0.16.69 documentation (not tried on the bench), page n starts in video RAM at n × (bytes per line × lines), an address the blitter reaches through pages $80 and $81: in mode 2, page 1 is at $80:9600 (160 × 240); in mode 1, at $80:7B0C (90 × 350). The example, in mode 0, shows page 1 being refused.

Firmware documentation text

Select the page (Parameter:0) that console and graphics commands draw into (F-55). Mode 0 has one page, modes 1 and 2 have two (0 and 1) ; mode 2 is the 16 colour trial of T-90. Sets the error flag if the page does not exist. Page n starts at offset n x (bytes per line x lines) of the video RAM, which is what the blitter addresses as pages $80/$81 : in mode 2, page 1 is at $80:9600 (38400 = 160 x 240), so a 12,3 into the hidden page targets $80:9600 + y x 160 + x / 2, with target format 5 (even x) or 6 (odd x). In mode 1, page 1 is at $80:7B0C (31500 = 90 x 350).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

static uint8_t page(uint8_t p) {                /* Set Draw Page, erreur rendue */
    libre();
    ControlPort.params[0] = p;
    api(5, 11);
    return ControlPort.error;
}

/* Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity). */
int main(void) {
    uint8_t e1 = page(1);                       /* le mode 0 n'a qu'une page */
    uint8_t e0 = page(0);
    printf("Page 1 : erreur %u, page 0 : erreur %u\n", e1, e0);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0
Mad Pascal
// Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity).
program page11;
uses crt, neo6502;
var e1, e0: byte;

function page(p: byte): byte;                   // Set Draw Page, erreur rendue
begin
  NeoWaitMessage;
  NeoMessage.params[0] := p;
  NeoSendMessage(5, 11);
  NeoWaitMessage;
  result := NeoMessage.error;
end;

begin
  e1 := page(1);                                // le mode 0 n'a qu'une page
  e0 := page(0);
  writeln('Page 1 : erreur ', e1, ', page 0 : erreur ', e0);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0
NeoBASIC
10 ' Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity)
20 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 11 : poke $ff00, 5
30 while peek($ff00) : wend : e1 = peek($ff02)
40 poke $ff04, 0 : poke $ff01, 11 : poke $ff00, 5
50 while peek($ff00) : wend : e0 = peek($ff02)
60 print "Page 1 : erreur ";e1;", page 0 : erreur ";e0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0
65C02 assembly (64tass)
; Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #1                     ; le mode 0 n'a qu'une page
        jsr page
        sta e1
        lda #0
        jsr page
        sta e0
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e1
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jmp WriteCharacter

; Page A (5,11), erreur rendue dans A.
page:   pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0 : page
        lda #5
        ldx #11                    ; fonction 11 : Set Draw Page
        jsr appel
        lda ControlPort+2
        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

e1:     .byte 0
e0:     .byte 0
t0:     .text "Page 1 : erreur ", 0
t1:     .text ", page 0 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0

5,12 Set Display Page Trinity

Selects the page shown from the next frame.

Inputs
BytesTypeMeaning
P0uint8page: 0, or 1 in modes 1 and 2
Outputs
BytesTypeMeaning
erreuruint8non zero if the page does not exist in the current mode

Trinity only. The change happens at the next frame: wait for 5,37 to change to be sure it is done. The example, in mode 0 (a single page), shows page 1 being refused.

Firmware documentation text

Select the page (Parameter:0) shown on screen from the next frame (F-55). Use Function 37 (Frame Count) to wait for the swap. Sets the error flag if the page does not exist.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

static uint8_t page(uint8_t p) {                /* Set Display Page, erreur rendue */
    libre();
    ControlPort.params[0] = p;
    api(5, 12);
    return ControlPort.error;
}

/* Choisir la page affichée (groupe 5, fonction 12, Trinity). */
int main(void) {
    uint8_t e1 = page(1);                       /* le mode 0 n'a qu'une page */
    uint8_t e0 = page(0);
    printf("Page 1 : erreur %u, page 0 : erreur %u\n", e1, e0);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0
Mad Pascal
// Choisir la page affichée (groupe 5, fonction 12, Trinity).
program page12;
uses crt, neo6502;
var e1, e0: byte;

function page(p: byte): byte;                   // Set Display Page, erreur rendue
begin
  NeoWaitMessage;
  NeoMessage.params[0] := p;
  NeoSendMessage(5, 12);
  NeoWaitMessage;
  result := NeoMessage.error;
end;

begin
  e1 := page(1);                                // le mode 0 n'a qu'une page
  e0 := page(0);
  writeln('Page 1 : erreur ', e1, ', page 0 : erreur ', e0);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0
NeoBASIC
10 ' Choisir la page affichee (groupe 5, fonction 12, Trinity)
20 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 12 : poke $ff00, 5
30 while peek($ff00) : wend : e1 = peek($ff02)
40 poke $ff04, 0 : poke $ff01, 12 : poke $ff00, 5
50 while peek($ff00) : wend : e0 = peek($ff02)
60 print "Page 1 : erreur ";e1;", page 0 : erreur ";e0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0
65C02 assembly (64tass)
; Choisir la page affichée (groupe 5, fonction 12, Trinity).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #1                     ; le mode 0 n'a qu'une page
        jsr page
        sta e1
        lda #0
        jsr page
        sta e0
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e1
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jmp WriteCharacter

; Page A (5,12), erreur rendue dans A.
page:   pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0 : page
        lda #5
        ldx #12                    ; fonction 12 : Set Display Page
        jsr appel
        lda ControlPort+2
        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

e1:     .byte 0
e0:     .byte 0
t0:     .text "Page 1 : erreur ", 0
t1:     .text ", page 0 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Page 1 : erreur 1, page 0 : erreur 0

5,32 Set Palette Official

Changes the colour of a palette entry.

Inputs
BytesTypeMeaning
P0uint8colour number
P1uint8red (0-255)
P2uint8green (0-255)
P3uint8blue (0-255)

Outputs: none.

Everything already shown in this colour changes at once. 5,34 restores the original palette. In NeoBASIC, palette n, r, g, b makes this call.

NeoBASIC keywords that make this call: palette

Firmware documentation text

Set the palette colour at the index spcified in Parameter:0 to the values in Parameter:1,Parameter:2,Parameter:3 (RGB).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

/* Changer puis relire une couleur de la palette (groupe 5, fonction 32). */
int main(void) {
    neo_graphics_set_palette(5, 255, 128, 0);   /* Set Palette : orange */
    libre();
    ControlPort.params[0] = 5;
    api(5, 38);                                 /* 5,38 : Get Palette */
    printf("Couleur 5 : %u %u %u\n", ControlPort.params[1], ControlPort.params[2], ControlPort.params[3]);
    neo_graphics_reset_palette();               /* 5,34 */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 5 : 255 128 0
Mad Pascal
// Changer puis relire une couleur de la palette (groupe 5, fonction 32).
program palette;
uses crt, neo6502;
var r, g, b: byte;
begin
  NeoSetPalette(5, 255, 128, 0);                // Set Palette : orange
  NeoGetPalette(5, r, g, b);                    // 5,38
  NeoResetPalette;                              // 5,34
  writeln('Couleur 5 : ', r, ' ', g, ' ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 5 : 255 128 0
NeoBASIC
10 ' Changer puis relire une couleur de la palette (groupe 5, fonction 32)
20 palette 5, 255, 128, 0
30 while peek($ff00) : wend : poke $ff04, 5 : poke $ff01, 38 : poke $ff00, 5 : ' 5,38
40 while peek($ff00) : wend : r = peek($ff05) : g = peek($ff06) : b = peek($ff07)
50 print "Couleur 5 : ";r;" ";g;" ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 5 : 255 128 0
65C02 assembly (64tass)
; Changer puis relire une couleur de la palette (groupe 5, fonction 32).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  jsr WaitMessage
        lda #5
        sta ControlPort+4          ; P0 : couleur 5
        lda #255
        sta ControlPort+5          ; P1-P3 : rouge, vert, bleu
        lda #128
        sta ControlPort+6
        stz ControlPort+7
        ldx #32                    ; fonction 32 : Set Palette
        jsr g5
        lda #5
        sta ControlPort+4
        ldx #38                    ; 5,38 : Get Palette
        jsr g5
        lda ControlPort+5
        sta r
        lda ControlPort+6
        sta v
        lda ControlPort+7
        sta b
        ldx #34                    ; 5,34 : Reset Palette
        jsr g5
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda r
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda v
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

r:      .byte 0
v:      .byte 0
b:      .byte 0
t0:     .text "Couleur 5 : ", 0
t2:     .text " ", 0
t4:     .text " ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 5 : 255 128 0

5,33 Read Pixel Official

Reads the colour of a screen pixel.

Inputs
BytesTypeMeaning
P0-P1int16point X
P2-P3int16point Y
Outputs
BytesTypeMeaning
P0uint8colour: 0 to 255, or 0 to 15 (background only) while sprites are shown
erreuruint81 if the point is off screen

While sprites are used, the firmware only returns the low 4 bits (the background); 5,36 reads the sprite layer. In NeoBASIC, point(x, y) makes this call.

NeoBASIC keywords that make this call: point()

Firmware documentation text

Read a single pixel at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (X,Y). When the routine completes, the result will be in Parameter:0. If sprites are in use, this will be the background only (0..15), if sprites are not in use it may return (0..255)

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Lire la couleur d'un pixel (groupe 5, fonction 33). */
int main(void) {
    neo_graphics_set_color(6);                  /* 5,64 */
    neo_graphics_draw_pixel(210, 170);          /* 5,5 */
    uint8_t a = neo_graphics_read_pixel(210, 170);   /* 5,33 : Read Pixel */
    uint8_t b = neo_graphics_read_pixel(211, 170);
    printf("Pixel (210, 170) : %u, voisin : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
Mad Pascal
// Lire la couleur d'un pixel (groupe 5, fonction 33).
program pixel33;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(6);                               // 5,64
  NeoDrawPixel(210, 170);                       // 5,5
  a := NeoGetPixel(210, 170);                   // 5,33 : Read Pixel
  b := NeoGetPixel(211, 170);
  writeln('Pixel (210, 170) : ', a, ', voisin : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
NeoBASIC
10 ' Lire la couleur d'un pixel (groupe 5, fonction 33)
20 plot 0,0 ink 6 to 210,170
30 a = point(210,170) : b = point(211,170)
40 print "Pixel (210, 170) : ";a;", voisin : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
65C02 assembly (64tass)
; Lire la couleur d'un pixel (groupe 5, fonction 33).
        .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 #6
        sta ControlPort+4          ; P0 : couleur 6
        ldx #64                    ; 5,64 : Set Color
        jsr g5
        lda #210
        ldy #170
        jsr point1
        ldx #5                     ; 5,5 : Draw Pixel
        jsr g5
        lda #210
        ldy #170
        jsr lire                   ; 5,33 : Read Pixel
        sta a
        lda #211
        ldy #170
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
b:      .byte 0
t0:     .text "Pixel (210, 170) : ", 0
t2:     .text ", voisin : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0

5,34 Reset Palette Official

Restores the palette to its original colours.

Inputs: none.

Outputs: none.

The example changes colour 1 to (1, 2, 3), restores the original palette and reads colour 1 back. In NeoBASIC, palette clear makes this call.

NeoBASIC keywords that make this call: palette

Firmware documentation text

Reset the palette to the defaults.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

/* Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34). */
int main(void) {
    neo_graphics_set_palette(1, 1, 2, 3);       /* 5,32 */
    neo_graphics_reset_palette();               /* Reset Palette */
    libre();
    ControlPort.params[0] = 1;
    api(5, 38);                                 /* 5,38 : Get Palette */
    printf("Couleur 1 remise : %u %u %u\n", ControlPort.params[1], ControlPort.params[2], ControlPort.params[3]);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 1 remise : 255 0 77
Mad Pascal
// Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34).
program repalette;
uses crt, neo6502;
var r, g, b: byte;
begin
  NeoSetPalette(1, 1, 2, 3);                    // 5,32
  NeoResetPalette;                              // Reset Palette
  NeoGetPalette(1, r, g, b);                    // 5,38
  writeln('Couleur 1 remise : ', r, ' ', g, ' ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 1 remise : 255 0 77
NeoBASIC
10 ' Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34)
20 palette 1, 1, 2, 3
30 palette clear
40 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 38 : poke $ff00, 5 : ' 5,38
50 while peek($ff00) : wend : r = peek($ff05) : g = peek($ff06) : b = peek($ff07)
60 print "Couleur 1 remise : ";r;" ";g;" ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 1 remise : 255 0 77
65C02 assembly (64tass)
; Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34).
        .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          ; couleur 1 := (1, 2, 3)
        sta ControlPort+5
        lda #2
        sta ControlPort+6
        lda #3
        sta ControlPort+7
        ldx #32                    ; 5,32 : Set Palette
        jsr g5
        ldx #34                    ; fonction 34 : Reset Palette
        jsr g5
        lda #1
        sta ControlPort+4
        ldx #38                    ; 5,38 : Get Palette
        jsr g5
        lda ControlPort+5
        sta r
        lda ControlPort+6
        sta v
        lda ControlPort+7
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda r
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda v
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

r:      .byte 0
v:      .byte 0
b:      .byte 0
t0:     .text "Couleur 1 remise : ", 0
t2:     .text " ", 0
t4:     .text " ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 1 remise : 255 0 77

5,35 Set Tilemap Official

Selects the tile map, in 65C02 memory, and the starting offset in pixels.

Inputs
BytesTypeMeaning
P0-P1addraddress of the map: a format byte, width and height in tiles, then one tile number per cell, row by row
P2-P3uint16X offset in the map, in pixels
P4-P5uint16Y offset in the map, in pixels

Outputs: none.

The map stays in 65C02 memory and is read again at each drawing (5,8). On Trinity, a map that runs past the end of memory is refused (T-60). In NeoBASIC, tilemap address, x, y makes this call.

NeoBASIC keywords that make this call: tilemap

Firmware documentation text

Set the current tilemap. Parameters:0,1 is the memory address of the tilemap, and Parameters:2,3,Parameters:4,5 (X,Y) specifies the offset into the tilemap, in units of pixels, of the top-left pixel of the tile.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

static uint8_t gfx[256 + 128];                  /* en-tête + une image 16x16, 4 bits par pixel */

static void images(uint8_t genre) {             /* 1 : une tuile ; 2 : un sprite 16x16 */
    gfx[0] = 1;
    gfx[genre] = 1;
    for (uint8_t y = 0; y < 16; y++)
        for (uint8_t i = 0; i < 8; i++)
            gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55;   /* gauche : couleur 2, droite : 5 */
    neo_file_store("img.gfx", gfx, sizeof gfx);
    neo_file_load("img.gfx", (void *)0xFFFF);   /* $FFFF : mémoire graphique */
}

static const uint8_t carte[] = { 1, 2, 1, 0, 0 };   /* format, largeur 2, hauteur 1, tuiles 0 0 */

/* Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35). */
int main(void) {
    images(1);
    neo_graphics_set_tilemap(carte, 0, 0);      /* 5,35 : Set Tilemap */
    neo_graphics_draw_tilemap(150, 160, 182, 176);   /* 5,8 */
    uint8_t a = neo_graphics_read_pixel(152, 165);
    uint8_t b = neo_graphics_read_pixel(160, 165);
    uint8_t c = neo_graphics_read_pixel(168, 165);
    printf("Couleurs sur la ligne : %u %u %u\n", a, b, c);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2
Mad Pascal
// Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35).
program carte35;
uses crt, neo6502;
var a, b, c: byte;
    carte: array[0..4] of byte = (1, 2, 1, 0, 0);   // format, largeur 2, hauteur 1, tuiles 0 0
    gfx: array[0..383] of byte;                 // en-tête + une image 16x16

procedure images(genre: byte);                  // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
  fillchar(@gfx, 384, 0);
  gfx[0] := 1;
  gfx[genre] := 1;
  for y := 0 to 15 do
    for i := 0 to 7 do
      if i < 4 then gfx[256 + y * 8 + i] := $22   // gauche : couleur 2
      else gfx[256 + y * 8 + i] := $55;         // droite : couleur 5
  NeoSave('img.gfx', word(@gfx), 384);
  NeoLoad('img.gfx', $FFFF);                    // $FFFF : mémoire graphique
end;

begin
  images(1);
  NeoSelectTileMap(word(@carte), 0, 0);         // 5,35 : Set Tilemap
  NeoDrawTileMap(150, 160, 182, 176);           // 5,8
  a := NeoGetPixel(152, 165);
  b := NeoGetPixel(160, 165);
  c := NeoGetPixel(168, 165);
  writeln('Couleurs sur la ligne : ', a, ' ', b, ' ', c);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2
NeoBASIC
10 ' Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 m = alloc(8) : poke m, 1 : poke m + 1, 2 : poke m + 2, 1 : poke m + 3, 0 : poke m + 4, 0 : ' carte 2 x 1
40 tilemap m, 0, 0
50 tiledraw 150,160 to 182,176
60 a = point(152,165) : b = point(160,165) : c = point(168,165)
70 print "Couleurs sur la ligne : ";a;" ";b;" ";c
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2
65C02 assembly (64tass)
; Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35).
        .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
        jsr images
        jsr WaitMessage
        lda #<carte
        sta ControlPort+4          ; P0-P1 : carte
        lda #>carte
        sta ControlPort+5
        stz ControlPort+6          ; P2-P5 : décalage (0, 0)
        stz ControlPort+7
        stz ControlPort+8
        stz ControlPort+9
        ldx #35                    ; 5,35 : Set Tilemap
        jsr g5
        lda #150
        ldy #160
        jsr point1
        lda #182
        ldy #176
        jsr point2
        ldx #8                     ; 5,8 : Draw Tilemap
        jsr g5
        lda #152
        ldy #165
        jsr lire
        sta a
        lda #160
        ldy #165
        jsr lire
        sta b
        lda #168
        ldy #165
        jsr lire
        sta c
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda c
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #<gfx
        sta ControlPort+6
        lda #>gfx
        sta ControlPort+7
        lda #<384
        sta ControlPort+8
        lda #>384
        sta ControlPort+9
        lda #3
        ldx #3                     ; 3,3 : Save File
        jsr appel
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #$FF
        sta ControlPort+6          ; $FFFF : mémoire graphique
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jmp appel
nomgfx: .byte 7
        .text "img.gfx"

; 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

gfx:    .byte 1, 1, 0, 0             ; en-tête : une tuile
        .fill 252
        .rept 16                   ; 16 lignes : gauche couleur 2, droite couleur 5
        .byte $22, $22, $22, $22, $55, $55, $55, $55
        .endrept
carte:  .byte 1, 2, 1, 0, 0         ; format, largeur 2, hauteur 1, tuiles 0 0
a:      .byte 0
b:      .byte 0
c:      .byte 0
t0:     .text "Couleurs sur la ligne : ", 0
t2:     .text " ", 0
t4:     .text " ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleurs sur la ligne : 2 5 2

5,36 Read Sprite Pixel Official

Reads the colour of a pixel of the sprite layer.

Inputs
BytesTypeMeaning
P0-P1int16point X
P2-P3int16point Y
Outputs
BytesTypeMeaning
P0uint8sprite colour (0 to 15), 0 if there is no sprite there or no sprites at all
erreuruint81 if the point is off screen

Sprites use the high 4 bits of screen memory, the background the low 4 bits. The example puts sprite 0 (16×16 image, anchored at its centre) over a background pixel of colour 6: 5,36 reads the sprite, 5,33 the background. It then clears the sprites (6,1). In NeoBASIC, spoint(x, y) makes this call.

NeoBASIC keywords that make this call: spoint()

Firmware documentation text

Read Pixel from the sprite layer at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (X,Y). When the routine completes, the result will be in Parameter:0. Refer to Section "Pixel Colors" for details.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

static uint8_t gfx[256 + 128];                  /* en-tête + une image 16x16, 4 bits par pixel */

static void images(uint8_t genre) {             /* 1 : une tuile ; 2 : un sprite 16x16 */
    gfx[0] = 1;
    gfx[genre] = 1;
    for (uint8_t y = 0; y < 16; y++)
        for (uint8_t i = 0; i < 8; i++)
            gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55;   /* gauche : couleur 2, droite : 5 */
    neo_file_store("img.gfx", gfx, sizeof gfx);
    neo_file_load("img.gfx", (void *)0xFFFF);   /* $FFFF : mémoire graphique */
}

/* Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36). */
int main(void) {
    images(2);                                  /* un sprite 16x16 */
    neo_graphics_set_color(6);
    neo_graphics_draw_pixel(200, 170);          /* fond : couleur 6 */
    neo_sprite_set(0, 200, 170, 0, 0, 0);       /* 6,2 : sprite 0, image 0 */
    libre();
    xy(0, 200, 170);
    api(5, 36);                                 /* Read Sprite Pixel */
    uint8_t a = ControlPort.params[0];
    uint8_t b = neo_graphics_read_pixel(200, 170);
    neo_sprite_reset();                         /* 6,1 */
    printf("Sprite : %u, fond : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sprite : 5, fond : 6
Mad Pascal
// Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36).
program spoint;
uses crt, neo6502;
var a, b: byte;
    gfx: array[0..383] of byte;                 // en-tête + une image 16x16

procedure images(genre: byte);                  // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
  fillchar(@gfx, 384, 0);
  gfx[0] := 1;
  gfx[genre] := 1;
  for y := 0 to 15 do
    for i := 0 to 7 do
      if i < 4 then gfx[256 + y * 8 + i] := $22   // gauche : couleur 2
      else gfx[256 + y * 8 + i] := $55;         // droite : couleur 5
  NeoSave('img.gfx', word(@gfx), 384);
  NeoLoad('img.gfx', $FFFF);                    // $FFFF : mémoire graphique
end;

begin
  images(2);                                    // un sprite 16x16
  NeoSetColor(6);
  NeoDrawPixel(200, 170);                       // fond : couleur 6
  NeoUpdateSprite(0, 200, 170, 0, 0, 0);        // 6,2 : sprite 0, image 0
  a := NeoGetSpritePixel(200, 170);             // Read Sprite Pixel
  b := NeoGetPixel(200, 170);
  NeoResetSprites;                              // 6,1
  writeln('Sprite : ', a, ', fond : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sprite : 5, fond : 6
NeoBASIC
10 ' Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 2, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 plot 0,0 ink 6 to 200,170 : ' fond : couleur 6
40 sprite 0 image $80 to 200,170 : ' $80 : premier sprite 16x16
50 a = spoint(200,170) : b = point(200,170)
60 sprite clear
70 print "Sprite : ";a;", fond : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sprite : 5, fond : 6
65C02 assembly (64tass)
; Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36).
        .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
        jsr images                 ; un sprite 16x16
        lda #6
        sta ControlPort+4
        ldx #64                    ; 5,64 : couleur 6
        jsr g5
        lda #200
        ldy #170
        jsr point1
        ldx #5                     ; 5,5 : fond
        jsr g5
        stz ControlPort+4          ; P0 : sprite 0
        lda #200
        sta ControlPort+5          ; P1-P2 : X
        stz ControlPort+6
        lda #170
        sta ControlPort+7          ; P3-P4 : Y
        stz ControlPort+8
        stz ControlPort+9          ; P5 : image 0
        stz ControlPort+10         ; P6 : pas de retournement
        stz ControlPort+11         ; P7 : ancre au centre
        lda #6
        ldx #2                     ; 6,2 : Sprite Set
        jsr appel
        lda #200
        ldy #170
        jsr point1
        ldx #36                    ; fonction 36 : Read Sprite Pixel
        jsr g5
        lda ControlPort+4
        sta a
        lda #200
        ldy #170
        jsr lire
        sta b
        lda #6
        ldx #1                     ; 6,1 : Sprite Reset
        jsr appel
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #<gfx
        sta ControlPort+6
        lda #>gfx
        sta ControlPort+7
        lda #<384
        sta ControlPort+8
        lda #>384
        sta ControlPort+9
        lda #3
        ldx #3                     ; 3,3 : Save File
        jsr appel
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #$FF
        sta ControlPort+6          ; $FFFF : mémoire graphique
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jmp appel
nomgfx: .byte 7
        .text "img.gfx"

; 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

gfx:    .byte 1, 0, 1, 0             ; en-tête : un sprite 16x16
        .fill 252
        .rept 16                   ; 16 lignes : gauche couleur 2, droite couleur 5
        .byte $22, $22, $22, $22, $55, $55, $55, $55
        .endrept
a:      .byte 0
b:      .byte 0
t0:     .text "Sprite : ", 0
t2:     .text ", fond : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Sprite : 5, fond : 6

5,37 Frame Count Official

Gives the number of screen refreshes (frames) since power-on.

Inputs: none.

Outputs
BytesTypeMeaning
P0-P3uint32number of frames

The counter changes at the start of each refresh: waiting for it to change synchronises a program with the screen (this is what NeoWaitForVblank does in Mad Pascal). The example waits for a change and prints the difference. In NeoBASIC, vblanks() makes this call.

NeoBASIC keywords that make this call: vblanks()

Firmware documentation text

Deposit into Parameters:0..3, the number of v-blanks (full screen redraws) which have occurred since power-on. This is updated at the start of each v-blank period.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Attendre la trame suivante (groupe 5, fonction 37). */
int main(void) {
    long t0 = neo_graphics_frame_count();       /* Frame Count */
    long t1;
    do
        t1 = neo_graphics_frame_count();
    while (t1 == t0);
    printf("Trame suivante : ecart %ld\n", t1 - t0);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Trame suivante : ecart 1
Mad Pascal
// Attendre la trame suivante (groupe 5, fonction 37).
program trames;
uses crt, neo6502;
var t0, t1: cardinal;
begin
  t0 := NeoGetVblanks;                          // Frame Count
  repeat
    t1 := NeoGetVblanks;
  until t1 <> t0;
  writeln('Trame suivante : ecart ', t1 - t0);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Trame suivante : ecart 1
NeoBASIC
10 ' Attendre la trame suivante (groupe 5, fonction 37)
20 t0 = vblanks()
30 repeat : t1 = vblanks() : until t1 <> t0
40 print "Trame suivante : ecart ";t1 - t0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Trame suivante : ecart 1
65C02 assembly (64tass)
; Attendre la trame suivante (groupe 5, fonction 37).
        .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 trame
        sta t0
_att:   jsr trame
        cmp t0
        beq _att
        sec
        sbc t0
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter

; Octet bas du compteur de trames (5,37) dans A.
trame:  jsr WaitMessage
        lda #5
        ldx #37                    ; fonction 37 : Frame Count
        jsr appel
        lda ControlPort+4
        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

t0:     .byte 0
m:      .text "Trame suivante : ecart ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Trame suivante : ecart 1

5,38 Get Palette Official

Reads the red, green and blue components of a palette entry.

Inputs
BytesTypeMeaning
P0uint8colour number
Outputs
BytesTypeMeaning
P1uint8red
P2uint8green
P3uint8blue

The example reads colours 0 to 2 of the original palette. llvm-mos has no function for this call: the C example makes it directly.

Firmware documentation text

Get the palette colour at the index spcified in Parameter:0. Values are returned in Parameter:1,Parameter:2,Parameter:3 (RGB).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

/* Lire les trois premières couleurs de la palette (groupe 5, fonction 38). */
int main(void) {
    for (uint8_t c = 0; c < 3; c++) {
        libre();
        ControlPort.params[0] = c;
        api(5, 38);                             /* Get Palette */
        printf("Couleur %u : %u %u %u\n", c, ControlPort.params[1], ControlPort.params[2], ControlPort.params[3]);
    }
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54
Mad Pascal
// Lire les trois premières couleurs de la palette (groupe 5, fonction 38).
program litpalette;
uses crt, neo6502;
var c, r, g, b: byte;
begin
  for c := 0 to 2 do
  begin
    NeoGetPalette(c, r, g, b);                  // Get Palette
    writeln('Couleur ', c, ' : ', r, ' ', g, ' ', b);
  end;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54
NeoBASIC
10 ' Lire les trois premieres couleurs de la palette (groupe 5, fonction 38)
20 for c = 0 to 2
30 while peek($ff00) : wend : poke $ff04, c : poke $ff01, 38 : poke $ff00, 5
40 while peek($ff00) : wend : r = peek($ff05) : g = peek($ff06) : b = peek($ff07)
50 print "Couleur ";c;" : ";r;" ";g;" ";b
60 next c
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54
65C02 assembly (64tass)
; Lire les trois premières couleurs de la palette (groupe 5, fonction 38).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  stz c
_suiv:  jsr WaitMessage
        lda c
        sta ControlPort+4          ; P0 : couleur
        lda #5
        ldx #38                    ; fonction 38 : Get Palette
        jsr appel
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda c
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        ldy #5
_rvb:   lda ControlPort,y          ; P1, P2, P3 ($FF05-$FF07)
        jsr decimal
        cpy #7
        beq _fin
        lda #' '
        jsr WriteCharacter
        iny
        bra _rvb
_fin:   lda #13
        jsr WriteCharacter
        inc c
        lda c
        cmp #3
        bne _suiv
        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

c:      .byte 0
t0:     .text "Couleur ", 0
t1:     .text " : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54

5,39 Write Pixel Official

Writes a colour as is into a pixel, with no mask nor EXCLUSIVE OR.

Inputs
BytesTypeMeaning
P0-P1int16point X
P2-P3int16point Y
P4uint8colour

Outputs: none.

Unlike 5,5, the result does not depend on the 5,1 settings: the example sets an EXCLUSIVE OR (mask $FF, colour 3) that would change a 5,5 drawing, then writes 9 and reads 9 back.

Firmware documentation text

Write Pixel index Parameter:4 to the screen coordinate specified in Parameters:0,1,Parameters:2,3 (X,Y).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Écrire une couleur telle quelle (groupe 5, fonction 39). */
int main(void) {
    neo_graphics_set_defaults(0xFF, 3, 0, 1, 0);   /* 5,1 : OU EXCLUSIF, sans effet ici */
    neo_graphics_write_pixel(210, 170, 9);      /* Write Pixel */
    printf("Pixel ecrit : %u\n", neo_graphics_read_pixel(210, 170));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel ecrit : 9
Mad Pascal
// Écrire une couleur telle quelle (groupe 5, fonction 39).
program ecrit;
uses crt, neo6502;
var a: byte;
begin
  NeoSetDefaults($FF, 3, 0, 1, 0);              // 5,1 : OU EXCLUSIF, sans effet ici
  NeoWritePixel(210, 170, 9);                   // Write Pixel
  a := NeoGetPixel(210, 170);
  writeln('Pixel ecrit : ', a);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel ecrit : 9
NeoBASIC
10 ' Ecrire une couleur telle quelle (groupe 5, fonction 39)
20 while peek($ff00) : wend
30 poke $ff04, 210 : poke $ff05, 0 : poke $ff06, 170 : poke $ff07, 0 : poke $ff08, 9 : poke $ff01, 39 : poke $ff00, 5
40 while peek($ff00) : wend
50 print "Pixel ecrit : ";point(210,170)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel ecrit : 9
65C02 assembly (64tass)
; Écrire une couleur telle quelle (groupe 5, fonction 39).
        .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 #$FF
        sta ControlPort+4          ; 5,1 : masque $FF, couleur 3 (sans effet ici)
        lda #3
        sta ControlPort+5
        stz ControlPort+6
        lda #1
        sta ControlPort+7
        stz ControlPort+8
        ldx #1
        jsr g5
        lda #210
        ldy #170
        jsr point1
        lda #9
        sta ControlPort+8          ; P4 : couleur 9
        ldx #39                    ; fonction 39 : Write Pixel
        jsr g5
        lda #210
        ldy #170
        jsr lire
        sta a
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
t0:     .text "Pixel ecrit : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel ecrit : 9

5,40 Get Late Scanlines Trinity

Gives the number of scanlines the second core could not produce in time since the last mode change (diagnostic).

Inputs: none.

Outputs
BytesTypeMeaning
P0-P3uint32number of late scanlines

Trinity only (T-32c). On the board, these lines show as coloured streaks; a counter that keeps growing while a program runs means the second core is overloaded. Emulators always return 0 (value checked by the bench).

Firmware documentation text

Returns in Parameters:0-3 the number of scanlines the display could not encode in time since the last mode change (Trinity T-32c, Function 5,40, diagnostic : these show as coloured streaks on the board ; 0 in the emulators). A counter that keeps growing while a program runs means the second core is starved.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

/* Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity). */
int main(void) {
    libre();
    api(5, 40);
    printf("Lignes en retard : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                                   | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lignes en retard : 0
Mad Pascal
// Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity).
program diag40;
uses crt, neo6502;
var valeur: cardinal;
begin
  NeoWaitMessage;
  NeoSendMessage(5, 40);
  NeoWaitMessage;
  valeur := dwordParams[0];
  writeln('Lignes en retard : ', valeur);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lignes en retard : 0
NeoBASIC
10 ' Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity)
20 while peek($ff00) : wend : poke $ff01, 40 : poke $ff00, 5
22 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
24 print "Lignes en retard : ";v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lignes en retard : 0
65C02 assembly (64tass)
; Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity).
; L'exemple asm n'affiche que l'octet bas de chaque compteur.
        .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 #5
        ldx #40                    ; fonction 40
        jsr appel
        lda ControlPort+4          ; octet bas
        sta v
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda v
        jsr decimal
        lda #13
        jsr WriteCharacter
        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

v:      .byte 0
t0:     .text "Lignes en retard : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Lignes en retard : 0

5,41 Get Bus Stalls Trinity

Gives one of the 6502 bus fault counters recorded by the RP2040 PIOs (diagnostic).

Inputs
BytesTypeMeaning
P0uint8counter: 0 TXSTALL (read data not ready in time), 1 RXSTALL (address FIFO not drained in time), 2 RXUNDER (empty FIFO read)
Outputs
BytesTypeMeaning
P0-P3uint32counter value

Trinity only (T-49, T-52). Emulators have no PIO and return 0 (value checked by the bench). The firmware documentation details the meaning of each counter.

Firmware documentation text

Returns in Parameters:0-3 one of the PIO fault counters of the 6502 bus, chosen by Parameter:0 on entry (Trinity T-49/T-52, diagnostic ; 0 in the emulators, which have no PIO) : 0 TXSTALL : the data of a read was not ready in time. 1 RXSTALL : the address FIFO was not drained in time. 2 RXUNDER : an EMPTY FIFO was read — the firmware then acts on a stale word and writes a phantom byte at a phantom address into the 6502 memory. This one corrupts the running program. 3 TXOVER : a read reply was pushed into a full FIFO and lost. The state machine generates the 6502 clock, so TXSTALL and RXSTALL merely stretch the processor and are normal while an API command is served ; RXUNDER and TXOVER are not, and any growth there is a fault. Sampled about 95 times a second, so these are windows containing at least one event, not exact counts. Pass $FF in Parameter:0 to reset all four (it then returns TXSTALL).

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

/* Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity). */
int main(void) {
    libre();
    ControlPort.params[0] = 0;
    api(5, 41);
    printf("TXSTALL : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                                   | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
    libre();
    ControlPort.params[0] = 1;
    api(5, 41);
    printf("RXSTALL : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                                   | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
    libre();
    ControlPort.params[0] = 2;
    api(5, 41);
    printf("RXUNDER : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                                   | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
TXSTALL : 0
RXSTALL : 0
RXUNDER : 0
Mad Pascal
// Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity).
program diag41;
uses crt, neo6502;
var valeur: cardinal;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 0;
  NeoSendMessage(5, 41);
  NeoWaitMessage;
  valeur := dwordParams[0];
  writeln('TXSTALL : ', valeur);
  NeoWaitMessage;
  NeoMessage.params[0] := 1;
  NeoSendMessage(5, 41);
  NeoWaitMessage;
  valeur := dwordParams[0];
  writeln('RXSTALL : ', valeur);
  NeoWaitMessage;
  NeoMessage.params[0] := 2;
  NeoSendMessage(5, 41);
  NeoWaitMessage;
  valeur := dwordParams[0];
  writeln('RXUNDER : ', valeur);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
TXSTALL : 0
RXSTALL : 0
RXUNDER : 0
NeoBASIC
10 ' Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity)
20 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 41 : poke $ff00, 5
22 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
24 print "TXSTALL : ";v
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 41 : poke $ff00, 5
32 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
34 print "RXSTALL : ";v
40 while peek($ff00) : wend : poke $ff04, 2 : poke $ff01, 41 : poke $ff00, 5
42 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
44 print "RXUNDER : ";v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
TXSTALL : 0
RXSTALL : 0
RXUNDER : 0
65C02 assembly (64tass)
; Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity).
; L'exemple asm n'affiche que l'octet bas de chaque compteur.
        .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 #0
        sta ControlPort+4          ; P0 : compteur choisi
        lda #5
        ldx #41                    ; fonction 41
        jsr appel
        lda ControlPort+4          ; octet bas
        sta v
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda v
        jsr decimal
        lda #13
        jsr WriteCharacter
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : compteur choisi
        lda #5
        ldx #41                    ; fonction 41
        jsr appel
        lda ControlPort+4          ; octet bas
        sta v
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda v
        jsr decimal
        lda #13
        jsr WriteCharacter
        jsr WaitMessage
        lda #2
        sta ControlPort+4          ; P0 : compteur choisi
        lda #5
        ldx #41                    ; fonction 41
        jsr appel
        lda ControlPort+4          ; octet bas
        sta v
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda v
        jsr decimal
        lda #13
        jsr WriteCharacter
        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

v:      .byte 0
t0:     .text "TXSTALL : ", 0
t1:     .text "RXSTALL : ", 0
t2:     .text "RXUNDER : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
TXSTALL : 0
RXSTALL : 0
RXUNDER : 0

5,42 Get Bus Timing Trinity

Gives a timing measure (diagnostic, T-50 and T-90): the longest synchronisation, the longest API command, or a display measure.

Inputs
BytesTypeMeaning
P0uint80: longest DSPSync (keyboard, USB, blink); 1: longest API command; display side (core 1): 2 longest processing of one line, 3 longest gap between two line callbacks (nominal: 32 in mode 1, 63 in modes 0 and 2, where each line is doubled and the callback runs every other line), 4 number of callbacks late by more than twice that nominal gap
Outputs
BytesTypeMeaning
P0-P3uint32duration in microseconds (0 to 3) or number of lines (4)

Trinity only (T-50). During these times, the firmware is away from the 6502 bus and the processor clock is stopped: normal for an API call, abnormal if it lasts. The bench emulator returns 0; its values do not measure the board.

Firmware documentation text

Returns in Parameters:0-3 a bus timing measure of Trinity T-50, chosen by Parameter:0 on entry : 0 the longest DSPSync ever seen in microseconds (keyboard, USB task, blink), 1 the longest API command (DSPHandler) ; Trinity T-90 adds the display side, core 1 : 2 the longest scanline callback (conversion of one line into the scan buffer), 3 the longest gap between two scanline callbacks (nominal : 32 in mode 1, whose lines are native, but 63 in modes 0 and 2, whose lines are doubled : the callback runs every other line), 4 the number of callbacks late by more than twice that nominal gap. 0 and 1 are the time the firmware spends away from the 6502 bus : while it is there the PIO stalls and the processor clock stops, which is normal for an API call and pathological when it lasts. Counts of stalls alone (Function 5,41) cannot tell the two apart, hence these. Reset with 5,41 and $FF. 0 in the emulators.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

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

static void xy(uint8_t i, uint16_t x, uint16_t y) {   /* point (x, y) en Pi..Pi+3 */
    ControlPort.params[i] = x & 0xFF;
    ControlPort.params[i + 1] = x >> 8;
    ControlPort.params[i + 2] = y & 0xFF;
    ControlPort.params[i + 3] = y >> 8;
}

/* Durées pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity). */
int main(void) {
    libre();
    ControlPort.params[0] = 0;
    api(5, 42);
    printf("DSPSync le plus long : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                                   | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
    libre();
    ControlPort.params[0] = 1;
    api(5, 42);
    printf("Commande la plus longue : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
                                   | ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
DSPSync le plus long : 0
Commande la plus longue : 0
Mad Pascal
// Durées pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity).
program diag42;
uses crt, neo6502;
var valeur: cardinal;
begin
  NeoWaitMessage;
  NeoMessage.params[0] := 0;
  NeoSendMessage(5, 42);
  NeoWaitMessage;
  valeur := dwordParams[0];
  writeln('DSPSync le plus long : ', valeur);
  NeoWaitMessage;
  NeoMessage.params[0] := 1;
  NeoSendMessage(5, 42);
  NeoWaitMessage;
  valeur := dwordParams[0];
  writeln('Commande la plus longue : ', valeur);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
DSPSync le plus long : 0
Commande la plus longue : 0
NeoBASIC
10 ' Durees pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity)
20 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 42 : poke $ff00, 5
22 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
24 print "DSPSync le plus long : ";v
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 42 : poke $ff00, 5
32 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
34 print "Commande la plus longue : ";v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
DSPSync le plus long : 0
Commande la plus longue : 0
65C02 assembly (64tass)
; Durées pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity).
; L'exemple asm n'affiche que l'octet bas de chaque compteur.
        .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 #0
        sta ControlPort+4          ; P0 : compteur choisi
        lda #5
        ldx #42                    ; fonction 42
        jsr appel
        lda ControlPort+4          ; octet bas
        sta v
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda v
        jsr decimal
        lda #13
        jsr WriteCharacter
        jsr WaitMessage
        lda #1
        sta ControlPort+4          ; P0 : compteur choisi
        lda #5
        ldx #42                    ; fonction 42
        jsr appel
        lda ControlPort+4          ; octet bas
        sta v
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda v
        jsr decimal
        lda #13
        jsr WriteCharacter
        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

v:      .byte 0
t0:     .text "DSPSync le plus long : ", 0
t1:     .text "Commande la plus longue : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
DSPSync le plus long : 0
Commande la plus longue : 0

5,64 Set Color Official

Selects the colour of the following drawings (mask set to 0).

Inputs
BytesTypeMeaning
P0uint8colour

Outputs: none.

Same as 5,1 with a mask of 0 and the given colour, leaving the other settings alone. NeoBASIC does not make this call (ink c makes 5,1): the BASIC example writes it with poke.

Firmware documentation text

Set Color Sets the current drawing colour to Parameter:0

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Choisir la couleur de tracé (groupe 5, fonction 64). */
int main(void) {
    neo_graphics_set_color(6);                  /* 5,64 : Set Color */
    neo_graphics_draw_pixel(210, 170);          /* 5,5 */
    uint8_t a = neo_graphics_read_pixel(210, 170);   /* 5,33 */
    uint8_t b = neo_graphics_read_pixel(211, 170);
    printf("Pixel (210, 170) : %u, voisin : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
Mad Pascal
// Choisir la couleur de tracé (groupe 5, fonction 64).
program pixel64;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(6);                               // 5,64 : Set Color
  NeoDrawPixel(210, 170);                       // 5,5
  a := NeoGetPixel(210, 170);                   // 5,33
  b := NeoGetPixel(211, 170);
  writeln('Pixel (210, 170) : ', a, ', voisin : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
NeoBASIC
10 ' Choisir la couleur de trace (groupe 5, fonction 64)
20 while peek($ff00) : wend : poke $ff04, 6 : poke $ff01, 64 : poke $ff00, 5 : ' Set Color
25 plot to 210,170
30 a = point(210,170) : b = point(211,170)
40 print "Pixel (210, 170) : ";a;", voisin : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0
65C02 assembly (64tass)
; Choisir la couleur de tracé (groupe 5, fonction 64).
        .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 #6
        sta ControlPort+4          ; P0 : couleur 6
        ldx #64                    ; 5,64 : Set Color
        jsr g5
        lda #210
        ldy #170
        jsr point1
        ldx #5                     ; 5,5 : Draw Pixel
        jsr g5
        lda #210
        ldy #170
        jsr lire                   ; 5,33 : Read Pixel
        sta a
        lda #211
        ldy #170
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        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

a:      .byte 0
b:      .byte 0
t0:     .text "Pixel (210, 170) : ", 0
t2:     .text ", voisin : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Pixel (210, 170) : 6, voisin : 0

5,65 Set Solid Flag Official

Sets the fill flag: solid shapes, and a solid background for text and images.

Inputs
BytesTypeMeaning
P0uint80: outline (transparent background); non zero: solid

Outputs: none.

In NeoBASIC, frame and solid make 5,1 with this flag.

Firmware documentation text

Set Solid Flag

Sets the solid flag to Parameter:0, which indicates either solid fill (for shapes) or solid background (for images and fonts)

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Le même rectangle en contour puis plein (groupe 5, fonction 65). */
int main(void) {
    neo_graphics_set_color(4);
    neo_graphics_set_solid_flag(0);             /* Set Solid Flag : contour */
    neo_graphics_draw_rectangle(150, 160, 190, 200);
    uint8_t a = neo_graphics_read_pixel(170, 180);   /* centre */
    neo_graphics_set_solid_flag(1);             /* plein */
    neo_graphics_draw_rectangle(150, 160, 190, 200);
    uint8_t b = neo_graphics_read_pixel(170, 180);
    printf("Contour : %u, plein : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Contour : 0, plein : 4
Mad Pascal
// Le même rectangle en contour puis plein (groupe 5, fonction 65).
program remplir;
uses crt, neo6502;
var a, b: byte;
begin
  NeoSetColor(4);
  NeoSetSolidFlag(0);                           // Set Solid Flag : contour
  NeoDrawRect(150, 160, 190, 200);
  a := NeoGetPixel(170, 180);                   // centre
  NeoSetSolidFlag(1);                           // plein
  NeoDrawRect(150, 160, 190, 200);
  b := NeoGetPixel(170, 180);
  writeln('Contour : ', a, ', plein : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Contour : 0, plein : 4
NeoBASIC
10 ' Le meme rectangle en contour puis plein (groupe 5, fonction 65)
20 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 65 : poke $ff00, 5 : ' contour
30 rect 150,160 ink 4 to 190,200 : a = point(170,180)
40 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 65 : poke $ff00, 5 : ' plein
50 rect 150,160 to 190,200 : b = point(170,180)
60 print "Contour : ";a;", plein : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Contour : 0, plein : 4
65C02 assembly (64tass)
; Le même rectangle en contour puis plein (groupe 5, fonction 65).
        .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 #4
        sta ControlPort+4
        ldx #64                    ; 5,64 : couleur 4
        jsr g5
        lda #0
        jsr rect                   ; contour
        sta a
        lda #1
        jsr rect                   ; plein
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Drapeau A (5,65), rectangle (150, 160)-(190, 200), couleur du centre dans A.
rect:   sta ControlPort+4
        ldx #65                    ; fonction 65 : Set Solid Flag
        jsr g5
        lda #150
        ldy #160
        jsr point1
        lda #190
        ldy #200
        jsr point2
        ldx #3                     ; 5,3 : rectangle
        jsr g5
        lda #170
        ldy #180
        jmp lire

; 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

a:      .byte 0
b:      .byte 0
t0:     .text "Contour : ", 0
t2:     .text ", plein : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Contour : 0, plein : 4

5,66 Set Draw Size Official

Selects the size (scale factor) of images and text.

Inputs
BytesTypeMeaning
P0uint8size: 1 normal, 2 double…

Outputs: none.

The point read is 20 pixels right of the corner: outside the image at size 1 (16 pixels wide), in its right half at size 2 (32 pixels). Size 2 is also used for 32×32 tile maps (5,8). In NeoBASIC, dim n makes 5,1 with this size.

Firmware documentation text

Set Draw Size

Sets the drawing scale for images and fonts to Parameter:0

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

static uint8_t gfx[256 + 128];                  /* en-tête + une image 16x16, 4 bits par pixel */

static void images(uint8_t genre) {             /* 1 : une tuile ; 2 : un sprite 16x16 */
    gfx[0] = 1;
    gfx[genre] = 1;
    for (uint8_t y = 0; y < 16; y++)
        for (uint8_t i = 0; i < 8; i++)
            gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55;   /* gauche : couleur 2, droite : 5 */
    neo_file_store("img.gfx", gfx, sizeof gfx);
    neo_file_load("img.gfx", (void *)0xFFFF);   /* $FFFF : mémoire graphique */
}

/* Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66). */
int main(void) {
    images(1);
    neo_graphics_set_draw_size(1);             /* 5,66 : Set Draw Size */
    neo_graphics_set_flip_bits(0);             /* 5,67 */
    neo_graphics_draw_image(150, 160, 0);         /* 5,7, image 0 */
    uint8_t a = neo_graphics_read_pixel(170, 165);
    neo_graphics_set_draw_size(2);             /* 5,66 : Set Draw Size */
    neo_graphics_set_flip_bits(0);             /* 5,67 */
    neo_graphics_draw_image(200, 160, 0);         /* 5,7, image 0 */
    uint8_t b = neo_graphics_read_pixel(220, 165);
    printf("Taille 1 : %u, taille 2 : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille 1 : 0, taille 2 : 5
Mad Pascal
// Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66).
program image66;
uses crt, neo6502;
var a, b: byte;
    gfx: array[0..383] of byte;                 // en-tête + une image 16x16

procedure images(genre: byte);                  // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
  fillchar(@gfx, 384, 0);
  gfx[0] := 1;
  gfx[genre] := 1;
  for y := 0 to 15 do
    for i := 0 to 7 do
      if i < 4 then gfx[256 + y * 8 + i] := $22   // gauche : couleur 2
      else gfx[256 + y * 8 + i] := $55;         // droite : couleur 5
  NeoSave('img.gfx', word(@gfx), 384);
  NeoLoad('img.gfx', $FFFF);                    // $FFFF : mémoire graphique
end;

begin
  images(1);
  NeoSetDrawSize(1);                            // 5,66 : Set Draw Size
  NeoSetFlip(0);                                // 5,67
  NeoDrawImage(150, 160, 0);                      // 5,7, image 0
  a := NeoGetPixel(170, 165);
  NeoSetDrawSize(2);                            // 5,66 : Set Draw Size
  NeoSetFlip(0);                                // 5,67
  NeoDrawImage(200, 160, 0);                      // 5,7, image 0
  b := NeoGetPixel(220, 165);
  writeln('Taille 1 : ', a, ', ', 'taille 2 : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille 1 : 0, taille 2 : 5
NeoBASIC
10 ' Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 66 : poke $ff00, 5 : ' taille
31 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
32 while peek($ff00) : wend : poke $ff04, 150 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
33 while peek($ff00) : wend : a = point(170,165)
40 while peek($ff00) : wend : poke $ff04, 2 : poke $ff01, 66 : poke $ff00, 5 : ' taille
41 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
42 while peek($ff00) : wend : poke $ff04, 200 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
43 while peek($ff00) : wend : b = point(220,165)
50 print "Taille 1 : ";a; ", ";"taille 2 : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille 1 : 0, taille 2 : 5
65C02 assembly (64tass)
; Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66).
        .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
        jsr images
        lda #1
        sta ControlPort+4
        ldx #66                    ; 5,66 : taille 1
        jsr g5
        lda #0
        sta ControlPort+4
        ldx #67                    ; 5,67 : retournement 0
        jsr g5
        lda #150
        ldy #160
        jsr point1
        stz ControlPort+8          ; P4 : image 0
        ldx #7                     ; 5,7 : Draw Image
        jsr g5
        lda #170
        ldy #165
        jsr lire
        sta a
        lda #2
        sta ControlPort+4
        ldx #66                    ; 5,66 : taille 2
        jsr g5
        lda #0
        sta ControlPort+4
        ldx #67                    ; 5,67 : retournement 0
        jsr g5
        lda #200
        ldy #160
        jsr point1
        stz ControlPort+8          ; P4 : image 0
        ldx #7                     ; 5,7 : Draw Image
        jsr g5
        lda #220
        ldy #165
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #<gfx
        sta ControlPort+6
        lda #>gfx
        sta ControlPort+7
        lda #<384
        sta ControlPort+8
        lda #>384
        sta ControlPort+9
        lda #3
        ldx #3                     ; 3,3 : Save File
        jsr appel
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #$FF
        sta ControlPort+6          ; $FFFF : mémoire graphique
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jmp appel
nomgfx: .byte 7
        .text "img.gfx"

; 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

gfx:    .byte 1, 1, 0, 0             ; en-tête : une tuile
        .fill 252
        .rept 16                   ; 16 lignes : gauche couleur 2, droite couleur 5
        .byte $22, $22, $22, $22, $55, $55, $55, $55
        .endrept
a:      .byte 0
b:      .byte 0
t0:     .text "Taille 1 : ", 0
t2:     .text ", ", 0
t3:     .text "taille 2 : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Taille 1 : 0, taille 2 : 5

5,67 Set Flip Bits Official

Sets the flipping of images: bit 0 horizontal, bit 1 vertical.

Inputs
BytesTypeMeaning
P0uint8bit 0: horizontal mirror; bit 1: vertical mirror

Outputs: none.

The image has its left half in colour 2: flipped horizontally, it shows colour 5 there. In NeoBASIC, image n, flip to x,y makes 5,1 with this setting.

Firmware documentation text

Set Flip Bits Sets the flip bits for drawing images. Bit 0 set causes a horizontal flip, bit 1 set causes a vertical flip.

C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

static uint8_t gfx[256 + 128];                  /* en-tête + une image 16x16, 4 bits par pixel */

static void images(uint8_t genre) {             /* 1 : une tuile ; 2 : un sprite 16x16 */
    gfx[0] = 1;
    gfx[genre] = 1;
    for (uint8_t y = 0; y < 16; y++)
        for (uint8_t i = 0; i < 8; i++)
            gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55;   /* gauche : couleur 2, droite : 5 */
    neo_file_store("img.gfx", gfx, sizeof gfx);
    neo_file_load("img.gfx", (void *)0xFFFF);   /* $FFFF : mémoire graphique */
}

/* Dessiner une image retournée (groupe 5, fonction 67). */
int main(void) {
    images(1);
    neo_graphics_set_draw_size(1);             /* 5,66 */
    neo_graphics_set_flip_bits(0);             /* 5,67 : Set Flip Bits */
    neo_graphics_draw_image(150, 160, 0);         /* 5,7, image 0 */
    uint8_t a = neo_graphics_read_pixel(152, 165);
    neo_graphics_set_draw_size(1);             /* 5,66 */
    neo_graphics_set_flip_bits(1);             /* 5,67 : Set Flip Bits */
    neo_graphics_draw_image(200, 160, 0);         /* 5,7, image 0 */
    uint8_t b = neo_graphics_read_pixel(202, 165);
    printf("Normale : %u, retournee : %u\n", a, b);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Normale : 2, retournee : 5
Mad Pascal
// Dessiner une image retournée (groupe 5, fonction 67).
program image67;
uses crt, neo6502;
var a, b: byte;
    gfx: array[0..383] of byte;                 // en-tête + une image 16x16

procedure images(genre: byte);                  // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
  fillchar(@gfx, 384, 0);
  gfx[0] := 1;
  gfx[genre] := 1;
  for y := 0 to 15 do
    for i := 0 to 7 do
      if i < 4 then gfx[256 + y * 8 + i] := $22   // gauche : couleur 2
      else gfx[256 + y * 8 + i] := $55;         // droite : couleur 5
  NeoSave('img.gfx', word(@gfx), 384);
  NeoLoad('img.gfx', $FFFF);                    // $FFFF : mémoire graphique
end;

begin
  images(1);
  NeoSetDrawSize(1);                            // 5,66
  NeoSetFlip(0);                                // 5,67 : Set Flip Bits
  NeoDrawImage(150, 160, 0);                      // 5,7, image 0
  a := NeoGetPixel(152, 165);
  NeoSetDrawSize(1);                            // 5,66
  NeoSetFlip(1);                                // 5,67 : Set Flip Bits
  NeoDrawImage(200, 160, 0);                      // 5,7, image 0
  b := NeoGetPixel(202, 165);
  writeln('Normale : ', a, ', ', 'retournee : ', b);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Normale : 2, retournee : 5
NeoBASIC
10 ' Dessiner une image retournee (groupe 5, fonction 67)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 66 : poke $ff00, 5 : ' taille
31 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
32 while peek($ff00) : wend : poke $ff04, 150 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
33 while peek($ff00) : wend : a = point(152,165)
40 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 66 : poke $ff00, 5 : ' taille
41 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
42 while peek($ff00) : wend : poke $ff04, 200 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
43 while peek($ff00) : wend : b = point(202,165)
50 print "Normale : ";a; ", ";"retournee : ";b
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Normale : 2, retournee : 5
65C02 assembly (64tass)
; Dessiner une image retournée (groupe 5, fonction 67).
        .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
        jsr images
        lda #1
        sta ControlPort+4
        ldx #66                    ; 5,66 : taille 1
        jsr g5
        lda #0
        sta ControlPort+4
        ldx #67                    ; 5,67 : retournement 0
        jsr g5
        lda #150
        ldy #160
        jsr point1
        stz ControlPort+8          ; P4 : image 0
        ldx #7                     ; 5,7 : Draw Image
        jsr g5
        lda #152
        ldy #165
        jsr lire
        sta a
        lda #1
        sta ControlPort+4
        ldx #66                    ; 5,66 : taille 1
        jsr g5
        lda #1
        sta ControlPort+4
        ldx #67                    ; 5,67 : retournement 1
        jsr g5
        lda #200
        ldy #160
        jsr point1
        stz ControlPort+8          ; P4 : image 0
        ldx #7                     ; 5,7 : Draw Image
        jsr g5
        lda #202
        ldy #165
        jsr lire
        sta b
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda b
        jsr decimal
        lda #13
        jmp WriteCharacter

; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
        stz ControlPort+5
        sty ControlPort+6
        stz ControlPort+7
        rts
point2: sta ControlPort+8
        stz ControlPort+9
        sty ControlPort+10
        stz ControlPort+11
        rts

; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire:   pha
        jsr WaitMessage
        pla
        jsr point1
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        rts

; Appel du groupe 5, fonction X.
g5:     lda #5
        jmp appel

; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #<gfx
        sta ControlPort+6
        lda #>gfx
        sta ControlPort+7
        lda #<384
        sta ControlPort+8
        lda #>384
        sta ControlPort+9
        lda #3
        ldx #3                     ; 3,3 : Save File
        jsr appel
        lda #<nomgfx
        sta ControlPort+4
        lda #>nomgfx
        sta ControlPort+5
        lda #$FF
        sta ControlPort+6          ; $FFFF : mémoire graphique
        sta ControlPort+7
        lda #3
        ldx #2                     ; 3,2 : Load File
        jmp appel
nomgfx: .byte 7
        .text "img.gfx"

; 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

gfx:    .byte 1, 1, 0, 0             ; en-tête : une tuile
        .fill 252
        .rept 16                   ; 16 lignes : gauche couleur 2, droite couleur 5
        .byte $22, $22, $22, $22, $55, $55, $55, $55
        .endrept
a:      .byte 0
b:      .byte 0
t0:     .text "Normale : ", 0
t2:     .text ", ", 0
t3:     .text "retournee : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Normale : 2, retournee : 5

← The Neo6502 API