Groupe 32 — QuickDraw Trinity
32,1 Init Graf · 32,2 Set Clip · 32,3 Get Clip · 32,4 Set Pen Colour · 32,5 Move To · 32,6 Get Pen · 32,7 Frame Rect · 32,8 Paint Rect · 32,9 Erase Rect · 32,10 Invert Rect · 32,11 Line To · 32,12 Set Pattern · 32,13 Fill Rect · 32,14 Copy Bits · 32,15 Set Font · 32,16 Draw String · 32,17 Text Width · 32,18 Get Font Info · 32,19 Toolbox Reset
QuickDraw est la couche de dessin de la boîte à outils de Trinity (groupes 32 à 38). Il dessine dans la page de dessin, sous les sprites, et toujours à l'intérieur d'un rectangle de découpe.
Les structures sont en RAM du 6502 et passées par adresse. Un Rect fait 8 octets : gauche, haut, droite, bas, en 16 bits signés ; la droite et le bas sont exclus (100, 100, 104, 102 couvre x 100 à 103 et y 100 à 101).
La plume a une position et une couleur ; 32,1 la remet en (0, 0), couleur 15, avec la découpe sur tout l'écran et un motif plein. Les exemples effacent l'écran, dessinent, puis relisent les pixels avec 5,33.
32,1 Init Graf Trinity
Remet QuickDraw dans son état de départ : découpe sur tout l'écran, plume en (0, 0), couleur 15, motif plein.
Entrées : aucune.
Sorties : aucune.
Rien n'est dessiné ni effacé. Un programme peut l'appeler à tout moment pour repartir d'un état connu ; les exemples du groupe l'appellent au début et à la fin. L'exemple déplace d'abord la plume et change sa couleur, puis relit l'état avec 32,6 et 32,3. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Toolbox (Trinity, T-12, ADR-01 of the fork). Resets the drawing port : the clip rectangle is the whole screen, the pen is at (0,0) with colour 15. Structures of this group live in 6502 RAM and are passed by address : a Rect is left, top, right, bottom as signed 16 bit values, right and bottom exclusive. Drawing is always clipped to the clip rectangle and goes to the draw page, ignoring the sprite layer.
C (llvm-mos)
/* Remettre QuickDraw dans son état de départ (groupe 32, fonction 1, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static int16_t plume_x, plume_y;
static uint8_t plume_c;
static void get_pen(void) { /* 32,6 Get Pen */
libre();
qd(6);
plume_x = ControlPort.params[0] | ControlPort.params[1] << 8;
plume_y = ControlPort.params[2] | ControlPort.params[3] << 8;
plume_c = ControlPort.params[4];
}
static Rect clip;
static void get_clip(void) { /* 32,3 Get Clip : écrit le rectangle de découpe dans clip */
qd_rect(3, &clip);
}
int main(void) {
couleur(5); /* un état quelconque : plume en (10, 20), couleur 5 */
qd_xy(5, 10, 20);
init_graf(); /* Init Graf */
get_pen();
get_clip();
printf("Plume : %d, %d, couleur %u\n", plume_x, plume_y, plume_c);
printf("Decoupe : %d, %d, %d, %d\n", clip.g, clip.h, clip.d, clip.b);
return 0;
}Plume : 0, 0, couleur 15
Decoupe : 0, 0, 320, 240Mad Pascal
// Remettre QuickDraw dans son état de départ (groupe 32, fonction 1, Trinity).
program qd1;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var plume_x, plume_y: smallint;
plume_c: byte;
procedure get_pen; // 32,6 Get Pen
begin
NeoWaitMessage;
qd(6);
plume_x := smallint(wordParams[0]);
plume_y := smallint(wordParams[1]);
plume_c := NeoMessage.params[4];
end;
var clip: Rect;
procedure get_clip; // 32,3 Get Clip : écrit le rectangle de découpe dans clip
begin
qd_rect(3, @clip);
end;
begin
couleur(5); // un état quelconque : plume en (10, 20), couleur 5
qd_xy(5, 10, 20);
init_graf; // Init Graf
get_pen;
get_clip;
writeln('Plume : ', plume_x, ', ', plume_y, ', couleur ', plume_c);
writeln('Decoupe : ', clip.g, ', ', clip.h, ', ', clip.d, ', ', clip.b);
end.Plume : 0, 0, couleur 15
Decoupe : 0, 0, 320, 240NeoBASIC
10 ' Remettre QuickDraw dans son etat de depart (groupe 32, fonction 1, Trinity)
20 k = alloc(8)
30 c = 5 : gosub 9300 : x = 10 : y = 20 : f = 5 : gosub 9200 : ' un etat quelconque : plume en (10, 20), couleur 5
40 gosub 9400 : ' Init Graf
50 gosub 9500 : gosub 9600
60 print "Plume : ";px;", ";py;", couleur ";pc
70 print "Decoupe : ";cg;", ";ch;", ";cd;", ";cb
80 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9500 ' 32,6 Get Pen : px, py, pc
9510 while peek($ff00) : wend : f = 6 : gosub 9110
9520 px = deek($ff04) : py = deek($ff06) : pc = peek($ff08)
9530 if px > 32767 then px = px - 65536
9540 if py > 32767 then py = py - 65536
9550 return
9600 ' 32,3 Get Clip dans le Rect k ; valeurs dans cg, ch, cd, cb
9610 a = k : f = 3 : gosub 9000
9620 cg = deek(k) : ch = deek(k + 2) : cd = deek(k + 4) : cb = deek(k + 6)
9630 returnPlume : 0, 0, couleur 15
Decoupe : 0, 0, 320, 240Assembleur 65C02 (64tass)
; Remettre QuickDraw dans son état de départ (groupe 32, fonction 1, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
; un état quelconque : plume en (10, 20), couleur 5
lda #<b2
ldx #>b2
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
ldx #4
_c3: lda ControlPort+4,x
sta pen,x
dex
bpl _c3
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda pen
ldx pen+1
jsr dec16
lda #<t7
ldx #>t7
jsr ecrire
lda pen+2
ldx pen+2+1
jsr dec16
lda #<t8
ldx #>t8
jsr ecrire
lda pen+4
jsr decimal
lda #13
jsr WriteCharacter
lda #<t9
ldx #>t9
jsr ecrire
lda k
ldx k+1
jsr dec16
lda #<t10
ldx #>t10
jsr ecrire
lda k+2
ldx k+2+1
jsr dec16
lda #<t11
ldx #>t11
jsr ecrire
lda k+4
ldx k+4+1
jsr dec16
lda #<t12
ldx #>t12
jsr ecrire
lda k+6
ldx k+6+1
jsr dec16
lda #13
jsr WriteCharacter
rts
b0: .byte 32, 4, 1, 5 ; 32,4 : Set Pen Colour
b1: .byte 32, 5, 4 ; 32,5 : Move To
.word 10, 20
b2: .byte 32, 1, 0 ; 32,1 : Init Graf
b4: .byte 32, 6, 0 ; 32,6 : Get Pen
pen: .fill 5 ; x, y (16 bits), couleur
b5: .byte 32, 3, 2 ; 32,3 : Get Clip
.word k
k: .fill 8
t6: .text "Plume : ", 0
t7: .text ", ", 0
t8: .text ", couleur ", 0
t9: .text "Decoupe : ", 0
t10: .text ", ", 0
t11: .text ", ", 0
t12: .text ", ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Plume : 0, 0, couleur 15
Decoupe : 0, 0, 320, 24032,2 Set Clip Trinity
Limite tout dessin de QuickDraw au rectangle donné, ramené aux bords de l'écran.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le rectangle est à l'envers (droite avant gauche ou bas avant haut) ou hors de la RAM |
L'exemple pose une zone de 100 à 110, puis peint un rectangle plus grand : seul l'intérieur de la zone est peint (le pixel (95, 95) reste à 0). Un rectangle à l'envers est refusé. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Sets the clip rectangle to the Rect at Parameters:0,1, intersected with the screen. Error if the Rect is inverted or its address is not in RAM.
C (llvm-mos)
/* Limiter le dessin à un rectangle (groupe 32, fonction 2, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static Rect zone = {100, 100, 110, 110}, grand = {90, 90, 120, 120}, envers = {50, 50, 40, 40};
int main(void) {
putchar(12); /* écran effacé : on relit des pixels */
init_graf();
qd_rect(2, &zone); /* Set Clip : rien ne se dessine hors de zone */
couleur(4);
qd_rect(8, &grand); /* 32,8 : peint un rectangle plus grand */
uint8_t dehors = px(95, 95), dedans = px(105, 105);
uint8_t e = qd_rect(2, &envers); /* droite < gauche : refusé */
init_graf(); /* rend tout l'écran au dessin */
printf("Hors de la zone : %u, dedans : %u\n", dehors, dedans);
printf("Rectangle a l'envers : erreur %u\n", e);
return 0;
}Hors de la zone : 0, dedans : 4
Rectangle a l'envers : erreur 1Mad Pascal
// Limiter le dessin à un rectangle (groupe 32, fonction 2, Trinity).
program qd2;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var zone, grand, envers: Rect;
dehors, dedans, e: byte;
begin
write(chr(12)); // écran effacé : on relit des pixels
zone.g := 100; zone.h := 100; zone.d := 110; zone.b := 110;
grand.g := 90; grand.h := 90; grand.d := 120; grand.b := 120;
envers.g := 50; envers.h := 50; envers.d := 40; envers.b := 40;
init_graf;
qd_rect(2, @zone); // Set Clip : rien ne se dessine hors de zone
couleur(4);
qd_rect(8, @grand); // 32,8 : peint un rectangle plus grand
dehors := NeoGetPixel(95, 95);
dedans := NeoGetPixel(105, 105);
e := qd_rect(2, @envers); // droite < gauche : refusé
init_graf; // rend tout l'écran au dessin
writeln('Hors de la zone : ', dehors, ', dedans : ', dedans);
writeln('Rectangle a l''envers : erreur ', e);
end.Hors de la zone : 0, dedans : 4
Rectangle a l'envers : erreur 1NeoBASIC
10 ' Limiter le dessin a un rectangle (groupe 32, fonction 2, Trinity)
20 cls : ' ecran efface : on relit des pixels
30 z = alloc(8) : q = z : g = 100 : h = 100 : d = 110 : b = 110 : gosub 8000
40 gr = alloc(8) : q = gr : g = 90 : h = 90 : d = 120 : b = 120 : gosub 8000
50 ev = alloc(8) : q = ev : g = 50 : h = 50 : d = 40 : b = 40 : gosub 8000
60 gosub 9400
70 a = z : f = 2 : gosub 9000 : ' Set Clip : rien ne se dessine hors de la zone
80 c = 4 : gosub 9300 : a = gr : f = 8 : gosub 9000 : ' 32,8 : peint un rectangle plus grand
90 de = point(95, 95) : dd = point(105, 105)
100 a = ev : f = 2 : gosub 9000 : e2 = e : ' droite < gauche : refuse
110 gosub 9400 : ' rend tout l'ecran au dessin
120 print "Hors de la zone : ";de;", dedans : ";dd
130 print "Rectangle a l'envers : erreur ";e2
140 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Hors de la zone : 0, dedans : 4
Rectangle a l'envers : erreur 1Assembleur 65C02 (64tass)
; Limiter le dessin à un rectangle (groupe 32, fonction 2, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #95
ldy #95
jsr pixel
sta de
lda #105
ldy #105
jsr pixel
sta dd
lda #<b4
ldx #>b4
jsr envoi
lda ControlPort+2
sta e2
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda de
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda dd
jsr decimal
lda #13
jsr WriteCharacter
lda #<t8
ldx #>t8
jsr ecrire
lda e2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
z: .word 100, 100, 110, 110 ; gauche, haut, droite, bas (droite et bas exclus)
gr: .word 90, 90, 120, 120 ; gauche, haut, droite, bas (droite et bas exclus)
ev: .word 50, 50, 40, 40 ; gauche, haut, droite, bas (droite et bas exclus)
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 2, 2 ; 32,2 : Set Clip, rien ne se dessine hors de la zone
.word z
b2: .byte 32, 4, 1, 4 ; 32,4 : Set Pen Colour
b3: .byte 32, 8, 2 ; 32,8 : peint un rectangle plus grand
.word gr
de: .byte 0
dd: .byte 0
b4: .byte 32, 2, 2 ; droite < gauche : refusé
.word ev
e2: .byte 0
b5: .byte 32, 1, 0 ; rend tout l'écran au dessin
t6: .text "Hors de la zone : ", 0
t7: .text ", dedans : ", 0
t8: .text "Rectangle a l'envers : erreur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Hors de la zone : 0, dedans : 4
Rectangle a l'envers : erreur 132,3 Get Clip Trinity
Écrit le rectangle de découpe en cours dans le Rect donné.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect à remplir |
Sorties : aucune.
La découpe relue est celle qui s'applique vraiment : 32,2 l'a croisée avec l'écran. L'exemple demande -10, -10, 500, 50 et relit 0, 0, 320, 50. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Writes the current clip rectangle into the Rect at Parameters:0,1.
C (llvm-mos)
/* Relire le rectangle de découpe (groupe 32, fonction 3, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static Rect clip;
static void get_clip(void) { /* 32,3 Get Clip : écrit le rectangle de découpe dans clip */
qd_rect(3, &clip);
}
static Rect demande = {-10, -10, 500, 50};
int main(void) {
init_graf();
qd_rect(2, &demande); /* 32,2 : déborde de l'écran à gauche, en haut et à droite */
get_clip(); /* Get Clip */
init_graf();
printf("Decoupe : %d, %d, %d, %d\n", clip.g, clip.h, clip.d, clip.b);
return 0;
}Decoupe : 0, 0, 320, 50Mad Pascal
// Relire le rectangle de découpe (groupe 32, fonction 3, Trinity).
program qd3;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var clip: Rect;
procedure get_clip; // 32,3 Get Clip : écrit le rectangle de découpe dans clip
begin
qd_rect(3, @clip);
end;
var demande: Rect;
begin
demande.g := -10; demande.h := -10; demande.d := 500; demande.b := 50;
init_graf;
qd_rect(2, @demande); // 32,2 : déborde de l'écran à gauche, en haut et à droite
get_clip; // Get Clip
init_graf;
writeln('Decoupe : ', clip.g, ', ', clip.h, ', ', clip.d, ', ', clip.b);
end.Decoupe : 0, 0, 320, 50NeoBASIC
10 ' Relire le rectangle de decoupe (groupe 32, fonction 3, Trinity)
20 k = alloc(8) : q = alloc(8) : g = -10 : h = -10 : d = 500 : b = 50 : gosub 8000
30 gosub 9400
40 a = q : f = 2 : gosub 9000 : ' 32,2 : deborde de l'ecran a gauche, en haut et a droite
50 gosub 9600 : ' Get Clip
60 gosub 9400
70 print "Decoupe : ";cg;", ";ch;", ";cd;", ";cb
80 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9600 ' 32,3 Get Clip dans le Rect k ; valeurs dans cg, ch, cd, cb
9610 a = k : f = 3 : gosub 9000
9620 cg = deek(k) : ch = deek(k + 2) : cd = deek(k + 4) : cb = deek(k + 6)
9630 returnDecoupe : 0, 0, 320, 50Assembleur 65C02 (64tass)
; Relire le rectangle de découpe (groupe 32, fonction 3, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
lda k
ldx k+1
jsr dec16
lda #<t5
ldx #>t5
jsr ecrire
lda k+2
ldx k+2+1
jsr dec16
lda #<t6
ldx #>t6
jsr ecrire
lda k+4
ldx k+4+1
jsr dec16
lda #<t7
ldx #>t7
jsr ecrire
lda k+6
ldx k+6+1
jsr dec16
lda #13
jsr WriteCharacter
rts
q: .word 65526, 65526, 500, 50 ; gauche, haut, droite, bas (droite et bas exclus)
k: .fill 8
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 2, 2 ; 32,2 : déborde de l'écran à gauche, en haut et à droite
.word q
b2: .byte 32, 3, 2 ; Get Clip
.word k
b3: .byte 32, 1, 0 ; 32,1 : Init Graf
t4: .text "Decoupe : ", 0
t5: .text ", ", 0
t6: .text ", ", 0
t7: .text ", ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Decoupe : 0, 0, 320, 5032,4 Set Pen Colour Trinity
Choisit la couleur de la plume (indice de palette), utilisée par 32,7, 32,8, 32,11, 32,13 et 32,16.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | couleur (indice de palette) |
Sorties : aucune.
L'exemple choisit la couleur 9, peint un rectangle, puis relit un pixel et la plume (32,6). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Sets the pen colour (palette index) used by Frame Rect and Paint Rect to Parameter:0.
C (llvm-mos)
/* Choisir la couleur de la plume (groupe 32, fonction 4, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static int16_t plume_x, plume_y;
static uint8_t plume_c;
static void get_pen(void) { /* 32,6 Get Pen */
libre();
qd(6);
plume_x = ControlPort.params[0] | ControlPort.params[1] << 8;
plume_y = ControlPort.params[2] | ControlPort.params[3] << 8;
plume_c = ControlPort.params[4];
}
static Rect r = {100, 100, 104, 104};
int main(void) {
putchar(12);
init_graf();
couleur(9); /* Set Pen Colour */
qd_rect(8, &r); /* 32,8 peint dans cette couleur */
uint8_t p = px(101, 101);
get_pen();
init_graf();
printf("Pixel : %u, plume : %u\n", p, plume_c);
return 0;
}Pixel : 9, plume : 9Mad Pascal
// Choisir la couleur de la plume (groupe 32, fonction 4, Trinity).
program qd4;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var plume_x, plume_y: smallint;
plume_c: byte;
procedure get_pen; // 32,6 Get Pen
begin
NeoWaitMessage;
qd(6);
plume_x := smallint(wordParams[0]);
plume_y := smallint(wordParams[1]);
plume_c := NeoMessage.params[4];
end;
var r: Rect;
p: byte;
begin
write(chr(12));
r.g := 100; r.h := 100; r.d := 104; r.b := 104;
init_graf;
couleur(9); // Set Pen Colour
qd_rect(8, @r); // 32,8 peint dans cette couleur
p := NeoGetPixel(101, 101);
get_pen;
init_graf;
writeln('Pixel : ', p, ', plume : ', plume_c);
end.Pixel : 9, plume : 9NeoBASIC
10 ' Choisir la couleur de la plume (groupe 32, fonction 4, Trinity)
20 cls : q = alloc(8) : g = 100 : h = 100 : d = 104 : b = 104 : gosub 8000
30 gosub 9400
40 c = 9 : gosub 9300 : ' Set Pen Colour
50 a = q : f = 8 : gosub 9000 : ' 32,8 peint dans cette couleur
60 p = point(101, 101) : gosub 9500
70 gosub 9400
80 print "Pixel : ";p;", plume : ";pc
90 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9500 ' 32,6 Get Pen : px, py, pc
9510 while peek($ff00) : wend : f = 6 : gosub 9110
9520 px = deek($ff04) : py = deek($ff06) : pc = peek($ff08)
9530 if px > 32767 then px = px - 65536
9540 if py > 32767 then py = py - 65536
9550 returnPixel : 9, plume : 9Assembleur 65C02 (64tass)
; Choisir la couleur de la plume (groupe 32, fonction 4, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #101
ldy #101
jsr pixel
sta px
lda #<b4
ldx #>b4
jsr envoi
ldx #4
_c3: lda ControlPort+4,x
sta pen,x
dex
bpl _c3
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda px
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda pen+4
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 100, 100, 104, 104 ; gauche, haut, droite, bas (droite et bas exclus)
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 9 ; Set Pen Colour
b2: .byte 32, 8, 2 ; 32,8 peint dans cette couleur
.word q
px: .byte 0
b4: .byte 32, 6, 0 ; 32,6 : Get Pen
pen: .fill 5 ; x, y (16 bits), couleur
b5: .byte 32, 1, 0 ; 32,1 : Init Graf
t6: .text "Pixel : ", 0
t7: .text ", plume : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Pixel : 9, plume : 932,5 Move To Trinity
Déplace la plume sans rien dessiner.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X (signé) |
P2-P3 | int16 | Y (signé) |
Sorties : aucune.
L'exemple place la plume en (30, 40) : le pixel reste à 0 ; le trait de 32,11 part ensuite de là. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Moves the pen to Parameters:0,1 (X) and Parameters:2,3 (Y), signed 16 bit, without drawing.
C (llvm-mos)
/* Déplacer la plume sans dessiner (groupe 32, fonction 5, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static int16_t plume_x, plume_y;
static uint8_t plume_c;
static void get_pen(void) { /* 32,6 Get Pen */
libre();
qd(6);
plume_x = ControlPort.params[0] | ControlPort.params[1] << 8;
plume_y = ControlPort.params[2] | ControlPort.params[3] << 8;
plume_c = ControlPort.params[4];
}
int main(void) {
putchar(12);
init_graf();
qd_xy(5, 30, 40); /* Move To : rien n'est dessiné */
get_pen();
int16_t x = plume_x, y = plume_y;
uint8_t avant = px(30, 40);
qd_xy(11, 60, 40); /* 32,11 : trait depuis la plume */
uint8_t trait = px(45, 40);
init_graf();
printf("Plume : %d, %d ; pixel %u, puis trait : %u\n", x, y, avant, trait);
return 0;
}Plume : 30, 40 ; pixel 0, puis trait : 15Mad Pascal
// Déplacer la plume sans dessiner (groupe 32, fonction 5, Trinity).
program qd5;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var plume_x, plume_y: smallint;
plume_c: byte;
procedure get_pen; // 32,6 Get Pen
begin
NeoWaitMessage;
qd(6);
plume_x := smallint(wordParams[0]);
plume_y := smallint(wordParams[1]);
plume_c := NeoMessage.params[4];
end;
var x, y: smallint;
avant, trait: byte;
begin
write(chr(12));
init_graf;
qd_xy(5, 30, 40); // Move To : rien n'est dessiné
get_pen;
x := plume_x;
y := plume_y;
avant := NeoGetPixel(30, 40);
qd_xy(11, 60, 40); // 32,11 : trait depuis la plume
trait := NeoGetPixel(45, 40);
init_graf;
writeln('Plume : ', x, ', ', y, ' ; pixel ', avant, ', puis trait : ', trait);
end.Plume : 30, 40 ; pixel 0, puis trait : 15NeoBASIC
10 ' Deplacer la plume sans dessiner (groupe 32, fonction 5, Trinity)
20 cls : gosub 9400
30 x = 30 : y = 40 : f = 5 : gosub 9200 : ' Move To : rien n'est dessine
40 gosub 9500 : xx = px : yy = py : av = point(30, 40)
50 x = 60 : y = 40 : f = 11 : gosub 9200 : ' 32,11 : trait depuis la plume
60 tr = point(45, 40)
70 gosub 9400
80 print "Plume : ";xx;", ";yy;" ; pixel ";av;", puis trait : ";tr
90 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9500 ' 32,6 Get Pen : px, py, pc
9510 while peek($ff00) : wend : f = 6 : gosub 9110
9520 px = deek($ff04) : py = deek($ff06) : pc = peek($ff08)
9530 if px > 32767 then px = px - 65536
9540 if py > 32767 then py = py - 65536
9550 returnPlume : 30, 40 ; pixel 0, puis trait : 15Assembleur 65C02 (64tass)
; Déplacer la plume sans dessiner (groupe 32, fonction 5, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
ldx #4
_c2: lda ControlPort+4,x
sta pen,x
dex
bpl _c2
lda #30
ldy #40
jsr pixel
sta av
lda #<b4
ldx #>b4
jsr envoi
lda #45
ldy #40
jsr pixel
sta tr
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda pen
ldx pen+1
jsr dec16
lda #<t7
ldx #>t7
jsr ecrire
lda pen+2
ldx pen+2+1
jsr dec16
lda #<t8
ldx #>t8
jsr ecrire
lda av
jsr decimal
lda #<t9
ldx #>t9
jsr ecrire
lda tr
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 5, 4 ; Move To : rien n'est dessiné
.word 30, 40
b3: .byte 32, 6, 0 ; 32,6 : Get Pen
pen: .fill 5 ; x, y (16 bits), couleur
av: .byte 0
b4: .byte 32, 11, 4 ; 32,11 : Line To
.word 60, 40
tr: .byte 0
b5: .byte 32, 1, 0 ; 32,1 : Init Graf
t6: .text "Plume : ", 0
t7: .text ", ", 0
t8: .text " ; pixel ", 0
t9: .text ", puis trait : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Plume : 30, 40 ; pixel 0, puis trait : 1532,6 Get Pen Trinity
Rend la position et la couleur de la plume.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X de la plume |
P2-P3 | int16 | Y de la plume |
P4 | uint8 | couleur de la plume |
Après 32,11, la plume est au bout du trait : l'exemple trace de (10, 50) à (70, 50) en couleur 3. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns the pen position in Parameters:0,1 (X) and Parameters:2,3 (Y) and the pen colour in Parameter:4.
C (llvm-mos)
/* Lire la position et la couleur de la plume (groupe 32, fonction 6, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static int16_t plume_x, plume_y;
static uint8_t plume_c;
static void get_pen(void) { /* 32,6 Get Pen */
libre();
qd(6);
plume_x = ControlPort.params[0] | ControlPort.params[1] << 8;
plume_y = ControlPort.params[2] | ControlPort.params[3] << 8;
plume_c = ControlPort.params[4];
}
int main(void) {
putchar(12);
init_graf();
couleur(3);
qd_xy(5, 10, 50);
qd_xy(11, 70, 50); /* 32,11 : la plume finit au bout du trait */
get_pen(); /* Get Pen */
init_graf();
printf("Plume : %d, %d, couleur %u\n", plume_x, plume_y, plume_c);
return 0;
}Plume : 70, 50, couleur 3Mad Pascal
// Lire la position et la couleur de la plume (groupe 32, fonction 6, Trinity).
program qd6;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var plume_x, plume_y: smallint;
plume_c: byte;
procedure get_pen; // 32,6 Get Pen
begin
NeoWaitMessage;
qd(6);
plume_x := smallint(wordParams[0]);
plume_y := smallint(wordParams[1]);
plume_c := NeoMessage.params[4];
end;
begin
write(chr(12));
init_graf;
couleur(3);
qd_xy(5, 10, 50);
qd_xy(11, 70, 50); // 32,11 : la plume finit au bout du trait
get_pen; // Get Pen
init_graf;
writeln('Plume : ', plume_x, ', ', plume_y, ', couleur ', plume_c);
end.Plume : 70, 50, couleur 3NeoBASIC
10 ' Lire la position et la couleur de la plume (groupe 32, fonction 6, Trinity)
20 cls : gosub 9400
30 c = 3 : gosub 9300
40 x = 10 : y = 50 : f = 5 : gosub 9200
50 x = 70 : y = 50 : f = 11 : gosub 9200 : ' 32,11 : la plume finit au bout du trait
60 gosub 9500 : ' Get Pen
70 gosub 9400
80 print "Plume : ";px;", ";py;", couleur ";pc
90 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9500 ' 32,6 Get Pen : px, py, pc
9510 while peek($ff00) : wend : f = 6 : gosub 9110
9520 px = deek($ff04) : py = deek($ff06) : pc = peek($ff08)
9530 if px > 32767 then px = px - 65536
9540 if py > 32767 then py = py - 65536
9550 returnPlume : 70, 50, couleur 3Assembleur 65C02 (64tass)
; Lire la position et la couleur de la plume (groupe 32, fonction 6, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
ldx #4
_cp: lda ControlPort+4,x
sta pen,x
dex
bpl _cp
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda pen
ldx pen+1
jsr dec16
lda #<t7
ldx #>t7
jsr ecrire
lda pen+2
ldx pen+2+1
jsr dec16
lda #<t8
ldx #>t8
jsr ecrire
lda pen+4
jsr decimal
lda #13
jsr WriteCharacter
rts
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 3 ; 32,4 : Set Pen Colour
b2: .byte 32, 5, 4 ; 32,5 : Move To
.word 10, 50
b3: .byte 32, 11, 4 ; 32,11 : la plume finit au bout du trait
.word 70, 50
b4: .byte 32, 6, 0 ; Get Pen
pen: .fill 5 ; x, y (16 bits), couleur
b5: .byte 32, 1, 0 ; 32,1 : Init Graf
t6: .text "Plume : ", 0
t7: .text ", ", 0
t8: .text ", couleur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Plume : 70, 50, couleur 332,7 Frame Rect Trinity
Trace le contour d'un rectangle, d'un pixel d'épaisseur, dans la couleur de la plume.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect |
Sorties : aucune.
Le contour est à l'intérieur du rectangle : pour 100, 100, 120, 110, les coins sont en (100, 100) et (119, 109), et le pixel (120, 100) reste vide. L'intérieur n'est pas touché. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Draws the one pixel outline of the Rect at Parameters:0,1 in the pen colour, inside the rectangle, clipped.
C (llvm-mos)
/* Tracer le contour d'un rectangle (groupe 32, fonction 7, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static Rect r = {100, 100, 120, 110};
int main(void) {
putchar(12);
init_graf();
couleur(6);
qd_rect(7, &r); /* Frame Rect */
uint8_t a = px(100, 100), b = px(119, 109); /* coins : le contour est à l'intérieur */
uint8_t c = px(120, 100), d = px(110, 105); /* juste à droite, et au milieu */
init_graf();
printf("Coins : %u %u, a droite : %u, au milieu : %u\n", a, b, c, d);
return 0;
}Coins : 6 6, a droite : 0, au milieu : 0Mad Pascal
// Tracer le contour d'un rectangle (groupe 32, fonction 7, Trinity).
program qd7;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var r: Rect;
a, b, c, d: byte;
begin
write(chr(12));
r.g := 100; r.h := 100; r.d := 120; r.b := 110;
init_graf;
couleur(6);
qd_rect(7, @r); // Frame Rect
a := NeoGetPixel(100, 100); // coins : le contour est à l'intérieur
b := NeoGetPixel(119, 109);
c := NeoGetPixel(120, 100); // juste à droite, et au milieu
d := NeoGetPixel(110, 105);
init_graf;
writeln('Coins : ', a, ' ', b, ', a droite : ', c, ', au milieu : ', d);
end.Coins : 6 6, a droite : 0, au milieu : 0NeoBASIC
10 ' Tracer le contour d'un rectangle (groupe 32, fonction 7, Trinity)
20 cls : q = alloc(8) : g = 100 : h = 100 : d = 120 : b = 110 : gosub 8000
30 gosub 9400 : c = 6 : gosub 9300
40 a = q : f = 7 : gosub 9000 : ' Frame Rect
50 c1 = point(100, 100) : c2 = point(119, 109) : ' coins : le contour est a l'interieur
60 dr = point(120, 100) : mi = point(110, 105) : ' juste a droite, et au milieu
70 gosub 9400
80 print "Coins : ";c1;" ";c2;", a droite : ";dr;", au milieu : ";mi
90 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Coins : 6 6, a droite : 0, au milieu : 0Assembleur 65C02 (64tass)
; Tracer le contour d'un rectangle (groupe 32, fonction 7, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #100
ldy #100
jsr pixel
sta c1
lda #119
ldy #109
jsr pixel
sta c2
lda #120
ldy #100
jsr pixel
sta dr
lda #110
ldy #105
jsr pixel
sta mi
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
lda c1
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda c2
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda dr
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda mi
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 100, 100, 120, 110 ; gauche, haut, droite, bas (droite et bas exclus)
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 6 ; 32,4 : Set Pen Colour
b2: .byte 32, 7, 2 ; Frame Rect
.word q
c1: .byte 0
c2: .byte 0
dr: .byte 0
mi: .byte 0
b3: .byte 32, 1, 0 ; 32,1 : Init Graf
t4: .text "Coins : ", 0
t5: .text " ", 0
t6: .text ", a droite : ", 0
t7: .text ", au milieu : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Coins : 6 6, a droite : 0, au milieu : 032,8 Paint Rect Trinity
Peint un rectangle dans la couleur de la plume.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect |
Sorties : aucune.
Les bords droit et bas sont exclus : 100, 100, 104, 102 peint x 100 à 103 sur les lignes 100 et 101. Le motif de 32,12 n'est pas utilisé (c'est 32,13 qui s'en sert). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Fills the Rect at Parameters:0,1 with the pen colour, clipped.
C (llvm-mos)
/* Peindre un rectangle (groupe 32, fonction 8, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static Rect r = {100, 100, 104, 102};
int main(void) {
putchar(12);
init_graf();
couleur(5);
qd_rect(8, &r); /* Paint Rect : x 100 à 103, y 100 et 101 */
uint8_t a = px(100, 100), b = px(103, 101), c = px(104, 101), d = px(103, 102);
init_graf();
printf("Dedans : %u %u, droite : %u, bas : %u\n", a, b, c, d);
return 0;
}Dedans : 5 5, droite : 0, bas : 0Mad Pascal
// Peindre un rectangle (groupe 32, fonction 8, Trinity).
program qd8;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var r: Rect;
a, b, c, d: byte;
begin
write(chr(12));
r.g := 100; r.h := 100; r.d := 104; r.b := 102;
init_graf;
couleur(5);
qd_rect(8, @r); // Paint Rect : x 100 à 103, y 100 et 101
a := NeoGetPixel(100, 100);
b := NeoGetPixel(103, 101);
c := NeoGetPixel(104, 101);
d := NeoGetPixel(103, 102);
init_graf;
writeln('Dedans : ', a, ' ', b, ', droite : ', c, ', bas : ', d);
end.Dedans : 5 5, droite : 0, bas : 0NeoBASIC
10 ' Peindre un rectangle (groupe 32, fonction 8, Trinity)
20 cls : q = alloc(8) : g = 100 : h = 100 : d = 104 : b = 102 : gosub 8000
30 gosub 9400 : c = 5 : gosub 9300
40 a = q : f = 8 : gosub 9000 : ' Paint Rect : x 100 a 103, y 100 et 101
50 p1 = point(100, 100) : p2 = point(103, 101) : p3 = point(104, 101) : p4 = point(103, 102)
60 gosub 9400
70 print "Dedans : ";p1;" ";p2;", droite : ";p3;", bas : ";p4
80 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Dedans : 5 5, droite : 0, bas : 0Assembleur 65C02 (64tass)
; Peindre un rectangle (groupe 32, fonction 8, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #100
ldy #100
jsr pixel
sta p1
lda #103
ldy #101
jsr pixel
sta p2
lda #104
ldy #101
jsr pixel
sta p3
lda #103
ldy #102
jsr pixel
sta p4
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
lda p1
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda p2
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda p3
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda p4
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 100, 100, 104, 102 ; gauche, haut, droite, bas (droite et bas exclus)
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 5 ; 32,4 : Set Pen Colour
b2: .byte 32, 8, 2 ; Paint Rect : x 100 à 103, y 100 et 101
.word q
p1: .byte 0
p2: .byte 0
p3: .byte 0
p4: .byte 0
b3: .byte 32, 1, 0 ; 32,1 : Init Graf
t4: .text "Dedans : ", 0
t5: .text " ", 0
t6: .text ", droite : ", 0
t7: .text ", bas : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Dedans : 5 5, droite : 0, bas : 032,9 Erase Rect Trinity
Remplit un rectangle avec une couleur de fond donnée.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect |
P2 | uint8 | couleur du fond |
Sorties : aucune.
La couleur de la plume n'est pas changée. L'exemple peint un carré en couleur 4, puis en efface le centre en couleur 2. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Fills the Rect at Parameters:0,1 with the colour in Parameter:2 (the background), clipped.
C (llvm-mos)
/* Effacer un rectangle avec une couleur de fond (groupe 32, fonction 9, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static Rect r = {100, 100, 110, 110}, petit = {102, 102, 106, 106};
int main(void) {
putchar(12);
init_graf();
couleur(4);
qd_rect(8, &r); /* 32,8 : un carré de couleur 4 */
libre();
ControlPort.params[0] = (uint16_t)&petit & 0xFF;
ControlPort.params[1] = (uint16_t)&petit >> 8;
ControlPort.params[2] = 2; /* P2 : couleur du fond */
qd(9); /* Erase Rect */
uint8_t a = px(103, 103), b = px(100, 100);
init_graf();
printf("Efface : %u, autour : %u\n", a, b);
return 0;
}Efface : 2, autour : 4Mad Pascal
// Effacer un rectangle avec une couleur de fond (groupe 32, fonction 9, Trinity).
program qd9;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var r, petit: Rect;
a, b: byte;
begin
write(chr(12));
r.g := 100; r.h := 100; r.d := 110; r.b := 110;
petit.g := 102; petit.h := 102; petit.d := 106; petit.b := 106;
init_graf;
couleur(4);
qd_rect(8, @r); // 32,8 : un carré de couleur 4
NeoWaitMessage;
wordParams[0] := word(@petit);
NeoMessage.params[2] := 2; // P2 : couleur du fond
qd(9); // Erase Rect
a := NeoGetPixel(103, 103);
b := NeoGetPixel(100, 100);
init_graf;
writeln('Efface : ', a, ', autour : ', b);
end.Efface : 2, autour : 4NeoBASIC
10 ' Effacer un rectangle avec une couleur de fond (groupe 32, fonction 9, Trinity)
20 cls : r = alloc(8) : q = r : g = 100 : h = 100 : d = 110 : b = 110 : gosub 8000
30 pe = alloc(8) : q = pe : g = 102 : h = 102 : d = 106 : b = 106 : gosub 8000
40 gosub 9400 : c = 4 : gosub 9300
50 a = r : f = 8 : gosub 9000 : ' 32,8 : un carre de couleur 4
60 while peek($ff00) : wend : doke $ff04, pe : poke $ff06, 2 : f = 9 : gosub 9110 : ' Erase Rect, P2 : couleur du fond
70 p1 = point(103, 103) : p2 = point(100, 100)
80 gosub 9400
90 print "Efface : ";p1;", autour : ";p2
100 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Efface : 2, autour : 4Assembleur 65C02 (64tass)
; Effacer un rectangle avec une couleur de fond (groupe 32, 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 #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #103
ldy #103
jsr pixel
sta p1
lda #100
ldy #100
jsr pixel
sta p2
lda #<b4
ldx #>b4
jsr envoi
lda #<t5
ldx #>t5
jsr ecrire
lda p1
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda p2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
r: .word 100, 100, 110, 110 ; gauche, haut, droite, bas (droite et bas exclus)
pe: .word 102, 102, 106, 106 ; gauche, haut, droite, bas (droite et bas exclus)
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 4 ; 32,4 : Set Pen Colour
b2: .byte 32, 8, 2 ; 32,8 : un carré de couleur 4
.word r
b3: .byte 32, 9, 3 ; Erase Rect, P2 : couleur du fond
.word pe
.byte 2
p1: .byte 0
p2: .byte 0
b4: .byte 32, 1, 0 ; 32,1 : Init Graf
t5: .text "Efface : ", 0
t6: .text ", autour : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Efface : 2, autour : 432,10 Invert Rect Trinity
Inverse les pixels d'un rectangle.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect |
Sorties : aucune.
En mode 0, chaque indice de couleur est combiné par OU exclusif avec $FF : 5 devient 250. Une seconde inversion rend l'image de départ. Selon le mode, Trinity prend $0F ou 1 au lieu de $FF. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Inverts every pixel of the Rect at Parameters:0,1 (colour index XOR $FF, $0F or 1 depending on the mode), clipped.
C (llvm-mos)
/* Inverser les pixels d'un rectangle (groupe 32, fonction 10, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static Rect r = {100, 100, 104, 104};
int main(void) {
putchar(12);
init_graf();
couleur(5);
qd_rect(8, &r);
qd_rect(10, &r); /* Invert Rect : en mode 0, XOR $FF */
uint8_t a = px(101, 101);
qd_rect(10, &r); /* deux fois : retour au départ */
uint8_t b = px(101, 101);
init_graf();
printf("Inverse : %u, deux fois : %u\n", a, b);
return 0;
}Inverse : 250, deux fois : 5Mad Pascal
// Inverser les pixels d'un rectangle (groupe 32, fonction 10, Trinity).
program qd10;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var r: Rect;
a, b: byte;
begin
write(chr(12));
r.g := 100; r.h := 100; r.d := 104; r.b := 104;
init_graf;
couleur(5);
qd_rect(8, @r);
qd_rect(10, @r); // Invert Rect : en mode 0, XOR $FF
a := NeoGetPixel(101, 101);
qd_rect(10, @r); // deux fois : retour au départ
b := NeoGetPixel(101, 101);
init_graf;
writeln('Inverse : ', a, ', deux fois : ', b);
end.Inverse : 250, deux fois : 5NeoBASIC
10 ' Inverser les pixels d'un rectangle (groupe 32, fonction 10, Trinity)
20 cls : q = alloc(8) : g = 100 : h = 100 : d = 104 : b = 104 : gosub 8000
30 gosub 9400 : c = 5 : gosub 9300
40 a = q : f = 8 : gosub 9000
50 f = 10 : gosub 9000 : p1 = point(101, 101) : ' Invert Rect : en mode 0, XOR $FF
60 f = 10 : gosub 9000 : p2 = point(101, 101) : ' deux fois : retour au depart
70 gosub 9400
80 print "Inverse : ";p1;", deux fois : ";p2
90 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Inverse : 250, deux fois : 5Assembleur 65C02 (64tass)
; Inverser les pixels d'un rectangle (groupe 32, 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: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #101
ldy #101
jsr pixel
sta p1
lda #<b4
ldx #>b4
jsr envoi
lda #101
ldy #101
jsr pixel
sta p2
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda p1
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda p2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 100, 100, 104, 104 ; gauche, haut, droite, bas (droite et bas exclus)
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 5 ; 32,4 : Set Pen Colour
b2: .byte 32, 8, 2 ; 32,8
.word q
b3: .byte 32, 10, 2 ; Invert Rect : en mode 0, XOR $FF
.word q
p1: .byte 0
b4: .byte 32, 10, 2 ; deux fois : retour au départ
.word q
p2: .byte 0
b5: .byte 32, 1, 0 ; 32,1 : Init Graf
t6: .text "Inverse : ", 0
t7: .text ", deux fois : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Inverse : 250, deux fois : 532,11 Line To Trinity
Trace un trait de la plume jusqu'au point donné, dans la couleur de la plume, et y déplace la plume.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X d'arrivée (signé) |
P2-P3 | int16 | Y d'arrivée (signé) |
Sorties : aucune.
Le point de départ et le point d'arrivée sont tous deux tracés, mais pas le pixel suivant. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Draws a line from the pen to Parameters:0,1 (X) and Parameters:2,3 (Y) in the pen colour, clipped, and moves the pen there.
C (llvm-mos)
/* Tracer un trait depuis la plume (groupe 32, fonction 11, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
int main(void) {
putchar(12);
init_graf();
couleur(7);
qd_xy(5, 50, 60); /* 32,5 : départ */
qd_xy(11, 60, 60); /* Line To : le point d'arrivée est tracé */
uint8_t a = px(50, 60), b = px(60, 60), c = px(61, 60);
init_graf();
printf("Depart : %u, arrivee : %u, apres : %u\n", a, b, c);
return 0;
}Depart : 7, arrivee : 7, apres : 0Mad Pascal
// Tracer un trait depuis la plume (groupe 32, fonction 11, Trinity).
program qd11;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var a, b, c: byte;
begin
write(chr(12));
init_graf;
couleur(7);
qd_xy(5, 50, 60); // 32,5 : départ
qd_xy(11, 60, 60); // Line To : le point d'arrivée est tracé
a := NeoGetPixel(50, 60);
b := NeoGetPixel(60, 60);
c := NeoGetPixel(61, 60);
init_graf;
writeln('Depart : ', a, ', arrivee : ', b, ', apres : ', c);
end.Depart : 7, arrivee : 7, apres : 0NeoBASIC
10 ' Tracer un trait depuis la plume (groupe 32, fonction 11, Trinity)
20 cls : gosub 9400 : c = 7 : gosub 9300
30 x = 50 : y = 60 : f = 5 : gosub 9200 : ' 32,5 : depart
40 x = 60 : y = 60 : f = 11 : gosub 9200 : ' Line To : le point d'arrivee est trace
50 p1 = point(50, 60) : p2 = point(60, 60) : p3 = point(61, 60)
60 gosub 9400
70 print "Depart : ";p1;", arrivee : ";p2;", apres : ";p3
80 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Depart : 7, arrivee : 7, apres : 0Assembleur 65C02 (64tass)
; Tracer un trait depuis la plume (groupe 32, 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 #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #50
ldy #60
jsr pixel
sta p1
lda #60
ldy #60
jsr pixel
sta p2
lda #61
ldy #60
jsr pixel
sta p3
lda #<b4
ldx #>b4
jsr envoi
lda #<t5
ldx #>t5
jsr ecrire
lda p1
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda p2
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda p3
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 7 ; 32,4 : Set Pen Colour
b2: .byte 32, 5, 4 ; 32,5 : Move To
.word 50, 60
b3: .byte 32, 11, 4 ; Line To : le point d'arrivée est tracé
.word 60, 60
p1: .byte 0
p2: .byte 0
p3: .byte 0
b4: .byte 32, 1, 0 ; 32,1 : Init Graf
t5: .text "Depart : ", 0
t6: .text ", arrivee : ", 0
t7: .text ", apres : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Depart : 7, arrivee : 7, apres : 032,12 Set Pattern Trinity
Charge le motif 8 × 8 utilisé par 32,13.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse des 8 octets du motif : un octet par ligne, bit 7 = pixel de gauche |
Sorties : aucune.
Le motif est calé sur les coordonnées de l'écran, pas sur le rectangle : l'exemple remplit à partir de x = 96, un multiple de 8, pour que la première colonne reçoive le bit 7. 32,1 remet le motif plein. L'exemple charge un damier ($AA, $55) : bits à 1 en couleur 3, bits à 0 en couleur 9. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Loads the 8x8 fill pattern from the 8 bytes at Parameters:0,1 (one byte per row, bit 7 = left pixel). Init Graf resets it to solid. The pattern is aligned on screen coordinates.
C (llvm-mos)
/* Choisir le motif de remplissage (groupe 32, fonction 12, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static const uint8_t damier[8] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
static void motif(const uint8_t *m) { /* 32,12 Set Pattern : 8 octets, bit 7 = pixel de gauche */
libre();
ControlPort.params[0] = (uint16_t)m & 0xFF;
ControlPort.params[1] = (uint16_t)m >> 8;
qd(12);
}
static void remplir(Rect *r, uint8_t fond) { /* 32,13 Fill Rect : bits à 1 couleur de la plume, à 0 fond */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
ControlPort.params[2] = fond;
qd(13);
}
static Rect r = {96, 100, 104, 102}; /* x 96 à 103 : une rangée du motif, alignée sur l'écran */
int main(void) {
putchar(12);
init_graf();
couleur(3);
motif(damier); /* Set Pattern */
remplir(&r, 9);
uint8_t l[2][8];
for (uint8_t y = 0; y < 2; y++)
for (uint8_t x = 0; x < 8; x++)
l[y][x] = px(96 + x, 100 + y);
init_graf(); /* remet aussi le motif plein */
for (uint8_t y = 0; y < 2; y++) {
printf("y %u :", 100 + y);
for (uint8_t x = 0; x < 8; x++)
printf(" %u", l[y][x]);
printf("\n");
}
return 0;
}y 100 : 3 9 3 9 3 9 3 9
y 101 : 9 3 9 3 9 3 9 3Mad Pascal
// Choisir le motif de remplissage (groupe 32, fonction 12, Trinity).
program qd12;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
const damier: array[0..7] of byte = ($AA, $55, $AA, $55, $AA, $55, $AA, $55);
procedure motif(m: pointer); // 32,12 Set Pattern : 8 octets, bit 7 = pixel de gauche
begin
qd_rect(12, m);
end;
procedure remplir(r: pointer; fond: byte); // 32,13 Fill Rect : bits à 1 couleur de la plume, à 0 fond
begin
NeoWaitMessage;
wordParams[0] := word(r);
NeoMessage.params[2] := fond;
qd(13);
end;
var r: Rect;
l: array[0..15] of byte;
x, y: byte;
begin
write(chr(12));
r.g := 96; r.h := 100; r.d := 104; r.b := 102; // x 96 à 103 : une rangée du motif, alignée sur l'écran
init_graf;
couleur(3);
motif(@damier); // Set Pattern
remplir(@r, 9);
for y := 0 to 1 do
for x := 0 to 7 do l[y * 8 + x] := NeoGetPixel(96 + x, 100 + y);
init_graf; // remet aussi le motif plein
for y := 0 to 1 do begin
write('y ', 100 + y, ' :');
for x := 0 to 7 do write(' ', l[y * 8 + x]);
writeln;
end;
end.y 100 : 3 9 3 9 3 9 3 9
y 101 : 9 3 9 3 9 3 9 3NeoBASIC
10 ' Choisir le motif de remplissage (groupe 32, fonction 12, Trinity)
20 cls : q = alloc(8) : g = 96 : h = 100 : d = 104 : b = 102 : gosub 8000 : ' x 96 a 103 : une rangee du motif, alignee sur l'ecran
30 m = alloc(8) : for i = 0 to 3 : poke m + i * 2, $aa : poke m + i * 2 + 1, $55 : next i : ' damier, bit 7 = pixel de gauche
40 gosub 9400 : c = 3 : gosub 9300
50 a = m : f = 12 : gosub 9000 : ' Set Pattern
60 while peek($ff00) : wend : doke $ff04, q : poke $ff06, 9 : f = 13 : gosub 9110 : ' 32,13 : bits a 0 en couleur 9
70 l0$ = "" : l1$ = "" : for x = 96 to 103 : l0$ = l0$ + " " + str$(point(x, 100)) : l1$ = l1$ + " " + str$(point(x, 101)) : next x
80 gosub 9400 : ' remet aussi le motif plein
90 print "y 100 :";l0$
100 print "y 101 :";l1$
110 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110y 100 : 3 9 3 9 3 9 3 9
y 101 : 9 3 9 3 9 3 9 3Assembleur 65C02 (64tass)
; Choisir le motif de remplissage (groupe 32, 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 #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
ldx #0
_l4: phx
txa
clc
adc #96
ldy #100
jsr pixel
plx
sta l0,x
inx
cpx #8
bne _l4
ldx #0
_l5: phx
txa
clc
adc #96
ldy #101
jsr pixel
plx
sta l1,x
inx
cpx #8
bne _l5
lda #<b6
ldx #>b6
jsr envoi
lda #<t7
ldx #>t7
jsr ecrire
ldx #0
_a8: lda #' '
jsr WriteCharacter
lda l0,x
jsr decimal
inx
cpx #8
bne _a8
lda #13
jsr WriteCharacter
lda #<t9
ldx #>t9
jsr ecrire
ldx #0
_a10: lda #' '
jsr WriteCharacter
lda l1,x
jsr decimal
inx
cpx #8
bne _a10
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 96, 100, 104, 102 ; gauche, haut, droite, bas (droite et bas exclus)
motif: .byte $AA, $55, $AA, $55, $AA, $55, $AA, $55 ; damier, bit 7 = pixel de gauche
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 4, 1, 3 ; 32,4 : Set Pen Colour
b2: .byte 32, 12, 2 ; Set Pattern
.word motif
b3: .byte 32, 13, 3 ; 32,13 : bits à 0 en couleur 9
.word q
.byte 9
l0: .fill 8
l1: .fill 8
b6: .byte 32, 1, 0 ; remet aussi le motif plein
t7: .text "y 100 :", 0
t9: .text "y 101 :", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0y 100 : 3 9 3 9 3 9 3 9
y 101 : 9 3 9 3 9 3 9 332,13 Fill Rect Trinity
Remplit un rectangle avec le motif : bits à 1 dans la couleur de la plume, bits à 0 dans la couleur donnée.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du Rect |
P2 | uint8 | couleur des bits à 0 |
Sorties : aucune.
Avec le motif plein de départ, 32,13 fait comme 32,8. L'exemple remplit ensuite avec des rayures ($F0 : quatre pixels allumés, quatre éteints). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Fills the Rect at Parameters:0,1 with the pattern : set bits in the pen colour, clear bits in the colour of Parameter:2. Clipped.
C (llvm-mos)
/* Remplir un rectangle avec le motif (groupe 32, fonction 13, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static const uint8_t damier[8] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
static void motif(const uint8_t *m) { /* 32,12 Set Pattern : 8 octets, bit 7 = pixel de gauche */
libre();
ControlPort.params[0] = (uint16_t)m & 0xFF;
ControlPort.params[1] = (uint16_t)m >> 8;
qd(12);
}
static void remplir(Rect *r, uint8_t fond) { /* 32,13 Fill Rect : bits à 1 couleur de la plume, à 0 fond */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
ControlPort.params[2] = fond;
qd(13);
}
static const uint8_t rayures[8] = {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}; /* 4 pixels allumés, 4 éteints */
static Rect r = {96, 100, 104, 101};
int main(void) {
putchar(12);
init_graf();
uint8_t avant[2] = {px(96, 100), px(103, 100)};
couleur(3);
remplir(&r, 9); /* Fill Rect, motif plein au départ */
uint8_t plein[2] = {px(96, 100), px(103, 100)};
motif(rayures);
remplir(&r, 9); /* Fill Rect : 3 pour les bits à 1, 9 pour les bits à 0 */
uint8_t ray[2] = {px(96, 100), px(103, 100)};
init_graf();
printf("Avant : %u %u, motif plein : %u %u, rayures : %u %u\n", avant[0], avant[1], plein[0], plein[1], ray[0], ray[1]);
return 0;
}Avant : 0 0, motif plein : 3 3, rayures : 3 9Mad Pascal
// Remplir un rectangle avec le motif (groupe 32, fonction 13, Trinity).
program qd13;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
const damier: array[0..7] of byte = ($AA, $55, $AA, $55, $AA, $55, $AA, $55);
procedure motif(m: pointer); // 32,12 Set Pattern : 8 octets, bit 7 = pixel de gauche
begin
qd_rect(12, m);
end;
procedure remplir(r: pointer; fond: byte); // 32,13 Fill Rect : bits à 1 couleur de la plume, à 0 fond
begin
NeoWaitMessage;
wordParams[0] := word(r);
NeoMessage.params[2] := fond;
qd(13);
end;
const rayures: array[0..7] of byte = ($F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0); // 4 pixels allumés, 4 éteints
var r: Rect;
a0, a1, p0, p1, r0, r1: byte;
begin
write(chr(12));
r.g := 96; r.h := 100; r.d := 104; r.b := 101;
init_graf;
a0 := NeoGetPixel(96, 100); a1 := NeoGetPixel(103, 100);
couleur(3);
remplir(@r, 9); // Fill Rect, motif plein au départ
p0 := NeoGetPixel(96, 100); p1 := NeoGetPixel(103, 100);
motif(@rayures);
remplir(@r, 9); // Fill Rect : 3 pour les bits à 1, 9 pour les bits à 0
r0 := NeoGetPixel(96, 100); r1 := NeoGetPixel(103, 100);
init_graf;
writeln('Avant : ', a0, ' ', a1, ', motif plein : ', p0, ' ', p1, ', rayures : ', r0, ' ', r1);
end.Avant : 0 0, motif plein : 3 3, rayures : 3 9NeoBASIC
10 ' Remplir un rectangle avec le motif (groupe 32, fonction 13, Trinity)
20 cls : q = alloc(8) : g = 96 : h = 100 : d = 104 : b = 101 : gosub 8000
30 m = alloc(8) : for i = 0 to 7 : poke m + i, $f0 : next i : ' rayures : 4 pixels allumes, 4 eteints
40 gosub 9400 : a0 = point(96, 100) : a1 = point(103, 100)
50 c = 3 : gosub 9300
60 gosub 2000 : p0 = point(96, 100) : p1 = point(103, 100) : ' Fill Rect, motif plein au depart
70 a = m : f = 12 : gosub 9000
80 gosub 2000 : r0 = point(96, 100) : r1 = point(103, 100) : ' 3 pour les bits a 1, 9 pour les bits a 0
90 gosub 9400
100 print "Avant : ";a0;" ";a1;", motif plein : ";p0;" ";p1;", rayures : ";r0;" ";r1
110 end
2000 ' Fill Rect sur q, fond 9
2010 while peek($ff00) : wend : doke $ff04, q : poke $ff06, 9 : f = 13 : gosub 9110
2020 return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Avant : 0 0, motif plein : 3 3, rayures : 3 9Assembleur 65C02 (64tass)
; Remplir un rectangle avec le motif (groupe 32, fonction 13, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #96
ldy #100
jsr pixel
sta a0
lda #103
ldy #100
jsr pixel
sta a1
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #96
ldy #100
jsr pixel
sta p0
lda #103
ldy #100
jsr pixel
sta p1
lda #<b3
ldx #>b3
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
lda #96
ldy #100
jsr pixel
sta r0
lda #103
ldy #100
jsr pixel
sta r1
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda a0
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda a1
jsr decimal
lda #<t8
ldx #>t8
jsr ecrire
lda p0
jsr decimal
lda #<t9
ldx #>t9
jsr ecrire
lda p1
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda r0
jsr decimal
lda #<t11
ldx #>t11
jsr ecrire
lda r1
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 96, 100, 104, 101 ; gauche, haut, droite, bas (droite et bas exclus)
motif: .fill 8, $F0 ; rayures : 4 pixels allumés, 4 éteints
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
a0: .byte 0
a1: .byte 0
b1: .byte 32, 4, 1, 3 ; 32,4 : Set Pen Colour
b2: .byte 32, 13, 3 ; Fill Rect, motif plein au départ, fond 9
.word q
.byte 9
p0: .byte 0
p1: .byte 0
b3: .byte 32, 12, 2 ; 32,12
.word motif
b4: .byte 32, 13, 3 ; 3 pour les bits à 1, 9 pour les bits à 0
.word q
.byte 9
r0: .byte 0
r1: .byte 0
b5: .byte 32, 1, 0 ; 32,1 : Init Graf
t6: .text "Avant : ", 0
t7: .text " ", 0
t8: .text ", motif plein : ", 0
t9: .text " ", 0
t10: .text ", rayures : ", 0
t11: .text " ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Avant : 0 0, motif plein : 3 3, rayures : 3 932,14 Copy Bits Trinity
Pose une zone source (décrite comme pour 12,3) dans la page de dessin, découpée par le rectangle de 32,2.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | action : 0 copie, 1 masquée, 2 couleur unie |
P1-P2 | addr | adresse du descripteur de 12 octets de la source |
P3-P4 | int16 | X (signé) |
P5-P6 | int16 | Y (signé) |
Sorties : aucune.
Tous les formats de source de 12,3 sont acceptés. L'exemple pose 8 pixels de 4 bits (1 à 8) en (100, 120) sous une découpe qui s'arrête avant x = 104 : seuls les quatre premiers paraissent. Comme pour 12,4, un bord gauche découpé est arrondi à un octet source entier. Hors du mode 0, la copie se fait pixel par pixel. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Blits the source area described at Parameters:1,2 (the 12 byte structure of Function 12,3, any source format) at Parameters:3,4 (X) and Parameters:5,6 (Y) of the draw page, with the blit action of Parameter:0 (0 copy, 1 masked, 2 solid), clipped to the clip rectangle. As Function 12,4, the left clip is rounded up to a whole source byte. Outside mode 0 the copy is done pixel by pixel (source values are reduced to their bit 0 in monochrome).
C (llvm-mos)
/* Copier une image dans la zone de dessin, découpée (groupe 32, fonction 14, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static uint8_t pixels[4] = {0x12, 0x34, 0x56, 0x78}; /* 8 pixels de 4 bits : 1 à 8 */
static uint8_t source[12]; /* descripteur de zone de 12,3 */
static Rect zone = {0, 0, 104, 240}; /* découpe : rien au-delà de x = 103 */
int main(void) {
putchar(12);
init_graf();
source[0] = (uint16_t)pixels & 0xFF; /* adresse en RAM du 6502 (page $00) */
source[1] = (uint16_t)pixels >> 8;
source[6] = 1; /* format 1 : paires de 4 bits */
source[9] = 1; /* hauteur */
source[10] = 8; /* largeur */
qd_rect(2, &zone); /* 32,2 */
libre();
ControlPort.params[0] = 0; /* P0 : action 0, copie */
ControlPort.params[1] = (uint16_t)source & 0xFF; /* P1-P2 : zone source */
ControlPort.params[2] = (uint16_t)source >> 8;
ControlPort.params[3] = 100; /* P3-P4 : X */
ControlPort.params[4] = 0;
ControlPort.params[5] = 120; /* P5-P6 : Y */
ControlPort.params[6] = 0;
uint8_t e = qd(14); /* Copy Bits */
uint8_t l[8];
for (uint8_t x = 0; x < 8; x++)
l[x] = px(100 + x, 120);
init_graf();
printf("Erreur %u ; x 100 a 107 :", e);
for (uint8_t x = 0; x < 8; x++)
printf(" %u", l[x]);
printf("\n");
return 0;
}Erreur 0 ; x 100 a 107 : 1 2 3 4 0 0 0 0Mad Pascal
// Copier une image dans la zone de dessin, découpée (groupe 32, fonction 14, Trinity).
program qd14;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
const pixels: array[0..3] of byte = ($12, $34, $56, $78); // 8 pixels de 4 bits : 1 à 8
var source: array[0..11] of byte; // descripteur de zone de 12,3
zone: Rect;
l: array[0..7] of byte;
x, e: byte;
begin
write(chr(12));
init_graf;
fillchar(@source, 12, 0);
source[0] := lo(word(@pixels)); // adresse en RAM du 6502 (page $00)
source[1] := hi(word(@pixels));
source[6] := 1; // format 1 : paires de 4 bits
source[9] := 1; // hauteur
source[10] := 8; // largeur
zone.g := 0; zone.h := 0; zone.d := 104; zone.b := 240; // découpe : rien au-delà de x = 103
qd_rect(2, @zone);
NeoWaitMessage;
NeoMessage.params[0] := 0; // P0 : action 0, copie
wordxParams[0] := word(@source); // P1-P2 : zone source
wordxParams[1] := 100; // P3-P4 : X
wordxParams[2] := 120; // P5-P6 : Y
e := qd(14); // Copy Bits
for x := 0 to 7 do l[x] := NeoGetPixel(100 + x, 120);
init_graf;
write('Erreur ', e, ' ; x 100 a 107 :');
for x := 0 to 7 do write(' ', l[x]);
writeln;
end.Erreur 0 ; x 100 a 107 : 1 2 3 4 0 0 0 0NeoBASIC
10 ' Copier une image dans la zone de dessin, decoupee (groupe 32, fonction 14, Trinity)
20 cls : gosub 9400
30 pp = alloc(4) : poke pp, $12 : poke pp + 1, $34 : poke pp + 2, $56 : poke pp + 3, $78 : ' 8 pixels de 4 bits : 1 a 8
40 s = alloc(12) : for i = 0 to 11 : poke s + i, 0 : next i
50 doke s, pp : poke s + 6, 1 : poke s + 9, 1 : poke s + 10, 8 : ' descripteur de 12,3 : format 1, hauteur 1, largeur 8
60 q = alloc(8) : g = 0 : h = 0 : d = 104 : b = 240 : gosub 8000 : a = q : f = 2 : gosub 9000 : ' decoupe : rien au-dela de x = 103
70 while peek($ff00) : wend
80 poke $ff04, 0 : doke $ff05, s : doke $ff07, 100 : doke $ff09, 120 : f = 14 : gosub 9110 : ' Copy Bits : action 0, en (100, 120)
90 l$ = "" : for x = 100 to 107 : l$ = l$ + " " + str$(point(x, 120)) : next x
100 gosub 9400
110 print "Erreur ";e;" ; x 100 a 107 :";l$
120 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Erreur 0 ; x 100 a 107 : 1 2 3 4 0 0 0 0Assembleur 65C02 (64tass)
; Copier une image dans la zone de dessin, découpée (groupe 32, fonction 14, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda ControlPort+2
sta e
ldx #0
_l3: phx
txa
clc
adc #100
ldy #120
jsr pixel
plx
sta l,x
inx
cpx #8
bne _l3
lda #<b4
ldx #>b4
jsr envoi
lda #<t5
ldx #>t5
jsr ecrire
lda e
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
ldx #0
_a7: lda #' '
jsr WriteCharacter
lda l,x
jsr decimal
inx
cpx #8
bne _a7
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
q: .word 0, 0, 104, 240 ; gauche, haut, droite, bas (droite et bas exclus)
pixels: .byte $12, $34, $56, $78 ; 8 pixels de 4 bits : 1 à 8
source: .word pixels ; descripteur de 12,3 : adresse en RAM du 6502...
.byte 0, 0 ; ... page $00, octet de bourrage
.word 0 ; pas
.byte 1, 0, 0, 1 ; format 1 (paires de 4 bits), transparent, uni, hauteur 1
.word 8 ; largeur
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 2, 2 ; découpe : rien au-delà de x = 103
.word q
b2: .byte 32, 14, 7, 0 ; Copy Bits : action 0, en (100, 120)
.word source, 100, 120
e: .byte 0
l: .fill 8
b4: .byte 32, 1, 0 ; 32,1 : Init Graf
t5: .text "Erreur ", 0
t6: .text " ; x 100 a 107 :", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Erreur 0 ; x 100 a 107 : 1 2 3 4 0 0 0 032,15 Set Font Trinity
Choisit la police proportionnelle utilisée par 32,16 et 32,17.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | page : $00 RAM du 6502, $90 mémoire graphique |
P1-P2 | addr | adresse de la police (0 en page 0 : police intégrée 6 × 8) |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si l'en-tête ou la taille ne vont pas |
Format NF1 : « NF », version 1, hauteur, premier caractère, nombre de caractères, espacement, octets par ligne (1 ou 2), puis pour chaque caractère sa largeur et une ligne par rangée, bit 7 = pixel de gauche. La police est lue sur place à chaque appel : elle doit rester en mémoire. L'exemple fabrique une police d'un seul caractère, « A », dessiné comme un cadre 8 × 8, l'écrit avec 32,16, puis essaie un en-tête faux avant de revenir à la police intégrée. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Selects the proportional font at page Parameter:0, address Parameters:1,2 (pages of Function 12,2 : $00 6502 RAM, $90 graphics RAM ; load a font file there with Function 3,2 or 12,1). Page 0 address 0 restores the built in 6x8 font. The font is read in place at each call, without copy. NF1 format (made by tools/mkfont.py of the fork archive) : "NF", version 1, height, first character, character count, spacing, bytes per row (1 or 2), then one glyph per character of width byte plus height rows, bit 7 = left pixel. Error 1 if the header or the size is invalid.
C (llvm-mos)
/* Choisir une police proportionnelle (groupe 32, fonction 15, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
/* Une police NF1 d'un seul caractère, « A » : en-tête puis largeur et 8 rangées (bit 7 = pixel de gauche). */
static const uint8_t police[] = {'N', 'F', 1, 8, 'A', 1, 1, 1, /* NF, version 1, hauteur 8, premier « A », 1 caractère, espacement 1, 1 octet par rangée */
8, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}; /* largeur 8 : un cadre */
static uint8_t choisir_police(uint8_t page, uint16_t adresse) { /* 32,15 Set Font */
libre();
ControlPort.params[0] = page; /* P0 : page ($00 RAM du 6502, $90 mémoire graphique) */
ControlPort.params[1] = adresse & 0xFF; /* P1-P2 : adresse */
ControlPort.params[2] = adresse >> 8;
return qd(15);
}
static void ecrire_qd(const uint8_t *s) { /* 32,16 Draw String : chaîne précédée de sa longueur */
libre();
ControlPort.params[0] = (uint16_t)s & 0xFF;
ControlPort.params[1] = (uint16_t)s >> 8;
qd(16);
}
static const uint8_t faux[] = {'X', 'F', 1, 8, 'A', 1, 1, 1};
static const uint8_t texte[] = "\x01" "A";
int main(void) {
putchar(12);
init_graf();
uint8_t e = choisir_police(0x00, (uint16_t)police); /* Set Font */
couleur(6);
qd_xy(5, 100, 100);
ecrire_qd(texte); /* 32,16 : le « A » de la police, un cadre 8x8 */
uint8_t coin = px(100, 100), milieu = px(104, 104);
uint8_t f = choisir_police(0x00, (uint16_t)faux); /* en-tête faux : refusé */
choisir_police(0x00, 0); /* page 0, adresse 0 : police intégrée */
init_graf();
printf("Police : erreur %u ; coin %u, milieu %u\n", e, coin, milieu);
printf("En-tete faux : erreur %u\n", f);
return 0;
}Police : erreur 0 ; coin 6, milieu 0
En-tete faux : erreur 1Mad Pascal
// Choisir une police proportionnelle (groupe 32, fonction 15, Trinity).
program qd15;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
// Une police NF1 d'un seul caractère, « A » : en-tête puis largeur et 8 rangées (bit 7 = pixel de gauche).
const police: array[0..16] of byte = (ord('N'), ord('F'), 1, 8, ord('A'), 1, 1, 1, // NF, version 1, hauteur 8, premier « A », 1 caractère, espacement 1, 1 octet par rangée
8, $FF, $81, $81, $81, $81, $81, $81, $FF); // largeur 8 : un cadre
function choisir_police(page: byte; adresse: word): byte; // 32,15 Set Font
begin
NeoWaitMessage;
NeoMessage.params[0] := page; // P0 : page ($00 RAM du 6502, $90 mémoire graphique)
wordxParams[0] := adresse; // P1-P2 : adresse
result := qd(15);
end;
procedure ecrire_qd(s: pointer); // 32,16 Draw String : chaîne précédée de sa longueur
begin
qd_rect(16, s);
end;
const faux: array[0..7] of byte = (ord('X'), ord('F'), 1, 8, ord('A'), 1, 1, 1);
texte: array[0..1] of byte = (1, ord('A')); // chaîne précédée de sa longueur
var e, f, coin, milieu: byte;
begin
write(chr(12));
init_graf;
e := choisir_police($00, word(@police)); // Set Font
couleur(6);
qd_xy(5, 100, 100);
ecrire_qd(@texte); // 32,16 : le « A » de la police, un cadre 8x8
coin := NeoGetPixel(100, 100);
milieu := NeoGetPixel(104, 104);
f := choisir_police($00, word(@faux)); // en-tête faux : refusé
choisir_police($00, 0); // page 0, adresse 0 : police intégrée
init_graf;
writeln('Police : erreur ', e, ' ; coin ', coin, ', milieu ', milieu);
writeln('En-tete faux : erreur ', f);
end.Police : erreur 0 ; coin 6, milieu 0
En-tete faux : erreur 1NeoBASIC
10 ' Choisir une police proportionnelle (groupe 32, fonction 15, Trinity)
20 cls : gosub 9400
30 po = alloc(17) : for i = 0 to 16 : read v : poke po + i, v : next i
40 data 78, 70, 1, 8, 65, 1, 1, 1 : ' NF, version 1, hauteur 8, premier A, 1 caractere, espacement 1, 1 octet par rangee
50 data 8, 255, 129, 129, 129, 129, 129, 129, 255 : ' largeur 8 : un cadre
60 fx = alloc(8) : for i = 0 to 7 : poke fx + i, peek(po + i) : next i : poke fx, asc("X") : ' en-tete faux
70 t = alloc(2) : poke t, 1 : poke t + 1, asc("A")
80 pg = 0 : ad = po : gosub 2000 : e1 = e : ' Set Font
90 c = 6 : gosub 9300 : x = 100 : y = 100 : f = 5 : gosub 9200
100 a = t : f = 16 : gosub 9000 : ' 32,16 : le A de la police, un cadre 8x8
110 co = point(100, 100) : mi = point(104, 104)
120 ad = fx : gosub 2000 : e2 = e : ' en-tete faux : refuse
130 ad = 0 : gosub 2000 : ' page 0, adresse 0 : police integree
140 gosub 9400
150 print "Police : erreur ";e1;" ; coin ";co;", milieu ";mi
160 print "En-tete faux : erreur ";e2
170 end
2000 ' Set Font : page pg, adresse ad
2010 while peek($ff00) : wend : poke $ff04, pg : doke $ff05, ad : f = 15 : gosub 9110
2020 return
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Police : erreur 0 ; coin 6, milieu 0
En-tete faux : erreur 1Assembleur 65C02 (64tass)
; Choisir une police proportionnelle (groupe 32, fonction 15, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda ControlPort+2
sta e1
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
lda #100
ldy #100
jsr pixel
sta co
lda #104
ldy #104
jsr pixel
sta mi
lda #<b5
ldx #>b5
jsr envoi
lda ControlPort+2
sta e2
lda #<b6
ldx #>b6
jsr envoi
lda #<b7
ldx #>b7
jsr envoi
lda #<t8
ldx #>t8
jsr ecrire
lda e1
jsr decimal
lda #<t9
ldx #>t9
jsr ecrire
lda co
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda mi
jsr decimal
lda #13
jsr WriteCharacter
lda #<t11
ldx #>t11
jsr ecrire
lda e2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
police: .text "NF" ; en-tête
.byte 1, 8, 'A', 1 ; version 1, hauteur 8, premier A, 1 caractère
.byte 1, 1 ; espacement 1, 1 octet par rangée
.byte 8, $FF, $81, $81, $81, $81, $81, $81, $FF ; largeur 8 : un cadre
faux: .text "XF" ; en-tête faux
.byte 1, 8, 'A', 1, 1, 1
texte: .byte 1, 'A'
b0: .byte 32, 1, 0 ; 32,1 : Init Graf
b1: .byte 32, 15, 3, 0 ; Set Font : page 0, adresse
.word police
e1: .byte 0
b2: .byte 32, 4, 1, 6 ; 32,4 : Set Pen Colour
b3: .byte 32, 5, 4 ; 32,5 : Move To
.word 100, 100
b4: .byte 32, 16, 2 ; 32,16 : le A de la police, un cadre 8x8
.word texte
co: .byte 0
mi: .byte 0
b5: .byte 32, 15, 3, 0 ; en-tête faux : refusé
.word faux
e2: .byte 0
b6: .byte 32, 15, 3, 0 ; page 0, adresse 0 : police intégrée
.word 0
b7: .byte 32, 1, 0 ; 32,1 : Init Graf
t8: .text "Police : erreur ", 0
t9: .text " ; coin ", 0
t10: .text ", milieu ", 0
t11: .text "En-tete faux : erreur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Police : erreur 0 ; coin 6, milieu 0
En-tete faux : erreur 132,16 Draw String Trinity
Écrit une chaîne avec la police en cours, coin haut gauche à la plume, dans la couleur de la plume ; la plume avance.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse de la chaîne, précédée de sa longueur |
Sorties : aucune.
Les pixels éteints des caractères ne touchent pas le fond (transparence). La plume avance de la largeur de chaque caractère plus l'espacement de la police : « AB » en police intégrée 6 × 8 la fait passer de x = 100 à 112. Les caractères absents de la police sont sautés sans avancer. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Draws the length-prefixed string at Parameters:0,1 with the current font, top left at the pen, set pixels in the pen colour, other pixels untouched (transparent), clipped ; the pen advances by the width of each glyph plus the font spacing. Characters absent from the font are skipped without advance.
C (llvm-mos)
/* Écrire un texte à la plume (groupe 32, fonction 16, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static int16_t plume_x, plume_y;
static uint8_t plume_c;
static void get_pen(void) { /* 32,6 Get Pen */
libre();
qd(6);
plume_x = ControlPort.params[0] | ControlPort.params[1] << 8;
plume_y = ControlPort.params[2] | ControlPort.params[3] << 8;
plume_c = ControlPort.params[4];
}
/* Une police NF1 d'un seul caractère, « A » : en-tête puis largeur et 8 rangées (bit 7 = pixel de gauche). */
static const uint8_t police[] = {'N', 'F', 1, 8, 'A', 1, 1, 1, /* NF, version 1, hauteur 8, premier « A », 1 caractère, espacement 1, 1 octet par rangée */
8, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}; /* largeur 8 : un cadre */
static uint8_t choisir_police(uint8_t page, uint16_t adresse) { /* 32,15 Set Font */
libre();
ControlPort.params[0] = page; /* P0 : page ($00 RAM du 6502, $90 mémoire graphique) */
ControlPort.params[1] = adresse & 0xFF; /* P1-P2 : adresse */
ControlPort.params[2] = adresse >> 8;
return qd(15);
}
static void ecrire_qd(const uint8_t *s) { /* 32,16 Draw String : chaîne précédée de sa longueur */
libre();
ControlPort.params[0] = (uint16_t)s & 0xFF;
ControlPort.params[1] = (uint16_t)s >> 8;
qd(16);
}
static const uint8_t texte[] = "\x02" "AB";
int main(void) {
putchar(12);
init_graf(); /* police intégrée 6x8 */
couleur(6);
qd_xy(5, 100, 100);
ecrire_qd(texte); /* Draw String : en haut à gauche à la plume */
get_pen();
uint8_t n = 0;
for (uint8_t y = 100; y < 108; y++)
for (uint8_t x = 100; x < 112; x++)
n += px(x, y) == 6;
init_graf();
printf("Plume apres AB : %d, %d ; pixels allumes : %u\n", plume_x, plume_y, n);
return 0;
}Plume apres AB : 112, 100 ; pixels allumes : 35Mad Pascal
// Écrire un texte à la plume (groupe 32, fonction 16, Trinity).
program qd16;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var plume_x, plume_y: smallint;
plume_c: byte;
procedure get_pen; // 32,6 Get Pen
begin
NeoWaitMessage;
qd(6);
plume_x := smallint(wordParams[0]);
plume_y := smallint(wordParams[1]);
plume_c := NeoMessage.params[4];
end;
// Une police NF1 d'un seul caractère, « A » : en-tête puis largeur et 8 rangées (bit 7 = pixel de gauche).
const police: array[0..16] of byte = (ord('N'), ord('F'), 1, 8, ord('A'), 1, 1, 1, // NF, version 1, hauteur 8, premier « A », 1 caractère, espacement 1, 1 octet par rangée
8, $FF, $81, $81, $81, $81, $81, $81, $FF); // largeur 8 : un cadre
function choisir_police(page: byte; adresse: word): byte; // 32,15 Set Font
begin
NeoWaitMessage;
NeoMessage.params[0] := page; // P0 : page ($00 RAM du 6502, $90 mémoire graphique)
wordxParams[0] := adresse; // P1-P2 : adresse
result := qd(15);
end;
procedure ecrire_qd(s: pointer); // 32,16 Draw String : chaîne précédée de sa longueur
begin
qd_rect(16, s);
end;
const texte: string[2] = 'AB';
var n, x, y: byte;
begin
write(chr(12));
init_graf; // police intégrée 6x8
couleur(6);
qd_xy(5, 100, 100);
ecrire_qd(@texte); // Draw String : en haut à gauche à la plume
get_pen;
n := 0;
for y := 100 to 107 do
for x := 100 to 111 do
if NeoGetPixel(x, y) = 6 then inc(n);
init_graf;
writeln('Plume apres AB : ', plume_x, ', ', plume_y, ' ; pixels allumes : ', n);
end.Plume apres AB : 112, 100 ; pixels allumes : 35NeoBASIC
10 ' Ecrire un texte a la plume (groupe 32, fonction 16, Trinity)
20 cls : gosub 9400 : ' police integree 6x8
30 t = alloc(3) : poke t, 2 : poke t + 1, asc("A") : poke t + 2, asc("B")
40 c = 6 : gosub 9300 : x = 100 : y = 100 : f = 5 : gosub 9200
50 a = t : f = 16 : gosub 9000 : ' Draw String : en haut a gauche a la plume
60 gosub 9500
70 n = 0 : for y = 100 to 107 : for x = 100 to 111 : if point(x, y) = 6 then n = n + 1
80 next x : next y
90 gosub 9400
100 print "Plume apres AB : ";px;", ";py;" ; pixels allumes : ";n
110 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9500 ' 32,6 Get Pen : px, py, pc
9510 while peek($ff00) : wend : f = 6 : gosub 9110
9520 px = deek($ff04) : py = deek($ff06) : pc = peek($ff08)
9530 if px > 32767 then px = px - 65536
9540 if py > 32767 then py = py - 65536
9550 returnPlume apres AB : 112, 100 ; pixels allumes : 35Assembleur 65C02 (64tass)
; Écrire un texte à la plume (groupe 32, fonction 16, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b5
ldx #>b5
jsr envoi
ldx #4
_c4: lda ControlPort+4,x
sta pen,x
dex
bpl _c4
stz n ; pixels de couleur 6 dans x 100 à 111, y 100 à 107
lda #100
sta yy
_y: lda #100
sta xx
_x: lda xx
ldy yy
jsr pixel
cmp #6
bne _nx
inc n
_nx: inc xx
lda xx
cmp #112
bne _x
inc yy
lda yy
cmp #108
bne _y
lda #<b6
ldx #>b6
jsr envoi
lda #<t7
ldx #>t7
jsr ecrire
lda pen
ldx pen+1
jsr dec16
lda #<t8
ldx #>t8
jsr ecrire
lda pen+2
ldx pen+2+1
jsr dec16
lda #<t9
ldx #>t9
jsr ecrire
lda n
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
texte: .byte 2
.text "AB"
n: .byte 0
xx: .byte 0
yy: .byte 0
b0: .byte 32, 1, 0 ; police intégrée 6x8
b1: .byte 32, 4, 1, 6 ; 32,4 : Set Pen Colour
b2: .byte 32, 5, 4 ; 32,5 : Move To
.word 100, 100
b3: .byte 32, 16, 2 ; Draw String : en haut à gauche à la plume
.word texte
b5: .byte 32, 6, 0 ; 32,6 : Get Pen
pen: .fill 5 ; x, y (16 bits), couleur
b6: .byte 32, 1, 0 ; 32,1 : Init Graf
t7: .text "Plume apres AB : ", 0
t8: .text ", ", 0
t9: .text " ; pixels allumes : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Plume apres AB : 112, 100 ; pixels allumes : 3532,17 Text Width Trinity
Rend la largeur en pixels qu'aurait une chaîne écrite par 32,16, sans rien dessiner.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse de la chaîne, précédée de sa longueur |
| Octets | Type | Rôle |
|---|---|---|
P2-P3 | uint16 | largeur en pixels |
En police intégrée, chaque caractère compte 6 pixels : « Neo6502 » en fait 42. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns in Parameters:2,3 the width in pixels the string at Parameters:0,1 would take with Draw String.
C (llvm-mos)
/* Mesurer un texte avant de l'écrire (groupe 32, fonction 17, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static const uint8_t texte[] = "\x07" "Neo6502";
static uint16_t largeur(const uint8_t *s) { /* Text Width */
libre();
ControlPort.params[0] = (uint16_t)s & 0xFF;
ControlPort.params[1] = (uint16_t)s >> 8;
qd(17);
return ControlPort.params[2] | ControlPort.params[3] << 8;
}
int main(void) {
init_graf(); /* police intégrée 6x8 */
printf("Neo6502 : %u pixels\n", largeur(texte));
return 0;
}Neo6502 : 42 pixelsMad Pascal
// Mesurer un texte avant de l'écrire (groupe 32, fonction 17, Trinity).
program qd17;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
const texte: string[7] = 'Neo6502';
var l: word;
begin
init_graf; // police intégrée 6x8
qd_rect(17, @texte); // Text Width
l := wordParams[1]; // P2-P3 : largeur en pixels
writeln('Neo6502 : ', l, ' pixels');
end.Neo6502 : 42 pixelsNeoBASIC
10 ' Mesurer un texte avant de l'ecrire (groupe 32, fonction 17, Trinity)
20 gosub 9400 : ' police integree 6x8
30 t = alloc(8) : t$ = "Neo6502" : poke t, len(t$) : for i = 1 to len(t$) : poke t + i, asc(mid$(t$, i, 1)) : next i
40 a = t : f = 17 : gosub 9000 : l = deek($ff06) : ' Text Width : largeur en P2-P3
50 print "Neo6502 : ";l;" pixels"
60 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Neo6502 : 42 pixelsAssembleur 65C02 (64tass)
; Mesurer un texte avant de l'écrire (groupe 32, fonction 17, 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 #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda ControlPort+6 ; P2-P3 : largeur en pixels
sta l
lda ControlPort+7
sta l+1
lda #<t2
ldx #>t2
jsr ecrire
lda l
ldx l+1
jsr dec16
lda #<t3
ldx #>t3
jsr ecrire
lda #13
jsr WriteCharacter
rts
texte: .byte 7
.text "Neo6502"
b0: .byte 32, 1, 0 ; police intégrée 6x8
b1: .byte 32, 17, 2 ; Text Width : largeur en P2-P3
.word texte
l: .word 0
t2: .text "Neo6502 : ", 0
t3: .text " pixels", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Neo6502 : 42 pixels32,18 Get Font Info Trinity
Rend la hauteur, le premier caractère et le nombre de caractères de la police en cours.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | hauteur en pixels |
P1 | uint8 | premier caractère |
P2 | uint8 | nombre de caractères |
La police intégrée fait 8 pixels de haut et couvre les 96 caractères de 32 (espace) à 127. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns the height of the current font in Parameter:0, its first character in Parameter:1 and its character count in Parameter:2.
C (llvm-mos)
/* Lire la hauteur et les caractères de la police (groupe 32, fonction 18, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
int main(void) {
init_graf(); /* police intégrée */
libre();
qd(18); /* Get Font Info */
printf("Hauteur %u, premier caractere %u, %u caracteres\n",
ControlPort.params[0], ControlPort.params[1], ControlPort.params[2]);
return 0;
}Hauteur 8, premier caractere 32, 96 caracteresMad Pascal
// Lire la hauteur et les caractères de la police (groupe 32, fonction 18, Trinity).
program qd18;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var h, p, n: byte;
begin
init_graf; // police intégrée
NeoWaitMessage;
qd(18); // Get Font Info
h := NeoMessage.params[0];
p := NeoMessage.params[1];
n := NeoMessage.params[2];
writeln('Hauteur ', h, ', premier caractere ', p, ', ', n, ' caracteres');
end.Hauteur 8, premier caractere 32, 96 caracteresNeoBASIC
10 ' Lire la hauteur et les caracteres de la police (groupe 32, fonction 18, Trinity)
20 gosub 9400 : ' police integree
30 while peek($ff00) : wend : f = 18 : gosub 9110 : ' Get Font Info
40 h = peek($ff04) : p = peek($ff05) : n = peek($ff06)
50 print "Hauteur ";h;", premier caractere ";p;", ";n;" caracteres"
60 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110Hauteur 8, premier caractere 32, 96 caracteresAssembleur 65C02 (64tass)
; Lire la hauteur et les caractères de la police (groupe 32, fonction 18, 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 #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda ControlPort+4 ; hauteur
sta h
lda ControlPort+5 ; premier caractère
sta pr
lda ControlPort+6 ; nombre de caractères
sta nb
lda #<t2
ldx #>t2
jsr ecrire
lda h
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda pr
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda nb
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda #13
jsr WriteCharacter
rts
b0: .byte 32, 1, 0 ; police intégrée
b1: .byte 32, 18, 0 ; Get Font Info
h: .byte 0
pr: .byte 0
nb: .byte 0
t2: .text "Hauteur ", 0
t3: .text ", premier caractere ", 0
t4: .text ", ", 0
t5: .text " caracteres", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Hauteur 8, premier caractere 32, 96 caracteres32,19 Toolbox Reset Trinity
Remet toute la boîte à outils de Trinity dans son état de départ : plus de fenêtre, de menu, de contrôle ni de dialogue, QuickDraw comme après 32,1.
Entrées : aucune.
Sorties : aucune.
Rien n'est dessiné ni effacé. La boîte à outils garde son état d'un programme à l'autre : selon la documentation de Trinity, NeoDOS doit appeler cette fonction au retour d'un programme, et un programme peut aussi l'appeler en premier. Contrairement à 32,1, elle ne doit pas être appelée tant que le programme a des fenêtres ouvertes. L'exemple change la plume et la découpe, puis les relit après l'appel. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Puts the whole toolbox back in its start up state (Trinity T-88) : no window, no menu (and the menu bar back to the full width, Function 35,9), no control, no dialog, event manager off, no resource file, QuickDraw as after 32,1. Nothing is drawn or erased. The toolbox otherwise keeps its state from one program to the next : NeoDOS is to call this when a program returns to it (T-88, asked of NeoDOS), so the next program does not inherit its menus or windows. A program may call it first thing as well. Unlike 32,1, which a program may call again while its windows exist.
C (llvm-mos)
/* Remettre toute la boîte à outils dans son état de départ (groupe 32, fonction 19, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* QuickDraw : une structure Rect = gauche, haut, droite, bas (16 bits signés ; droite et bas exclus). */
typedef struct { int16_t g, h, d, b; } Rect;
static uint8_t qd(uint8_t f) { /* appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur */
api(32, f);
return ControlPort.error;
}
static uint8_t qd_rect(uint8_t f, Rect *r) { /* appel 32,f sur un Rect : P0-P1 = adresse du Rect */
libre();
ControlPort.params[0] = (uint16_t)r & 0xFF;
ControlPort.params[1] = (uint16_t)r >> 8;
return qd(f);
}
static void qd_xy(uint8_t f, int16_t x, int16_t y) { /* 32,5 Move To ou 32,11 Line To */
libre();
ControlPort.params[0] = x & 0xFF;
ControlPort.params[1] = x >> 8;
ControlPort.params[2] = y & 0xFF;
ControlPort.params[3] = y >> 8;
qd(f);
}
static void couleur(uint8_t c) { /* 32,4 Set Pen Colour */
libre();
ControlPort.params[0] = c;
qd(4);
}
static void init_graf(void) { /* 32,1 Init Graf */
libre();
qd(1);
}
static uint8_t px(uint16_t x, uint16_t y) { /* 5,33 : couleur du pixel */
return neo_graphics_read_pixel(x, y);
}
static int16_t plume_x, plume_y;
static uint8_t plume_c;
static void get_pen(void) { /* 32,6 Get Pen */
libre();
qd(6);
plume_x = ControlPort.params[0] | ControlPort.params[1] << 8;
plume_y = ControlPort.params[2] | ControlPort.params[3] << 8;
plume_c = ControlPort.params[4];
}
static Rect clip;
static void get_clip(void) { /* 32,3 Get Clip : écrit le rectangle de découpe dans clip */
qd_rect(3, &clip);
}
static Rect zone = {10, 10, 50, 50};
int main(void) {
couleur(9); /* un état quelconque */
qd_xy(5, 30, 30);
qd_rect(2, &zone);
libre();
qd(19); /* Toolbox Reset */
get_pen();
get_clip();
printf("Plume : %d, %d, couleur %u ; decoupe : %d, %d, %d, %d\n",
plume_x, plume_y, plume_c, clip.g, clip.h, clip.d, clip.b);
return 0;
}Plume : 0, 0, couleur 15 ; decoupe : 0, 0, 320, 240Mad Pascal
// Remettre toute la boîte à outils dans son état de départ (groupe 32, fonction 19, Trinity).
program qd19;
uses crt, neo6502;
type Rect = record g, h, d, b: smallint; end; // gauche, haut, droite, bas (16 bits signés ; droite et bas exclus)
function qd(f: byte): byte; // appel 32,f (paramètres déjà posés) ; rend l'indicateur d'erreur
begin
NeoSendMessage(32, f);
NeoWaitMessage;
result := NeoMessage.error;
end;
function qd_rect(f: byte; r: pointer): byte; // appel 32,f sur un Rect : P0-P1 = adresse du Rect
begin
NeoWaitMessage;
wordParams[0] := word(r);
result := qd(f);
end;
procedure qd_xy(f: byte; x, y: smallint); // 32,5 Move To ou 32,11 Line To
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
qd(f);
end;
procedure couleur(c: byte); // 32,4 Set Pen Colour
begin
NeoWaitMessage;
NeoMessage.params[0] := c;
qd(4);
end;
procedure init_graf; // 32,1 Init Graf
begin
NeoWaitMessage;
qd(1);
end;
var plume_x, plume_y: smallint;
plume_c: byte;
procedure get_pen; // 32,6 Get Pen
begin
NeoWaitMessage;
qd(6);
plume_x := smallint(wordParams[0]);
plume_y := smallint(wordParams[1]);
plume_c := NeoMessage.params[4];
end;
var clip: Rect;
procedure get_clip; // 32,3 Get Clip : écrit le rectangle de découpe dans clip
begin
qd_rect(3, @clip);
end;
var zone: Rect;
begin
zone.g := 10; zone.h := 10; zone.d := 50; zone.b := 50;
couleur(9); // un état quelconque
qd_xy(5, 30, 30);
qd_rect(2, @zone);
NeoWaitMessage;
qd(19); // Toolbox Reset
get_pen;
get_clip;
writeln('Plume : ', plume_x, ', ', plume_y, ', couleur ', plume_c, ' ; decoupe : ', clip.g, ', ', clip.h, ', ', clip.d, ', ', clip.b);
end.Plume : 0, 0, couleur 15 ; decoupe : 0, 0, 320, 240NeoBASIC
10 ' Remettre toute la boite a outils dans son etat de depart (groupe 32, fonction 19, Trinity)
20 k = alloc(8) : q = alloc(8) : g = 10 : h = 10 : d = 50 : b = 50 : gosub 8000
30 c = 9 : gosub 9300 : x = 30 : y = 30 : f = 5 : gosub 9200 : a = q : f = 2 : gosub 9000 : ' un etat quelconque
40 while peek($ff00) : wend : f = 19 : gosub 9110 : ' Toolbox Reset
50 gosub 9500 : gosub 9600
60 print "Plume : ";px;", ";py;", couleur ";pc;" ; decoupe : ";cg;", ";ch;", ";cd;", ";cb
70 end
8000 ' Rect en q : gauche g, haut h, droite d, bas b (16 bits signes ; droite et bas exclus)
8010 doke q, g & $ffff : doke q + 2, h & $ffff : doke q + 4, d & $ffff : doke q + 6, b & $ffff
8020 return
9000 ' appel 32,f sur l'adresse a (P0-P1) ; erreur dans e
9010 while peek($ff00) : wend : doke $ff04, a
9100 ' appel 32,f, parametres deja poses ; erreur dans e
9110 poke $ff01, f : poke $ff00, 32
9120 while peek($ff00) : wend : e = peek($ff02)
9130 return
9200 ' 32,f en (x, y) : 5 Move To, 11 Line To
9210 while peek($ff00) : wend : doke $ff04, x & $ffff : doke $ff06, y & $ffff : goto 9110
9300 ' 32,4 Set Pen Colour c
9310 while peek($ff00) : wend : poke $ff04, c : f = 4 : goto 9110
9400 ' 32,1 Init Graf
9410 while peek($ff00) : wend : f = 1 : goto 9110
9500 ' 32,6 Get Pen : px, py, pc
9510 while peek($ff00) : wend : f = 6 : gosub 9110
9520 px = deek($ff04) : py = deek($ff06) : pc = peek($ff08)
9530 if px > 32767 then px = px - 65536
9540 if py > 32767 then py = py - 65536
9550 return
9600 ' 32,3 Get Clip dans le Rect k ; valeurs dans cg, ch, cd, cb
9610 a = k : f = 3 : gosub 9000
9620 cg = deek(k) : ch = deek(k + 2) : cd = deek(k + 4) : cb = deek(k + 6)
9630 returnPlume : 0, 0, couleur 15 ; decoupe : 0, 0, 320, 240Assembleur 65C02 (64tass)
; Remettre toute la boîte à outils dans son état de départ (groupe 32, fonction 19, 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 #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b5
ldx #>b5
jsr envoi
ldx #4
_c4: lda ControlPort+4,x
sta pen,x
dex
bpl _c4
lda #<b6
ldx #>b6
jsr envoi
lda #<t7
ldx #>t7
jsr ecrire
lda pen
ldx pen+1
jsr dec16
lda #<t8
ldx #>t8
jsr ecrire
lda pen+2
ldx pen+2+1
jsr dec16
lda #<t9
ldx #>t9
jsr ecrire
lda pen+4
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda k
ldx k+1
jsr dec16
lda #<t11
ldx #>t11
jsr ecrire
lda k+2
ldx k+2+1
jsr dec16
lda #<t12
ldx #>t12
jsr ecrire
lda k+4
ldx k+4+1
jsr dec16
lda #<t13
ldx #>t13
jsr ecrire
lda k+6
ldx k+6+1
jsr dec16
lda #13
jsr WriteCharacter
rts
q: .word 10, 10, 50, 50 ; gauche, haut, droite, bas (droite et bas exclus)
k: .fill 8
b0: .byte 32, 4, 1, 9 ; un état quelconque : couleur 9...
b1: .byte 32, 5, 4 ; 32,5 : Move To
.word 30, 30
b2: .byte 32, 2, 2 ; ... plume en (30, 30), découpe réduite
.word q
b3: .byte 32, 19, 0 ; Toolbox Reset
b5: .byte 32, 6, 0 ; 32,6 : Get Pen
pen: .fill 5 ; x, y (16 bits), couleur
b6: .byte 32, 3, 2 ; 32,3 : Get Clip
.word k
t7: .text "Plume : ", 0
t8: .text ", ", 0
t9: .text ", couleur ", 0
t10: .text " ; decoupe : ", 0
t11: .text ", ", 0
t12: .text ", ", 0
t13: .text ", ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
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
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Plume : 0, 0, couleur 15 ; decoupe : 0, 0, 320, 240