Programmazione di TI-84 Plus CE (identica alla TI-83 Premium CE, versione francese) con un emulatore
Per prima cosa si inizia con il compilare l'emulatore
sudo apt update
sudo apt install liblua5.4-dev libpng-dev
git clone https://github.com/ThePhD/sol2.git
cd sol2
mkdir build && cd build
cmake .. -Dsol2_BUILD_TESTS=OFF -Dsol2_BUILD_EXAMPLES=OFF
sudo cmake --install .
git clone --recursive https://github.com/CE-Programming/CEmu.git
cd CEmu
cmake ../gui/qt
cmake -DLUA_VERSION=5.4 ../gui/qt
mkdir build && cd build
cmake ..
Per il funzionamento dell'emulatore si deve scaricare il firmware in formato .rom. Il link seguente e' per il firmware 5.3
https://web.archive.org/web/20231217022137/https://tiroms.weebly.com/uploads/1/1/0/5/110560031/ti-84ce.rom
successivamente si puo' aggiornare il firmware alla versione 5.8.3 da
https://tiplanet.org/forum/archives_voir.php?id=4601907
ed inviandolo all'emulatore tramite
~/CEmu/build/CEmu --send /home/luca/Downloads/os_prd_48.8eu
messo a punto l'emulatore si passa al compilatore
sudo mkdir -p /opt/CEdev
cd /opt/CEdev
curl -sL https://github.com/CE-Programming/toolchain/releases/latest/download/CEdev-Linux.tar.gz | sudo tar -xz
echo 'export CEDEV=/opt/CEdev' >> ~/.bashrc
echo 'export PATH=$CEDEV/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
in /opt/CEDev/examples ci sono numerosi esempi che si compilano tramite make come hello world. Dopo la compilazione si trova il file /bin/DEMO.8xp che si puo' inviare all'emulatore tramite
~/CEmu/build/CEmu --send ./bin/DEMO.8xp
per lanciare il programma si preme il tasto prgm (quarta fila dall'alto, terzo da sinistra), si ha la lista dei programmi installati, si sceglie il numero relativo al programma (si avra' prgmDEMO) e si preme enter
se si ha l'errore libload si deve inviare il file clibs.8xg scaricato da qui
https://github.com/CE-Programming/libraries/releases/tag/v15.0
tramite
~/CEmu/build/CEmu --send ~/Downloads/clibs.8xg
di seguito un esempio di Mandelbrot scritto
/*
* Mandelbrot per TI-84 Plus CE - CE C Toolchain (CEdev)
*
* Usa solo gli header del toolchain (ti/getcsc.h, ti/screen.h): nessuna
* libreria esterna, quindi sulla calcolatrice non serve LibLoad.
*
* Virgola fissa con 8 bit frazionari (1.0 = 256). Sull'ez80 `int` e' a
* 24 bit: con |valore| < 1700 il prodotto resta sotto 2^23, quindi non
* c'e' overflow nemmeno nell'iterazione in cui il punto diverge.
*
* Ottimizzazioni (le stesse di mandelf.asm):
* - test algebrico per cardioide e bulbo di periodo 2 (niente iterazioni);
* - simmetria rispetto all'asse reale: si calcolano le righe 0..120 e le
* righe 1..119 vengono copiate in 239..121.
*/
#include <stdint.h>
#include <string.h>
#include <ti/getcsc.h>
#include <ti/screen.h>
#define LCD_WIDTH 320
#define LCD_HEIGHT 240
#define F 8 /* bit frazionari */
#define ONE (1 << F)
#define STEP 3 /* passo per pixel (3/256) */
#define MAXITER 30
#define X0 (-640) /* c_re iniziale: -2.5 */
#define Y0 (-360) /* c_im iniziale: -1.406 */
#define VRAM ((uint16_t *)0xD40000)
#define LCD_UPBASE (*(volatile uint24_t *)0xE30010)
#define LCD_CTRL (*(volatile uint8_t *)0xE30018)
static uint16_t palette[MAXITER + 1];
static uint16_t rgb565(int r, int g, int b)
{
return (uint16_t)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
}
/* 1 se c sta nel bulbo di periodo 2 o nella cardioide principale */
static int in_main_bulbs(int cx, int cy2)
{
int t = cx + ONE;
int xm, q;
if (((t * t) >> F) + cy2 < ONE / 16) /* (x+1)^2 + y^2 < 1/16 */
return 1;
xm = cx - ONE / 4;
q = ((xm * xm) >> F) + cy2; /* (x-1/4)^2 + y^2 */
return ((q * (q + xm)) >> F) < (cy2 >> 2); /* q(q+x-1/4) < y^2/4 */
}
int main(void)
{
uint16_t *vram = VRAM;
int n, px, py;
os_ClrHomeFull();
/* LCD: buffer in vRam, 16 bpp (5:6:5) */
LCD_UPBASE = 0xD40000;
LCD_CTRL = 0x2D;
/* colori: blu per i punti che divergono subito, arancio vicino al bordo */
palette[0] = 0;
for (n = 1; n < MAXITER; n++) {
int t = n * 255 / MAXITER;
palette[n] = rgb565(t, (t * t) >> 8, 255 - t);
}
palette[MAXITER] = 0; /* interno: nero */
for (py = 0; py <= LCD_HEIGHT / 2; py++) {
int cy = Y0 + py * STEP;
int cy2 = (cy * cy) >> F;
int near_axis = cy2 < 112; /* |y| < ~0.66 */
int cx = X0;
uint16_t *row = vram + py * LCD_WIDTH;
for (px = 0; px < LCD_WIDTH; px++, cx += STEP) {
if (near_axis && cx < ONE * 3 / 8 && cx >= -(ONE * 5 / 4)
&& in_main_bulbs(cx, cy2)) {
n = MAXITER;
} else {
int x = 0, y = 0, x2 = 0, y2 = 0;
for (n = 0; n < MAXITER && x2 + y2 < 4 * ONE; n++) {
y = ((x * y) >> (F - 1)) + cy; /* 2xy + cy */
x = x2 - y2 + cx;
x2 = (x * x) >> F;
y2 = (y * y) >> F;
}
}
row[px] = palette[n];
}
/* specchio: riga py -> riga 240-py (per py = 1..119) */
if (py > 0 && py < LCD_HEIGHT / 2) {
memcpy(vram + (LCD_HEIGHT - py) * LCD_WIDTH, row,
LCD_WIDTH * sizeof(uint16_t));
}
}
while (os_GetCSC()) { } /* aspetta il rilascio dei tasti */
while (!os_GetCSC()) { } /* poi un nuovo tasto */
os_ClrHomeFull();
os_DrawStatusBar();
return 0;
}
# ----------------------------
# Makefile per CE C Toolchain
# ----------------------------
NAME = MANDELC
DESCRIPTION = "Mandelbrot"
COMPRESSED = NO
CFLAGS = -Wall -Wextra -O3
CXXFLAGS = -Wall -Wextra -O3
# ----------------------------
include $(CEDEV)/meta/makefile.mk
Sulla calcolatrice si possono esegire anche programmi in Assembler ma c'e' un dettaglio importante. Texas Instruments da un firmware in poi ha rimosso questa opzione e questo succede anche l'emulare...ho quindi dovuto fare il downgrade alla versione 5.3 per effettuare questa prova (tecnicamente non e' vero..esiste un jailbreak per continuare ad usare programmi compilati in assembler su firmware moderni)
per compilare si usa fasmg programma.asm MANDEL.8xp
; Mandelbrot per TI-84 Plus CE (CEdev / fasmg)
; Schermo 320x240 a 16 bpp (modalita' predefinita dell'OS), scrittura diretta in vRam.
;
; Aritmetica in virgola fissa con segno: 3 bit interi + 9 bit frazionari (1.0 = 512).
; I valori sono tenuti come interi a 24 bit con segno esteso.
; c_re : da -2.25 a +0.875 (passo 5/512, 320 colonne)
; c_im : da -1.17 a +1.17 (passo 5/512, 240 righe)
; Colore = iterazioni * 0x0841 (sfumatura di grigio); interno dell'insieme = nero.
include 'include/ez80.inc'
include 'include/ti84pceg.inc'
include 'include/tiformat.inc'
format ti executable 'MANDEL'
MAXITER := 30
call ti.ClrScrnFull
; LCD: buffer in vRam, 16 bpp (5:6:5)
ld hl, ti.vRam
ld (0E30010h), hl ; mpLcdUpbase
ld a, 02Dh
ld (0E30018h), a ; mpLcdCtrl
; --- TEST: riempie lo schermo di grigio-viola. Se NON lo vedi cambiare
; --- subito, le scritture in vRam non arrivano allo schermo. ---
ld hl, ti.vRam
ld de, ti.vRam+1
ld bc, 320*240*2-1
ld (hl), 0A5h
ldir
ld hl, ti.vRam
ld (pixptr), hl
ld hl, -600 ; cy iniziale (-1.17)
ld (cy), hl
row_loop:
ld hl, -1152 ; cx iniziale (-2.25)
ld (cx), hl
col_loop:
ld hl, 0
ld (zx), hl
ld (zy), hl
xor a, a
ld (iter), a
iter_loop:
ld hl, (zx)
ld de, (zx)
call fmul
ld (zx2), hl ; x^2
ld hl, (zy)
ld de, (zy)
call fmul
ld (zy2), hl ; y^2
ld de, (zx2)
add hl, de ; x^2 + y^2
ld de, 4*512
or a, a
sbc hl, de
jp nc, escaped ; >= 4.0 -> divergente
ld hl, (zx)
ld de, (zy)
call fmul ; x*y
add hl, hl ; 2xy
ld de, (cy)
add hl, de
ld (zy), hl ; y = 2xy + cy
ld hl, (zx2)
ld de, (zy2)
or a, a
sbc hl, de ; x^2 - y^2
ld de, (cx)
add hl, de
ld (zx), hl ; x = x^2 - y^2 + cx
ld a, (iter)
inc a
ld (iter), a
cp a, MAXITER
jp nz, iter_loop
ld hl, 0 ; non e' scappato: nero
jr put_pixel
escaped:
ld a, (iter)
ld hl, 0
ld l, a
ld h, 65
mlt hl ; n*65 = n + (n << 6)
ld de, 0
ld d, a
ld e, 8
mlt de ; n*8
ld d, e
ld e, 0 ; n << 11
add hl, de ; colore RGB565 = n*0x0841
put_pixel:
ex de, hl
ld hl, (pixptr)
ld (hl), e
inc hl
ld (hl), d
inc hl
ld (pixptr), hl
ld hl, (cx)
ld de, 5
add hl, de
ld (cx), hl
ld de, 448 ; -1152 + 320*5
or a, a
sbc hl, de
jp nz, col_loop
ld hl, (cy)
ld de, 5
add hl, de
ld (cy), hl
ld de, 600 ; -600 + 240*5
or a, a
sbc hl, de
jp nz, row_loop
wait_release: ; aspetta che tutti i tasti siano rilasciati
call ti.GetCSC
or a, a
jr nz, wait_release
wait_press: ; poi aspetta un nuovo tasto
call ti.GetCSC
or a, a
jr z, wait_press
call ti.ClrScrnFull
call ti.HomeUp
call ti.DrawStatusBar
ret
; ---------------------------------------------------------------
; HL = (HL * DE) >> 9 con segno, |HL|,|DE| < 4096
; Distrugge AF, BC, DE, HL, IX
; ---------------------------------------------------------------
fmul:
ld a, h
xor a, d ; bit 7 = segno del risultato
push af
bit 7, h
call nz, negHL
ex de, hl
bit 7, h
call nz, negHL
ex de, hl ; ora HL=H:L e DE=D:E sono positivi
ld ix, 0
ld bc, 0
ld b, l
ld c, e
mlt bc ; L*E
ld c, b
ld b, 0 ; (L*E) >> 8
add ix, bc
ld bc, 0
ld b, h
ld c, e
mlt bc ; H*E
add ix, bc
ld bc, 0
ld b, l
ld c, d
mlt bc ; L*D
add ix, bc
ld bc, 0
ld b, h
ld c, d
mlt bc ; H*D (< 256)
ld b, c
ld c, 0 ; (H*D) << 8
add ix, bc ; IX = prodotto >> 8
push ix
pop hl
srl h
rr l ; HL = prodotto >> 9
pop af
bit 7, a
call nz, negHL
ret
negHL: ; HL = -HL, DE preservato
push de
ex de, hl
or a, a
sbc hl, hl
sbc hl, de
pop de
ret
; ---------------------------------------------------------------
; Variabili (24 bit)
; ---------------------------------------------------------------
pixptr: dl 0
cx: dl 0
cy: dl 0
zx: dl 0
zy: dl 0
zx2: dl 0
zy2: dl 0
iter: db 0
https://www.ticalc.org/pub/84plusce/asm/
Se si crea una versione in TiBasic la velocita' di esecuzione crolla miseramente
Per caricare il softare da PC sull'emulatore si deve usare un editor compatibile come https://www.cemetech.net/sc/ esportare il file e inviarlo all'emulatore (il formato non e' un semplice ascii) salvando con nome tutto maiuscolo ed estensione 8xp
/////////////////////////////////////////////////////////////////////////////////////////
AxesOff
ClrDraw
24→N
1→S
For(R,0,82,S)
(82-R)*.0125→B
B²→D
For(C,0,264,S)
C*.0125-2.2→A
(A-.25)²+D→Q
If Q*(Q+A-.25)<.25D or (A+1)²+D<.0625
Then
N→K
Else
0→X
0→Y
0→K
While K<N and X²+Y²<4
X²-Y²+A→T
2XY+B→Y
T→X
K+1→K
End
End
If K>2
Then
20+(K>2)+(K>6)+(K>12)+(K>19)→E
If K=N
12→E
Pxl-On(R,C,E)
Pxl-On(164-R,C,E)
End
End
End
Repeat getKey
End
Nessun commento:
Posta un commento