In questo articolo viene riportato come implementare il classico helloWorld su macchina Sinclair ZX81, utilizzando il linguaggio assembler.
Normalmente, gli sviluppatori di software per cosidette macchine retrò, implementano il software su normali PC o Workstation moderne equipaggiati di relativi sistemi operativi altrettanto moderno. Una volta che il software è terminato, può essere trasferito sulla macchina target ed eseguito.
E’ necessario quindi installare sulla propria macchina di sviluppo : un Assembler che generi linguaggio macchina per l’architettura target, di un emulatore e di un editor di testo per poter editare il codice. Tutti i sistemi operativo maggiormente utilizzati dispongono di un’ampia scelta di software per poter assemblare il proprio ambiente di sviluppo. Di seguito alcuni di questi :
| Sistema Operativo | Nome Software | Tipologia | Ultima Versione | Licenza | Annotazione | |
|---|---|---|---|---|---|---|
| 1 | DOS/Windows | TASM | Assembler | 3.2 | Valutazione 30 giorni | Utilizzato dai nerd storici. Probabilmente è stato il primo cross-assembler liberamente utilizzabile per DOS/Windows. |
| 2 | DOS/Windows | eightyone | Emulatore | 1.0a | Software Libero (GNU GPL) | Probabilmente il piu’ utilizzato. |
Installazione di TASM Cross Assembler
In stile nerd (old-school) l’installazione di TASM (da *non* confondere con il Borland Turbo Assembler) si concretizza semplicemente nell’unzippare il file compresso.
jack0e@harlock MINGW64 ~/Desktop/hack
$ mkdir zx81Dev
$ mkdir zx81Dev/tasm
$ cp /tmp/tasm32.zip zx81Dev/tasm
$ cd zx81Dev/tasm
$ unzip tasm32.zip
Archive: tasm32.zip
inflating: 8051.H
inflating: COPYRIGH.TXT
inflating: MOTO.H
inflating: ORDERFRM.HTM
inflating: ORDERFRM.TXT
inflating: README.1ST
inflating: README.TXT
inflating: RELNOTES.TXT
inflating: TASM.EXE
inflating: TASM05.TAB
inflating: TASM3210.TAB
inflating: TASM3225.TAB
inflating: TASM48.TAB
inflating: TASM51.TAB
inflating: TASM65.TAB
inflating: TASM68.TAB
inflating: TASM70.TAB
inflating: TASM80.TAB
inflating: TASM85.TAB
inflating: TASM96.TAB
inflating: TASMMAN.HTM
inflating: TASMTABS.HTM
inflating: TEST05.ASM
inflating: TEST3210.ASM
inflating: TEST3225.ASM
inflating: TEST48.ASM
inflating: TEST51.ASM
inflating: TEST65.ASM
inflating: TEST68.ASM
inflating: TEST70.ASM
inflating: TEST85.ASM
inflating: TEST96.ASM
inflating: TESTTABS.BAT
inflating: TESTZ80.ASM
Come riportato nella tabellina riepilogativa, il TASM CROSS Assembler non è un software libero, ma un trial che può essere utilizzato per soli 30 giorni, dopodichè la licenza (leggi README) ne vieterebbe il suo utilizzo anche continua regolarmente a funzionare. Per usufruire del diritto all’uso è necessario acquistare una licenza tramite preventiva registrazione (compilazione del modulo ORDERFRM.txt) per un costo di 40 Euro. Con l’acquisto della licenza d’uso verrà fornita il sorgente C di TASM Cross Assembler, il manuale d’uso ed un riferimento telefonico per il supporto, oltre a riceverne l’ultima versione.
TASM Cross Assembler, lo dico per completezza, supporta anche altri processori target, oltre allo Zilog Z80, di seguito una lista completa :
| CPU | File con tabelle delle istruzioni | Descrizione | |
|---|---|---|---|
| 1 | Zilog Z80 | TASM80.TAB | Processore della ZILOG a 8 bit (e relativi Cloni, essendo coperto da una licenza d’uso che ne permetteva ed invogliava la replicabilità). E’ il cuore di molti computer 8 bit sin dalla fine degli anni 70 dello scorso secolo. |
| 2 | 8048 | TASM48.TAB | Microcontrollore di Intel delle serie MCS-48, prodotti a partire dall’anno 1976, prima dei microprocessori (CPU) a 8 bit. Appartengono a tale famiglia : 8048, 8035, 8748 Inizialmente tali microcontrollori utilizzavano tecnologia NMOS, e solo dopo il 1980 rimpiazzata da CMOS. Montavano ROM intern o esterna di pochi byte su cui risiedeva il software. Per il basso costo non scomparvero nemmeno dopo l’avvento delle CPU ad 8 bit, ma continuarono ad avere un loro mercato, ad esempio all’interno di elettrodomestici, tastiere di computer e terminali per la comunicazione seriale. Gli MCS-48 furono soppiantati da MCS-51. |
| 3 | 8051 | TASM51.TAB | Microcontrollore della famiglia MCS-51. Inizialmente utilizzatavo tecnologia NMOS, subito dopo rimpiazzata da CMOS (80C51). La famiglia Intel MCS-51 prodotta a partire dal 1980 migliora gli MCS-48, rendendo utilizzabili tali microcontrollori anche in elettrodomestici e macchine molto piu’ complesse. L’8051 implementa un set di istruzioni molto piu’ amplio del precedente e la possibilità di leggere e scrivere su memorie RAM, su un bus a 8 bit. L’architetto del 8051 è John H. Wharton |
| 4 | 6502 | TASM65.TAB | Il MOS Technology 6502 è un microprocessore a 8 bit prodotto con tecnologia NMOS, al momento conosciuta a partire dal mese di settembre del 1975 da un piccolo gruppo di persone guidate da Chuck Peddle che aveva lavorato già a Motorola sul 6800. Il 6502 semplifica, il risultato fu che era piu veloce e sei volte piu’ economico dei concorrenti (Motorola 6800, Intel 8080). Assieme allo Zilog Z80 diede vita alla rivoluzione degli Home Computer ad 8 bit. Molti console di videogiochi dagli anni 70 fino al 1990 montavano una CPU 6502, ad esempio Atari 2600, Atari a 8 bit e Lynx, Commodore 64, Apple, BBC Micro, Nintendo Entertainment System ed altri. |
| 5 | 8085 | TASM85.TAB | L’Intel 8085 è uscito nel marzo del 1976, ed è compativole a libello di binari con Intel 8080. A differenza di questo richiede una sola alimentazione di +5V rendendolo piu’ facilmente integrabilenelle circuiterie dell’epoca, rispetto alle 2 alimentazioni 5V/12V del predecessore. Come microprocessore l’Intel 8085 fu superato dallo Zilog Z80, nonostante questo continuò ad essere prodotto e venne utilizzato come microcontrollore ad esempio nei terminali. |
| 6 | 6805 | TASM05.TAB | Il Motorola 6805 venne prodotto nel 1975 ed è una delle variante del 6800 il cui progetto inizia nel 1971, molti di questa famiglia di microprocessori fu clonata da Hitachi. Anch’esso utilizzato come microcontrollore, in alcune varianti riportanto RAM/ROM internamente. Anche per i Motorola 68xx non ci margine in ambito prettamente informatico, negli home computer dell’epoca a 8 bit. |
| 7 | TMS32010 | TASM3210.TAB | Il Texas Instruments TMS32010 è un microprocessore prodotto nel 1983. E’ una variante del TMS320, il primo della famiglia a poter utilizzare una RAM esterna, ed indirizzava a 16bit. Puoò essere programmato in C/C++ ed in linguaggio Assembler. |
| 8 | TMS32025 | TASM3225.TAB | Il Texas Instruments TMS32025 è un evoluzione del TMS32010. |
| 9 | 6800/6801 | TASM68.TAB | Il Motorola 6800/1 sono le prime versioni di un progetto che inizia nel 1971. Usato come microcontrollore, molto costoso complesso. |
| 10 | TMS7000 | TASM7000.TAB | Il Texas Instruments TMS7000 è un’evoluzione del TAMS prodotto nel 2020. |
| 11 | 8096 | TASM8096.TAB | l’Intel 8096 appartiene alla famiglia MCS-96, microcontrollori a 12MHz e 16bit |
L’autore di TASM Cross Assembler è Thomas N. Anderson.
Nonostante io sia piu’ orientato ad utilizzare e ad invogliare l’uso di Software Livero (ossia coperto da licenze quali GNU GPLv3 o BSD e simili), invoglio a cui fosse interessato a questo software di acquistarne una licenza, per ripagare Thomas del lavoro fatto, riceverete i dono il codice sorgente se vorrete studiarlo. Resta il fatto che esistono altri Assembler con la licenza che piu’ vi aggrada.
Installazione di EightOne (emulatore ZX81)
Il secondo software necessario per avere un ambiente di sviluppo e run-time completo per il nostro ZX81, è l’emulatore, ossia quel software che ci permetterà di emulare a run-time al 100% la macchina target. Ho deciso di utilizzare EightOne, su suggerimento di Paul Farrow, persona che stimo molto, per il grosso lavoro fatto per questa macchina, sia dal punto di vista software che hardware.
Per installare l’emulatore eightyone (81) sarà necessario semplicemente unzipparlo
jack0e@harlock MINGW64 ~/Desktop/hack
$ mkdir zx81Dev
$ mkdir zx81Dev/eightyone
$ cp /tmp/eightyone.1.0a.zip zx81Dev/eightyone
$ cd zx81Dev/eightone
$ unzip eightone.1.0a.zip
[_CUT_]
// La struttura di EaightyOne sul filesystem
jack0e@harlock MINGW64 $ ls -ltr
-rw-r--r-- 1 37502307 1049089 14938 Feb 7 2000 gpl.txt
-rw-r--r-- 1 37502307 1049089 49206 May 22 2008 zx81.cset.bmp
drwxr-xr-x 1 37502307 1049089 0 May 27 2008 nvram/
drwxr-xr-x 1 37502307 1049089 0 May 27 2008 Dock/
drwxr-xr-x 1 37502307 1049089 0 May 27 2008 Disks/
drwxr-xr-x 1 37502307 1049089 0 May 27 2008 Tapes/
-rw-r--r-- 1 37502307 1049089 23729 May 28 2008 Changes.txt
drwxr-xr-x 1 37502307 1049089 0 May 28 2008 ROM/
-rwxr-xr-x 1 37502307 1049089 4606464 Dec 26 2008 EightyOne.exe*
// DUMP della ROM del Sinclair ZX81 (ROM/zx81.rom)
jack0e@harlock MINGW64 $ ls -ltr ROM/zx*
-rw-r--r-- 1 37502307 1049089 8192 Jan 1 1981 ROM/zx81.rom
-rw-r--r-- 1 37502307 1049089 32768 Mar 18 1998 ROM/zx97.rom
-rw-r--r-- 1 37502307 1049089 4096 Sep 17 2003 ROM/zx80.rom
-rw-r--r-- 1 37502307 1049089 16384 May 28 2006 ROM/zxcflba.rom
-rw-r--r-- 1 37502307 1049089 16384 Oct 30 2006 ROM/zx8blbs.rom
-rw-r--r-- 1 37502307 1049089 16384 Oct 30 2006 ROM/zxidelbs.rom
-rw-r--r-- 1 37502307 1049089 10616 May 22 2008 ROM/zx81.rom.sym
-rw-r--r-- 1 37502307 1049089 5654 May 28 2008 ROM/zx80.rom.sym
Primo Esempio : HelloClive.asm ed editor
Di seguito il listato di un primo esempio in assembler che ho creato nella directory zx81Dev/tasm/. Il programma si limita a visualizzare la scritta “hello Clive!”. E’ possibile utilizzarre un qualsiasi editor di testo, nel mio caso ho utilizzato il “vi”.
Appare un pò lunghetto perchè ho preferito commentarlo molto, essendo anche per me ad uso didattico. E’ consuetudine per gli sviluppatori assembler che sviluppano per Sinclair ZX81 utilizzare degli header standard, questo gli agevola la vita. Gli header normalmente utilizzati sono: zx81defs.asm, zx81roms.asm, charcodes.asm, zx81sys.asm, line1.asm, vars.asm, line2.asm, screen.asm ed endbasic.asm. Ne parlerò successivamente di questi header successivamente, ed in dettaglio. Nel codice di helloClive.asm ho preferito commentarli ed estrapolare da essi esclusivamente ciò che era necessario, mantenendo tutto il codice in un unico file, per una questione di leggibilità.
$ cat helloClive.asm
;/*
;.--------------------------------------------------------------------------.
;| |
;| |
;| PROGRAM : HelloClive |
;| |
;| AUTHOR : jack0e |
;| |
;| REMARK ; My first software for Sinclair ZX81 |
;| Written in Assembly Language |
;| |
;| DATE : 09/03/2026 |
;| |
;| COMPILE : tasm -80 -b -s helloClive.asm helloClive.p |
;| |
;| |
;'--------------------------------------------------------------------------'
; ============================================================
; name : zx81defs.asm
; remark : defines to make us feel more at home
; ------------------------------------------------------------
; #include "zx81defs.asm"
; ============================================================
; ============================================================
; name : zx81rom.asm
; remark : EQUs for ZX81 ROM routines
; ------------------------------------------------------------
; #include "zx81rom.asm"
; ============================================================
; ============================================================
; name : charcodes.asm
; remarks : ZX81 Character code / How to survive whith ASCII
; ------------------------------------------------------------
;
; Sinclair Code.
;
; Char Code | Char Code | Char Code | Char Code |
; ----- ----- | ----- ----- | ----- ----- | ----- ----- |
; blank $00 | 0 $1C | A $26 | CR $76 |
; " $0B | 1 $1D | B $27 | NULL $FF |
; funt $0C | 2 $1E | C $28 |
; $ $0D | 3 $1F | D $29 |
; : $0E | 4 $20 | E $2A |
; ? $0F | 5 $21 | F $2B |
; ( $10 | 6 $22 | G $2C |
; ) $11 | 7 $23 | H $2D |
; > $12 | 8 $24 | I $2E |
; < $13 | 9 $25 | J $2F |
; = $14 | | K $30 |
; + $15 | L $31 |
; - $16 | M $32 |
; * $17 | N $33 |
; / $18 | O $34 |
; ; $19 | P $35 |
; , $1A | Q $36 |
; . $1B | R $37 |
; | S $38
; | T $39
; | U $3A
; | V $3B
; | W $3C
; | X $3D
; | Y $3E
; | Z $3F
;
; ------------------------------------------------------------
; #include "charcodes.asm"
; ============================================================
; =============================================================
; Name ; zx81sys.asm
; Remark : Definition System variables
; -------------------------------------------------------------
; #include "zx81sys.asm"
; =============================================================
.ORG 16393 ; Origin of a ZX81 file is always 16393
; /*
; .-----------------------------------------------------------.
; | SYSTEM VARIABLE of the Sinclair ZX81 |
; | memory byte from 16384 to 16508 |
; '-----------------------------------------------------------' */
;ERROR_NR
;FLAGS
;ERR_SP
;RAMTOP
;MODE
;PPC
VERSN: .BYTE 0
E_PPC: .WORD 2
D_FILE: .WORD Display
DF_CC: .WORD Display+1 ; First character of display
VARS: .WORD Variables
DEST: .WORD 0
E_LINE: .WORD BasicEnd
CH_ADD: .WORD BasicEnd+4 ; Simulate SAVE "X"
X_PTR: .WORD 0
STKBOT: .WORD BasicEnd+5
STKEND: .WORD BasicEnd+5 ; Empty stack
BREG: .BYTE 0
MEM: .WORD MEMBOT
UNUSED1: .BYTE 0
DF_SZ: .BYTE 2
S_TOP: .WORD $0002 ; Top program line number
LAST_K: .WORD $fdbf
DEBOUN: .BYTE 15
MARGIN: .BYTE 55
NXTLIN: .WORD Line2 ; Next line address
OLDPPC: .WORD 0
FLAGX: .BYTE 0
STRLEN: .WORD 0
T_ADDR: .WORD $0c8d
SEED: .WORD 0
FRAMES: .WORD $f5a3
COORDS: .WORD 0
PR_CC: .BYTE $bc
S_POSN: .WORD $1821
CDFLAG: .BYTE $40
PRBUFF: .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,$76 ; 32 Spaces + Newline
MEMBOT: .BYTE 0,0,0,0,0,0,0,0,0,0,$84,$20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 30 zeros
UNUNSED2: .WORD 0
;.===========================================================.
;| MAIN Function |
;'==========================================================='
;main()
;{
; =============================================
; name : line1.asm
; remark : Standard REM statement will
; contain our 'hex' code.
; line1 | This is the REM statement.
; example statement :
; 00 00 39 00 EA
; XX
; X===X ^
; X===X ^ '---- REM
; ^ '--------- Lenght Code
; '--------------- 00 00
;
; ---------------------------------------------
; #include "line1.asm
; =============================================
Line1: .BYTE $00,$00 ; Line 1
.WORD Line1End-Line1Text ; Line 1 length
Line1Text: .BYTE $ea ; REM
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; The UserCode starts here and gets added to the end of the REM
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ld bc,1
ld de,helloClive ; load helloString to DE register
call printf ; print helloString
ld bc,64 ;
ld de,author ; load autorString to DE register
call printf ; print authorString
; /*
; .-----------------.
; | Return to BASIC |
; '-----------------' */
ret
;}
;.===========================================================.
;| The my function |
;'==========================================================='
;/*
;.-----------------------------------------------------------.
;| name : printf ;) |
;| remark : display a string. Write directly to the screen. |
;| input ; register bc : |
;| register de : string |
;'-----------------------------------------------------------' */
printf
; /*
; .------------------------------.
; | write directly to the screen |
; '------------------------------' */
ld hl,(D_FILE)
add hl,bc
printfLoop
ld a,(de) ; Load in Accumulator (A) the address of string
cp $ff ; Compare character for verify the endString ($ff=\0|null)
jp z,printfEnd ; If the character is null, goto end function
ld (hl),a ; If the character is *not* null load accumulator (A) to hl (hight/low) register -- string pointer
inc hl ; inc hl (so display memory pointer)
inc de ; inc de (so string pointer)
jr printfLoop ; repeat while
printfEnd
ret
; ================================================================
; name : vars.asm
; remark : my variable
; ----------------------------------------------------------------
; #include "vars.asm"
; ================================================================
; H E L L O _ C L I V E \0
helloClive .BYTE $2D,$2A,$31,$31,$34,$00,$28,$31,$2E,$3B,$2A,$FF
; \CR J A C K 0 E \0
author .BYTE $76,$2F,$26,$28,$30,$1C,$2A,$FF
; ============================================================
; code ends
; ============================================================
; name : line2.asm
; remark : end the REM line and put in the RAND USR line
; to call our 'hex code'
; ------------------------------------------------------------
; #include "line2.asm"
; ------------------------------------------------------------
; /*
; .---------------------------------------.
; | This is the end of line 1 - the REM |
; '---------------------------------------' */
.BYTE $76 ; Newline
; /*
; .---------------------------------------.
; | Followed by the the RAND USR line. |
; '---------------------------------------' */
Line1End
Line2 .BYTE $00,$0a
.WORD Line2End-Line2Text
Line2Text .BYTE $F9,$D4 ; RAND USR
.BYTE $1D,$22,$21,$1D,$20 ; 16514
.BYTE $7E ; Number
.BYTE $8F,$01,$04,$00,$00 ; Numeric encoding
.BYTE $76 ; Newline
Line2End
; ============================================================
; ZX81 Screen Definition
; ============================================================
; name : screen.asm
; remark : Display file definition (24x32+CR) - lowres
; ------------------------------------------------------------
; #include "screen.asm"
; ------------------------------------------------------------
Display .BYTE $76
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 0
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 1
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 2
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 3
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 4
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 5
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 6
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 7
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 8
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 9
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 10
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 11
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 12
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 13
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 14
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 15
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 16
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 17
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 18
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 19
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 20
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 21
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 22
.BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$76 ; Line 23
; ============================================================
; ZX81 Screen Definition
; ============================================================
; name : endbasic.asm
; remark : Close out the basic program structure
; BASIC Variable Area
; ------------------------------------------------------------
; #include "endbasic.asm"
; ------------------------------------------------------------
Variables:
VariablesEnd: .BYTE $80
BasicEnd:
#END
Compilazione del codice.
Per la compilazione del codice ho usato i seguente script :
$ cat helloClive.sh
#!/bin/bash
./tasm -80 -b -s helloClive.asm helloClive.p
a cui bisogna dar i permessi di esecuzione, dopodichè eseguirlo :
$ ./helloClive.sh
TASM Z80 Assembler. Version 3.2 September, 2001.
Copyright (C) 2001 Squak Valley Software
tasm: pass 1 complete.
tasm: pass 2 complete.
tasm: Number of errors = 0
Se la compilazione termina correttamente, nel mio caso si, viene creato l’eseguibile, ma vediamo nel dettaglio i 3 file generati dal TASM Cross Assembler (.sym, .p, .lst) nella fase di compilazione,
$ ls -ltr helloClive.*
-rwxr-xr-x 1 37502307 1049089 58 Mar 8 20:19 helloClive.sh*
-rw-r--r-- 1 37502307 1049089 11660 Mar 8 20:19 helloClive.asm
-rw-r--r-- 1 37502307 1049089 2784 Mar 9 00:11 helloClive.sym
-rw-r--r-- 1 37502307 1049089 972 Mar 9 00:11 helloClive.p
-rw-r--r-- 1 37502307 1049089 23477 Mar 9 00:11 helloClive.lst
Il file helloClive.P è l’eseguibile per ZX81, che andremo successivamente ad eseguire nell’emulatore.
Esecuzione di helloClive con EightyOne (hardware virtuale)
Per eseguire helloClive.p su macchina virtuale, è estremamente semplice :
Va avviato l’emulatore, tramite l’esecuzione di EightyOne.exe

Tramite la funzione File > OpenTape selezionato il file da eseguire (helloClive.p)

Ottenere in output, il nostro helloWord!

Verificato che tutto funzioni come previsto, possiamo eseguire il nostro codice su hardware reale.
Esecuzione di helloClive su ZX81 (hardware reale)
Il file helloClive.p è un formato audio, lo stesso utilizzato per i nastri magnetici utilizzati negli anni 80, prima dell’avvento delle unità di memorizzazione di massa diffuso dopo la metà degli anni 80 con i primi home computer a 16bit. Non avendoci un registratore a nastri su cui riversare l’eseguibile (helloClive.p), ho deciso di utilizzare un software che legge tali file e genera un output sonoro come farebbe un normale registratore di nastri musicali. Quindi per prima cosa ho trasferito il file helloClive.p sul mio cellullare Android. Nel mio caso il trasferimento l’ho eseguito tramite posta elettronica, ma sarebbe stato possibile farlo anche tramite bluetooth o altro metodo.
Ho installato sullo smartphone un lettore di file .P, ad esempio PlayZX, che trovate sullo store ufficiale di Android. L’omino che saluta, che vedete come icona di PlayZX è lui, il caro zio Clive.

Nella sezione local è possibile selezionare il nostro file helloClive.P e suonarlo tramite il tringolo, che simboleggia il PLAY. Se lo fate sentirete il sonoro del nostro helloWorld, che vi farà riassaporare l’informatica casalinga negli anni 80.

Ora, non ci resta che posizionare sul banco da lavoro lo ZX81, e collegare a computer spento l’uscita cuffie del cellulare all’ingresso audio dello ZX81 (denominato qui sempre come EAR), tramite un cavo mono. Nel mio caso il cavo era mono ad etrambi i capi, quindi anche sull’uscita del player (smartphone o chromebook) nativamente stereo.
Dopo dopo aver fatto collegato tutto, ho alimentato il Sinclair ZX81, ed inserito il comando :
LOAD ""
A quel punto ho dato il PLAY. In quel preciso momento lo ZX81 ho smesso di inviare il segnale al monitor. Dopo un 20 secondi, a fine riproduzione audio, lo ZX81 eseguito il codice ricevuto, visualizzando nella TV/Monitor il messaggio di helloWorld.

Premendo INVIO (NewLine) + qualcosa altro, che non ho ben capito, forse BREAK o LIST, mi ha presentato il pseudo listato BASIC che esegue al termine il mio codice macchina, tramite l’esecuzione della riga :
10 RAND USR 16514

La riga 0, invece, non è facilmente interpretabile. Di sicuro è generata (nel sorgente assembler) dai blocchi LINE1 e LINE2, che avvolgono il mio BODY in cui è contenuto il codice applicativo. Rappresentano la modalità fornita dagli ingegneri Sinclair per eseguire con codice assembler da SO/Basic.
Un altro aspetto da approndire è il seguente : nella versione attuale di helloClive, non faccio uso di Routine di SO (Contenute nella ROM), ma ad esempio per scrivere il messaggio a video, vado direttamente a puntare alla memoria video, e non invocando la PRINT o la PRINT-AT del Sinclair Basic. Questo slega un pò il proprio codice dal tipo di macchina, ma nello stesso tempo rende piu’ laborioso lo sviluppo. Se rendessi parametrizzabile la posizione dell’aria video, potrei far girare probabilmente helloClive su qualsiasi macchina con CPU Z80, ad esempio su Acorn-1, ZX Spectrum o macchine giapponesi MSX. Chissà!
C’è molto ancora da approfondire ! …ed è tutto molto divertente 😉
Seguiranno aggiornamenti.