Sei sulla pagina 1di 18

gldm Tutorial STM8-BASIC

STM8-BASIC
il più piccolo computer con interprete basic
Sommario
Introduzione .................................................................................................................................................. 2
Connessione al dispositivo ........................................................................................................................ 3
Cosa? ............................................................................................................................................................. 6
Una variante... ........................................................................................................................................... 6
Esempio: calcolo per cella sul bordo laterale ............................................................................................ 7
Esempio: calcolo per cella sul bordo inferiore .......................................................................................... 7
Esempio: calcolo per cella in un angolo .................................................................................................... 8
Come? ............................................................................................................................................................ 9
Allocare la nuova generazione ................................................................................................................ 10
Il programma ........................................................................................................................................... 11
Dalle idee al codice .................................................................................................................................. 12
Algoritmo ..................................................................................................................................................... 14
Stato della cellula corrente...................................................................................................................... 14
Somma delle cellule vive ......................................................................................................................... 15
Mettiamo insieme i pezzi ........................................................................................................................ 16
Appendici: bonus content ........................................................................................................................... 17
1. Codice sorgente ............................................................................................................................... 17
2. Oscillatore ........................................................................................................................................ 18
3. Doppio glider ................................................................................................................................... 18

1
gldm Tutorial STM8-BASIC

Introduzione
Poiché negli ultimi tempi ho sviluppato una certa saudade per la tecnologia dei primi anni '80 (in particolare
gli interpreti BASIC), ho recentemente acquistato una scheda STM8 BASIC.

Il costo è irrisorio, la spedizione è stata rapida, ed in breve mi sono trovato tra le mani questo
microcontrollore, di cui consiglio senza riserve l'acquisto.

Il dispositivo contiene un interprete BASIC ed offre all'utente:

• 256 bytes di RAM (volatile)


• 630 bytes di memoria non volatile per ospitare il programma BASIC.
• Inoltre sono disponibili per l'utente:
• 6 variabili a 16 bit con segno (dalla A alla F)
• 6 variabili a 16 bit senza segno (dalla G alla L)
• 10 variabili ad 8 bit senza segno (dalla N alla W)
• X e Z sono byte senza segno non volatili
• Z è una variabile a 16 bit senza segno, il cui valore è uguale a X*256+Y; ovviamente
è non volatile come X ed Y, essendo sostanzialmente un altro modo di indirizzare quei due
byte.

2
gldm Tutorial STM8-BASIC

Connessione al dispositivo
Naturalmente la prima cosa da fare è collegare un terminale seriale al dispositivo in modo da poter interagire
con l'interprete BASIC.
Per fare questo, occorre dotarsi di un convertitore USB/Seriale: io ho utilizzato una schedina del tipo FDTI (si
possono acquistare online a costi ragionevoli).

Qui occorre fare attenzione: la scheda SMT8 vuole i segnali seriali tra 0 e 3.3V, ma l'alimentazione Vcc a
5V.
Comprate un convertitore con il jumper che vi permetta di selezionare la tensione di uscita (3.3V - 5V)
e configuratela in modo che esca a 3.3V - altrimenti causerete danni alla scheda STM8.

Potete recuperare la tensione di alimentazione a 5V da uno dei piedini laterali, come nella figura seguente.

I cavi andranno collegati alla scheda secondo lo schema illustrato in calce.

3
gldm Tutorial STM8-BASIC

A questo punto la connessione seriale è a posto; collegate un cavo USB, aprite un emulatore di terminale ed
impostate i parametri, come da figura (io ho usato PuTTY).

4
gldm Tutorial STM8-BASIC

Se tutto è andato per il verso giusto, collegandovi alla scheda ed eseguendo il comando RST, dovreste
vedere una schermata simile a questa.

5
gldm Tutorial STM8-BASIC

Cosa?
Abbiamo il nostro computer, collegato tramite terminale seriale, pronto ad eseguire i nostri programmi
BASIC.
Bene, cosa vogliamo far eseguire al nostro interprete?
In onore di John Conway, scomparso ad aprile di questo sciagurato 2020, ritengo opportuno programmare
una variante della simulazione LIFE in BASIC.

Cosa dovremo fare, quindi? Elenchiamo i punti principali:


1. stabilire come memorizzare la griglia che rappresenta la generazione corrente
2. definire un algoritmo che conti le cellule vive intorno ad una generica cella della griglia
3. calcolare la generazione successiva e memorizzarla

Date le limitazioni dell'interprete (abbiamo a disposizione una manciata di variabili numeriche, 256 byte di
RAM e 630 byte per il programma) avremo una semplice griglia di 8x8 celle, ognuna delle quali potrà essere
"viva" o "morta".

Una variante...
La griglia può essere allocata in 8 byte di RAM. Ogni byte ospiterà una riga della griglia, dove il simbolo 1
rappresenterà una cellula "viva" e lo 0 una cellula "morta".

Nella figura vediamo un esempio dei casi che dovremo gestire: durante il calcolo della nuova generazione,
per stabilire il valore del bit con indice 3 del 3° byte, dovremo contare il numero di cellule "vive" presenti
intorno al nostro bit.
Segnatamente, dovremo contare gli "1" presenti :
• nel secondo byte (alle posizioni 2, 3 e 4)
• nel terzo byte (alle posizioni 2 e 4)
• nel quarto byte (alle posizioni 2, 3 e 4)
Per rendere più interessante la simulazione, introduciamo una variante: consideriamo la griglia finita ma non
limitata. Consideriamo cioè una griglia che si ripete infinitamente: sopra, sotto, a destra ed a sinistra.
Con questa variante, la somma delle cellule vicine deve essere opportunamente adeguata.

6
gldm Tutorial STM8-BASIC

Esempio: calcolo per cella sul bordo laterale


Vediamo il caso di una cella sul bordo destro della griglia.

Nella figura presentata, proviamo a fare il calcolo per il bit in posizione 0 del terzo byte. Dovremo
considerare, oltre alle posizioni 0 ed 1 del 2° e del 4° byte ed alla posizione 1 del 3°, anche le posizioni 7 del
1°, 2° e 3° byte.

Esempio: calcolo per cella sul bordo inferiore


In questo caso consideriamo una cella appartenente all'ottavo byte, alla posizione 2.

Naturalmente considereremo le posizioni 1,2 e 3 del 7° byte, le posizioni 1 e 3 dell'8° byte.


Poiché la griglia è illimitata verticalmente, dovremo considerare anche le celle appartenenti al 1° byte.

7
gldm Tutorial STM8-BASIC

Esempio: calcolo per cella in un angolo


Nel caso di una cella posizionata in un angolo, vediamo in figura la posizione 7 del primo byte.

Naturalmente la somma delle cellule "vive" conterà la posizione 6 del 1° byte e le posizioni 6 e 7 del 2° byte.
Per la non limitatezza della griglia, dovremo contare anche la posizione 0 del 1° e 2° byte.
Il calcolo deve poi tenere conto dei "vicini" che appartengono anche all'8° byte, alle posizioni 0, 6 e 7.

8
gldm Tutorial STM8-BASIC

Come?
Una prima soluzione per aggirare la limitatezza verticale della griglia è di utilizzare due byte, in testa ed in
coda alla griglia; nel byte in testa verrà replicato l'ottavo byte della griglia, nel byte in coda verrà replicato il
contenuto del 1° byte.

Usiamo gli indirizzi da $0201 a $0208 per la griglia della generazione corrente (nell'esempio in figura ho
inserito un glider).
Copiamo l'ottavo byte della griglia (all'indirizzo $0208) nel byte all'indirizzo $0200.
Copiamo anche il primo byte della griglia (all'indirizzo $0201) nel byte all'indirizzo $0209.

Questa è la mappa della RAM che ospita la generazione corrente della griglia, con il primo ed ultimo byte
replicati in testa ed in coda.

9
gldm Tutorial STM8-BASIC

Allocare la nuova generazione


abbiamo visto nel capitolo precedente la mappa di memoria in cui ospitare la generazione corrente delle
nostre cellule.

Per ospitare la generazione successiva, utilizziamo gli 8 bytes immediatamente successivi della memoria.

10
gldm Tutorial STM8-BASIC

Il programma
Vediamo quindi come passare dalla generazione corrente a quella futura:
dovremo fare una scansione di tutte le cellule della generazione corrente, per ogni cellula dovremo sapere
se è viva o morta, e dovremo contare il numero di cellule vive intorno (chiamiamo questa somma S).
Con queste due informazioni stabiliremo lo stato della cellula nella prossima generazione:
• cellula attualmente morta
• se S=3, nella prossima generazione la cellula sarà viva
• cellula attualmente viva:
• se S=3 oppure S=2, nella prossima generazione la cellula sarà viva
• in tutti gli altri casi, nella prossima generazione la cellula sarà morta.
Per implementare questo algoritmo dovremo effettuare una scansione dei byte della generazione corrente,
per ogni byte effettuare una scansione dei bit (ovvero delle cellule) - calcolare lo stato del bit per la prossima
generazione ed infine memorizzare lo stato della nuova generazione nell'area di memoria preposta.

La logica di massima del nostro programma BASIC sarà quindi:


➢ (1) eseguiamo un ciclo sui byte della generazione corrente (dall'indirizzo $0201 a $0208)
o per ognuno di questi byte eseguiamo un ciclo sui bit (da 0 a 7) - chiamiamo R il byte
corrente
▪ per ogni bit, calcoliamo la somma delle cellule vive intorno ad esso
▪ stabiliamo quindi se il corrispondente bit della prossima generazione sarà 1 o 0
(cellula viva o meno)
o al termine del ciclo sui bit avremo calcolato un intero byte della prossima generazione,
chiamiamo T questo byte
o salviamo il byte T in un indirizzo 9 locazioni più avanti rispetto al corrispondente byte R (es:
da $0203 a $0203+9 = $020C)
➢ al termine del ciclo sui byte, avremo le locazioni $020A-$0211 riempite con la nuova generazione
➢ (2) copiamo la nuova generazione dalle locazioni [$020A-$0211] alle locazioni [$0201-$0208]
➢ (3) copiamo il primo byte della nuova generazione da $020A a $0209
➢ (4) copiamo l'ultimo byte della nuova generazione da $0211 a $0200
➢ ricominciamo da capo.

Ho evidenziato in colore blu le operazioni eseguite per ogni byte della generazione corrente, ed in
colore rosso le operazioni eseguite per ogni bit del byte corrente.

Per ogni byte preso in esame (ricordo che per calcolare la somma delle cellule vive dovrò tenere conto
anche del byte precedente e del byte successivo) nella generazione corrente il programma calcolerà il
corrispondente byte della generazione futura e lo salverà nell'opportuno indirizzo (9 locazioni più "in basso"
nella mappa della memoria).

11
gldm Tutorial STM8-BASIC

Dalle idee al codice


Proviamo ora a strutturare un programma BASIC su questa logica; in questa prima stesura trascuriamo i
dettagli del calcolo della cellula per la nuova generazione (righe tra la 90 e la 140).

10 REM (1) CICLO SUI BYTE IN RAM


20 FOR A=$0201 TO A+7
30 REM INIZIALIZZO BYTE T DELLA PROSSIMA GENERAZIONE
40 T=0
50 REM CARICO IL BYTE R DELLA GENERAZIONE CORRENTE
60 R=PEEK A
70 REM CICLO SUI BIT DEL BYTE R
80 FOR N=0 TO 7
90 REM CALCOLO IL VALORE DELLA CELLA
100 REM CORRISPONDENTE AL BIT 2^N DEL BYTE T
...
140 REM FINE CALCOLO
150 NEXT N
160 REM C = INDIRIZZO IN CUI DEVO SCRIVERE
170 REM IL BYTE DELLA PROSSIMA GENERAZIONE
180 C=A+9
190 POKE C,T
200 NEXT A
210 REM (2) COPIO LA NUOVA GENERAZIONE CALCOLATA
220 REM DA $020A-$0211 A $0201-$0208
230 FOR B=$0201 TO B+7
240 P=PEEK B+9
250 POKE B,P
260 NEXT B
270 REM (3) COPIO IL BYTE IN $020A SU $0209
280 P=PEEK $020A
290 POKE $0209,P
300 REM (4) COPIO IL BYTE IN $0211 SU $0200
310 P=PEEK $0211
320 POKE $0200,P
330 SLEEP 1
340 GOTO 10

12
gldm Tutorial STM8-BASIC

Questa è la struttura generale del programma, naturalmente mancano ancora le parti per:

• stampare a video la generazione corrente


• calcolare il byte T della generazione futura, che si traduce praticamente in
o calcolare la somma delle cellule vive intorno al bit n-esimo del byte corrente

13
gldm Tutorial STM8-BASIC

Algoritmo
Iniziamo ora a pensare come calcolare le due informazioni che ci servono per calcolare se la cellula
sarà viva o morta nella prossima generazione:
1. stato della cellula nella generazione corrente
2. somma S delle cellule vive intorno ad essa

Stato della cellula corrente

Riprendendo la notazione introdotta nel capitolo precedente, supponiamo di avere il byte R che
ospita la riga di cellule.
Se stiamo considerando il bit con indice N, un'operazione di AND bit a bit tra il byte R e
2N restituirà due possibili valori:
➢ 0 (se il bit con indice N è 0 su R)
➢ 2N (se il bit con indice N è 1 su R)

Nell'esempio in figura N=3, calcoliamo 23 e facciamo l'operazione (R&8): in base al valore del bit
X, otterremo 8 oppure 0.
Se vogliamo un risultato che sia 1 per cellula viva e 0 per cellula morta, l'operazione completa sarà:

bitN = (R&2N)/2N

Questa informazione mi è utile anche al fine di stampare a video lo stato della cella, continuando
nel ciclo fino alla fine del byte, quando dovrò andare a capo prima di iniziare il byte successivo.

Nota implementativa: in BASIC, l'operazione di divisione può essere sostituita con un'operazione di
confronto: l'espressione (R&2N)=2N restituisce 1 se i due membri dell'uguaglianza sono uguali, 0
altrimenti.

14
gldm Tutorial STM8-BASIC

Somma delle cellule vive

Passiamo ora al calcolo delle cellule vive intorno al bit corrente.


Iniziamo con la premessa che ora dovremo gestire non il solo byte R ma anche il precedente ed il
successivo sulla griglia; compreso questo, il discorso non si discosta molto da quanto visto prima.
Dovremo considerare non solo il bit in posizione N, ma anche il precedente ed il successivo.

Usiamo le variabili di tipo byte offerte dal dispositivo per i nostri "moltiplicatori" e battezziamo:
O=2N+1 P=2N Q=2N-1

Dovremo però gestire due casi limite: quando N=0, Q dovrà essere 128 (perché la griglia è illimitata
lateralmente)

Nel caso opposto, quanto N=7, O dovrà essere 1.

La somma delle cellule vive intorno al bit corrente comprende i contributi dati dai 3 byte:
per V= byte superiore, avremo un contributo pari a:
(V&O)/O+(V&P)/P+(V&Q)/Q

per il byte R avremo un contributo:


(R&O)/O+(R&Q)/Q

infine per V= byte inferiore (nuovamente) un contributo:


(V&O)/O+(V&P)/P+(V&Q)/Q

La somma dei tre contributi sarà il risultato del calcolo voluto.

15
gldm Tutorial STM8-BASIC

Mettiamo insieme i pezzi

Con queste informazioni, vado a strutturare il programma BASIC come segue:

10 M020000000000082818000000 'inizializzazione griglia 8+8x8+8


20 CLR 'svuoto schermo
30 FOR A=$0200 TO A+7 'inizio ciclo sui bytes in memoria
40 P=0 'inizializzo moltiplicatore bit centrale
50 T=0 'inizializzo byte prossima generazione
60 FOR N=0 TO 7 'inizio ciclo sui bit (0->7)
70 GOSUB 1000 'subroutine di calcolo moltiplicatori
80 V=PEEK A 'carico il byte superiore dalla RAM
90 S=(V&O)/O+(V&P)/P+(V&Q)/Q 'contributo del byte superiore
100 V=PEEK A+1 'carico il byte centrale dalla RAM
110 R=V 'copio il byte centrale su R
120 S=S+(R&O)/O+(R&Q)/Q 'contributo del byte centrale
130 V=PEEK A+2 'carico il byte inferiore dalla RAM
140 S=S+(V&O)/O+(V&P)/P+(V&Q)/Q 'contributo del byte inferiore
150 U=(R&P)=P 'U=1 se attuale cella piena, 0 se vuota
160 PRINT U; 'stampo 1 o 0
170 T=T+P*(S=3) 'aggiungo al byte T l'informazione se nella
180 T=T+P*(S=2)*U 'prossima generazione il bit N sarà 1 o 0
190 NEXT N
200 PRINT "" 'vado a capo
210 C=A+10
220 ...
...
500 GOTO 20 'torno all'inizio
1000 O=128*(N=0) 'subroutine aggiornamento moltiplicatori
1010 O=O+P 'O = moltiplicatore bit a sx
1020 P=1<<N 'P = moltiplicatore bit centrale
1030 Q=(N=7) 'Q = moltiplicatore bit a dx
1040 Q=P*2+Q
1050 RETURN 'fine subroutine

Il programma richiede alcune osservazioni:


• Alla riga 10 c'è una istruzione, specifica del STM8 BASIC, che carica all'indirizzo
$0200 i valori esadecimali che seguono, raggruppati per byte (due cifre esadecimali
ogni byte). L'istruzione inizializza la matrice con un glider, come mostrato nel
capitolo “Come”.
• Alla riga 1020 c'è l'operatore "<<" che rappresenta lo shift a sinistra dei bit
dell'operando di sinistra, di tante posizioni quanto vale il secondo operando
• Ho ritenuto opportuno calcolare, per ogni N, i moltiplicatori O,P e Q una sola volta
ed utilizzarli per i tre byte. Il calcolo dei moltiplicatori viene fatto nella
subroutine evidenziata in giallo alla riga 1000.
• La stampa dello stato della cella corrente, poiché viene fatto da sinistra verso destra,
farà apparire sullo schermo una griglia "allo specchio", dove il bit meno significativo
viene stampato più a sinistra e quello più significativo a destra.
• alle righe 170 e 180 si trova una moltiplicazione in cui un operando è un'operazione
di confronto. Il significato di questa notazione è che se l'uguaglianza è verificata,
l'operando vale 1; se non è verificata, vale 0. In particolare la riga 180 significa: al
valore T viene sommato P se S è uguale a 2 e se U è uguale ad 1. Ricordiamo che U
è lo stato della cellula corrente (1=viva, 0=morta) - si veda la riga 150.
• Il programma non può essere inserito così sul dispositivo stm8: occorre eliminare
completamente i commenti e riassegnare i numeri di riga in modo da ridurre al
massimo i byte utilizzati.
16
gldm Tutorial STM8-BASIC

Appendici: bonus content


1. Codice sorgente
1 M020000000000082818000000
2 CLR
3 FOR A=$0200 TO A+7
4 P=0
5 T=0
6 FOR N=0 TO 7
7 GOSUB 90
8 V=PEEK A
9 S=(V&O)/O+(V&P)/P+(V&Q)/Q
10 V=PEEK A+1
11 R=V
12 S=S+(V&O)/O+(V&Q)/Q
13 V=PEEK A+2
14 S=S+(V&O)/O+(V&P)/P+(V&Q)/Q
15 U=(R&P)=P
16 PRINT U;
17 T=T+P*(S=3)
18 T=T+P*(S=2)*U
19 NEXT N
20 PRINT ""
21 C=A+10
22 POKE C,T
23 NEXT A
24 FOR B=$0201 TO B+7
25 P=PEEK B+9
26 POKE B,P
27 NEXT B
28 P=PEEK $020A
29 POKE $0209,P
30 P=PEEK $0211
31 POKE $0200,P
32 SLEEP 1
33 GOTO 2
90 O=128*(N=0)
91 O=O+P
92 P=1<<N
93 Q=(N=7)
94 Q=P*2+Q
95 RETURN

17
gldm Tutorial STM8-BASIC

2. Oscillatore

provate ad inizializzare la griglia con questa configurazione:


1 M0200000000007E0000000000

3. Doppio glider

provate ad inizializzare la griglia con questa configurazione:


1 M02000020A06000020A060020

18