Groupe 5 — Graphisme Officiel
5,1 Set Defaults · 5,2 Draw Line · 5,3 Draw Rectangle · 5,4 Draw Ellipse · 5,5 Draw Pixel · 5,6 Draw Text · 5,7 Draw Image · 5,8 Draw Tilemap · 5,9 Set Graphics Mode · 5,10 Get Graphics Mode · 5,11 Set Draw Page · 5,12 Set Display Page · 5,32 Set Palette · 5,33 Read Pixel · 5,34 Reset Palette · 5,35 Set Tilemap · 5,36 Read Sprite Pixel · 5,37 Frame Count · 5,38 Get Palette · 5,39 Write Pixel · 5,40 Get Late Scanlines · 5,41 Get Bus Stalls · 5,42 Get Bus Timing · 5,64 Set Color · 5,65 Set Solid Flag · 5,66 Set Draw Size · 5,67 Set Flip Bits
Le groupe 5 dessine dans la mémoire graphique : 320 × 240 pixels en mode 0, un octet par pixel qui désigne une couleur de la palette. Les coordonnées sont des entiers signés de 16 bits (P0-P1 et P2-P3 pour le premier point, P4-P5 et P6-P7 pour le second) ; ce qui sort de l'écran est ignoré.
La couleur d'un tracé suit la règle du firmware : nouveau pixel = (ancien pixel ET masque) OU EXCLUSIF couleur. 5,1 règle le masque et la couleur ensemble ; 5,64 met le masque à 0, et le pixel prend alors simplement la couleur donnée.
Les images (5,7), les cartes de tuiles (5,8) et les sprites (groupe 6) se lisent dans une mémoire graphique séparée, remplie en chargeant un fichier à l'adresse $FFFF (3,2). Ce fichier commence par un en-tête de 256 octets : octet 0 non nul, puis les nombres de tuiles 16 × 16, de sprites 16 × 16 et de sprites 32 × 32 ; suivent les images, 4 bits par pixel, pixel de gauche dans le quartet haut, la couleur 0 étant transparente. Les exemples fabriquent un tel fichier de 384 octets : une image 16 × 16, moitié gauche couleur 2, moitié droite couleur 5.
Pour vérifier ce qui est dessiné sans capture d'écran, chaque exemple relit des pixels avec 5,33 et affiche leur couleur. Les dessins sont faits dans le bas de l'écran, là où la console n'a encore rien écrit.
5,1 Set Defaults Officiel
Règle d'un coup le masque et la couleur du tracé, le remplissage, la taille (images et texte) et le retournement.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | masque (ET) appliqué à l'ancien pixel |
P1 | uint8 | couleur (OU EXCLUSIF) |
P2 | uint8 | remplissage : non nul pour des formes pleines (et un fond plein pour texte et images) |
P3 | uint8 | taille des images et du texte |
P4 | uint8 | retournement : bit 0 horizontal, bit 1 vertical |
Sorties : aucune.
Nouveau pixel = (ancien ET masque) OU EXCLUSIF couleur. Avec le masque $FF, la couleur s'ajoute par OU EXCLUSIF : tracer deux fois le même point le rend à sa couleur d'origine, ce que montre l'exemple. En NeoBASIC, ink m, c (ou ink c, masque 0), solid, frame et dim font cet appel.
Texte de la documentation du firmware (anglais)
Configure the global graphics system settings. Not all parameters are relevant for all graphics commands; but all parameters will be set by this command. So mind their values. Refer to Section "Graphics Settings" for details.
The parameters are And, Or, Fill Flag, Extent, and Flip. Bit 0 of flip sets the horizontal flip, Bit 1 sets the vertical flip.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Tracer deux fois le même point en OU EXCLUSIF (groupe 5, fonction 1). */
int main(void) {
neo_graphics_set_defaults(0xFF, 3, 0, 1, 0); /* Set Defaults : masque $FF, couleur 3 */
neo_graphics_draw_pixel(200, 170); /* 5,5 */
uint8_t a = neo_graphics_read_pixel(200, 170);
neo_graphics_draw_pixel(200, 170); /* même point : 3 XOR 3 = 0 */
uint8_t b = neo_graphics_read_pixel(200, 170);
printf("Premier trace : %u, second trace : %u\n", a, b);
return 0;
}Premier trace : 3, second trace : 0Mad Pascal
// Tracer deux fois le même point en OU EXCLUSIF (groupe 5, fonction 1).
program defauts;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetDefaults($FF, 3, 0, 1, 0); // Set Defaults : masque $FF, couleur 3
NeoDrawPixel(200, 170); // 5,5
a := NeoGetPixel(200, 170);
NeoDrawPixel(200, 170); // même point : 3 XOR 3 = 0
b := NeoGetPixel(200, 170);
writeln('Premier trace : ', a, ', second trace : ', b);
end.Premier trace : 3, second trace : 0NeoBASIC
10 ' Tracer deux fois le meme point en OU EXCLUSIF (groupe 5, fonction 1)
20 plot 0,0 ink $ff,3 to 200,170 : a = point(200,170) : ' ink masque, couleur : 5,1
30 plot to 200,170 : b = point(200,170)
40 print "Premier trace : ";a;", second trace : ";bPremier trace : 3, second trace : 0Assembleur 65C02 (64tass)
; Tracer deux fois le même point en OU EXCLUSIF (groupe 5, fonction 1).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #$FF
sta ControlPort+4 ; P0 : masque $FF
lda #3
sta ControlPort+5 ; P1 : couleur 3
stz ControlPort+6 ; P2 : pas de remplissage
lda #1
sta ControlPort+7 ; P3 : taille 1
stz ControlPort+8 ; P4 : pas de retournement
ldx #1 ; fonction 1 : Set Defaults
jsr g5
jsr trace
sta a
jsr trace ; même point : 3 XOR 3 = 0
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Trace le point (200, 170) par 5,5 et relit sa couleur.
trace: lda #200
ldy #170
jsr point1
ldx #5 ; 5,5 : Draw Pixel
jsr g5
lda #200
ldy #170
jmp lire
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Premier trace : ", 0
t2: .text ", second trace : ", 0Premier trace : 3, second trace : 05,2 Draw Line Officiel
Trace un segment entre deux points.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du premier point |
P2-P3 | int16 | Y du premier point |
P4-P5 | int16 | X du second point |
P6-P7 | int16 | Y du second point |
Sorties : aucune.
En NeoBASIC, line x1,y1 to x2,y2 fait cet appel (avec ink pour la couleur).
Texte de la documentation du firmware (anglais)
Draw a line between the screen coordinates specified in Parameters:0,1,Parameters:2,3 (begin X,Y) and Parameters:4,5,Parameters:6,7 (end X,Y).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Tracer une ligne horizontale (groupe 5, fonction 2). */
int main(void) {
neo_graphics_set_color(3); /* 5,64 */
neo_graphics_draw_line(150, 200, 250, 200); /* Draw Line */
uint8_t a = neo_graphics_read_pixel(200, 200);
uint8_t b = neo_graphics_read_pixel(200, 201);
printf("Sur la ligne : %u, juste dessous : %u\n", a, b);
return 0;
}Sur la ligne : 3, juste dessous : 0Mad Pascal
// Tracer une ligne horizontale (groupe 5, fonction 2).
program ligne;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(3); // 5,64
NeoDrawLine(150, 200, 250, 200); // Draw Line
a := NeoGetPixel(200, 200);
b := NeoGetPixel(200, 201);
writeln('Sur la ligne : ', a, ', juste dessous : ', b);
end.Sur la ligne : 3, juste dessous : 0NeoBASIC
10 ' Tracer une ligne horizontale (groupe 5, fonction 2)
20 line 150,200 ink 3 to 250,200
30 a = point(200,200) : b = point(200,201)
40 print "Sur la ligne : ";a;", juste dessous : ";bSur la ligne : 3, juste dessous : 0Assembleur 65C02 (64tass)
; Tracer une ligne horizontale (groupe 5, fonction 2).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #3
sta ControlPort+4 ; P0 : couleur 3
ldx #64 ; 5,64 : Set Color
jsr g5
lda #150
ldy #200
jsr point1 ; P0-P3 : (150, 200)
lda #250
ldy #200
jsr point2 ; P4-P7 : (250, 200)
ldx #2 ; fonction 2 : Draw Line
jsr g5
lda #200
ldy #200
jsr lire
sta a
lda #200
ldy #201
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Sur la ligne : ", 0
t2: .text ", juste dessous : ", 0Sur la ligne : 3, juste dessous : 05,3 Draw Rectangle Officiel
Trace un rectangle défini par deux coins opposés, plein ou en contour selon le drapeau de remplissage.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du premier point |
P2-P3 | int16 | Y du premier point |
P4-P5 | int16 | X du second point |
P6-P7 | int16 | Y du second point |
Sorties : aucune.
Contour ou plein selon 5,65 (ou 5,1). En NeoBASIC, rect x1,y1 to x2,y2 fait cet appel ; frame et solid choisissent le contour ou le plein.
Texte de la documentation du firmware (anglais)
Draw a rectangle spanning the screen coordinates specified in Parameters:0,1,Parameters:2,3 (corner X,Y) and Parameters:4,5,Parameters:6,7 (opposite corner X,Y).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Tracer le contour d'un rectangle (groupe 5, fonction 3). */
int main(void) {
neo_graphics_set_color(4); /* 5,64 */
neo_graphics_set_solid_flag(0); /* 5,65 : contour */
neo_graphics_draw_rectangle(150, 160, 190, 200);
uint8_t a = neo_graphics_read_pixel(150, 180);
uint8_t b = neo_graphics_read_pixel(170, 180);
printf("Bord : %u, centre : %u\n", a, b);
return 0;
}Bord : 4, centre : 0Mad Pascal
// Tracer le contour d'un rectangle (groupe 5, fonction 3).
program forme3;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(4); // 5,64
NeoSetSolidFlag(0); // 5,65 : contour
NeoDrawRect(150, 160, 190, 200);
a := NeoGetPixel(150, 180);
b := NeoGetPixel(170, 180);
writeln('Bord : ', a, ', centre : ', b);
end.Bord : 4, centre : 0NeoBASIC
10 ' Tracer le contour d'un rectangle (groupe 5, fonction 3)
20 rect 150,160 ink 4 frame to 190,200
30 a = point(150,180) : b = point(170,180)
40 print "Bord : ";a;", centre : ";bBord : 4, centre : 0Assembleur 65C02 (64tass)
; Tracer le contour d'un rectangle (groupe 5, fonction 3).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #4
sta ControlPort+4 ; P0 : couleur 4
ldx #64 ; 5,64 : Set Color
jsr g5
lda #0
sta ControlPort+4 ; P0 : contour
ldx #65 ; 5,65 : Set Solid Flag
jsr g5
lda #150
ldy #160
jsr point1
lda #190
ldy #200
jsr point2
ldx #3 ; 5,3
jsr g5
lda #150
ldy #180
jsr lire
sta a
lda #170
ldy #180
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Bord : ", 0
t2: .text ", centre : ", 0Bord : 4, centre : 05,4 Draw Ellipse Officiel
Trace l'ellipse inscrite dans le rectangle défini par deux coins opposés.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du premier point |
P2-P3 | int16 | Y du premier point |
P4-P5 | int16 | X du second point |
P6-P7 | int16 | Y du second point |
Sorties : aucune.
Pleine ou en contour selon le drapeau de remplissage (5,65). Un carré donne un cercle. En NeoBASIC, ellipse x1,y1 to x2,y2 fait cet appel.
Texte de la documentation du firmware (anglais)
Draw an ellipse spanning the screen coordinates specified in Parameters:0,1,Parameters:2,3 (corner X,Y) and Parameters:4,5,Parameters:6,7 (opposite corner X,Y).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Tracer une ellipse pleine (groupe 5, fonction 4). */
int main(void) {
neo_graphics_set_color(4); /* 5,64 */
neo_graphics_set_solid_flag(1); /* 5,65 : plein */
neo_graphics_draw_ellipse(200, 160, 240, 200);
uint8_t a = neo_graphics_read_pixel(220, 180);
uint8_t b = neo_graphics_read_pixel(201, 161);
printf("Centre : %u, coin : %u\n", a, b);
return 0;
}Centre : 4, coin : 0Mad Pascal
// Tracer une ellipse pleine (groupe 5, fonction 4).
program forme4;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(4); // 5,64
NeoSetSolidFlag(1); // 5,65 : plein
NeoDrawEllipse(200, 160, 240, 200);
a := NeoGetPixel(220, 180);
b := NeoGetPixel(201, 161);
writeln('Centre : ', a, ', coin : ', b);
end.Centre : 4, coin : 0NeoBASIC
10 ' Tracer une ellipse pleine (groupe 5, fonction 4)
20 ellipse 200,160 ink 4 solid to 240,200
30 a = point(220,180) : b = point(201,161)
40 print "Centre : ";a;", coin : ";bCentre : 4, coin : 0Assembleur 65C02 (64tass)
; Tracer une ellipse pleine (groupe 5, fonction 4).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #4
sta ControlPort+4 ; P0 : couleur 4
ldx #64 ; 5,64 : Set Color
jsr g5
lda #1
sta ControlPort+4 ; P0 : plein
ldx #65 ; 5,65 : Set Solid Flag
jsr g5
lda #200
ldy #160
jsr point1
lda #240
ldy #200
jsr point2
ldx #4 ; 5,4
jsr g5
lda #220
ldy #180
jsr lire
sta a
lda #201
ldy #161
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Centre : ", 0
t2: .text ", coin : ", 0Centre : 4, coin : 05,5 Draw Pixel Officiel
Trace un pixel dans la couleur courante.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du point |
P2-P3 | int16 | Y du point |
Sorties : aucune.
Le pixel suit la règle masque/couleur de 5,1 ; 5,39 écrit au contraire une couleur telle quelle. En NeoBASIC, plot to x,y fait cet appel (plot x,y seul ne fait que déplacer le point courant).
Texte de la documentation du firmware (anglais)
Draw a single pixel at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (X,Y).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Allumer un pixel (groupe 5, fonction 5). */
int main(void) {
neo_graphics_set_color(6); /* 5,64 */
neo_graphics_draw_pixel(210, 170); /* 5,5 : Draw Pixel */
uint8_t a = neo_graphics_read_pixel(210, 170); /* 5,33 */
uint8_t b = neo_graphics_read_pixel(211, 170);
printf("Pixel (210, 170) : %u, voisin : %u\n", a, b);
return 0;
}Pixel (210, 170) : 6, voisin : 0Mad Pascal
// Allumer un pixel (groupe 5, fonction 5).
program pixel5;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(6); // 5,64
NeoDrawPixel(210, 170); // 5,5 : Draw Pixel
a := NeoGetPixel(210, 170); // 5,33
b := NeoGetPixel(211, 170);
writeln('Pixel (210, 170) : ', a, ', voisin : ', b);
end.Pixel (210, 170) : 6, voisin : 0NeoBASIC
10 ' Allumer un pixel (groupe 5, fonction 5)
20 plot 0,0 ink 6 to 210,170
30 a = point(210,170) : b = point(211,170)
40 print "Pixel (210, 170) : ";a;", voisin : ";bPixel (210, 170) : 6, voisin : 0Assembleur 65C02 (64tass)
; Allumer un pixel (groupe 5, fonction 5).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #6
sta ControlPort+4 ; P0 : couleur 6
ldx #64 ; 5,64 : Set Color
jsr g5
lda #210
ldy #170
jsr point1
ldx #5 ; 5,5 : Draw Pixel
jsr g5
lda #210
ldy #170
jsr lire ; 5,33 : Read Pixel
sta a
lda #211
ldy #170
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Pixel (210, 170) : ", 0
t2: .text ", voisin : ", 0Pixel (210, 170) : 6, voisin : 05,6 Draw Text Officiel
Écrit un texte en mode graphique, à une position en pixels.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du coin haut gauche, en pixels |
P2-P3 | int16 | Y du coin haut gauche, en pixels |
P4-P5 | addr | adresse du texte (précédé de sa longueur) |
Sorties : aucune.
La documentation du firmware parle d'une case de caractère ; le code (GFXScaledText) prend des coordonnées en pixels, ce que confirme l'exemple. Taille (5,66), couleur et fond plein (5,65) s'appliquent. L'exemple compte les pixels allumés dans un carré de 14 pixels autour de la lettre A. En NeoBASIC, text "…" to x,y fait cet appel.
Texte de la documentation du firmware (anglais)
Draw the length-prefixed string of text stored at the memory location specified in Parameters:4,5 at the screen character cell specified in Parameters:0,1,Parameters:2,3 (X,Y).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
static uint16_t compte(uint8_t couleur, uint8_t x0, uint8_t y0, uint8_t cote) { /* pixels de cette couleur */
uint16_t n = 0;
for (uint8_t y = y0; y < y0 + cote; y++)
for (uint8_t x = x0; x < x0 + cote; x++)
if (neo_graphics_read_pixel(x, y) == couleur)
n++;
return n;
}
/* Écrire A en mode graphique et compter ses pixels (groupe 5, fonction 6). */
int main(void) {
neo_graphics_set_color(5);
neo_graphics_draw_text(200, 170, "A"); /* Draw Text */
printf("Pixels du A en couleur 5 : %u\n", compte(5, 198, 168, 14));
return 0;
}Pixels du A en couleur 5 : 16Mad Pascal
// Écrire A en mode graphique et compter ses pixels (groupe 5, fonction 6).
program texte;
uses crt, neo6502;
var s: string[4];
function compte(couleur, x0, y0, cote: byte): word; // pixels de cette couleur
var x, y: byte;
begin
result := 0;
for y := y0 to y0 + cote - 1 do
for x := x0 to x0 + cote - 1 do
if NeoGetPixel(x, y) = couleur then inc(result);
end;
begin
NeoSetColor(5);
s := 'A';
NeoDrawString(200, 170, s); // Draw Text
writeln('Pixels du A en couleur 5 : ', compte(5, 198, 168, 14));
end.Pixels du A en couleur 5 : 16NeoBASIC
10 ' Ecrire A en mode graphique et compter ses pixels (groupe 5, fonction 6)
20 text "A" dim 1 ink 5 to 200,170
30 n = 0 : for y = 168 to 181 : for x = 198 to 211
40 if point(x,y) = 5 then n = n + 1
50 next x : next y
60 print "Pixels du A en couleur 5 : ";nPixels du A en couleur 5 : 16Assembleur 65C02 (64tass)
; Écrire A en mode graphique et compter ses pixels (groupe 5, fonction 6).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #5
sta ControlPort+4
ldx #64 ; 5,64 : couleur 5
jsr g5
lda #200
ldy #170
jsr point1 ; P0-P3 : (200, 170)
lda #<lettre
sta ControlPort+8 ; P4-P5 : texte
lda #>lettre
sta ControlPort+9
ldx #6 ; fonction 6 : Draw Text
jsr g5
jsr compte
lda #<t0
ldx #>t0
jsr ecrire
lda n
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Compte les pixels de couleur coul dans le carré (x0, y0), côté cote ; résultat dans n.
compte: stz n
lda y0
sta yc
_ly: lda x0
sta xc
_lx: lda xc
ldy yc
jsr lire
cmp coul
bne _pas
inc n
_pas: inc xc
lda xc
sec
sbc x0
cmp cote
bne _lx
inc yc
lda yc
sec
sbc y0
cmp cote
bne _ly
rts
xc: .byte 0
yc: .byte 0
n: .byte 0
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
lettre: .byte 1
.text "A"
coul: .byte 5
x0: .byte 198
y0: .byte 168
cote: .byte 14
t0: .text "Pixels du A en couleur 5 : ", 0Pixels du A en couleur 5 : 165,7 Draw Image Officiel
Dessine une image de la mémoire graphique (tuile ou sprite) à une position donnée.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du coin haut gauche |
P2-P3 | int16 | Y du coin haut gauche |
P4 | uint8 | numéro d'image : $00-$7F tuiles 16×16, $80-$BF sprites 16×16, $C0-$FF sprites 32×32 |
Sorties : aucune.
La taille (5,66), le retournement (5,67) et le fond plein (5,65) s'appliquent ; la couleur 0 de l'image est transparente sauf en fond plein. Sans mémoire graphique chargée, rien n'est dessiné. En NeoBASIC, image n to x,y fait cet appel (image n, retournement dim taille to x,y).
Texte de la documentation du firmware (anglais)
Draw the image with image ID in Parameter:4 at the screen coordinates Parameters:0,1,Parameters:2,3 (X,Y). The extent and flip settings influence this command.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
static uint8_t gfx[256 + 128]; /* en-tête + une image 16x16, 4 bits par pixel */
static void images(uint8_t genre) { /* 1 : une tuile ; 2 : un sprite 16x16 */
gfx[0] = 1;
gfx[genre] = 1;
for (uint8_t y = 0; y < 16; y++)
for (uint8_t i = 0; i < 8; i++)
gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55; /* gauche : couleur 2, droite : 5 */
neo_file_store("img.gfx", gfx, sizeof gfx);
neo_file_load("img.gfx", (void *)0xFFFF); /* $FFFF : mémoire graphique */
}
/* Dessiner une image de la mémoire graphique (groupe 5, fonction 7). */
int main(void) {
images(1);
neo_graphics_set_draw_size(1); /* 5,66 */
neo_graphics_set_flip_bits(0); /* 5,67 */
neo_graphics_draw_image(200, 160, 0); /* 5,7 : Draw Image, image 0 */
uint8_t a = neo_graphics_read_pixel(202, 165);
neo_graphics_set_draw_size(1); /* 5,66 */
neo_graphics_set_flip_bits(0); /* 5,67 */
neo_graphics_draw_image(200, 160, 0); /* 5,7 : Draw Image, image 0 */
uint8_t b = neo_graphics_read_pixel(212, 165);
printf("Gauche : %u, droite : %u\n", a, b);
return 0;
}Gauche : 2, droite : 5Mad Pascal
// Dessiner une image de la mémoire graphique (groupe 5, fonction 7).
program image7;
uses crt, neo6502;
var a, b: byte;
gfx: array[0..383] of byte; // en-tête + une image 16x16
procedure images(genre: byte); // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
fillchar(@gfx, 384, 0);
gfx[0] := 1;
gfx[genre] := 1;
for y := 0 to 15 do
for i := 0 to 7 do
if i < 4 then gfx[256 + y * 8 + i] := $22 // gauche : couleur 2
else gfx[256 + y * 8 + i] := $55; // droite : couleur 5
NeoSave('img.gfx', word(@gfx), 384);
NeoLoad('img.gfx', $FFFF); // $FFFF : mémoire graphique
end;
begin
images(1);
NeoSetDrawSize(1); // 5,66
NeoSetFlip(0); // 5,67
NeoDrawImage(200, 160, 0); // 5,7 : Draw Image, image 0
a := NeoGetPixel(202, 165);
NeoSetDrawSize(1); // 5,66
NeoSetFlip(0); // 5,67
NeoDrawImage(200, 160, 0); // 5,7 : Draw Image, image 0
b := NeoGetPixel(212, 165);
writeln('Gauche : ', a, ', ', 'droite : ', b);
end.Gauche : 2, droite : 5NeoBASIC
10 ' Dessiner une image de la memoire graphique (groupe 5, fonction 7)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 image 0 to 200,160 : a = point(202,165)
40 image 0 to 200,160 : b = point(212,165)
50 print "Gauche : ";a; ", ";"droite : ";bGauche : 2, droite : 5Assembleur 65C02 (64tass)
; Dessiner une image de la mémoire graphique (groupe 5, fonction 7).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
jsr images
lda #1
sta ControlPort+4
ldx #66 ; 5,66 : taille 1
jsr g5
lda #0
sta ControlPort+4
ldx #67 ; 5,67 : retournement 0
jsr g5
lda #200
ldy #160
jsr point1
stz ControlPort+8 ; P4 : image 0
ldx #7 ; 5,7 : Draw Image
jsr g5
lda #202
ldy #165
jsr lire
sta a
lda #1
sta ControlPort+4
ldx #66 ; 5,66 : taille 1
jsr g5
lda #0
sta ControlPort+4
ldx #67 ; 5,67 : retournement 0
jsr g5
lda #200
ldy #160
jsr point1
stz ControlPort+8 ; P4 : image 0
ldx #7 ; 5,7 : Draw Image
jsr g5
lda #212
ldy #165
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda #<t3
ldx #>t3
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #<gfx
sta ControlPort+6
lda #>gfx
sta ControlPort+7
lda #<384
sta ControlPort+8
lda #>384
sta ControlPort+9
lda #3
ldx #3 ; 3,3 : Save File
jsr appel
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #$FF
sta ControlPort+6 ; $FFFF : mémoire graphique
sta ControlPort+7
lda #3
ldx #2 ; 3,2 : Load File
jmp appel
nomgfx: .byte 7
.text "img.gfx"
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
gfx: .byte 1, 1, 0, 0 ; en-tête : une tuile
.fill 252
.rept 16 ; 16 lignes : gauche couleur 2, droite couleur 5
.byte $22, $22, $22, $22, $55, $55, $55, $55
.endrept
a: .byte 0
b: .byte 0
t0: .text "Gauche : ", 0
t2: .text ", ", 0
t3: .text "droite : ", 0Gauche : 2, droite : 55,8 Draw Tilemap Modifié par Trinity
Dessine la carte de tuiles courante (5,35) dans un rectangle de l'écran.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du premier point |
P2-P3 | int16 | Y du premier point |
P4-P5 | int16 | X du second point |
P6-P7 | int16 | Y du second point |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 sans carte, si le décalage sort de la carte ou si la fenêtre est moins large qu'une tuile |
Tuiles 16×16 (32×32 en taille 2, voir 5,66), lues dans la mémoire graphique. La carte a deux tuiles 0 côte à côte : on lit donc 2 (gauche de la première), 5 (sa droite), puis 2 (gauche de la seconde). La fenêtre fait |x2-x1| pixels de large et |y2-y1| de haut : les bords droit et bas sont exclus. La carte commence par 3 octets (type, largeur, hauteur en tuiles), puis un octet par tuile ($F0 transparente, $F1-$FF couleur unie). Avec le type $81 au lieu de 1 (Trinity), un pixel de couleur 0 laisse l'écran tel quel, de même que la partie de la fenêtre hors de la carte : on superpose ainsi des cartes (plans de parallaxe). Trinity dessine aussi les cartes dans les modes 1 et 2. En NeoBASIC, tiledraw x1,y1 to x2,y2 fait cet appel.
Texte de la documentation du firmware (anglais)
Draw the current tilemap at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (top-left X,Y) and Parameters:4,5,Parameters:6,7 (bottom-right X,Y) using current graphics settings. The window is |x2-x1| pixels wide and |y2-y1| high : the right and bottom edges are excluded. The tilemap starts with 3 bytes : type, width, height (in tiles), then one byte per tile ($F0 transparent, $F1-$FF solid colour). Type bit 7 set ($81 rather than 1, Trinity T-92) : a pixel of colour 0 in a tile leaves the screen as it is, and so does the part of the window beyond the map, so that maps can be drawn over each other (parallax layers).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
static uint8_t gfx[256 + 128]; /* en-tête + une image 16x16, 4 bits par pixel */
static void images(uint8_t genre) { /* 1 : une tuile ; 2 : un sprite 16x16 */
gfx[0] = 1;
gfx[genre] = 1;
for (uint8_t y = 0; y < 16; y++)
for (uint8_t i = 0; i < 8; i++)
gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55; /* gauche : couleur 2, droite : 5 */
neo_file_store("img.gfx", gfx, sizeof gfx);
neo_file_load("img.gfx", (void *)0xFFFF); /* $FFFF : mémoire graphique */
}
static const uint8_t carte[] = { 1, 2, 1, 0, 0 }; /* format, largeur 2, hauteur 1, tuiles 0 0 */
/* Dessiner une carte de deux tuiles (groupe 5, fonction 8). */
int main(void) {
images(1);
neo_graphics_set_tilemap(carte, 0, 0); /* 5,35 */
neo_graphics_draw_tilemap(150, 160, 182, 176); /* 5,8 : Draw Tilemap */
uint8_t a = neo_graphics_read_pixel(152, 165);
uint8_t b = neo_graphics_read_pixel(160, 165);
uint8_t c = neo_graphics_read_pixel(168, 165);
printf("Couleurs sur la ligne : %u %u %u\n", a, b, c);
return 0;
}Couleurs sur la ligne : 2 5 2Mad Pascal
// Dessiner une carte de deux tuiles (groupe 5, fonction 8).
program carte8;
uses crt, neo6502;
var a, b, c: byte;
carte: array[0..4] of byte = (1, 2, 1, 0, 0); // format, largeur 2, hauteur 1, tuiles 0 0
gfx: array[0..383] of byte; // en-tête + une image 16x16
procedure images(genre: byte); // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
fillchar(@gfx, 384, 0);
gfx[0] := 1;
gfx[genre] := 1;
for y := 0 to 15 do
for i := 0 to 7 do
if i < 4 then gfx[256 + y * 8 + i] := $22 // gauche : couleur 2
else gfx[256 + y * 8 + i] := $55; // droite : couleur 5
NeoSave('img.gfx', word(@gfx), 384);
NeoLoad('img.gfx', $FFFF); // $FFFF : mémoire graphique
end;
begin
images(1);
NeoSelectTileMap(word(@carte), 0, 0); // 5,35
NeoDrawTileMap(150, 160, 182, 176); // 5,8 : Draw Tilemap
a := NeoGetPixel(152, 165);
b := NeoGetPixel(160, 165);
c := NeoGetPixel(168, 165);
writeln('Couleurs sur la ligne : ', a, ' ', b, ' ', c);
end.Couleurs sur la ligne : 2 5 2NeoBASIC
10 ' Dessiner une carte de deux tuiles (groupe 5, fonction 8)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 m = alloc(8) : poke m, 1 : poke m + 1, 2 : poke m + 2, 1 : poke m + 3, 0 : poke m + 4, 0 : ' carte 2 x 1
40 tilemap m, 0, 0
50 tiledraw 150,160 to 182,176
60 a = point(152,165) : b = point(160,165) : c = point(168,165)
70 print "Couleurs sur la ligne : ";a;" ";b;" ";cCouleurs sur la ligne : 2 5 2Assembleur 65C02 (64tass)
; Dessiner une carte de deux tuiles (groupe 5, fonction 8).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
jsr images
jsr WaitMessage
lda #<carte
sta ControlPort+4 ; P0-P1 : carte
lda #>carte
sta ControlPort+5
stz ControlPort+6 ; P2-P5 : décalage (0, 0)
stz ControlPort+7
stz ControlPort+8
stz ControlPort+9
ldx #35 ; 5,35 : Set Tilemap
jsr g5
lda #150
ldy #160
jsr point1
lda #182
ldy #176
jsr point2
ldx #8 ; 5,8 : Draw Tilemap
jsr g5
lda #152
ldy #165
jsr lire
sta a
lda #160
ldy #165
jsr lire
sta b
lda #168
ldy #165
jsr lire
sta c
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda c
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #<gfx
sta ControlPort+6
lda #>gfx
sta ControlPort+7
lda #<384
sta ControlPort+8
lda #>384
sta ControlPort+9
lda #3
ldx #3 ; 3,3 : Save File
jsr appel
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #$FF
sta ControlPort+6 ; $FFFF : mémoire graphique
sta ControlPort+7
lda #3
ldx #2 ; 3,2 : Load File
jmp appel
nomgfx: .byte 7
.text "img.gfx"
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
gfx: .byte 1, 1, 0, 0 ; en-tête : une tuile
.fill 252
.rept 16 ; 16 lignes : gauche couleur 2, droite couleur 5
.byte $22, $22, $22, $22, $55, $55, $55, $55
.endrept
carte: .byte 1, 2, 1, 0, 0 ; format, largeur 2, hauteur 1, tuiles 0 0
a: .byte 0
b: .byte 0
c: .byte 0
t0: .text "Couleurs sur la ligne : ", 0
t2: .text " ", 0
t4: .text " ", 0Couleurs sur la ligne : 2 5 25,9 Set Graphics Mode Trinity
Choisit le mode d'affichage et réinitialise écran, palette et console.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | mode : 0 standard 320×240 en 256 couleurs, 1 Hercules 720×350 monochrome, 2 essai 320×240 en 16 couleurs |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | non nul si le mode est inconnu ou non pris en charge par le matériel |
Propre à Trinity. Le mode 2 est un essai (Trinity 0.16.58), qui peut changer ou disparaître : 320×240 en 16 couleurs, deux pixels par octet (celui de gauche dans les 4 bits hauts), deux pages (5,11, 5,12), couleurs 0 à 15, console de 53×30 ; pas de couche de sprites (ils sont dessinés en XOR, comme en mode 1). L'ancien mode 2 du fork, en 320×256, a été retiré. Les sprites et les images n'existent qu'en mode 0 ; les cartes de tuiles se dessinent aussi dans les modes 1 et 2. L'exemple passe en mode 2, relit ses dimensions (5,10), puis revient au mode 0 ; l'écran étant effacé à chaque changement, il garde ses résultats et les affiche à la fin.
Texte de la documentation du firmware (anglais)
Select the display mode in Parameter:0 and reinitialise the screen, palette and console (F5 / ADR-02). 0 is the standard 320x240 256 colour mode. 1 is the Hercules mode (720x350 monochrome, 80x25 text in 9x14 cells). 2 is a TRIAL mode (Trinity T-90, study) : 320x240 in 16 colours, 4 bits per pixel, two pixels per byte, left pixel in the high nibble, two pages (5,11 / 5,12), palette entries 0-15, same display timing as mode 0 ; no sprite layer (sprites are drawn in XOR as in mode 1), console 53x30. It may change or go. (The fork's 320x256x16 mode 2 was removed on 2026-09-19.) Tilemaps are drawn in modes 1 and 2 too (packed path of 5,8). Sets the error flag if the mode is unknown or not supported by this hardware.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
static uint8_t mode, bpp, cols, lignes;
static uint16_t largeur, hauteur;
static void lire_mode(void) { /* 5,10 : Get Graphics Mode */
libre();
api(5, 10);
mode = ControlPort.params[0];
largeur = ControlPort.params[1] | (ControlPort.params[2] << 8);
hauteur = ControlPort.params[3] | (ControlPort.params[4] << 8);
bpp = ControlPort.params[5];
cols = ControlPort.params[6];
lignes = ControlPort.params[7];
}
static uint8_t choisir(uint8_t m) { /* Set Graphics Mode, erreur rendue */
libre();
ControlPort.params[0] = m;
api(5, 9);
return ControlPort.error;
}
/* Changer de mode d'affichage (groupe 5, fonction 9, Trinity). */
int main(void) {
uint8_t e2 = choisir(2); /* essai 320x240, 16 couleurs */
lire_mode(); /* 5,10 */
uint16_t l2 = largeur, h2 = hauteur;
uint8_t e0 = choisir(0); /* retour au mode standard (écran effacé) */
lire_mode();
printf("Mode 2 : erreur %u, %u x %u\n", e2, l2, h2);
printf("Mode 0 : erreur %u, %u x %u\n", e0, largeur, hauteur);
return 0;
}Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240Mad Pascal
// Changer de mode d'affichage (groupe 5, fonction 9, Trinity).
program choisirmode;
uses crt, neo6502;
var e2, e0: byte;
largeur, hauteur, l2, h2: word;
function choisir(m: byte): byte; // Set Graphics Mode, erreur rendue
begin
NeoWaitMessage;
NeoMessage.params[0] := m;
NeoSendMessage(5, 9);
NeoWaitMessage;
result := NeoMessage.error;
end;
procedure lire_mode; // 5,10 : Get Graphics Mode
begin
NeoSendMessage(5, 10);
NeoWaitMessage;
largeur := wordxParams[0];
hauteur := wordxParams[1];
end;
begin
e2 := choisir(2); // essai 320x240, 16 couleurs
lire_mode;
l2 := largeur;
h2 := hauteur;
e0 := choisir(0); // retour au mode standard (écran effacé)
lire_mode;
writeln('Mode 2 : erreur ', e2, ', ', l2, ' x ', h2);
writeln('Mode 0 : erreur ', e0, ', ', largeur, ' x ', hauteur);
end.Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240NeoBASIC
10 ' Changer de mode d'affichage (groupe 5, fonction 9, Trinity)
20 m = 2 : gosub 1000 : e2 = e : l2 = l : h2 = h : ' essai 320x240, 16 couleurs
30 m = 0 : gosub 1000 : ' retour au mode standard (ecran efface)
40 print "Mode 2 : erreur ";e2;", ";l2;" x ";h2
50 print "Mode 0 : erreur ";e;", ";l;" x ";h
60 end
1000 ' 5,9 : mode m, erreur dans e ; puis 5,10 : largeur l, hauteur h
1010 while peek($ff00) : wend : poke $ff04, m : poke $ff01, 9 : poke $ff00, 5
1020 while peek($ff00) : wend : e = peek($ff02)
1030 poke $ff01, 10 : poke $ff00, 5
1040 while peek($ff00) : wend : l = deek($ff05) : h = deek($ff07)
1050 returnMode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 240Assembleur 65C02 (64tass)
; Changer de mode d'affichage (groupe 5, fonction 9, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #2 ; essai 320x240, 16 couleurs
jsr choisir
sta e2
ldy #0
jsr taille ; dimensions du mode 2 en dim
lda #0 ; retour au mode standard (écran effacé)
jsr choisir
sta e0
ldy #4
jsr taille ; dimensions du mode 0 en dim+4
lda #<t0
ldx #>t0
jsr ecrire
lda e2
jsr decimal
ldy #0
jsr montrer
lda #<t1
ldx #>t1
jsr ecrire
lda e0
jsr decimal
ldy #4
jmp montrer
; 5,10 : largeur et hauteur (P1-P4) copiées en dim+Y, à l'abri avant d'afficher.
taille: jsr WaitMessage
lda #5
ldx #10 ; 5,10 : Get Graphics Mode
jsr appel
ldx #0
_copie: lda ControlPort+5,x
sta dim,y
iny
inx
cpx #4
bne _copie
rts
; Affiche « , largeur x hauteur » des dimensions en dim+Y, puis un retour à la ligne.
montrer:
sty ou
lda #<t2
ldx #>t2
jsr ecrire
ldy ou
lda dim,y ; largeur
ldx dim+1,y
jsr decimal16
lda #<t3
ldx #>t3
jsr ecrire
ldy ou
lda dim+2,y ; hauteur
ldx dim+3,y
jsr decimal16
lda #13
jmp WriteCharacter
ou: .byte 0
; Mode A (5,9), erreur rendue dans A.
choisir:
pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0 : mode
lda #5
ldx #9 ; fonction 9 : Set Graphics Mode
jsr appel
lda ControlPort+2
rts
; Affiche en décimal le nombre de 16 bits A (poids faible) X (poids fort), jusqu'à 999.
decimal16:
stx fort
ldy #0 ; centaines
_c: sec
sbc #100
pha
lda fort
sbc #0
bcc _cf
sta fort
pla
iny
bra _c
_cf: pla
clc
adc #100
pha
tya
beq _d
ora #'0'
jsr WriteCharacter
pla
jmp decimal2
_d: pla
jmp decimal
decimal2: ; A (0-99) sur deux chiffres
ldy #0
_dz: cmp #10
bcc _u
sbc #10
iny
bra _dz
_u: pha
tya
ora #'0'
jsr WriteCharacter
pla
ora #'0'
jmp WriteCharacter
fort: .byte 0
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
e2: .byte 0
e0: .byte 0
dim: .fill 8
t0: .text "Mode 2 : erreur ", 0
t1: .text "Mode 0 : erreur ", 0
t2: .text ", ", 0
t3: .text " x ", 0Mode 2 : erreur 0, 320 x 240
Mode 0 : erreur 0, 320 x 2405,10 Get Graphics Mode Trinity
Donne le mode d'affichage courant et ses dimensions.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | mode |
P1-P2 | uint16 | largeur en pixels |
P3-P4 | uint16 | hauteur en pixels |
P5 | uint8 | bits par pixel |
P6-P7 | uint8 | console : colonnes, puis lignes |
Propre à Trinity. En mode 0 : 320 × 240, 8 bits par pixel, console de 53 colonnes sur 30 lignes (police 6 × 8).
Texte de la documentation du firmware (anglais)
Return the current display mode in Parameter:0, the pixel width in Parameters:1,2, the pixel height in Parameters:3,4, the bits per pixel in Parameter:5 and the console size in characters in Parameters:6,7.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
static uint8_t mode, bpp, cols, lignes;
static uint16_t largeur, hauteur;
static void lire_mode(void) { /* 5,10 : Get Graphics Mode */
libre();
api(5, 10);
mode = ControlPort.params[0];
largeur = ControlPort.params[1] | (ControlPort.params[2] << 8);
hauteur = ControlPort.params[3] | (ControlPort.params[4] << 8);
bpp = ControlPort.params[5];
cols = ControlPort.params[6];
lignes = ControlPort.params[7];
}
/* Lire le mode d'affichage (groupe 5, fonction 10, Trinity). */
int main(void) {
lire_mode();
printf("Mode %u : %u x %u, %u bits, console %u x %u\n", mode, largeur, hauteur, bpp, cols, lignes);
return 0;
}Mode 0 : 320 x 240, 8 bits, console 53 x 30Mad Pascal
// Lire le mode d'affichage (groupe 5, fonction 10, Trinity).
program litmode;
uses crt, neo6502;
var mode, bpp, cols, lignes: byte;
largeur, hauteur: word;
begin
NeoWaitMessage;
NeoSendMessage(5, 10); // Get Graphics Mode
NeoWaitMessage;
mode := NeoMessage.params[0];
largeur := wordxParams[0]; // P1-P2
hauteur := wordxParams[1]; // P3-P4
bpp := NeoMessage.params[5];
cols := NeoMessage.params[6];
lignes := NeoMessage.params[7];
writeln('Mode ', mode, ' : ', largeur, ' x ', hauteur, ', ', bpp, ' bits, console ', cols, ' x ', lignes);
end.Mode 0 : 320 x 240, 8 bits, console 53 x 30NeoBASIC
10 ' Lire le mode d'affichage (groupe 5, fonction 10, Trinity)
20 while peek($ff00) : wend : poke $ff01, 10 : poke $ff00, 5
30 while peek($ff00) : wend : m = peek($ff04) : l = peek($ff05) + 256 * peek($ff06) : h = peek($ff07) + 256 * peek($ff08)
40 b = peek($ff09) : c = peek($ff0a) : r = peek($ff0b)
50 print "Mode ";m;" : ";l;" x ";h;", ";b;" bits, console ";c;" x ";rMode 0 : 320 x 240, 8 bits, console 53 x 30Assembleur 65C02 (64tass)
; Lire le mode d'affichage (groupe 5, fonction 10, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #5
ldx #10 ; fonction 10 : Get Graphics Mode
jsr appel
ldx #7
_copie: lda ControlPort+4,x ; P0-P7 à l'abri avant d'afficher
sta p,x
dex
bpl _copie
lda #<t0
ldx #>t0
jsr ecrire
lda p
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
lda p+1 ; 320 = $0140 : poids fort 1
ldx p+2
jsr decimal16
lda #<t2
ldx #>t2
jsr ecrire
lda p+3
ldx p+4
jsr decimal16
lda #<t3
ldx #>t3
jsr ecrire
lda p+5
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda p+6
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda p+7
jsr decimal
lda #13
jmp WriteCharacter
; Affiche en décimal le nombre de 16 bits A (poids faible) X (poids fort), jusqu'à 999.
decimal16:
stx fort
ldy #0 ; centaines
_c: sec
sbc #100
pha
lda fort
sbc #0
bcc _cf
sta fort
pla
iny
bra _c
_cf: pla
clc
adc #100
pha
tya
beq _d
ora #'0'
jsr WriteCharacter
pla
jmp decimal2
_d: pla
jmp decimal
decimal2: ; A (0-99) sur deux chiffres
ldy #0
_dz: cmp #10
bcc _u
sbc #10
iny
bra _dz
_u: pha
tya
ora #'0'
jsr WriteCharacter
pla
ora #'0'
jmp WriteCharacter
fort: .byte 0
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
p: .fill 8
t0: .text "Mode ", 0
t1: .text " : ", 0
t2: .text " x ", 0
t3: .text ", ", 0
t4: .text " bits, console ", 0Mode 0 : 320 x 240, 8 bits, console 53 x 305,11 Set Draw Page Trinity
Choisit la page dans laquelle dessinent la console et les fonctions graphiques.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | page : 0, ou 1 dans les modes 1 et 2 |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | non nul si la page n'existe pas dans le mode courant |
Propre à Trinity. Le mode 0 n'a qu'une page, les modes 1 et 2 (l'essai en 16 couleurs, voir 5,9) en ont deux : on dessine dans l'une pendant que l'autre est affichée (5,12). Selon la documentation de Trinity 0.16.69 (non essayé au banc), la page n commence en mémoire vidéo à n × (octets par ligne × lignes), adresse que le blitter atteint par les pages $80 et $81 : en mode 2, la page 1 est en $80:9600 (160 × 240) ; en mode 1, en $80:7B0C (90 × 350). L'exemple, en mode 0, montre le refus de la page 1.
Texte de la documentation du firmware (anglais)
Select the page (Parameter:0) that console and graphics commands draw into (F-55). Mode 0 has one page, modes 1 and 2 have two (0 and 1) ; mode 2 is the 16 colour trial of T-90. Sets the error flag if the page does not exist. Page n starts at offset n x (bytes per line x lines) of the video RAM, which is what the blitter addresses as pages $80/$81 : in mode 2, page 1 is at $80:9600 (38400 = 160 x 240), so a 12,3 into the hidden page targets $80:9600 + y x 160 + x / 2, with target format 5 (even x) or 6 (odd x). In mode 1, page 1 is at $80:7B0C (31500 = 90 x 350).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
static uint8_t page(uint8_t p) { /* Set Draw Page, erreur rendue */
libre();
ControlPort.params[0] = p;
api(5, 11);
return ControlPort.error;
}
/* Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity). */
int main(void) {
uint8_t e1 = page(1); /* le mode 0 n'a qu'une page */
uint8_t e0 = page(0);
printf("Page 1 : erreur %u, page 0 : erreur %u\n", e1, e0);
return 0;
}Page 1 : erreur 1, page 0 : erreur 0Mad Pascal
// Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity).
program page11;
uses crt, neo6502;
var e1, e0: byte;
function page(p: byte): byte; // Set Draw Page, erreur rendue
begin
NeoWaitMessage;
NeoMessage.params[0] := p;
NeoSendMessage(5, 11);
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
e1 := page(1); // le mode 0 n'a qu'une page
e0 := page(0);
writeln('Page 1 : erreur ', e1, ', page 0 : erreur ', e0);
end.Page 1 : erreur 1, page 0 : erreur 0NeoBASIC
10 ' Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity)
20 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 11 : poke $ff00, 5
30 while peek($ff00) : wend : e1 = peek($ff02)
40 poke $ff04, 0 : poke $ff01, 11 : poke $ff00, 5
50 while peek($ff00) : wend : e0 = peek($ff02)
60 print "Page 1 : erreur ";e1;", page 0 : erreur ";e0Page 1 : erreur 1, page 0 : erreur 0Assembleur 65C02 (64tass)
; Choisir la page où l'on dessine (groupe 5, fonction 11, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #1 ; le mode 0 n'a qu'une page
jsr page
sta e1
lda #0
jsr page
sta e0
lda #<t0
ldx #>t0
jsr ecrire
lda e1
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
lda e0
jsr decimal
lda #13
jmp WriteCharacter
; Page A (5,11), erreur rendue dans A.
page: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0 : page
lda #5
ldx #11 ; fonction 11 : Set Draw Page
jsr appel
lda ControlPort+2
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
e1: .byte 0
e0: .byte 0
t0: .text "Page 1 : erreur ", 0
t1: .text ", page 0 : erreur ", 0Page 1 : erreur 1, page 0 : erreur 05,12 Set Display Page Trinity
Choisit la page affichée à partir de la trame suivante.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | page : 0, ou 1 dans les modes 1 et 2 |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | non nul si la page n'existe pas dans le mode courant |
Propre à Trinity. Le changement a lieu à la trame suivante : attendre que 5,37 change pour être sûr qu'il est fait. L'exemple, en mode 0 (une seule page), montre le refus de la page 1.
Texte de la documentation du firmware (anglais)
Select the page (Parameter:0) shown on screen from the next frame (F-55). Use Function 37 (Frame Count) to wait for the swap. Sets the error flag if the page does not exist.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
static uint8_t page(uint8_t p) { /* Set Display Page, erreur rendue */
libre();
ControlPort.params[0] = p;
api(5, 12);
return ControlPort.error;
}
/* Choisir la page affichée (groupe 5, fonction 12, Trinity). */
int main(void) {
uint8_t e1 = page(1); /* le mode 0 n'a qu'une page */
uint8_t e0 = page(0);
printf("Page 1 : erreur %u, page 0 : erreur %u\n", e1, e0);
return 0;
}Page 1 : erreur 1, page 0 : erreur 0Mad Pascal
// Choisir la page affichée (groupe 5, fonction 12, Trinity).
program page12;
uses crt, neo6502;
var e1, e0: byte;
function page(p: byte): byte; // Set Display Page, erreur rendue
begin
NeoWaitMessage;
NeoMessage.params[0] := p;
NeoSendMessage(5, 12);
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
e1 := page(1); // le mode 0 n'a qu'une page
e0 := page(0);
writeln('Page 1 : erreur ', e1, ', page 0 : erreur ', e0);
end.Page 1 : erreur 1, page 0 : erreur 0NeoBASIC
10 ' Choisir la page affichee (groupe 5, fonction 12, Trinity)
20 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 12 : poke $ff00, 5
30 while peek($ff00) : wend : e1 = peek($ff02)
40 poke $ff04, 0 : poke $ff01, 12 : poke $ff00, 5
50 while peek($ff00) : wend : e0 = peek($ff02)
60 print "Page 1 : erreur ";e1;", page 0 : erreur ";e0Page 1 : erreur 1, page 0 : erreur 0Assembleur 65C02 (64tass)
; Choisir la page affichée (groupe 5, fonction 12, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #1 ; le mode 0 n'a qu'une page
jsr page
sta e1
lda #0
jsr page
sta e0
lda #<t0
ldx #>t0
jsr ecrire
lda e1
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
lda e0
jsr decimal
lda #13
jmp WriteCharacter
; Page A (5,12), erreur rendue dans A.
page: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0 : page
lda #5
ldx #12 ; fonction 12 : Set Display Page
jsr appel
lda ControlPort+2
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
e1: .byte 0
e0: .byte 0
t0: .text "Page 1 : erreur ", 0
t1: .text ", page 0 : erreur ", 0Page 1 : erreur 1, page 0 : erreur 05,32 Set Palette Officiel
Change la couleur d'un numéro de la palette.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro de couleur |
P1 | uint8 | rouge (0-255) |
P2 | uint8 | vert (0-255) |
P3 | uint8 | bleu (0-255) |
Sorties : aucune.
Tout ce qui est déjà affiché dans cette couleur change aussitôt. 5,34 rend la palette d'origine. En NeoBASIC, palette n, r, g, b fait cet appel.
Mots-clés NeoBASIC qui font cet appel : palette
Texte de la documentation du firmware (anglais)
Set the palette colour at the index spcified in Parameter:0 to the values in Parameter:1,Parameter:2,Parameter:3 (RGB).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
/* Changer puis relire une couleur de la palette (groupe 5, fonction 32). */
int main(void) {
neo_graphics_set_palette(5, 255, 128, 0); /* Set Palette : orange */
libre();
ControlPort.params[0] = 5;
api(5, 38); /* 5,38 : Get Palette */
printf("Couleur 5 : %u %u %u\n", ControlPort.params[1], ControlPort.params[2], ControlPort.params[3]);
neo_graphics_reset_palette(); /* 5,34 */
return 0;
}Couleur 5 : 255 128 0Mad Pascal
// Changer puis relire une couleur de la palette (groupe 5, fonction 32).
program palette;
uses crt, neo6502;
var r, g, b: byte;
begin
NeoSetPalette(5, 255, 128, 0); // Set Palette : orange
NeoGetPalette(5, r, g, b); // 5,38
NeoResetPalette; // 5,34
writeln('Couleur 5 : ', r, ' ', g, ' ', b);
end.Couleur 5 : 255 128 0NeoBASIC
10 ' Changer puis relire une couleur de la palette (groupe 5, fonction 32)
20 palette 5, 255, 128, 0
30 while peek($ff00) : wend : poke $ff04, 5 : poke $ff01, 38 : poke $ff00, 5 : ' 5,38
40 while peek($ff00) : wend : r = peek($ff05) : g = peek($ff06) : b = peek($ff07)
50 print "Couleur 5 : ";r;" ";g;" ";bCouleur 5 : 255 128 0Assembleur 65C02 (64tass)
; Changer puis relire une couleur de la palette (groupe 5, fonction 32).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #5
sta ControlPort+4 ; P0 : couleur 5
lda #255
sta ControlPort+5 ; P1-P3 : rouge, vert, bleu
lda #128
sta ControlPort+6
stz ControlPort+7
ldx #32 ; fonction 32 : Set Palette
jsr g5
lda #5
sta ControlPort+4
ldx #38 ; 5,38 : Get Palette
jsr g5
lda ControlPort+5
sta r
lda ControlPort+6
sta v
lda ControlPort+7
sta b
ldx #34 ; 5,34 : Reset Palette
jsr g5
lda #<t0
ldx #>t0
jsr ecrire
lda r
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda v
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
r: .byte 0
v: .byte 0
b: .byte 0
t0: .text "Couleur 5 : ", 0
t2: .text " ", 0
t4: .text " ", 0Couleur 5 : 255 128 05,33 Read Pixel Officiel
Lit la couleur d'un pixel de l'écran.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du point |
P2-P3 | int16 | Y du point |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | couleur : 0 à 255, ou 0 à 15 (fond seul) quand des sprites sont affichés |
erreur | uint8 | 1 si le point est hors de l'écran |
Quand des sprites sont utilisés, le firmware ne rend que les 4 bits bas (le fond) ; 5,36 lit la couche des sprites. En NeoBASIC, point(x, y) fait cet appel.
Mots-clés NeoBASIC qui font cet appel : point()
Texte de la documentation du firmware (anglais)
Read a single pixel at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (X,Y). When the routine completes, the result will be in Parameter:0. If sprites are in use, this will be the background only (0..15), if sprites are not in use it may return (0..255)
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Lire la couleur d'un pixel (groupe 5, fonction 33). */
int main(void) {
neo_graphics_set_color(6); /* 5,64 */
neo_graphics_draw_pixel(210, 170); /* 5,5 */
uint8_t a = neo_graphics_read_pixel(210, 170); /* 5,33 : Read Pixel */
uint8_t b = neo_graphics_read_pixel(211, 170);
printf("Pixel (210, 170) : %u, voisin : %u\n", a, b);
return 0;
}Pixel (210, 170) : 6, voisin : 0Mad Pascal
// Lire la couleur d'un pixel (groupe 5, fonction 33).
program pixel33;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(6); // 5,64
NeoDrawPixel(210, 170); // 5,5
a := NeoGetPixel(210, 170); // 5,33 : Read Pixel
b := NeoGetPixel(211, 170);
writeln('Pixel (210, 170) : ', a, ', voisin : ', b);
end.Pixel (210, 170) : 6, voisin : 0NeoBASIC
10 ' Lire la couleur d'un pixel (groupe 5, fonction 33)
20 plot 0,0 ink 6 to 210,170
30 a = point(210,170) : b = point(211,170)
40 print "Pixel (210, 170) : ";a;", voisin : ";bPixel (210, 170) : 6, voisin : 0Assembleur 65C02 (64tass)
; Lire la couleur d'un pixel (groupe 5, fonction 33).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #6
sta ControlPort+4 ; P0 : couleur 6
ldx #64 ; 5,64 : Set Color
jsr g5
lda #210
ldy #170
jsr point1
ldx #5 ; 5,5 : Draw Pixel
jsr g5
lda #210
ldy #170
jsr lire ; 5,33 : Read Pixel
sta a
lda #211
ldy #170
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Pixel (210, 170) : ", 0
t2: .text ", voisin : ", 0Pixel (210, 170) : 6, voisin : 05,34 Reset Palette Officiel
Rend à la palette ses couleurs d'origine.
Entrées : aucune.
Sorties : aucune.
L'exemple change la couleur 1 en (1, 2, 3), remet la palette d'origine et relit la couleur 1. En NeoBASIC, palette clear fait cet appel.
Mots-clés NeoBASIC qui font cet appel : palette
Texte de la documentation du firmware (anglais)
Reset the palette to the defaults.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
/* Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34). */
int main(void) {
neo_graphics_set_palette(1, 1, 2, 3); /* 5,32 */
neo_graphics_reset_palette(); /* Reset Palette */
libre();
ControlPort.params[0] = 1;
api(5, 38); /* 5,38 : Get Palette */
printf("Couleur 1 remise : %u %u %u\n", ControlPort.params[1], ControlPort.params[2], ControlPort.params[3]);
return 0;
}Couleur 1 remise : 255 0 77Mad Pascal
// Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34).
program repalette;
uses crt, neo6502;
var r, g, b: byte;
begin
NeoSetPalette(1, 1, 2, 3); // 5,32
NeoResetPalette; // Reset Palette
NeoGetPalette(1, r, g, b); // 5,38
writeln('Couleur 1 remise : ', r, ' ', g, ' ', b);
end.Couleur 1 remise : 255 0 77NeoBASIC
10 ' Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34)
20 palette 1, 1, 2, 3
30 palette clear
40 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 38 : poke $ff00, 5 : ' 5,38
50 while peek($ff00) : wend : r = peek($ff05) : g = peek($ff06) : b = peek($ff07)
60 print "Couleur 1 remise : ";r;" ";g;" ";bCouleur 1 remise : 255 0 77Assembleur 65C02 (64tass)
; Changer une couleur, puis remettre la palette d'origine (groupe 5, fonction 34).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #1
sta ControlPort+4 ; couleur 1 := (1, 2, 3)
sta ControlPort+5
lda #2
sta ControlPort+6
lda #3
sta ControlPort+7
ldx #32 ; 5,32 : Set Palette
jsr g5
ldx #34 ; fonction 34 : Reset Palette
jsr g5
lda #1
sta ControlPort+4
ldx #38 ; 5,38 : Get Palette
jsr g5
lda ControlPort+5
sta r
lda ControlPort+6
sta v
lda ControlPort+7
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda r
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda v
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
r: .byte 0
v: .byte 0
b: .byte 0
t0: .text "Couleur 1 remise : ", 0
t2: .text " ", 0
t4: .text " ", 0Couleur 1 remise : 255 0 775,35 Set Tilemap Officiel
Désigne la carte de tuiles, en mémoire du 65C02, et le décalage de départ en pixels.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse de la carte : un octet de format, largeur et hauteur en tuiles, puis un numéro de tuile par case, ligne par ligne |
P2-P3 | uint16 | décalage X dans la carte, en pixels |
P4-P5 | uint16 | décalage Y dans la carte, en pixels |
Sorties : aucune.
La carte reste en mémoire du 65C02 et est relue à chaque tracé (5,8). Sur Trinity, une carte qui déborde de la mémoire est refusée (T-60). En NeoBASIC, tilemap adresse, x, y fait cet appel.
Mots-clés NeoBASIC qui font cet appel : tilemap
Texte de la documentation du firmware (anglais)
Set the current tilemap. Parameters:0,1 is the memory address of the tilemap, and Parameters:2,3,Parameters:4,5 (X,Y) specifies the offset into the tilemap, in units of pixels, of the top-left pixel of the tile.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
static uint8_t gfx[256 + 128]; /* en-tête + une image 16x16, 4 bits par pixel */
static void images(uint8_t genre) { /* 1 : une tuile ; 2 : un sprite 16x16 */
gfx[0] = 1;
gfx[genre] = 1;
for (uint8_t y = 0; y < 16; y++)
for (uint8_t i = 0; i < 8; i++)
gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55; /* gauche : couleur 2, droite : 5 */
neo_file_store("img.gfx", gfx, sizeof gfx);
neo_file_load("img.gfx", (void *)0xFFFF); /* $FFFF : mémoire graphique */
}
static const uint8_t carte[] = { 1, 2, 1, 0, 0 }; /* format, largeur 2, hauteur 1, tuiles 0 0 */
/* Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35). */
int main(void) {
images(1);
neo_graphics_set_tilemap(carte, 0, 0); /* 5,35 : Set Tilemap */
neo_graphics_draw_tilemap(150, 160, 182, 176); /* 5,8 */
uint8_t a = neo_graphics_read_pixel(152, 165);
uint8_t b = neo_graphics_read_pixel(160, 165);
uint8_t c = neo_graphics_read_pixel(168, 165);
printf("Couleurs sur la ligne : %u %u %u\n", a, b, c);
return 0;
}Couleurs sur la ligne : 2 5 2Mad Pascal
// Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35).
program carte35;
uses crt, neo6502;
var a, b, c: byte;
carte: array[0..4] of byte = (1, 2, 1, 0, 0); // format, largeur 2, hauteur 1, tuiles 0 0
gfx: array[0..383] of byte; // en-tête + une image 16x16
procedure images(genre: byte); // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
fillchar(@gfx, 384, 0);
gfx[0] := 1;
gfx[genre] := 1;
for y := 0 to 15 do
for i := 0 to 7 do
if i < 4 then gfx[256 + y * 8 + i] := $22 // gauche : couleur 2
else gfx[256 + y * 8 + i] := $55; // droite : couleur 5
NeoSave('img.gfx', word(@gfx), 384);
NeoLoad('img.gfx', $FFFF); // $FFFF : mémoire graphique
end;
begin
images(1);
NeoSelectTileMap(word(@carte), 0, 0); // 5,35 : Set Tilemap
NeoDrawTileMap(150, 160, 182, 176); // 5,8
a := NeoGetPixel(152, 165);
b := NeoGetPixel(160, 165);
c := NeoGetPixel(168, 165);
writeln('Couleurs sur la ligne : ', a, ' ', b, ' ', c);
end.Couleurs sur la ligne : 2 5 2NeoBASIC
10 ' Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 m = alloc(8) : poke m, 1 : poke m + 1, 2 : poke m + 2, 1 : poke m + 3, 0 : poke m + 4, 0 : ' carte 2 x 1
40 tilemap m, 0, 0
50 tiledraw 150,160 to 182,176
60 a = point(152,165) : b = point(160,165) : c = point(168,165)
70 print "Couleurs sur la ligne : ";a;" ";b;" ";cCouleurs sur la ligne : 2 5 2Assembleur 65C02 (64tass)
; Choisir une carte de tuiles et la dessiner (groupe 5, fonction 35).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
jsr images
jsr WaitMessage
lda #<carte
sta ControlPort+4 ; P0-P1 : carte
lda #>carte
sta ControlPort+5
stz ControlPort+6 ; P2-P5 : décalage (0, 0)
stz ControlPort+7
stz ControlPort+8
stz ControlPort+9
ldx #35 ; 5,35 : Set Tilemap
jsr g5
lda #150
ldy #160
jsr point1
lda #182
ldy #176
jsr point2
ldx #8 ; 5,8 : Draw Tilemap
jsr g5
lda #152
ldy #165
jsr lire
sta a
lda #160
ldy #165
jsr lire
sta b
lda #168
ldy #165
jsr lire
sta c
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda c
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #<gfx
sta ControlPort+6
lda #>gfx
sta ControlPort+7
lda #<384
sta ControlPort+8
lda #>384
sta ControlPort+9
lda #3
ldx #3 ; 3,3 : Save File
jsr appel
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #$FF
sta ControlPort+6 ; $FFFF : mémoire graphique
sta ControlPort+7
lda #3
ldx #2 ; 3,2 : Load File
jmp appel
nomgfx: .byte 7
.text "img.gfx"
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
gfx: .byte 1, 1, 0, 0 ; en-tête : une tuile
.fill 252
.rept 16 ; 16 lignes : gauche couleur 2, droite couleur 5
.byte $22, $22, $22, $22, $55, $55, $55, $55
.endrept
carte: .byte 1, 2, 1, 0, 0 ; format, largeur 2, hauteur 1, tuiles 0 0
a: .byte 0
b: .byte 0
c: .byte 0
t0: .text "Couleurs sur la ligne : ", 0
t2: .text " ", 0
t4: .text " ", 0Couleurs sur la ligne : 2 5 25,36 Read Sprite Pixel Officiel
Lit la couleur d'un pixel de la couche des sprites.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du point |
P2-P3 | int16 | Y du point |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | couleur du sprite (0 à 15), 0 s'il n'y a pas de sprite à cet endroit ou pas de sprites |
erreur | uint8 | 1 si le point est hors de l'écran |
Les sprites occupent les 4 bits hauts de la mémoire d'écran, le fond les 4 bits bas. L'exemple place le sprite 0 (image 16×16, ancré au centre) sur un pixel de fond de couleur 6 : 5,36 lit le sprite, 5,33 le fond. Il efface ensuite les sprites (6,1). En NeoBASIC, spoint(x, y) fait cet appel.
Mots-clés NeoBASIC qui font cet appel : spoint()
Texte de la documentation du firmware (anglais)
Read Pixel from the sprite layer at the screen coordinates specified in Parameters:0,1,Parameters:2,3 (X,Y). When the routine completes, the result will be in Parameter:0. Refer to Section "Pixel Colors" for details.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
static uint8_t gfx[256 + 128]; /* en-tête + une image 16x16, 4 bits par pixel */
static void images(uint8_t genre) { /* 1 : une tuile ; 2 : un sprite 16x16 */
gfx[0] = 1;
gfx[genre] = 1;
for (uint8_t y = 0; y < 16; y++)
for (uint8_t i = 0; i < 8; i++)
gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55; /* gauche : couleur 2, droite : 5 */
neo_file_store("img.gfx", gfx, sizeof gfx);
neo_file_load("img.gfx", (void *)0xFFFF); /* $FFFF : mémoire graphique */
}
/* Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36). */
int main(void) {
images(2); /* un sprite 16x16 */
neo_graphics_set_color(6);
neo_graphics_draw_pixel(200, 170); /* fond : couleur 6 */
neo_sprite_set(0, 200, 170, 0, 0, 0); /* 6,2 : sprite 0, image 0 */
libre();
xy(0, 200, 170);
api(5, 36); /* Read Sprite Pixel */
uint8_t a = ControlPort.params[0];
uint8_t b = neo_graphics_read_pixel(200, 170);
neo_sprite_reset(); /* 6,1 */
printf("Sprite : %u, fond : %u\n", a, b);
return 0;
}Sprite : 5, fond : 6Mad Pascal
// Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36).
program spoint;
uses crt, neo6502;
var a, b: byte;
gfx: array[0..383] of byte; // en-tête + une image 16x16
procedure images(genre: byte); // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
fillchar(@gfx, 384, 0);
gfx[0] := 1;
gfx[genre] := 1;
for y := 0 to 15 do
for i := 0 to 7 do
if i < 4 then gfx[256 + y * 8 + i] := $22 // gauche : couleur 2
else gfx[256 + y * 8 + i] := $55; // droite : couleur 5
NeoSave('img.gfx', word(@gfx), 384);
NeoLoad('img.gfx', $FFFF); // $FFFF : mémoire graphique
end;
begin
images(2); // un sprite 16x16
NeoSetColor(6);
NeoDrawPixel(200, 170); // fond : couleur 6
NeoUpdateSprite(0, 200, 170, 0, 0, 0); // 6,2 : sprite 0, image 0
a := NeoGetSpritePixel(200, 170); // Read Sprite Pixel
b := NeoGetPixel(200, 170);
NeoResetSprites; // 6,1
writeln('Sprite : ', a, ', fond : ', b);
end.Sprite : 5, fond : 6NeoBASIC
10 ' Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 2, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 plot 0,0 ink 6 to 200,170 : ' fond : couleur 6
40 sprite 0 image $80 to 200,170 : ' $80 : premier sprite 16x16
50 a = spoint(200,170) : b = point(200,170)
60 sprite clear
70 print "Sprite : ";a;", fond : ";bSprite : 5, fond : 6Assembleur 65C02 (64tass)
; Lire un pixel de sprite et le fond dessous (groupe 5, fonction 36).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
jsr images ; un sprite 16x16
lda #6
sta ControlPort+4
ldx #64 ; 5,64 : couleur 6
jsr g5
lda #200
ldy #170
jsr point1
ldx #5 ; 5,5 : fond
jsr g5
stz ControlPort+4 ; P0 : sprite 0
lda #200
sta ControlPort+5 ; P1-P2 : X
stz ControlPort+6
lda #170
sta ControlPort+7 ; P3-P4 : Y
stz ControlPort+8
stz ControlPort+9 ; P5 : image 0
stz ControlPort+10 ; P6 : pas de retournement
stz ControlPort+11 ; P7 : ancre au centre
lda #6
ldx #2 ; 6,2 : Sprite Set
jsr appel
lda #200
ldy #170
jsr point1
ldx #36 ; fonction 36 : Read Sprite Pixel
jsr g5
lda ControlPort+4
sta a
lda #200
ldy #170
jsr lire
sta b
lda #6
ldx #1 ; 6,1 : Sprite Reset
jsr appel
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #<gfx
sta ControlPort+6
lda #>gfx
sta ControlPort+7
lda #<384
sta ControlPort+8
lda #>384
sta ControlPort+9
lda #3
ldx #3 ; 3,3 : Save File
jsr appel
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #$FF
sta ControlPort+6 ; $FFFF : mémoire graphique
sta ControlPort+7
lda #3
ldx #2 ; 3,2 : Load File
jmp appel
nomgfx: .byte 7
.text "img.gfx"
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
gfx: .byte 1, 0, 1, 0 ; en-tête : un sprite 16x16
.fill 252
.rept 16 ; 16 lignes : gauche couleur 2, droite couleur 5
.byte $22, $22, $22, $22, $55, $55, $55, $55
.endrept
a: .byte 0
b: .byte 0
t0: .text "Sprite : ", 0
t2: .text ", fond : ", 0Sprite : 5, fond : 65,37 Frame Count Officiel
Donne le nombre de balayages d'écran (trames) depuis la mise sous tension.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0-P3 | uint32 | nombre de trames |
Le compteur change au début de chaque balayage : attendre qu'il change synchronise un programme sur l'écran (c'est ce que fait NeoWaitForVblank en Mad Pascal). L'exemple attend un changement et affiche l'écart. En NeoBASIC, vblanks() fait cet appel.
Mots-clés NeoBASIC qui font cet appel : vblanks()
Texte de la documentation du firmware (anglais)
Deposit into Parameters:0..3, the number of v-blanks (full screen redraws) which have occurred since power-on. This is updated at the start of each v-blank period.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Attendre la trame suivante (groupe 5, fonction 37). */
int main(void) {
long t0 = neo_graphics_frame_count(); /* Frame Count */
long t1;
do
t1 = neo_graphics_frame_count();
while (t1 == t0);
printf("Trame suivante : ecart %ld\n", t1 - t0);
return 0;
}Trame suivante : ecart 1Mad Pascal
// Attendre la trame suivante (groupe 5, fonction 37).
program trames;
uses crt, neo6502;
var t0, t1: cardinal;
begin
t0 := NeoGetVblanks; // Frame Count
repeat
t1 := NeoGetVblanks;
until t1 <> t0;
writeln('Trame suivante : ecart ', t1 - t0);
end.Trame suivante : ecart 1NeoBASIC
10 ' Attendre la trame suivante (groupe 5, fonction 37)
20 t0 = vblanks()
30 repeat : t1 = vblanks() : until t1 <> t0
40 print "Trame suivante : ecart ";t1 - t0Trame suivante : ecart 1Assembleur 65C02 (64tass)
; Attendre la trame suivante (groupe 5, fonction 37).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr trame
sta t0
_att: jsr trame
cmp t0
beq _att
sec
sbc t0
pha
lda #<m
ldx #>m
jsr ecrire
pla
jsr decimal
lda #13
jmp WriteCharacter
; Octet bas du compteur de trames (5,37) dans A.
trame: jsr WaitMessage
lda #5
ldx #37 ; fonction 37 : Frame Count
jsr appel
lda ControlPort+4
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
t0: .byte 0
m: .text "Trame suivante : ecart ", 0Trame suivante : ecart 15,38 Get Palette Officiel
Lit les composantes rouge, verte et bleue d'un numéro de la palette.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro de couleur |
| Octets | Type | Rôle |
|---|---|---|
P1 | uint8 | rouge |
P2 | uint8 | vert |
P3 | uint8 | bleu |
L'exemple lit les couleurs 0 à 2 de la palette d'origine. llvm-mos n'a pas de fonction pour cet appel : l'exemple C le fait directement.
Texte de la documentation du firmware (anglais)
Get the palette colour at the index spcified in Parameter:0. Values are returned in Parameter:1,Parameter:2,Parameter:3 (RGB).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
/* Lire les trois premières couleurs de la palette (groupe 5, fonction 38). */
int main(void) {
for (uint8_t c = 0; c < 3; c++) {
libre();
ControlPort.params[0] = c;
api(5, 38); /* Get Palette */
printf("Couleur %u : %u %u %u\n", c, ControlPort.params[1], ControlPort.params[2], ControlPort.params[3]);
}
return 0;
}Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54Mad Pascal
// Lire les trois premières couleurs de la palette (groupe 5, fonction 38).
program litpalette;
uses crt, neo6502;
var c, r, g, b: byte;
begin
for c := 0 to 2 do
begin
NeoGetPalette(c, r, g, b); // Get Palette
writeln('Couleur ', c, ' : ', r, ' ', g, ' ', b);
end;
end.Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54NeoBASIC
10 ' Lire les trois premieres couleurs de la palette (groupe 5, fonction 38)
20 for c = 0 to 2
30 while peek($ff00) : wend : poke $ff04, c : poke $ff01, 38 : poke $ff00, 5
40 while peek($ff00) : wend : r = peek($ff05) : g = peek($ff06) : b = peek($ff07)
50 print "Couleur ";c;" : ";r;" ";g;" ";b
60 next cCouleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 54Assembleur 65C02 (64tass)
; Lire les trois premières couleurs de la palette (groupe 5, fonction 38).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: stz c
_suiv: jsr WaitMessage
lda c
sta ControlPort+4 ; P0 : couleur
lda #5
ldx #38 ; fonction 38 : Get Palette
jsr appel
lda #<t0
ldx #>t0
jsr ecrire
lda c
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
ldy #5
_rvb: lda ControlPort,y ; P1, P2, P3 ($FF05-$FF07)
jsr decimal
cpy #7
beq _fin
lda #' '
jsr WriteCharacter
iny
bra _rvb
_fin: lda #13
jsr WriteCharacter
inc c
lda c
cmp #3
bne _suiv
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
c: .byte 0
t0: .text "Couleur ", 0
t1: .text " : ", 0Couleur 0 : 0 0 0
Couleur 1 : 255 0 0
Couleur 2 : 0 228 545,39 Write Pixel Officiel
Écrit une couleur telle quelle dans un pixel, sans masque ni OU EXCLUSIF.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X du point |
P2-P3 | int16 | Y du point |
P4 | uint8 | couleur |
Sorties : aucune.
Contrairement à 5,5, le résultat ne dépend pas des réglages de 5,1 : l'exemple règle un OU EXCLUSIF (masque $FF, couleur 3) qui changerait un tracé 5,5, puis écrit 9 et relit 9.
Texte de la documentation du firmware (anglais)
Write Pixel index Parameter:4 to the screen coordinate specified in Parameters:0,1,Parameters:2,3 (X,Y).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Écrire une couleur telle quelle (groupe 5, fonction 39). */
int main(void) {
neo_graphics_set_defaults(0xFF, 3, 0, 1, 0); /* 5,1 : OU EXCLUSIF, sans effet ici */
neo_graphics_write_pixel(210, 170, 9); /* Write Pixel */
printf("Pixel ecrit : %u\n", neo_graphics_read_pixel(210, 170));
return 0;
}Pixel ecrit : 9Mad Pascal
// Écrire une couleur telle quelle (groupe 5, fonction 39).
program ecrit;
uses crt, neo6502;
var a: byte;
begin
NeoSetDefaults($FF, 3, 0, 1, 0); // 5,1 : OU EXCLUSIF, sans effet ici
NeoWritePixel(210, 170, 9); // Write Pixel
a := NeoGetPixel(210, 170);
writeln('Pixel ecrit : ', a);
end.Pixel ecrit : 9NeoBASIC
10 ' Ecrire une couleur telle quelle (groupe 5, fonction 39)
20 while peek($ff00) : wend
30 poke $ff04, 210 : poke $ff05, 0 : poke $ff06, 170 : poke $ff07, 0 : poke $ff08, 9 : poke $ff01, 39 : poke $ff00, 5
40 while peek($ff00) : wend
50 print "Pixel ecrit : ";point(210,170)Pixel ecrit : 9Assembleur 65C02 (64tass)
; Écrire une couleur telle quelle (groupe 5, fonction 39).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #$FF
sta ControlPort+4 ; 5,1 : masque $FF, couleur 3 (sans effet ici)
lda #3
sta ControlPort+5
stz ControlPort+6
lda #1
sta ControlPort+7
stz ControlPort+8
ldx #1
jsr g5
lda #210
ldy #170
jsr point1
lda #9
sta ControlPort+8 ; P4 : couleur 9
ldx #39 ; fonction 39 : Write Pixel
jsr g5
lda #210
ldy #170
jsr lire
sta a
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
t0: .text "Pixel ecrit : ", 0Pixel ecrit : 95,40 Get Late Scanlines Trinity
Donne le nombre de lignes de balayage que le second cœur n'a pas pu produire à temps depuis le dernier changement de mode (diagnostic).
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0-P3 | uint32 | nombre de lignes en retard |
Propre à Trinity (T-32c). Sur la carte, ces lignes apparaissent comme des traînées colorées ; un compteur qui grandit pendant un programme indique un second cœur débordé. Les émulateurs rendent toujours 0 (valeur vérifiée par le banc).
Texte de la documentation du firmware (anglais)
Returns in Parameters:0-3 the number of scanlines the display could not encode in time since the last mode change (Trinity T-32c, Function 5,40, diagnostic : these show as coloured streaks on the board ; 0 in the emulators). A counter that keeps growing while a program runs means the second core is starved.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
/* Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity). */
int main(void) {
libre();
api(5, 40);
printf("Lignes en retard : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
| ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
return 0;
}Lignes en retard : 0Mad Pascal
// Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity).
program diag40;
uses crt, neo6502;
var valeur: cardinal;
begin
NeoWaitMessage;
NeoSendMessage(5, 40);
NeoWaitMessage;
valeur := dwordParams[0];
writeln('Lignes en retard : ', valeur);
end.Lignes en retard : 0NeoBASIC
10 ' Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity)
20 while peek($ff00) : wend : poke $ff01, 40 : poke $ff00, 5
22 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
24 print "Lignes en retard : ";vLignes en retard : 0Assembleur 65C02 (64tass)
; Lignes que l'affichage n'a pas pu produire à temps (groupe 5, fonction 40, Trinity).
; L'exemple asm n'affiche que l'octet bas de chaque compteur.
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start:
jsr WaitMessage
lda #5
ldx #40 ; fonction 40
jsr appel
lda ControlPort+4 ; octet bas
sta v
lda #<t0
ldx #>t0
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
v: .byte 0
t0: .text "Lignes en retard : ", 0Lignes en retard : 05,41 Get Bus Stalls Trinity
Donne l'un des compteurs d'incidents du bus du 6502 relevés par les PIO du RP2040 (diagnostic).
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | compteur : 0 TXSTALL (donnée d'une lecture pas prête à temps), 1 RXSTALL (file des adresses pas vidée à temps), 2 RXUNDER (file vide lue) |
| Octets | Type | Rôle |
|---|---|---|
P0-P3 | uint32 | valeur du compteur |
Propre à Trinity (T-49, T-52). Les émulateurs n'ont pas de PIO et rendent 0 (valeur vérifiée par le banc). La documentation du firmware détaille la signification de chaque compteur.
Texte de la documentation du firmware (anglais)
Returns in Parameters:0-3 one of the PIO fault counters of the 6502 bus, chosen by Parameter:0 on entry (Trinity T-49/T-52, diagnostic ; 0 in the emulators, which have no PIO) : 0 TXSTALL : the data of a read was not ready in time. 1 RXSTALL : the address FIFO was not drained in time. 2 RXUNDER : an EMPTY FIFO was read — the firmware then acts on a stale word and writes a phantom byte at a phantom address into the 6502 memory. This one corrupts the running program. 3 TXOVER : a read reply was pushed into a full FIFO and lost. The state machine generates the 6502 clock, so TXSTALL and RXSTALL merely stretch the processor and are normal while an API command is served ; RXUNDER and TXOVER are not, and any growth there is a fault. Sampled about 95 times a second, so these are windows containing at least one event, not exact counts. Pass $FF in Parameter:0 to reset all four (it then returns TXSTALL).
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
/* Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity). */
int main(void) {
libre();
ControlPort.params[0] = 0;
api(5, 41);
printf("TXSTALL : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
| ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
libre();
ControlPort.params[0] = 1;
api(5, 41);
printf("RXSTALL : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
| ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
libre();
ControlPort.params[0] = 2;
api(5, 41);
printf("RXUNDER : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
| ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
return 0;
}TXSTALL : 0
RXSTALL : 0
RXUNDER : 0Mad Pascal
// Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity).
program diag41;
uses crt, neo6502;
var valeur: cardinal;
begin
NeoWaitMessage;
NeoMessage.params[0] := 0;
NeoSendMessage(5, 41);
NeoWaitMessage;
valeur := dwordParams[0];
writeln('TXSTALL : ', valeur);
NeoWaitMessage;
NeoMessage.params[0] := 1;
NeoSendMessage(5, 41);
NeoWaitMessage;
valeur := dwordParams[0];
writeln('RXSTALL : ', valeur);
NeoWaitMessage;
NeoMessage.params[0] := 2;
NeoSendMessage(5, 41);
NeoWaitMessage;
valeur := dwordParams[0];
writeln('RXUNDER : ', valeur);
end.TXSTALL : 0
RXSTALL : 0
RXUNDER : 0NeoBASIC
10 ' Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity)
20 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 41 : poke $ff00, 5
22 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
24 print "TXSTALL : ";v
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 41 : poke $ff00, 5
32 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
34 print "RXSTALL : ";v
40 while peek($ff00) : wend : poke $ff04, 2 : poke $ff01, 41 : poke $ff00, 5
42 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
44 print "RXUNDER : ";vTXSTALL : 0
RXSTALL : 0
RXUNDER : 0Assembleur 65C02 (64tass)
; Compteurs d'incidents du bus du 6502 (groupe 5, fonction 41, Trinity).
; L'exemple asm n'affiche que l'octet bas de chaque compteur.
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start:
jsr WaitMessage
lda #0
sta ControlPort+4 ; P0 : compteur choisi
lda #5
ldx #41 ; fonction 41
jsr appel
lda ControlPort+4 ; octet bas
sta v
lda #<t0
ldx #>t0
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
jsr WaitMessage
lda #1
sta ControlPort+4 ; P0 : compteur choisi
lda #5
ldx #41 ; fonction 41
jsr appel
lda ControlPort+4 ; octet bas
sta v
lda #<t1
ldx #>t1
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
jsr WaitMessage
lda #2
sta ControlPort+4 ; P0 : compteur choisi
lda #5
ldx #41 ; fonction 41
jsr appel
lda ControlPort+4 ; octet bas
sta v
lda #<t2
ldx #>t2
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
v: .byte 0
t0: .text "TXSTALL : ", 0
t1: .text "RXSTALL : ", 0
t2: .text "RXUNDER : ", 0TXSTALL : 0
RXSTALL : 0
RXUNDER : 05,42 Get Bus Timing Trinity
Donne une mesure de temps (diagnostic, T-50 et T-90) : la plus longue synchronisation, la plus longue commande de l'API, ou une mesure de l'affichage.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 0 : plus long DSPSync (clavier, USB, clignotement) ; 1 : plus longue commande de l'API ; côté affichage (cœur 1) : 2 plus long traitement d'une ligne, 3 plus long écart entre deux rappels de ligne (nominal : 32 en mode 1, 63 en modes 0 et 2, où chaque ligne est doublée et le rappel n'a lieu qu'une ligne sur deux), 4 nombre de rappels en retard de plus de deux fois cet écart nominal |
| Octets | Type | Rôle |
|---|---|---|
P0-P3 | uint32 | durée en microsecondes (0 à 3) ou nombre de lignes (4) |
Propre à Trinity (T-50). Pendant ces durées, le firmware n'est pas sur le bus du 6502 et l'horloge du processeur est arrêtée : normal pour un appel de l'API, anormal si cela dure. L'émulateur du banc rend 0 ; ses valeurs ne mesurent pas la carte.
Texte de la documentation du firmware (anglais)
Returns in Parameters:0-3 a bus timing measure of Trinity T-50, chosen by Parameter:0 on entry : 0 the longest DSPSync ever seen in microseconds (keyboard, USB task, blink), 1 the longest API command (DSPHandler) ; Trinity T-90 adds the display side, core 1 : 2 the longest scanline callback (conversion of one line into the scan buffer), 3 the longest gap between two scanline callbacks (nominal : 32 in mode 1, whose lines are native, but 63 in modes 0 and 2, whose lines are doubled : the callback runs every other line), 4 the number of callbacks late by more than twice that nominal gap. 0 and 1 are the time the firmware spends away from the 6502 bus : while it is there the PIO stalls and the processor clock stops, which is normal for an API call and pathological when it lasts. Counts of stalls alone (Function 5,41) cannot tell the two apart, hence these. Reset with 5,41 and $FF. 0 in the emulators.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static void xy(uint8_t i, uint16_t x, uint16_t y) { /* point (x, y) en Pi..Pi+3 */
ControlPort.params[i] = x & 0xFF;
ControlPort.params[i + 1] = x >> 8;
ControlPort.params[i + 2] = y & 0xFF;
ControlPort.params[i + 3] = y >> 8;
}
/* Durées pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity). */
int main(void) {
libre();
ControlPort.params[0] = 0;
api(5, 42);
printf("DSPSync le plus long : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
| ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
libre();
ControlPort.params[0] = 1;
api(5, 42);
printf("Commande la plus longue : %lu\n", (unsigned long)(ControlPort.params[0] | ((uint32_t)ControlPort.params[1] << 8)
| ((uint32_t)ControlPort.params[2] << 16) | ((uint32_t)ControlPort.params[3] << 24)));
return 0;
}DSPSync le plus long : 0
Commande la plus longue : 0Mad Pascal
// Durées pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity).
program diag42;
uses crt, neo6502;
var valeur: cardinal;
begin
NeoWaitMessage;
NeoMessage.params[0] := 0;
NeoSendMessage(5, 42);
NeoWaitMessage;
valeur := dwordParams[0];
writeln('DSPSync le plus long : ', valeur);
NeoWaitMessage;
NeoMessage.params[0] := 1;
NeoSendMessage(5, 42);
NeoWaitMessage;
valeur := dwordParams[0];
writeln('Commande la plus longue : ', valeur);
end.DSPSync le plus long : 0
Commande la plus longue : 0NeoBASIC
10 ' Durees pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity)
20 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 42 : poke $ff00, 5
22 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
24 print "DSPSync le plus long : ";v
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 42 : poke $ff00, 5
32 while peek($ff00) : wend : v0 = peek($ff04) : v1 = peek($ff05) : v2 = peek($ff06) : v = v0 + 256 * v1 + 65536 * v2
34 print "Commande la plus longue : ";vDSPSync le plus long : 0
Commande la plus longue : 0Assembleur 65C02 (64tass)
; Durées pendant lesquelles le firmware quitte le bus (groupe 5, fonction 42, Trinity).
; L'exemple asm n'affiche que l'octet bas de chaque compteur.
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start:
jsr WaitMessage
lda #0
sta ControlPort+4 ; P0 : compteur choisi
lda #5
ldx #42 ; fonction 42
jsr appel
lda ControlPort+4 ; octet bas
sta v
lda #<t0
ldx #>t0
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
jsr WaitMessage
lda #1
sta ControlPort+4 ; P0 : compteur choisi
lda #5
ldx #42 ; fonction 42
jsr appel
lda ControlPort+4 ; octet bas
sta v
lda #<t1
ldx #>t1
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
rts
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
v: .byte 0
t0: .text "DSPSync le plus long : ", 0
t1: .text "Commande la plus longue : ", 0DSPSync le plus long : 0
Commande la plus longue : 05,64 Set Color Officiel
Choisit la couleur des tracés suivants (masque à 0).
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | couleur |
Sorties : aucune.
Revient à 5,1 avec un masque de 0 et la couleur donnée, sans toucher aux autres réglages. NeoBASIC ne fait pas cet appel (ink c fait 5,1) : l'exemple BASIC l'écrit avec poke.
Texte de la documentation du firmware (anglais)
Set Color Sets the current drawing colour to Parameter:0
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Choisir la couleur de tracé (groupe 5, fonction 64). */
int main(void) {
neo_graphics_set_color(6); /* 5,64 : Set Color */
neo_graphics_draw_pixel(210, 170); /* 5,5 */
uint8_t a = neo_graphics_read_pixel(210, 170); /* 5,33 */
uint8_t b = neo_graphics_read_pixel(211, 170);
printf("Pixel (210, 170) : %u, voisin : %u\n", a, b);
return 0;
}Pixel (210, 170) : 6, voisin : 0Mad Pascal
// Choisir la couleur de tracé (groupe 5, fonction 64).
program pixel64;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(6); // 5,64 : Set Color
NeoDrawPixel(210, 170); // 5,5
a := NeoGetPixel(210, 170); // 5,33
b := NeoGetPixel(211, 170);
writeln('Pixel (210, 170) : ', a, ', voisin : ', b);
end.Pixel (210, 170) : 6, voisin : 0NeoBASIC
10 ' Choisir la couleur de trace (groupe 5, fonction 64)
20 while peek($ff00) : wend : poke $ff04, 6 : poke $ff01, 64 : poke $ff00, 5 : ' Set Color
25 plot to 210,170
30 a = point(210,170) : b = point(211,170)
40 print "Pixel (210, 170) : ";a;", voisin : ";bPixel (210, 170) : 6, voisin : 0Assembleur 65C02 (64tass)
; Choisir la couleur de tracé (groupe 5, fonction 64).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #6
sta ControlPort+4 ; P0 : couleur 6
ldx #64 ; 5,64 : Set Color
jsr g5
lda #210
ldy #170
jsr point1
ldx #5 ; 5,5 : Draw Pixel
jsr g5
lda #210
ldy #170
jsr lire ; 5,33 : Read Pixel
sta a
lda #211
ldy #170
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Pixel (210, 170) : ", 0
t2: .text ", voisin : ", 0Pixel (210, 170) : 6, voisin : 05,65 Set Solid Flag Officiel
Règle le drapeau de remplissage : formes pleines, et fond plein pour le texte et les images.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 0 : contour (fond transparent) ; non nul : plein |
Sorties : aucune.
En NeoBASIC, frame et solid font 5,1 avec ce drapeau.
Texte de la documentation du firmware (anglais)
Set Solid Flag
Sets the solid flag to Parameter:0, which indicates either solid fill (for shapes) or solid background (for images and fonts)
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Le même rectangle en contour puis plein (groupe 5, fonction 65). */
int main(void) {
neo_graphics_set_color(4);
neo_graphics_set_solid_flag(0); /* Set Solid Flag : contour */
neo_graphics_draw_rectangle(150, 160, 190, 200);
uint8_t a = neo_graphics_read_pixel(170, 180); /* centre */
neo_graphics_set_solid_flag(1); /* plein */
neo_graphics_draw_rectangle(150, 160, 190, 200);
uint8_t b = neo_graphics_read_pixel(170, 180);
printf("Contour : %u, plein : %u\n", a, b);
return 0;
}Contour : 0, plein : 4Mad Pascal
// Le même rectangle en contour puis plein (groupe 5, fonction 65).
program remplir;
uses crt, neo6502;
var a, b: byte;
begin
NeoSetColor(4);
NeoSetSolidFlag(0); // Set Solid Flag : contour
NeoDrawRect(150, 160, 190, 200);
a := NeoGetPixel(170, 180); // centre
NeoSetSolidFlag(1); // plein
NeoDrawRect(150, 160, 190, 200);
b := NeoGetPixel(170, 180);
writeln('Contour : ', a, ', plein : ', b);
end.Contour : 0, plein : 4NeoBASIC
10 ' Le meme rectangle en contour puis plein (groupe 5, fonction 65)
20 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 65 : poke $ff00, 5 : ' contour
30 rect 150,160 ink 4 to 190,200 : a = point(170,180)
40 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 65 : poke $ff00, 5 : ' plein
50 rect 150,160 to 190,200 : b = point(170,180)
60 print "Contour : ";a;", plein : ";bContour : 0, plein : 4Assembleur 65C02 (64tass)
; Le même rectangle en contour puis plein (groupe 5, fonction 65).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
lda #4
sta ControlPort+4
ldx #64 ; 5,64 : couleur 4
jsr g5
lda #0
jsr rect ; contour
sta a
lda #1
jsr rect ; plein
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Drapeau A (5,65), rectangle (150, 160)-(190, 200), couleur du centre dans A.
rect: sta ControlPort+4
ldx #65 ; fonction 65 : Set Solid Flag
jsr g5
lda #150
ldy #160
jsr point1
lda #190
ldy #200
jsr point2
ldx #3 ; 5,3 : rectangle
jsr g5
lda #170
ldy #180
jmp lire
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
a: .byte 0
b: .byte 0
t0: .text "Contour : ", 0
t2: .text ", plein : ", 0Contour : 0, plein : 45,66 Set Draw Size Officiel
Choisit la taille (facteur d'agrandissement) des images et du texte.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | taille : 1 normale, 2 double… |
Sorties : aucune.
Le point lu est à 20 pixels à droite du coin : hors de l'image en taille 1 (16 pixels de large), dans sa moitié droite en taille 2 (32 pixels). La taille 2 sert aussi aux cartes de tuiles 32×32 (5,8). En NeoBASIC, dim n fait 5,1 avec cette taille.
Texte de la documentation du firmware (anglais)
Set Draw Size
Sets the drawing scale for images and fonts to Parameter:0
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
static uint8_t gfx[256 + 128]; /* en-tête + une image 16x16, 4 bits par pixel */
static void images(uint8_t genre) { /* 1 : une tuile ; 2 : un sprite 16x16 */
gfx[0] = 1;
gfx[genre] = 1;
for (uint8_t y = 0; y < 16; y++)
for (uint8_t i = 0; i < 8; i++)
gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55; /* gauche : couleur 2, droite : 5 */
neo_file_store("img.gfx", gfx, sizeof gfx);
neo_file_load("img.gfx", (void *)0xFFFF); /* $FFFF : mémoire graphique */
}
/* Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66). */
int main(void) {
images(1);
neo_graphics_set_draw_size(1); /* 5,66 : Set Draw Size */
neo_graphics_set_flip_bits(0); /* 5,67 */
neo_graphics_draw_image(150, 160, 0); /* 5,7, image 0 */
uint8_t a = neo_graphics_read_pixel(170, 165);
neo_graphics_set_draw_size(2); /* 5,66 : Set Draw Size */
neo_graphics_set_flip_bits(0); /* 5,67 */
neo_graphics_draw_image(200, 160, 0); /* 5,7, image 0 */
uint8_t b = neo_graphics_read_pixel(220, 165);
printf("Taille 1 : %u, taille 2 : %u\n", a, b);
return 0;
}Taille 1 : 0, taille 2 : 5Mad Pascal
// Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66).
program image66;
uses crt, neo6502;
var a, b: byte;
gfx: array[0..383] of byte; // en-tête + une image 16x16
procedure images(genre: byte); // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
fillchar(@gfx, 384, 0);
gfx[0] := 1;
gfx[genre] := 1;
for y := 0 to 15 do
for i := 0 to 7 do
if i < 4 then gfx[256 + y * 8 + i] := $22 // gauche : couleur 2
else gfx[256 + y * 8 + i] := $55; // droite : couleur 5
NeoSave('img.gfx', word(@gfx), 384);
NeoLoad('img.gfx', $FFFF); // $FFFF : mémoire graphique
end;
begin
images(1);
NeoSetDrawSize(1); // 5,66 : Set Draw Size
NeoSetFlip(0); // 5,67
NeoDrawImage(150, 160, 0); // 5,7, image 0
a := NeoGetPixel(170, 165);
NeoSetDrawSize(2); // 5,66 : Set Draw Size
NeoSetFlip(0); // 5,67
NeoDrawImage(200, 160, 0); // 5,7, image 0
b := NeoGetPixel(220, 165);
writeln('Taille 1 : ', a, ', ', 'taille 2 : ', b);
end.Taille 1 : 0, taille 2 : 5NeoBASIC
10 ' Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 66 : poke $ff00, 5 : ' taille
31 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
32 while peek($ff00) : wend : poke $ff04, 150 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
33 while peek($ff00) : wend : a = point(170,165)
40 while peek($ff00) : wend : poke $ff04, 2 : poke $ff01, 66 : poke $ff00, 5 : ' taille
41 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
42 while peek($ff00) : wend : poke $ff04, 200 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
43 while peek($ff00) : wend : b = point(220,165)
50 print "Taille 1 : ";a; ", ";"taille 2 : ";bTaille 1 : 0, taille 2 : 5Assembleur 65C02 (64tass)
; Dessiner une image en taille 1 puis 2 (groupe 5, fonction 66).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
jsr images
lda #1
sta ControlPort+4
ldx #66 ; 5,66 : taille 1
jsr g5
lda #0
sta ControlPort+4
ldx #67 ; 5,67 : retournement 0
jsr g5
lda #150
ldy #160
jsr point1
stz ControlPort+8 ; P4 : image 0
ldx #7 ; 5,7 : Draw Image
jsr g5
lda #170
ldy #165
jsr lire
sta a
lda #2
sta ControlPort+4
ldx #66 ; 5,66 : taille 2
jsr g5
lda #0
sta ControlPort+4
ldx #67 ; 5,67 : retournement 0
jsr g5
lda #200
ldy #160
jsr point1
stz ControlPort+8 ; P4 : image 0
ldx #7 ; 5,7 : Draw Image
jsr g5
lda #220
ldy #165
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda #<t3
ldx #>t3
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #<gfx
sta ControlPort+6
lda #>gfx
sta ControlPort+7
lda #<384
sta ControlPort+8
lda #>384
sta ControlPort+9
lda #3
ldx #3 ; 3,3 : Save File
jsr appel
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #$FF
sta ControlPort+6 ; $FFFF : mémoire graphique
sta ControlPort+7
lda #3
ldx #2 ; 3,2 : Load File
jmp appel
nomgfx: .byte 7
.text "img.gfx"
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
gfx: .byte 1, 1, 0, 0 ; en-tête : une tuile
.fill 252
.rept 16 ; 16 lignes : gauche couleur 2, droite couleur 5
.byte $22, $22, $22, $22, $55, $55, $55, $55
.endrept
a: .byte 0
b: .byte 0
t0: .text "Taille 1 : ", 0
t2: .text ", ", 0
t3: .text "taille 2 : ", 0Taille 1 : 0, taille 2 : 55,67 Set Flip Bits Officiel
Règle le retournement des images : bit 0 horizontal, bit 1 vertical.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | bit 0 : miroir horizontal ; bit 1 : miroir vertical |
Sorties : aucune.
L'image a sa moitié gauche en couleur 2 : retournée horizontalement, elle y montre la couleur 5. En NeoBASIC, image n, retournement to x,y fait 5,1 avec ce réglage.
Texte de la documentation du firmware (anglais)
Set Flip Bits Sets the flip bits for drawing images. Bit 0 set causes a horizontal flip, bit 1 set causes a vertical flip.
C (llvm-mos)
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
static uint8_t gfx[256 + 128]; /* en-tête + une image 16x16, 4 bits par pixel */
static void images(uint8_t genre) { /* 1 : une tuile ; 2 : un sprite 16x16 */
gfx[0] = 1;
gfx[genre] = 1;
for (uint8_t y = 0; y < 16; y++)
for (uint8_t i = 0; i < 8; i++)
gfx[256 + y * 8 + i] = i < 4 ? 0x22 : 0x55; /* gauche : couleur 2, droite : 5 */
neo_file_store("img.gfx", gfx, sizeof gfx);
neo_file_load("img.gfx", (void *)0xFFFF); /* $FFFF : mémoire graphique */
}
/* Dessiner une image retournée (groupe 5, fonction 67). */
int main(void) {
images(1);
neo_graphics_set_draw_size(1); /* 5,66 */
neo_graphics_set_flip_bits(0); /* 5,67 : Set Flip Bits */
neo_graphics_draw_image(150, 160, 0); /* 5,7, image 0 */
uint8_t a = neo_graphics_read_pixel(152, 165);
neo_graphics_set_draw_size(1); /* 5,66 */
neo_graphics_set_flip_bits(1); /* 5,67 : Set Flip Bits */
neo_graphics_draw_image(200, 160, 0); /* 5,7, image 0 */
uint8_t b = neo_graphics_read_pixel(202, 165);
printf("Normale : %u, retournee : %u\n", a, b);
return 0;
}Normale : 2, retournee : 5Mad Pascal
// Dessiner une image retournée (groupe 5, fonction 67).
program image67;
uses crt, neo6502;
var a, b: byte;
gfx: array[0..383] of byte; // en-tête + une image 16x16
procedure images(genre: byte); // 1 : une tuile ; 2 : un sprite 16x16
var y, i: byte;
begin
fillchar(@gfx, 384, 0);
gfx[0] := 1;
gfx[genre] := 1;
for y := 0 to 15 do
for i := 0 to 7 do
if i < 4 then gfx[256 + y * 8 + i] := $22 // gauche : couleur 2
else gfx[256 + y * 8 + i] := $55; // droite : couleur 5
NeoSave('img.gfx', word(@gfx), 384);
NeoLoad('img.gfx', $FFFF); // $FFFF : mémoire graphique
end;
begin
images(1);
NeoSetDrawSize(1); // 5,66
NeoSetFlip(0); // 5,67 : Set Flip Bits
NeoDrawImage(150, 160, 0); // 5,7, image 0
a := NeoGetPixel(152, 165);
NeoSetDrawSize(1); // 5,66
NeoSetFlip(1); // 5,67 : Set Flip Bits
NeoDrawImage(200, 160, 0); // 5,7, image 0
b := NeoGetPixel(202, 165);
writeln('Normale : ', a, ', ', 'retournee : ', b);
end.Normale : 2, retournee : 5NeoBASIC
10 ' Dessiner une image retournee (groupe 5, fonction 67)
20 d = alloc(384) : for i = 0 to 383 : poke d + i, 0 : next i : poke d, 1 : poke d + 1, 1 : ' en-tete
22 for y = 0 to 15 : for i = 0 to 7 : c = $22 : if i > 3 then c = $55
24 poke d + 256 + y * 8 + i, c : next i : next y : ' gauche : couleur 2, droite : 5
26 save "img.gfx", d, 384 : load "img.gfx", $ffff : ' $ffff : memoire graphique
30 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 66 : poke $ff00, 5 : ' taille
31 while peek($ff00) : wend : poke $ff04, 0 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
32 while peek($ff00) : wend : poke $ff04, 150 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
33 while peek($ff00) : wend : a = point(152,165)
40 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 66 : poke $ff00, 5 : ' taille
41 while peek($ff00) : wend : poke $ff04, 1 : poke $ff01, 67 : poke $ff00, 5 : ' retournement
42 while peek($ff00) : wend : poke $ff04, 200 : poke $ff05, 0 : poke $ff06, 160 : poke $ff07, 0 : poke $ff08, 0 : poke $ff01, 7 : poke $ff00, 5
43 while peek($ff00) : wend : b = point(202,165)
50 print "Normale : ";a; ", ";"retournee : ";bNormale : 2, retournee : 5Assembleur 65C02 (64tass)
; Dessiner une image retournée (groupe 5, fonction 67).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: jsr WaitMessage
jsr images
lda #1
sta ControlPort+4
ldx #66 ; 5,66 : taille 1
jsr g5
lda #0
sta ControlPort+4
ldx #67 ; 5,67 : retournement 0
jsr g5
lda #150
ldy #160
jsr point1
stz ControlPort+8 ; P4 : image 0
ldx #7 ; 5,7 : Draw Image
jsr g5
lda #152
ldy #165
jsr lire
sta a
lda #1
sta ControlPort+4
ldx #66 ; 5,66 : taille 1
jsr g5
lda #1
sta ControlPort+4
ldx #67 ; 5,67 : retournement 1
jsr g5
lda #200
ldy #160
jsr point1
stz ControlPort+8 ; P4 : image 0
ldx #7 ; 5,7 : Draw Image
jsr g5
lda #202
ldy #165
jsr lire
sta b
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t2
ldx #>t2
jsr ecrire
lda #<t3
ldx #>t3
jsr ecrire
lda b
jsr decimal
lda #13
jmp WriteCharacter
; Point (A, Y) en P0-P3, point2 en P4-P7 (coordonnées inférieures à 256).
point1: sta ControlPort+4
stz ControlPort+5
sty ControlPort+6
stz ControlPort+7
rts
point2: sta ControlPort+8
stz ControlPort+9
sty ControlPort+10
stz ControlPort+11
rts
; Couleur du pixel (A, Y), lue par 5,33, rendue dans A.
lire: pha
jsr WaitMessage
pla
jsr point1
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Appel du groupe 5, fonction X.
g5: lda #5
jmp appel
; Enregistre gfx dans img.gfx (3,3), puis le charge en mémoire graphique (3,2 vers $FFFF).
images: jsr WaitMessage
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #<gfx
sta ControlPort+6
lda #>gfx
sta ControlPort+7
lda #<384
sta ControlPort+8
lda #>384
sta ControlPort+9
lda #3
ldx #3 ; 3,3 : Save File
jsr appel
lda #<nomgfx
sta ControlPort+4
lda #>nomgfx
sta ControlPort+5
lda #$FF
sta ControlPort+6 ; $FFFF : mémoire graphique
sta ControlPort+7
lda #3
ldx #2 ; 3,2 : Load File
jmp appel
nomgfx: .byte 7
.text "img.gfx"
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
diviseur: .byte 0
gfx: .byte 1, 1, 0, 0 ; en-tête : une tuile
.fill 252
.rept 16 ; 16 lignes : gauche couleur 2, droite couleur 5
.byte $22, $22, $22, $22, $55, $55, $55, $55
.endrept
a: .byte 0
b: .byte 0
t0: .text "Normale : ", 0
t2: .text ", ", 0
t3: .text "retournee : ", 0Normale : 2, retournee : 5