Si tratta di un emulatore, disponibile per vari sistemi operativi, di home computer Commodore.
Si può installare dai repo Ubuntu, ma poi bisogna copiare le ROM dal pacchetto sorgente, pena errore di “fail to load kernal”.
Le tre ROM da copiare corrispondono ai chip fisici:
$ wget http://www.zimmers.net/anonftp/pub/cbm/crossplatform/emulators/VICE/vice-2.4.tar.gz $ tar vzxf vice-2.4.tar.gz $ cd Scaricati/vice-2.4/data/C64 # cp kernal basic chargen /usr/lib/vice/C64
Copiare anche le ROM dei varie drive e datassette:
$ cd Scaricati/vice-2.4/data/DRIVES # cp d* /usr/lib/vice/DRIVES
Digitare “Commodore…” e seleziore il 64. Oppure da bash digitare x64.
Home: fn + cursore sx
Ad esempio per cancellare lo schermo, sul C64 si fa shift + Home, qui si fa shift + fn + cursore sx.
RUN/STOP: esc
RESTORE: fn + cursorse su
Insert: vedi qui
Altri tasti sono disponibili qui.
Per salvare un programma Basic (ed eventualmente poi importarlo in un vero C64…) si fa:
Create and attach an empty disk image….
Dare poi il nome del programma, che avrà come estensione .d64. Una volta creata l'immagine disco, si potrà collegarla semplicemente con Attach a disk image; i vari programmi verranno salvati come file separati con estensione .PRG.
Un MLM (machine language monitor) in assembly è un tool che consente di:
Per entrare nel VICE Monitor digitare Alt+H (Command+H per i Mac ). Quando è attivo il monitor non è attivo il Basic.
Visualizzare i registri (con 'R'):
(C:$e5d1) R ADDR A X Y SP 00 01 NV-BDIZC LIN CYC STOPWATCH .;e5d1 00 00 0a f3 2f 37 00100010 000 000 5425056 (C:$e5d1)
Visualizzare il contenuto della memoria (con 'M'):
(C:$1011) M 033c 0348 >C:033c 00 00 00 00 00 00 00 00 00 00 00 00 00 ............. (C:$0349)
Le locazioni $033C-$0348 sono tutte vuote; scriviamo nella memoria (con '>C') in linguaggio macchina:
(C:$0349) >C:033c ad 80 03 ae 81 03 8d 81 03 8e 80 03 00 (C:$0349)
Di seguito alcuni opcodes utilizzati:
Il programma consiste nello scambiare il contenuto delle locazioni $0380 e $381 (questo è ancora da verificare/modificare).
Per verificare il contenuto della memoria appena scritta:
(C:$0349) M 033c 0348 >C:033c ad 80 03 ae 81 03 8d 81 03 8e 80 03 00 ............. (C:$0349)
Verifichiamo e quindi copiamo dei valori nelle locazioni $0380 e $381:
(C:$0410) M $0380 $0381 >C:0380 00 00 (C:$0382) >C:0380 11 99
Adesso la locazione $0380 contiene il valore $11 e la $0381 contiene $99.
Eseguiamo il programma (con 'G') che inverte le locazioni:
(C:$0382) G 033c
Le due locazioni adesso hanno effettivamente il contenuto invertito:
(C:$e5d1) M 0380 0381 >C:0380 99 11
Per disassemblare (tradurre da linguaggio macchina in assembly) le locazioni dove si è salvato il codice si fa così (con 'D'):
(C:$0382) D 033c 0348 .C:033c AD 80 03 LDA $0380 .C:033f AE 81 03 LDX $0381 .C:0342 8D 81 03 STA $0381 .C:0345 8E 80 03 STX $0380 .C:0348 00 BRK
L'ultimo comando (BRK) presente in $0348 interrompe il Monitor e passa il controllo al Basic nel VICE. Anche qui possiamo verificare il valore, modificato, delle locazioni $0380 (896 in decimale) e $0381 (897):
? PEEK(896) 153 (cioè $99) ? PEEK(897) 17 (cioè $11)
Un altro modo per passare dal monitor al Basic è premendo 'X'.
Per assemblare (scrivere in assembly per poi essere tradotto in linguaggio macchina) si fa così (con 'A'):
(C:$034b) A 033c .033c LDA #$99 .033e STA $0380 .0341 LDX #$98 .0343 STX $0381 .0346 (C:$0346) M 033c 034a >C:033c a9 99 8d 80 03 a2 98 8e 81 03 00 00 00 00 00 ............... (C:$034b)
Il carattere '#' indica che il valore da caricare nel registro non è quello di una locazione di memoria, ma un valore immediato (o letterale).
L'esecuzione può avvenire anche nel Basic del C64:
SYS 828
Dove '828' è il decimale di $033C.
Il programma, che carica i valori $99 e $98 nelle locazioni $0380 e $0381, è stato eseguito:
(C:$e5d1) M 0380 0381 >C:0380 99 98 ..
Per scrivere a video possiamo usare il seguente codice:
(C:$e5cd) >C:0400 3 9 1 f 20 12 f 2 5 12 14 f (C:$e5cd) X
dove $0400 è l'inizio della memoria video del C64; i caratteri che seguono non sono ASCII, ma screen codes (vedi Appendice B della C64 Programmer's Reference Guide).
Il codice produrrà il seguente output:
Invece che scrivere direttamente in memoria, si possono usare le KERNAL subroutines. Uno dei vantaggi di queste è che usano i codici ASCII; ad es. la CHROUT ($FFD2) mostra a video il contenuto del registro A.
(C:$e5cf) A 033c LDA #$41 .033e JSR $FFD2 .0341 LDA #$42 .0343 JSR $FFD2 .0346 LDA #$43 .0348 JSR $FFD2 .034b (C:$034b) G 033c
A video comparirà velocemente la scritta 'ABC' ($41 $42 $43).
Aggiungendo 'RTS' (Return from subroutine):
.034b RTS
è possibile eseguire il comando dal Basic:
SYS 828
Ipotizziamo di voler ottimizzare il precedente codice memorizzando, invece di 'ABC' la sequenza 'HELLO' in locazioni di memoria consecutive e leggerle tramite un loop.
(C:$e5cd) A 033c .033c LDX #$00 .033e LDA $034A,X .0341 JSR $FFD2 .0344 INX .0345 CPX #$06 .0347 BNE $033E .0349 RTS
Per questo loop andremo ad utilizzare il registro X perché:
Le righe $0345 e $0347 possono essere spiegate così: CPX ('compare X') in realtà effettua una sottrazione del valore immediato $06 dal registro X. In questo modo, si ottiene un valore, che se non è zero (BNE) comporta un branch, creando così il loop.
Il flag Carry, oltre che dalle operazioni aritmetiche, viene influenzato anche dalle operazioni di comparazione CPX, CPY e CMP, come indicato qui di seguito.
Ma in questo caso è quindi necessario cambiare anche la comparazione in CPX #$07, con un valore maggiore di uno rispetto a quello cercato.
Per stampare la stringa voluta, sarà sufficiente memorizzare i valori ASCII esadecimali di HELLO e RETURN. Sono valori che dobbiamo memorizzare come tali, non possiamo assemblarli:
(C:$0368) >C:034a 48 45 4c 4c 4f 0d
Richiamando la subroutine dal Basic otteniamo:
Per potere salvare il codice bisogna essere in Basic; bisogna:
Recuperiamo intanto il codice e valori stringa; il codice in assembly è compreso tra $033c e $034f, che corrispondono ai decimali 828 e 847. Quindi:
Si tratta dei valori decimali del codice esadecimale inserito nelle locazioni. Tali valori possono poi essere ricopiati tramite comandi Basic DATA e memorizzati con dei POKE:
Tale codice, che ricrea il codice assembly di prima, si può ovviamente salvare come un qualsiasi programma Basic:
Per salvare su nastro usa il comando File-Create and attach datassette image…. Dopodiché si potrà salvare il listato ed eseguirlo:
Un'altra KERNAL subroutine, oltre alla già vista CHROUT, è GETIN ($FFE4), che testa la pressione di un tasto (simile al comando Basic GET) e lo salva nel registro A in formato ASCII.
C'è anche STOP ($FFE1), che testa la pressione di RUN/STOP.
Il seguente programma testa proprio inizialmente la pressione di RUN/STOP ed in tal caso effettua un opportuno RTS:
(C:$e5d4) A 033C JSR $FFe1 .033f BEQ $0351 ... .0351 RTS
Successivamente chiama la KERNAL routine GETIN e ottiene quindi la pressione di un tasto, che viene salvato in A sotto forma di codice ASCII:
... .0341 JSR $FFe4 .0344 CMP #$30 .0346 BCC $033C .0348 CMP #$3A .034a BCS $033C .034c JSR $FFD2 .034f NOP .0351 RTS
Siccome in questo programma ci interessano solo i numeri da 0 a 9 (codici ASCII da $30 a $39), le righe $0344-$0346 testano se il codice ASCII digitato è minore di 30 (vedi uso BCC sopra) mentre le righe $0348-$034a testano se il codice ASCII digitato è maggiore o uguale di 3A; non essendo questi valori accettabili, in entrambe le condizioni il programma torna all'inizio per un ulteriore verifica del pulsante premuto.
Quindi solo la pressione di numeri 0-9 produrrà un output:
Con gli operandi AND, ORA e EOR si possono effettuare operazioni sui singoli bit dell'accumulatore A, senza toccare gli altri bit.
AND #$FE
ORA #$80
VICMON è un MLM per VIC20. Per eseguirlo su VICE è necessario
Di seguito il codice per stampare a video “HELLO WORLD”.
., 1100 ldx #$00 ., 1102 lda $110e,x ., 1105 beq $110d ., 1107 jsr $ffd2 ., 110a inx ., 110b bne $1102 ., 110d brk
Questi i valori ASCII da memorizzare:
.m 110e .:110e 48 45 4c 4c 4f .:1113 20 57 4f 52 4c .:1118 44 00
Conviene prima della 'H', inserire il valore ASCII $93 per cancellare lo schermo, quindi le locazioni di memoria dove viene salvato il testo cambiano così:
.m 110e .:110e 93 48 45 4c 4c .:1113 4f 20 57 4f 52 .:1118 4c 44 00
Una variante prevede l'output a video senza l'uso della subroutine kernal CHROUT, ma effettuando l'output direttamente sulla memoria video del VIC 20 $1E00-$1FFF (7680-8191).
Come prima cosa conviene sfruttare gli screen codes della scritta già presente a video:
Poi basta cambiare l'indirizzo della prima locazione di memoria in $1113 (dando Return ad ogni riga), per sovrascrivere le locazioni con i codici ASCII in Screen codes:
Il codice è stato cambiato, ed è stato necessario modificare sia la mappa schermo che la mappa colore (in rosso), altrimenti le scritte non sarebbero comparse; inoltre, a causa dello scrolling, è stato necessario modificare le locazioni schermo e colore a partire dalla sesta riga (a partire quindi dalle locazioni $1E6E - 7790 per lo schermo e $966E - 38510 per la mappa colore), così che la scritta non scomparisse in alto.
Programmando il VIC 20 in assembly, si va direttamente ad utilizzare/scrivere sulla sua memoria; può essere quindi utili conoscere alcune aree della memoria, così da comprenderne meglio il comportamento del computer.
L'indirizzo del reset vector è nella memoria in KERNAL rom ($E000-$FFFF 57344-65535); è contenuto in due indirizzi di memoria, $FFFD - 65533 (high byte) e $FFFC - 65532 (low byte); facendo un po' di calcoli si ottiene:
che è l'indirizzo del reset vector ($FD22 - 64802), che può quindi essere richiamato, ad es. da BASIC, per effettuare un reset del computer:
La routine Kernal vera e propria presente in $FD22 è abbastanza complessa; incollo qui di seguito le prime istruzioni:
L'inizio della RAM Basic è definito, a seconda che il VIC 20 sia o meno espanso, così:
tratto da qui. Il vettore di inizio Basic è dato dal contenuto di due locazioni, 43 (low byte) e 44 (high byte); il valore $1001 è confermato:
Questo valore e i successivi, potrebbero interferire con il codice assembly che scriviamo; fino ad adesso per questo abbiamo utilizzato $1100 - 4352: un programma Basic potrebbe andare a sovrascriverlo. E' consigliabile quindi spostare in avanti il vettore di Start-of-Basic; come indicato qui conviene procedere così:
Per la nuova locazione dello Start-of-Basic prendiamo l'attuale + 1024, cioè 4096+1024=5120; per ottenere quanto sopra si procede quindi così:
POKE 5120,0 POKE 43,1:POKE 44,20:NEW
Infatti 5121=1+20*256.
Per conferma, si può provare a digitare il seguente programma in BASIC e verificare dove viene memorizzato:
1234PRINT"CIAO"
e controllare quello che viene memorizzato nel nuovo Start-of-Basic a $1400:
dove: