Commodore Petscii reader on the Sinclair ZX Spectrum

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.

la “scusa” per completare lo ZX PETSCII VIEWER.

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

Stampa completa del charset C64 per ZX Spectrum con indicazioni ASCII

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.

Il charset “custom” per il visualizzatore PETSCII

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

2 Comments Add yours

  1. Stefano ha detto:

    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

    1. Carlo Santagostino ha detto:

      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!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.