Tachibana
Language: English

Group 10 — UExt I/O Official

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

The UEXT connector has 10 pins, known by their number: 1 the 3.3 V, 2 ground, 3 TXD and 4 RXD (serial port), 5 SCL and 6 SDA (I2C), 7 MISO, 8 MOSI, 9 SCK and 10 SSEL (SPI). Pins 3 to 10 also work as plain inputs and outputs; 3, 4, 8 and 9 can read a voltage (analogue input).

Using I2C or SPI, or setting up the serial port, reserves their pins: reading or writing them as plain pins then gives error 1, until 10,1. On the board, Trinity starts its debug port on TXD and RXD: pins 3 and 4 belong to it, even after 10,1 (in the emulator, they are free).

On the bench, Phosphoneo has nothing plugged into the UEXT port: its answers (level of an input, analogue value, I2C or SPI bytes) are dummy values. The examples of these functions are checked (the call is made, without error), but their output is not shown. Those that depend on the firmware alone (output latch, direction, reserved pins, errors, serial port with nothing plugged in) are published as elsewhere.

10,1 UExt Initialise Official

Puts the UEXT I/O back in their starting state: pins 3 to 10 as inputs, latches at 0, reserved pins given back.

Inputs: none.

Outputs: none.

The example writes over I2C, which reserves pins 5 and 6: pin 5 is refused (error 1), then accepted after 10,1. The debug port pins (3 and 4 on the board) stay reserved. In NeoBASIC, clear (and therefore run) makes this call; as clear also erases the variables, the NeoBASIC example writes the mailbox.

NeoBASIC keywords that make this call: clear

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Apres 10,5 : broche 5, erreur 1
Apres 10,1 : broche 5, erreur 0

10,2 Write GPIO Official

Writes the output latch of a pin; it only shows on the pin if the pin is an output.

Inputs
BytesTypeMeaning
P0uint8pin (3 to 10)
P1uint80 low, any other value high
Outputs
BytesTypeMeaning
erreuruint81 if the pin does not exist or is reserved

The latch keeps its value even as an input: turning the pin back into an output (10,4) puts it back on the pin. As an output, 10,3 reads the latch back: the example therefore reads 255 then 0, with nothing plugged in. Pin 2 (ground) is refused. In NeoBASIC, pin n, v makes this call (and pin(n) returns 1 or 0, not 255 or 0).

NeoBASIC keywords that make this call: pin

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 : 255 puis 0
Broche 2 : erreur 1
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 : 255 puis 0
Broche 2 : erreur 1
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 : 1 puis 0
Broche 2 : erreur 1
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 : 255 puis 0
Broche 2 : erreur 1

10,3 Read GPIO Official

Reads a pin: its level if it is an input, its latch if it is an output.

Inputs
BytesTypeMeaning
P0uint8pin (3 to 10)
Outputs
BytesTypeMeaning
P0uint80 low, 255 ($FF) high
erreuruint81 if the pin does not exist or is reserved

A floating input (nothing plugged in) may read high or low. In NeoBASIC, pin(n) makes this call and returns 1 or 0.

NeoBASIC keywords that make this call: pin()

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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$

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,4 Set Port Direction Official

Chooses the direction of a pin: input, output or analogue input.

Inputs
BytesTypeMeaning
P0uint8pin (3 to 10)
P1uint81 input, 2 output, 3 analogue input
Outputs
BytesTypeMeaning
erreuruint81 if the pin does not exist, is reserved, or has no analogue input

Only pins 3, 4, 8 and 9 have an analogue input: pin 10 is refused, pin 8 accepted. Switching to output puts the latch (10,2) on the pin at once. In NeoBASIC, pin n, input, pin n, output and pin n, analog make this call (with a comma) and raise a range error on failure.

NeoBASIC keywords that make this call: pin

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Broche 10 en analogique : erreur 1
Broche 8 en analogique : erreur 0
Broche 10 en sortie : erreur 0

10,5 Write I2C Official

Writes a byte into a register of an I2C device.

Inputs
BytesTypeMeaning
P0uint8device address (7 bits)
P1uint8register
P2uint8value
Outputs
BytesTypeMeaning
erreuruint81 if the transfer is not complete

The firmware documentation says no error is flagged if the device is absent; the board code nevertheless returns 1 when the write does not complete, which is the case without a device (not checked on the board). The first I2C call reserves pins 5 and 6. In NeoBASIC, iwrite dev, reg, val makes this call.

NeoBASIC keywords that make this call: iwrite

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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 ";e

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,6 Read I2C Official

Reads a byte from a register of an I2C device.

Inputs
BytesTypeMeaning
P0uint8device address
P1uint8register
Outputs
BytesTypeMeaning
P0uint8value read
erreuruint81 if the device does not answer

The call writes the register number, then reads one byte. The example first checks that the device is there (10,8). In NeoBASIC, iread(dev, reg) makes this call.

NeoBASIC keywords that make this call: iread()

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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 : ";v

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,7 Read Analog Official

Reads the voltage of a pin set as an analogue input, from 0 to 4095 for 0 to 3.3 V.

Inputs
BytesTypeMeaning
P0uint8pin (3, 4, 8 or 9)
Outputs
BytesTypeMeaning
P0-P1uint16value, 0 to 4095
erreuruint81 pin without analogue input, 2 pin not set to analogue (10,4)

In millivolts: value × 3300 / 4095. The example first shows both errors (2 on pin 8, not set yet, 1 on pin 10), checked on the bench; the value read depends on what is plugged in. In NeoBASIC, analog(n) makes this call.

NeoBASIC keywords that make this call: analog()

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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 return

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,8 I2C Status Official

Tells whether a device answers at an I2C address.

Inputs
BytesTypeMeaning
P0uint8device address
Outputs
BytesTypeMeaning
P0uint81 if the device answers, 0 otherwise

The call tries to read one byte. The example scans addresses $08 to $77 and prints those that answer. In NeoBASIC, idevice(dev) makes this call.

NeoBASIC keywords that make this call: idevice()

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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 print

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,9 Read I2C Block Changed by Trinity

Reads a run of bytes from an I2C device into 6502 memory.

Inputs
BytesTypeMeaning
P0uint8device address
P1-P2addrdestination
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint81 if the transfer is not complete

Nothing is written before the read: to read from a register, send it first (here, 10,5 sets the pointer of an EEPROM). Trinity limits the length to the end of 6502 memory. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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)

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,10 Write I2C Block Changed by Trinity

Sends a run of bytes from 6502 memory to an I2C device.

Inputs
BytesTypeMeaning
P0uint8device address
P1-P2addrsource
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint81 if the transfer is not complete

The first byte is often the target register, followed by the data. Trinity limits the length to the end of 6502 memory. In NeoBASIC, isend dev, list makes this call; the list mixes numbers (one byte each) and strings.

NeoBASIC keywords that make this call: isend

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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 ";e

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,11 Read SPI Block Changed by Trinity

Reads a run of bytes from the SPI bus into 6502 memory.

Inputs
BytesTypeMeaning
P1-P2addrdestination
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint81 if the transfer is not complete

P0 is not read: there is a single device, selected by SSEL (pin 10), pulled to 0 during the transfer. The first SPI call reserves pins 7 to 10. On a board whose storage is an SD card, SPI is taken and the call returns 1. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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)

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,12 Write SPI Block Changed by Trinity

Sends a run of bytes from 6502 memory over the SPI bus.

Inputs
BytesTypeMeaning
P1-P2addrsource
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint81 if the transfer is not complete

As for 10,11: P0 is not read, SSEL (pin 10) goes to 0 during the send. The example shows that SPI has taken pins 7 to 10: writing pin 10 then gives error 1 (checked on the bench). In NeoBASIC, ssend list makes this call.

NeoBASIC keywords that make this call: ssend

Firmware documentation text

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;
}

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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.

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

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 return

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

65C02 assembly (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 0

Checked on the bench (call made, no error). The output depends on the hardware plugged into the UEXT port: the emulator's, a dummy one, is not shown.

10,13 Read UART Block Changed by Trinity

Waits for a run of bytes on the serial port and stores it in 6502 memory.

Inputs
BytesTypeMeaning
P1-P2addrdestination
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint81 if a byte does not arrive within 5 seconds

The 5 second timeout applies to each byte; while waiting, the 65C02 is stopped. With nothing plugged in, the example therefore ends on error 1 after 5 seconds, on the board as on the bench. If 10,19 routes the port to a plugged USB modem, that is what is read. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
4 octets attendus : erreur 1
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
4 octets attendus : erreur 1
NeoBASIC
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 depasse
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
4 octets attendus : erreur 1
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
4 octets attendus : erreur 1

10,14 Write UART Block Changed by Trinity

Sends a run of bytes from 6502 memory over the serial port.

Inputs
BytesTypeMeaning
P1-P2addrsource
P3-P4uint16number of bytes
Outputs
BytesTypeMeaning
erreuruint8always 0 on the board's serial port; 1 if a routed USB modem (10,19) refuses

Sending does not check that a device is listening. The serial port is shared with the Trinity debug port: its speed is that of the last 10,15. In NeoBASIC, usend list makes this call.

NeoBASIC keywords that make this call: usend

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Envoye : 5 octets, erreur 0
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Envoye : 5 octets, erreur 0
NeoBASIC
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 ";e
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Envoye : 5 octets, erreur 0
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Envoye : 5 octets, erreur 0

10,15 Set UART Speed and Protocol Changed by Trinity

Sets the speed (in bauds) and format of the serial port.

Inputs
BytesTypeMeaning
P0-P3uint32speed in bauds
P4uint8protocol: 0 = 8N1, the only one supported
Outputs
BytesTypeMeaning
erreuruint8always 0

The call reserves pins 3 (TXD) and 4 (RXD): writing them as plain pins gives error 1. The Trinity debug port follows the new speed (its trace becomes unreadable at a speed other than its own). If 10,19 routes to a USB modem, the call sets its line (most ignore it). In NeoBASIC, uconfig bauds makes this call, in 8N1.

NeoBASIC keywords that make this call: uconfig

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Reglage : erreur 0
Broche 3 ensuite : erreur 1
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Reglage : erreur 0
Broche 3 ensuite : erreur 1
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Reglage : erreur 0
Broche 3 ensuite : erreur 1
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Reglage : erreur 0
Broche 3 ensuite : erreur 1

10,16 Write byte to UART Changed by Trinity

Sends one byte over the serial port.

Inputs
BytesTypeMeaning
P0uint8byte
Outputs
BytesTypeMeaning
erreuruint8always 0

As 10,14, without checking that a device is listening; routed to a USB modem if 10,19 selects it. NeoBASIC has no keyword for this call (usend sends a block).

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet envoye : erreur 0
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet envoye : erreur 0
NeoBASIC
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 ";e
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet envoye : erreur 0
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet envoye : erreur 0

10,17 Read byte from UART Changed by Trinity

Reads a byte received on the serial port, without waiting.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint8byte received
erreuruint81 if nothing has arrived

Unlike 10,13, the call does not wait. With nothing plugged in, the example gets error 1, on the board as on the bench. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rien a lire : erreur 1
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rien a lire : erreur 1
NeoBASIC
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 : ";v
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rien a lire : erreur 1
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Rien a lire : erreur 1

10,18 Check if Byte Available Changed by Trinity

Tells whether a received byte is waiting to be read on the serial port.

Inputs: none.

Outputs
BytesTypeMeaning
P0uint81 if a byte is waiting, 0 otherwise

Call it before 10,17 to read only what has arrived. In NeoBASIC, uhasdata() makes this call.

NeoBASIC keywords that make this call: uhasdata()

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet en attente : non
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet en attente : non
NeoBASIC
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$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet en attente : non
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Octet en attente : non

10,19 Route UART to USB CDC modem Trinity

Chooses where the serial port functions (10,13 to 10,18) go: the UEXT serial port, a USB modem, or the modem when one is plugged in.

Inputs
BytesTypeMeaning
P0uint80 UEXT serial port, 1 first USB (CDC) modem, 2 automatic; above: automatic
Outputs
BytesTypeMeaning
P0uint8mode kept (0, 1 or 2)

Automatic is the starting setting: a serial program (netconfig, prophet...) thus goes through a USB Wi-Fi modem when there is one, unchanged. The documentation says P0 returns the mode "in effect": it is the setting kept (2 for automatic), not the port actually used. The example puts automatic back before ending. NeoBASIC has no keyword for this call.

Firmware documentation text

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;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Demande 0 : 0, demande 9 : 2
Mad 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.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Demande 0 : 0, demande 9 : 2
NeoBASIC
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 return
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Demande 0 : 0, demande 9 : 2
65C02 assembly (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 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Demande 0 : 0, demande 9 : 2

← The Neo6502 API