Convertire un piccolo programma che occupi meno di 8kb in una rom, che sia una
cartuccia o una rom del basic, non e' troppo difficile, una volta studiato
un po' il disassemblato della rom a partire dalla routine di reset a $FCE2.
Tutto sta nel trasferire il programma che abbiamo "Infilato" nella ROM,
programma che normalmente sarebbe caricabile e lanciabile con un RUN, dalla ROM
alla memoria normale a $0801.
Da una richiesta avvenuta di recente, ma che avevo affrontato gia' tempo fa,
provo a spiegare come trasformare il programma CynthCart in una ROM.
Iniziamo disassemblando il programma in questione:
Filename: cynthcart.prg
Loading address: $0801
0801 0B 08 anc #$08 ; mettere qua l'header per le cart
0803 0A ASL ;
0804 00 BRK ;
0805 9E 32 30 shx $3032,Y;
0808 36 31 ROL $31,X;
080A 00 BRK ; qua mettere una jmp
080B 00 BRK ; ad una routine di init necessaria in tutte le cart
080C 00 BRK ; che metteremo in fondo al file
080D A2 18 LDX #$18 ; la routine di trasferimento ci torna utile:
080F A9 32 LDA #$32 : patch: #$31
0811 85 22 STA $22
0813 A9 08 LDA #$08 ; patch: #$80, cosi' copia da $8031
0815 85 23 STA $23 ; trasferisce da $0832 ...
0817 A9 00 LDA #$00
0819 85 24 STA $24
081B A9 30 LDA #$30
081D 85 25 STA $25 ; ... a $3000
081F A0 00 LDY #$00
0821 B1 22 LDA ($22),Y
0823 91 24 STA ($24),Y
0825 88 DEY
0826 D0 F9 BNE $0821
0828 E6 23 INC $23
082A E6 25 INC $25
082C CA DEX ; per $18 volte (quindi fino a $2031)
082D D0 F0 BNE $081F; eccessivo, dato che a $1c00 il prg e' finito
082F 4C 00 30 JMP $3000; e qua parte il programma vero e proprio
[il resto del disassemblato e' irrilevante]
Come possiamo vedere anche dai commenti che ho aggiunto, lo stesso programma
fa gia' una rilocazione da $0832 a $3000 e poi esegue il programma cosi'
trasferito. Lo spazio occupato dalla linea basic con la SYS2061 e' sufficiente
per infilarci l'header necessaria perche' sia interpretabile dal kernal come
una cartuccia, header con i 2 vettori di reset e warm start e la famigerata
signature "CBM80", che indica appunto che quel che si trova a $8000 e' una
cartuccia. Possiamo notare che e' sufficiente cambiare il puntatore in zp a
$22/$23 contenente l'indirizzo sorgente della routine di trasferimento,
facendoli puntare al nuovo indirizzo, calcolabile con:
($8000-$0801)+$0832=$8031
e giusto per correggere un esagerazione, limitare la copia a soli $14 blocchi
da $100 bytes, essendo il prg lungo $1302 bytes, per risparmiare qualche
millisecondo e non certo perche copiare piu' bytes sia un grave errore.
; iAN CooG/HokutoForce
; conversione del programma cynthcart.prg in un .bin da 8kb
; per farne una cartuccia (eprom da 8 kb, senza ulteriore hw)
; rimuovere i primi 2 byte (00 80) dal .prg risultante prima di usarlo
; per programmare la eprom.
*=$8000,$ff
incprg _orig\cynthcart.prg
; qua siamo dopo la fine del prg caricato a $8000
; ci mettiamo la routine di init necessaria durante il reset
patch jsr $fda3; stesse chiamate di inizializzazione che troviamo
jsr $fd50; a $FCE2: Initialise I/O, Initialise System Constants,
jsr $fd15; Restore Kernal Vectors,Initialize screen editor
jsr $ff5b;
cli
ldx #$00 ; schermo nero, dopo l'init sarebbe blu/azzurro
stx $d020
stx $d021
dex
txs ; azzera lo stack
lda #$1b
sta $d011; modo testo
lda #$c8
sta $d016; modo singlecolor
lda #$15
sta $d018; schermo a $0400, chars a $1000
jmp back ; ok, continuiamo il normale svolgimento del programma
*=$8000,$ff
word start
word start
byte $c3,$c2,$cd,$38,$30;CBM80 signature
start
jmp patch; e non jsr perche' dobbiamo anche resettare lo stack
back
*=$800d
byte #$14
*=$800f
byte <$8031; facciamo partire la rilocazione dal punto corretto
*=$8013
byte >$8031
*=$9ff0,$ff
byte "iAN CooG/HF 2007"
le 4 JSR nella routine patch sono necessarie perche' quando il kernal vede
che deve eseguire il codice puntato dal primo vettore ($8000) non le esegue,
cosa che avviene quando invece deve partire normalmente lanciando l'interprete
Basic. Noi abbiamo proprio bisogno di simulare la partenza da basic, il
caricamento del programma a $0801 e conseguente RUN, da qui la necessita' di
effettuare tutte le inizializzazioni del caso.
La sola compilazione di questo programma che crea una versione patchata e
rilocata del prg non basta, dobbiamo operare in 2 modi
1) creare un .CRT, file emulabile da Vice/CCS
2) creare un .BIN, file da dare in pasto ad un eprom burner, programmando
cosi' la nostra eprom.
Nel primo caso, se non si vuole creare manualmente l'header del .CRT seguendo
la struttura spiegata nei dox (CRT.TXT, fornito con formats.zip in 64copy),
abbiamo bisogno di mcart di Markus Brenner, o di Cartconv, fornito con Vice.
usarli e' facile, basta seguire le istruzioni stampate a schermo semplicemente
lanciandoli senza parametri. Nell'archivio fornito c'e' anche un comodo batch
che fa tutto al vostro posto, pigroni!1
Nel secondo caso invece, abbiamo bisogno che il file sia di esattamente 8192
bytes, mentre il prg e' di 8194; questo perche' il prg ha nei primi 2 bytes
l'indirizzo di partenza $8000. Basta levarli con un hexeditor, con dd (comando
gnu/unix, googlando troverete che e' disponibile anche in dos/windows) o quel
che vi pare.
A quel punto dovete arrangiarvi perche' non ho mai visto un eprom burner in vita
mia e non saprei proprio come consigliare lo svolgimento dell'operazione.
Non e' finita qua. Oltre che creare una Cartuccia, si puo' in taluni casi
convertire un prg da meno di 8kb in una ROM sostitutiva del Basic, ammesso che
questo programma non faccia in alcun modo uso delle routine appunto contenute
nel Basic, fosse anche solo la stampa tramite jsr $ab1e.
Appurato questo, la conversione e' ancora piu' semplice del primo caso: le
routine di init le esegue il kernal, serve solo un vettore a $a000 che punta
alla nostra routine di reloc, e il gioco e' fatto.
; iAN CooG/HokutoForce
; conversione del programma cynthcart.prg in un .bin da 8kb
; per sostituire la ROM del BASIC.
; rimuovere i primi 2 byte (00 A0) dal .prg risultante prima di usarlo
; per programmare la eprom.
*=$a000,$ff
incprg _orig\cynthcart.prg
; qua siamo dopo la fine del prg caricato a $a000
; ci mettiamo la routine di init necessaria durante il reset
patch
ldx #$00 ; schermo nero, dopo l'init sarebbe blu/azzurro
stx $d020
stx $d021
lda #$1b
sta $d011; modo testo
lda #$c8
sta $d016; modo singlecolor
lda #$15
sta $d018; schermo a $0400, chars a $1000
rts; ok, continuiamo il normale svolgimento del programma
*=$a000,$ff
word start; la routine a $fce2, se non c'e' la signature delle cart,
; esegue una jmp ($a000) quindi qua ci mettiamo l'indirizzo
start
jsr patch
nop ; riempitivo per arrivare alla routine rilocante
nop
nop
nop
nop
nop
nop
back
*=$a00d
byte #$14
*=$a00f
byte <$a031; facciamo partire la rilocazione dal punto corretto
*=$a013
byte >$a031
*=$bff0,$ff
byte "iAN CooG/HF 2007"
in questo caso l'unica opzione e' solo quella dello strip dello startaddres.
Il binario risultante, sempre di 8192 bytes puo' essere usato sia come
basic.rom da Vice/CCS, che programmato su eprom.
Quale vantaggio puo' avere usare una ROM Basic piuttosto di una cart?
Un programma su cart occupa la zona $8000-9FFF rendendola inacessibile come RAM. Se il programma una volta trasferito ed eseguito dovesse usare questa zona per scriverci, salterebbe per aria. Con una rom invece, come gia' detto, l'unica limitazione e' dovuta all'impossibilita' di usare le routine del basic.
Per fare in modo che questa zona torni ad essere utilizzabile quando si usa una cart, la stessa dovrebbe essere dotata di circuiteria speciale per gestire il bankswitching, che permetterebbe di selezionare cosa far vedere al C64 in quella zona, rom o ram. Cartucce di questo tipo sono ad esempio la Magic desk/HESware, le Ocean, le comuni cart di Freeze come Action Replay, e altre spiegate sempre in CRT.TXT. Queste cartucce consentono tra l'altro di avere piu' banchi da 8kb, quindi ampliando la capacita' a programmi ben piu' estesi di 8kb.
Per ogni delucidazione
, grazie per l'attenzione, buonasera.
iancoog.altervista.org/hid/cynthcart_prg2rom.7z