Tachibana
Language: English

Group 4 — Mathematics Official

4,0 Addition · 4,1 Subtraction · 4,2 Multiplication · 4,3 Decimal Division · 4,4 Integer Division · 4,5 Integer Modulus · 4,6 Compare · 4,7 Power · 4,8 Distance (counter-rectangle) · 4,9 Angle calculation (arctangent2) · 4,16 Negate · 4,17 Floor · 4,18 Square Root · 4,19 Sine · 4,20 Cosine · 4,21 Tangent · 4,22 Arctangent · 4,23 Exponent · 4,24 Logarithm · 4,25 Absolute Value · 4,26 Sign · 4,27 Random Decimal · 4,28 Random Integer · 4,32 Number to Decimal · 4,33 String to Number · 4,34 Number to String · 4,35 Set Degree/Radian Mode

Group 4 is a maths coprocessor: the RP2040 computes in 32-bit integers or single-precision floats (IEEE 754) for the 65C02. Numbers do not go through the mailbox but through two registers kept in 65C02 memory, whose address each call gives.

A register is 5 bytes: a type byte ($00 integer, $40 float), then the 4 bytes of the value, low byte first. P0-P1 gives the address of the type byte of register 1; that of register 2 is at the next byte. P2 gives the step between two bytes of the same register: with a step of 2, both registers are interleaved over 10 bytes (types, then byte 0 of both values, then byte 1…). This is the layout of the examples, and that of the Mad Pascal neo6502math unit; NeoBASIC keeps its expression stack this way.

The result comes back in register 1, with its type. A two-register operation computes in floating point as soon as one of the two is a float, in integers otherwise. To print a result, the examples convert it to text with 4,34, which gives the firmware format (6 decimals for a float).

Angles are in degrees by default; 4,35 switches to radians. Starting a Mad Pascal program switches to radians (Mad Pascal 1.7.8 start-up code): the Pascal examples that use angles switch back to degrees.

4,0 Addition Official

Register 1 := register 1 + register 2.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombresum (float if either operand is)

Mad Pascal neo6502math unit (version 0.30.0): SetMathStack(v, 0) also writes position 1 (the position 0 code falls through into the position 1 code). Position 0 must therefore be set before position 1; in the other order, both registers hold the first number (checked: 7 \ 2 then gives 1). In NeoBASIC, + uses this call for floats; two integers are added by the 65C02.

Firmware documentation text

Register1 := Register 1 + Register2

C (llvm-mos)
/* Additionner deux nombres (groupe 4, fonction 0). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    flottant(1, 1.5f);                          /* registre 1 */
    flottant(2, 2.25f);                         /* registre 2 */
    calcul(0);                                      /* Addition */
    printf("1.5 + 2.25 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
1.5 + 2.25 = 3.750000
Mad Pascal
// Additionner deux nombres (groupe 4, fonction 0).
program calcul0;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: float;
    b: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 1.5;
  b := 2.25;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(0);                                 // Addition
  writeln('1.5 + 2.25 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
1.5 + 2.25 = 3.750000
NeoBASIC
10 ' Additionner deux nombres (groupe 4, fonction 0)
20 print "1.5 + 2.25 = ";1.5 + 2.25
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
1.5 + 2.25 = 3.750000
65C02 assembly (64tass)
; Additionner deux nombres (groupe 4, fonction 0).
        .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:  ldx #0                  ; fonction 0 : Addition
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $40, $40, $00, $00, $00, $00, $C0, $10, $3F, $40
        ; registre 1 : 1.5 (flottant), registre 2 : 2.25 (flottant) (types, puis octets entrelacés)
m:      .text "1.5 + 2.25 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
1.5 + 2.25 = 3.750000

4,1 Subtraction Official

Register 1 := register 1 − register 2.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombredifference

An integer and a float: the computation is done in floating point. In NeoBASIC, - uses this call for floats.

Firmware documentation text

Register1 := Register 1 - Register2

C (llvm-mos)
/* Soustraire deux nombres (groupe 4, fonction 1). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 10);                              /* registre 1 */
    flottant(2, 25.5f);                         /* registre 2 */
    calcul(1);                                      /* Subtraction */
    printf("10 - 25.5 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
10 - 25.5 = -15.500000
Mad Pascal
// Soustraire deux nombres (groupe 4, fonction 1).
program calcul1;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 10;
  b := 25.5;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(1);                                 // Subtraction
  writeln('10 - 25.5 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
10 - 25.5 = -15.500000
NeoBASIC
10 ' Soustraire deux nombres (groupe 4, fonction 1)
20 print "10 - 25.5 = ";10 - 25.5
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
10 - 25.5 = -15.500000
65C02 assembly (64tass)
; Soustraire deux nombres (groupe 4, 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:  ldx #1                  ; fonction 1 : Subtraction
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $40, $0A, $00, $00, $00, $00, $CC, $00, $41
        ; registre 1 : 10 (entier), registre 2 : 25.5 (flottant) (types, puis octets entrelacés)
m:      .text "10 - 25.5 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
10 - 25.5 = -15.500000

4,2 Multiplication Official

Register 1 := register 1 × register 2.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombreproduct (integer if both operands are)

Two integers give a 32-bit integer (no overflow check). In NeoBASIC, * always uses this call.

Firmware documentation text

Register1 := Register 1 * Register2

C (llvm-mos)
/* Multiplier deux entiers (groupe 4, fonction 2). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 6);                               /* registre 1 */
    entier(2, 7);                               /* registre 2 */
    calcul(2);                                      /* Multiplication */
    printf("6 * 7 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
6 * 7 = 42
Mad Pascal
// Multiplier deux entiers (groupe 4, fonction 2).
program calcul2;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 6;
  b := 7;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(2);                                 // Multiplication
  writeln('6 * 7 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
6 * 7 = 42
NeoBASIC
10 ' Multiplier deux entiers (groupe 4, fonction 2)
20 print "6 * 7 = ";6 * 7
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
6 * 7 = 42
65C02 assembly (64tass)
; Multiplier deux entiers (groupe 4, 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:  ldx #2                  ; fonction 2 : Multiplication
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $06, $07, $00, $00, $00, $00, $00, $00
        ; registre 1 : 6 (entier), registre 2 : 7 (entier) (types, puis octets entrelacés)
m:      .text "6 * 7 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
6 * 7 = 42

4,3 Decimal Division Official

Register 1 := register 1 / register 2, always in floating point.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombrequotient (float)
erreuruint81 if register 2 is 0

Even with two integers, the result is a float. In NeoBASIC, / makes this call.

Firmware documentation text

Register1 := Register 1 / Register2 (floating point)

C (llvm-mos)
/* Diviser en flottant (groupe 4, fonction 3). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 7);                               /* registre 1 */
    entier(2, 2);                               /* registre 2 */
    calcul(3);                                      /* Decimal Division */
    printf("7 / 2 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 / 2 = 3.500000
Mad Pascal
// Diviser en flottant (groupe 4, fonction 3).
program calcul3;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 7;
  b := 2;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(3);                                 // Decimal Division
  writeln('7 / 2 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 / 2 = 3.500000
NeoBASIC
10 ' Diviser en flottant (groupe 4, fonction 3)
20 print "7 / 2 = ";7 / 2
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 / 2 = 3.500000
65C02 assembly (64tass)
; Diviser en flottant (groupe 4, 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:  ldx #3                  ; fonction 3 : Decimal Division
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $07, $02, $00, $00, $00, $00, $00, $00
        ; registre 1 : 7 (entier), registre 2 : 2 (entier) (types, puis octets entrelacés)
m:      .text "7 / 2 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 / 2 = 3.500000

4,4 Integer Division Official

Register 1 := register 1 / register 2, in integers (truncated quotient).

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombreinteger quotient
erreuruint81 if register 2 is 0

Floats are converted to integers first. In NeoBASIC, \ makes this call.

Firmware documentation text

Register1 := Register 1 / Register2 (integer result)

C (llvm-mos)
/* Diviser en entier (groupe 4, fonction 4). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 7);                               /* registre 1 */
    entier(2, 2);                               /* registre 2 */
    calcul(4);                                      /* Integer Division */
    printf("7 \\ 2 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 \ 2 = 3
Mad Pascal
// Diviser en entier (groupe 4, fonction 4).
program calcul4;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 7;
  b := 2;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(4);                                 // Integer Division
  writeln('7 \ 2 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 \ 2 = 3
NeoBASIC
10 ' Diviser en entier (groupe 4, fonction 4)
20 print "7 \ 2 = ";7 \ 2
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 \ 2 = 3
65C02 assembly (64tass)
; Diviser en entier (groupe 4, 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:  ldx #4                  ; fonction 4 : Integer Division
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $07, $02, $00, $00, $00, $00, $00, $00
        ; registre 1 : 7 (entier), registre 2 : 2 (entier) (types, puis octets entrelacés)
m:      .text "7 \ 2 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
7 \ 2 = 3

4,5 Integer Modulus Official

Register 1 := remainder of the integer division of register 1 by register 2, computed on absolute values.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombreremainder (always zero or positive)
erreuruint81 if register 2 is 0

The firmware takes the absolute values of both operands: -17 % 5 gives 2 (not -2 as in C). In NeoBASIC, % makes this call.

Firmware documentation text

Register1 := Register 1 mod Register2

C (llvm-mos)
/* Reste d'une division entière (groupe 4, fonction 5). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, -17);                             /* registre 1 */
    entier(2, 5);                               /* registre 2 */
    calcul(5);                                      /* Integer Modulus */
    printf("-17 %% 5 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-17 % 5 = 2
Mad Pascal
// Reste d'une division entière (groupe 4, fonction 5).
program calcul5;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := -17;
  b := 5;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(5);                                 // Integer Modulus
  writeln('-17 % 5 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-17 % 5 = 2
NeoBASIC
10 ' Reste d'une division entiere (groupe 4, fonction 5)
20 n = -17 : print "-17 % 5 = ";n % 5
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-17 % 5 = 2
65C02 assembly (64tass)
; Reste d'une division entière (groupe 4, 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:  ldx #5                  ; fonction 5 : Integer Modulus
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $EF, $05, $FF, $00, $FF, $00, $FF, $00
        ; registre 1 : -17 (entier), registre 2 : 5 (entier) (types, puis octets entrelacés)
m:      .text "-17 % 5 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-17 % 5 = 2

4,6 Compare Official

Compares register 1 and register 2; the result comes back in P0.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
P0uint8$FF if register 1 < register 2, 0 if equal, 1 if greater

Between floats, the comparison is approximate: two numbers whose difference is below one ten-millionth of their size are equal. In NeoBASIC, float comparisons (<, =, >…) make this call; integer ones are done on the 65C02.

Firmware documentation text

Parameter:0 := Register 1 compare Register2 : returns $FF, 0, 1 for less equal and greater. Note: float comparison is approximate because of rounding.

C (llvm-mos)
/* Comparer deux flottants (groupe 4, fonction 6). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    flottant(1, 2.5f);                          /* registre 1 */
    flottant(2, 3.5f);                          /* registre 2 */
    calcul(6);                                  /* Compare */
    printf("compare(2.5, 3.5) = %u\n", ControlPort.params[0]);   /* $FF : plus petit */
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
compare(2.5, 3.5) = 255
Mad Pascal
// Comparer deux flottants (groupe 4, fonction 6).
program compare;
uses crt, neo6502, neo6502math;
var s: string[32];
    a, b: float;
    r: byte;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 2.5;
  b := 3.5;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(MATHCmp);                              // Compare
  r := NeoMessage.params[0];                    // $FF : plus petit
  writeln('compare(2.5, 3.5) = ', r);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
compare(2.5, 3.5) = 255
NeoBASIC
10 ' Comparer deux flottants (groupe 4, fonction 6)
20 print "2.5 < 3.5 : ";2.5 < 3.5
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
2.5 < 3.5 : -1
65C02 assembly (64tass)
; Comparer deux flottants (groupe 4, 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:  ldx #6                     ; fonction 6 : Compare
        jsr calcul
        lda ControlPort+4          ; P0 : $FF, 0 ou 1
        pha
        lda #<m
        ldx #>m
        jsr ecrire
        pla
        jsr decimal
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $40, $40, $00, $00, $00, $00, $20, $60, $40, $40
        ; registre 1 : 2.5 (flottant), registre 2 : 3.5 (flottant) (types, puis octets entrelacés)
m:      .text "compare(2.5, 3.5) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
compare(2.5, 3.5) = 255

4,7 Power Official

Register 1 := register 1 raised to the power of register 2, in floating point.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombrepower (float)

The result is always a float. In NeoBASIC, pow(a, b) makes this call.

Firmware documentation text

Register1 := Register 1 to the power of Register2 (floating point result whatever)

C (llvm-mos)
/* Élever à une puissance (groupe 4, fonction 7). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 2);                               /* registre 1 */
    entier(2, 10);                              /* registre 2 */
    calcul(7);                                      /* Power */
    printf("2 ^ 10 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
2 ^ 10 = 1024.000000
Mad Pascal
// Élever à une puissance (groupe 4, fonction 7).
program calcul7;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 2;
  b := 10;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(7);                                 // Power
  writeln('2 ^ 10 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
2 ^ 10 = 1024.000000
NeoBASIC
10 ' Élever à une puissance (groupe 4, fonction 7)
20 print "2 ^ 10 = ";pow(2, 10)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
2 ^ 10 = 1024.000000
65C02 assembly (64tass)
; Élever à une puissance (groupe 4, 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:  ldx #7                  ; fonction 7 : Power
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $02, $0A, $00, $00, $00, $00, $00, $00
        ; registre 1 : 2 (entier), registre 2 : 10 (entier) (types, puis octets entrelacés)
m:      .text "2 ^ 10 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
2 ^ 10 = 1024.000000

4,8 Distance (counter-rectangle) Official

Register 1 := square root of (register 1² + register 2²): the distance from point (x, y) to the origin.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombredistance (float)

No NeoBASIC keyword: the BASIC example writes the registers with poke.

Firmware documentation text

Register1 := Square root of (Register1 * Register1) + (Register2 * Register2)

C (llvm-mos)
/* Distance à l'origine d'un point (groupe 4, fonction 8). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 3);                               /* registre 1 */
    entier(2, 4);                               /* registre 2 */
    calcul(8);                                      /* Distance (counter-rectangle) */
    printf("distance(3, 4) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
distance(3, 4) = 5.000000
Mad Pascal
// Distance à l'origine d'un point (groupe 4, fonction 8).
program calcul8;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 3;
  b := 4;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(8);                                 // Distance (counter-rectangle)
  writeln('distance(3, 4) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
distance(3, 4) = 5.000000
NeoBASIC
10 ' Distance à l'origine d'un point (groupe 4, fonction 8)
20 r = alloc(10) : for i = 0 to 9 : poke r + i, 0 : next i
30 poke r + 2, 3 : poke r + 3, 4 : ' registre 1 : 3, registre 2 : 4 (entiers, pas de 2)
40 while peek($ff00) : wend
50 poke $ff04, r & 255 : poke $ff05, r >> 8 : poke $ff06, 2 : poke $ff01, 8 : poke $ff00, 4
60 while peek($ff00) : wend : t = alloc(34)
70 poke $ff04, r & 255 : poke $ff05, r >> 8 : poke $ff06, 2 : poke $ff08, t & 255 : poke $ff09, t >> 8 : poke $ff01, 34 : poke $ff00, 4
80 while peek($ff00) : wend : b = t : s$ = "" : for i = 1 to peek(b) : s$ = s$ + chr$(peek(b + i)) : next i
90 print "distance(3, 4) = ";s$
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
distance(3, 4) = 5.000000
65C02 assembly (64tass)
; Distance à l'origine d'un point (groupe 4, 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:  ldx #8                  ; fonction 8 : Distance (counter-rectangle)
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $03, $04, $00, $00, $00, $00, $00, $00
        ; registre 1 : 3 (entier), registre 2 : 4 (entier) (types, puis octets entrelacés)
m:      .text "distance(3, 4) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
distance(3, 4) = 5.000000

4,9 Angle calculation (arctangent2) Official

Register 1 := arc tangent of register 1 / register 2, in the right quadrant: the angle of point (x = register 2, y = register 1).

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte); register 2 is one byte further
P2uint8step between the bytes of a register
registre 1nombrefirst operand
registre 2nombresecond operand
Outputs
BytesTypeMeaning
registre 1nombreangle, in degrees or radians depending on 4,35

The firmware computes atan2(register 1, register 2): register 1 is the ordinate. In NeoBASIC, atan2(y, x) makes this call.

Firmware documentation text

Register1 := arctangent2(Register 1,Register 2) - angle in degrees/radians

C (llvm-mos)
/* Angle d'un point (groupe 4, fonction 9). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 1);                               /* registre 1 */
    entier(2, 1);                               /* registre 2 */
    calcul(9);                                      /* Angle calculation (arctangent2) */
    printf("atan2(1, 1) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan2(1, 1) = 45.000000
Mad Pascal
// Angle d'un point (groupe 4, fonction 9).
program calcul9;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  NeoWaitMessage;
  SetDegreeMode;                                // Mad Pascal démarre en radians
  a := 1;
  b := 1;
  SetMathStack(a, 0);                          // position 0 d'abord (voir 4,0)
  SetMathStack(b, 1);
  calcul(9);                                 // Angle calculation (arctangent2)
  writeln('atan2(1, 1) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan2(1, 1) = 45.000000
NeoBASIC
10 ' Angle d'un point (groupe 4, fonction 9)
20 print "atan2(1, 1) = ";atan2(1, 1)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan2(1, 1) = 45.000000
65C02 assembly (64tass)
; Angle d'un point (groupe 4, 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:  ldx #9                  ; fonction 9 : Angle calculation (arctangent2)
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $01, $01, $00, $00, $00, $00, $00, $00
        ; registre 1 : 1 (entier), registre 2 : 1 (entier) (types, puis octets entrelacés)
m:      .text "atan2(1, 1) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan2(1, 1) = 45.000000

4,16 Negate Official

Register 1 := −register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombreopposite, same type

In NeoBASIC, unary minus makes this call for a float; for an integer, it is not made (observed on the bench).

Firmware documentation text

Register1 := -Register 1

C (llvm-mos)
/* Changer de signe (groupe 4, fonction 16). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    flottant(1, 2.5f);                          /* registre 1 */
    calcul(16);                                     /* Negate */
    printf("-(2.5) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-(2.5) = -2.500000
Mad Pascal
// Changer de signe (groupe 4, fonction 16).
program calcul16;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 2.5;
  SetMathStack(a, 0);
  calcul(16);                                // Negate
  writeln('-(2.5) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-(2.5) = -2.500000
NeoBASIC
10 ' Changer de signe (groupe 4, fonction 16)
20 n = 2.5 : print "-(2.5) = ";-n
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-(2.5) = -2.500000
65C02 assembly (64tass)
; Changer de signe (groupe 4, 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:  ldx #16                 ; fonction 16 : Negate
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $40, $00, $00, $00, $00, $00, $20, $00, $40, $00
        ; registre 1 : 2.5 (flottant) (types, puis octets entrelacés)
m:      .text "-(2.5) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-(2.5) = -2.500000

4,17 Floor Official

Register 1 := largest integer less than or equal to register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombreinteger

The result is an integer. The firmware only converts if one of the two registers is marked float (it tests both types, like a two-register operation). In NeoBASIC, int( makes this call.

Firmware documentation text

Register1 := floor(Register 1)

C (llvm-mos)
/* Partie entière par défaut (groupe 4, fonction 17). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    flottant(1, -3.7f);                         /* registre 1 */
    calcul(17);                                     /* Floor */
    printf("floor(-3.7) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
floor(-3.7) = -4
Mad Pascal
// Partie entière par défaut (groupe 4, fonction 17).
program calcul17;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := -3.7;
  SetMathStack(a, 0);
  calcul(17);                                // Floor
  writeln('floor(-3.7) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
floor(-3.7) = -4
NeoBASIC
10 ' Partie entiere par defaut (groupe 4, fonction 17)
20 print "floor(-3.7) = ";int(-3.7)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
floor(-3.7) = -4
65C02 assembly (64tass)
; Partie entière par défaut (groupe 4, 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:  ldx #17                 ; fonction 17 : Floor
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $40, $00, $CD, $00, $CC, $00, $6C, $00, $C0, $00
        ; registre 1 : -3.7 (flottant) (types, puis octets entrelacés)
m:      .text "floor(-3.7) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
floor(-3.7) = -4

4,18 Square Root Official

Register 1 := square root of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombreroot (float)
erreuruint81 if register 1 is negative

Error 1 for a negative number. In NeoBASIC, sqr( makes this call.

Firmware documentation text

Register1 := square root(Register 1)

C (llvm-mos)
/* Racine carrée (groupe 4, fonction 18). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 2);                               /* registre 1 */
    calcul(18);                                     /* Square Root */
    printf("sqrt(2) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sqrt(2) = 1.414214
Mad Pascal
// Racine carrée (groupe 4, fonction 18).
program calcul18;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 2;
  SetMathStack(a, 0);
  calcul(18);                                // Square Root
  writeln('sqrt(2) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sqrt(2) = 1.414214
NeoBASIC
10 ' Racine carree (groupe 4, fonction 18)
20 print "sqrt(2) = ";sqr(2)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sqrt(2) = 1.414214
65C02 assembly (64tass)
; Racine carrée (groupe 4, 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:  ldx #18                 ; fonction 18 : Square Root
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $02, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 2 (entier) (types, puis octets entrelacés)
m:      .text "sqrt(2) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sqrt(2) = 1.414214

4,19 Sine Official

Register 1 := sine of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombresine (float)

Angle in degrees by default, in radians after 4,35 with P0 = 0. In NeoBASIC, sin( makes this call.

Firmware documentation text

Register1 := sine(Register 1) angles in degrees/radians

C (llvm-mos)
/* Sinus (groupe 4, fonction 19). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 30);                              /* registre 1 */
    calcul(19);                                     /* Sine */
    printf("sin(30) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sin(30) = 0.500000
Mad Pascal
// Sinus (groupe 4, fonction 19).
program calcul19;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  NeoWaitMessage;
  SetDegreeMode;                                // Mad Pascal démarre en radians
  a := 30;
  SetMathStack(a, 0);
  calcul(19);                                // Sine
  writeln('sin(30) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sin(30) = 0.500000
NeoBASIC
10 ' Sinus (groupe 4, fonction 19)
20 print "sin(30) = ";sin(30)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sin(30) = 0.500000
65C02 assembly (64tass)
; Sinus (groupe 4, fonction 19).
        .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:  ldx #19                 ; fonction 19 : Sine
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $1E, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 30 (entier) (types, puis octets entrelacés)
m:      .text "sin(30) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sin(30) = 0.500000

4,20 Cosine Official

Register 1 := cosine of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombrecosine (float)

Angle in degrees by default (see 4,35). In NeoBASIC, cos( makes this call.

Firmware documentation text

Register1 := cosine(Register 1) angles in degrees/radians

C (llvm-mos)
/* Cosinus (groupe 4, fonction 20). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 60);                              /* registre 1 */
    calcul(20);                                     /* Cosine */
    printf("cos(60) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
cos(60) = 0.500000
Mad Pascal
// Cosinus (groupe 4, fonction 20).
program calcul20;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  NeoWaitMessage;
  SetDegreeMode;                                // Mad Pascal démarre en radians
  a := 60;
  SetMathStack(a, 0);
  calcul(20);                                // Cosine
  writeln('cos(60) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
cos(60) = 0.500000
NeoBASIC
10 ' Cosinus (groupe 4, fonction 20)
20 print "cos(60) = ";cos(60)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
cos(60) = 0.500000
65C02 assembly (64tass)
; Cosinus (groupe 4, fonction 20).
        .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:  ldx #20                 ; fonction 20 : Cosine
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $3C, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 60 (entier) (types, puis octets entrelacés)
m:      .text "cos(60) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
cos(60) = 0.500000

4,21 Tangent Official

Register 1 := tangent of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombretangent (float)

Angle in degrees by default (see 4,35). In NeoBASIC, tan( makes this call.

Firmware documentation text

Register1 := tangent(Register 1) angles in degrees/radians

C (llvm-mos)
/* Tangente (groupe 4, fonction 21). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 45);                              /* registre 1 */
    calcul(21);                                     /* Tangent */
    printf("tan(45) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
tan(45) = 1.000000
Mad Pascal
// Tangente (groupe 4, fonction 21).
program calcul21;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  NeoWaitMessage;
  SetDegreeMode;                                // Mad Pascal démarre en radians
  a := 45;
  SetMathStack(a, 0);
  calcul(21);                                // Tangent
  writeln('tan(45) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
tan(45) = 1.000000
NeoBASIC
10 ' Tangente (groupe 4, fonction 21)
20 print "tan(45) = ";tan(45)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
tan(45) = 1.000000
65C02 assembly (64tass)
; Tangente (groupe 4, fonction 21).
        .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:  ldx #21                 ; fonction 21 : Tangent
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $2D, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 45 (entier) (types, puis octets entrelacés)
m:      .text "tan(45) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
tan(45) = 1.000000

4,22 Arctangent Official

Register 1 := arc tangent of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombreangle (float), in degrees or radians depending on 4,35

In NeoBASIC, atan( makes this call.

Firmware documentation text

Register1 := arctangent(Register 1) angles in degrees/radians

C (llvm-mos)
/* Arc tangente (groupe 4, fonction 22). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 1);                               /* registre 1 */
    calcul(22);                                     /* Arctangent */
    printf("atan(1) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) = 45.000000
Mad Pascal
// Arc tangente (groupe 4, fonction 22).
program calcul22;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  NeoWaitMessage;
  SetDegreeMode;                                // Mad Pascal démarre en radians
  a := 1;
  SetMathStack(a, 0);
  calcul(22);                                // Arctangent
  writeln('atan(1) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) = 45.000000
NeoBASIC
10 ' Arc tangente (groupe 4, fonction 22)
20 print "atan(1) = ";atan(1)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) = 45.000000
65C02 assembly (64tass)
; Arc tangente (groupe 4, fonction 22).
        .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:  ldx #22                 ; fonction 22 : Arctangent
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $01, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 1 (entier) (types, puis octets entrelacés)
m:      .text "atan(1) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) = 45.000000

4,23 Exponent Official

Register 1 := e to the power of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombreexponential (float)

In NeoBASIC, exp( makes this call.

Firmware documentation text

Register1 := e to the power of Register 1

C (llvm-mos)
/* Exponentielle (groupe 4, fonction 23). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 1);                               /* registre 1 */
    calcul(23);                                     /* Exponent */
    printf("exp(1) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
exp(1) = 2.718282
Mad Pascal
// Exponentielle (groupe 4, fonction 23).
program calcul23;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 1;
  SetMathStack(a, 0);
  calcul(23);                                // Exponent
  writeln('exp(1) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
exp(1) = 2.718282
NeoBASIC
10 ' Exponentielle (groupe 4, fonction 23)
20 print "exp(1) = ";exp(1)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
exp(1) = 2.718282
65C02 assembly (64tass)
; Exponentielle (groupe 4, fonction 23).
        .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:  ldx #23                 ; fonction 23 : Exponent
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $01, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 1 (entier) (types, puis octets entrelacés)
m:      .text "exp(1) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
exp(1) = 2.718282

4,24 Logarithm Official

Register 1 := natural logarithm of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombrelogarithm (float)
erreuruint81 if register 1 is negative

Error 1 for a negative number. In NeoBASIC, log( makes this call.

Firmware documentation text

Register1 := log(Register 1) natural logarithm

C (llvm-mos)
/* Logarithme népérien (groupe 4, fonction 24). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 10);                              /* registre 1 */
    calcul(24);                                     /* Logarithm */
    printf("log(10) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
log(10) = 2.302585
Mad Pascal
// Logarithme népérien (groupe 4, fonction 24).
program calcul24;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 10;
  SetMathStack(a, 0);
  calcul(24);                                // Logarithm
  writeln('log(10) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
log(10) = 2.302585
NeoBASIC
10 ' Logarithme neperien (groupe 4, fonction 24)
20 print "log(10) = ";log(10)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
log(10) = 2.302585
65C02 assembly (64tass)
; Logarithme népérien (groupe 4, fonction 24).
        .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:  ldx #24                 ; fonction 24 : Logarithm
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $0A, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 10 (entier) (types, puis octets entrelacés)
m:      .text "log(10) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
log(10) = 2.302585

4,25 Absolute Value Official

Register 1 := absolute value of register 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombreabsolute value, same type

In NeoBASIC, abs( makes this call.

Firmware documentation text

Register1 := absolute value(Register 1)

C (llvm-mos)
/* Valeur absolue (groupe 4, fonction 25). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    flottant(1, -7.25f);                        /* registre 1 */
    calcul(25);                                     /* Absolute Value */
    printf("abs(-7.25) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abs(-7.25) = 7.250000
Mad Pascal
// Valeur absolue (groupe 4, fonction 25).
program calcul25;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := -7.25;
  SetMathStack(a, 0);
  calcul(25);                                // Absolute Value
  writeln('abs(-7.25) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abs(-7.25) = 7.250000
NeoBASIC
10 ' Valeur absolue (groupe 4, fonction 25)
20 print "abs(-7.25) = ";abs(-7.25)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abs(-7.25) = 7.250000
65C02 assembly (64tass)
; Valeur absolue (groupe 4, fonction 25).
        .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:  ldx #25                 ; fonction 25 : Absolute Value
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $40, $00, $00, $00, $00, $00, $E8, $00, $C0, $00
        ; registre 1 : -7.25 (flottant) (types, puis octets entrelacés)
m:      .text "abs(-7.25) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
abs(-7.25) = 7.250000

4,26 Sign Official

Register 1 := sign of register 1: −1, 0 or 1.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombre−1, 0 or 1 (integer)

In NeoBASIC, sgn( makes this call.

Firmware documentation text

Register1 := sign(Register 1), returns -1 0 or 1

C (llvm-mos)
/* Signe (groupe 4, fonction 26). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    flottant(1, -3.5f);                         /* registre 1 */
    calcul(26);                                     /* Sign */
    printf("sgn(-3.5) = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sgn(-3.5) = -1
Mad Pascal
// Signe (groupe 4, fonction 26).
program calcul26;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := -3.5;
  SetMathStack(a, 0);
  calcul(26);                                // Sign
  writeln('sgn(-3.5) = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sgn(-3.5) = -1
NeoBASIC
10 ' Signe (groupe 4, fonction 26)
20 print "sgn(-3.5) = ";sgn(-3.5)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sgn(-3.5) = -1
65C02 assembly (64tass)
; Signe (groupe 4, fonction 26).
        .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:  ldx #26                 ; fonction 26 : Sign
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $40, $00, $00, $00, $00, $00, $60, $00, $C0, $00
        ; registre 1 : -3.5 (flottant) (types, puis octets entrelacés)
m:      .text "sgn(-3.5) = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
sgn(-3.5) = -1

4,27 Random Decimal Official

Register 1 := random number between 0 (included) and 1 (excluded).

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
Outputs
BytesTypeMeaning
registre 1nombrerandom number (float)

The firmware draws an integer from 0 to 31999 and divides it by 32000: 32000 possible values. In NeoBASIC, rnd( makes this call.

Firmware documentation text

Register1 := random float from 0-1

C (llvm-mos)
/* Tirer un nombre au hasard entre 0 et 1 (groupe 4, fonction 27). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    calcul(27);                                 /* Random Decimal */
    printf("Hasard : %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Hasard : 0.043219
Mad Pascal
// Tirer un nombre au hasard entre 0 et 1 (groupe 4, fonction 27).
program hasard;
uses crt, neo6502, neo6502math;
var s: string[32];

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  calcul(MATHFRnd);                             // Random Decimal
  writeln('Hasard : ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Hasard : 0.043219
NeoBASIC
10 ' Tirer un nombre au hasard entre 0 et 1 (groupe 4, fonction 27)
20 print "Hasard : ";rnd(1)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Hasard : 0.043219
65C02 assembly (64tass)
; Tirer un nombre au hasard entre 0 et 1 (groupe 4, fonction 27).
        .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:  ldx #27                    ; fonction 27 : Random Decimal
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .fill 10
m:      .text "Hasard : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Hasard : 0.043219

4,28 Random Integer Official

Register 1 := random integer from 0 to (register 1 − 1).

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
Outputs
BytesTypeMeaning
registre 1nombrerandom integer

If register 1 is 0 or less, it is left unchanged. In NeoBASIC, rand( makes this call.

Firmware documentation text

Register1 := random integer from 0 to (Register 1-1)

C (llvm-mos)
/* Lancer un dé à 6 faces (groupe 4, fonction 28). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, 6);                               /* registre 1 */
    calcul(28);                                     /* Random Integer */
    printf("Tirage de 0 a 5 : %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Tirage de 0 a 5 : 1
Mad Pascal
// Lancer un dé à 6 faces (groupe 4, fonction 28).
program calcul28;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 6;
  SetMathStack(a, 0);
  calcul(28);                                // Random Integer
  writeln('Tirage de 0 a 5 : ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Tirage de 0 a 5 : 1
NeoBASIC
10 ' Lancer un de à 6 faces (groupe 4, fonction 28)
20 print "Tirage de 0 a 5 : ";rand(6)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Tirage de 0 a 5 : 1
65C02 assembly (64tass)
; Lancer un dé à 6 faces (groupe 4, fonction 28).
        .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:  ldx #28                 ; fonction 28 : Random Integer
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $06, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 6 (entier) (types, puis octets entrelacés)
m:      .text "Tirage de 0 a 5 : ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
Tirage de 0 a 5 : 1

4,32 Number to Decimal Official

Adds to register 1 a decimal part given as BCD digits: it is the NeoBASIC tokeniser helper for decimal constants.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreinteger part
P4-P5addraddress of the digits after the point, two per byte (BCD), ended by a $F nibble
Outputs
BytesTypeMeaning
registre 1nombreregister 1 + 0.digits (float)

The firmware documentation says not to use it: it is an internal NeoBASIC helper, called for each decimal constant of a program (1.5, 3.14…). The Mad Pascal neo6502math unit wraps it in AddFractionalBCD. Example: 3 and the digits 1 4 1 5 9 ($14 $15 $9F) give 3.14159.

Firmware documentation text

Helper function for tokeniser, do not use.

C (llvm-mos)
/* Ajouter une partie décimale en BCD (groupe 4, fonction 32). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

static const uint8_t chiffres[] = { 0x14, 0x15, 0x9F };   /* 1 4 1 5 9, fin : $F */

int main(void) {
    entier(1, 3);                               /* registre 1 : partie entière */
    ControlPort.params[4] = (uint16_t)chiffres & 0xFF;  /* P4-P5 : chiffres */
    ControlPort.params[5] = (uint16_t)chiffres >> 8;
    calcul(32);                                 /* Number to Decimal */
    printf("3 + 0,14159 = %s\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
3 + 0,14159 = 3.141590
Mad Pascal
// Ajouter une partie décimale en BCD (groupe 4, fonction 32).
program decimales;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    chiffres: array[0..2] of byte = ($14, $15, $9F);   // 1 4 1 5 9, fin : $F

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := 3;
  SetMathStack(a, 0);                          // registre 1 : partie entière
  wordParams[2] := word(@chiffres);             // P4-P5 : chiffres
  calcul(MATHProcessDecimal);                   // Number to Decimal
  writeln('3 + 0,14159 = ', texte);
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
3 + 0,14159 = 3.141590
NeoBASIC
10 ' Ajouter une partie decimale en BCD (groupe 4, fonction 32)
20 ' NeoBASIC fait cet appel pour chaque constante decimale, ici 3.14159
30 print "3 + 0,14159 = ";3.14159
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
3 + 0,14159 = 3.141590
65C02 assembly (64tass)
; Ajouter une partie décimale en BCD (groupe 4, fonction 32).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<chiffres
        sta ControlPort+8          ; P4-P5 : chiffres
        lda #>chiffres
        sta ControlPort+9
        ldx #32                    ; fonction 32 : Number to Decimal
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jmp WriteCharacter

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $03, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 3 (entier) (types, puis octets entrelacés)
chiffres: .byte $14, $15, $9F     ; 1 4 1 5 9, fin : $F
m:      .text "3 + 0,14159 = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
3 + 0,14159 = 3.141590

4,33 String to Number Official

Converts a text into a number in register 1: integer if it has no decimal part, float otherwise.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
P4-P5addraddress of the text (length-prefixed)
Outputs
BytesTypeMeaning
registre 1nombrenumber
erreuruint81 if the text is not a number

The example converts "2.5" then prints the resulting type ($40: float). In NeoBASIC, val( makes this call, as does input for a number. The Mad Pascal neo6502math unit uses it in NeoParseInt and NeoParseFloat.

Firmware documentation text

Convert the length prefixed string at Parameters:4,5 to a constant in Register1.

C (llvm-mos)
/* Convertir un texte en nombre (groupe 4, fonction 33). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

static const uint8_t nombre[] = "\x03" "2.5";

int main(void) {
    ControlPort.params[4] = (uint16_t)nombre & 0xFF;    /* P4-P5 : texte */
    ControlPort.params[5] = (uint16_t)nombre >> 8;
    calcul(33);                                 /* String to Number */
    uint8_t type = reg[0];                      /* $40 : flottant */
    printf("\"2.5\" -> %s (type %u)\n", en_texte(), type);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
"2.5" -> 2.500000 (type 64)
Mad Pascal
// Convertir un texte en nombre (groupe 4, fonction 33).
program valeur;
uses crt, neo6502, neo6502math;
var s: string[32];
    nombre: string[8];
    t: byte;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  nombre := '2.5';
  wordParams[2] := word(@nombre);               // P4-P5 : texte
  calcul(MATHConvertStringToNumber);            // String to Number
  t := peek($F5);                               // type du registre 1 : $40, flottant
  writeln('"2.5" -> ', texte, ' (type ', t, ')');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
"2.5" -> 2.500000 (type 64)
NeoBASIC
10 ' Convertir un texte en nombre (groupe 4, fonction 33)
20 print chr$(34);"2.5";chr$(34);" -> ";val("2.5")
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
"2.5" -> 2.500000
65C02 assembly (64tass)
; Convertir un texte en nombre (groupe 4, fonction 33).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<nombre
        sta ControlPort+8          ; P4-P5 : texte
        lda #>nombre
        sta ControlPort+9
        ldx #33                    ; fonction 33 : String to Number
        jsr calcul
        lda reg                    ; type du registre 1 : $40, flottant
        sta type
        lda #<m1
        ldx #>m1
        jsr ecrire
        jsr affiche
        lda #<m2
        ldx #>m2
        jsr ecrire
        lda type
        jsr decimal
        lda #<m3
        ldx #>m3
        jmp ecrire

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .fill 10
nombre: .byte 3
        .text "2.5"
type:   .byte 0
m1:     .text '"2.5" -> ', 0
m2:     .text " (type ", 0
m3:     .text ")", 13, 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
"2.5" -> 2.500000 (type 64)

4,34 Number to String Official

Converts register 1 into text (length-prefixed): integer in decimal, float with 6 decimals.

Inputs
BytesTypeMeaning
P0-P1addraddress of register 1 (type byte)
P2uint8step between the bytes of the register
registre 1nombreoperand
P4-P5addraddress of the text buffer
Outputs
BytesTypeMeaning
tamponstringtext (length-prefixed)

C format: %d for an integer, %f for a float (0.250000). On Trinity, the write is bounded to the end of 65C02 memory (T-59); the official firmware writes as many characters as the number needs. NeoBASIC makes this call to print a number (print) and in str$(.

Firmware documentation text

Convert the constant in Register1 to a length prefixed string which is stored at Parameters:4,5

C (llvm-mos)
/* Convertir des nombres en texte (groupe 4, fonction 34). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

int main(void) {
    entier(1, -123);
    printf("-123 -> \"%s\"\n", en_texte());  /* en_texte : Number to String */
    flottant(1, 0.25f);
    printf("0.25 -> \"%s\"\n", en_texte());
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-123 -> "-123"
0.25 -> "0.250000"
Mad Pascal
// Convertir des nombres en texte (groupe 4, fonction 34).
program texte34;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;
    b: float;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  a := -123;
  SetMathStack(a, 0);
  writeln('-123 -> "', texte, '"');             // texte : Number to String
  b := 0.25;
  SetMathStack(b, 0);
  writeln('0.25 -> "', texte, '"');
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-123 -> "-123"
0.25 -> "0.250000"
NeoBASIC
10 ' Convertir des nombres en texte (groupe 4, fonction 34)
20 print "-123 -> ";chr$(34);str$(-123);chr$(34)
30 print "0.25 -> ";chr$(34);str$(0.25);chr$(34)
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-123 -> "-123"
0.25 -> "0.250000"
65C02 assembly (64tass)
; Convertir des nombres en texte (groupe 4, fonction 34).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #<m1
        ldx #>m1
        jsr ecrire
        jsr affiche                ; affiche : fonction 34, Number to String
        lda #<m2
        ldx #>m2
        jsr ecrire
        ldx #9
_copie: lda quart,x                ; registre 1 := 0.25
        sta reg,x
        dex
        bpl _copie
        lda #<m3
        ldx #>m3
        jsr ecrire
        jsr affiche
        lda #<m2
        ldx #>m2
        jmp ecrire

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $85, $00, $FF, $00, $FF, $00, $FF, $00
        ; registre 1 : -123 (entier) (types, puis octets entrelacés)
quart:  .byte $40, $00, $00, $00, $00, $00, $80, $00, $3E, $00
        ; registre 1 : 0.25 (flottant) (types, puis octets entrelacés)
m1:     .text '-123 -> "', 0
m2:     .text '"', 13, 0
m3:     .text '0.25 -> "', 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
-123 -> "-123"
0.25 -> "0.250000"

4,35 Set Degree/Radian Mode Official

Selects the angle unit of functions 9, 19 to 22: degrees (default) or radians.

Inputs
BytesTypeMeaning
P0uint8non zero: degrees; 0: radians

Outputs: none.

The setting holds for all programs until the next call. The Mad Pascal 1.7.8 start-up code switches to radians; its SetDegreeMode and SetRadianMode routines make this call. In NeoBASIC, clear (and so run) restores degrees. The example switches to radians, computes atan(1) = π/4, then goes back to degrees.

NeoBASIC keywords that make this call: clear

Firmware documentation text

Sets the use of degrees (the default) when non zero, radians when zero.

C (llvm-mos)
/* Calculer en radians, puis revenir aux degrés (groupe 4, fonction 35). */
#include <stdio.h>
#include <neo6502.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 reg[10];                         /* registres 1 et 2 entrelacés, pas de 2 */
static char texte[34];

static void entier(uint8_t r, int32_t v) {      /* registre r (1 ou 2) := entier v */
    reg[r - 1] = 0x00;
    for (uint8_t i = 0; i < 4; i++)
        reg[r + 1 + 2 * i] = (uint8_t)(v >> (8 * i));
}
static void flottant(uint8_t r, float v) {      /* registre r := flottant v */
    union { float f; int32_t i; } u;
    u.f = v;
    entier(r, u.i);
    reg[r - 1] = 0x40;
}
static void calcul(uint8_t fonction) {          /* appel du groupe 4 sur les registres */
    libre();
    ControlPort.params[0] = (uint16_t)reg & 0xFF;
    ControlPort.params[1] = (uint16_t)reg >> 8;
    ControlPort.params[2] = 2;                  /* pas */
    api(4, fonction);
}
static const char *en_texte(void) {             /* registre 1 en texte, par 4,34 */
    ControlPort.params[4] = (uint16_t)texte & 0xFF;
    ControlPort.params[5] = (uint16_t)texte >> 8;
    calcul(34);
    texte[(uint8_t)texte[0] + 1] = 0;
    return texte + 1;
}

static void mode(uint8_t degres) {
    libre();
    ControlPort.params[0] = degres;             /* P0 : 0 radians, sinon degrés */
    api(4, 35);                                 /* Set Degree/Radian Mode */
}

int main(void) {
    mode(0);
    entier(1, 1);
    calcul(22);                                 /* 4,22 : arc tangente */
    printf("atan(1) en radians = %s\n", en_texte());
    mode(1);
    return 0;
}
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) en radians = 0.785398
Mad Pascal
// Calculer en radians, puis revenir aux degrés (groupe 4, fonction 35).
program radians;
uses crt, neo6502, neo6502math;
var s: string[32];
    a: integer;

procedure calcul(f: byte);                      // appel du groupe 4 sur la pile ($F5, pas de 2)
begin
  DoMathOnStack(f);
  NeoWaitMessage;                               // attendre le résultat
end;

function texte: string;                         // registre 1 en texte, par 4,34
begin
  wordParams[2] := word(@s);                    // P4-P5 : tampon
  calcul(MATHConvertNumberToString);
  result := s;
end;

begin
  NeoWaitMessage;
  SetRadianMode;                                // Set Degree/Radian Mode, P0 = 0
  a := 1;
  SetMathStack(a, 0);
  calcul(MATHATan);                             // 4,22 : arc tangente
  writeln('atan(1) en radians = ', texte);
  NeoWaitMessage;
  SetDegreeMode;                                // P0 = 1
  NeoWaitMessage;
end.
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) en radians = 0.785398
NeoBASIC
10 ' Calculer en radians, puis revenir aux degres (groupe 4, fonction 35)
20 while peek($ff00) : wend
30 poke $ff04, 0 : poke $ff01, 35 : poke $ff00, 4 : ' radians
40 while peek($ff00) : wend
50 print "atan(1) en radians = ";atan(1)
60 while peek($ff00) : wend
70 poke $ff04, 1 : poke $ff01, 35 : poke $ff00, 4 : ' degres
80 while peek($ff00) : wend
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) en radians = 0.785398
65C02 assembly (64tass)
; Calculer en radians, puis revenir aux degrés (groupe 4, fonction 35).
        .cpu "65c02"
        * = $0800
ControlPort    = $FF00             ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage    = $FFF4             ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1             ; affiche le caractère de A

start:  lda #0
        jsr mode                   ; radians
        ldx #22                    ; 4,22 : arc tangente
        jsr calcul
        lda #<m
        ldx #>m
        jsr ecrire
        jsr affiche
        lda #13
        jsr WriteCharacter
        lda #1                     ; retour aux degrés
mode:   pha
        jsr WaitMessage
        pla
        sta ControlPort+4          ; P0 : 0 radians, sinon degrés
        lda #4
        ldx #35                    ; fonction 35 : Set Degree/Radian Mode
        jmp appel

; Appel du groupe 4, fonction X, sur les registres de reg (pas de 2).
calcul: jsr WaitMessage
        lda #<reg
        sta ControlPort+4          ; P0-P1 : registre 1
        lda #>reg
        sta ControlPort+5
        lda #2
        sta ControlPort+6          ; P2 : pas
        lda #4
        jmp appel

; Affiche le registre 1, converti en texte par 4,34.
affiche:
        jsr WaitMessage
        lda #<texte
        sta ControlPort+8          ; P4-P5 : tampon
        lda #>texte
        sta ControlPort+9
        ldx #34
        jsr calcul
        lda #<texte
        ldx #>texte
        jmp pecrire
texte:  .fill 34

; Affiche la chaîne précédée de sa longueur dont l'adresse est dans A (poids faible) et X (poids fort).
pecrire:
        sta ptr
        stx ptr+1
        lda (ptr)
        sta reste
        ldy #1
_p:     lda reste
        beq _pf
        lda (ptr),y
        jsr WriteCharacter
        iny
        dec reste
        bra _p
_pf:    rts
reste:  .byte 0

; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
        stx ptr+1
        ldy #0
_e:     lda (ptr),y
        beq _f
        jsr WriteCharacter
        iny
        bne _e
_f:     rts

; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
        phx
        phy
        ldx #0
        ldy #100
        jsr _chiffre
        ldy #10
        jsr _chiffre
        ora #'0'
        jsr WriteCharacter
        ply
        plx
        rts
_chiffre:
        sty diviseur
        ldy #0
_div:   cmp diviseur
        bcc _fini
        sbc diviseur
        iny
        bne _div
_fini:  pha
        tya
        bne _ecrit
        cpx #0
        beq _saute
_ecrit: ora #'0'
        jsr WriteCharacter
        ldx #1
_saute: pla
        rts

; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel:  stx ControlPort+1
        sta ControlPort            ; écrit en dernier : lance l'appel
        jmp WaitMessage

ptr      = $80
diviseur: .byte 0

reg:    .byte $00, $00, $01, $00, $00, $00, $00, $00, $00, $00
        ; registre 1 : 1 (entier) (types, puis octets entrelacés)
m:      .text "atan(1) en radians = ", 0
Output observed in the Phosphoneo emulator, Trinity firmware 0.16.69:
atan(1) en radians = 0.785398

← The Neo6502 API