Tachibana
Language: English

Group 39 — AGI Pictures Trinity

39,1 Draw Picture · 39,2 Show Picture · 39,3 Picture Duration · 39,4 Read Picture Point · 39,5 Draw Cel · 39,6 Restore Rect · 39,7 Add Cel To Plane · 39,8 Fill Plane Priority

Group 39 decodes and displays the pictures of Sierra AGI games (version 2), the interface asked for by the Neo6502AGI port. An AGI picture (PICTURE resource) is a series of drawing commands: visual colour (F0), priority (F2), lines (F6), fill (F8), end (FF). 39,1 decodes it into a 160 × 168 point plane kept at the start of graphics memory: one byte per point, priority in the high nibble, visual colour (0 to 15) in the low one. A cleared plane is colour 15, priority 4.

39,2 copies the colours of the plane to the screen (320 points wide, each point doubled; 8 or 4 bit per pixel modes). 39,4 reads a point of the plane. 39,5 and 39,6 draw and erase the cels of animated objects on the screen without writing the plane, which serves for the priority test: an object is hidden behind scenery of higher priority. 39,7 and 39,8 write into the plane (the add.to.pic command).

The examples use a 21 byte picture: a red rectangle (colour 12, priority 9) filled with yellow (14), from (20, 30) to (100, 80). They read plane points back with 39,4 or screen points with 5,33. Pictures, tiles and sprites use the same graphics memory: a program using this group must not use them. NeoBASIC has no keyword for this group: the example writes the mailbox ($FF00).

39,1 Draw Picture Trinity

Decodes an AGI picture (a Sierra PICTURE resource) into the 160 × 168 point plane.

Inputs
BytesTypeMeaning
P0-P1addraddress of the picture in 6502 RAM
P2-P3uint16length of the picture in bytes
P4uint8bit 0: clear the plane first (priority 4, colour 15)
Outputs
BytesTypeMeaning
erreuruint81 address outside 6502 RAM or length 0, 2 fill stack overflow

The plane is kept in graphics memory, one byte per point: priority in the high nibble, visual colour in the low one. A cleared plane is colour 15, priority 4. The picture of the examples (21 bytes) draws a red rectangle (colour 12, priority 9) and fills it with yellow (14): the plane is read back with 39,4. Without clearing (bit 0 at 0) a second picture is drawn over the first; with clearing it starts from an empty plane. Graphics memory is shared with sprites, tiles and images: a program using this group must not use them. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Trinity (T-107). Decodes the Sierra AGI v2 PICTURE resource at address Parameters:0,1 of 6502 RAM, length Parameters:2,3, into the 160x168 AGI plane kept at offset 0 of graphics memory (page $90, 26 880 bytes, one byte per pixel : priority in the high nibble, visual colour in the low nibble). If bit 0 of Parameter:4 is set the plane is first cleared (priority 4, visual 15). Generic : works for any AGI game. The 6502 is held for the whole decoding (a few ms to about 40 ms). Errors : 1 address range outside 6502 RAM or length 0, 2 fill stack overflow. The fill stack uses graphics memory just after the plane (offsets 26 880 to 30 975, 4 096 bytes). Graphics memory is shared with sprites, tiles and images : a program using this group must not use them.

C (llvm-mos)
/* Décoder une image AGI (groupe 39, fonction 1, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};
/* seconde image : un seul point de couleur 3 en (90,90) */
static const uint8_t img2[] = {0xF0, 0x03, 0xF6, 0x5A, 0x5A, 0xFF};

int main(void) {
    uint8_t e0, c1, p1, c2, p2, c3, p3, c4, p4, c5, p5, c6, p6, c7, p7, e1;
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    e0 = ControlPort.error;
    libre();
    ControlPort.params[0] = 20;
    ControlPort.params[1] = 30;
    api(39, 4);
    c1 = ControlPort.params[2];
    p1 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 50;
    ControlPort.params[1] = 50;
    api(39, 4);
    c2 = ControlPort.params[2];
    p2 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 5;
    ControlPort.params[1] = 5;
    api(39, 4);
    c3 = ControlPort.params[2];
    p3 = ControlPort.params[3];
    libre();
    p16(0, (uint16_t)img2);
    p16(2, sizeof img2);
    ControlPort.params[4] = 0;
    api(39, 1);
    libre();
    ControlPort.params[0] = 20;
    ControlPort.params[1] = 30;
    api(39, 4);
    c4 = ControlPort.params[2];
    p4 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 90;
    ControlPort.params[1] = 90;
    api(39, 4);
    c5 = ControlPort.params[2];
    p5 = ControlPort.params[3];
    libre();
    p16(0, (uint16_t)img2);
    p16(2, sizeof img2);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    ControlPort.params[0] = 20;
    ControlPort.params[1] = 30;
    api(39, 4);
    c6 = ControlPort.params[2];
    p6 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 90;
    ControlPort.params[1] = 90;
    api(39, 4);
    c7 = ControlPort.params[2];
    p7 = ControlPort.params[3];
    libre();
    p16(0, (uint16_t)img);
    p16(2, 0);
    ControlPort.params[4] = 1;
    api(39, 1);
    e1 = ControlPort.error;
    printf("Image : erreur %u\n", e0);
    printf("Trait : couleur %u, priorite %u\n", c1, p1);
    printf("Interieur : couleur %u, priorite %u\n", c2, p2);
    printf("Fond : couleur %u, priorite %u\n", c3, p3);
    printf("Sans effacement : trait %u, point %u\n", c4, c5);
    printf("Avec effacement : trait %u, point %u\n", c6, c7);
    printf("Longueur 0 : erreur %u\n", e1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Image : erreur 0
Trait : couleur 12, priorite 9
Interieur : couleur 14, priorite 9
Fond : couleur 15, priorite 4
Sans effacement : trait 12, point 3
Avec effacement : trait 15, point 3
Longueur 0 : erreur 1
Mad Pascal
// Décoder une image AGI (groupe 39, fonction 1, Trinity).
program agi1;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);
// seconde image : un seul point de couleur 3 en (90,90)
const img2: array[0..5] of byte = ($F0, $03, $F6, $5A, $5A, $FF);

var e0, c1, p1, c2, p2, c3, p3, c4, p4, c5, p5, c6, p6, c7, p7, e1: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  e0 := NeoMessage.error;
  NeoWaitMessage;
  NeoMessage.params[0] := 20;
  NeoMessage.params[1] := 30;
  appel(39, 4);
  c1 := NeoMessage.params[2];
  p1 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 50;
  NeoMessage.params[1] := 50;
  appel(39, 4);
  c2 := NeoMessage.params[2];
  p2 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 5;
  NeoMessage.params[1] := 5;
  appel(39, 4);
  c3 := NeoMessage.params[2];
  p3 := NeoMessage.params[3];
  NeoWaitMessage;
  p16(0, word(@img2));
  p16(2, 6);
  NeoMessage.params[4] := 0;
  appel(39, 1);
  NeoWaitMessage;
  NeoMessage.params[0] := 20;
  NeoMessage.params[1] := 30;
  appel(39, 4);
  c4 := NeoMessage.params[2];
  p4 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 90;
  NeoMessage.params[1] := 90;
  appel(39, 4);
  c5 := NeoMessage.params[2];
  p5 := NeoMessage.params[3];
  NeoWaitMessage;
  p16(0, word(@img2));
  p16(2, 6);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  NeoMessage.params[0] := 20;
  NeoMessage.params[1] := 30;
  appel(39, 4);
  c6 := NeoMessage.params[2];
  p6 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 90;
  NeoMessage.params[1] := 90;
  appel(39, 4);
  c7 := NeoMessage.params[2];
  p7 := NeoMessage.params[3];
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 0);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  e1 := NeoMessage.error;
  writeln('Image : erreur ', e0);
  writeln('Trait : couleur ', c1, ', priorite ', p1);
  writeln('Interieur : couleur ', c2, ', priorite ', p2);
  writeln('Fond : couleur ', c3, ', priorite ', p3);
  writeln('Sans effacement : trait ', c4, ', point ', c5);
  writeln('Avec effacement : trait ', c6, ', point ', c7);
  writeln('Longueur 0 : erreur ', e1);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Image : erreur 0
Trait : couleur 12, priorite 9
Interieur : couleur 14, priorite 9
Fond : couleur 15, priorite 4
Sans effacement : trait 12, point 3
Avec effacement : trait 15, point 3
Longueur 0 : erreur 1
NeoBASIC
10 ' Décoder une image AGI (groupe 39, fonction 1, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 ' seconde image : un seul point de couleur 3 en (90,90)
90 dj = alloc(6)
100 poke dj + 0, 240 : poke dj + 1, 3 : poke dj + 2, 246 : poke dj + 3, 90 : poke dj + 4, 90 : poke dj + 5, 255
110 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
120 e0 = e
130 while peek($ff00) : wend : poke $ff04 + 0, 20 : poke $ff04 + 1, 30 : f = 4 : gosub 8100
140 c1 = peek($ff04 + 2)
150 p1 = peek($ff04 + 3)
160 while peek($ff00) : wend : poke $ff04 + 0, 50 : poke $ff04 + 1, 50 : f = 4 : gosub 8100
170 c2 = peek($ff04 + 2)
180 p2 = peek($ff04 + 3)
190 while peek($ff00) : wend : poke $ff04 + 0, 5 : poke $ff04 + 1, 5 : f = 4 : gosub 8100
200 c3 = peek($ff04 + 2)
210 p3 = peek($ff04 + 3)
220 while peek($ff00) : wend : doke $ff04 + 0, dj : doke $ff04 + 2, 6 : poke $ff04 + 4, 0 : f = 1 : gosub 8100
230 while peek($ff00) : wend : poke $ff04 + 0, 20 : poke $ff04 + 1, 30 : f = 4 : gosub 8100
240 c4 = peek($ff04 + 2)
250 p4 = peek($ff04 + 3)
260 while peek($ff00) : wend : poke $ff04 + 0, 90 : poke $ff04 + 1, 90 : f = 4 : gosub 8100
270 c5 = peek($ff04 + 2)
280 p5 = peek($ff04 + 3)
290 while peek($ff00) : wend : doke $ff04 + 0, dj : doke $ff04 + 2, 6 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
300 while peek($ff00) : wend : poke $ff04 + 0, 20 : poke $ff04 + 1, 30 : f = 4 : gosub 8100
310 c6 = peek($ff04 + 2)
320 p6 = peek($ff04 + 3)
330 while peek($ff00) : wend : poke $ff04 + 0, 90 : poke $ff04 + 1, 90 : f = 4 : gosub 8100
340 c7 = peek($ff04 + 2)
350 p7 = peek($ff04 + 3)
360 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 0 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
370 e1 = e
380 print "Image : erreur ";e0
390 print "Trait : couleur ";c1;", priorite ";p1
400 print "Interieur : couleur ";c2;", priorite ";p2
410 print "Fond : couleur ";c3;", priorite ";p3
420 print "Sans effacement : trait ";c4;", point ";c5
430 print "Avec effacement : trait ";c6;", point ";c7
440 print "Longueur 0 : erreur ";e1
450 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Image : erreur 0
Trait : couleur 12, priorite 9
Interieur : couleur 14, priorite 9
Fond : couleur 15, priorite 4
Sans effacement : trait 12, point 3
Avec effacement : trait 15, point 3
Longueur 0 : erreur 1
65C02 assembly (64tass)
; Décoder une image AGI (groupe 39, fonction 1, 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 #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        lda ControlPort+2
        sta e0
        jsr WaitMessage
        lda #20
        sta ControlPort+4
        lda #30
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c1
        lda ControlPort+7
        sta p1
        jsr WaitMessage
        lda #50
        sta ControlPort+4
        lda #50
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c2
        lda ControlPort+7
        sta p2
        jsr WaitMessage
        lda #5
        sta ControlPort+4
        lda #5
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c3
        lda ControlPort+7
        sta p3
        jsr WaitMessage
        lda #<img2
        sta ControlPort+4
        lda #>img2
        sta ControlPort+5
        lda #<(fimg2-img2)
        sta ControlPort+6
        lda #>(fimg2-img2)
        sta ControlPort+7
        stz ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #20
        sta ControlPort+4
        lda #30
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c4
        lda ControlPort+7
        sta p4
        jsr WaitMessage
        lda #90
        sta ControlPort+4
        lda #90
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c5
        lda ControlPort+7
        sta p5
        jsr WaitMessage
        lda #<img2
        sta ControlPort+4
        lda #>img2
        sta ControlPort+5
        lda #<(fimg2-img2)
        sta ControlPort+6
        lda #>(fimg2-img2)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #20
        sta ControlPort+4
        lda #30
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c6
        lda ControlPort+7
        sta p6
        jsr WaitMessage
        lda #90
        sta ControlPort+4
        lda #90
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c7
        lda ControlPort+7
        sta p7
        jsr WaitMessage
        lda #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<0
        sta ControlPort+6
        lda #>0
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        lda ControlPort+2
        sta e1
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda c3
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda c4
        jsr decimal
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda c5
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda c6
        jsr decimal
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda c7
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t8
        ldx #>t8
        jsr ecrire
        lda e1
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
; seconde image : un seul point de couleur 3 en (90,90)
img2:
        .byte $F0, $03, $F6, $5A, $5A, $FF
fimg2:
e0: .byte 0
c1: .byte 0
p1: .byte 0
c2: .byte 0
p2: .byte 0
c3: .byte 0
p3: .byte 0
c4: .byte 0
p4: .byte 0
c5: .byte 0
p5: .byte 0
c6: .byte 0
p6: .byte 0
c7: .byte 0
p7: .byte 0
e1: .byte 0
t0: .text "Image : erreur ", 0
t1: .text "Trait : couleur ", 0
t2: .text ", priorite ", 0
t3: .text "Interieur : couleur ", 0
t4: .text "Fond : couleur ", 0
t5: .text "Sans effacement : trait ", 0
t6: .text ", point ", 0
t7: .text "Avec effacement : trait ", 0
t8: .text "Longueur 0 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Image : erreur 0
Trait : couleur 12, priorite 9
Interieur : couleur 14, priorite 9
Fond : couleur 15, priorite 4
Sans effacement : trait 12, point 3
Avec effacement : trait 15, point 3
Longueur 0 : erreur 1

39,2 Show Picture Trinity

Copies the colours of the AGI picture to the screen, each point doubled in width (320 × 168).

Inputs
BytesTypeMeaning
P0-P1uint16screen line for the top of the picture
Outputs
BytesTypeMeaning
erreuruint81 if the mode is not 320 points wide with 8 or 4 bits, or if the picture does not fit

Only the colours (0 to 15) are copied; the palette is not changed. The example shows the picture at line 72 of mode 0 (72 + 168 = 240) and reads the screen back with 5,33: picture point (20, 30) takes screen pixels 40 and 41 of line 102, point (19, 30) pixels 38 and 39. At line 100 the picture runs off the screen: error 1. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Copies the visual colours (0-15) of the AGI plane to the screen draw page, from line Parameters:0,1, each pixel doubled in width (320 x 168). Modes 320 pixels wide with 8 or 4 bits per pixel. The palette is not changed. Error 1 if the mode is not supported or the picture does not fit.

C (llvm-mos)
/* Montrer l'image AGI à l'écran (groupe 39, fonction 2, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};

int main(void) {
    uint8_t e0, a1, a2, a3, a4, e1;
    putchar(12);                                /* efface l'écran avant toute mesure */
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    p16(0, 72);
    api(39, 2);
    e0 = ControlPort.error;
    libre(); p16(0, 40); p16(2, 102); api(5, 33); a1 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 41); p16(2, 102); api(5, 33); a2 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 38); p16(2, 102); api(5, 33); a3 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 100); p16(2, 122); api(5, 33); a4 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre();
    p16(0, 100);
    api(39, 2);
    e1 = ControlPort.error;
    printf("Montrer : erreur %u\n", e0);
    printf("Trait : %u %u, a gauche : %u\n", a1, a2, a3);
    printf("Interieur : %u\n", a4);
    printf("Ligne 100 : erreur %u\n", e1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Montrer : erreur 0
Trait : 12 12, a gauche : 15
Interieur : 14
Ligne 100 : erreur 1
Mad Pascal
// Montrer l'image AGI à l'écran (groupe 39, fonction 2, Trinity).
program agi2;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);

var e0, a1, a2, a3, a4, e1: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  write(chr(12));                               // efface l'écran avant toute mesure
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  p16(0, 72);
  appel(39, 2);
  e0 := NeoMessage.error;
  NeoWaitMessage; p16(0, 40); p16(2, 102); appel(5, 33); a1 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 41); p16(2, 102); appel(5, 33); a2 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 38); p16(2, 102); appel(5, 33); a3 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 100); p16(2, 122); appel(5, 33); a4 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage;
  p16(0, 100);
  appel(39, 2);
  e1 := NeoMessage.error;
  writeln('Montrer : erreur ', e0);
  writeln('Trait : ', a1, ' ', a2, ', a gauche : ', a3);
  writeln('Interieur : ', a4);
  writeln('Ligne 100 : erreur ', e1);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Montrer : erreur 0
Trait : 12 12, a gauche : 15
Interieur : 14
Ligne 100 : erreur 1
NeoBASIC
10 ' Montrer l'image AGI à l'écran (groupe 39, fonction 2, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 cls
90 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
100 while peek($ff00) : wend : doke $ff04 + 0, 72 : f = 2 : gosub 8100
110 e0 = e
120 while peek($ff00) : wend : doke $ff04, 40 : doke $ff06, 102 : f = 33 : g = 5 : gosub 8110 : a1 = peek($ff04)
130 while peek($ff00) : wend : doke $ff04, 41 : doke $ff06, 102 : f = 33 : g = 5 : gosub 8110 : a2 = peek($ff04)
140 while peek($ff00) : wend : doke $ff04, 38 : doke $ff06, 102 : f = 33 : g = 5 : gosub 8110 : a3 = peek($ff04)
150 while peek($ff00) : wend : doke $ff04, 100 : doke $ff06, 122 : f = 33 : g = 5 : gosub 8110 : a4 = peek($ff04)
160 while peek($ff00) : wend : doke $ff04 + 0, 100 : f = 2 : gosub 8100
170 e1 = e
180 print "Montrer : erreur ";e0
190 print "Trait : ";a1;" ";a2;", a gauche : ";a3
200 print "Interieur : ";a4
210 print "Ligne 100 : erreur ";e1
220 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Montrer : erreur 0
Trait : 12 12, a gauche : 15
Interieur : 14
Ligne 100 : erreur 1
65C02 assembly (64tass)
; Montrer l'image AGI à l'écran (groupe 39, fonction 2, 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 #12                    ; efface l'écran avant toute mesure
        jsr WriteCharacter
        jsr WaitMessage
        lda #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #<72
        sta ControlPort+4
        lda #>72
        sta ControlPort+5
        lda #39
        ldx #2
        jsr appel
        lda ControlPort+2
        sta e0
        jsr WaitMessage
        lda #<40
        sta ControlPort+4
        lda #>40
        sta ControlPort+5
        lda #<102
        sta ControlPort+6
        lda #>102
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a1
        jsr WaitMessage
        lda #<41
        sta ControlPort+4
        lda #>41
        sta ControlPort+5
        lda #<102
        sta ControlPort+6
        lda #>102
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a2
        jsr WaitMessage
        lda #<38
        sta ControlPort+4
        lda #>38
        sta ControlPort+5
        lda #<102
        sta ControlPort+6
        lda #>102
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a3
        jsr WaitMessage
        lda #<100
        sta ControlPort+4
        lda #>100
        sta ControlPort+5
        lda #<122
        sta ControlPort+6
        lda #>122
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a4
        jsr WaitMessage
        lda #<100
        sta ControlPort+4
        lda #>100
        sta ControlPort+5
        lda #39
        ldx #2
        jsr appel
        lda ControlPort+2
        sta e1
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda a2
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda a3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda a4
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda e1
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
e0: .byte 0
a1: .byte 0
a2: .byte 0
a3: .byte 0
a4: .byte 0
e1: .byte 0
t0: .text "Montrer : erreur ", 0
t1: .text "Trait : ", 0
t2: .text " ", 0
t3: .text ", a gauche : ", 0
t4: .text "Interieur : ", 0
t5: .text "Ligne 100 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Montrer : erreur 0
Trait : 12 12, a gauche : 15
Interieur : 14
Ligne 100 : erreur 1

39,3 Picture Duration Trinity

Gives the duration of the last picture decoding, in microseconds.

Inputs: none.

Outputs
BytesTypeMeaning
P0-P3uint32duration of 39,1 in microseconds (0 on the emulators)

The duration is measured on the board only: the emulators answer 0, which is what the example prints (the four bytes P0 to P3). On the board expect a few milliseconds up to about forty, depending on the picture. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Returns in Parameters:0-3 the duration of the last Draw Picture in microseconds (board only, 0 on the emulators).

C (llvm-mos)
/* Durée du décodage d'une image AGI (groupe 39, fonction 3, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};

int main(void) {
    uint8_t d0, d1, d2, d3;
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    api(39, 3);
    d0 = ControlPort.params[0];
    d1 = ControlPort.params[1];
    d2 = ControlPort.params[2];
    d3 = ControlPort.params[3];
    printf("Duree : %u %u %u %u\n", d0, d1, d2, d3);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Duree : 0 0 0 0
Mad Pascal
// Durée du décodage d'une image AGI (groupe 39, fonction 3, Trinity).
program agi3;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);

var d0, d1, d2, d3: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  appel(39, 3);
  d0 := NeoMessage.params[0];
  d1 := NeoMessage.params[1];
  d2 := NeoMessage.params[2];
  d3 := NeoMessage.params[3];
  writeln('Duree : ', d0, ' ', d1, ' ', d2, ' ', d3);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Duree : 0 0 0 0
NeoBASIC
10 ' Durée du décodage d'une image AGI (groupe 39, fonction 3, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
90 while peek($ff00) : wend : f = 3 : gosub 8100
100 d0 = peek($ff04 + 0)
110 d1 = peek($ff04 + 1)
120 d2 = peek($ff04 + 2)
130 d3 = peek($ff04 + 3)
140 print "Duree : ";d0;" ";d1;" ";d2;" ";d3
150 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Duree : 0 0 0 0
65C02 assembly (64tass)
; Durée du décodage d'une image AGI (groupe 39, fonction 3, 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 #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #39
        ldx #3
        jsr appel
        lda ControlPort+4
        sta d0
        lda ControlPort+5
        sta d1
        lda ControlPort+6
        sta d2
        lda ControlPort+7
        sta d3
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda d0
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda d1
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda d2
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda d3
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
d0: .byte 0
d1: .byte 0
d2: .byte 0
d3: .byte 0
t0: .text "Duree : ", 0
t1: .text " ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Duree : 0 0 0 0

39,4 Read Picture Point Trinity

Reads the colour and the priority of a point of the AGI plane.

Inputs
BytesTypeMeaning
P0uint8X (0 to 159)
P1uint8Y (0 to 167)
Outputs
BytesTypeMeaning
P2uint8visual colour (0 to 15)
P3uint8priority (0 to 15)
erreuruint81 if the point is outside the plane

The coordinates are those of the plane (160 × 168), not of the screen. Outside the plane the error is 1 and P2, P3 are left unchanged. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Returns the visual colour (Parameter:2) and the priority (Parameter:3) of the point Parameter:0, Parameter:1 (X 0-159, Y 0-167) of the AGI plane. Error 1 if out of range.

C (llvm-mos)
/* Lire un point du plan AGI (groupe 39, fonction 4, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};

int main(void) {
    uint8_t c1, p1, c2, p2, c3, p3, c4, p4, e1, c5, p5, e2;
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    ControlPort.params[0] = 20;
    ControlPort.params[1] = 30;
    api(39, 4);
    c1 = ControlPort.params[2];
    p1 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 50;
    ControlPort.params[1] = 50;
    api(39, 4);
    c2 = ControlPort.params[2];
    p2 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 5;
    ControlPort.params[1] = 5;
    api(39, 4);
    c3 = ControlPort.params[2];
    p3 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 160;
    ControlPort.params[1] = 0;
    api(39, 4);
    c4 = ControlPort.params[2];
    p4 = ControlPort.params[3];
    e1 = ControlPort.error;
    libre();
    ControlPort.params[0] = 0;
    ControlPort.params[1] = 168;
    api(39, 4);
    c5 = ControlPort.params[2];
    p5 = ControlPort.params[3];
    e2 = ControlPort.error;
    printf("Trait (20, 30) : couleur %u, priorite %u\n", c1, p1);
    printf("Dedans (50, 50) : couleur %u, priorite %u\n", c2, p2);
    printf("Fond (5, 5) : couleur %u, priorite %u\n", c3, p3);
    printf("X = 160 : erreur %u ; Y = 168 : erreur %u\n", e1, e2);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Trait (20, 30) : couleur 12, priorite 9
Dedans (50, 50) : couleur 14, priorite 9
Fond (5, 5) : couleur 15, priorite 4
X = 160 : erreur 1 ; Y = 168 : erreur 1
Mad Pascal
// Lire un point du plan AGI (groupe 39, fonction 4, Trinity).
program agi4;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);

var c1, p1, c2, p2, c3, p3, c4, p4, e1, c5, p5, e2: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  NeoMessage.params[0] := 20;
  NeoMessage.params[1] := 30;
  appel(39, 4);
  c1 := NeoMessage.params[2];
  p1 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 50;
  NeoMessage.params[1] := 50;
  appel(39, 4);
  c2 := NeoMessage.params[2];
  p2 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 5;
  NeoMessage.params[1] := 5;
  appel(39, 4);
  c3 := NeoMessage.params[2];
  p3 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 160;
  NeoMessage.params[1] := 0;
  appel(39, 4);
  c4 := NeoMessage.params[2];
  p4 := NeoMessage.params[3];
  e1 := NeoMessage.error;
  NeoWaitMessage;
  NeoMessage.params[0] := 0;
  NeoMessage.params[1] := 168;
  appel(39, 4);
  c5 := NeoMessage.params[2];
  p5 := NeoMessage.params[3];
  e2 := NeoMessage.error;
  writeln('Trait (20, 30) : couleur ', c1, ', priorite ', p1);
  writeln('Dedans (50, 50) : couleur ', c2, ', priorite ', p2);
  writeln('Fond (5, 5) : couleur ', c3, ', priorite ', p3);
  writeln('X = 160 : erreur ', e1, ' ; Y = 168 : erreur ', e2);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Trait (20, 30) : couleur 12, priorite 9
Dedans (50, 50) : couleur 14, priorite 9
Fond (5, 5) : couleur 15, priorite 4
X = 160 : erreur 1 ; Y = 168 : erreur 1
NeoBASIC
10 ' Lire un point du plan AGI (groupe 39, fonction 4, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
90 while peek($ff00) : wend : poke $ff04 + 0, 20 : poke $ff04 + 1, 30 : f = 4 : gosub 8100
100 c1 = peek($ff04 + 2)
110 p1 = peek($ff04 + 3)
120 while peek($ff00) : wend : poke $ff04 + 0, 50 : poke $ff04 + 1, 50 : f = 4 : gosub 8100
130 c2 = peek($ff04 + 2)
140 p2 = peek($ff04 + 3)
150 while peek($ff00) : wend : poke $ff04 + 0, 5 : poke $ff04 + 1, 5 : f = 4 : gosub 8100
160 c3 = peek($ff04 + 2)
170 p3 = peek($ff04 + 3)
180 while peek($ff00) : wend : poke $ff04 + 0, 160 : poke $ff04 + 1, 0 : f = 4 : gosub 8100
190 c4 = peek($ff04 + 2)
200 p4 = peek($ff04 + 3)
210 e1 = e
220 while peek($ff00) : wend : poke $ff04 + 0, 0 : poke $ff04 + 1, 168 : f = 4 : gosub 8100
230 c5 = peek($ff04 + 2)
240 p5 = peek($ff04 + 3)
250 e2 = e
260 print "Trait (20, 30) : couleur ";c1;", priorite ";p1
270 print "Dedans (50, 50) : couleur ";c2;", priorite ";p2
280 print "Fond (5, 5) : couleur ";c3;", priorite ";p3
290 print "X = 160 : erreur ";e1;" ; Y = 168 : erreur ";e2
300 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Trait (20, 30) : couleur 12, priorite 9
Dedans (50, 50) : couleur 14, priorite 9
Fond (5, 5) : couleur 15, priorite 4
X = 160 : erreur 1 ; Y = 168 : erreur 1
65C02 assembly (64tass)
; Lire un point du plan AGI (groupe 39, fonction 4, 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 #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #20
        sta ControlPort+4
        lda #30
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c1
        lda ControlPort+7
        sta p1
        jsr WaitMessage
        lda #50
        sta ControlPort+4
        lda #50
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c2
        lda ControlPort+7
        sta p2
        jsr WaitMessage
        lda #5
        sta ControlPort+4
        lda #5
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c3
        lda ControlPort+7
        sta p3
        jsr WaitMessage
        lda #160
        sta ControlPort+4
        stz ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c4
        lda ControlPort+7
        sta p4
        lda ControlPort+2
        sta e1
        jsr WaitMessage
        stz ControlPort+4
        lda #168
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c5
        lda ControlPort+7
        sta p5
        lda ControlPort+2
        sta e2
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda p1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda p2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda c3
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda p3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda e1
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda e2
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
c1: .byte 0
p1: .byte 0
c2: .byte 0
p2: .byte 0
c3: .byte 0
p3: .byte 0
c4: .byte 0
p4: .byte 0
e1: .byte 0
c5: .byte 0
p5: .byte 0
e2: .byte 0
t0: .text "Trait (20, 30) : couleur ", 0
t1: .text ", priorite ", 0
t2: .text "Dedans (50, 50) : couleur ", 0
t3: .text "Fond (5, 5) : couleur ", 0
t4: .text "X = 160 : erreur ", 0
t5: .text " ; Y = 168 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Trait (20, 30) : couleur 12, priorite 9
Dedans (50, 50) : couleur 14, priorite 9
Fond (5, 5) : couleur 15, priorite 4
X = 160 : erreur 1 ; Y = 168 : erreur 1

39,5 Draw Cel Trinity

Draws an AGI view cel to the screen, without touching the plane.

Inputs
BytesTypeMeaning
P0-P1addraddress of the cel header in 6502 RAM
P2uint8X of the left side
P3uint8Y of the bottom line
P4uint8object priority
P5uint8bit 0: mirror horizontally
P6-P7uint16screen line of the top of the plane
Outputs
BytesTypeMeaning
erreuruint81 empty cel, position outside the plane, header outside RAM or unsupported mode; 2 cel data cut by the end of RAM

The cel starts with its width, its height and a byte in PC format (bit 7 mirror, bits 6 to 4 loop, low nibble transparent colour); then the lines, a series of bytes "colour in the high nibble, length in the low nibble", 0 at the end of a line. A point is drawn if it is not transparent and if the object priority is greater than or equal to the plane priority there. The plane is never written. The example draws the 4 × 2 point cel with priority 12 on the inside of the rectangle (priority 9): it shows, the transparent point lets the yellow through. With priority 5 it is hidden, and the plane stays 14 / 9. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Trinity (T-109). Draws the AGI view cel whose header (width, height, then a byte in PC format : bit 7 mirror, bits 6-4 normal loop, low nibble transparent colour ; only the transparent colour is read, then the RLE lines : colour in the high nibble, length in the low nibble, 0 at the end of each line) is at address Parameters:0,1 of 6502 RAM, its left side at X Parameter:2, its bottom line at Y Parameter:3 (AGI pixels), with the object priority Parameter:4 ; bit 0 of Parameter:5 mirrors it horizontally. The plane top is at screen line Parameters:6,7. A pixel is drawn when it is not transparent and the object priority is greater than or equal to the plane priority at that point ; on a control line (priority 0 to 3) the first point below which is not one is used, 15 if the bottom is reached (assumptions, see Neo6502AGI docs/specs/view-v2.md). The cel is clipped to the plane ; a line longer than the width is cut. Draw Cel never writes the plane. The caller handles the order of the objects : after Restore Rect has erased an object, the objects it overlapped must be drawn again. Errors : 1 empty cel, position outside the plane, header outside 6502 RAM or unsupported mode ; 2 cel data cut by the end of 6502 RAM.

C (llvm-mos)
/* Dessiner un cel sur l'image (groupe 39, fonction 5, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};
/* cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne) */
static const uint8_t cel[] = {0x04, 0x02, 0x00, 0x01, 0x32, 0x11, 0x00, 0x24, 0x00};

int main(void) {
    uint8_t e0, a1, a2, a3, a4, e1, a5, c1, p1;
    putchar(12);                                /* efface l'écran avant toute mesure */
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    p16(0, 72);
    api(39, 2);
    libre();
    p16(0, (uint16_t)cel);
    ControlPort.params[2] = 60;
    ControlPort.params[3] = 60;
    ControlPort.params[4] = 12;
    ControlPort.params[5] = 0;
    p16(6, 72);
    api(39, 5);
    e0 = ControlPort.error;
    libre(); p16(0, 120); p16(2, 131); api(5, 33); a1 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 122); p16(2, 131); api(5, 33); a2 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 126); p16(2, 131); api(5, 33); a3 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 120); p16(2, 132); api(5, 33); a4 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre();
    p16(0, (uint16_t)cel);
    ControlPort.params[2] = 60;
    ControlPort.params[3] = 76;
    ControlPort.params[4] = 5;
    ControlPort.params[5] = 0;
    p16(6, 72);
    api(39, 5);
    e1 = ControlPort.error;
    libre(); p16(0, 120); p16(2, 148); api(5, 33); a5 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre();
    ControlPort.params[0] = 60;
    ControlPort.params[1] = 60;
    api(39, 4);
    c1 = ControlPort.params[2];
    p1 = ControlPort.params[3];
    printf("Priorite 12 : erreur %u\n", e0);
    printf("Haut : %u %u %u, bas : %u\n", a1, a2, a3, a4);
    printf("Priorite 5 : erreur %u, ecran %u\n", e1, a5);
    printf("Plan : couleur %u, priorite %u\n", c1, p1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Priorite 12 : erreur 0
Haut : 14 3 1, bas : 2
Priorite 5 : erreur 0, ecran 14
Plan : couleur 14, priorite 9
Mad Pascal
// Dessiner un cel sur l'image (groupe 39, fonction 5, Trinity).
program agi5;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);
// cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
const cel: array[0..8] of byte = ($04, $02, $00, $01, $32, $11, $00, $24, $00);

var e0, a1, a2, a3, a4, e1, a5, c1, p1: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  write(chr(12));                               // efface l'écran avant toute mesure
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  p16(0, 72);
  appel(39, 2);
  NeoWaitMessage;
  p16(0, word(@cel));
  NeoMessage.params[2] := 60;
  NeoMessage.params[3] := 60;
  NeoMessage.params[4] := 12;
  NeoMessage.params[5] := 0;
  p16(6, 72);
  appel(39, 5);
  e0 := NeoMessage.error;
  NeoWaitMessage; p16(0, 120); p16(2, 131); appel(5, 33); a1 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 122); p16(2, 131); appel(5, 33); a2 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 126); p16(2, 131); appel(5, 33); a3 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 120); p16(2, 132); appel(5, 33); a4 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage;
  p16(0, word(@cel));
  NeoMessage.params[2] := 60;
  NeoMessage.params[3] := 76;
  NeoMessage.params[4] := 5;
  NeoMessage.params[5] := 0;
  p16(6, 72);
  appel(39, 5);
  e1 := NeoMessage.error;
  NeoWaitMessage; p16(0, 120); p16(2, 148); appel(5, 33); a5 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage;
  NeoMessage.params[0] := 60;
  NeoMessage.params[1] := 60;
  appel(39, 4);
  c1 := NeoMessage.params[2];
  p1 := NeoMessage.params[3];
  writeln('Priorite 12 : erreur ', e0);
  writeln('Haut : ', a1, ' ', a2, ' ', a3, ', bas : ', a4);
  writeln('Priorite 5 : erreur ', e1, ', ecran ', a5);
  writeln('Plan : couleur ', c1, ', priorite ', p1);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Priorite 12 : erreur 0
Haut : 14 3 1, bas : 2
Priorite 5 : erreur 0, ecran 14
Plan : couleur 14, priorite 9
NeoBASIC
10 ' Dessiner un cel sur l'image (groupe 39, fonction 5, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 ' cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
90 dc = alloc(9)
100 poke dc + 0, 4 : poke dc + 1, 2 : poke dc + 2, 0 : poke dc + 3, 1 : poke dc + 4, 50 : poke dc + 5, 17
110 poke dc + 6, 0 : poke dc + 7, 36 : poke dc + 8, 0
120 cls
130 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
140 while peek($ff00) : wend : doke $ff04 + 0, 72 : f = 2 : gosub 8100
150 while peek($ff00) : wend : doke $ff04 + 0, dc : poke $ff04 + 2, 60 : poke $ff04 + 3, 60 : poke $ff04 + 4, 12 : poke $ff04 + 5, 0 : doke $ff04 + 6, 72 : f = 5 : gosub 8100
160 e0 = e
170 while peek($ff00) : wend : doke $ff04, 120 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a1 = peek($ff04)
180 while peek($ff00) : wend : doke $ff04, 122 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a2 = peek($ff04)
190 while peek($ff00) : wend : doke $ff04, 126 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a3 = peek($ff04)
200 while peek($ff00) : wend : doke $ff04, 120 : doke $ff06, 132 : f = 33 : g = 5 : gosub 8110 : a4 = peek($ff04)
210 while peek($ff00) : wend : doke $ff04 + 0, dc : poke $ff04 + 2, 60 : poke $ff04 + 3, 76 : poke $ff04 + 4, 5 : poke $ff04 + 5, 0 : doke $ff04 + 6, 72 : f = 5 : gosub 8100
220 e1 = e
230 while peek($ff00) : wend : doke $ff04, 120 : doke $ff06, 148 : f = 33 : g = 5 : gosub 8110 : a5 = peek($ff04)
240 while peek($ff00) : wend : poke $ff04 + 0, 60 : poke $ff04 + 1, 60 : f = 4 : gosub 8100
250 c1 = peek($ff04 + 2)
260 p1 = peek($ff04 + 3)
270 print "Priorite 12 : erreur ";e0
280 print "Haut : ";a1;" ";a2;" ";a3;", bas : ";a4
290 print "Priorite 5 : erreur ";e1;", ecran ";a5
300 print "Plan : couleur ";c1;", priorite ";p1
310 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Priorite 12 : erreur 0
Haut : 14 3 1, bas : 2
Priorite 5 : erreur 0, ecran 14
Plan : couleur 14, priorite 9
65C02 assembly (64tass)
; Dessiner un cel sur l'image (groupe 39, fonction 5, 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 #12                    ; efface l'écran avant toute mesure
        jsr WriteCharacter
        jsr WaitMessage
        lda #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #<72
        sta ControlPort+4
        lda #>72
        sta ControlPort+5
        lda #39
        ldx #2
        jsr appel
        jsr WaitMessage
        lda #<cel
        sta ControlPort+4
        lda #>cel
        sta ControlPort+5
        lda #60
        sta ControlPort+6
        lda #60
        sta ControlPort+7
        lda #12
        sta ControlPort+8
        stz ControlPort+9
        lda #<72
        sta ControlPort+10
        lda #>72
        sta ControlPort+11
        lda #39
        ldx #5
        jsr appel
        lda ControlPort+2
        sta e0
        jsr WaitMessage
        lda #<120
        sta ControlPort+4
        lda #>120
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a1
        jsr WaitMessage
        lda #<122
        sta ControlPort+4
        lda #>122
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a2
        jsr WaitMessage
        lda #<126
        sta ControlPort+4
        lda #>126
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a3
        jsr WaitMessage
        lda #<120
        sta ControlPort+4
        lda #>120
        sta ControlPort+5
        lda #<132
        sta ControlPort+6
        lda #>132
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a4
        jsr WaitMessage
        lda #<cel
        sta ControlPort+4
        lda #>cel
        sta ControlPort+5
        lda #60
        sta ControlPort+6
        lda #76
        sta ControlPort+7
        lda #5
        sta ControlPort+8
        stz ControlPort+9
        lda #<72
        sta ControlPort+10
        lda #>72
        sta ControlPort+11
        lda #39
        ldx #5
        jsr appel
        lda ControlPort+2
        sta e1
        jsr WaitMessage
        lda #<120
        sta ControlPort+4
        lda #>120
        sta ControlPort+5
        lda #<148
        sta ControlPort+6
        lda #>148
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a5
        jsr WaitMessage
        lda #60
        sta ControlPort+4
        lda #60
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c1
        lda ControlPort+7
        sta p1
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda a2
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda a3
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda a4
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda e1
        jsr decimal
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda a5
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda p1
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
; cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
cel:
        .byte $04, $02, $00, $01, $32, $11, $00, $24
        .byte $00
fcel:
e0: .byte 0
a1: .byte 0
a2: .byte 0
a3: .byte 0
a4: .byte 0
e1: .byte 0
a5: .byte 0
c1: .byte 0
p1: .byte 0
t0: .text "Priorite 12 : erreur ", 0
t1: .text "Haut : ", 0
t2: .text " ", 0
t3: .text ", bas : ", 0
t4: .text "Priorite 5 : erreur ", 0
t5: .text ", ecran ", 0
t6: .text "Plan : couleur ", 0
t7: .text ", priorite ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Priorite 12 : erreur 0
Haut : 14 3 1, bas : 2
Priorite 5 : erreur 0, ecran 14
Plan : couleur 14, priorite 9

39,6 Restore Rect Trinity

Copies a rectangle of the AGI plane to the screen: erases the objects drawn there.

Inputs
BytesTypeMeaning
P0uint8X
P1uint8Y
P2uint8width
P3uint8height
P4-P5uint16screen line of the top of the plane
Outputs
BytesTypeMeaning
erreuruint81 if the width or the height is 0, or if the mode is not supported

The rectangle is clipped to the plane. The objects it overlapped must then be drawn again by the caller. The example draws a cel, restores 2 × 1 points: the restored point gets the plane colour back (14), the rest of the cel is untouched. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Trinity (T-109). Copies the visual colours of the AGI plane to the screen on the rectangle X Parameter:0, Y Parameter:1, width Parameter:2, height Parameter:3 (AGI pixels, clipped to the plane), the plane top being at screen line Parameters:4,5 : this erases the objects drawn there. Error 1 if the width or the height is 0 or the mode is not supported.

C (llvm-mos)
/* Restaurer un rectangle de l'image (groupe 39, fonction 6, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};
/* cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne) */
static const uint8_t cel[] = {0x04, 0x02, 0x00, 0x01, 0x32, 0x11, 0x00, 0x24, 0x00};

int main(void) {
    uint8_t a1, a2, e0, a3, a4, e1;
    putchar(12);                                /* efface l'écran avant toute mesure */
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    p16(0, 72);
    api(39, 2);
    libre();
    p16(0, (uint16_t)cel);
    ControlPort.params[2] = 60;
    ControlPort.params[3] = 60;
    ControlPort.params[4] = 12;
    ControlPort.params[5] = 0;
    p16(6, 72);
    api(39, 5);
    libre(); p16(0, 122); p16(2, 131); api(5, 33); a1 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 126); p16(2, 131); api(5, 33); a2 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre();
    ControlPort.params[0] = 60;
    ControlPort.params[1] = 59;
    ControlPort.params[2] = 2;
    ControlPort.params[3] = 1;
    p16(4, 72);
    api(39, 6);
    e0 = ControlPort.error;
    libre(); p16(0, 122); p16(2, 131); api(5, 33); a3 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre(); p16(0, 126); p16(2, 131); api(5, 33); a4 = ControlPort.params[0];   /* 5,33 : Read Pixel */
    libre();
    ControlPort.params[0] = 60;
    ControlPort.params[1] = 59;
    ControlPort.params[2] = 0;
    ControlPort.params[3] = 1;
    p16(4, 72);
    api(39, 6);
    e1 = ControlPort.error;
    printf("Avant : %u et %u\n", a1, a2);
    printf("Restaurer : erreur %u, apres : %u et %u\n", e0, a3, a4);
    printf("Largeur 0 : erreur %u\n", e1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Avant : 3 et 1
Restaurer : erreur 0, apres : 14 et 1
Largeur 0 : erreur 1
Mad Pascal
// Restaurer un rectangle de l'image (groupe 39, fonction 6, Trinity).
program agi6;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);
// cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
const cel: array[0..8] of byte = ($04, $02, $00, $01, $32, $11, $00, $24, $00);

var a1, a2, e0, a3, a4, e1: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  write(chr(12));                               // efface l'écran avant toute mesure
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  p16(0, 72);
  appel(39, 2);
  NeoWaitMessage;
  p16(0, word(@cel));
  NeoMessage.params[2] := 60;
  NeoMessage.params[3] := 60;
  NeoMessage.params[4] := 12;
  NeoMessage.params[5] := 0;
  p16(6, 72);
  appel(39, 5);
  NeoWaitMessage; p16(0, 122); p16(2, 131); appel(5, 33); a1 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 126); p16(2, 131); appel(5, 33); a2 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage;
  NeoMessage.params[0] := 60;
  NeoMessage.params[1] := 59;
  NeoMessage.params[2] := 2;
  NeoMessage.params[3] := 1;
  p16(4, 72);
  appel(39, 6);
  e0 := NeoMessage.error;
  NeoWaitMessage; p16(0, 122); p16(2, 131); appel(5, 33); a3 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage; p16(0, 126); p16(2, 131); appel(5, 33); a4 := NeoMessage.params[0];   // 5,33 : Read Pixel
  NeoWaitMessage;
  NeoMessage.params[0] := 60;
  NeoMessage.params[1] := 59;
  NeoMessage.params[2] := 0;
  NeoMessage.params[3] := 1;
  p16(4, 72);
  appel(39, 6);
  e1 := NeoMessage.error;
  writeln('Avant : ', a1, ' et ', a2);
  writeln('Restaurer : erreur ', e0, ', apres : ', a3, ' et ', a4);
  writeln('Largeur 0 : erreur ', e1);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Avant : 3 et 1
Restaurer : erreur 0, apres : 14 et 1
Largeur 0 : erreur 1
NeoBASIC
10 ' Restaurer un rectangle de l'image (groupe 39, fonction 6, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 ' cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
90 dc = alloc(9)
100 poke dc + 0, 4 : poke dc + 1, 2 : poke dc + 2, 0 : poke dc + 3, 1 : poke dc + 4, 50 : poke dc + 5, 17
110 poke dc + 6, 0 : poke dc + 7, 36 : poke dc + 8, 0
120 cls
130 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
140 while peek($ff00) : wend : doke $ff04 + 0, 72 : f = 2 : gosub 8100
150 while peek($ff00) : wend : doke $ff04 + 0, dc : poke $ff04 + 2, 60 : poke $ff04 + 3, 60 : poke $ff04 + 4, 12 : poke $ff04 + 5, 0 : doke $ff04 + 6, 72 : f = 5 : gosub 8100
160 while peek($ff00) : wend : doke $ff04, 122 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a1 = peek($ff04)
170 while peek($ff00) : wend : doke $ff04, 126 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a2 = peek($ff04)
180 while peek($ff00) : wend : poke $ff04 + 0, 60 : poke $ff04 + 1, 59 : poke $ff04 + 2, 2 : poke $ff04 + 3, 1 : doke $ff04 + 4, 72 : f = 6 : gosub 8100
190 e0 = e
200 while peek($ff00) : wend : doke $ff04, 122 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a3 = peek($ff04)
210 while peek($ff00) : wend : doke $ff04, 126 : doke $ff06, 131 : f = 33 : g = 5 : gosub 8110 : a4 = peek($ff04)
220 while peek($ff00) : wend : poke $ff04 + 0, 60 : poke $ff04 + 1, 59 : poke $ff04 + 2, 0 : poke $ff04 + 3, 1 : doke $ff04 + 4, 72 : f = 6 : gosub 8100
230 e1 = e
240 print "Avant : ";a1;" et ";a2
250 print "Restaurer : erreur ";e0;", apres : ";a3;" et ";a4
260 print "Largeur 0 : erreur ";e1
270 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Avant : 3 et 1
Restaurer : erreur 0, apres : 14 et 1
Largeur 0 : erreur 1
65C02 assembly (64tass)
; Restaurer un rectangle de l'image (groupe 39, fonction 6, 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 #12                    ; efface l'écran avant toute mesure
        jsr WriteCharacter
        jsr WaitMessage
        lda #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #<72
        sta ControlPort+4
        lda #>72
        sta ControlPort+5
        lda #39
        ldx #2
        jsr appel
        jsr WaitMessage
        lda #<cel
        sta ControlPort+4
        lda #>cel
        sta ControlPort+5
        lda #60
        sta ControlPort+6
        lda #60
        sta ControlPort+7
        lda #12
        sta ControlPort+8
        stz ControlPort+9
        lda #<72
        sta ControlPort+10
        lda #>72
        sta ControlPort+11
        lda #39
        ldx #5
        jsr appel
        jsr WaitMessage
        lda #<122
        sta ControlPort+4
        lda #>122
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a1
        jsr WaitMessage
        lda #<126
        sta ControlPort+4
        lda #>126
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a2
        jsr WaitMessage
        lda #60
        sta ControlPort+4
        lda #59
        sta ControlPort+5
        lda #2
        sta ControlPort+6
        lda #1
        sta ControlPort+7
        lda #<72
        sta ControlPort+8
        lda #>72
        sta ControlPort+9
        lda #39
        ldx #6
        jsr appel
        lda ControlPort+2
        sta e0
        jsr WaitMessage
        lda #<122
        sta ControlPort+4
        lda #>122
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a3
        jsr WaitMessage
        lda #<126
        sta ControlPort+4
        lda #>126
        sta ControlPort+5
        lda #<131
        sta ControlPort+6
        lda #>131
        sta ControlPort+7
        lda #5
        ldx #33                    ; 5,33 : Read Pixel
        jsr appel
        lda ControlPort+4
        sta a4
        jsr WaitMessage
        lda #60
        sta ControlPort+4
        lda #59
        sta ControlPort+5
        stz ControlPort+6
        lda #1
        sta ControlPort+7
        lda #<72
        sta ControlPort+8
        lda #>72
        sta ControlPort+9
        lda #39
        ldx #6
        jsr appel
        lda ControlPort+2
        sta e1
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda a1
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda e0
        jsr decimal
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda a3
        jsr decimal
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda a4
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda e1
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
; cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
cel:
        .byte $04, $02, $00, $01, $32, $11, $00, $24
        .byte $00
fcel:
a1: .byte 0
a2: .byte 0
e0: .byte 0
a3: .byte 0
a4: .byte 0
e1: .byte 0
t0: .text "Avant : ", 0
t1: .text " et ", 0
t2: .text "Restaurer : erreur ", 0
t3: .text ", apres : ", 0
t4: .text "Largeur 0 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Avant : 3 et 1
Restaurer : erreur 0, apres : 14 et 1
Largeur 0 : erreur 1

39,7 Add Cel To Plane Trinity

Writes a cel into the AGI plane (the add.to.pic command) instead of the screen.

Inputs
BytesTypeMeaning
P0-P1addraddress of the cel header in 6502 RAM
P2uint8X of the left side
P3uint8Y of the bottom line
P4uint8priority (4 to 15)
P5uint8bit 0: mirror horizontally
Outputs
BytesTypeMeaning
erreuruint81 priority outside 4-15, empty cel, position outside the plane or header outside RAM; 2 cel data cut

Same parameters as 39,5, without a screen line: each non-transparent point that passes the priority test receives the cel colour and the given priority (control lines 0 to 3 already in the plane are kept). Priority 0 ("from Y") is for the caller to compute, hence the refusal of 0 to 3. 39,6 then shows the result. The example reads the plane after the addition, tries priority 3 (error 1), then priority 5 on a plane of priority 9: nothing is written. NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Trinity (T-122), for the AGI command add.to.pic. Same parameters as Draw Cel (cel header at Parameters:0,1 of 6502 RAM, left X Parameter:2, bottom Y Parameter:3, priority Parameter:4, bit 0 of Parameter:5 = mirror) without screen line : the cel is written into the AGI plane, not to the screen. Each point which is not transparent and passes the priority test of Draw Cel (priority greater than or equal to the plane priority, control lines included) receives the cel colour and the given priority. The priority must be 4 to 15 (0, "from Y", is computed by the caller). Same clipping as Draw Cel ; Restore Rect then shows the result. Errors : 1 priority outside 4-15 and the errors 1 and 2 of Draw Cel (the screen mode is not used).

C (llvm-mos)
/* Ajouter un cel au plan AGI (groupe 39, fonction 7, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};
/* cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne) */
static const uint8_t cel[] = {0x04, 0x02, 0x00, 0x01, 0x32, 0x11, 0x00, 0x24, 0x00};

int main(void) {
    uint8_t e0, c1, p1, c2, p2, c3, p3, e1, e2, c4, p4;
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    p16(0, (uint16_t)cel);
    ControlPort.params[2] = 60;
    ControlPort.params[3] = 60;
    ControlPort.params[4] = 12;
    ControlPort.params[5] = 0;
    api(39, 7);
    e0 = ControlPort.error;
    libre();
    ControlPort.params[0] = 61;
    ControlPort.params[1] = 59;
    api(39, 4);
    c1 = ControlPort.params[2];
    p1 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 60;
    ControlPort.params[1] = 59;
    api(39, 4);
    c2 = ControlPort.params[2];
    p2 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 60;
    ControlPort.params[1] = 60;
    api(39, 4);
    c3 = ControlPort.params[2];
    p3 = ControlPort.params[3];
    libre();
    p16(0, (uint16_t)cel);
    ControlPort.params[2] = 60;
    ControlPort.params[3] = 60;
    ControlPort.params[4] = 3;
    ControlPort.params[5] = 0;
    api(39, 7);
    e1 = ControlPort.error;
    libre();
    p16(0, (uint16_t)cel);
    ControlPort.params[2] = 60;
    ControlPort.params[3] = 76;
    ControlPort.params[4] = 5;
    ControlPort.params[5] = 0;
    api(39, 7);
    e2 = ControlPort.error;
    libre();
    ControlPort.params[0] = 60;
    ControlPort.params[1] = 76;
    api(39, 4);
    c4 = ControlPort.params[2];
    p4 = ControlPort.params[3];
    printf("Ajout : erreur %u\n", e0);
    printf("Cel (61, 59) : couleur %u, priorite %u\n", c1, p1);
    printf("Vide (60, 59) : couleur %u, priorite %u\n", c2, p2);
    printf("Bas (60, 60) : couleur %u, priorite %u\n", c3, p3);
    printf("Priorite 3 : erreur %u\n", e1);
    printf("Priorite 5 : erreur %u\n", e2);
    printf("Point (60, 76) : couleur %u, priorite %u\n", c4, p4);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Ajout : erreur 0
Cel (61, 59) : couleur 3, priorite 12
Vide (60, 59) : couleur 14, priorite 9
Bas (60, 60) : couleur 2, priorite 12
Priorite 3 : erreur 1
Priorite 5 : erreur 0
Point (60, 76) : couleur 14, priorite 9
Mad Pascal
// Ajouter un cel au plan AGI (groupe 39, fonction 7, Trinity).
program agi7;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);
// cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
const cel: array[0..8] of byte = ($04, $02, $00, $01, $32, $11, $00, $24, $00);

var e0, c1, p1, c2, p2, c3, p3, e1, e2, c4, p4: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  p16(0, word(@cel));
  NeoMessage.params[2] := 60;
  NeoMessage.params[3] := 60;
  NeoMessage.params[4] := 12;
  NeoMessage.params[5] := 0;
  appel(39, 7);
  e0 := NeoMessage.error;
  NeoWaitMessage;
  NeoMessage.params[0] := 61;
  NeoMessage.params[1] := 59;
  appel(39, 4);
  c1 := NeoMessage.params[2];
  p1 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 60;
  NeoMessage.params[1] := 59;
  appel(39, 4);
  c2 := NeoMessage.params[2];
  p2 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 60;
  NeoMessage.params[1] := 60;
  appel(39, 4);
  c3 := NeoMessage.params[2];
  p3 := NeoMessage.params[3];
  NeoWaitMessage;
  p16(0, word(@cel));
  NeoMessage.params[2] := 60;
  NeoMessage.params[3] := 60;
  NeoMessage.params[4] := 3;
  NeoMessage.params[5] := 0;
  appel(39, 7);
  e1 := NeoMessage.error;
  NeoWaitMessage;
  p16(0, word(@cel));
  NeoMessage.params[2] := 60;
  NeoMessage.params[3] := 76;
  NeoMessage.params[4] := 5;
  NeoMessage.params[5] := 0;
  appel(39, 7);
  e2 := NeoMessage.error;
  NeoWaitMessage;
  NeoMessage.params[0] := 60;
  NeoMessage.params[1] := 76;
  appel(39, 4);
  c4 := NeoMessage.params[2];
  p4 := NeoMessage.params[3];
  writeln('Ajout : erreur ', e0);
  writeln('Cel (61, 59) : couleur ', c1, ', priorite ', p1);
  writeln('Vide (60, 59) : couleur ', c2, ', priorite ', p2);
  writeln('Bas (60, 60) : couleur ', c3, ', priorite ', p3);
  writeln('Priorite 3 : erreur ', e1);
  writeln('Priorite 5 : erreur ', e2);
  writeln('Point (60, 76) : couleur ', c4, ', priorite ', p4);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Ajout : erreur 0
Cel (61, 59) : couleur 3, priorite 12
Vide (60, 59) : couleur 14, priorite 9
Bas (60, 60) : couleur 2, priorite 12
Priorite 3 : erreur 1
Priorite 5 : erreur 0
Point (60, 76) : couleur 14, priorite 9
NeoBASIC
10 ' Ajouter un cel au plan AGI (groupe 39, fonction 7, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 ' cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
90 dc = alloc(9)
100 poke dc + 0, 4 : poke dc + 1, 2 : poke dc + 2, 0 : poke dc + 3, 1 : poke dc + 4, 50 : poke dc + 5, 17
110 poke dc + 6, 0 : poke dc + 7, 36 : poke dc + 8, 0
120 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
130 while peek($ff00) : wend : doke $ff04 + 0, dc : poke $ff04 + 2, 60 : poke $ff04 + 3, 60 : poke $ff04 + 4, 12 : poke $ff04 + 5, 0 : f = 7 : gosub 8100
140 e0 = e
150 while peek($ff00) : wend : poke $ff04 + 0, 61 : poke $ff04 + 1, 59 : f = 4 : gosub 8100
160 c1 = peek($ff04 + 2)
170 p1 = peek($ff04 + 3)
180 while peek($ff00) : wend : poke $ff04 + 0, 60 : poke $ff04 + 1, 59 : f = 4 : gosub 8100
190 c2 = peek($ff04 + 2)
200 p2 = peek($ff04 + 3)
210 while peek($ff00) : wend : poke $ff04 + 0, 60 : poke $ff04 + 1, 60 : f = 4 : gosub 8100
220 c3 = peek($ff04 + 2)
230 p3 = peek($ff04 + 3)
240 while peek($ff00) : wend : doke $ff04 + 0, dc : poke $ff04 + 2, 60 : poke $ff04 + 3, 60 : poke $ff04 + 4, 3 : poke $ff04 + 5, 0 : f = 7 : gosub 8100
250 e1 = e
260 while peek($ff00) : wend : doke $ff04 + 0, dc : poke $ff04 + 2, 60 : poke $ff04 + 3, 76 : poke $ff04 + 4, 5 : poke $ff04 + 5, 0 : f = 7 : gosub 8100
270 e2 = e
280 while peek($ff00) : wend : poke $ff04 + 0, 60 : poke $ff04 + 1, 76 : f = 4 : gosub 8100
290 c4 = peek($ff04 + 2)
300 p4 = peek($ff04 + 3)
310 print "Ajout : erreur ";e0
320 print "Cel (61, 59) : couleur ";c1;", priorite ";p1
330 print "Vide (60, 59) : couleur ";c2;", priorite ";p2
340 print "Bas (60, 60) : couleur ";c3;", priorite ";p3
350 print "Priorite 3 : erreur ";e1
360 print "Priorite 5 : erreur ";e2
370 print "Point (60, 76) : couleur ";c4;", priorite ";p4
380 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Ajout : erreur 0
Cel (61, 59) : couleur 3, priorite 12
Vide (60, 59) : couleur 14, priorite 9
Bas (60, 60) : couleur 2, priorite 12
Priorite 3 : erreur 1
Priorite 5 : erreur 0
Point (60, 76) : couleur 14, priorite 9
65C02 assembly (64tass)
; Ajouter un cel au plan AGI (groupe 39, fonction 7, 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 #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #<cel
        sta ControlPort+4
        lda #>cel
        sta ControlPort+5
        lda #60
        sta ControlPort+6
        lda #60
        sta ControlPort+7
        lda #12
        sta ControlPort+8
        stz ControlPort+9
        lda #39
        ldx #7
        jsr appel
        lda ControlPort+2
        sta e0
        jsr WaitMessage
        lda #61
        sta ControlPort+4
        lda #59
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c1
        lda ControlPort+7
        sta p1
        jsr WaitMessage
        lda #60
        sta ControlPort+4
        lda #59
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c2
        lda ControlPort+7
        sta p2
        jsr WaitMessage
        lda #60
        sta ControlPort+4
        lda #60
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c3
        lda ControlPort+7
        sta p3
        jsr WaitMessage
        lda #<cel
        sta ControlPort+4
        lda #>cel
        sta ControlPort+5
        lda #60
        sta ControlPort+6
        lda #60
        sta ControlPort+7
        lda #3
        sta ControlPort+8
        stz ControlPort+9
        lda #39
        ldx #7
        jsr appel
        lda ControlPort+2
        sta e1
        jsr WaitMessage
        lda #<cel
        sta ControlPort+4
        lda #>cel
        sta ControlPort+5
        lda #60
        sta ControlPort+6
        lda #76
        sta ControlPort+7
        lda #5
        sta ControlPort+8
        stz ControlPort+9
        lda #39
        ldx #7
        jsr appel
        lda ControlPort+2
        sta e2
        jsr WaitMessage
        lda #60
        sta ControlPort+4
        lda #76
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c4
        lda ControlPort+7
        sta p4
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda c3
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p3
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda e1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t6
        ldx #>t6
        jsr ecrire
        lda e2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t7
        ldx #>t7
        jsr ecrire
        lda c4
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p4
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
; cel 4 x 2, transparent = 0 : ligne du haut 0,3,3,1 ; ligne du bas 2,2,2,2 (RLE : couleur dans le quartet haut, longueur dans le bas, 0 en fin de ligne)
cel:
        .byte $04, $02, $00, $01, $32, $11, $00, $24
        .byte $00
fcel:
e0: .byte 0
c1: .byte 0
p1: .byte 0
c2: .byte 0
p2: .byte 0
c3: .byte 0
p3: .byte 0
e1: .byte 0
e2: .byte 0
c4: .byte 0
p4: .byte 0
t0: .text "Ajout : erreur ", 0
t1: .text "Cel (61, 59) : couleur ", 0
t2: .text ", priorite ", 0
t3: .text "Vide (60, 59) : couleur ", 0
t4: .text "Bas (60, 60) : couleur ", 0
t5: .text "Priorite 3 : erreur ", 0
t6: .text "Priorite 5 : erreur ", 0
t7: .text "Point (60, 76) : couleur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Ajout : erreur 0
Cel (61, 59) : couleur 3, priorite 12
Vide (60, 59) : couleur 14, priorite 9
Bas (60, 60) : couleur 2, priorite 12
Priorite 3 : erreur 1
Priorite 5 : erreur 0
Point (60, 76) : couleur 14, priorite 9

39,8 Fill Plane Priority Trinity

Sets the priority of the points of a rectangle of the AGI plane, without changing the colours.

Inputs
BytesTypeMeaning
P0uint8X
P1uint8Y
P2uint8width
P3uint8height
P4uint8priority (0 to 15)
Outputs
BytesTypeMeaning
erreuruint81 if the width or the height is 0, or the priority above 15

The rectangle is clipped to the plane. Used for the margin of add.to.pic (priority 0 to 3). NeoBASIC has no keyword for this call: the example writes the mailbox directly.

Firmware documentation text

Trinity (T-122). Sets to Parameter:4 (0 to 15) the priority of the points of the AGI plane in the rectangle X Parameter:0, Y Parameter:1, width Parameter:2, height Parameter:3 (AGI pixels, clipped to the plane) ; the visual colours are not changed. Used for the margin of add.to.pic (priority 0 to 3). Error 1 if the width or the height is 0 or the priority is above 15.

C (llvm-mos)
/* Fixer la priorité d'un rectangle du plan (groupe 39, fonction 8, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>

/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
    ControlPort.function = fonction;
    ControlPort.command = groupe;
    while (ControlPort.command)        /* attendre la fin */
        ;
}
static void libre(void) {              /* attendre que la boîte aux lettres soit libre */
    while (ControlPort.command)
        ;
}
static void p16(uint8_t i, uint16_t v) {       /* paramètre 16 bits en Pi, Pi+1 */
    ControlPort.params[i] = v & 0xFF;
    ControlPort.params[i + 1] = v >> 8;
}

/* image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50) */
static const uint8_t img[] = {0xF0, 0x0C, 0xF2, 0x09, 0xF6, 0x14, 0x1E, 0x64, 0x1E, 0x64, 0x50, 0x14, 0x50, 0x14, 0x1E, 0xF0, 0x0E, 0xF8, 0x32, 0x32, 0xFF};

int main(void) {
    uint8_t e0, c1, p1, c2, p2, e1, e2;
    libre();
    p16(0, (uint16_t)img);
    p16(2, sizeof img);
    ControlPort.params[4] = 1;
    api(39, 1);
    libre();
    ControlPort.params[0] = 30;
    ControlPort.params[1] = 40;
    ControlPort.params[2] = 10;
    ControlPort.params[3] = 10;
    ControlPort.params[4] = 2;
    api(39, 8);
    e0 = ControlPort.error;
    libre();
    ControlPort.params[0] = 35;
    ControlPort.params[1] = 45;
    api(39, 4);
    c1 = ControlPort.params[2];
    p1 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 45;
    ControlPort.params[1] = 45;
    api(39, 4);
    c2 = ControlPort.params[2];
    p2 = ControlPort.params[3];
    libre();
    ControlPort.params[0] = 30;
    ControlPort.params[1] = 40;
    ControlPort.params[2] = 10;
    ControlPort.params[3] = 10;
    ControlPort.params[4] = 16;
    api(39, 8);
    e1 = ControlPort.error;
    libre();
    ControlPort.params[0] = 30;
    ControlPort.params[1] = 40;
    ControlPort.params[2] = 0;
    ControlPort.params[3] = 10;
    ControlPort.params[4] = 2;
    api(39, 8);
    e2 = ControlPort.error;
    printf("Rectangle : erreur %u\n", e0);
    printf("Dedans (35, 45) : couleur %u, priorite %u\n", c1, p1);
    printf("Dehors (45, 45) : couleur %u, priorite %u\n", c2, p2);
    printf("Priorite 16 : erreur %u\n", e1);
    printf("Largeur 0 : erreur %u\n", e2);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Rectangle : erreur 0
Dedans (35, 45) : couleur 14, priorite 2
Dehors (45, 45) : couleur 14, priorite 9
Priorite 16 : erreur 1
Largeur 0 : erreur 1
Mad Pascal
// Fixer la priorité d'un rectangle du plan (groupe 39, fonction 8, Trinity).
program agi8;
uses crt, neo6502;
// image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
const img: array[0..20] of byte = ($F0, $0C, $F2, $09, $F6, $14, $1E, $64, $1E, $64, $50, $14, $50, $14, $1E, $F0, $0E, $F8, $32, $32, $FF);

var e0, c1, p1, c2, p2, e1, e2: byte;

procedure p16(i: byte; v: word);                // paramètre 16 bits en Pi, Pi+1
begin
  NeoMessage.params[i] := lo(v);
  NeoMessage.params[i + 1] := hi(v);
end;

procedure appel(g, f: byte);                    // lance l'appel et attend la fin
begin
  NeoSendMessage(g, f);
  NeoWaitMessage;
end;

begin
  NeoWaitMessage;
  p16(0, word(@img));
  p16(2, 21);
  NeoMessage.params[4] := 1;
  appel(39, 1);
  NeoWaitMessage;
  NeoMessage.params[0] := 30;
  NeoMessage.params[1] := 40;
  NeoMessage.params[2] := 10;
  NeoMessage.params[3] := 10;
  NeoMessage.params[4] := 2;
  appel(39, 8);
  e0 := NeoMessage.error;
  NeoWaitMessage;
  NeoMessage.params[0] := 35;
  NeoMessage.params[1] := 45;
  appel(39, 4);
  c1 := NeoMessage.params[2];
  p1 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 45;
  NeoMessage.params[1] := 45;
  appel(39, 4);
  c2 := NeoMessage.params[2];
  p2 := NeoMessage.params[3];
  NeoWaitMessage;
  NeoMessage.params[0] := 30;
  NeoMessage.params[1] := 40;
  NeoMessage.params[2] := 10;
  NeoMessage.params[3] := 10;
  NeoMessage.params[4] := 16;
  appel(39, 8);
  e1 := NeoMessage.error;
  NeoWaitMessage;
  NeoMessage.params[0] := 30;
  NeoMessage.params[1] := 40;
  NeoMessage.params[2] := 0;
  NeoMessage.params[3] := 10;
  NeoMessage.params[4] := 2;
  appel(39, 8);
  e2 := NeoMessage.error;
  writeln('Rectangle : erreur ', e0);
  writeln('Dedans (35, 45) : couleur ', c1, ', priorite ', p1);
  writeln('Dehors (45, 45) : couleur ', c2, ', priorite ', p2);
  writeln('Priorite 16 : erreur ', e1);
  writeln('Largeur 0 : erreur ', e2);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Rectangle : erreur 0
Dedans (35, 45) : couleur 14, priorite 2
Dehors (45, 45) : couleur 14, priorite 9
Priorite 16 : erreur 1
Largeur 0 : erreur 1
NeoBASIC
10 ' Fixer la priorité d'un rectangle du plan (groupe 39, fonction 8, Trinity)
20 ' image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
30 di = alloc(21)
40 poke di + 0, 240 : poke di + 1, 12 : poke di + 2, 242 : poke di + 3, 9 : poke di + 4, 246 : poke di + 5, 20
50 poke di + 6, 30 : poke di + 7, 100 : poke di + 8, 30 : poke di + 9, 100 : poke di + 10, 80 : poke di + 11, 20
60 poke di + 12, 80 : poke di + 13, 20 : poke di + 14, 30 : poke di + 15, 240 : poke di + 16, 14 : poke di + 17, 248
70 poke di + 18, 50 : poke di + 19, 50 : poke di + 20, 255
80 while peek($ff00) : wend : doke $ff04 + 0, di : doke $ff04 + 2, 21 : poke $ff04 + 4, 1 : f = 1 : gosub 8100
90 while peek($ff00) : wend : poke $ff04 + 0, 30 : poke $ff04 + 1, 40 : poke $ff04 + 2, 10 : poke $ff04 + 3, 10 : poke $ff04 + 4, 2 : f = 8 : gosub 8100
100 e0 = e
110 while peek($ff00) : wend : poke $ff04 + 0, 35 : poke $ff04 + 1, 45 : f = 4 : gosub 8100
120 c1 = peek($ff04 + 2)
130 p1 = peek($ff04 + 3)
140 while peek($ff00) : wend : poke $ff04 + 0, 45 : poke $ff04 + 1, 45 : f = 4 : gosub 8100
150 c2 = peek($ff04 + 2)
160 p2 = peek($ff04 + 3)
170 while peek($ff00) : wend : poke $ff04 + 0, 30 : poke $ff04 + 1, 40 : poke $ff04 + 2, 10 : poke $ff04 + 3, 10 : poke $ff04 + 4, 16 : f = 8 : gosub 8100
180 e1 = e
190 while peek($ff00) : wend : poke $ff04 + 0, 30 : poke $ff04 + 1, 40 : poke $ff04 + 2, 0 : poke $ff04 + 3, 10 : poke $ff04 + 4, 2 : f = 8 : gosub 8100
200 e2 = e
210 print "Rectangle : erreur ";e0
220 print "Dedans (35, 45) : couleur ";c1;", priorite ";p1
230 print "Dehors (45, 45) : couleur ";c2;", priorite ";p2
240 print "Priorite 16 : erreur ";e1
250 print "Largeur 0 : erreur ";e2
260 end
8100 ' appel 39,f, parametres deja poses ; erreur dans e
8105 g = 39
8110 poke $ff01, f : poke $ff00, g
8120 while peek($ff00) : wend : e = peek($ff02) : return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Rectangle : erreur 0
Dedans (35, 45) : couleur 14, priorite 2
Dehors (45, 45) : couleur 14, priorite 9
Priorite 16 : erreur 1
Largeur 0 : erreur 1
65C02 assembly (64tass)
; Fixer la priorité d'un rectangle du plan (groupe 39, fonction 8, 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 #<img
        sta ControlPort+4
        lda #>img
        sta ControlPort+5
        lda #<(fimg-img)
        sta ControlPort+6
        lda #>(fimg-img)
        sta ControlPort+7
        lda #1
        sta ControlPort+8
        lda #39
        ldx #1
        jsr appel
        jsr WaitMessage
        lda #30
        sta ControlPort+4
        lda #40
        sta ControlPort+5
        lda #10
        sta ControlPort+6
        lda #10
        sta ControlPort+7
        lda #2
        sta ControlPort+8
        lda #39
        ldx #8
        jsr appel
        lda ControlPort+2
        sta e0
        jsr WaitMessage
        lda #35
        sta ControlPort+4
        lda #45
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c1
        lda ControlPort+7
        sta p1
        jsr WaitMessage
        lda #45
        sta ControlPort+4
        lda #45
        sta ControlPort+5
        lda #39
        ldx #4
        jsr appel
        lda ControlPort+6
        sta c2
        lda ControlPort+7
        sta p2
        jsr WaitMessage
        lda #30
        sta ControlPort+4
        lda #40
        sta ControlPort+5
        lda #10
        sta ControlPort+6
        lda #10
        sta ControlPort+7
        lda #16
        sta ControlPort+8
        lda #39
        ldx #8
        jsr appel
        lda ControlPort+2
        sta e1
        jsr WaitMessage
        lda #30
        sta ControlPort+4
        lda #40
        sta ControlPort+5
        stz ControlPort+6
        lda #10
        sta ControlPort+7
        lda #2
        sta ControlPort+8
        lda #39
        ldx #8
        jsr appel
        lda ControlPort+2
        sta e2
        lda #<t0
        ldx #>t0
        jsr ecrire
        lda e0
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t1
        ldx #>t1
        jsr ecrire
        lda c1
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t3
        ldx #>t3
        jsr ecrire
        lda c2
        jsr decimal
        lda #<t2
        ldx #>t2
        jsr ecrire
        lda p2
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t4
        ldx #>t4
        jsr ecrire
        lda e1
        jsr decimal
        lda #13
        jsr WriteCharacter
        lda #<t5
        ldx #>t5
        jsr ecrire
        lda e2
        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

; image AGI : ligne rouge (12) priorité 9 autour de (20,30)-(100,80), puis remplissage jaune (14) en (50,50)
img:
        .byte $F0, $0C, $F2, $09, $F6, $14, $1E, $64
        .byte $1E, $64, $50, $14, $50, $14, $1E, $F0
        .byte $0E, $F8, $32, $32, $FF
fimg:
e0: .byte 0
c1: .byte 0
p1: .byte 0
c2: .byte 0
p2: .byte 0
e1: .byte 0
e2: .byte 0
t0: .text "Rectangle : erreur ", 0
t1: .text "Dedans (35, 45) : couleur ", 0
t2: .text ", priorite ", 0
t3: .text "Dehors (45, 45) : couleur ", 0
t4: .text "Priorite 16 : erreur ", 0
t5: .text "Largeur 0 : erreur ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.94:
Rectangle : erreur 0
Dedans (35, 45) : couleur 14, priorite 2
Dehors (45, 45) : couleur 14, priorite 9
Priorite 16 : erreur 1
Largeur 0 : erreur 1

← The Neo6502 API