Groupe 10 — Entrées-sorties UEXT Officiel
10,1 UExt Initialise · 10,2 Write GPIO · 10,3 Read GPIO · 10,4 Set Port Direction · 10,5 Write I2C · 10,6 Read I2C · 10,7 Read Analog · 10,8 I2C Status · 10,9 Read I2C Block · 10,10 Write I2C Block · 10,11 Read SPI Block · 10,12 Write SPI Block · 10,13 Read UART Block · 10,14 Write UART Block · 10,15 Set UART Speed and Protocol · 10,16 Write byte to UART · 10,17 Read byte from UART · 10,18 Check if Byte Available · 10,19 Route UART to USB CDC modem
Le connecteur UEXT a 10 broches, désignées par leur numéro : 1 le 3,3 V, 2 la masse, 3 TXD et 4 RXD (port série), 5 SCL et 6 SDA (I2C), 7 MISO, 8 MOSI, 9 SCK et 10 SSEL (SPI). Les broches 3 à 10 servent aussi d'entrées-sorties simples ; 3, 4, 8 et 9 peuvent lire une tension (entrée analogique).
Utiliser l'I2C, le SPI ou régler le port série réserve leurs broches : les lire ou les écrire comme broches simples donne alors l'erreur 1, jusqu'à 10,1. Sur la carte, Trinity démarre son port de débogage sur TXD et RXD : les broches 3 et 4 lui appartiennent, même après 10,1 (dans l'émulateur, elles sont libres).
Au banc, Phosphoneo n'a rien de branché sur le port UEXT : ses réponses (niveau d'une entrée, valeur analogique, octets I2C ou SPI) sont des valeurs factices. Les exemples de ces fonctions sont vérifiés (l'appel est fait, sans erreur), mais leur sortie n'est pas reproduite. Celles qui ne dépendent que du firmware (verrou de sortie, sens, broches réservées, erreurs, port série sans rien de branché) sont publiées comme ailleurs.
10,1 UExt Initialise Officiel
Remet les entrées-sorties UEXT dans leur état de départ : broches 3 à 10 en entrée, verrous à 0, broches réservées rendues.
Entrées : aucune.
Sorties : aucune.
L'exemple écrit en I2C, ce qui réserve les broches 5 et 6 : la broche 5 est refusée (erreur 1), puis acceptée après 10,1. Les broches du port de débogage (3 et 4 sur la carte) restent réservées. En NeoBASIC, clear (et donc run) fait cet appel ; comme clear efface aussi les variables, l'exemple NeoBASIC écrit la boîte aux lettres.
Mots-clés NeoBASIC qui font cet appel : clear
Texte de la documentation du firmware (anglais)
Initialise the UExt I/O system. This resets the IO system to its default state, where all UEXT pins are I/O pins, inputs and enabled.
C (llvm-mos)
/* Libérer les broches prises par l'I2C (groupe 10, fonction 1). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t ecrire(uint8_t broche, uint8_t v) { /* 10,2 : rend l'indicateur d'erreur */
libre();
ControlPort.params[0] = broche;
ControlPort.params[1] = v;
api(10, 2);
return ControlPort.error;
}
int main(void) {
neo_uext_i2c_write(0x50, 0, 0); /* 10,5 : l'I2C prend les broches 5 (SCL) et 6 (SDA) */
uint8_t e1 = ecrire(5, 1);
neo_uext_init(); /* UExt Initialise : toutes les broches en entrée, libres */
uint8_t e2 = ecrire(5, 1);
printf("Apres 10,5 : broche 5, erreur %u\n", e1);
printf("Apres 10,1 : broche 5, erreur %u\n", e2);
return 0;
}Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0Mad Pascal
// Libérer les broches prises par l'I2C (groupe 10, fonction 1).
program uext1;
uses crt, neo6502, neo6502uext;
var e1, e2: byte;
function ecrire(broche, v: byte): byte; // 10,2 : rend l'indicateur d'erreur
begin
NeoWriteGPIO(broche, v);
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
NeoWriteI2C($50, 0, 0); // 10,5 : l'I2C prend les broches 5 (SCL) et 6 (SDA)
e1 := ecrire(5, 1);
NeoUExtInitialize; // UExt Initialise : toutes les broches en entrée, libres
e2 := ecrire(5, 1);
writeln('Apres 10,5 : broche 5, erreur ', e1);
writeln('Apres 10,1 : broche 5, erreur ', e2);
end.Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0NeoBASIC
10 ' Liberer les broches prises par l'I2C (groupe 10, fonction 1)
20 iwrite $50, 0, 0 : ' 10,5 : l'I2C prend les broches 5 (SCL) et 6 (SDA)
30 b = 5 : v = 1 : gosub 1000 : e1 = e
40 while peek($ff00) : wend : poke $ff01, 1 : poke $ff00, 10 : ' UExt Initialise (clear le fait aussi, mais efface les variables)
50 gosub 1000 : e2 = e
60 print "Apres 10,5 : broche 5, erreur ";e1
70 print "Apres 10,1 : broche 5, erreur ";e2
80 end
1000 ' 10,2 : ecrire v sur la broche b ; erreur dans e
1010 while peek($ff00) : wend : poke $ff04, b : poke $ff05, v : poke $ff01, 2 : poke $ff00, 10
1020 while peek($ff00) : wend : e = peek($ff02)
1030 returnApres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0Assembleur 65C02 (64tass)
; Libérer les broches prises par l'I2C (groupe 10, fonction 1).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<i2c
ldx #>i2c
jsr envoi
lda #<ecr5
ldx #>ecr5
jsr envoi
lda ControlPort+2
sta e1
lda #<init
ldx #>init
jsr envoi
lda #<ecr5
ldx #>ecr5
jsr envoi
lda ControlPort+2
sta e2
lda #<t0
ldx #>t0
jsr ecrire
lda e1
jsr decimal
lda #13
jsr WriteCharacter
lda #<t1
ldx #>t1
jsr ecrire
lda e2
jsr decimal
lda #13
jsr WriteCharacter
rts
i2c: .byte 10, 5, 3, $50, 0, 0 ; 10,5 : l'I2C prend les broches 5 (SCL) et 6 (SDA)
ecr5: .byte 10, 2, 2, 5, 1 ; 10,2 : broche 5, valeur 1
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
t0: .text "Apres 10,5 : broche 5, erreur ", 0
t1: .text "Apres 10,1 : broche 5, erreur ", 0
e1: .byte 0
e2: .byte 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
; 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 0Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 010,2 Write GPIO Officiel
Écrit le verrou de sortie d'une broche ; il n'apparaît sur la broche que si elle est en sortie.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | broche (3 à 10) |
P1 | uint8 | 0 bas, autre valeur haut |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si la broche n'existe pas ou est réservée |
Le verrou garde la valeur même en entrée : repasser la broche en sortie (10,4) la remet sur la broche. En sortie, 10,3 relit le verrou : l'exemple relit donc 255 puis 0, sans rien brancher. La broche 2 (la masse) est refusée. En NeoBASIC, pin n, v fait cet appel (et pin(n) rend 1 ou 0, pas 255 ou 0).
Mots-clés NeoBASIC qui font cet appel : pin
Texte de la documentation du firmware (anglais)
This copies the value Parameter:1 to the output latch for UEXT pin Parameter:0. This will only display on the output pin if it is enabled, and its direction is set to "Output" direction.
C (llvm-mos)
/* Écrire le verrou de sortie d'une broche (groupe 10, fonction 2). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t ecrire(uint8_t broche, uint8_t v) { /* Write GPIO : rend l'indicateur d'erreur */
libre();
ControlPort.params[0] = broche;
ControlPort.params[1] = v;
api(10, 2);
return ControlPort.error;
}
int main(void) {
neo_uext_init(); /* 10,1 */
neo_uext_gpio_set_direction(10, NEO_UEXT_OUTPUT); /* 10,4 : broche 10 en sortie */
ecrire(10, 1);
uint8_t haut = neo_uext_gpio_read(10); /* 10,3 : en sortie, on relit le verrou */
ecrire(10, 0);
uint8_t bas = neo_uext_gpio_read(10);
uint8_t e = ecrire(2, 1); /* la broche 2 du connecteur est la masse */
neo_uext_init(); /* tout remettre en entrée */
printf("Broche 10 : %u puis %u\n", haut, bas);
printf("Broche 2 : erreur %u\n", e);
return 0;
}Broche 10 : 255 puis 0
Broche 2 : erreur 1Mad Pascal
// Écrire le verrou de sortie d'une broche (groupe 10, fonction 2).
program uext2;
uses crt, neo6502, neo6502uext;
var haut, bas, e: byte;
function ecrire(broche, v: byte): byte; // 10,2 : rend l'indicateur d'erreur
begin
NeoWriteGPIO(broche, v);
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
NeoUExtInitialize; // 10,1
NeoSetDirection(10, GPIO_PINMODE_OUTPUT); // 10,4 : broche 10 en sortie
ecrire(10, 1); // Write GPIO
haut := NeoReadGPIO(10); // 10,3 : en sortie, on relit le verrou
ecrire(10, 0);
bas := NeoReadGPIO(10);
e := ecrire(2, 1); // la broche 2 du connecteur est la masse
NeoUExtInitialize; // tout remettre en entrée
writeln('Broche 10 : ', haut, ' puis ', bas);
writeln('Broche 2 : erreur ', e);
end.Broche 10 : 255 puis 0
Broche 2 : erreur 1NeoBASIC
10 ' Ecrire le verrou de sortie d'une broche (groupe 10, fonction 2)
20 pin 10, output : ' 10,4 : broche 10 en sortie
30 pin 10, 1 : h = pin(10) : ' Write GPIO, puis 10,3 : en sortie, on relit le verrou
40 pin 10, 0 : l = pin(10)
50 b = 2 : v = 1 : gosub 1000 : ' la broche 2 du connecteur est la masse
60 pin 10, input : ' remettre en entree
70 print "Broche 10 : ";h;" puis ";l
80 print "Broche 2 : erreur ";e
90 end
1000 ' 10,2 : ecrire v sur la broche b ; erreur dans e
1010 while peek($ff00) : wend : poke $ff04, b : poke $ff05, v : poke $ff01, 2 : poke $ff00, 10
1020 while peek($ff00) : wend : e = peek($ff02)
1030 returnBroche 10 : 1 puis 0
Broche 2 : erreur 1Assembleur 65C02 (64tass)
; Écrire le verrou de sortie d'une broche (groupe 10, fonction 2).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<init
ldx #>init
jsr envoi
lda #<sortie
ldx #>sortie
jsr envoi
lda #<haut
ldx #>haut
jsr envoi
lda #10
jsr lire
sta h
lda #<bas
ldx #>bas
jsr envoi
lda #10
jsr lire
sta l
lda #<masse
ldx #>masse
jsr envoi
lda ControlPort+2
sta e
lda #<init
ldx #>init
jsr envoi
; tout remettre en entrée
lda #<t0
ldx #>t0
jsr ecrire
lda h
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
lda l
jsr decimal
lda #13
jsr WriteCharacter
lda #<t2
ldx #>t2
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
; 10,3 : niveau de la broche A (0 ou 255), rendu dans A.
lire: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #10
ldx #3 ; 10,3 : Read GPIO
jsr appel
lda ControlPort+4
rts
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
sortie: .byte 10, 4, 2, 10, 2 ; 10,4 : broche 10 en sortie
haut: .byte 10, 2, 2, 10, 1 ; 10,2 : broche 10, valeur 1 (Write GPIO)
bas: .byte 10, 2, 2, 10, 0 ; 10,2 : broche 10, valeur 0
masse: .byte 10, 2, 2, 2, 1 ; 10,2 : broche 2, valeur 1 : la broche 2 du connecteur est la masse
t0: .text "Broche 10 : ", 0
t1: .text " puis ", 0
t2: .text "Broche 2 : erreur ", 0
h: .byte 0
l: .byte 0
e: .byte 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
; 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 0Broche 10 : 255 puis 0
Broche 2 : erreur 110,3 Read GPIO Officiel
Lit une broche : son niveau si elle est en entrée, son verrou si elle est en sortie.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | broche (3 à 10) |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 0 bas, 255 ($FF) haut |
erreur | uint8 | 1 si la broche n'existe pas ou est réservée |
Une entrée en l'air (rien de branché) peut se lire haute ou basse. En NeoBASIC, pin(n) fait cet appel et rend 1 ou 0.
Mots-clés NeoBASIC qui font cet appel : pin()
Texte de la documentation du firmware (anglais)
If the pin is set to "Input" direction, reads the level on pin on UEXT port Parameter:0. If it is set to "Output" direction, reads the output latch for pin on UEXT port Parameter:0. If the read is successful, the result will be in Parameter:0.
C (llvm-mos)
/* Lire le niveau d'une broche en entrée (groupe 10, fonction 3). */
#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)
;
}
int main(void) {
neo_uext_init(); /* 10,1 : toutes les broches en entrée */
uint8_t v = neo_uext_gpio_read(7); /* Read GPIO : 0 (bas) ou 255 (haut) */
printf("Broche 7 : %s\n", v ? "haut" : "bas");
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Lire le niveau d'une broche en entrée (groupe 10, fonction 3).
program uext3;
uses crt, neo6502, neo6502uext;
var v: byte;
begin
NeoUExtInitialize; // 10,1 : toutes les broches en entrée
v := NeoReadGPIO(7); // Read GPIO : 0 (bas) ou 255 (haut)
if v <> 0 then writeln('Broche 7 : haut') else writeln('Broche 7 : bas');
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Lire le niveau d'une broche en entree (groupe 10, fonction 3)
20 v = pin(7) : ' Read GPIO (au lancement, run remet les broches en entree)
30 n$ = "bas" : if v then n$ = "haut"
40 print "Broche 7 : ";n$Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Lire le niveau d'une broche en entrée (groupe 10, fonction 3).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<init
ldx #>init
jsr envoi
lda #7
jsr lire ; Read GPIO : 0 (bas) ou 255 (haut)
bne _haut
lda #<tb
ldx #>tb
jsr ecrire
rts
_haut: lda #<th
ldx #>th
jsr ecrire
rts
; 10,3 : niveau de la broche A (0 ou 255), rendu dans A.
lire: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #10
ldx #3 ; 10,3 : Read GPIO
jsr appel
lda ControlPort+4
rts
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
tb: .text "Broche 7 : bas", 13, 0
th: .text "Broche 7 : haut", 13, 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,4 Set Port Direction Officiel
Choisit le sens d'une broche : entrée, sortie ou entrée analogique.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | broche (3 à 10) |
P1 | uint8 | 1 entrée, 2 sortie, 3 entrée analogique |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si la broche n'existe pas, est réservée, ou n'a pas d'entrée analogique |
Seules les broches 3, 4, 8 et 9 ont une entrée analogique : la broche 10 est refusée, la 8 acceptée. Passer en sortie met aussitôt le verrou (10,2) sur la broche. En NeoBASIC, pin n, input, pin n, output et pin n, analog font cet appel (avec une virgule) et lèvent une erreur de plage en cas d'échec.
Mots-clés NeoBASIC qui font cet appel : pin
Texte de la documentation du firmware (anglais)
Set the port direction for UEXT Port Parameter:0 to the value in Parameter:1. This can be $01 (Input), $02 (Output), or $03 (Analogue Input).
C (llvm-mos)
/* Choisir le sens d'une broche (groupe 10, fonction 4). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t sens(uint8_t broche, uint8_t s) { /* Set Port Direction : rend l'indicateur d'erreur */
libre();
ControlPort.params[0] = broche;
ControlPort.params[1] = s; /* 1 entrée, 2 sortie, 3 entrée analogique */
api(10, 4);
return ControlPort.error;
}
int main(void) {
neo_uext_init(); /* 10,1 */
uint8_t a = sens(10, 3); /* broche 10 : pas d'entrée analogique */
uint8_t b = sens(8, 3); /* broche 8 : analogique possible */
uint8_t c = sens(10, 2);
neo_uext_init(); /* tout remettre en entrée */
printf("Broche 10 en analogique : erreur %u\n", a);
printf("Broche 8 en analogique : erreur %u\n", b);
printf("Broche 10 en sortie : erreur %u\n", c);
return 0;
}Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0Mad Pascal
// Choisir le sens d'une broche (groupe 10, fonction 4).
program uext4;
uses crt, neo6502, neo6502uext;
var a, b, c: byte;
function sens(broche, s: byte): byte; // Set Port Direction : rend l'indicateur d'erreur
begin
NeoSetDirection(broche, s); // 1 entrée, 2 sortie, 3 entrée analogique
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
NeoUExtInitialize; // 10,1
a := sens(10, GPIO_PINMODE_ANALOGUE); // broche 10 : pas d'entrée analogique
b := sens(8, GPIO_PINMODE_ANALOGUE); // broche 8 : analogique possible
c := sens(10, GPIO_PINMODE_OUTPUT);
NeoUExtInitialize; // tout remettre en entrée
writeln('Broche 10 en analogique : erreur ', a);
writeln('Broche 8 en analogique : erreur ', b);
writeln('Broche 10 en sortie : erreur ', c);
end.Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0NeoBASIC
10 ' Choisir le sens d'une broche (groupe 10, fonction 4)
20 b = 10 : s = 3 : gosub 1000 : a = e : ' broche 10 : pas d'entree analogique
30 b = 8 : s = 3 : gosub 1000 : c8 = e : ' broche 8 : analogique possible
40 b = 10 : s = 2 : gosub 1000 : c10 = e
50 pin 8, input : pin 10, input : ' remettre en entree
60 print "Broche 10 en analogique : erreur ";a
70 print "Broche 8 en analogique : erreur ";c8
80 print "Broche 10 en sortie : erreur ";c10
90 end
1000 ' Set Port Direction : broche b, sens s (1 entree, 2 sortie, 3 analogique) ; erreur dans e
1010 while peek($ff00) : wend : poke $ff04, b : poke $ff05, s : poke $ff01, 4 : poke $ff00, 10
1020 while peek($ff00) : wend : e = peek($ff02)
1030 returnBroche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0Assembleur 65C02 (64tass)
; Choisir le sens d'une broche (groupe 10, fonction 4).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<init
ldx #>init
jsr envoi
lda #<s10a
ldx #>s10a
jsr envoi
lda ControlPort+2
sta a
lda #<s8a
ldx #>s8a
jsr envoi
lda ControlPort+2
sta b
lda #<s10s
ldx #>s10s
jsr envoi
lda ControlPort+2
sta c
lda #<init
ldx #>init
jsr envoi
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #13
jsr WriteCharacter
lda #<t1
ldx #>t1
jsr ecrire
lda b
jsr decimal
lda #13
jsr WriteCharacter
lda #<t2
ldx #>t2
jsr ecrire
lda c
jsr decimal
lda #13
jsr WriteCharacter
rts
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
s10a: .byte 10, 4, 2, 10, 3 ; 10,4 : broche 10, analogique : impossible
s8a: .byte 10, 4, 2, 8, 3 ; 10,4 : broche 8, analogique : possible
s10s: .byte 10, 4, 2, 10, 2 ; 10,4 : broche 10, sortie
t0: .text "Broche 10 en analogique : erreur ", 0
t1: .text "Broche 8 en analogique : erreur ", 0
t2: .text "Broche 10 en sortie : erreur ", 0
a: .byte 0
b: .byte 0
c: .byte 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
; 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 0Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 010,5 Write I2C Officiel
Écrit un octet dans un registre d'un périphérique I2C.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | adresse du périphérique (7 bits) |
P1 | uint8 | registre |
P2 | uint8 | valeur |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le transfert n'est pas complet |
La documentation du firmware dit qu'aucune erreur n'est signalée si le périphérique est absent ; le code de la carte rend pourtant 1 quand l'écriture n'aboutit pas, ce qui est le cas sans périphérique (non vérifié sur la carte). Le premier appel I2C réserve les broches 5 et 6. En NeoBASIC, iwrite dev, reg, val fait cet appel.
Mots-clés NeoBASIC qui font cet appel : iwrite
Texte de la documentation du firmware (anglais)
Write to I2C Device Parameter:0, Register Parameter:1, value Parameter:2. No error is flagged if the device is not present.
C (llvm-mos)
/* Écrire un registre d'un périphérique I2C (groupe 10, fonction 5). */
#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)
;
}
int main(void) {
libre();
ControlPort.params[0] = 0x50; /* P0 : adresse du périphérique (une EEPROM 24C02, par exemple) */
ControlPort.params[1] = 0x00; /* P1 : registre */
ControlPort.params[2] = 0x42; /* P2 : valeur */
api(10, 5); /* Write I2C */
printf("Ecriture en $50 : erreur %u\n", ControlPort.error);
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Écrire un registre d'un périphérique I2C (groupe 10, fonction 5).
program uext5;
uses crt, neo6502, neo6502uext;
var e: byte;
begin
NeoWriteI2C($50, $00, $42); // Write I2C : périphérique $50 (une EEPROM 24C02, par exemple), registre 0, valeur $42
NeoWaitMessage;
e := NeoMessage.error;
writeln('Ecriture en $50 : erreur ', e);
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Ecrire un registre d'un peripherique I2C (groupe 10, fonction 5)
20 iwrite $50, 0, $42 : ' Write I2C : peripherique $50 (une EEPROM 24C02, par exemple), registre 0, valeur $42
30 e = peek($ff02)
40 print "Ecriture en $50 : erreur ";eVérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Écrire un registre d'un périphérique I2C (groupe 10, fonction 5).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<reg
ldx #>reg
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
reg: .byte 10, 5, 3, $50, 0, $42 ; Write I2C : périphérique $50 (une EEPROM 24C02, par exemple), registre 0, valeur $42
t0: .text "Ecriture en $50 : erreur ", 0
e: .byte 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,6 Read I2C Officiel
Lit un octet dans un registre d'un périphérique I2C.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | adresse du périphérique |
P1 | uint8 | registre |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | valeur lue |
erreur | uint8 | 1 si le périphérique ne répond pas |
L'appel écrit le numéro de registre, puis lit un octet. L'exemple vérifie d'abord la présence du périphérique (10,8). En NeoBASIC, iread(dev, reg) fait cet appel.
Mots-clés NeoBASIC qui font cet appel : iread()
Texte de la documentation du firmware (anglais)
Read from I2C Device Parameter:0, Register Parameter:1. If the read is successful, the result will be in Parameter:0. If the device is not present, this will flag an error. Use FUNCTION 10,2 first, to check for its presence.
C (llvm-mos)
/* Lire un registre d'un périphérique I2C (groupe 10, fonction 6). */
#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)
;
}
int main(void) {
if (!neo_uext_i2c_status(0x50)) { /* 10,8 : périphérique présent ? */
printf("Rien en $50\n");
return 0;
}
uint8_t v = neo_uext_i2c_read(0x50, 0x00); /* Read I2C : registre 0 */
printf("Registre 0 de $50 : %u\n", v);
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Lire un registre d'un périphérique I2C (groupe 10, fonction 6).
program uext6;
uses crt, neo6502, neo6502uext;
var v: byte;
begin
if NeoCheckI2C($50) = 0 then // 10,8 : périphérique présent ?
writeln('Rien en $50')
else begin
v := NeoReadI2C($50, $00); // Read I2C : registre 0
writeln('Registre 0 de $50 : ', v);
end;
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Lire un registre d'un peripherique I2C (groupe 10, fonction 6)
20 if idevice($50) = 0 then print "Rien en $50" : end : ' 10,8 : peripherique present ?
30 v = iread($50, 0) : ' Read I2C : registre 0
40 print "Registre 0 de $50 : ";vVérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Lire un registre d'un périphérique I2C (groupe 10, fonction 6).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<etat
ldx #>etat
jsr envoi
lda ControlPort+4 ; non nul : présent
bne _la
lda #<t0
ldx #>t0
jsr ecrire
rts
_la: lda #<reg
ldx #>reg
jsr envoi
lda ControlPort+4
sta v
lda #<t1
ldx #>t1
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
rts
etat: .byte 10, 8, 1, $50 ; 10,8 : périphérique $50 présent ?
reg: .byte 10, 6, 2, $50, 0 ; Read I2C : registre 0
t0: .text "Rien en $50", 13, 0
t1: .text "Registre 0 de $50 : ", 0
v: .byte 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,7 Read Analog Officiel
Lit la tension d'une broche réglée en entrée analogique, de 0 à 4095 pour 0 à 3,3 V.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | broche (3, 4, 8 ou 9) |
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | uint16 | valeur, 0 à 4095 |
erreur | uint8 | 1 broche sans entrée analogique, 2 broche pas réglée en analogique (10,4) |
En millivolts : valeur × 3300 / 4095. L'exemple montre d'abord les deux erreurs (2 sur la broche 8 pas encore réglée, 1 sur la broche 10), vérifiées au banc ; la valeur lue, elle, dépend de ce qui est branché. En NeoBASIC, analog(n) fait cet appel.
Mots-clés NeoBASIC qui font cet appel : analog()
Texte de la documentation du firmware (anglais)
Read the analogue value on UEXT Pin Parameter:0. This has to be set to analogue type to work. Returns a value from 0..4095 stored in Parameters:0,1, which represents an input value of 0 to 3.3 volts.
C (llvm-mos)
/* Lire une entrée analogique (groupe 10, fonction 7). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint16_t valeur;
static uint8_t analogique(uint8_t broche) { /* Read Analog : valeur dans valeur, erreur rendue */
libre();
ControlPort.params[0] = broche;
api(10, 7);
valeur = ControlPort.params[0] | ControlPort.params[1] << 8;
return ControlPort.error;
}
int main(void) {
neo_uext_init(); /* 10,1 : broches en entrée numérique */
uint8_t e1 = analogique(8); /* pas encore réglée en analogique */
uint8_t e2 = analogique(10); /* pas d'entrée analogique sur la broche 10 */
neo_uext_gpio_set_direction(8, NEO_UEXT_ANALOGUE_INPUT); /* 10,4 */
analogique(8);
neo_uext_init();
printf("Broche 8 non reglee : erreur %u\n", e1);
printf("Broche 10 : erreur %u\n", e2);
printf("Broche 8 : %u sur 4095\n", valeur); /* 4095 : 3,3 V */
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Lire une entrée analogique (groupe 10, fonction 7).
program uext7;
uses crt, neo6502, neo6502uext;
var e1, e2: byte;
valeur: word;
function analogique(broche: byte): byte; // Read Analog : valeur dans valeur, erreur rendue
begin
NeoReadAnalog(broche);
NeoWaitMessage; // attendre la fin de l'appel, puis relire P0-P1
valeur := NeoMessage.params[0] + NeoMessage.params[1] shl 8;
result := NeoMessage.error;
end;
begin
NeoUExtInitialize; // 10,1 : broches en entrée numérique
e1 := analogique(8); // pas encore réglée en analogique
e2 := analogique(10); // pas d'entrée analogique sur la broche 10
NeoSetDirection(8, GPIO_PINMODE_ANALOGUE); // 10,4
analogique(8);
NeoUExtInitialize;
writeln('Broche 8 non reglee : erreur ', e1);
writeln('Broche 10 : erreur ', e2);
writeln('Broche 8 : ', valeur, ' sur 4095'); // 4095 : 3,3 V
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Lire une entree analogique (groupe 10, fonction 7)
20 b = 8 : gosub 1000 : e1 = e : ' pas encore reglee en analogique
30 b = 10 : gosub 1000 : e2 = e : ' pas d'entree analogique sur la broche 10
40 pin 8, analog : ' 10,4
50 v = analog(8) : ' Read Analog, 0-4095 pour 0 a 3,3 V
70 pin 8, input
80 print "Broche 8 non reglee : erreur ";e1
90 print "Broche 10 : erreur ";e2
100 print "Broche 8 : ";v;" sur 4095"
110 end
1000 ' 10,7 sur la broche b ; erreur dans e
1010 while peek($ff00) : wend : poke $ff04, b : poke $ff01, 7 : poke $ff00, 10
1020 while peek($ff00) : wend : e = peek($ff02)
1030 returnVérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Lire une entrée analogique (groupe 10, fonction 7).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<init
ldx #>init
jsr envoi
lda #<an8
ldx #>an8
jsr envoi
lda ControlPort+2
sta e1
lda #<an10
ldx #>an10
jsr envoi
lda ControlPort+2
sta e2
lda #<s8a
ldx #>s8a
jsr envoi
lda #<an8
ldx #>an8
jsr envoi
lda ControlPort+4 ; P0-P1 : 0-4095 pour 0 à 3,3 V
sta v
lda ControlPort+5
sta v+1
lda #<init
ldx #>init
jsr envoi
lda #<t0
ldx #>t0
jsr ecrire
lda e1
jsr decimal
lda #13
jsr WriteCharacter
lda #<t1
ldx #>t1
jsr ecrire
lda e2
jsr decimal
lda #13
jsr WriteCharacter
lda #<t2
ldx #>t2
jsr ecrire
lda v
ldx v+1
jsr decimal16
lda #<t3 ; 4095 : 3,3 V
ldx #>t3
jsr ecrire
lda #13
jsr WriteCharacter
rts
; Affiche en décimal le nombre de 16 bits A (poids faible) X (poids fort).
decimal16:
sta n16
stx n16+1
ldy #0 ; nombre de chiffres empilés
_div10: ldx #16 ; n16 / 10 : quotient dans n16, reste dans A
lda #0
_bit: asl n16
rol n16+1
rol a
cmp #10
bcc _pas
sbc #10
inc n16
_pas: dex
bne _bit
pha
iny
lda n16
ora n16+1
bne _div10
_sort: pla
ora #'0'
jsr WriteCharacter
dey
bne _sort
rts
n16: .word 0
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
an8: .byte 10, 7, 1, 8 ; 10,7 : Read Analog, broche 8
an10: .byte 10, 7, 1, 10 ; broche 10 : pas d'entrée analogique
s8a: .byte 10, 4, 2, 8, 3 ; 10,4 : broche 8, entrée analogique
t0: .text "Broche 8 non reglee : erreur ", 0
t1: .text "Broche 10 : erreur ", 0
t2: .text "Broche 8 : ", 0
t3: .text " sur 4095", 0
e1: .byte 0
e2: .byte 0
v: .word 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,8 I2C Status Officiel
Dit si un périphérique répond à une adresse I2C.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | adresse du périphérique |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 1 si le périphérique répond, 0 sinon |
L'appel essaie de lire un octet. L'exemple parcourt les adresses $08 à $77 et affiche celles qui répondent. En NeoBASIC, idevice(dev) fait cet appel.
Mots-clés NeoBASIC qui font cet appel : idevice()
Texte de la documentation du firmware (anglais)
Try to read from I2C Device Parameter:0. If present, then Parameter:0 will contain a non-zero value.
C (llvm-mos)
/* Chercher les périphériques I2C présents (groupe 10, fonction 8). */
#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)
;
}
int main(void) {
printf("Presents :");
for (uint8_t a = 0x08; a < 0x78; a++) /* adresses I2C ordinaires */
if (neo_uext_i2c_status(a)) /* I2C Status : non nul si présent */
printf(" $%02X", a);
printf("\n");
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Chercher les périphériques I2C présents (groupe 10, fonction 8).
program uext8;
uses crt, neo6502, neo6502uext;
const hex: string[16] = '0123456789ABCDEF';
var a: byte;
begin
write('Presents :');
for a := $08 to $77 do // adresses I2C ordinaires
if NeoCheckI2C(a) <> 0 then // I2C Status : non nul si présent
write(' $', hex[a shr 4 + 1], hex[a and 15 + 1]);
writeln;
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Chercher les peripheriques I2C presents (groupe 10, fonction 8)
20 h$ = "0123456789ABCDEF"
30 print "Presents :";
40 for a = $08 to $77 : ' adresses I2C ordinaires
50 if idevice(a) then print " $";mid$(h$, (a >> 4) + 1, 1);mid$(h$, (a & 15) + 1, 1); : ' I2C Status
60 next a
70 printVérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Chercher les périphériques I2C présents (groupe 10, fonction 8).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<t0
ldx #>t0
jsr ecrire
lda #$08 ; adresses I2C ordinaires, $08 à $77
sta adr
_suiv: jsr WaitMessage
lda adr
sta ControlPort+4
lda #10
ldx #8 ; 10,8 : I2C Status
jsr appel
lda ControlPort+4 ; non nul : présent
beq _abs
lda #' '
jsr WriteCharacter
lda #'$'
jsr WriteCharacter
lda adr
lsr a
lsr a
lsr a
lsr a
jsr hex
lda adr
and #15
jsr hex
_abs: inc adr
lda adr
cmp #$78
bne _suiv
lda #13
jsr WriteCharacter
rts
; Affiche le chiffre hexadécimal A (0-15).
hex: tax
lda chiffres,x
jmp WriteCharacter
chiffres: .text "0123456789ABCDEF"
t0: .text "Presents :", 0
adr: .byte 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,9 Read I2C Block Modifié par Trinity
Lit une suite d'octets d'un périphérique I2C dans la mémoire du 6502.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | adresse du périphérique |
P1-P2 | addr | destination |
P3-P4 | uint16 | nombre d'octets |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le transfert n'est pas complet |
Rien n'est écrit avant la lecture : pour lire à partir d'un registre, on l'envoie d'abord (ici, 10,5 place le pointeur d'une EEPROM). Trinity borne la longueur à la fin de la mémoire du 6502. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Try to read a block of memory from I2C Device Parameter:0 into memory at Parameters:1,2, length Parameters:3,4.
C (llvm-mos)
/* Lire un bloc d'octets d'un périphérique I2C (groupe 10, fonction 9). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t tampon[4];
int main(void) {
neo_uext_i2c_write(0x50, 0x00, 0x00); /* 10,5 : sans valeur, place le pointeur d'une EEPROM... */
libre();
ControlPort.params[0] = 0x50; /* P0 : périphérique */
ControlPort.params[1] = (uint16_t)tampon & 0xFF; /* P1-P2 : destination */
ControlPort.params[2] = (uint16_t)tampon >> 8;
ControlPort.params[3] = sizeof tampon; /* P3-P4 : longueur */
ControlPort.params[4] = 0;
api(10, 9); /* Read I2C Block */
uint8_t e = ControlPort.error;
printf("Lu en $50 (erreur %u) : %u %u %u %u\n", e, tampon[0], tampon[1], tampon[2], tampon[3]);
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Lire un bloc d'octets d'un périphérique I2C (groupe 10, fonction 9).
program uext9;
uses crt, neo6502, neo6502uext;
var tampon: array[0..3] of byte;
e: byte;
begin
NeoWriteI2C($50, $00, $00); // 10,5 : place le pointeur d'une EEPROM...
NeoReadBlockI2C($50, word(@tampon), 4); // Read I2C Block
NeoWaitMessage;
e := NeoMessage.error;
writeln('Lu en $50 (erreur ', e, ') : ', tampon[0], ' ', tampon[1], ' ', tampon[2], ' ', tampon[3]);
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Lire un bloc d'octets d'un peripherique I2C (groupe 10, fonction 9)
20 t = alloc(4)
30 iwrite $50, 0, 0 : ' 10,5 : place le pointeur d'une EEPROM...
40 while peek($ff00) : wend
50 poke $ff04, $50 : doke $ff05, t : doke $ff07, 4 : poke $ff01, 9 : poke $ff00, 10 : ' Read I2C Block
60 while peek($ff00) : wend : e = peek($ff02)
70 print "Lu en $50 (erreur ";e;") : ";peek(t);" ";peek(t + 1);" ";peek(t + 2);" ";peek(t + 3)Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Lire un bloc d'octets d'un périphérique I2C (groupe 10, fonction 9).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<ptr0
ldx #>ptr0
jsr envoi
lda #<bloc
ldx #>bloc
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
ldx #0
_oct: lda tampon,x
jsr decimal
cpx #3
beq _fin
lda #' '
jsr WriteCharacter
inx
bra _oct
_fin: lda #13
jsr WriteCharacter
rts
ptr0: .byte 10, 5, 3, $50, 0, 0 ; 10,5 : place le pointeur d'une EEPROM...
bloc: .byte 10, 9, 5, $50 ; 10,9 : Read I2C Block, périphérique, destination, longueur
.word tampon, 4
t0: .text "Lu en $50 (erreur ", 0
t1: .text ") : ", 0
e: .byte 0
tampon: .fill 4
; 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,10 Write I2C Block Modifié par Trinity
Envoie une suite d'octets de la mémoire du 6502 à un périphérique I2C.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | adresse du périphérique |
P1-P2 | addr | source |
P3-P4 | uint16 | nombre d'octets |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le transfert n'est pas complet |
Le premier octet est souvent le registre visé, suivi des données. Trinity borne la longueur à la fin de la mémoire du 6502. En NeoBASIC, isend dev, liste fait cet appel ; la liste mêle nombres (un octet chacun) et chaînes.
Mots-clés NeoBASIC qui font cet appel : isend
Texte de la documentation du firmware (anglais)
Try to write a block of memory to I2C Device Parameter:0 from memory at Parameters:1,2, length Parameters:3,4.
C (llvm-mos)
/* Envoyer un bloc d'octets à un périphérique I2C (groupe 10, fonction 10). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static const uint8_t bloc[] = { 0x00, 'N', 'E', 'O' }; /* registre 0, puis trois octets */
int main(void) {
libre();
ControlPort.params[0] = 0x50; /* P0 : périphérique */
ControlPort.params[1] = (uint16_t)bloc & 0xFF; /* P1-P2 : source */
ControlPort.params[2] = (uint16_t)bloc >> 8;
ControlPort.params[3] = sizeof bloc; /* P3-P4 : longueur */
ControlPort.params[4] = 0;
api(10, 10); /* Write I2C Block */
printf("Envoye en $50 : %u octets, erreur %u\n", sizeof bloc, ControlPort.error);
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Envoyer un bloc d'octets à un périphérique I2C (groupe 10, fonction 10).
program uext10;
uses crt, neo6502, neo6502uext;
const bloc: array[0..3] of byte = ($00, ord('N'), ord('E'), ord('O')); // registre 0, puis trois octets
var e: byte;
begin
NeoWriteBlockI2C($50, word(@bloc), 4); // Write I2C Block
NeoWaitMessage;
e := NeoMessage.error;
writeln('Envoye en $50 : 4 octets, erreur ', e);
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Envoyer un bloc d'octets a un peripherique I2C (groupe 10, fonction 10)
20 isend $50, 0, "NEO" : ' Write I2C Block : registre 0, puis trois octets
30 e = peek($ff02)
40 print "Envoye en $50 : 4 octets, erreur ";eVérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Envoyer un bloc d'octets à un périphérique I2C (groupe 10, fonction 10).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<bloc
ldx #>bloc
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
bloc: .byte 10, 10, 5, $50 ; 10,10 : Write I2C Block, périphérique, source, longueur
.word donnees, 4
donnees: .byte 0 ; registre 0, puis trois octets
.text "NEO"
t0: .text "Envoye en $50 : 4 octets, erreur ", 0
e: .byte 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,11 Read SPI Block Modifié par Trinity
Lit une suite d'octets sur le bus SPI dans la mémoire du 6502.
| Octets | Type | Rôle |
|---|---|---|
P1-P2 | addr | destination |
P3-P4 | uint16 | nombre d'octets |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le transfert n'est pas complet |
P0 n'est pas lu : il n'y a qu'un périphérique, choisi par SSEL (broche 10), mis à 0 pendant le transfert. Le premier appel SPI réserve les broches 7 à 10. Sur une carte dont le stockage est une carte SD, le SPI est pris et l'appel rend 1. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Try to read a block of memory from SPI Device into memory at Parameters:1,2, length Parameters:3,4.
C (llvm-mos)
/* Lire un bloc d'octets sur le bus SPI (groupe 10, fonction 11). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t tampon[4];
int main(void) {
libre();
ControlPort.params[1] = (uint16_t)tampon & 0xFF; /* P1-P2 : destination (P0 n'est pas lu) */
ControlPort.params[2] = (uint16_t)tampon >> 8;
ControlPort.params[3] = sizeof tampon; /* P3-P4 : longueur */
ControlPort.params[4] = 0;
api(10, 11); /* Read SPI Block */
uint8_t e = ControlPort.error;
printf("Lu en SPI (erreur %u) : %u %u %u %u\n", e, tampon[0], tampon[1], tampon[2], tampon[3]);
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Lire un bloc d'octets sur le bus SPI (groupe 10, fonction 11).
program uext11;
uses crt, neo6502, neo6502uext;
var tampon: array[0..3] of byte;
e: byte;
begin
NeoReadBlockSPI(word(@tampon), 4); // Read SPI Block
NeoWaitMessage;
e := NeoMessage.error;
writeln('Lu en SPI (erreur ', e, ') : ', tampon[0], ' ', tampon[1], ' ', tampon[2], ' ', tampon[3]);
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Lire un bloc d'octets sur le bus SPI (groupe 10, fonction 11)
20 t = alloc(4)
30 while peek($ff00) : wend
40 doke $ff05, t : doke $ff07, 4 : poke $ff01, 11 : poke $ff00, 10 : ' Read SPI Block (P0 n'est pas lu)
50 while peek($ff00) : wend : e = peek($ff02)
60 print "Lu en SPI (erreur ";e;") : ";peek(t);" ";peek(t + 1);" ";peek(t + 2);" ";peek(t + 3)Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Lire un bloc d'octets sur le bus SPI (groupe 10, fonction 11).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<bloc
ldx #>bloc
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
ldx #0
_oct: lda tampon,x
jsr decimal
cpx #3
beq _fin
lda #' '
jsr WriteCharacter
inx
bra _oct
_fin: lda #13
jsr WriteCharacter
rts
bloc: .byte 10, 11, 5, 0 ; 10,11 : Read SPI Block (P0 n'est pas lu), destination, longueur
.word tampon, 4
t0: .text "Lu en SPI (erreur ", 0
t1: .text ") : ", 0
e: .byte 0
tampon: .fill 4
; 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,12 Write SPI Block Modifié par Trinity
Envoie une suite d'octets de la mémoire du 6502 sur le bus SPI.
| Octets | Type | Rôle |
|---|---|---|
P1-P2 | addr | source |
P3-P4 | uint16 | nombre d'octets |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le transfert n'est pas complet |
Comme 10,11 : P0 n'est pas lu, SSEL (broche 10) passe à 0 pendant l'envoi. L'exemple montre que le SPI a pris les broches 7 à 10 : écrire la broche 10 donne ensuite l'erreur 1 (vérifié au banc). En NeoBASIC, ssend liste fait cet appel.
Mots-clés NeoBASIC qui font cet appel : ssend
Texte de la documentation du firmware (anglais)
Try to write a block of memory to SPI Device from memory at Parameters:1,2, length Parameters:3,4.
C (llvm-mos)
/* Envoyer un bloc d'octets sur le bus SPI (groupe 10, fonction 12). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static const uint8_t bloc[] = { 0x9F, 0x00, 0x00 }; /* une commande et deux octets */
static uint8_t ecrire(uint8_t broche, uint8_t v) { /* 10,2 : rend l'indicateur d'erreur */
libre();
ControlPort.params[0] = broche;
ControlPort.params[1] = v;
api(10, 2);
return ControlPort.error;
}
int main(void) {
neo_uext_init(); /* 10,1 */
libre();
ControlPort.params[1] = (uint16_t)bloc & 0xFF; /* P1-P2 : source (P0 n'est pas lu) */
ControlPort.params[2] = (uint16_t)bloc >> 8;
ControlPort.params[3] = sizeof bloc; /* P3-P4 : longueur */
ControlPort.params[4] = 0;
api(10, 12); /* Write SPI Block */
uint8_t e = ControlPort.error;
uint8_t b = ecrire(10, 1); /* le SPI a pris les broches 7 à 10 */
neo_uext_init();
printf("Envoye en SPI : erreur %u\n", e);
printf("Broche 10 ensuite : erreur %u\n", b);
return 0;
}Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Mad Pascal
// Envoyer un bloc d'octets sur le bus SPI (groupe 10, fonction 12).
program uext12;
uses crt, neo6502, neo6502uext;
const bloc: array[0..2] of byte = ($9F, $00, $00); // une commande et deux octets
var e, b: byte;
function ecrire(broche, v: byte): byte; // 10,2 : rend l'indicateur d'erreur
begin
NeoWriteGPIO(broche, v);
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
NeoUExtInitialize; // 10,1
NeoWriteBlockSPI(word(@bloc), 3); // Write SPI Block
NeoWaitMessage;
e := NeoMessage.error;
b := ecrire(10, 1); // le SPI a pris les broches 7 à 10
NeoUExtInitialize;
writeln('Envoye en SPI : erreur ', e);
writeln('Broche 10 ensuite : erreur ', b);
end.Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
NeoBASIC
10 ' Envoyer un bloc d'octets sur le bus SPI (groupe 10, fonction 12)
20 ssend $9f, 0, 0 : ' Write SPI Block : une commande et deux octets
30 e1 = peek($ff02)
40 b = 10 : v = 1 : gosub 1000 : ' le SPI a pris les broches 7 a 10
50 print "Envoye en SPI : erreur ";e1
60 print "Broche 10 ensuite : erreur ";e
70 end
1000 ' 10,2 : ecrire v sur la broche b ; erreur dans e
1010 while peek($ff00) : wend : poke $ff04, b : poke $ff05, v : poke $ff01, 2 : poke $ff00, 10
1020 while peek($ff00) : wend : e = peek($ff02)
1030 returnVérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
Assembleur 65C02 (64tass)
; Envoyer un bloc d'octets sur le bus SPI (groupe 10, fonction 12).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<init
ldx #>init
jsr envoi
lda #<bloc
ldx #>bloc
jsr envoi
lda ControlPort+2
sta e
lda #<ecr10
ldx #>ecr10
jsr envoi
lda ControlPort+2
sta b
lda #<init
ldx #>init
jsr envoi
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
lda #<t1
ldx #>t1
jsr ecrire
lda b
jsr decimal
lda #13
jsr WriteCharacter
rts
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
bloc: .byte 10, 12, 5, 0 ; 10,12 : Write SPI Block (P0 n'est pas lu), source, longueur
.word donnees, 3
donnees: .byte $9F, 0, 0 ; une commande et deux octets
ecr10: .byte 10, 2, 2, 10, 1 ; 10,2 : broche 10, valeur 1 : le SPI a pris les broches 7 à 10
t0: .text "Envoye en SPI : erreur ", 0
t1: .text "Broche 10 ensuite : erreur ", 0
e: .byte 0
b: .byte 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
; 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 0Vérifié au banc (appel fait, sans erreur). La sortie dépend du matériel branché sur le port UEXT : celle de l'émulateur, factice, n'est pas reproduite.
10,13 Read UART Block Modifié par Trinity
Attend une suite d'octets sur le port série et la range dans la mémoire du 6502.
| Octets | Type | Rôle |
|---|---|---|
P1-P2 | addr | destination |
P3-P4 | uint16 | nombre d'octets |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si un octet n'arrive pas dans les 5 secondes |
Le délai de 5 secondes vaut pour chaque octet ; pendant l'attente, le 65C02 est arrêté. Sans rien de branché, l'exemple finit donc sur l'erreur 1 au bout de 5 secondes, sur la carte comme au banc. Si 10,19 route le port vers un modem USB branché, c'est lui qui est lu. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Try to read a block of memory from UART into memory at Parameters:1,2, length Parameters:3,4. This can fail with a timeout. If UART routing (10,19) selects a USB CDC modem, the block is read from it instead.
C (llvm-mos)
/* Attendre un bloc d'octets sur le port série (groupe 10, fonction 13). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t tampon[4];
int main(void) {
libre();
ControlPort.params[1] = (uint16_t)tampon & 0xFF; /* P1-P2 : destination */
ControlPort.params[2] = (uint16_t)tampon >> 8;
ControlPort.params[3] = sizeof tampon; /* P3-P4 : longueur */
ControlPort.params[4] = 0;
api(10, 13); /* Read UART Block : attend jusqu'à 5 s par octet */
printf("4 octets attendus : erreur %u\n", ControlPort.error); /* 1 : délai dépassé */
return 0;
}4 octets attendus : erreur 1Mad Pascal
// Attendre un bloc d'octets sur le port série (groupe 10, fonction 13).
program uext13;
uses crt, neo6502, neo6502uext;
var tampon: array[0..3] of byte;
e: byte;
begin
NeoReadBlockUART(word(@tampon), 4); // Read UART Block : attend jusqu'à 5 s par octet
NeoWaitMessage;
e := NeoMessage.error;
writeln('4 octets attendus : erreur ', e); // 1 : délai dépassé
end.4 octets attendus : erreur 1NeoBASIC
10 ' Attendre un bloc d'octets sur le port serie (groupe 10, fonction 13)
20 t = alloc(4)
30 while peek($ff00) : wend
40 doke $ff05, t : doke $ff07, 4 : poke $ff01, 13 : poke $ff00, 10 : ' Read UART Block : jusqu'a 5 s par octet
50 while peek($ff00) : wend : e = peek($ff02)
60 print "4 octets attendus : erreur ";e : ' 1 : delai depasse4 octets attendus : erreur 1Assembleur 65C02 (64tass)
; Attendre un bloc d'octets sur le port série (groupe 10, fonction 13).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<bloc
ldx #>bloc
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
bloc: .byte 10, 13, 5, 0 ; 10,13 : Read UART Block, jusqu'à 5 s par octet
.word tampon, 4
t0: .text "4 octets attendus : erreur ", 0 ; 1 : délai dépassé
e: .byte 0
tampon: .fill 4
; 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
; 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 04 octets attendus : erreur 110,14 Write UART Block Modifié par Trinity
Envoie une suite d'octets de la mémoire du 6502 sur le port série.
| Octets | Type | Rôle |
|---|---|---|
P1-P2 | addr | source |
P3-P4 | uint16 | nombre d'octets |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | toujours 0 sur le port série de la carte ; 1 si un modem USB routé (10,19) refuse |
L'envoi ne vérifie pas qu'un appareil écoute. Le port série est partagé avec le port de débogage de Trinity : sa vitesse est celle du dernier 10,15. En NeoBASIC, usend liste fait cet appel.
Mots-clés NeoBASIC qui font cet appel : usend
Texte de la documentation du firmware (anglais)
Try to write a block of memory to UART from memory at Parameters:1,2, length Parameters:3,4. Routed to a USB CDC modem if 10,19 selects it.
C (llvm-mos)
/* Envoyer un bloc d'octets sur le port série (groupe 10, fonction 14). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static const char texte[] = "NEO\r\n";
int main(void) {
libre();
ControlPort.params[1] = (uint16_t)texte & 0xFF; /* P1-P2 : source */
ControlPort.params[2] = (uint16_t)texte >> 8;
ControlPort.params[3] = sizeof texte - 1; /* P3-P4 : longueur */
ControlPort.params[4] = 0;
api(10, 14); /* Write UART Block */
printf("Envoye : %u octets, erreur %u\n", sizeof texte - 1, ControlPort.error);
return 0;
}Envoye : 5 octets, erreur 0Mad Pascal
// Envoyer un bloc d'octets sur le port série (groupe 10, fonction 14).
program uext14;
uses crt, neo6502, neo6502uext;
var texte: string[8];
e: byte;
begin
texte := 'NEO'#13#10;
NeoWriteBlockUART(word(@texte) + 1, length(texte)); // Write UART Block
NeoWaitMessage;
e := NeoMessage.error;
writeln('Envoye : ', length(texte), ' octets, erreur ', e);
end.Envoye : 5 octets, erreur 0NeoBASIC
10 ' Envoyer un bloc d'octets sur le port serie (groupe 10, fonction 14)
20 usend "NEO", 13, 10 : ' Write UART Block
30 e = peek($ff02)
40 print "Envoye : 5 octets, erreur ";eEnvoye : 5 octets, erreur 0Assembleur 65C02 (64tass)
; Envoyer un bloc d'octets sur le port série (groupe 10, fonction 14).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<bloc
ldx #>bloc
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
bloc: .byte 10, 14, 5, 0 ; 10,14 : Write UART Block, source, longueur
.word texte, 5
texte: .text "NEO", 13, 10
t0: .text "Envoye : 5 octets, erreur ", 0
e: .byte 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
; 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 0Envoye : 5 octets, erreur 010,15 Set UART Speed and Protocol Modifié par Trinity
Règle la vitesse (en bauds) et le format du port série.
| Octets | Type | Rôle |
|---|---|---|
P0-P3 | uint32 | vitesse en bauds |
P4 | uint8 | protocole : 0 = 8N1, le seul pris en charge |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | toujours 0 |
L'appel réserve les broches 3 (TXD) et 4 (RXD) : les écrire comme broches simples donne l'erreur 1. Le port de débogage de Trinity suit la nouvelle vitesse (sa trace devient illisible à une autre vitesse que la sienne). Si 10,19 route vers un modem USB, l'appel règle sa ligne (la plupart l'ignorent). En NeoBASIC, uconfig bauds fait cet appel, en 8N1.
Mots-clés NeoBASIC qui font cet appel : uconfig
Texte de la documentation du firmware (anglais)
Set the Baud Rate and Serial Protocol for the UART interface. The baud rate is in Parameters:0..3 and the protocol number is Parameter:4. Currently only 8N1 is supported, this is protocol 0. If UART routing selects a USB CDC modem, this sets its line coding (most USB modems ignore it).
C (llvm-mos)
/* Régler la vitesse du port série (groupe 10, fonction 15). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
static uint8_t ecrire(uint8_t broche, uint8_t v) { /* 10,2 : rend l'indicateur d'erreur */
libre();
ControlPort.params[0] = broche;
ControlPort.params[1] = v;
api(10, 2);
return ControlPort.error;
}
int main(void) {
neo_uext_uart_configure(115200, 0); /* Set UART Speed and Protocol : 115200 bauds, 8N1 */
uint8_t e = ControlPort.error;
uint8_t apres = ecrire(3, 0); /* TXD (3) et RXD (4) sont au port série */
neo_uext_init();
printf("Reglage : erreur %u\n", e);
printf("Broche 3 ensuite : erreur %u\n", apres);
return 0;
}Reglage : erreur 0
Broche 3 ensuite : erreur 1Mad Pascal
// Régler la vitesse du port série (groupe 10, fonction 15).
program uext15;
uses crt, neo6502, neo6502uext;
var e, apres: byte;
function ecrire(broche, v: byte): byte; // 10,2 : rend l'indicateur d'erreur
begin
NeoWriteGPIO(broche, v);
NeoWaitMessage;
result := NeoMessage.error;
end;
begin
NeoSetupUART(115200, UART_PROTOCOL_8N1); // Set UART Speed and Protocol : 115200 bauds, 8N1
NeoWaitMessage;
e := NeoMessage.error;
apres := ecrire(3, 0); // TXD (3) et RXD (4) sont au port série
NeoUExtInitialize;
writeln('Reglage : erreur ', e);
writeln('Broche 3 ensuite : erreur ', apres);
end.Reglage : erreur 0
Broche 3 ensuite : erreur 1NeoBASIC
10 ' Regler la vitesse du port serie (groupe 10, fonction 15)
20 uconfig 115200 : ' Set UART Speed and Protocol : 115200 bauds, 8N1
30 e1 = peek($ff02)
40 b = 3 : v = 0 : gosub 1000 : ' TXD (3) et RXD (4) sont au port serie
50 print "Reglage : erreur ";e1
60 print "Broche 3 ensuite : erreur ";e
70 end
1000 ' 10,2 : ecrire v sur la broche b ; erreur dans e
1010 while peek($ff00) : wend : poke $ff04, b : poke $ff05, v : poke $ff01, 2 : poke $ff00, 10
1020 while peek($ff00) : wend : e = peek($ff02)
1030 returnReglage : erreur 0
Broche 3 ensuite : erreur 1Assembleur 65C02 (64tass)
; Régler la vitesse du port série (groupe 10, fonction 15).
.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 #<vitesse
ldx #>vitesse
jsr envoi
lda ControlPort+2
sta e
lda #<ecr3
ldx #>ecr3
jsr envoi
lda ControlPort+2
sta b
lda #<init
ldx #>init
jsr envoi
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
lda #<t1
ldx #>t1
jsr ecrire
lda b
jsr decimal
lda #13
jsr WriteCharacter
rts
init: .byte 10, 1, 0 ; 10,1 : UExt Initialise
vitesse: .byte 10, 15, 5 ; 10,15 : Set UART Speed and Protocol
.dword 115200 ; P0-P3 : bauds
.byte 0 ; P4 : protocole 0, 8N1
ecr3: .byte 10, 2, 2, 3, 0 ; 10,2 : broche 3, valeur 0 : TXD (3) et RXD (4) sont au port série
t0: .text "Reglage : erreur ", 0
t1: .text "Broche 3 ensuite : erreur ", 0
e: .byte 0
b: .byte 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
; 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 0Reglage : erreur 0
Broche 3 ensuite : erreur 110,16 Write byte to UART Modifié par Trinity
Envoie un octet sur le port série.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | octet |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | toujours 0 |
Comme 10,14, sans vérifier qu'un appareil écoute ; routé vers un modem USB si 10,19 le choisit. NeoBASIC n'a pas de mot-clé pour cet appel (usend envoie un bloc).
Texte de la documentation du firmware (anglais)
Write byte Parameter:0 to the UART (or the routed USB CDC modem).
C (llvm-mos)
/* Envoyer un octet sur le port série (groupe 10, fonction 16). */
#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)
;
}
int main(void) {
neo_uext_uart_write('A'); /* Write byte to UART */
printf("Octet envoye : erreur %u\n", ControlPort.error);
return 0;
}Octet envoye : erreur 0Mad Pascal
// Envoyer un octet sur le port série (groupe 10, fonction 16).
program uext16;
uses crt, neo6502, neo6502uext;
var e: byte;
begin
NeoWriteByteUART(ord('A')); // Write byte to UART
NeoWaitMessage;
e := NeoMessage.error;
writeln('Octet envoye : erreur ', e);
end.Octet envoye : erreur 0NeoBASIC
10 ' Envoyer un octet sur le port serie (groupe 10, fonction 16)
20 while peek($ff00) : wend : poke $ff04, asc("A") : poke $ff01, 16 : poke $ff00, 10 : ' Write byte to UART
30 while peek($ff00) : wend : e = peek($ff02)
40 print "Octet envoye : erreur ";eOctet envoye : erreur 0Assembleur 65C02 (64tass)
; Envoyer un octet sur le port série (groupe 10, fonction 16).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<octet
ldx #>octet
jsr envoi
lda ControlPort+2
sta e
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
octet: .byte 10, 16, 1, 'A' ; 10,16 : Write byte to UART
t0: .text "Octet envoye : erreur ", 0
e: .byte 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
; 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 0Octet envoye : erreur 010,17 Read byte from UART Modifié par Trinity
Lit un octet reçu sur le port série, sans attendre.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | octet reçu |
erreur | uint8 | 1 si rien n'est arrivé |
Contrairement à 10,13, l'appel n'attend pas. Sans rien de branché, l'exemple trouve l'erreur 1, sur la carte comme au banc. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Read a byte from the UART (or the routed USB CDC modem). It is returned in Parameter:0. Error 1 if nothing is available.
C (llvm-mos)
/* Lire un octet du port série s'il y en a un (groupe 10, fonction 17). */
#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)
;
}
int main(void) {
libre();
api(10, 17); /* Read byte from UART */
if (ControlPort.error) /* 1 : rien n'est arrivé */
printf("Rien a lire : erreur %u\n", ControlPort.error);
else
printf("Recu : %u\n", ControlPort.params[0]);
return 0;
}Rien a lire : erreur 1Mad Pascal
// Lire un octet du port série s'il y en a un (groupe 10, fonction 17).
program uext17;
uses crt, neo6502, neo6502uext;
var v, e: byte;
begin
NeoReadByteUART; // Read byte from UART
NeoWaitMessage; // attendre la fin de l'appel, puis relire P0
v := NeoMessage.params[0];
e := NeoMessage.error; // 1 : rien n'est arrivé
if e <> 0 then writeln('Rien a lire : erreur ', e)
else writeln('Recu : ', v);
end.Rien a lire : erreur 1NeoBASIC
10 ' Lire un octet du port serie s'il y en a un (groupe 10, fonction 17)
20 while peek($ff00) : wend : poke $ff01, 17 : poke $ff00, 10 : ' Read byte from UART
30 while peek($ff00) : wend : e = peek($ff02) : v = peek($ff04)
40 if e then print "Rien a lire : erreur ";e : end : ' 1 : rien n'est arrive
50 print "Recu : ";vRien a lire : erreur 1Assembleur 65C02 (64tass)
; Lire un octet du port série s'il y en a un (groupe 10, fonction 17).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<lire
ldx #>lire
jsr envoi
lda ControlPort+4
sta v
lda ControlPort+2 ; 1 : rien n'est arrivé
sta e
beq _recu
lda #<t0
ldx #>t0
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
_recu: lda #<t1
ldx #>t1
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
rts
lire: .byte 10, 17, 0 ; 10,17 : Read byte from UART
t0: .text "Rien a lire : erreur ", 0
t1: .text "Recu : ", 0
e: .byte 0
v: .byte 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
; 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 0Rien a lire : erreur 110,18 Check if Byte Available Modifié par Trinity
Dit si un octet reçu attend d'être lu sur le port série.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 1 si un octet attend, 0 sinon |
À appeler avant 10,17 pour ne lire que ce qui est arrivé. En NeoBASIC, uhasdata() fait cet appel.
Mots-clés NeoBASIC qui font cet appel : uhasdata()
Texte de la documentation du firmware (anglais)
See if a byte is available in the UART input buffer. If available Parameter:0 is non zero.
C (llvm-mos)
/* Savoir si un octet attend sur le port série (groupe 10, fonction 18). */
#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)
;
}
int main(void) {
printf("Octet en attente : %s\n", neo_uext_uart_available() ? "oui" : "non"); /* Check if Byte Available */
return 0;
}Octet en attente : nonMad Pascal
// Savoir si un octet attend sur le port série (groupe 10, fonction 18).
program uext18;
uses crt, neo6502, neo6502uext;
var v: byte;
begin
NeoCheckUART; // Check if Byte Available
NeoWaitMessage; // attendre la fin de l'appel, puis relire P0
v := NeoMessage.params[0];
if v <> 0 then writeln('Octet en attente : oui') else writeln('Octet en attente : non');
end.Octet en attente : nonNeoBASIC
10 ' Savoir si un octet attend sur le port serie (groupe 10, fonction 18)
20 r$ = "non" : if uhasdata() then r$ = "oui" : ' Check if Byte Available
30 print "Octet en attente : ";r$Octet en attente : nonAssembleur 65C02 (64tass)
; Savoir si un octet attend sur le port série (groupe 10, fonction 18).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<test
ldx #>test
jsr envoi
lda ControlPort+4 ; non nul : un octet attend
bne _oui
lda #<tn
ldx #>tn
jsr ecrire
rts
_oui: lda #<to
ldx #>to
jsr ecrire
rts
test: .byte 10, 18, 0 ; 10,18 : Check if Byte Available
tn: .text "Octet en attente : non", 13, 0
to: .text "Octet en attente : oui", 13, 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
; 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 0Octet en attente : non10,19 Route UART to USB CDC modem Trinity
Choisit où vont les fonctions du port série (10,13 à 10,18) : le port série du UEXT, un modem USB, ou le modem s'il est branché.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 0 port série du UEXT, 1 premier modem USB (CDC), 2 automatique ; au-delà : automatique |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | mode retenu (0, 1 ou 2) |
Automatique est le réglage de départ : un programme série (netconfig, prophet...) passe ainsi par un modem Wi-Fi USB s'il y en a un, sans changement. La documentation dit que P0 rend le mode « en vigueur » : c'est le réglage retenu (2 pour automatique), pas le port effectivement utilisé. L'exemple remet le mode automatique avant de finir. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Select the source/target of the UART functions 10,13-10,18. Parameter:0 = 0 for the hardware UART (UEXT), 1 for the first USB CDC modem, 2 for AUTO (the CDC modem if one is plugged in, otherwise the hardware UART). AUTO is the default, so serial programs such as netconfig/prophet use a USB Wi-Fi modem unchanged when one is present. Parameter:0 returns the mode in effect.
C (llvm-mos)
/* Choisir où vont les fonctions du port série (groupe 10, 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)
;
}
static uint8_t router(uint8_t mode) { /* Route UART to USB CDC modem : rend le mode retenu */
libre();
ControlPort.params[0] = mode; /* 0 UART du UEXT, 1 modem USB, 2 automatique */
api(10, 19);
return ControlPort.params[0];
}
int main(void) {
uint8_t a = router(0);
uint8_t b = router(9); /* hors plage : automatique */
router(2); /* remettre le mode par défaut */
printf("Demande 0 : %u, demande 9 : %u\n", a, b);
return 0;
}Demande 0 : 0, demande 9 : 2Mad Pascal
// Choisir où vont les fonctions du port série (groupe 10, fonction 19, Trinity).
program uext19;
uses crt, neo6502, neo6502uext;
var a, b: byte;
function router(mode: byte): byte; // Route UART to USB CDC modem : rend le mode retenu
begin
NeoMessage.params[0] := mode; // 0 UART du UEXT, 1 modem USB, 2 automatique
NeoSendMessage(10, 19);
NeoWaitMessage;
result := NeoMessage.params[0];
end;
begin
a := router(0);
b := router(9); // hors plage : automatique
router(2); // remettre le mode par défaut
writeln('Demande 0 : ', a, ', demande 9 : ', b);
end.Demande 0 : 0, demande 9 : 2NeoBASIC
10 ' Choisir ou vont les fonctions du port serie (groupe 10, fonction 19, Trinity)
20 m = 0 : gosub 1000 : a = r
30 m = 9 : gosub 1000 : b = r : ' hors plage : automatique
40 m = 2 : gosub 1000 : ' remettre le mode par defaut
50 print "Demande 0 : ";a;", demande 9 : ";b
60 end
1000 ' Route UART to USB CDC modem : mode m (0 UART du UEXT, 1 modem USB, 2 automatique) ; mode retenu dans r
1010 while peek($ff00) : wend : poke $ff04, m : poke $ff01, 19 : poke $ff00, 10
1020 while peek($ff00) : wend : r = peek($ff04)
1030 returnDemande 0 : 0, demande 9 : 2Assembleur 65C02 (64tass)
; Choisir où vont les fonctions du port série (groupe 10, 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 #<r0
ldx #>r0
jsr envoi
lda ControlPort+4 ; mode retenu
sta a
lda #<r9
ldx #>r9
jsr envoi
lda ControlPort+4
sta b
lda #<r2
ldx #>r2
jsr envoi
lda #<t0
ldx #>t0
jsr ecrire
lda a
jsr decimal
lda #<t1
ldx #>t1
jsr ecrire
lda b
jsr decimal
lda #13
jsr WriteCharacter
rts
r0: .byte 10, 19, 1, 0 ; 10,19 : 0 UART du UEXT
r9: .byte 10, 19, 1, 9 ; hors plage : automatique
r2: .byte 10, 19, 1, 2 ; remettre le mode par défaut, automatique
t0: .text "Demande 0 : ", 0
t1: .text ", demande 9 : ", 0
a: .byte 0
b: .byte 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
; 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 0Demande 0 : 0, demande 9 : 2