vai direttamente a download
Era da tempo che progettavo un “simulatore di C64” per ZX Spectrum, l’idea strampalata girava nella mia testa da diversi anni ormai, ma quando qualche settimana fa il mio amico Francesco ha pubblicato il suo font “Sinclair” per C64 mi ha dato la spinta a perdere qualche ulteriore notte di sonno per finalizzare questo mio lavoro sospeso da anni.

Come prima cosa, usando il mitico ZX-Paintbrush ho adattato il fontset completo del C64 allo ZX Spectrum.

Il modo di gestire il set di caratteri è abbastanza diverso tra C64 e ZX Spectrum. Sul C64 i set di caratteri sono due di 128 caratteri alternati, uno con tutti i simboli PETSCII e i soli caratteri maiuscoli (default) e l’altro set con i caratteri alfabetici maiuscoli e minuscoli ed un set PETSCII ridotto, i due font-set sono alternativi e non possono essere usati contemporaneamente. Lo ZX Spectrum invece usa un solo set di 96 caratteri con maiuscole e minuscole alfabetiche e relega la possibilità dei caratteri grafici ad un set di 16 caratteri non modificabili (il set dei blocchi da 4×4 pixel) e “n” set di 21 caratteri ridefinibili mappati dalla A alla U chiamati UDG (User Defined Graphics). I set UDG sono utilizzabili selezionandoli con una POKE e una volta stampati non cambiano quindi si possono definire un numero a piacimento di caratteri a seconda della memoria disponibile, per realizzare il set completo di tutti i caratteri PETSCII + set maiuscole e minuscole ho usato 3 banchi di caratteri UDG oltre al set di 21 caratteri base.
Una volta terminata la conversione completa del charset, visto che “l’appetito vien mangiando” perchè fermarsi? Ho partorito quindi l’idea di realizzare un convertitore automatico delle PETSCII ART che vengono realizzate per C64. Per questo scopo ho appositamente realizzato un secondo set, ristretto, solo per i caratteri maiuscoli e set di caratteri grafici PETSCII completo ma che corrispondesse anche come ordinamento al charset originario del C64 in modo da facilitare la conversione dei codici ASCII dei caratteri.

C’era anche da risolvere il problema della conversione dei colori, il Commodore 64 ha 16 colori differenti mentre lo ZX Spectrum gestisce 8 colori con due livelli di luminosità (Bright 0 e 1) ma il nero non cambia tra i due livelli quindi il totale dei colori su ZX Spectrum è 15. Inoltre le due palette sono cromaticamente MOLTO diverse. Dopo svariati tentativi empirici sono giunto alla conclusione che questa mappatura è quella che da i migliori risultati:
-------------------------------------
COMMODORE 64 | ZX SPECTRUM
-------------------------------------
black 0 = 0 black
white 1 = 7+ bright white
red 2 = 2 red
cyan 3 = 5+ bright cyan
purple 4 = 3 magenta
green 5 = 4 green
blue 6 = 1 blue
yellow 7 = 6+ bright yellow
orange 8 = 2+ bright red
brown 9 = 6 yellow
pink 10 = 3+ bright magenta
dark grey 11 = 1 blue
grey 12 = 7 white
light green 13 = 4+ bright green
light blue 14 = 1+ bright blue
light grey 15 = 7 white
-------------------------------------
Nella sezione DOWNLOAD Potete scaricare il programma “ZX64 Simulator” contenente il set di caratteri PETSCII completo con corrispondenze dirette al set dello ZX Spectrum e quindi usabile normalmente in SINCLAIR BASIC.
Sempre in DOWNLOAD potete scaricare anche il PETSCII SLIDE SHOW che invece ha un charset ordinato con corrispondenza al set del C64 per permettere una conversione più semplice delle PETSCII ART, lo slide show in formato TAP eseguibile contiene già 10 PETSCII ART.
Per la conversione delle PETSCII ART in file binari ho usato il programma PETMATE. I file sono salvati in formato binario, la struttura è molto semplice, sono files di 2002 bytes: il primo byte definisce il colore del bordo, il secondo il colore di sfondo (paper), a seguire 1000 bytes per definire i 40×25 caratteri del disegno e altri 1000 bytes per i colori (attributi).

Il tutto è stato sviluppato con BORIEL BASIC, compilatore BASIC compatibile con il SINCLAIR BASIC ma che fornisce anche strutture proprie dei dialetti BASIC più moderni e permette anche di includere parti in assembler Z80 direttamente “inline”.
Ecco i listati completi, sono commentati quindi dovrebbe essere abbastanza facile capire i sorgenti.
' ----------------------------------------------------------------
' ZX64 SIMULATOR V.0.3 by Carlo Santagostino (c) 2019
' ----------------------------------------------------------------
DIM num AS UBYTE
DIM rig AS INTEGER
DIM tas AS STRING
' Set character set
POKE UINTEGER 23606, @typeface-256
' Initialize screen
100 INK 5: PAPER 1: BORDER 5: BRIGHT 0: FLASH 0: CLS
PRINT AT 1,4;"**** ZX 64 BASIC V2 ****"
PRINT AT 3,1;"48K RAM SYSTEM ALL BYTES FREE"
PRINT AT 5,0;"READY."
PRINT FLASH 1;AT 6,0;" "
' Wait until key is PRESSED
PAUSE 0
' Print all charset
200 CLS
PRINT INK 7;AT 1,9;"ZX64 SIMULATOR"
PRINT INK 7;AT 2,5;"by Carlo Santagostino"
PRINT INK 7;AT 3,11;"(c) 2019"
PRINT
PRINT INK 7;"CHR$ from 32 to 128 (ASCII):"
FOR a=32 TO 128
PRINT CHR$ a;
NEXT a
' Set UDG set #1
POKE UINTEGER 23675, @typeface+768
PRINT : PRINT
PRINT INK 7;"CHR$ from 144 to 164 (UDG SET1):";
FOR a=144 TO 164
PRINT CHR$ a;
NEXT a
' Set UDG set #2
POKE UINTEGER 23675, @typeface+1024
PRINT : PRINT
PRINT INK 7;"CHR$ from 144 to 164 (UDG SET2):";
FOR a=144 TO 164
PRINT CHR$ a;
NEXT a
' Set UDG set #3
POKE UINTEGER 23675, @typeface+1280
PRINT : PRINT
PRINT INK 7;"CHR$ from 144 to 164 (UDG SET3):";
FOR a=144 TO 164
PRINT CHR$ a;
NEXT a
PRINT : PRINT
PRINT FLASH 1;" "
' Wait until key is PRESSED
PAUSE 0
' The Labirinth
300 CLS
RANDOMIZE
rig = 0
DO WHILE rig < 768
num = RND * 2
IF num=0 THEN PRINT "\";
IF num=1 THEN PRINT "}";
rig = rig + 1
LOOP
' Wait until key is PRESSED
PAUSE 0
400 CLS
PRINT AT 1,1;"PRESS 1 TO RESTART"
PRINT AT 3,1;"PRESS 2 TO USE BASIC"
PRINT AT 5,0;FLASH 1;" "
' Wait until key is PRESSED
PAUSE 0
tas=INKEY$
IF tas="1" THEN GOTO 100
IF tas="2" THEN GOTO 500
GOTO 400
500
END
typeface:
asm
incbin "ZX64_PETSCII.chr"
end asm
'---------------------------------------------------------'
' ZX64 PETSCII VIEWER V.1.0 - CARLO SANTAGOSTINO (c) 2019 '
'---------------------------------------------------------'
' Define Functions
' convert colors code from C64 to ZXSpectrum
FUNCTION zxcol(x AS UBYTE) AS UBYTE
IF x = 0 THEN
x = 0
ELSE IF x = 1 THEN
x = 7
ELSE IF x = 2 THEN
x = 2
ELSE IF x = 3 THEN
x = 5
ELSE IF x = 4 THEN
x = 3
ELSE IF x = 5 THEN
x = 4
ELSE IF x = 6 THEN
x = 1
ELSE IF x = 7 THEN
x = 6
ELSE IF x = 8 THEN
x = 2
ELSE IF x = 9 THEN
x = 6
ELSE IF x = 10 THEN
x = 3
ELSE IF x = 11 THEN
x = 1
ELSE IF x = 12 THEN
x = 7
ELSE IF x = 13 THEN
x = 4
ELSE IF x = 14 THEN
x = 1
ELSE IF x = 15 THEN
x = 7
END IF
RETURN x
END FUNCTION
' return bright value for colors from C64 to ZXSpectrum
FUNCTION zxbri(x AS UBYTE) AS UBYTE
IF x = 0 THEN
x = 0
ELSE IF x = 1 THEN
x = 1
ELSE IF x = 2 THEN
x = 0
ELSE IF x = 3 THEN
x = 1
ELSE IF x = 4 THEN
x = 0
ELSE IF x = 5 THEN
x = 0
ELSE IF x = 6 THEN
x = 0
ELSE IF x = 7 THEN
x = 1
ELSE IF x = 8 THEN
x = 1
ELSE IF x = 9 THEN
x = 0
ELSE IF x = 10 THEN
x = 1
ELSE IF x = 11 THEN
x = 0
ELSE IF x = 12 THEN
x = 0
ELSE IF x = 13 THEN
x = 1
ELSE IF x = 14 THEN
x = 1
ELSE IF x = 15 THEN
x = 0
END IF
RETURN x
END FUNCTION
FUNCTION readcar() AS UBYTE
DIM x as UBYTE
DIM con AS UINTEGER
LET con=PEEK (UINTEGER, @counter)
x = PEEK (@petsciis+con)
LET con=con+1
POKE UINTEGER (@counter),con
RETURN x
END FUNCTION
' Change character set
POKE UINTEGER 23606, @typeface-256
' init variables
DIM brd, pap, car, inv, bri AS UBYTE
' Initialize screen
100 INK 5: PAPER 1: BORDER 5: BRIGHT 0: FLASH 0: CLS
PRINT AT 1,4;"**** ZX 64 BASIC V2 ****"
PRINT AT 3,1;"48K RAM SYSTEM ALL BYTES FREE"
PRINT AT 5,0;"READY."
PRINT FLASH 1;AT 6,0;" "
PAUSE 80
PRINT FLASH 0;AT 6,0;" "
'hint CHR$ 8 step back one character
RANDOMIZE
PRINT
LET scritta$="--------------------------------"+"ZX SPECTRUM PETSCII VIEWER V1.0 "+"--------------------------------"+" BY CARLO SANTAGOSTINO (C)2019 "+"--------------------------------"+" PRESS ANY KEY TO START!"
FOR x = 0 TO LEN scritta$
PRINT FLASH 0;scritta$(x);FLASH 1;" ";
PRINT CHR$ 8;
BEEP 0,0
PAUSE (RND*10)+1
NEXT x
PAUSE 0
POKE UINTEGER @counter,0
'slide show
FOR f=0 to 9
CLS
GO SUB PrintPetscii
PAUSE 0
NEXT f
GO TO 100
PrintPetscii:
BORDER 0 : PAPER 0 : INK 4
CLS
brd = readcar()
pap = readcar()
'read col
FOR b=0 TO 23
' skip left characters
FOR a=0 TO 3:car=readcar():NEXT a
'read line
FOR a=0 TO 31
car=readcar()
LET inv = 0
IF car >= 224 AND car < 256 THEN
car=car-64 : inv=1
ELSE IF car >= 192 AND car < 224 THEN
car=car-96 : inv=1
ELSE IF car >= 160 AND car < 192 THEN
car=car-128 : inv=1
ELSE IF car >= 128 AND car < 160 THEN
car=car-64 : inv=1
ELSE IF car >= 96 AND car < 128 THEN
car=car+64
ELSE IF car >= 64 AND car < 96 THEN
car=car+32
ELSE IF car >= 0 AND car < 32 THEN
car=car+64
END IF
IF car >= 181 AND car < 192 THEN
POKE UINTEGER 23675, @typeface+1024
PRINT INVERSE inv;CHR$((car-181)+144);
ELSE IF car >=160 AND car < 181 THEN
POKE UINTEGER 23675, @typeface+768
PRINT INVERSE inv;CHR$((car-160)+144);
ELSE IF car >= 32 AND car < 160 THEN
PRINT INVERSE inv;CHR$(car);
END IF
NEXT a
' skip right characters
FOR a=0 TO 3:car=readcar():NEXT a
NEXT b
' skip 1 line
FOR a=0 to 39:car=readcar():NEXT a
' set border color
BORDER zxcol(brd)
' set ink colors
FOR b=0 TO 23
FOR a=0 TO 3:car=readcar(): NEXT a
FOR a=0 TO 31
car=readcar()
PRINT OVER 1;PAPER zxcol(pap);BRIGHT zxbri(car);INK zxcol(car);" ";
NEXT a
FOR a=0 TO 3:car=readcar(): NEXT a
NEXT b
' skip 1 line
FOR a=0 to 39:car=readcar():NEXT a
RETURN
typeface:
asm
incbin "PETSCII_VIEW.chr"
end asm
counter:
petsciis:
asm
incbin "collection1.petscii"
incbin "collection2.petscii"
end asm
Download:
Credits delle PETSCII ART incluse nell’archivio:
“Whom Are You Going to Call?” by Marq (2017)
https://csdb.dk/release/?id=160597
“Breakfast of Champions” by iLKke (2016)
https://csdb.dk/release/?id=151613
“Ernie” by redcrab (2018)
https://csdb.dk/release/?id=170942
“SixShots” by Electric (2016)
https://csdb.dk/release/?id=145059
“Datagubbe” by redcrab (2018)
https://csdb.dk/release/?id=165924
“It Ain’t Pretty!” by redcrab (2017)
https://csdb.dk/release/?id=157024
“Petscii Tracing” by Dr. TerrorZ (2017)
https://csdb.dk/release/?id=157375
“Coltrane” by Electric (2015)
https://csdb.dk/release/?id=142293
“Electric Circus” by Dr. TerrorZ (2017)
https://csdb.dk/release/?id=159741
“Rabbit on Acid Trip” by Manu (2013)
https://csdb.dk/release/?id=123163
non ricordo chi (mi pare qualche componente Ramsoft) che a suo tempo riuscì a creare una routine per leggere i nastri del c64 almeno… inteso come scambio dati il che, non dovrebbe neppure essere tanto difficile. Vorrei poi ricordare a tutti che è disponibile anche sul sito WolrdOfSpectrum l’emulatore Vic20 che emula sia i font che tutta la parte grafica e di programmi sia basic che linguaggio macchina. Quindi il tuo lavoro è stato in parte già fatto in precedenza tenendo pero’ conto che il vic20 aveva solo i caratteri maiuscoli se non ricordo male
Vero, l’ho scoperto solo dopo, sarebbe bello riuscire ad integrare almeno la routine per lettura dei nastri in formato c64… ma quella purtroppo non sono riuscito (ancora) a trovarla. Comunque ci sto ancora lavorando, presto pubblicherò delle interessanti novità! Stay tuned!