Il 100% ha trovato utile questo documento (1 voto)
988 visualizzazioni353 pagine

Assembler Per Il Commodore 64 e Vic 20

Caricato da

ettore68
Copyright
© Attribution Non-Commercial (BY-NC)
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 100% ha trovato utile questo documento (1 voto)
988 visualizzazioni353 pagine

Assembler Per Il Commodore 64 e Vic 20

Caricato da

ettore68
Copyright
© Attribution Non-Commercial (BY-NC)
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd

L'Assembler per 11 COMMODORE 64 e 11VIC-80

L'Assembler per 11 COlVllVlODOBE64 e 11VIC-SO

K. Skier

McGRAW-HILL

Book Company GmbH

Amburgo· New York· 5t Louie- San Prenciscc- Auckland· Bogoti • Cittc\ del Guatemala- Cina del Messico· Johannesburg· Lisbona· LondraMadrid· Montreal· Nuova Delhi· Panama· Parigi· San Juan· San PeeleSingapore· Sydney· Tokvo- Toronto

Un libro dl

Rill

Ogni cura e stata posta nella creaztone. realizzazione. verifica e documentazione dei programmi contenuti in questa libra. Tuttavia ne l'Autore ne la McGraw-Hili Book Co. possono assumersi alcuna responsabifita derivante dall'implementazione dei programmi stessi. ne possono forrure alcuna garanzla sulle prestazioni 0 sui risultati ottenibili dal loro usa, ne possono essere rttenuti responsabili di danni 0 benefici risultanti dall'uttlizzo dei programmi. Lo stesso dicas i per ogni persona 0 societa coinvolta nella creazione, nella produzione e nella distribuzione di questa libra.

Tttolo originale: Top-Down Assembly Language Programming


Commodore 64

for Your VIC-20 and

Copyright © 1984 McGraw-Hili Inc. Copyright © 1985 McGraw·Hili Book Co. GmbH Lademannbogen 136 02000 Hamburg 63, RFT I diritti di traduzione, di r-iproduzione, di memorizzazione elettronica e di adattamento totale e parziale con qualstast mezzo (compresi i microfilm e Ie copie fotosrenche) sono riservau per tutti i paesi. Re;!izzazione editoriale: EDIGEO sri, via del Lauro 3, 20121 Milano "Traduzlone: Alessandra Carmignano e Lucio Oriani Grafica di copertina: Valentina Boffa Composizione e stampa: Litovelox, Trento
ISBN 88-7700-0 11-2

1a edizione Marzo 1985

Commodore 64 e VIC-20 sana marchi registrati daJla Commodore Business Machines Inc.

Indice

Introduzione

11

Capitolo 1 La struttura del computer II microprocessore 6502 15 Diversi tipi d i memoria 16 II sistema operative 18 II BASIC 19 II cod ice del 6502 19

15

Capitolo 2 Introduzione all'Assembler 21 Rappresentazione binaria 22 Rappresentazione esadecimale 23 II cod ice ASCII dei caratteri 24 II cicio macchina 24 II cod ice macchina 25 Assemblatori 25 II programma in formato sorgente 26 Caricamento di un registro 27 Le costanti 28 Memorizzazione di un registro 29 Prima il byte basso 29 Indir-izzarnento in pagina zero 30 Espressioni simboliche 31 Alcuni esercizi 32

INDICE

Capltolo 3 Loop e subroutine 33 Indirizzamento indicizzato 33 L'istruzione eMP 35 I flag di stato 35 Salti condizionati ]6 Loop 37 Indirizzamento relativo 39 Salti incondizionati 39 Indirizzamento indiretto 40 Funzionamento dei salti 40 Rilocabilita 41 Subroutine 41 Subroutine fittizie 43 Lo stack 43 Capitolo 4 Arltmetica e logica 47 Transcodifica dei carancrt 47 Trasferimento dei registri 48 Tabelle di transcodifica 49 Operazioni aritmetiche 49 Traslazione 50 Rotazione 5/ Incremento e decremento 52 Somma 53 Sottrazione 53 Modo decimale 54 Operazione logiche 54 Settare i bit 54 Azzerare i bit 55 Commutare i bit 56 Capitola 5 Utility per la gestione Punta tori 60 [Link] 60 [Link] 6/ La posizione sullo schermo 62 TVTOXY 62 TVGIU-TVVAI-TVPIU 65 VEDCAR 66 VEDBYT 66 TVHOME, CENTRO 69 TVSALV e TVREC 70 Pulire 10 schermo 71 della schermo 59

Capitolo 6 II Monitor Visibile 75 Assemblaggio manuale 75 Un semplice monitor di codice macchina Obiettivi 78 II Monitor Visibile 78 Dati 80 Struttura 81 Visualizzazione 82 Linea dei titoli 83 Linea dei dati 84 La Ereccia indice 86 La sezione di aggiornamento 87 L'acquisizione del carattere 89 Conversione ASCII/binario 93 Le utility del Monitor Visibile 95 Usa del Monitor Visibile 95

76

Capitolo 7 Utility di stampa 97 Selezione della periferica di output 98 Una routine di starnpa dei caratteri 99 Vet tori di output 100 Routine di output per caratteri speciali 102 Invio r-ipetitivo 103 Come stampare un messaggio 104 Come stampare un testa 106 Salvataggio e recupero del puntatore SELEZ Conclusioni J09 Alcuni esercizi 110 Capitolo 8 II dump esadecimale II J TVDUMP 112 PRDUMP 115 Indirizzi di partenza e fine J 17 La testata 119 PRUNE 121 Come selezionare il byte successivo (NEXTSL) GOTOSA 124 Capitolo 9 Un dlsassemblatore J 25 Come determinare 10 mnemonico 128 Come stampare l'operando 129 Utility del disassemblatore 131 Subroutine di indir-izzamento 133 Come gestire i testi 138 La fine della linea: FIN ITO /40

J08

I
123

I I I

INDlCE

Capitolo 10 Utility di trasferimento 143 Configuraxione 143 Sovrapposizioni 144 Ottimizzazione per ouenerc la massima velocita Velocita 151 Capitolo 11 Un semplice text editor 155 SETBUF /56 MOSTRA /57 Modo sosti tuzione e modo inserimento 158 Come visualizzare la linea di testo 159 Come visualizzare la linea di stato 160 L'editor in pratica /61 Capitolo 12 II Monitor Visibile integrato 169

146

Capitolo 13 Caricamento del software 173 Usa del BASIC per car-icare il codice macchina 173 Attivazione del Monitor Visibile 177 Salvataggio di un programma in codice macchina /77 Appendice A Codice ASCII e set di istruzioni 18 J A.1 Codice ASCII dei caratteri 181 A.2 Istr-uzioni del 6502·Lista degli mnemonici 183 A.3 Istruzioni del 6S02-Lisla degli opccde 185 AA Tempo di esecuzione delle istruzioni 189 A.S Opcode del 6502 in ordine alfabetico e di indirizzamento Appendice B Istruzioni per l'implementazione B.I II VIC-20 /95 Memoria colore 196 Codici schermo 196 FIXCAR /98 Routine di input da tastiera 199 VICTVT /99 Riservare la memoria 200 Attivazionc del Monitor Visibile 200 Come ottenere la stampa 201 B.2 II C-64 202 Memoria colore 202 Codici schermo 203 FIXCAR 204 Routine di input da tastiera 205 C64TVT 205 195

191

INDICE

"'f'

Riservare la memoria 206 Attivazione del Monitor Visibile Come at tenere la stampa 207

207

Appendice C Listati-delle routine 209 C.l Utility per la gestione della schermo 209 C.2 II Monitor Visibile (primo livello e subroutine di visualizzazione) 219. C.3 II Monitor Visibi!e (subroutine di aggiornamento) 227 C.4 Utility di stampa 234 C.S II dump esadecimale 244 C.6 Un disassemblatore {prime livel lo e subroutine di utility) 255 C.7 Un disassemblatore (subroutine per it modo di indirizzamento) 265 C.8 Un disassernblatore (Labelle) 273 C.9 Utility dt trasferimento 279 [Link] Un semplice text editor [prime livello e subroutine di [Link]) 287 [Link] Un semplice text editor (subroutine EDITA) 293 C.12 II Monitor Visibile integrato 302 C.13 Dati di sistema per il VIC-20 305 C.14 Dati di sistema per il C-64 313 Appendice D Dump esadecimali 321 D.I Utility per la gestione delle schermo 321 0.2 II Monitor Visibile (primo livello e subroutine di utility) 322 0.3 II Monitor Visibile (subroutine di aggiornamento) 323 0.4 Utility di stampa 324 0.5 II dump esadecimale 325 0.6 Un disassemblatore (primo livello e subroutine di utility) 326 0.7 Un disassemblatore (subroutine per il modo di indirizzamento) D.B Un disassernblatore [tabelle] 328 0.9 Utility di trasferimento 329 0.10 Un semplice text editor 330 0.11 II Monitor Visibile integrato 331 0.12 Dati di sistema per it VIC-20 332 0.13 Dati di sistema per il C-64 333 . Appendice E Dump decimali 335 E.I Utility per la gestione delle schermo 335 E.2 II Monitor Visibile (primo livello e subroutine ne) 337 E.3 II Monitor Visibile (subroutine di aggiornamento) E.4 Utility di stampa 339 E.S II dump esadecimale 340

327

di visualizzazio338

10

INDICE

E.6 Un disassemblatore (primo liveLlo e subroutine di utility) 342 E.7 Un disassemblatore (subroutine per il modo di indir-izzarnento] E.8 Un disassemblatore (tabelle) 344 E.9 Utility di trasferimento 346 E.I0 Un semplice text editor 347 E.J 1 II Monitor Visibile integrato 349 E.12 Dati di sistema per il VIC-20 350 E.13 Dati di sistema per iJ C-64 351 Appendice F Programmi BASIC 353 F.l Routine per caricare iI programma Ie 353 F.2 Routine per salvare un programma disco 355 Appendice Iodice G Tabelle di converslone 361

343

oggetto

per

iI Monitor

Visibi0

in codice macchina

su nast rc

esadecimali-decimali

357

anaUtico

Introduzione

Generalmente si sente dire che i computer stanno diventando sempre piu "intelligent!": rna i computer, in quanta macchine, non sono per nulla intelligenti, 10 sono i programmatori, cioe quelle persone che insegnano ai microprocessori a risolvere i piu diversi problemi. La stesura dei programmi e quindi di fondamentale importanza per ottenere iI massimo dalla macchina. Tenendo presente queste considerazioni, questa Iibro si prefigge due scapi ben precisi: innanzitutto fornire ai principianti alcune tecntche. terminologie e conoscenze dell'Assembler in generale e del 6502 in particolare; in secondo luogo di presentare una serie di routine utili nello sviluppo di programmi in cod ice macchina per il 6502. II primo capitolo vuole essere una rapida guida attraverso l'hardware e il software del vostro computer. I capitoli 2, 3 e 4 costituiscono un rapido corso di Assembler destinate a quei let tori che si avvicinano all'argomento per la prima volta. II resto del volume riporta i Iistati in codice sorgente, oggetto e Assembler di programmi che potrete inset-ire nel vostro computer. I programmatori hanno a lungo cercato di sviluppare programmi compatti e veloci con 10 sconsolante risultato che spesso il programma risulta illeggibile semplicemente percbe il programmatore ha voluto risparmiare pochi byte 0 pochi cicli. In certi casi, quando la memoria e particolarmente ridotta 0 il tempo di esecuzione e cr-itico, la leggihilita del programma viene sacrificata aile prestazioni. Nella creazione dei programmi che compaiono in questo libro si e tenuto conto di numerosi obiettivi, molti dei quali pili importanti della velocita di esecuzione 0 della dimensione di un blocco di cod ice. I programmi risulteranno quindi:

12

INTRODUZIONE

Utili: nessun programma presentato sempiicemente per dimost rare una particolare tecnica di programmazione. Tutti i programmi del libra sono stati scri tti per necessita effettive. Facili da usare: dando semplicemente un'occhiata alia schermo possibile sapere quale programma si sta eseguendo e in quale modo. Quando I'esecuzione richiede un input dall'operatore. il programma specifica le informazioni nece~sarie e permette di correggere eventuali errori commessi nella risposta. Per usare questa software non dovrete ricordare indirizzi di programma a variabili. Le funzioni sono assegnate a tasti individuali ed e possibile stabilire i tasti funzione nella maniera che piu vi aggrada. Leggiblli: un principiante dovrebbe essere in grado dt comprendere la logica di ogni singolo programma. Le label e i commenti nei listati sono stati scelti molto accuratamente per spiegare 10 scopo di ogni variabile, subroutine e linea di programma. Portabili: il software qui presentato funziona indifferentemcntc sui C-64 e sui VIC-20. Con un adeguato adattamento e possibile usare questi programmi su qualunque computer basato sui 6502. Compatibili: fintanto che altro software non fa usa del quarto blocco di 4K della memoria (locazioni da 3000 a 3FFF) non dovrebbe esistere conflitto tra il vostro software e Ie routine di questo libro. In particolare. la maggior parte dei programmi presentati lascia inalterati i puntatori della pagina zero, cosicche non ci sara la necessita di salvarli e ripristinarli prima e dopo ogni chiamata alia subroutine. Espandibili: i programmi di questo libro sono altamente modulari e possono essere estesi 0 ristrutturati per meglio soddisfare i vostri bisogni. Le subroutine specifiche del sistema vengono richiamate indirettamente, cos icc he possibile sostituirle con altre e la maggior parte dei valori puo essere trattata come variabile. Non esistono programmi "monolitici" in questa libro, sono tutte subroutine che e possibile combinare in molte maniere per ottenere nuove potenti strutture. Compatti: sappiamo che ogni personal computer ha una certa disponibilita di memoria (troppo poca) e conosciamo anche il modo di scrivere prograrnmi che occupino il 10 0 il 20 per cento in meno di spazio, rna COSI facendo si sact-ificherebbe la leggibifita. portabilita 0 espandihilita. In molti casi abbiamo temuto, per risparmiare un byte, di perdere la chiara comprenaibilita della logica del programma e questa sarebbe state un prezzo troppo alto da pagare. Attenzione: se usate un VIC-20 necessaria i'espansione da SK. Veloci: il software di questo libro e state scritto per operare il piu velocemente possibile tenendo presenti gli obiettivi sopra esposti. Ma ogni volta che e state necessario operare una scelta tr-a chiarezza e veloci abbiamo penalizzato questultima. Un programma veloce rna illeggibile non e di alcun valore. Nessun programma in questa libro si

ta.

INTRODUZIONE

13

preoccupa di quanta dovrete attendere, rna cerca invece di essere il pili chiaro possibile. Inoltre, come pot reste stabilire se state aspeu ando un millisecondo in piu? Andale avanti, leggete, programmate, rna, soprauuuo. divertitevi!

Nota Ouesto testa ha una duplice valenza: da una parte e una com pi eta ed esauriente descrizione del Iinguaggio Assembler e dall'altra una guida alIa realizzazione di un assemblatore completo e funzionante. Questa progetto, che si snoda lunge i vari capitoli, consente una comprensione, dall'interno, dei concerti e della programmazione in cod ice macchina e J'assemblatore che ne risulta Ii esemplifica nella pratica. Ovviamente, questa programma non e confrontabile con un assemblatore/disassemblatore professionale che consente un uso piu sernplice ed immediato; consigliamo percio agli utenti che vogliono programmare intensivamente in codice macchina, l'acquisto della cassetta Assembler/Disassembler per it Commodore 64 di A_ Bleasby, prodotta dalla McGraw-

Hill.

Capltolo

La struttura del computer

1
I I I I

II C-64 e it VIC-20 srmo macchine mol to potenti, rna per poter sfruttare completamente questa potenza, dobbiamo innanzitutto capire come lavorano. Cost, prima di iniziare a program mare daremo uno sguardo veloce a1 computer.

II microprocessore

6502 e

Inizieremo con il 6502 che quel componente del vostro sistema che svolge i calcoli. Preso singolarmente, il 6502 non puc fare molto; dispone di tre registri (speciali aree di memoria che contengono i dati su cui iI presi tra 0 e 255. Questi registri hanno diverse caratteristiche, per esempio a un valore contenuto in A (accumuiatore) possibile addizionare 0 sottrarre qualsiasi valore compreso tra 0 e 255 mentre i valori contenuti in X e Y possono essere aumentati 0 diminuit i solo di una unita. II 6502 pub anche trasferire iI contenuto di un registro in un altro oppure in una qualsiasi locazione di memoria, corne pure compiere iI procedimen to inverso, cioe assegnare ad un registro i] valore contenuto in una locazione di memoria. Sfruttando queste capacna, iI 6502 pub ope rare su vari valori contemporaneamente, caricando i registri can i numeri contenuti nelle varie locazioni di memoria interessate, eseguendo Ie operazioni del caso e poi memorizzando il risultato in memoria.

programma opera) chiamati A, X eYe

che possono con tenere valori com-

:1

16

LA STRUTTURA DEL COMPUTER

Diversi tipi dl memoria


II computer memorizza i dati come una serie di leO semplicemente perche la memoria non altro che un'elaborata mat rice di interruttori che possono avere solo due posizioni possibili, aperto (I) 0 chiuso (0). Non tutte Ie memorie perc sono uguali: in quelle chiamate ROM (Read Only Memory - memoria a sola lettura) gli interruttori sana fissi, non possono cioe essere cambiati. In altre memorie. dette RAM (Random Access Memory - memoria ad accesso casuale), 10 stato degli interruttori puc essere cambia to dal microprocessore: il 6502 puc infatti aprire 0 chiudere gli interruttori (bit) della memoria programmabile (RAM) e in seguito rileggere do che ha seritto. La Figura 1.1 mostra come la memoria viene utilizzata dal processore.

Figura 1.1 Interazione del processore con la memoria. flusso dei dati

Le

Frecce indicano

il

Esistono altre memorie dette porte di input, che vengono utilizzate dai dispositivi esterni come tastiere, terminali, ecc. II 6502 eJabora i dati che vengono immessi da questi dispositivi esterni leggendo Ie porte. Essendoci Ie porte di input, non potranno mancare quelle di output che permetteranna al computer di colloquiare con il mondo esterno. Non pensate a questa punto che nel libro sia contenuta la ricetta per far parlare il vostro computer; infatti, troverete spesso modi di dire come: «il 6502 vede, ricorda 0 sa cosa fare»; naturalrnente questa e impossibile, rna serve a rendere piu chiare certe idee e piu digeribili certi concetti. Ritornando al discorso precedente, normale raggruppare i due tipi di memoria descritti in un unico gruppo; infatti accadra che alcuni dispositivi come registratore a cassette 0 floppy disk saranno connessi sia aile porte di input che a quelle di output; chiameremo dunque queste memorie con il nome di porte di I/O (input/output - ingresso/uscita). La Figura 1.2 riassume gli accessi del microprocessore aile memorie e ai dispositivi periferici. Anche il monitor collegato al vostro sistema puc essere considerato come un particolare tipo di memoria, infatti il 6502 puo leggere e sct-ivere sul-

LA STRUITURA

DEL

COMPUTER

17

Periferiche

Memoria

Processore

Porte di output

6502

Memoria centrale

Figura 1.2 Accessi del 6502 ai dati in memoria e aile periferiche. indica no il flusso dei dati

Le frecce

10 schermo. La tastiera viene scandita dalle porte di 110 che vengono decodificate, quindi la CPU puc leggere la tastiera semplicemente test an do alcune locazioni di memoria. Le porte di I/O sono di basilare importanza in ogni sistema perche permettono al microprocessore di colloquiare con I'utente come si puc vedere in Figura 1.3.

18

LA STRUTIURA

DEL COMPUTER

Figura 1.3 Come avviene la comunicazione Ira 6502 e dispositivi perifer-ici. Le frecce indicano iI flusso del dati

II sistema operativo
Abbiamo per il momento parlato solo dell'hardware del computer, rna il C·64 e iI VIC-20 non sono compost! solo da questa. Nel computer e memorizzato permanentemente nella ROM il sistema operative che, tra Ie altre cose, include Ie routine di gestione dell'I/O necessarie per l'uso del monitor TV e della tastiera. Non ci interessa, in

questa sede, iI principio del funzionamento

di queste routine, rna e neces-

saria renderei canto che dobbiamo dtpendere da esse per 10 svolgimento di parecchie funziani basilari. Nel sistema operativo del vostro computer sono comprese molte altre routine che sarebbe utile usare direttamente, rna poiche il software presentato in questa Iibro e stato concepito per funzionare su divers! tipi di computer, si e cercato di sfruttare il sistema operativo al minimo indispensablle. In altre parole, i programmi contenuti nel libro non traggono alcun vantaggio dal sistema operativo della macchina, rna il software che voi svilupperete per vostro con to e che quindi sara destinato a funzionare sulla vostra macchina dovrebbe avvalersi pienamente delle routine contenute nelle ROM del sistema operativo.

LA STRUTTURA DEL COMPUTER

19

II BASIC
Una delle caratteristiche principali del vostro computer l'Interprete BA· SIC contenuto nella ROM. Questa interprete non e altro che un programma che permette al computer di "capire" i comandi dati in linguaggio BASIC. La documentazione allegata al vostro sistema vi fornisee una lista di comandi usabili in BASIC. Questa linguaggio, malta facile da imparare, vi permettera di reahzzare molti programmi, rna ogni istruzione BASIC dovra essere analizzata e tradotta dall'interprete prima che la CPU possa eseguirla. La conseguenza di cia che un programma scritto in linguaggio BASIC non sara rna i malta veloce, 0 almena non sara mai cosl veloce come un programma scri tto in codice macchina.

II codice del 6502


La CPU (unita centrale di elaborazione) e il cuore del vostro computer. II C-64 e il VIC-20 usano il 6502. Ogni microprocessore ha un suo gruppo di istruzioni ben definito. Questa insieme di istruzioni e a un livello malta inferiore dei comandi BASIC. Per esempio, in BASIC, possiamo scrivere una singola linea di programma come PRINT "CIAO" mentre in codice macchina ci vogliono parecchie istruzioni per ottenere 10 stesso risultato. Una determinata sequenza di istruzioni in codice macclpna fornira 10 stesso risultato su macchine diverse rna basate sullo .§.testo microprocessore. Cost, se scrivete una sequenza di istruzioni del 6502 che compte una determinata funzione, questa verra eseguita da qualunque calcolatore basa to sui 6502, mentre non dara nessun risultato in macchine basate sull'8080 0 sullo Z80 0 suI 6800. I programmi contenut i in questa volume sono tutti scritti ne! codice del 6502; potranno quindi essere usati anche su Apple, PET, Atari e su tutte Ie rnacchine basate su questo microprocessore; inoltre richiedono mediamente 4K di memoria lasciandone quindi piu che a sufficienza per i vostri programmi.

I
I

Caplwlo

Introduzione all' Assembler

2
I I

I
I

Avete mai provato a guardare un giocoliere? Le palline, Ie mazze 0 qualsiasi altra cosa egli lancia in aria si intrecciano in traiettorie COSI complicate che difficilmente e possibile distinguerle. Questa e molto bello, rna non e magia! E solo il risultato di parecchie ore di allenamento e dell'applicazione di determinate sernplici regale. Con un buon allenamento e conoscendo Ie regale del gioco. anche voi potreste essere in grado di dare spettacolo. La programrnazione in linguaggio Assembler non mol to differente cial gioco dell'esempio; sarete infatti in grado di realizzare programmi che stupiranno voi stessi. In parole povere Ie regale di un giocoliere sono que lie di afferrare un oggetto con una mano. lanciarlo in una determinata direzione e riprender10. Queste semplici regale sana applicabiJi anche alia CPU, il cui compito non e altro che prendere i dati nelle varie locazioni di memoria e spostarIi in altre locazioni. In primo luogo una CPU e molto veloce e puc eseguire parecchie istruzioni in poco tempo; inoltre, per man tenere iI paragone con it giocoliere, quest'ultimo puc contare solo su due mani, mentre il 6502 su tre (i registri A, X e Y) e su parecchie tasche (8000 0 piu byte di memoria). Un byte e composto da 8 bit di dati che possono essere caricat i con temporaneamente in un registro. Diremo quindi che un registro puc contenere un byte corne pure ogni locazione di memoria puc con tenere un byte. II 6502 puc operare su un singolo byte alia volta, rna poiche e in grado di eseguire centinaia di migliaia di operazioni al secondo, e anche in grado di operare su centinaia di migliaia di byte al secondo.

I I
I

I
I

I
I

22

INTRODUZIONE

ALL'ASSEMBLER

Rappresentazione binaria
Ogni valore viene memorizzato dal computer come una serie di bit. Se volessimo, potremmo rappresentare un byte per mezzo della sua configurazione; questa tipo di rappresentazione che fa usa solo di I 0 0 viene chiamata binaria. Per esempio, il numero 25 decimale viene rappresentato in binario come 00011001. Nel sistema binario ogni bit definisce la presenza 0 I'assenza di un determinato valore. inoltre ogni bit ha valore 0 "peso" doppio di quello imrnediatamente alia sua destra. Da questa affermazione deduciamo che il bit pili a destra il me no significative (LSB - least significant bit) mentre quello piu a sinistra il piu significative (MSB - most signiiicant bit). La Tabella 2.1 chiartra meglio iI concetto e il peso di ogni bit componente un byte:

Tabella 2.1 Peso dei bit in un byte Bit numcro: Peso: 7 128 6 64 5 32 4 16

II bit piu a destra (bit 0) ci dice se abbiamo un I nel byte, quelJo irnmediatamente alia sua sinistra (bit I) ci dice se abbiamo un 2 e COS! via fino al bit piu a sinistra (bit 7) che ci dice se nel nostro byte e contenuto un 128, I! procedirnento per trovare la rappresentazione binaria di un numero decimale, e mclto semplice. Prendiamo ad esempio il numero 25; per prima cosa dobbiamo trovare la potenza del numero due che piu si avvicina per difetto al valore. nel nostro caso e 24, cioe 16. A questo punto abbiamo 25-16=9; tenendo nota che il bit 4 sara un uno cerchiamo la potenza di due che piu si avvicina per difetto al valore ottenuto, il risultato sara 3 2 , doe 8. Anche il bit 3 sara percio un uno e iI nostro valore sara diventato 9-8= 1; quindi ci manca una unlta per raggiungere il valore di partenza. La potenza del due che ha come valore 1 e 2°, quindi anche il bit 0 sara un uno. A questa punto il nostro valore di partenza 25 avra rappresentazione binaria 00011001, infatti sommando i pesi dei bit a uno otteniamo 16+8+ I =25. I! nurnero 25 puc essere perc espresso anche in altra maniera. Piuttosto che rappresentare un valore come una serie di 0 e 1 ci sara pill comodo usare la rappresentazione esadecimale.

INTRODUZIONE

ALL'ASSEMBLER-

23

Rappresentazione esadecimale
Contrariamente alia rappresentazione binaria che richiede un gruppo di otto caratteri per definire un valore a 8 hit, la rappresentazione esadecimale ne richiede solamente due. Ouest! caratteri non sono limitati a 0 e 1 rna includono tutta la serie dei numeri da 0 a 9 e Ie lettere dalla A alia F. In questa sistema abbiamo COSl un gruppo di 16 caratteri per rappresentare i valot-i. Per rappresentare un byte di 8 bit in notazione esadecimale dobbiamo dividerlo in due byte da quattro bit detti nybble. Questi due byte da 4 bit hanna un valore compreso tra 0 e 15 (decirnale) che possiarno esprimere con un singolo numero esadecimale. II numero 10 decimale viene rappresentato in esadecirnale con $A {il segno "S" indica per convenzione che il numero e espresso in [Link] esadecirnale). La Tabella 2.2 c! da l'equivalenza decimale/esadecimale per i valori compresi tra 0 e IS.

I
I

I
I I I I I I

Tabella 2.2 Equivalenza decimale/esadecimale Carattere esadecimale $0


$1

I I I
I

Decimale equivalente

o
1 2 3 4 5 6
7

$2 $3 $4 $5
$6

I I

$7 $8 $9
$A

$B
$C $D

8 9 10 11
12

13
14

$E $F

15

Nell'Appendice G e contenuta la tabella delle equivalenze decimalilesadecimali per valori compresi tra 0 e 255. In questa libra il codice oggetto di ogni programma sara generalmente presentato in notazione esadecimale, quindi una chiara comprensione dei concerti della numeraziane esadecimale indispensabile per interpretare le istruziani e per seguire 10 svolgersi dei pragrammi.

--------------_~

~J

24

INTRODUZIONE

ALL'ASSEMBLER

II codice ASCII dei caratteri


Un byte di 8 bit puc essere usato anche per rappresentare una lettera dell'alfabeto maiuscola 0 rninuscoia, un segno di interpunzione 0 un carattere di controllo per la stampante, per esempio un ritorno a capo. Una stringa di questi caratteri puo formare una parola, un messaggio 0 perfino un documento completo. Nell'Appendice Al comenuta 1a tabella dei caratteri ASCII e dei valori esadecimali corrispondenti. ASCII e l'acronirna di American Standard Code for information Interchange (cod ice standard americana per 10 scambio delle informazioni). Se, per esempio. volete memorizzare la lettera A in una qualsiasi locazione di memoria, guardando la tabella dell'Appendice AI, saprete che e necessar-io memorizzare il valore $41. L'interpretazione di un byte come numero, carattere ASCJI 0 aitro, dipende esclusivamente dal programma che usa que! particolare valore.

II ciclo macchina
Un microprocessore come il 6502 non puc fare nulla in mancanza di precise istruzioni. Esso conosce solo 151 istruzioni, chiamate opcode (codici operativi). Ogni opcode e lungo un byte e puc ordinare al microprocessore di svolgere una ben precisa aperazione come, per esempio, memot-izzare il valore di un registro in una [Link] di memoria, oppure caricare

Figura 2.1 11ciclo macchina del 6502

INTRODUZIONE

ALL'ASSEMBLER

25

un registro con un valore prelevato dalla memoria, oppure compiere qualche altra operazione altrettanto sernplice. L'Appendice A3 contiene una lista di tutti gli opcode del microprocessore 6502. Cosa avviene durante 10 svolgersi di un programma? II 6502 Jegge un opcode, com pie l'operazione specificata. legge il successive opcode e svolge l'operazione specificata ..... e cosi via. Ma come puo il microprocessore sapere dove si trova la successiva istruzione ? Esiste un quarto registro, chiamato PC (Program Counter - contatore di programma) che contiene I'indirizzo di alcune locazioni di memoria. Quando il 6502 inizia un cicio, legge l'Istruzfone dalla locazione di memoria specificate dal PC. Finito il cicio, il PC puntera ad una nuova locazione di memoria che contiene l'istruzione successiva. La Figura 2.1 mostra il diagramma di flusso di un ciclo del rnicroprocessore.

II codice macchina
Un programma in codice macchina non altro che una sequenza di ist r-uzioni immagazzinate nella memoria del computer. Se e possibile fare in modo che iI PC contenga I'indirizzo di partenza del nostro programma, allora diremo che il PC punta al nostro programma. Quando il 6502 inizia il cicio macchina, legge I'istruzione contenuta nella locazione di memoria puntata dal PC ed esegue il lavoro specificato. A questa pun to potremo dire che il programma sta girando. Ogni istruzione e memorizzata come un opcode di 1 byte che puc essere seguito da uno a due byte di operando. Ad esempio, un programma in codice macchina per il 6502 potrebbe essere HA9 05 20 02 04 A2 FS 60". A prima vista sembrerebbe solo una manciata di numeri (esadecimali naturalmente) rna e proprio questa codice che costituisce il "Iinguaggio" che la macchina puo interpret are e da qui il nome di codice macchina.

Assemblatori
Se voi foste macchine vi sarebbe malta facile leggere i programmi direttamente in codice macchina; se la cosa vi risulta facile, forse appartenete a una nuova generazione di mutantil Siccome non siamo macchine rna umani, sono stati sviluppati degli strumenti di programmazione, chiamati assemblatori, che accettano in ingresso un codice detto sorgerue (piu leggibile) e 10 trasformano in un Iistato e in un cod ice macchina detto oggetto. Un listato e naturalmente destinato a un essere umano poiche molto piu

26

~ONEALL'ASSEMBLER

facilmente leggibile, mentre l'oggetto una serie di istruzioni destinate at microprocessore. A ogni programma contenuto in questa libra corrisponde una appendice che De riporta i] listato Assembler ed esadecimale. II Iistato Assembler include it sorgente e l'oggetto, rnentre it listato esadecimale vi mostra quello che viene letto dalla CPU. La Figura 2.2 mostra come viene usato un assernblatore per produrre iI listato per iI programma tore e iI codice oggetto per it computer.

Fonte:

Input:

Programma:

Llsteto:

Per usc del"

Programma tore

6502

Figura 2.2 Dal programma tore al cod ice oggetto. L'assemblatore accetta il codice sorgente in Ingresso e produce in uscita il listato Assembler e il cod ice oggetto

II programma in formato sorgente


Un programma di questa tipo costituito da una a pili linee di cod ice sorgente. Una linea di codice sorgente e costituita da quattro campi: LABEL MNEMONICO OPERANDO COMMENTO

necessario in ogni caso, consiste di un gruppo di tre lettere scelte per ricordare la specifica funzione dell'istruzione rappresentata (naturalmente gli mnemonici sono in inglese). Per esempio, 10 mnemonico LDA significa LoaD Accumulator (carica l'accumulatore); LDX significa LoaD X (carica il registro X); TXA significa Transfer X register to the Accumulator (trasferisce iI registro X nell'accurnulatore).

Lo mnemonico,

INTRODUZIONE

ALL'ASSEMBLER

27

Questi codici mnemonici non sono cosl signiflcativi come Ie istruzioni BASIC rna rappresentano un grande passo avanti rlspeuc agli opcode (vedi Appendice A2 per la lista degli mnemonici). Alcune operazioni richiedono un operando: per esempio LOA richiede I'operando perche nella linea di programma bisogna specificate il valore con cui si vuole caricare I'accumulatore. I campi label e commento sana opzionali. Una label perrneue di assegnare un nome a determinate locazioni di memoria, mentre i commenti non vengono inclusi nel programma oggetto rna hanno la stessa funzione delle REM in un programma BASIC, cioe quell a di rendere piu facile l'interpretazione del programma. Quando scrivete un programma, anche se verdi letto esclusivamente da voi stessi, cercate di seegliere Ie label e i commenti in modo che chi u nque possa capire la logica del programma. Questa semplice regola vi fara rispanniare malta tempo quando, a distanza di giorni, settimane a mesi, potreste non ricordare la funzione di certe !inee prive di commento.

Caricamento

di un registro

Proviamo a scrivere un programma semplicissimo per carieare in un registro un valore, per esempio carichiamo in A il numero to. Poiche vogliarno caricare l'accurnulatore, faremo uso dell'istruzione LDA (se il regist ro Fosse stato X avremmo natural mente usato LDX e COSt via). Sappiamo qual 10 mnemonico da usare per scrivere la nostra prima riga di programma, rna uno sguardo all'Appendice AS, che contiene gli opcode in ordine alfabetico e i modi di indirizzamento, ci dice che LDA ha diverse possibilita di indirizzamento. Che operando dovremmo usare nella nostra linea di programma? II nostro scopo e quello di caricare I'accurnulatore con il numero 10, cosl dovremo usare I'indirizzamento immediato per caricare il numero 10 direttamente nell'accumulatore. Per indicare il modo immediato useremo il carattere "# '':

Esempio

LDA # IO L'esempio I una linea di programma sorgente che contiene solo 2 campi: uno mnemonico e un operando. Lo mnemonico, LDA, significa "carica l'accumulatore", rna con cosa? L'operando ci dice che cosa dovra essere carieato nell'accurnulatore. II segno "#" specifica che l'operazione deve

28

INl'RQDUZIONE ALL'ASSEMBLER

essere eseguita in modo immediato il che significa che intendiamo caricare l'accumulatore con una costante specificate in questa linea di cod ice sorgente. piuttosto che con valori 0 variabili che si Irovano in qualche 10cazione di memoria. Percio I'operando identifica la costante da caricare nell'accumulatore. nel nost ro caso 10.

Le costanti
Una costante e un valore conosciuto ed e immutabile nell'ambtto del programma. Se un valore cambia durante I'esecuzione di un programma, viene allora detto variabi!e, ed e necessaria riservare una 0 piu locazioni di memoria per contenere il valore di ogni variabile. Ci sono diversi tipi di costanti. Tutti i numeri sono delle costanti. 11 numero 7, per esempio, e una cost ante: yarra sempre 7, oggi come domani. Un carat tere e un altro tipo di cost ante, una "A" sara sempre una A. Ma un gruppo di caratteri. come per esempio "Carburante" cambiera il valore rappresentato durante 10 svolgersi del programma (per esempio la simulazione di un allunaggio), e cost non e una costante. Notate nell'esempio I che il segno "#" e l'unica interpunzione dell'operando. In assenza di speciali interpunzioni (come il segno "S" per indicare un numero esadecimale e il segno "'" per indicare un carattere ASCII) tutti i numeri verranno considerati decimali. Che codice oggetto appa rira assemblando questa linea di programma? Proviamo ad assemblarla manualmente guardando l'Appendice AS dove troveremo che l'opcode corr-ispondente a LDA/immediato $A9. II secondo byte deve specificare il valore da caricare nell'accumulatore. Vogliarna caricare iI registro A con il valore decimale 10, che corrisponde a $OA; quindi il programma oggetto per l'esempio 1 e: A9 ~A. Quando quest! 2 byte di codice oggetto verranno eseguiti dal 6502, l'accumulatore con terra il valore $OA, che in effetti quello che ci prefiggevamo. E se avessimo volute caricare l'accumulatore con la lettera "M" piuttosto che con un numero? Avremmo 10 s tesso usato I'istruzione LDA e anche il modo immediato, specificando nell'operando la costante da caricare nell'accurnulatore. Entrambe Ie linee seguenti otterranno 10 scopo prefissato:

Esempio 2 LDA #'M oppure LDA #$4D

INTRODUZIONE ALL'ASSEMBLER

29

In queste due linee di programma 10 mnemonico e il segno 1/ ci dicono che stiamo caricando l'accumulatore in modo immediate. cioe con una costante. L'operando che segue il 1/ specifica la costante. Un apostrofo indica che seguira un carattere ASCII, mentre un $ segnala un valore esadecimale. Nell'Appendicc Al t roviamo che il carattere ASCI "M" equivale a $4D; sono sernplicernente due maniere di rappresentare la stessa sequenza di bit. In questo modo le due Iinee di programma sono equivalenti: produrranno infat t i 10 stesso cod ice oggetto: A9 4D. Quale di queste due linee sara pill leggibile? Se una costante deve essere usata in un programma come un carattere ASCII, sara sicuramente meglia sct-iverfa come un carat tere ASCII.

Memorizzazione

di un registro

Proviamo adesso a memorizzare il valore contenuto nell'accumulatore in una qualsiasi locazione di memoria. Ogni locazione di memoria ha un indirizzo unico (proprio come Ie case), che varia da $0000 a $FFFF. Supponiamo di voler memorizzare il contenuto dell'accumulatore all'indirizzo $020C. Per fare questa dobbiamo usare la seguente linea di programma sorgente:

Esempio

STA $020C L'esernpio verdi assemblato in questi 3 byte di cod ice macchina: 8D OC 02. L'Appendice AS ci dice che I'opcode per STA in modo assoluto e $8D. Quando il 6502 incontra 80 sa che deve memorizzare il contenuto dell'accumulatore nell'indit-izzo specificate dai 2 byte cbe seguono. 11 modo assol uta e usa to quando si specifica un preciso indirizzo di memoria. Nell'esempio I'indirizzo potrebbe sembrare sbagliato. Sembra che l'operando specifichi I'indirizzo $OC02, perche i byte sono in questa ordine: OC seguito da 02. Ma noi vogliamo operare sul\'indirizzo $020C. C'e Forse qualcosa di sbagliato?

Prima iI byte basso


pensare che ci sia qualcosa di sbagliato nello scrivere l'indir-izzo $020C come OC seguito da 02, rna evidentemente il 6502 "pensa" in modo differente.

E. possibile

30

INTRQ!}UZIONE

ALL'ASSEMBLER

Quando scriviamo un numero siarno abituati a scrivere la cifra pill signiHcatlva per prima e la meno significative per ultima, rna il 6502 non "lavefa in questo modo. Quando la CPU incontra due byte che rappresentano un indirizzo di memoria (byte basso) interpreta il primo come parte meno significativa dell'indirizzo e il secondo come parte pill significative (byte alto). Tutti i modi di indirizzamento che richiedono un operando di 2 byte, li vogliono in quest'ordine: prima la parte meno significativa e poi la parte piu significativa. E da notare pero che non tutti gli indirizzamenti richiedono un operando di due byte.

Indlrtzzamento in pagina zero


La memoria contenuta nel calcolatore suddivisa in pagine, dove una pagina rappresenta un blocco di 256 byte consecutivi. La pagina compresa tra Ie locazioni $0000 e $OOFF viene chiamata pagina zero perche tutti gli indirizzi di questa pagina hanna it byte alto uguale a $00.- L'indirizzamento in pagina zero trae profitto proprio da questa fatto. II cod ice sorgente che fa usa dell'indirizzamento in pagina zero una volta assemblato richiedera un solo byte nell'operando proprio perche I'opcode specifica l'mdirizzamento in pagina zero e it byte alto viene sottinteso essendo sempre e comunque $00. Un indirizzo della pagina zero potra quindi essere specificato in modo assoluto a in modo pagina zero tenendo perc presente che in quest'ultimo caso I'operando sara di un solo byte. Se volete usare una locazione di pagina zero, per esempio $OOF4, potreste scrivere:

Esempio

STA $OOF4 oppure STA $F4 che assemblati darebbero, il primo: 80 F4 00 e il secondo: 85 F4. L'opcode 85 significa: memorizza l'accumulatore in pagina zero alia locazione assoluta indicata ($00F4).

INTRODUZIONE

ALL'ASSEMBLER

31

Espressioni

simboliche

Mettiamo il caso di voler trasferire valori contenuti nelle locazioni $0200, $0201 e $0202 rispettivamente nelle locazicni $0300. $0301 e $0302. Pot remmo scrivere queste linee di programma sorgente:

Esempio LOA STA LOA STA LOA STA

5 $0200 $0300 $0201 $0301 $0202 $0302

Questo programma carica alternativamente un byte nell'accumulatore e 10 scarica in un'altra locazione di memoria. Da notare il fatto che caricando un regtstro questa viene cambiato mentre non viene carnbiato il contenuto della Iocazione di memoria da cui si preleva il valore. In alternativa avremmo potuto scrivere il seguente programma che fa riferimento agli indirizzi come espressioni simboliche:

Esemplo

6 ORIGINE OESTINAZIONE LOA STA LOA STA LOA STA = $0200 = $0300 ORIGINE OESTINAZIONE ORIGINE+I OESTINAZIONE+ ORIGINE+2 OESTINAZIONE+2

Nell'esempio 6 Ie !inee I e 2 sono direttive per I'assemblatore che assegnano aile locazioni $0200 e $0300 Ie label rispettivamente di ORIGINE e DESTINAZIONE, In questa modo Ie linee che seguono possono fare riferimento a questi indirizzi per mezzo delle label 0 per mezzo di espressioni simboliche costituite dalle label e opzionalmente da costanti e operatori aritmetici. II programma sorgente dell'esempio 6, una volta assemblato, produrra 10 stesso risultato del programma sorgente dell'esempio 5; rna I'esempio 6,

r
32
INTRODUZIONE ALL'ASSEMBLER che fa uso dell'esernpio di espressioni simboliche, 5 dove gli operandi vengono risultera specificati molto pili leggibile in esadecimale.

Alcuni esercizi
1. Scrivete Ie istruzioni necessarie per caricare l'accumulatore con il valore decimale 127, per caricare iI registro X con la lettera "r" e per carrcare il registro Y con il contenuto della locazione $B092. 2. Scrivete Ie istruzioni necessarie per trasferire il contenuto della locazione $0043 nella locazione $0092.

C&plWlO

Loop e subroutine

Indirizzamento

indicizzato

Anche se funzionante, il programma dell'esempio 6 non molto efficiente poiche richiede due linee di codice sorgente per muovere ogni byte. Se dovessimo per esempio muovere 50 0 100 byte ci occorrerebbero 1000 200 linee di programma, il che non e molto conveniente. Fortunatarnente esiste un modo di indir-izzamento, chiamato indicizzato, che fa al caso nostro. In questa modo, piuttosto che specificare l'indirizzo assoluto 0 di pagina zero su cui operare, possiamo stabilire un indiritzo di base e un registro indice. II 6502 sommera iI valore contenuto nel registro Iodice all'indirizzo di base, ottenendo come risultato la locazione

dove e richiesta l'operazione. Percio, se dovessimo spostare 9 byte da una


locazione ad un'altra, potremmo registro X come indice: farlo nel modo seguente, sfruttando il

Esempio

7 ORIGINE= $0200 DESTINAZIONE=$0300

INIZIO LEGGE

LDX # 0 LDA ORIGINE,X

Pone per partire con il primo byte Legge l'Xcestmo byte dal blocco di origine

x=o

34 LOQP E SUBROUTINE

SCRIVE SOMMA TEST SALTA

STA DESTINAZIONE,X INX CPX #9 BNE LEGGE

La scrive nell'X-esima posizione del blocco di arrivo Incrementa X di un'unita per it byte successive Controlla se sono stati mossi 9 byte Se X diverso de 9 ritorna e legge iI successive

Useremo l'esempio 7 per spiegare alcune nuove ist ruzioni e modi di indirizzamento. L'esempio 7 composto da sei linee di cod ice sorgente che permettono di spostare il contenuto di nove locazioni di memoria consecutive. Se avessimo cercato di muovere questi nove byte con la tecnica illustrata negli esempi 5 e 6 sarebbero state necessarie 18 !inee di programma. Per mezzo dell'indirizzamento indicizzato. invece, abbiamo risparmiato ben 12 linee di programma; cerchiamo ora di capire corne funziona questo tipo di indirizzamento. Tutte Ie linee so no etichettate, quindi possiarno analizzarle una ad una. L'istruzione con label INIZIO carica il registro X in modo immediato con il valore o. Dopo aver eseguito questa operazione sappiamo per certo che X=O rna non sappiarno nulla circa gli altri registri. La linea LEGGE carica l'accumulatore con il valore contenuto nell'X-esima locazione di memoria a partire dall'ORIGINE, quindi, al primo passaggio da questa linea il registro X conterra 0 e I'accumulatore verra caricato con il valore contenuto nella locazione (ORIGINE+O). In ogni linea di programma sorgente, una virgola nell'operando indica che si fara usa dell'indirizzamento indicizzato; quindi, una virgola seguita da X significa che it registro X e l'Indlce dell'istruzione. Nell'indirizzamento indicizzato ci sono diversi modi. Due di questi sono indirizzamento indicituuo assoluto e indicizuuo in pagina zero. La linea LEGGE dell'esempio 7 usa I'indirizzamento indicizzato assoluto se l'ORIGINE si trova sopra la pagina zero, rna se I'ORIGINE Fosse in pagina zero si puc adoperare l'Indir-izzamento indicizzato in pagina zero che come I'indirizzamento in pagina zero richiede un solo byte nell'operando. Nell'indirizzamento indicizzato, l'operando contiene I'indirizzo di base e il 6502 operera sulla locazione che si ottiene sommando I'indirizzo di base al valore contenuto nell'Indtce (X 0 Y). II solo caso in cui it microprocessore opera sull'indirizzo di base e quando il registro indice uguale a zero; in caso contrario I'indirizzo sara una locazione di memoria piu alta. A questa punto del programma ci troviamo con I'accurnulatore che contiene iI valore della locazione ORIGINE. Nella linea SCRIVE, l'accumulatore verra scaricato nell'X-esima locazione di memoria a partire dalla

DESTINAZIONE. Poiche non abbiamo fatto nulla per cambiare it valore .: dell'lndice X, questo sara an cora uguale a e quindi I'accumulatore verscaricato proprio nella locazione DESTINAZIONE. _ Abbiamo cosi trasferito il valore dalla locazione ORIGINE alia locazione DESTINAZIONE e l'Indice ancora uguale a 0. Nella linea SOMMA, che per il momenta e Ia pili ccrta incontrata, troviamo l'Ist ruzione INX che significa INcrementa X; siccome fino a questa _ punta X era uguale a 0, adesso sara uguale a 1.

ra

L'istruzione

CMP

-Nell'esempio 7 la linea TEST campara il valore contenuto ne! registro X _:con il numero 9. Ci sana 3 istruzioni di comparazione per il 6502, una per ogni registro; CMP compara un valore con il contenuto dell'accumu"latore. CPX compara un valore can il contenuto del registro X e CPY compara un valore con il contenuto del registro Y. Possiamo usare queste istruzioni per comparare qualsiasi registro con qualsiasi valore in memoria 0, in modo immediato, per comparare un qualsiasi registro con una costante. Queste comparazioni ci permettono di controllare determinate condizioni, come nell'esempio 7 la linea TEST contralla se sono stati mossi 9 byte. Se il registro X contiene iI numero 9 vorra dire che sono stati effettuati 9 movimenti. Una istruzione di comparazione non cambia mai il contenuto di un registro 0 di una qualsiasi locazione di memoria. Percio, il registro X non subisce nessuna variazione quando il 6502 esegue la linea TEST. Ouello che potrebbe cambtare semmai sono i flag di stato del 6502.

I flag di stato
Oltre ai registri di uso comune (A. X e Y) il 6502 contiene uno speciale registra P detto anche registro di stato. I singoli bit del registro P vengono modificati ogni volta che iI 6502 esegue determinate operazioni. Questi bit sono: C Z I D bit bit bit bit 0: I: 2: 3: flag flag flag flag di Carry di Zero di Interrupt decimale

36

LOOP E SUBROUTINE

B V N

bit bit bit bit

4: 5: 6: 7:

flag non flag flag

di Break definito di Overflow negativo

In questa libro, non tratteremo l'uso di tutti i flag del regist ro P. In questa velocissrmo corso sulla programmazione in Assembler e nel software presentato piu avanti, i tre flag con cui avrerno a che fare sono C, ZeN. Un'istruzione di comparazione (eMP, CPX, CPY) non influenza iI valore contenuto nei registri A, X a Y, rna cambia 10 stato dei flag C, ZeN. Per esempio, se un registro e comparato con un valore uguale, il flag Z viene settato (I), contrariamente viene azzerato (0). Se un'Istruzione pone alii settimo bit di un registro a di un indirizzo, anche il flag N viene settato. COSt pure se un'istruzione azzera il settimo bit di un registro 0 di un indirizzo, anche il flag N viene azzerato. Similmente, operazioni matematiche e logiche settano a azzerano il flag C che si comporta come il nona bit in tutte Ie operazioni logiche e aritmetiche. La Tabella 3.1 riassume gli effetti di un'istruzione di comparazione sui registro P.

Tabella 3.1 Effetti di un'lstruzione di comparazione sui nag di stato. Notare che se si vuole testare 10 stato del flag C dopa una comparazione e necessario settarlo (usando l'istruzione SEC) prima della comparazione. Quando si testa il flag N pensate agli input come valori di 8 bit con segno Comparazione con valore uguale Cornparazione con valore maggiore Comparazione con valore minore

C~l C~O C~l

N~O N~O N~O

Z~l Z~O Z~O

Salti condizionati
Testando 10 state dei flag possiamo far compiere al programma determinate azioni piuttosto che altre. Per esempio, Ie due istruzioni BEO (Branch EQual - salta se uguale) e BNE (Branch Nor Equal - salta se diverso) fanno in modo che il 6502 salti ad eseguire nuove jstruzioni a seconda della stato del flag Z. Una istruzione che permette al 6502 di saltare in base alia stato dt un flag viene detta istrurione di salto condizionato. AItre istruzioni di salta condizionato dalJo stato dei flag sono illustrate in Tabella 3.2.

LOOP E SUBROUTINE

37

Tabella 3.2 Istruzioni di saito condizionato Flag e e N N


Z Z

Istruzione Bee BeS BPL BMI BEQ BNE BVe BVS

Descrizione salta salta salta salta salta salta salta salta se C=O se C= 1 se risultato positivo se risultato negative se uguale (Z= 1) se diverse (Z=O) se v=o se V= I

Opcode 90 BO 10 30 FO DO SO 70

V V

La linea TEST .dell'esempio 7 campara il registro X col val ore 9; questa setta 0 azzera il flag Z. La linea SALTA controllando 10 stato del flag Z ritorna alia linea LEGGE se il risultato della comparazione diverso. Se Y fosse stato uguale a 9, il risultato della comparazione sarebbe stato uguaIe e iI 6502 non sarebbe ritornato alia linea LEGGE.

Loop
L'esempio 7 viene tipicamente deuo loop. E possibile fare in modo che iI 6502 com pia una certa operazione parecchie volte, inizializzando e incrementando un contatore e test an dolo ogni volta per vedere se il lavoro finite. I loop sono molto potenti. Che cosa dovremmo aggiungere a cambiare nell'esempio 7 per fare sl che non 9, rna 90 byte vengano spostati da una locazione di memoria a un'altra? Non dovremo aggiungere niente fortunatarnente, rna semplicernente cambiare I'operando della linea TEST. Invece di comparare il registro X con iJ valore 9, dovremo comparario con 90, come si vede nell'esempio 8.

Esemplo

8 90 byte consecutivi ORIGINE = $0200 DESTINAZIONE= da una locazione ad un'altra

Come muovere

$0300

38

LOOP E SUBROUTINE

INIZIO LEGGE SCRIVE SOMMA TEST SALTA

LDX #0 LOA ORIGINE,X STA DESTINAZIONE,X INX CPX #90 BNE LEGGE

Inizializza iI registro X Legge I'X-esimo byte dal blocco di origine Scrive I'X-esimo byte nel blocco di destinazione Incrementa it registro X di 1 E il 90-esimo byte? Se non e, legge il successivo

Usando i loop possibile scrivere programmi non solo com patti, rna anche facilmente adattahili a particolari appiicazioni. In ogni caso non sarebbe possibile usare i loop senza I'indirizzamento indicizzato e i salti. I loop possono essere anche insidiosi. Dov'e l'errore nel seguente loop?

Esempio

9 ORIGINE $0200 DESTINAZIONE = $0300

INIZIO LEGGE SCRIVE TEST SALTA

LDX # 0 LDA ORIGINE,X STA DESTINAZIONE,X CPX #9 BNE LEGGE

Inizializza il registro X Legge l'Xcesimo byte dal blocco di origine Scrive I'X-esirno byte nel blocco di destinazione E il nona byte? Se non legge iI successive

e.

Esaminate attentamente l'esempio 9. In che cosa dtfferisce dall'esempio 7? Manca la linea SOMMA che incrementa il valore del registro X. Proviamo ad immaginare che cosa accade quando iI 6502 esegue il programma dell'esempio 9. Nella prima linea iI registro X e posto a 0; la seconda linea legge il byte dalla locazione $0200+ X (quindi $0200) e la terza linea 10 riscrive nella locazione $0300+ X (quindi $0300). La quarta linea cantrolla Il valore di X e torn a alia linea LEGGE poiche X=O. Alia linea LEGGE il cicio si ripetera fino al TEST, rna, poiche in questo programma non c'e nulla che incrementa il valore di X, il TEST non verra mai verificato e il loop sara senza fine. Diamo uno sguardo all'esempio 10. Ci sara un loop? E se st. sara un loop finito 0 infinito? Percbe S1 0 perche no?

LOOP E SUBROUTINE

39

Esernplo

10 ORIGINE=$0200 OESTINAZIONE=

$0300 lnizializza it registro X Legge 1'X-esimo byte dal blocco di origine Scrive l'Xcestmo byte nel blocco di destinazione Incrementa il registro X di I E it nona byte? Se non legge il successivo

INIZIO LEGGE SCRIVE SOMMA TEST SALTA

LOX #0 LOA ORIGINE,X STA OESTINAZIONE,X INX CPX #9 BNE INIZIO

e,

Indirizzamento

relativo

Tutte Ie istruzioni di saito condizionato si avvalgono dell'indirizzamento relativo. Come l'mdirizzamento in pagina zero (indicizzato e no) anche J'indirizzamento relative rlchiede un solo byte nell'operando. L'operando specifica l'indirizzo relative dell'opcode a cui il 6502 saltera se e veri ficata la condizione di test suI registro di stato. Una locazione relativa di 04 significa che l'opcode da eseguire si trova 4 byte piu avanti del successivo opcode, naturalmente se la condizione e verlficata. altrimenti iI 6502 eseguira l'opcode immediatamente successivo. Poiche I'operando di un salto condizionato lungo un solo byte, non sono ammessi salti in avanti maggiori di 127 byte e indietro maggiori di 12& byte. Si intende salto indietro quando il valore dell'operando negativo, avanti quando e positivo. Un byte e negativo se ha il settimc bit settato mentre positive se il settimo bit azzerato. Per questo motivo it valore 00 considerato positivo. Esiste poi una istruzione chiamata JMP che permette di specificare un saito incondizionato a qualsiasi locazione di memoria; sara percio possibile indirrzzare condizionatamente qualsiasi locazione di memoria, usando un saito condizionato a una locazione che contiene l'istruzione di saito incondizionato.

Salti incondizionati
Come in BASIC esiste I'istruzione GOTO che permette di saltare incondlzionatamente a una linea di programma, anche in Assembler esiste l'Istruzione JMP che permette di saltare senza condizioni a un indirizzo

40

LOOP E SUBROUTINE

specificato. E possibile far compiere al 6502 un loop infinite, semplicemente eseguendo un salta incondizionato alia locazione di inizio. Guardiamo l'esempio 1l : fino a che una linea di programma all'interno del loop non causera un saito a una locazione fuori dal loop, il 6502 continuera ad eseguire Ie istruzioni in esso contenute.

Esempio Loop

11

infinito: INIZIO aJcune istruzioni

xxxxxxxxxx xxxxxxxxxx
JMP INIZIO

Indirizzamento indiretto
Un'istruzione 1MP puc essere usata sia con I'indirizzamento assoluto che con quello indiretto. L'indirizzamento assoluto e quello usato neil'esempio II, dove l'operando rappresenta l'Indirtzzo dt memoria a cui saltare. Ma nell'indirizzamento indiretto, che si indica contenendo I'operando tra parentesi, I'operando specifica l'indtrlzzo di un punta tore. II 6502 salter-a all'indirizzo specificate dal punta tore, non al punta tore stesso. La linea JMP (puntatore) fara compiere al 6502 un salta alia locazione specificata dai byte contenuti nelle locazioni puntatare e puntatore+ 1. Percio, se punlatore=$0600 e nelle locazioni $0600 e $0601 sonc contenuti i valor i $00 e $20, ver ra eseguito un salta alla locazione $2000. (Ricordatevi che gli indirizzi sana memor-izzati can prima il byte basso).

Funzionamento dei salti


Tutte Ie istruzioni di salto, relative, assoluto 0 indiretto, influenzano il PC (Program Counter - contatore di programma). Prima che ogni istruzione di salta sia eseguita, iI PC contiene l'indirizzo dell'opcode corrente. Una istruzione di saito modifica il valore contenuto nel PC in modo cbe nel cicio macchina successivo, il 6502 non leggera I'istruzione successiva, rna quella che si trova all'indirizzo specificate dall'istruzione di salta. Dopa- un saito, l'elaborazione continua regolarmente dall'indirizzo raggiunto.

LOOP E SUBROUTINE

41

Rllocablllta
Generalmente

meglio

implementare

salti

incondizionati

come:

CLC BCC
piuttosto

LOCA
I

che:

JMP

LOCA
I

II motivo e molto semplice. II primo metoda, che fa usa dell'indirizzamento relativo piuttosto che assoluto, funzionera sempre anche quando il programma sara rilocato in altre aree di memoria. Scrivere i programmi in modo rilocabile portera certamente ad un risparmio di tempo e di problemi nel momento in cui sara necessaria spostarli in differenti aree di memoria, pur mantenendo la lora efficienza. Per rilocare in memoria il programma del secondo esempio necessaria cambiare l'operando. perche I'indirizzo assoluto LOCA sara differente, mentre it programma del primo esempio non necessita di alcun cambiamento.

Subroutine
Probabilmente Ie due istruzioni piu potenti disponibili in Assembler sono: JSR (Jump to Subtcoutine - vai alia subroutine) e RTS (ReTurn from Subroutine - ritorna dalla subroutine). Oueste istruzioni, che equivalgono

in BASIC a GOSUB e RETURN, permettono

di studiare dei blocchetti di

programma, chiamati subroutine, usabili da diversi programmi. Pensate a una subroutine come a un lavoro. Una volta insegnato al 6502 un lavoro, sara inutile spiegarglielo una seconda volta. Prendiamo per esempio un programma in cui 10 stesso lavoro deve essere eseguito parecchie volte. Dove iI programma 10 richiede, voi potete inserire Ie istruzioni per compiere il lavoro. D'altra parte, e possibile scrivere queste istruzioni, come subroutine. in una determinata area di memoria e chiamare questa subroutine dove richiesto dal programma principale. Una chiamata alia subroutine avra COSt l'effeuo di far eseguire al 6502 la subroutine e poi di ritornare al programma principale. E necessaria una sola linea di programma per chiamare una subroutine. L'istruzione JSR SUB chiamera la subroutine il cui indirizzo SUB (come se Fosse un salro incondizionato), il 6502 leggera ed eseguira Ie istru-

aionkcontenute nelle locazioni successive alia SUB fino a che non inconun RTS. Quando viene letta l'istruzione RTS verdi attuato un saito di ritorno al programma chiamante e quindi all'istruzione immediatamente successiva alia JSR. In pratica. quando una linea di programma chiama una subroutine, il 6502 ricorda dove si trovava prima del saito e quindi, quando viene incontrata l'istruzione RTS, il 6502 sa dove tornare proprio perche si ricorda I'indirizzo da dove e partite. La Figura 3.1 illustra questa procedimento. Notate che la stessa subroutine puc essere chiamata da punti different! dello stesso programma e, immancabilmente, tornera al punto di chiamata. Le subroutine permettono di strutturare i programmi. II vantaggio del software strutturato e quello di poter modificare parecchi programmi semplicemente cambfando una subroutine. Se, per esempio, tutti i programmi fanno uso della stessa subroutine di stampa, ogni volta che questa subroutine verra migliorata, sara migliore anche il comport amen to di tutti i programmi che la usano. Inoltre e molto pill facile modificare dei dati in un posto solo piuttosto che doverne modificare parecchi in posti different! e normalmente non chiaramente documentati. Questo il motivo per cui tutti i programmi presentati in questa libro fanno ampiarnente uso di subroutine.

trera

Programma principale

Saito alia subroutine

Chiamata della subroutine

Aitorno dalla subroutine

Figura 3.1 Saito e ritorno da una subroutine. Quando il microprocessore incontra una JSR, esegue la prima istruzione della subroutine. La subroutine SUB viene chiamata dal programma principale. L'ultirna istruzione di una subroutine deve essere RTS che rende iI controllo al\'istruzione irnrnediatamente seguente la chiamata. La suo broutine SUB puc essere chiamata da qualsiasi punta del programma dove e necessaria la particolare funztone che svolge

LOOP E SUBROUTINE

43

Subroutine

fittizie

Una subroutine fittizia non contiene altro che un'istruzione RTS. Una chiamata a una subroutine fittizia non modifichera nulla perche il 6502 ritornera immediatamente al programma principale con i registri intatti. La ragione di una chiamata a una subroutine fittizia quella di fornire un aggancio usabile in un secondo tempo per sostituire alia subroutine fittizia quell a effettiva. Nella sviluppare un programma sara possibile inserire delle chiamate alia subroutine fittizia e in seguito. dopo avere generato Ie subroutine necessarie, sostituire I'indirizzo della subroutine fittizia con quello della subroutine effettiva. Cercare di inserire una chiamata in un programma che non prevede questi agganci vi potrebbe far sognare un "calzascarpe per memoria" che permettesse di inserire 3 byte extra di programma nella stessa area di memoria.

Lo stack
Oltre ai modi di indirizzamento che permettono al 6502 di accedere alia memoria, esiste un modo che permette al 6502 I'accesso a una par-ticolare area di memoria, lunga 256 byte, chiamata stack (catasta). Possiamo irnmaginare 10 stack come una pita di mat toni. L'unico modo posslbile di aggiungere un mattone alia pila quello di posarlo sopra tutti gli altri come pure per prenderne uno dovremo partire dal piu alto. Questo metodo viene comunemente detto LIFO (Last In First Out - I'ultlrno che entra e il prime a uscire). L'ultimo mattone posto sulla pila sara il primo ad essere rimosso. Nel nostro caso chiameremo push l'operazione corrispondente a porre un mattone sulla pila e pop l'operazione corr'ispondente a toglierne uno. L'ultimo elemento della pila il top (cima) dello stack. Pensiamo, per esempio, di porre due byte sullo stack (ogni byte ha un valore di 8 bit, Forse un numero 0 un carattere ASCII; vedi Figura 3.2a). Per prima cosa eseguiremo un push del primo byte, come si vede in Figura 3.2b. Tutte Ie locazioni sopra iI primo byte vengono dette "vuote" e il primo byte la cima dello stack. Ora facciamo un push nello stack con i1 secondo byte (Figura 3.2c). Cosa e successo? II secondo byte adesso e la cima dello stack mentre il primo byte e ugualmente contenuto nello stack. Se togliamo il secondo byte dal10 stack, eseguiamo un pop (Figura 3.2d). II primo byte adesso di nuovo la cima della stack. Un altro pop togliera anche it primo byte lasciando 10 stack completamente vuoto. Notate che stato necessario levare il secondo byte prima di poter togliere anche i] primo. Ouesto it procedimento chiamato LIFO.

44

LOOP

E SUBROUTINE

aJ 256 byte

"

'---.---J 1 byte

cl

dJ

Stack

Stack

Figura 3.2 L'uso di push e pop

L'i st ruzione PHA ([Link] A) permette di inserire il valore dell'accumulatore nello stack, mentre I'istruzione PLA (Pop and Load AccumulaTor) perrnette di caricare l'accumulatore con i] valore contenuto nella cima della stack. L'istruzione PHP (PusH P) permette di trasferire il registro P nello stack, mentre la funzione contraria viene svolta dall'istruzione PLP (Pop Load p). Lo stack e un'area di memoria molto pratica quando si presenta la necessite di memorizzare temporaneamenle aleuni byte, senza dover ricorrere all'uso di locazioni assolute. Le subroutine possono trasferire i dati ai programmi principal! per mezzo della stack rna, se una subroutine scrive dei dati nello stack e poi falltsce nella lettura dl quei dati prima dell'RTS, non avverra i] ritorno al programma chiamante.

LOOP E SUBROUTINE 45

Questa avviene perche il 6502, quando incontra una JSR, memorizza l'indirizzo a cui tornare proprio nello stack. Una subroutine puc tornare al programma principale solo perche l'indi rizzo di rttorno memorizzato nello stack e, se questa indirizzo non si trova in eima alia stack quando viene eseguita I'Istruzione RTS, la subroutine non tornera al programma chiamante. COS! nelle subroutine sara sempre necessaria resettare 10 stack prima di incontrare l'RTS.

Capitola

Aritmetica e logica

4
e

Transcodifica del caratteri


Come dimostrato nell'esempio 7, l'Indir'izzamento indicizzato utile quando si deve compiere una determinata operazione, come ad esempio un trasferimento su una serie contigua di byte. Esiste perc un'altra importante operazione che possibile compiere e riguarda Ie tabelle di confronto. Diciamo. per esempio, che voi e un vostro arnica avete deciso di inviarvi dei messaggi usando un codice di sostituzione. Ad ogni numero, lettera 0 segno di interpunzione, vi siete accordati di sostituire un carattere differente; una "A" sara sostituita con una "R", un ":" con un "9", ecc. Sia voi che il vostro arnica avete una tabella che riporta per ogni carattere it corrispondente da sostituire. Quando scrivete un rnessaggio, quindi, 10 transcodificate usando la tabella e 10 inviate al vostro arnico. Chiunque verra in possesso del messaggio difficilmente sara in grado di cornprenderne il contenuto, rna it vostro amico, facendo usa della tabella. riuscira a decodificarlo. Molto spesso i prograrnrni r-ichiedono una decodifica per i caratteri ed e posslbile compiere questa lavoro sfruttando Ie tabelle di codifica/decodifica.

48

ARITMETICA E LOGICA

Esempio Subroutine

12 di transcodifica TAX Usa il carattere da transcodificare come indice della tabella Legge nella tabella il valore corr-ispondente Ritorna al programma principale A contiene il carattere t ranscodificato X contienc il carattere originale

TRANS

LDA TABELLA,X RTS

Trasferimento

dei registri

La subroutine TRANS, nell'esempio 12, assume chc il byte da t ranscodificare sia contenuto nell'accumulatore. Questa byte puc esscre una lettera. un numero, un segno d'interpunzione, un codice di controllo, un curut tere graflco. rna in ogni casu sara un valore di otto bit. La prima linea d i TRANS sposta il valore dell'accurnulatore ncl registro X per mezzo dell'istruzione TAX. Le istruzioni di trasferimento interagiscono solo con i registri e in nessun modo possono modificare la memoria indirizzabile. Oueste istruzioni permettono di trasferire un valore da un regis! 1'0 ad un altro. Dopo avere effettuato una operazione di trasfertmento. il registro di partenza restera inalterato, mentre quello di arrive conterra 10 stesso valore del registro di partenza. Le istruzioni di trasferimento sono: TAX TAY TXA TYA trasferisce trasferisce trasferisce trasferisce A A X Y in in in in X Y A A

II trasferimento dei registri modifica i flag NeZ. Queste istruzioni permettono di trasferire valori dall'accumulatore ai registri X 0 Y oppure di trasferire il valore contenuto nei registri X 0 Y all'accumulatore. Come faremo a t rasferire un valore da X a Y 0 viceversa? (Suggerimento: occorrono due linee di programma e ogni linea contiene un'istruzione elencat a qui sopra).

ARITMETICA E LOGICA

49

Tabelle di transcodifica
La seconda linea dell'esempio 12 e quella che si occupa della transcodifica cercando il dato richiesto nella tabella. La TABELLA contiene l'Indirizzo di base di una tabella che abbiarno preventivamente introdotto in memoria. L'indirizzamento indicizzato permette di leggere l'Xcesimo .byte a par-tire dall'indirizzo di base (cioe I'X-esimo byte della tabella). Una volta eseguita questa operazione, la ricerca e finita; il 6502 contiene nell'accumulatore l'Xcesimo byte della tabella e deve solo ritornare al programma principale. Questa si ottiene con la terza linea della subroutine che non pub essere altro che un RTS. A questa pun to possibile ottenere una transcodifica all'interno del programma principale semplicemente eseguendo:
I

JSR TRANS L'uso delle tabelle di transcodifica permette di avere programmi malta flessibili. Se un programma fa usa di tabelle e si vogliono ottenere funzioni differenti, sara probabilmente necessar-io cambiare solo i valori delle tabelle. Le tabelle sono veloci e flessibili, rna presentano uno svantaggio. Infatti. possiamo avere tutte [e tabelle necessarie per permettere alia macchina di cercare la risposta voluta direttamente in memoria, rna se la memoria non sufficiente, il computer sara costretto a calcolarsi Ie risposte.

I
I

Operazioni

aritmetiche
Ie seguenti operazioni aritmetiche a 8 bit:

II 6502 puc eseguire traslazione (shifl) rotazione (rotate) incremento decremento somma sottrazione

I
I

Per comprendere piu factlrnente Ie operazioni che il 6502 com pie su di un byte necessario pensare allo stato dei singoli bit di quel byte. Anche se il byte rappresenta un numero 0 una lettera, non pensate a quello che potreste fare con quel numero 0 letter-a. rna pensate alia configurazione dei bit. Cosa possiamo combinare con i bit?

50

ARITMETICA E LOGICA

TRASLAZIONE

Eo possibile traslare i bit che compongono un byte di una posizione a sinistra 0 a destra. L'istruzione ASL (Arithmetic Shift Left - traslazione aritmetica a sinistral manipola un byte muovendo ogni bit a sinistra di una posizione. II bit pill a sinistra (bit 7) viene trasferito nel Carry (flag C) e il bit pill a destra viene azzerato come si vede in Figura 4.1.
Bit

crfillillt4\
7 6 5 4 11 2 1

Figura 4.1 Effetto dell'istruzione ASL Prendiamo, figurazione: TMP per esempio, un byte alia locazione TMP con la seguente con-

01010110 ASL TMP il byte avra questa 0 1 0 1 1 0 0 piu a siniiI byte diconfigurazione:

Dopo un'Istruzione TMP 1

con it flag C (Carry) contenente 10 stato del bit che si trovava stra (nel nostro casal. Se eseguiamo aneora la stessa istruzione ventera: TMP e il flag C sara 01011000 settato a 1.
Bit

rftfttttth
7 6

"

;,

Figura 4.2 Effetto dell'istruzione LSR

ARITMETICA E -LOGICA

51

L'istruzione LSR (Logical Shift Righi - traslazione logica a destr'a) ha esattamente l'effetto 'contrario. Tutti i bit vengono t raslati a destra verso il flag Ceil bit a sinistra viene settato a O. Questo processo illustrato in Figura 4.2. Se teniamo corne esempio Il byte alta locazione TMP con la configu razione data in origine, dopo un'istruzione LSR TMP il dato si presenter-a COS!:

TMP

con il flag C che rispecchia 10 state del bit che stava piu a destra, nel nostro case O. Se la stessa istruzione viene eseguita di nuovo, il dato diventera: TMP 0 0 0 I 0 I 0 1

e it flag C sara posta a 1. Poiche in binario abbiamo la rappresentazione di un numero (ogni bit rappresenta una potenza success iva del 2), alcune operazioni aritmetiche diventano moho semplici. Per dividere un byte per due sara sufficiente traslare a destra. mentre per moltiplicare il valore in un byte per due sara necessario ope rare una traslazione a sinistra. ROTAZIONE E possibile anche ruotare i bit di un byte a sinistra 0 a destra attraverso if flag C. Diversamente dalla traslazione, la rotazione conserva tutte Ie informazioni originaimente con ten ute nel byte. La Figura 4.3 mostra il funzionamento dell'istruzione ROL (ROtate Lehrotazione a sinistra). Per esernpio, consideriamo il byte della locazione TMP come negli esempi precedenti e diciamo che iI flag C e settato (C=I): TMP

o
1 6

o
S

0
Bit

~liiiiij)
Figura 4.3 Effetto dell'istruzione ROL

52

ARITMETICA E LOGICA

Dopo I'istruzione TMP I

ROL, TMP il byte diventa: 0 I 0 I I 0 I

e it flag C verra posto alia stato del bit piu a sinistr-a. Nel nostro caso. C sara a 0 e iI bit sara a 1. A parte questa comportamento di C e del bit 0 tutto il resto molto simile all'istruzione ASL. Dopa aver eseguito una seconda volta un'istruzione ROL TMP il byte si presentera COS!:

TMP

e C sara a 1. In un'istruzione ROL il bit 0 assume sempre to stesso valore di C (mentre can ASL iI bit 0 viene sempre azzerato). Se Fosse stata eseguita una istruzione ASL qua Ie sarebbe stata la configurazione del bit di TMP? La Figura 4.4 mostra il funzionamento dell'istruzione ROR (ROtate Righirotazione a destra). Questa istruzione simile alia ROL; 1a differenza sta nel fatto che il bit 7 viene seuato da C e C viene senate dal bit O.

Bit
7 6 5 " 3 2 1 0

Figura 4.4 Effetto dell'istruzione

ROR

Ruotando un byte a destra a a sinistra nove volte consecutive otterrerno corne risultato 10 stesso byte di partenza. Traslando invece un byte nove volte di seguito ci ritrovererno con un byte completamente azzerato, cioe can niente.

INCREMENTO

E DECREMENTO

incrementare 0 decrementare un byte in tre modi differenti: usando Ie istruzioni INC e DEC quando si opera su una locazione di memoria, usando INX e DEX quando si opera sui registro X e can INY e DEY quando si opera sui registro Y. Nessuna di queste istruzioni rnodifica il flag C, mentre viene ad essere influenzato il flag Z. Z viene settato

E. possibile

ARITMETICA E LOGICA

53

se il risultato dell'operazione di incremento 0 decremento zero, mentre viene azzerato se l'operazione da come risultato un valore diverse da zeroo II flag N viene settato se il byte ri sul tante dopo un incremento 0 decremento ha il bit 7 a I; altrimenti N viene azzerato. E da notat-e che se si incontra un registro 0 un byte il cui valore $FF, il risultato sara $00. Similmente se si decrementa un registro 0 un byte di valore $00 il risultato sara $FF. Non e possibile incrementare 0 decrementare I'accumulatore, rna e possibile sommargli 0 sottrargli un byte.

SOMMA L'esempic 13 mostra come nella locazione NUMERO: sommare all'accumulatore il byte contenuto

I
I

Esempio

13 Azzera il flag C Somma all'accumulatore locazione NUMERO

CLC ADCNUMERO

il byte contenuto

nella

Dopo l'esecuzione di queste istruzioni, I'accumulatore con terra 'gli otto bit bassi del risultato della somma. Se, a seguito della somma, il flag C viene settato, significa che il risultato e un valore maggiore di 255; se il flag C resta a zero, il risultato della somma un valore minore di 256, e percio l'accumulatore contiene i] vero r-isultato dell'operazione. E sempre necessario azzerare il nag C prima di esegui re I'istruzione ADC (ADd with Carry - somma con i] r-iporto].

SOTTRAZIONE La sottrazione un'operazione facile come la somma. Per sottrarre un byte dall'accumulatore, prima di tutto necessario settare il flag C con l'Ist ruzione SEC (SEt Carry - setta C) e poi sottrarre dall'accumulatore una costante 0 i1 valore contenuto in una locazione di memoria, per mezzo dell'istruzione SBC (SuBtract with Carry - sottrae con il riporto):

I
e c
I

SEC SBCOPER

Setta C Sottrae dall'accumulatore nella locazione OPER

il valore

contenuto

54

ARITMETICA E LOGlCA

Se iI valore dell'operando maggiore del valore contenuto nefl'accumulatore, il flag C viene azzerato altrimenti resta settato. In ogni caso l'accumulatore con terra il risultato a 8 bit. Ricapitolando, dobbiamo set tare C prima di sottrarre e azzerar-lo prima di somrriare. Se il flag C non cambia di stato, I'accurnulatore contiene il risultato completo dell'operazione; rna se avviene un cambiamento di stato allora significa che il risultato e maggiore di 255 (per I'addizione) e minore di 0 (per la sottrazione).

Modo decimale
II registro di state, P, contiene un bit chiamato flag decimale. Se questa flag settato, it 6502 esegue Ie addizioni e Ie sottrazioni in modo decimale. altrimenti in modo binario. Operare in modo decimale stgnifica che i byte sana trattati in BCD (Binary Coded Decimal - decimale codificato binario) e che i 4 bit bassi possono rappresentare un valore compreso tra 0 e 9 come pure i 4 bit alti. Nessun nybble (4 bit) puc contenere valori compresi tra A ed F; quindi ogni nybble rappresenta un numero decimale. Le istruzioni SED (SEt Decimal - setta D) e CLD (CLear Decimal - azzera D) sana usate rispettivamente per settare e azzerare il flag decimale. Noterete che tutto iI software presentato in questa libra non fa usa del modo decimale. II valore decimale 255 il numero pill grande che siamo in grado di rappresentare in BCD, rna il numero 99 e il valore pili grande rappresentabiIe da un byte in BCD.

Operazioni logiche
Come si puc cambiare 10 stato di un singolo bit in un byte senza alterare 10 stato degli altri? Situazioni di questa genere sono usuali durante Ie operazioni di 110, e possono essere svolte per mezzo delle istruzioni ORA, AND e XOR.

SETTARE

I BIT

L'istruzione ORA ci permette di settare uno 0 pili bit dell'accumulatore senza influenzare 10 stato degli altri. ORA esegue I'operazione logica OR tra l'accumulatore e un byte specificato detto anche maschera. II bit n dell'accumularore sara settato se e inizialmente settato oppure se 10 e iI bit n della maschera oppure ancora se entrambi i bit n sono settati. M';::!1_"

ARITMETICA E LOGICA

55

tre il bit n sara azzerato solo se entrambi i bit n dell'accumulatore e della maschera saranno azzerati. La Tabella 4.1 rappresenta la tabella della verita dell'operazione logica OR. Una tabella della vet-ita ci da tutte Ie possibili combinazioni di due bit su cui si puc operare e il risultato dell'operazione che si compie (in questa caso OR).

Tabella 4.1 Tabella della verita dell'operando


Bit 1

OR

Bit 2 OR OR OR OR

Risultato

Supponiamo per esempio di eseguire l'Istruzione ORA # $80. In questa caso la maschera $80, rappresentabile anche come 10000000. Questa istruzione settera il bit 7 dell'accumulatore lasciando inalterato 10 stato degli altri bit. Quindi, se I'accumulatore prima dell'operazione conteneva it valore 00010010, dopo l'cperazione conterra 10010010. Un altro esempio potrebbe essere ORA # 3. Poiche il valore decimale 3 viene convertito nella maschera binaria 00000011 ne deduciamo che l'operazione setter-a i due bit bassi dell'accumulatore lasciando inalterati i bit da 2 a 7. Che valore dovremo scegliere per settare il nybble alto dell'accumulatore? E per quello basso?

AZZERARE

I BIT

Usando l'istruzione AND e possibile azzerare uno 0 pili bit dell'accumulatore senza alterare 10 stato degli altri. AND compie I'operazione logica AND tra l'accumulatore e un byte di maschera specificato nell'operando. L'istruzione AND settera it bit n dell'accumulatore solo se il bit n dell'accumulatore settato e se 10 pure it bit n della maschera. Se it bit n dell'accumulatore e azzerato 0 se 10 il hit n della maschera, allora, dopo l'operazione, il bit n dell'accumulatore sara azzerato. La Tabella 4.2 la tabella della verite dell'operazione logica AND. Per esempio, l'Istruzione AND # 1 azzerera tutti i bit dell'accumulatore eecetto il bit 1 che restera invariato. AND # $FO azzerera il nybble basso dell'accumulatore lasciando inalterato quello alto. Scegliendo la masche-

56

ARiTMETICA E LOGICA

Tabella 4.2 Tabella della


Bitt

verna dell'operando
Rlsultato

AND

Bit 2 AND AND AND AND

fa giusta, sara dell'accumulatore

quindi possibile azzerare qualsiasi senza influenzare gli altri.

bit

gruppo

di bit

COMMUTARE

I BIT

L'istruzione XOR, OR esclusivo, permette di commutare uno 0 piu bit dell'accumulatore lasciando inalterati gli altri. Compiendo uno XOR setteremo il bit n dell'accumulatore se il bit n dell'accumulatore e settato e se il bit n della maschera azzerato 0 viceversa. II bit n verdi azzerato se ha 10 stesso stato sia nell'accumulatore che nella maschera. La Tabella 4.3 e la tabella della verf ta dell'operazione XOR.

Tabella 4.3 Tabella della verita dell'operando


Bitt 8H2

XOR (OR esclusivo)

Risuitato

XOR XOR XOR XOR

Per commutare it hit n dell'accumulatore sufficiente compiere uno XOR fra I'accumulatore e una maschera che ha solo il bit n settato. II bit n dell'accumulatore cambiera stato. Le operazioni logiche, in congiunzione con Ie istruzioni di saito relativo, rendono possibile la decisione delle operazioni da eseguire testando 10 stato di un singolo bit in memoria. Supponiamo per esempio, che sia necessario che it programma compia determinate operazioni (operazione A) se it bit 6 di un byte alia locazione FLAG e settato e compia altre operazioni (operazione B) se il bit azzerato. L'esempio 14 mostra it modo di controllare 10 stato del bit 6 di FLAG pur mantenendo it byte inalterato.

ARITMETICA E LOGICA

57

Esempio

14 LDA FLAG AND #$40 BEQAZIONB Legge iI byte FLAG Azzera tutti i bit tranne

il 6

AZIONA xxxxxxxxx

Esegue l'azione settato

A perche

il bit 6

AZIONB

yyyyyyyyy yyyyyyyyy

Esegue l'azrone azzerato

B perche

iI hit 6

Facciamo ora un esempio sull'utilita del flag. In America sulle cassette postali situate davant! a ogni villetta c'e una bandierina di lamiera che puc essere sollevata se c'e posta da prelevare 0 abbassata se non c'e posta. Va spiegato che nell'immensa provincia americana dove Ie abitazioni sono moho disperse sui terri to ria, il servizio postale prevede anche il ritiro a domicilio della posta in partenza. L'azione di alzare 0 abbassare questa bandierina non richiede molta fatica, e permette al postino di compiere il suo giro pili velocemente, vista che ad ogni cassetta non dovra scendere dal furgone per controllare la presenza 0 meno della posta. L'uso di questa semplice indicatore, che Iunaicna esattamente come i flag nei linguaggi di programmazione. ottimizza immensamente il servizio. II tran-tran del postino a tutti gli effetti, un esempio di programmazione molto sofisticata. Proviamo a pensare al postino come ad una persona che segue scrupolosamente un programma e analizziamo tutti i vantaggi offerti dall'uso dei flag. II "programma" postino si divide in due parti distinte: il lavoro che deve essere fatto in ufficio e il lavoro che deve essere fatto per strada. In ufficio il postino mette in ordine Ie varie lettere e Ie divide in sacchi destinati aile varie zone della citta. L'ordinamento che avviene in ufficio permette al postino di compiere il suo giro pill velocemente, senza dover ulteriormente, una volta sulla strada, fare ricerche 0 selezioni. Nella seconcla parte del "programma" del postino abbiamo tutte Ie operazioni che devono essere compiute sulla strada. II postino carica la posta da distrtbuire sui furgone e comincia il suo giro. Guidando per la strada vede una cassetta delle lettere e pensa: pasta per Ie persone che abitano qui? Se la risposta affermativa, il postino si ferma e inserisce la posta nella cassetta, rna cosa accade se non c'e posta per quell'indirizzo? E necessaria fermarsi 0 proseguire per il prossimo indirizzo? II postino guarda meglio la cassetta. Come la bandierina? Se gill allo-

e,

c'e

58 ARlTMETICA E LOGICA

ra non c'e posta da ritirare e quindi puc proseguire, altrimenti e cost retto a fennarsi per r-itirare la posta in partenza. Un flag non alt rc che un'informazione fornita da un singolo bit rna, interpretando 10 stato di numerosi flag, perfino un semplice programma in grade di fronteggiare situazioni assai complesse. Se il vostro computer dispone di 8000 byte di memoria significa che cl sono 64000 bit di memoria. Sarebbe quindi possibile usare gran parte di questi bit come flag, per esempio simulando la presenza della posta in partenza in una comunita di oltre 50000 individui. Comunque, non avete comperato un computer per giocare al postino e a questa punto avete abbastanza conoscenze per pater seguire e capire i programmi che saranno presentati nei capitoli successivi. Questi programmi includono vari esempi per tutte Ie istruzioni e Ie teen iche di programmazione presentate in questa rapidissimo corso di linguaggio Assembler. II software contenuto nei prossimi capitoli vi fornira inoltre alcuni strumenti utili allo sviluppo del vostr-i programmi. Un'ultima informazione prima di passare aile applicazioni pratiche: esiste un'istruzione che non provoca nulla; I'istruzione NOP (NO operation -nessuna operazione). Quale il motivo di un'istruzione del genere? Occasionalmente puc capitare di dover sostituire un'Istruzione non voluta con una fittizia. Quando volete annullare parti di un programma senza dover10 riscrivere completamente potete cambiare Ie istruzioni nan volute con dei NOP che vengono rappresentati in memoria come SEA.

capitulo

Utility per la gestione della scherma

Pensiamo ora a come visualizzare qualcosa sullo schermo. Nel C-64 e nel VIC·20 il circuito video scandisce una particolare area di memoria chiamata memoria video. Ogni indirizzo della memoria video rappresenta una posizione sullo schermo (da qui la definizione video mappato in memoria). Per ogni carattere contenuto nella memoria video il circuito di gestione visualizza iI corrispondente carattere in una determinata posizione sullo schermo. Per visualizzare un carattere sullo schermo, sara quindi necessaria memorizzare il carattere desiderata nella memoria video e nella particolare locazione che corrisponde alia posizione di schermo. Per conoscere l'Indir-izzo corrispondente a una determinata posizione sullo schermo bisogna consultare la mappa della memoria video. Le Appendici Bl e B2 contengono Ie mappe della memoria video del C-64 e del VIC-20. E da notare che sistemi differenti avranno differenti locazioni per la stessa posizione fisica sullo schermo. Piuttosto che indirizzare la memoria video in maniera assoluta, sarebbe piu pratico indirizzarla in maniera indiretta, come se avessimo una freecia controllata via software in grado di spostarsi e indicare tutte Ie posizioni del video. Potremmo cosi individuare un carattere con la freccia, muoverlo e posizionarlo dove vogliamo, senza essere legati alia sua postzione assoluta. Una cosa del genere e facilmente implementabile usando un puntatore in pagina zero.

60

UTILITY PER LA GESTIONE

DELLO SCHERMO

Puntatori
Un puntatore non altro che una coppia di byte consecutivi in memoria. Poiche un byte formato da 8 bit, un puntatore e formato cia 16 bit, il che significa che un contatore puc specificare una delle 65536 (=2L6) differenti locazioni di memoria. Un punta tore puc specificare, 0 meglio puntare, solo un indirizzo alia volta. II byte basso di un puntatore contiene gli 8 bit meno significativi (LSB) dell'indirizzo, mentre it byte alto contiene gli 8 bit piu significativi (MSB) dell'indirizzo che specifica. Ad esempio, se vogliamo un punta tore alIa locazione $1000, dobbiamo riservare 2 byte per iI punta tore, il che significa occupare i byte aile locazioni $1000 e $1001. $1000 con terr. il byte basso e $1001 quello alto. Se, per esempio, vogliamo che questa puntatore specifichi l'indirizzo $ABCD, dobbiamo fare come segue:

PUNTA=$1000

LDA #$CD STA PUNTA LDA #$AB STAPUNTA+I

A9 8D A9 8D

CD 00 AB 01

10 10

Questa istruzione segna alia label $1000 Setta il byte basso Setta u byte alto

dell'Assembler asPUNTA il valore

Adesso PUNTA specifica l'indirizzo $ABCD. Anche se un punta tore puc essere dovunque in memoria, e particolarmente potente quando si trova in pagina zero (gli indirizzi compresi da $0000 a $OOFF). II modo di indirizzamento indiretto permette a un puntatore in pagina zero di specificare l'mdir'izzo in cui certe operazioni devono essere svolte. Un puntatore in pagina zero deve essere situato ovviamente in pagina zero, rna puc specificare qualsias! locazione di memoria. Per esemplo, un puntatore in pagina zero puc essere usato per specificare gli indirizzi in cui i dati saranno memorizzati. Poiche la memoria video come qualsiasi altra memoria ad accesso casuale, possiamo implemen tare la nostra freccia come un puntatore in pagina zero.

[Link]
Quello che ci occorre un puntatore in pagina zero che punti ad una particolare locazione della schermo. Quando vorremo esaminare 0 modi ficare il contenuto del video 10 faremo attraverso questo punta tore che chiameremo [Link].

UTILITY PER LA GESTIONE DELLO SCHERMO

61

Siccome sia il C-64 che il VIC-20 non fanno usa delle locazioni comprese tra $OOFB e $OOFE, faremo uso, per il nostro [Link], delle locazioni $OOFB e $OOFC. Questa sara possibile con la seguente istruzione Assembler: [Link]=$FB

[Link]
II puntatore [Link] visualizzare qualcosa ricare J'accumulatore gramma: LDY #0 STA ([Link]),Y delermina la locazione corrente sullo schermo. Per nell'anuale posizione occorrera semplicemente cacon un byte ed esegui re Ie seguenti linee di pro-

AD 91

00 FB

Questa procedura ci permette di visualizzare qualcosa sullo schermo, rna cosa dovremo fare per visualizzare un dato carattere? II cod ice ASCII di un carattere non e necessariamente uguale al cod ice video usa to per rappresentarlo sullo schermo. Per visualizzare una "Alt non possiamo sernplicemente caricare l'accumulatore con iI cod ice ASCII della A (che $41) ed eseguire Ie linee riportate pili sopra. perche iI simbolo "A" ha un differerue cod ice video sui C-64. Come si puc, allora, visualizzare un certo carattere ASCII? Cio e possibiIe assumendo che esista una subroutine, chiamata FIXCAR, che trasformi ogni carattere del codice ASCII nel corrispondente codice video. FIXCAR sara naturalmerue differente da computer a computer e non questo il luogo per entrare in ulteriori dettagli (vedere Ie appendicl relative al vostro computer per il listato e la spiegazione di FIXCAR). Diamo per scontato che esista la subroutine FIXCAR e che se viene chiamata dal programma principale can il carattere ASCII contenuto nell'accumulatore, ci restituisca iI corrispondente cod ice video sempre nell'accumulatore. Prima potevamo visualizzare un'immagine sullo schermo; can FIXCAR adesso siamo in grado di vtsualizzare il carattere ASCII che ci intercssa. Siccome questa necessita si presentera molto spesso, svilupperemo qui di seguitc, una subroutine, [Link], che ci permettera di scrivere i caratteri sullo schermo:

[Link]

JSR FIXCAR LDY #0 STA ([Link]),Y RTS

Converte iI carattere ASCII nel codice usa to dal sistema Visualizza il carattere nella posizione corrente

62

UTILITY PER LA GESTIONE

DELLO SCHERMO

La posizione sullo schermo


Questi esempi che ci permettono di modificare ed esaminare 10 scherrno
funzionano essere certi solo se il puntatore che [Link] indirizzi [Link] punta realmente a queste posizioi programmi degli esempi, dovremo alia locazione desiderata della memoria

ni. Percio. prima di far funzionare video.


Ci sono scrivere

parecchi sistemi per ottenere questa rtsultato. Se vi interessa un programma specificc per un solo tipo di computer, 0 su piu

modelli che hanno la memoria video mappata alia stessa maniera, sara
possibile usare l'indirizzamento immediato per far SI che [Link] punti un determinato indirizzo della memoria video. Diciamo. per esempio, di voler settare [Link] in maniera che indirizzi la terza colonna della quarta riga (contando a destra e verso it basso da un'origine situata nell'ango10 superiore sinistro della schermo). Se siete in possesso di un VIC-20 provvisto dell'espansione ad SK, consultando Ia documentazione troverete che l'indirizzo $1044 della memoria video corrisponde alia posizione che ci interessa. $10 il byte alto e $44 quello basso; sara quindi possibiIe predisporre [Link] con Ie seguenti linee di codice:

lOA STA lOA STA

#$44 [Link] #$10 [Link]

A9 A9

44 10

Setta

il

8S FB byte basso

+ 1 8S Fe

Setta u byte alto

Queste istruzioni vengono eseguite velocemente ed hanno I'Indubbto vantaggio della rilocabthta: rna non e molto conveniente dover accedere ad un indir'izzo della memoria video ogni volta che si presenta la necesstta di visualizzare qualcosa. Sarebbe molto piu praticc poter indirizzare 10 schermo come una coppia di coordinate X e Y. Perche non creare una subroutine che, prendendo le coordinate X e Y, inizializzi per noi [Link]?

TVTOXY
TVTOXY e una subroutine che inizializza it puntatore [Link] in modo che punti alla posizione del video Ie cui coordinate X e Y sono contenute nei registri X e Y. (Notate che la numerazione delle righe e delle colonne parte da zero). Affmche [Link] punti alia terza colonna da sinistra e alia quinta riga dall'alto occorre Includere nel programma prmcipale le seguenti linee:

UTILITY PER LA GESTIONE

DELLO SCHERMO

63

LDY #4 JSR TVTOXY

La prima colonna la zero, la seconda la uno, la terza la due, ecc. La prima riga la zero, la seconda la uno e COSt via Setta [Link] alla posizione di coordinate XeY con ten ute nei registri X e Y

Con quale logic a funzionera la subroutine TVTOXY? Potremmo memorizzare una tabella dove cereare I'indirizzo desiderata. Un computer puc svolgere questa lavoro molto velocemente, rna la velocita non vale iI sacrificio della quantita di memoria richiesta da una simile procedura. Se non ci interessa aspettare un po' di tempo in pill, possiamo fare in modo che TVTOXY calcoli il valore da passare a [Link]. Come possibile calcolare l'mdir-izzo di una data posizione X,Y sullo schermo? Sara necessario conoscere Ie seguenti informazioni:

HOME
RIGINC

L'indirizzo in memoria del punto che si trova nella riga zero e colonna zero (doe I'indirizzo pili basso della memoria video) Incremento di riga: la differenza degli indirizzi tra una riga e la successiva i valori di HOME e RIGINC posizione X,Y:

Conoscendo di qualsiasi

possibile

caicolare

I'indirizzo

+registro +(registro

HOME

X y). RIGINC

indirizzo della posizione +coordinata X +(coordinata Y).RIGINC indirizzo della posizione

0,0

[Link]

X, Y

Provate a calcolare l'indirizzo di qualche posizione schermo e comparate il risultato con quello fornito dalla tabella della memoria video del vostro computer (ricordatevi che contiamo Ie righe e Ie colonne partendo da zero, non da uno). A questa punto se la subroutine TVTOXY esegue questi caicoli, non sara pili necessaria cercare gli indirizzi nella tabella e potremo scrivere it programma per il video in termini di coordinate cartesiane. Eseguendo solamente questi calcoli, perc. la routine non perfettamente funzionale; infatti, cosa succederebbe se il contenuto del registra Y Fosse maggiore del numero di righe visualizzabili? [Link] punterebbe ad una locazione esterna all'area di memoria video e TVTOXY memorizzerebbe dei caratteri in aree di memoria non previste 0 gia occupate probabilmente dal programma principale, causando non pochi problemi. Spesso la ricerca degli errori nei programmi complicata; faremo cost in

'64 UTILITY PER LA GESTIONE

DElLO

SCHERMO

modo che la subroutine TVTOXY, oltre che calcolare gli indirizzi deo, controlli anche l'arnrnissibifita dei valori contenuti nei registri Per poter compiere questi controlli ci occorrono ulteriori dati; TVCOl TVRIG Riassumendo, HOME RIGINC TVRIG TVCOl Se memorizziamo questi semplicemente consultare quindi, Numero Numero

del viX e Y.

di colonne del video contando da zero di righe del video contando da zero quattro dati:

ci occorreranno

dati in un blocco di memoria, TVTOXY dovra questa piccola tabella per sapere tutto cia che come segue:

gli oecorre.
TVTOXY TVTOXY TVTOXY SEC CPX TVCOL [Link] LDXTVCOL X fuori dai limiti? sara quindi implementato

No, va bene COS! Si, setta X al massimo sentito Y fuori dai Iimiti?

valore

con-

[Link]

SEC CPYTVRIG [Link] LDYTVRIG

No, va bene cosi SI, setta Y al massimo senti to Sella [Link]~HOME

valore

con-

[Link]

LDAHOME STA [Link] LDAHOME+l STA [Link]+l TXA CLC [Link] BCC SETCOL INC [Link]+l CLC

Somma

X a [Link]

UTILITYPER LA GESTIONE DELLOSCHERMO 65

SETCOL LOOP

NEXT FINE

CPY #0 BEQFINE CLC ADC RIGINC BCC NEXT INC [Link]+ I DEY BNELOOP STA [Link] RTS

Somma [Link] a ([Link])

Ritorna

al programma

principale

TVGIU-TVVAI-TVPIU
Usando [Link]

la subroutine TVTOXY siamo


indirizzi una locazione della

in grado di far sl che il puntatore


memoria video corrispondente aIle

coordinate X e Y desiderate. Sarebbe percio anche molto utile riuscire a


modificare [Link] in relazione al valore corrente. Per esempio, dopo aver visualizzato un carattere sullo schermo, potremmo voler indirizzare la success iva posizione a destra 0 quella immediatamente sotto, oppure perfino saltare all'ennesima posizione de dove ci troviamo. Per tutti questi casi faranno comodo Ie subroutine TVGIU, TVVAI E TVPIU:

TVGIU, TVVAI, TVPIU TVGIU LDARIGINC CLC BCCTVPIU LDA # I CLC [Link] BCCNEXT INC [Link]+ 1 STA [Link] RTS Sposta [Link] alia riga successiva
Saito incondizionato locazione video [Link]

-~-

°x-

TVVAI TVPIU

Salta una mentando

Il puntatore

Somma il contenuto dell'accumulatore ai due byte in pagina zero rtservati a [Link]

NEXT

Torna

al programma

principale

I'accumulatore

Notate che TVGIU e TVVAI fanno uso della routine TVPIU che richiede settato con iI numero di locazioni da saltare. Per TVGIU e

66

UTILITY PER LA GESTIONE

DELLO SCHERMO

TVVAI I'accumulatore invece con terra rispettivamente RIG INC e 1. Potrebbe sembrare che TVPIU non sia lunga abba stanza per costituire una subroutine. Ogni programma che chiama TVPIU potrebbe eseguire la somma senza saltare ad una subroutine e questa ci farebbe risparmiare alcuni cieli macchina al prezzo di pochi byte. Pero. in futuro potremo rendere TVPIU molto piu sofisticata ed e questa il motivo che ci induce a creare una subroutine. Potremo migliorare TVPIU in modo da compiere un controllo sui valori di [Link] per evitare un indirizzamento al di fuori della memoria video. Questa controllo sarebbe mol to macchinoso se compiuto dal programma chiamante, rna se 10 inseriamo all'interno di TVPIU ogni programma che chiama questa subroutine godra dei benefici della modi fica.

VEDCAR
Con [Link] siamo in grado di visualizzare un carattere ASCII nella corrente posizione di schermo, e con TVV AI possiarno spostarci alia posizione success iva. Perche non fondere Ie due routine e creare una subroutine che visualizzi I'immagine di un dato carattere ASCII nella corrente posizione sullo schermo e increment! automaticamente it puntatore [Link] in modo che punti alia successiva posizione? Questo renderebbe molto facile la visualizzazione di una stringa di caratteri in posizioni di scherrno successive. Porche questa subroutine permettera all'utilizzatore di vedere un carattere sara chiamata VEDCAR: VEDCAR JSR [Link] JSR TVVAI RTS Visualizza nella corrente il carattere corrispondente Avanza fino alia posizione posizione al codice success iva

Possiamo per-sino inserire VEDCAR tra Ie !inee di programma viste per TVGIU, TVVAI e TVPIU aggiungendo una nuova linea di programma immediatamente prima di TVVAI. (Vedi in Appendice Ct, illistato Assembler di queste utility che include anche alcuni controlli degli errori all'Interno di TVPIU).

VEDBYT
Con Ie utility presentate in precedenza siamo in grado di visualizzare un carattere ASCII nella posizione corrente rna non abbiamo utility che visualizzano un byte in esadecimale. Vediamo di crearne una.

UTIUTY PER LA GESTIONE DELLO SCHERMO

67

Chiameremo questa utility VEDBYT poiche ci permettera di vedere un byte. Per visualizzare un byte in notazione esadecimale, iI programma principale, prima di chiamare VEDBYT, dovra compiere tre semplici operazioni: 1. settare il puntatore [Link] in modo che punti alia posizione 2. caricare l'accumulatore con il byte da visualizzare; 3. chiamare VEDBYT. La Figura 5.1 rappresenta il diagramma di flusso di VEDBYT. desiderata;

Figura 5.1 Diagramma di fiusso della routine sualizzare un byte in esadecimale

VEDBYT che permette

di vi-

------

------

--

_-

--

--

--

_---

68

UTILITY PER LA GESTIONE

DELLO SCHERMO

VEDBYT permettera di visuahzzare un date byte come due caratteri ASCII nella corrente posizione dello schermo e all'usclta della subroutine [Link] puntera alia success iva posizione della schermo. Il compito di VEDBYT quello di determinare il carattere ASCII corrisponclente al valore esadecimale dei 4 bit alti (MSB). memorizzare quel carattere ASCII nella locazione indicata da [Link] e poi vlsualizzare il carattere ASCII corrispondente al valore dei 4 bit bassi (LSB) nella posizione successiva. Per svolgere questa compilo VEDBYT richiede una subroutine che converta it valore esadecimale in carattere ASCII. Chiameremo quest'altra routine, ASCII. La routine ASCII eseguira la traduzione del valore esadecimale contenuto nell'LSB dell'accumulatore da esadecimale ad ASCII, ignorando I'MSB. Supponendo che questa routine esista potremo quindi scrivere il pro.

gramma VEDBYT: VEDBYT VEDBYT

PHA
LSRA LSRA LSRA LSRA JSRASCII JSR VEDCAR

Salva

I'accumulatore

Trasla

I'MSB

nella

posizione

occupata

dall'LSB

Determina il carattere corrtspondente all'LSB dell'accumulatore Visualizza posizione posizione Riprende cumulatore Determina il carattere ASCII nella corrente e avanza di una

PLA
JSRASCII JSR VEDCAR

il valore originale
il carattere

dell'ac-

ASCII cord-

spondente all'LSB
Visualizza iI carattere posizione success iva una posizione Ritorna al programma e ASCII nella avanza di

RTS

principale

UTILITY PER LA GESTIONE

DELLO SCHERMO

69

La routine ASCII al momento pleto VEDBYT la scriveremo

non esiste cost:

ancora,

quindi,

per rendere

com-

ASCII ASCII AND #$OF CMP #$OA BMIDECIML ADC #6 Azzera I'MSB dell'accumulatore

L'accumulatore

maggiore

di 9?

Se si, deve essere compreso tra A e F e bisogna sommare $36 per ottenere iI carattere ASCII corrispondente. (Sommeremo prima $6 e poi $30) Se no, e compreso tra 0 e 9. Scmmando $30 otterremo ,'ASCII corrispondente Ritorna al programma principale

DECIML

ADC #$30

RTS

TVHOME, CENTRO
Siamo a questa pun to in grado di visualizzare un carattere ASCII 0 un byte nella corrente posizione della schermo, e siamo inoltre in grado dl settare la posizione della schermo in ogni punto X e Y desiderata. Sarebhe utile pater settare [Link] a certe posizioni di uso comune; posizioni che potrebbero essere necessarie a piu di un programma chiamante. Per esempio, queste posizioni potrebbero essere HOME (0,0) 0 il centro dello schermo:

TVHOME,

CENTRO LDX #0 LDY #0 JSR TVTOXY RTS Setta [Link] alia colonna piu a sinistra della prima riga delle scherrno

TVHOME

Ritorna

al programma

principale

--

--"

--

--

--

--

70

UTILITY PER LA GESTIONE

DELLO SCHERMO

CENTRO

LOA TVRIG LSRA TAY

Carica in A il numero totale delle righe Divide per due Y contiene ora it numero della riga centrale Carica in' A il numero totale delle colonne Divide per due X contiene ora il numero della colonna centrale Setta [Link] aile coordinate XeY Ritorna al programma principaie

LOA TVCOL LSRA TAX

JSR TVTOXY RTS

TVSALV E TVREC
Le utility presentate qui di seguito ci permetteranno di salvare posizione sullo schermo e di recuperarla all'occorrenza. Saremo di fare questa inserendo e recuperando dallo stack il puntatore l'attuale in grado [Link].

TVSALV TVSALV PLA Legge l'Indi rizzo di ritorno dallo

stack
TAX PLA TAY LOA [Link]+ PHA LOA [Link] PHA TYA PHA TXA PHA RTS I Lo salva e in in X

Y
e 10 salva nello stack

Legge [Link]

Rimette nello stack ]'indirizzo di ritorno

Ri torna

al programma

principale

UTILITY PER LA GESTIONE

DELLO SCHERMO

71

TVREC
TVREC PLA TAX PLA TAY PLA STA [Link] PLA STA [Link]+l TYA PHA TXA PHA RTS Legge l'indirizzo stack La salva in X e in di ritorno dallo

Y
[Link] dallo stack

Recupera

Rimette nello stack J'indirizzo di ritorno

Ritorna

al programma

principale

II programma principaJe adesso in grado di salvare la posizione attuale sullo schermo con una semplice linea di cod ice ~ JSR TVSALV -, modificare a piacimento il punta tore [Link] e poi ristabilire it valore iniziale con JSR TVREC.

Pulire 10 schermo
Adesso che siamo in grado di visualizzare un carattere 0 un byte in ogni posizione delle schermo, proviamo a scrivere una subroutine che ci per-

metta di pulire parte

tutto 10 schermo. Una subroutine,

che chiamere-

rno PULTV cancellera tutto il contenuto della schermo, mentre un'altra subroutine, PULXY, cancelled iI rettangolo Ie cui dimensioni x e y sana contenute nei registri X e Y. Percio Il programma principale potra richiamare PULTV per cancellare tutto 10 schermo. oppure PULXY per cancellare una determinata area lasciando it resto inalterato. Per eseguire queste operazioni, sara necessario fare in modo che il puntatore [Link] punti al vertice superiore sinistro del rettangolo da cancell are e che i registri X e Y contengano Ie dimensioni (rispettivamente larghezza e altezza) delt'area da cancelJare. PULTV JSR TVSALV JSR TVHOME Salva ranno Sella i byte di pagina zero che sacambiati it puntatore alia posizione 0,0

72

UTILITY PER LA GESTIONE

DELLO SCHERMO

LDXTVCOL LDYTVRIG JSRPULXY JSR TVREC RTS

Carica in X e Y Ie dimensioni della schermo Cancel1a X colonne e Y righe dalla posizione attuale Resetta i byte di pagina zero Ritorna con 10 schermo pulito e la pagina zero inalterata Setta cellare

PULXY

STXCOL TYA TAX

it numero

di colonne

cia can-

PULRIG

LDA NULL LDY COL

PULPOS

STA ([Link]),Y DEY BPLPULPOS JSR TVGIU DEX BPLPULRIG RTS .BYTE 0

Setta il numero di righe da cancellare Carica in A iI val ore corrispondente a uno spazio bianco Carica in Y iI numero di colonne da cancellare Cancella la posizione scrtvendo uno spazio bianco Decrementa Y per la posizione suecessiva Se non finito cancella la .posizione successiva Se la riga finita passa alia succes-

siva

COL

E finita l'ultfma riga? Se no. cancella la success iva riga Ritorna al programma principaie Variabile: contiene iI numero di colonne da cancellare

Esistono molte altre utility che possono essere sviluppate, rna Ie routine presentate in questa capitolo vogliono essere solo una base di partenza. Adesso un programma si potra avvalere delle seguenti subroutine per ottenere i risultati descritti: ASCII CENTRO PULTV PULXY TVGIU TVHOME TVPIU Converte in ASCII i 4 LSB contenuti in A Setta la posizione corrente al centro dello schermo CancelJa iI contenuto della schermo Cancella iI rettangolo di dimensioni XeY Sposta la posizione di una riga verso il basso Sposta la posizione corrente nelJ'origine Somma a [Link] iI contenuto di A

UTIUTY

PER LA GESTIONE

DELLO SCHERMO

73

TVREC TVSALV [Link] TVVAI TVTOXY VEDBYT VEDCAR

Recupera dallo stack la posizione precedentemente


salvata Salva nello stack l'attuale posizione

Visualizza il carattere ASCII contenuto in A Avanza alia successiva posizione Setta la corrente posizione aile coordinate X e Y VisuaJizza il contenuto di A in sistema esadecimale e avanza di una posizione Visualizza il contenuto di A come carattere ASCII e avanza di una posizione

Per mezzo di queste utility il programma principale potra gestire 10 schermo senza preoccuparsi della memoria video e dei puntatori in pagina zero. II programma dovra solamente gestire la posizione corrente sullo schermo, senza preoccuparsi dell'indirizzamento della memoria video.

Capitolo

II Monitor Visibile

Assemblaggio manuale
Un assemblatore un potente strumento di programmazione, rna cosa si puc fare se non e disponibile? E possibile scr'ivere programmi per it 6502 senza un assemblatore? Non solo e possibile assernblare manualmente un programma, rna tutto Il software presentato in questa libro e state. in origine, assemblato e inserito nel computer manual mente. L'assemblaggio manuale impone una certa disci pi ina al programmatore. Infatti gli indirizzi di saito vanna calcolati contando avanti e indietro in esadecimale, il che non e mol to semplice. I programrni presentati so no questa e una buona norma anche qualora si usi un assemblatore, rna diventa indispensabile quando si cost [Link] all'assemblaggio manuale. Una volta seritto un programma in eodice maeehina, come potremo inserirlo in memoria? Sara possibile legger-lo sulla carta, rna come 10 presenteremo al 6502? Un programma chiamato monitor ci permette di esarninare e rnodificare il contenuto della memoria. Permette inoltre di eseguire un programma memorizzato. II C-64 e il VIC-20 non hanno un monitor incorporate: sono disponibil i monitor molto sofisticati su disco 0 su casset ta. rna da! punto di vista dell'apprendimento della teoria non e st ret tamente necessar-io possederne uno. COS), prima di correre a comperare un monitor, previarna a esaminarne uno molto sempiice. Quello che prenderemo in esame usa to sull'OSI C I-P (Ohiu Scientific

scritti come una serie di subroutine

annidaie e provate individualmente;

76

IL MONITOR VISIBILE

Challenger [-P). Viene presentato qui solo come esempio sponibile per i computer Commodore.

poiche

non

di-

Un semplice monitor di codice macchina


1:. possibile richiamare it monitor dell'OS! semplicemente premendo il tasto BREA.K e il tasto M. II monitor cancella 10 schermo e si presenta come si puc vedere in Figura 6.1. La videata costituita da due campi di caratteri esadecirnali: un campo degli indirizzi e uno dei dati. Nella Figura 6.1 possibile vedere che $A9

e l'attuale velore dell'indirizzo $0000. II monitor dell'OS! puc funzionare


in due modi: indirizzi e dati. Quando si trova in modo indirizzi

possihi-

Ie visualizzare il contenuto di ogni indirizzo sempliccmente scrivendo J'indirizzo sulla tastiera. Ogni carattere esadecimale entrera nel campo degli indirizzi da destra, quindi per impostare I'indirizzo $FEOD sara sufficiente premere in sequenza i tasti F, E, 0 e D. Per poter cambiare iI contenuto di un indirizzo bisogna passare in modo dati. Quando il monitor

Figura 6.1 II monitor dell'OSI

IL MONITOR VISIBILE

77

dell'OS! inseriranno sufficiente

non

in questa modo, i caratteri esadecimali digitati da tastiera si nel campo dati e per avanzare di un indirizzo alla volta sara premere il tasto RETURN. Sfortunatamente questa possibilita

disponibile nel modo indirizzi e in nessuno del due modi


di una locazione in memoria.

posstbl-

Ie retrocedere

Attenzione, perc, it monitor dell'OSI potrebbe confondervi. Se il monitor


sulla tastiera un carattere esadecimale, quel nel campo dati sullo schermo. Si presume

in modo dati e voi digitate carattere verra visualizzato

che quel carattere esadecimale venga anche memorizzato nella locazione visibile sullo schermo, rna questa potrebbe non essere vero; infatti, il monitor dell'OSI visualizza i dati che si vogliono memcrixzare piuttostc che it reale contenuto dell'indirizzo. Per esempio, se si cerca di cambiare un indirizzo di ROM, il monitor confermera che il data desiderato stato memorizzato, se peri> andiamo ad ispezionare quell'indirizzo (passando in modo indirizzi e digitando quell'indirizzo) sicuramente vedremo che non state cambiato nulla. Morale: non possibile scrivere nelle memorie di sola lettura, rna il monitor dell'OSI vi fa credere il contrario. Il monitor dell'OSI vi puc confondere in altri modi. Per esemplo. bisogna ricordarsi se si in modo indirizzi 0 dati e, per passare da un modo all'altro, necessaria una ben determinata sequenza di caratteri (bisognera quindi ricordare anche questi codicil. Inoltre, can questa monitor non molto facile I'inserimento delle stringhe di caratteri ASCII. Per inserire un messaggio in ASCII sara necessaria consultare una tabella dei codici ASCII (vedi Appendice A2), ricavare it val ore esadecimale di ogoi carattere e inserirlo in questa forma. Inoltre, dovendo rileggere il messaggio sara necessaria it procedirrtento inverso. Vale la pena dl esaminare la maniera in cui il monitor dell'OSI esegue un programma memorizzato. Quando si preme it tasto G, il monitor esegue un salto incondizionato (JMP) all'indirizzo visualizzato, quindi trasfertsce it controllo al programma selezionato. Questo procedimento perc viene eseguito in modo tale che it programma selezionato deve terminare can un altro saito incondizionato per ritornare al monitor. Questa fatto ca. stringe a scrivere programmi che terminano can l'istruzione JMP piuttosto che subroutine che finiscono di regola con l'istruzione RTS. I programmi che terminano can JMP non sono facilmente usabiB come base per altri programmi, mentre al contrario Ie subroutine possono essere incorporate in un software personalizzato. Sarebbe quindi meglio usare un monitor di sistema che permetta di saltare all'indirizzo visualizzato come ad una subroutine piuttosto che a un programma. Un monitor di questo tipo aiuterebbe ad acquisire un concreto stile di programmaztone, introducendo l'utente alia programmazione strutturata. In questo capitola svilupperemo un monitor di sistema can queste caratteristiche.

78

IL MONITOR VISIBILE

Obiettivi
Se vi gia capitato di usare un monitor di sistema avrete probabilmente pensato di apportargli una qualche rniglioria. Basandoci sulla nostra esperienza un monitor dovrebbe essere: I. Acc~rato: il campo dati deve visualizzare il reale contenuto dell'indirtzzo e non quello che dovrebbe esse rei. possibile avanzare e retrocedere di un passo alIa volta in memoria, qualsiasi sia iI modo selezionato. Deve inoltre esserci la pcsstbilita di inserire stringhe di caratteri ASCII dtrettamente da tastiera, senza dover consultare tabelle e di conseguenza deve essere possibile visualizzare queste stringhe in codice ASCII e non come coppie di valori esadecimali. 3. Orientate alia programmazione slrulturala: deve essere possibile richiamare I'indirizzo visualizzato come una subroutine piuttosto che saltare all'indirizzo. 4. Utile nella rice rca degli errori: deve essere possibile caricare nei registri del 6502 valor! definiti dall'utente prima di richiamare l'indh-izzc visualizzato. In questo modo sara possibile provare Ie subroutine con differenti valori e, finita l'esecuzione della subroutine, it monitor dovra visualizzare i nuovi valori dei registri. In questa modo, essendo possibile esaminare Ie modificazioni che avvengono, sara pili facile stabilire se la routine funziona correttamente 0 meno. Proprio per questa possibilita di poter visualizzare il contenuto dei registri prima e dopo l'esecuzione di una subroutine, chiameremo questo monitor Monitor Visibile. La Figura 6.2 most ra una videata tipica del Monitor Visibile.

2. Comodo da: usare: deve essere

II Monitor Visibile
Noterete che la videata di Figura 6.2 presenta ben sette campi e non due come succede con iI monitor OS!. I primi due campi (campo 0 e I) sono identici al monitor OS!, cioe rappresentano un indirizzo e il suo contenuto in esadecimale. II campo 2 una rappresentazione grafica 0 ASCII del valore contenuto nell'indirizzo. Se l'indirizzo visualizzato contiene un carattere ASCII, allora nel campo 2 ci sara l'immagine del carattere, numero 0 segno di interpunzione corr'ispondente, altrimenti ci sara I'irnrnagine di un carattere grafico caratteristico del Commodore, rna non contemplato dal codice ASCII. I campi da 3 a 6 rappresentano i quattro registri del 6502: A (l'accumulatore), X (il registro X), Y (it registro Y) e P (il registro di stato).

IL MONITOR VISIBILE

79

Campo 0

1135

00

00

Figura 6.2 Come si presenta

il Monitor Visibile con

campi numerati

Quando si premera il tasto G per eseguire un programma. i registri verranno caricati con il valore visualizzato e, quando il controllo r-itornera al monitor, i registri saranna visualizzati di nuovo. Oltre ai sette campi il nostro monitor visualizzera anche una freccia indicante uno del sette campi. Per modificare uno dei campi sara necessaria fare in modo che la freccia indichi il campo da modificare. Premendo iI tasto di movimento cursore sara possibile cambiare la posizione della freccia e puntare COS1 Hcampo desiderata. Auenatone: iI tasto di movimento cursore e unieo; pre men dolo senza 10 SHJFT ci si potra spostare a destra, mentre premendolo con 10 SHIFT ci si spostera a stnistra. Abbiamo see Ito la barr a spaziatr-ice per incrementare l'indirizzo e iI tasto RETURN per decrementarlo: ovviamente possibile usare una qualsiasi cop pia di tasti come, ad esempio. + e -. Con queste posstbilita di visualizzazione e questi tasti funzione dovrebbe essere possibile costruire un monitor potente e maneggevole.

80

IL MONITORVISIBILE

Dati
Prima di sviluppare la struttura e il programma del Monitor Visibile e utile fare iI punto sulle variabili e sui punta tori che occorreranno. II Monitor Visibile deve ccnoscere in qualche modo l'indirizzo da visuaIizzare nel campo O. Questa e possibile per mezzo di un puntatore che speclfichi J'indirizzo da visualizzare. Chiameremo questa puntatore SE· LEZ poiche puntera all'indirizzo selezionato. Quindi, ad ogni pressione della barra spaziatrtce. SELEZ dovra essere incrementato, mentre iI tasto RETURN dovra decrementarlo rendendo cosi possibile 10 spostamento avanti e indietro in memoria. L'utente dovra inoltre essere in grade di cambiare il contenuto dei registri. Poiche ci sono quattro registri, sara necessaria riservare quattro byte in memoria, uno per ogni registro. Se riserviamo questi byte in locezioni contigue sara utile riferrrci a questo bloeco chiamandolo REGISTRI o meglio REGI (REGISTRI sarebbe un'etichetta troppo lunga per essere accettata dall' Assembler che considera valide etichette lunghe non pill di sei caratteri). Sara infine necessario specificate il campo selezionato. Siccorrie verra selezionato un solo campo per volta, faremo uso di una variabile, CAMPO, il cui valore specifichera it campo selezionato. Quindi, quando si dovra passare a) campo successivo sara sufficiente incrementare questa variabile e, per passare al campo precedente, sara sufficiente decrementarla. Se il valore della varia bile CAMPOnon sara compreso nei [imiti stabiliti (cioe esterno all'intervallo ()"6)il monitor dovra assegnarle un valore appropriato. Le linee di programma sorgente riportate di seguito dichiarano queste variabili con la sintassi accettata dall'Assembler dell'OSI:

Variablli SELEZ REG.A REG.X REG.Y REG.P CAMPO .WORDO .BYTEO .BYTEO .BYTEO .BYTEO .BYTEO REGI=REG.A Punta tore di indirizzo Valore dell'accumulatore Valore del registro X Valore del registro Y Valore del registro P Numero del campo selezionato

IL MONITOR VISIBILE

81

Struttura
Si cercato di mantenere il Monitor Visibile altamente modulare per facllhare ulteriori modifiche 0 ampliamenti. E stata comunque tenuta ad esempio la struttura di Figura 6.3. Come si pub chiaramente intendere, il Monitor Visibile un loop. Questo loop consiste nel visualizzare sullo schermo i campi ed eseguire Ie modifiche richieste dall'utente con i tasti funzione.

Figura 6.3 Una semplice struttura

per programmi interattivi di vlsualizzazione

Con questo diagramma in mente possiamo cominciare che costituiscono il pr-ime livello del Monitor Visibile

a scrivere Ie linee (VISMON):

VISMON VISMON LOOP PHP


JSR VISUAL JSRAGGIOR Salva gli indicatori del registro Visualizza i campi Esegue Ie operazioni richieste Ricomincia P

CLC BCCLOOP

it cicio

Ouesto solo il primo abbozzo del Monitor Visibile e ovviamente non funzionera senza Ie subroutine VISUAL e AGGIOR. Potrebbe sembrare sconveniente scrivere una subroutine che ne richiama altre due, rna strutturando il monitor in questa maniera sara piu facile svilupparlo, modificarlo e correggere gli eventuali errori. Inizieremo con 10 studio del modulo VISUAL perche iI video costituisce I'interfaccia tra macchina e utente; questo modulo dovra r-ispettare Ie nostre esigenze. Una volta possibile la visualizzazione delle informazioni, potremo scrivere la routine AGGIOR.

82

IL MONITOR VISIBILE

Visualizzazione
La Figura 6.2 mostra 1a videata che vogliamo ottenere. Come potete notare, questa videata e composta da tre linee di caratteri: la linea dei titoli. quella dei dati e quell a che contiene la freccia di selezione. La prima linea, quella dei titoli, identifica i quattro campi riguardanti i registri con Ie lettere A, X, Y. P. La linea dei dati visuahzza un indirizzo, il suo contenuto (in forma esadecimale e come carattere) e il valore contenuto nei registri del 6502. La terza linea contiene una freccia che punta a uno dei campi visualizzati. Poiche a questa punto abbiamo definito quello che ci occorre in termini di linea dei [Link]. linea dei dati e linea indice, possiamo disegnare il diagramma a blocchi della routine VISUAL come mostrato in Figura 6.4. Tenendo presente questo diagramma scriviamo il primo abbozzo della subroutine VISUAL.

Figura 6.4 Routine per visualizzare

Ie informazioni

richieste

VISUAL VISUAL JSRPULMON JSR LINE. I JSR LINE.2 Cancella la parte del video r-iservata al monitor Visualizza Ia linea dei titoli Visualizza la linea dei dati

IL MONITOR VISIBILE

83

JSR LINE.3 RTS

Visualizza la freccia tndice Ritorna al programma principale

Corne noterete, adesso invece di una subroutine dovremo scriverne quattro: PULMON, LINE. I, 2 e 3. Man mana perc che iI numero delle subroutine aumenta, diminuisce la lora ccmplesaita. Prima di visualizzare quaJche cosa sara utile pulire quella parte della schermo usata dal monitor. Siccorne abbiamo gia creato unutility che permette di cancellare X colonne e Y r-ighe, sara sufficiente settare [Link] nella posizione di home (0,0), carie are i reglstri X e Y con i valori appropriati ed eseguire un salta alia subroutine PULXY. PULMON LDX #2 LDY #2 JSR TVTOXY LDXTVCOL LDY #3 JSR PULXY RTS Setta [Link] alIa riga 2 e colonna

Cancella per tutta la larghezza Cancella Ie prime 3 righe


Esegue Ritorna la cancellazione al programma principale

Linea dei titoli


La subroutine LINE.1 ha il compito di visualizzare la linea dei titoli. Memorizzeremo in qualche locazione di memoria la stringa di caratteri "A X Y P" e ci riferiremo a queste locazioni con il nome di TITOLI. Sara quindi sufficiente che la subroutine LINE.1 legga 10 byte dal blocco TITOll e li riscriva nell'appropriata posizione della schermo. Con questo procedimento saremo in grade di visualizzare la linea dei titoli:

LINE. I LINE.I LDX LDY JSR LDY STY LDA JSR INC H II #0 TVTOXY #0 TITCOL TITOLI, Y VEDCAR TITCOL Coordinata X del titolo "A" Coordinata Y del titolo "A" Setta [Link] aile coordinate XeY Visualizza Inizializza il contatore delle colonne Legge un carattere Lo visualizza Si prepara per il successivo

TITLOP

84

IL MONITOR VISIBILE

TITOL) TITCOL

LDYTITCOL CPY # 10 BNE TITLOP RTS .BYTE 'AX' .BYTE 'YP' .BYTEO

Usa TITCOL come indice E l'uhirno carattere? No, prosegue con il successive Ritorna al programma principaie Ouest! sono i caratteri

da visualizzare
Questo e il contatore

Linea del dati


Le operazioni da compiere per visualizzare la linea dei dati saranno un po' pill complicate per due motivi. In primo Juogo i dati da visualizzare cambieranno di volta in volta e, secondariamente, la maggior parte dei campi con terra dati in forma esadecimale. La visualizzazione di un byte in forma esadecimale richiede piu lavoro che non visualizzare un caratte-

re ASCII.
Fortunatamente abbiamo un'utility, VEDBYT, che ci permettera di compiere questa operazione. Possiamo quindi scrivere la routine che visualiz-

za la seconda linea: LINE.2 LINE. 2 LDX #0 LDY #1 JSRTVTOXY LDA SELEZ+ 1 JSR VEDBYT LDASELEZ JSR VEDBYT JSR TVVAI JSRLEGBYT PHA JSRVEDBYT JSR TVVAI
PLA

Coordinata X dell'inizio linea Coordinata Y della linea dati Setta [Link] Visualizza il nybble alto Visualizza quello basso Si sposta di una posizione verso destra Legge it valore del byte selezionato Lo salva Lo visualizza Recupera ll valore Lo visualizza in codice ASCII Visualizza i registri Legge i registri Visualizza il contenuto

VEDREG

JSRVEDCAR JSR TVVAI LDX #0 LDAREGI.X JSR VEDBYT

IL MONITORVISIBILE 85

JSR TVVAI INX CPX #4 BNE VEOREG RTS Noterete che la subroutine

Si prepara per il successivo Visualizzati tutti e 4? No, legge il successive Ritorna al programma principaJe

nato. Questa valore viene letto dalla subroutine LEGBYT che Jegge it contenuto dell'indirizzo puntato da SELEZ. Se SELEZ un puntatore in pagina zero, LEGBYT, sara una routine molto semplice e potra avvalersi del vantaggi dell'indirizzamento indiretto

LINE.2 non conosce it valore del byte selezio-

LEGBYT

LOY #0 LDA (SELEZ).Y RTS

Legge il byte a cui punta SELEZ

Pero SELEZ non un punta tore in pagina zero; si trova infatti in pagina $32. Come sappiamo il 6502 non possiede un indirizzamento che permetta di caricare un registro per mezzo di un punta tore estraneo alia pagina zero. Come sara possibile leggere il valore contenuto nella locazione specific ata da SELEZ? Ci riusclremo in due passaggi. Useremo un puntatore in pagina zero che sia uguale in valore a SELEZ e che quindi puntera aile stesso indirizzo e poi caricheremo l'accumulatore per mezzo di questa nuovo puntatore in pagina zero che chiameremo LEGPTR. Usando questa strategia la nostra routine si presentera cosi:

LEGBYT

LOASELEZ STALEGPTR LDA SELEZ+ 1 STALEGPTR+l LOY #0 LOA (LEGPTR). Y RTS

Setta LEGPTR uguale a SELEZ

it byte specificate LEGPTR


Legge

da

Ritorna al programma (A=contenuto dell'indirizzo puntato da

SELEZ)
Questa secondo tentativo carichera J'aecumulatore col valore della locazione specificata da SELEZ anche se questa puntatore non in pagina zero. Attenzione pero che settando LEGPTR uguale a SELEZ, la subroutine LEGBYT cambia il valore di LEGBYT, e questa puc essere malta pericoloso. Cosa succederebbe per esempio se un altro programma facesse usa di LEGPTR? L'altro programma sarebbe "sabotato" da LEGBYT. Se permettiamo che la routine LEGBYT cambi il valore del puntatore LEGPTR,

86

IL MONITORVISIBILE

dovremo essere slcuri che nessun altro programma usi LEGPTR. Questa risultato non ottenibile se si vuole mantenere la coabitazione con Ie routine di 110 del vostro sistema. Quando si devono usare dei byte in pagina zero, come nel nostro caso, necessaria, dopo l'uso, risistemare i

valor! originali.

Quindi, la nastra routine LEGBYT sara suddivisa in 4 parti: la prima salvera LEGPTR, la seconda settera LEGPTR uguale a SELEZ, la terza carichera l'accumulatore con it contenuto della locazione specificata e finalmente la quart a ripr'istinera il valore originario di LEGPTR. Questa versione di LEGBYT sara certamente pili ingombrante e piu lenta, rna largamente piu sicura:

LEGBYT

LOA LEGPTR PHA LOX LEGPTR + 1 LOASELEZ STALEGPTR LOA SELEZ+ 1 STA LEGPTR+ 1 LOY #0 LOA (LEGPTR), Y TAY PLA STA LEGPTR STX LEGPTR + 1 TYA RTS

Salva LEGPTR

LEGPTR = SELEZ

Legge

it valore

puntato

da SELEZ

Resetta LEGPTR

Ritorna

al programma

principale

La freccia indice
Questa routine visualizza la freccia indice che evidenzia il campo corrente:

L1NE,3 LINE.3 LOY CAMPO SEC CPY #7 [Link] LOY #0 STY CAMPO
Punta il campo Se fuori limite punta il campo corrente

di default

IL MONITOR VISIBILE

87

CAM. OK

LOA

CAMPI,Y

TAX LOY #2 JSR TVTOXY LOA JSR RTS .BYTE .BYTE .BYTE FRECC VEOCAR 3,6,8 $OB,$OE $11,$14

Legge a che colonna it campo corrente Questa sara la coordinata X

Coordinata Y
Setta [Link]

Visualizza la freccia
in quella Colonne apparire posizione dove potrebbe la freccia

CAMPI

Ora che abbiamo tutte Ie routine occorrenti per visualizzare, vediamo come vengono legate assieme per formare una struttura. Di seguito visibile la gerarchia delle subroutine richiamate cia VISUAL:

VISUAL LINE. 1 LINE.2 LEGBYT VEOBYT ASCII TVPIU TVVAI LINE.3 Quando VISUAL sara eseguito, verranno cancellate Ie prime quattro righe della scherrno e verranno visualizzate le tre linee ora descritte. Anche se it programma puc sembrare complicato e lento. verdi eseguito in

un batter d'occhio.

La sezione di aggiornamento
La routine AGGIOR permette di compiere determinate operazioni conda del tasto premuto. I tasti funzione che ci interessano son~: Tasto Spostamento Spostamento Incremento Decremento Funzione dell'indice verso destra dell'indice verso sinistra dell'indirizzo visualizzato dell'indirizzo visualizzato a se-

Barra
RETURN

spaziatrice

88

IL MONITOR VISIBILE

r---------,
I

I
I

IIMonitor Visihilflilin rnodocaratleri

t---_J I

r--------,

i ;::'~~~:~e 1--------:::, : ~!~~t~~~i::1e 10: L J


Figura 6.5 Diagramma di flusso della routine AGGIOR

I I Inqueslo~nl'l I s.'possooo,n_

I I I

-'

IL MONITOR VISIBILE

89

Se I'indice

nei campi 1, 3, 4, 5

6:
nel

da 0 a 9, da A a F
Se l'indice

Inserimento del carattere esadecimale campo indicato dalla freccia 2: Inserimento del carattere di refresh

nel campo

qualsiasi
Poiche it circuito

ASCII corrispondente entro un cer-

video non necessita

(riscrittura

to tempo). la routine AGGIORpotra funzionare senza problemi di temporizzazione. La routine AGGIOR pub quindi aspettare indefinitamente un comando da tastiera e compiere Ie operazioni richieste. II diagramma di f1usso di questa routine visibile in Figura 6.5. Sara possibile implementare ulteriori funzioni sempiicemente aggiungendo test per uno 0 pill. caratteri e scrivendo Ie eventuali subroutine di ampliamento.

L'acquisizione del carattere


Per prima cosa dobbiamo essere in grado di leggere un input da tastiera.

Naturalmente nel vostro sistema esiste gia una routine in ROM che svolge questa com pi to. Come si pub vedere nelle Appendici BI e B2, abbiamo memorizzato gli indirizzi di questa routine in un punta tore che chiamererno ROMKEY, situato alia locazione $3008. Una volta settato ROMKEY sara possibile leggere iI valore del tasto premuto chiamando la subroutine LEG KEY che trasferisce iI controllo alia routine contenuta in ROM. LEG KEY JMP (ROMKEY) siamo

Adesso che siamo in grade di leggere il valore del tasto premuto, anche in grado di scrivere la routine AGGIOR:

AGGIOR AGGIOR JSR LEGKEY CMP #$1D [Link] INC CAMPO LDACAMPO Legge il tasto premuto E il taste -? Se no, esegue il test successivo

NEXT.F

Se 51,seleziona iI campo successivo Se l'indice era al campo piu a destra,

90

IL MONITORVISIBILE

VIA I [Link] PREV.F

CMP #7 BNE VIA I LDA #0 STACAMPO RTS CMP #$9D BNE [Link] DEC CAMPO BPL VIA 2 LDA #6 STA CAMPO RTS CMP #SPAZlO BNE [Link] INC SELEZ BNE VIA 3 INC SELEZ+I RTS CMP#CR BNEIFCAR LDASELEZ BNENEXT.I DEC SELEZ+ I DEC SELEZ RTS LDXCAMPO CPX #2 BNE [Link] TAY LDA [Link] PHA LDX [Link]+ I LDASELEZ STA [Link] LDA SELEZ+ I [Link]+I TYA LDY #0 STA ([Link]),Y

si posiziona sinist ra

souo

quello

piu a

VIA 2 [Link] [Link] VIA 3 [Link] [Link] NEXT. I IFCAR [Link]

Ritorna al programma principaie E il tasto -? Se no, esegue il test successive Se st. seleziona il campo precedente Se l'Indice era at campo piu a sinistra si posiziona souo quello a destra Ritorna al programma principale E uno spazio? Se no, esegue il test successivo Se 51. avanza in memoria incrementando il punta tore che specifica l'mdi rizzo visualizzato Ritorna al programma principale E un RETURN? Se no, esegue il test successivo Se SI, retrocede in memoria decrementando it punta tore che specifica I'indirizzo visualizzato Ritorna L'indice al programma principale sotto il campo 2?

Se no, esegue il test successivo Memorizza l'accumulatore nell'In-

dirizzo

con tenere

selezionato usando iI carattere Salva [Link]

Y per

nello stack e in X prima di usarlo per visualizzare il carattere nella posizione desiderata

Setta [Link]=SELEZ
in modo che punti all'indirizzo selezionato Rimette nell'accumulatore it carattere da visualizzare Lo visualizza nella posizione desiderata

IL MONITOR VISIBILE

91

STX [Link] PLA STA [Link] RTS [Link] GO CMP # 'G [Link] LDY REG.Y LDXREG.X LDA REG.P PHA LDA REG.A PLP JSR CALLSL PHP STA STX STY PLA STA RTS JMP

+!

Resetta

[Link]

al val ore originate

E il taste G? Se no, esegue con 1a lora

il test successivo Se st. carica i registri del 6502


immagine visualizzata

REG.A REG.X REG.Y REG.P (SELEZ)

Chiama la subroutine all'indirizzo seiezionato AI ritorno dalla subroutine salva it valore dei registri nelle rispettive immagini

CALLSL IF. HEX

PHA JSR BINA

BMI [Link]

Ritorna al programma principale Chiama la subroutine all'indirizzo selezionato Salva il carattere Se l'accumulatore contiene un carattere ASCII compreso tra 0 e 9 0 A e F, BINA calcola la rappresentazione binaria di quel carattere. AItrimenti BINA setta l'accumulatore a FF e l'indicatore negativo Se l'accumuiatore non contiene un carattere esadecimale esegue it test successivo

METII

TAY PLA TYA LDXCAMPO BNE NOINDI

CAMPO! LOOP.!

LDX #3 CLC ASLSELEZ

Mette A in un campo esadecimale L'indice sotto it campo indirizzi? Se no, l'indice deve essere sotto un altro campo esadecimale Poiche l'tndice sotto iI campo indirizzi, mette it carattere esadecimale contenuto in A nel campo in-

92

IL MONITOR VISIBILE

NOINDI ROLLSL

ROLSELEZ+! DEX BPLLOOP.! TYA ORASELEZ STA SELEZ RTS CPX # ! BNECAMPOR AND # $OF PHA JSR LEGBYT ASLA ASLA ASLA ASLA AND #$FO STATEMP PLA ORA TEMP [Link] RTS

dirizzi settando il punta tore speciftca l'indirizzo visualizzato

che

Ritorna al programma principale L'indice sotto il campo 1? Se no, deve essere sotto I'immagine

di un registro Legge il contenuto dell'indirizzo selezionato e trasla a sinistra


4 volte

Lo salva in una variabile temporanea Memorizza il risultato nell'indirizzo selezionato e ritorna al programma principale
L'lndice deve essere 3,4, 5 0 6 sotto il campo

TEMP CAMPOR

LOOP.2

[Link]

.BYTEO DEX DEX DEX LDY #3 CLC ASLREGI,X DEY BPLLOOP.2 ORAREGI,X STAREGI,X RTS PLA CMP # '0 BNENO.O PLA PLA PLP RTS

Mette tenuto gine

iI carattere

esadecimale conin A nell'appropriata imma-

Ritorna al programma principale Recupera iI carattere dallo stack E una O? (0 per fine) Se no, esegue it test successive Se st. ritorna

al programma
che ha richiamato

VISMON

IL MONITOR VISIBILE

93

NO.Q

JSRCOMOO
RTS

COMOO

Cambia questa salta a COMOD con Ia chiamata ad altre subroutine che estendono la funzionalita Ritorna al programma principaie

Conversione ASCII/binario
La subroutine AGGIOR richiede un'altra subroutine chiamata BINA, che ci permette di stabili re se il carattere contenuto in A e compreso tra 0 e 9 0 A e F e, nel caso, di calcolare l'equivalente binario. Se l'accumulatore contiene caratteri ASCII al di fuori dei limiti definiti, BINA fornir-a il codice di errore $FF. Percio: Accumulatore BINA

$30 (ASCII "0") $31 (ASCII" 1") $32 (ASCII "2") $33 (ASCII "3") $34 (ASCII ..4") $35 (ASCII "5") $36 (ASCII "6") $37 (ASCII "7") $38 (ASCII "8") $39 (ASCII "9") $41 (ASCII "A") $42 (ASCII "B") $43 (ASCII "C") $44 (ASCII "0") $45 (ASCII "E") $46 (ASCII "F")
altri valor!

$00 $01 $02 $03 $04 $05 $06 $07 $08 $09
$OA $()B

SOC $00
$OE $OF $FF

Possiamo risolvere questa problema usando un'apposi ta tabella che chiameremo BINTAB. BINTAB si trova all'indirizzo $2000, quindi $2000 conterra $FF come pure $2001. $2002, fino all'indirizzo $202F; questa perche nessuno dei codici ASCII compresi tra $00 e $2F rappresenta i caratteri compresi tra 0 e 9 0 A e F. L'indirizzo $2030 con terra 00, perche $30 (il suo offset nella tabella) rappresenta iI codice ASCII della 0, e in questa modo l'indirizzo $2030 contiene il suo equivalente binario: $00. Sirnllmente. poiche $31 e it carattere ASCII 1, l'indirizzo $2031 conterr'a un 1 binario, $01, $2032 con terra $02 e cos. via fino a $2039 che conterra $09.

94

IL MONITOR VISIBILE

Gli indirizzi da $203A a $2040 conterranno tutti $FF, perche ness uno dei codict ASCII compresi ira $3A e $40 rappresentano uno dei caratteri compresi tra 0 e 9 0 A e F. Perc, l'indirizzo $2041 conterra $DA perche $41 rappresenta una A in ASCII e $OA I'equivalente binario. Lo stesso ragionamento vale fino all'indirizzo $2046 che con terra $OF. Gli indirizzi da $2047 a $20FF conterranno $FF perche nessuno dei valori compresi tra $47 e $FF rappresentano in ASCII i caratteri cia 0 a 9 0 cia A a F. BINA quindi sara una routine semplicissima:

BINA

TAY LDA BINTAB,Y RTS

Usa it carattere Trova il valore

ASCII come in tabella

indice

Questo e un tipico esempio di ricerca in tabella, rna e necessaria una tabella di 256 byte. Forse una routine leggermente piu complicata puc pervenire agli stessi r-isultati con una tabella piu piccola 0 addirittura facendone a meno. Una routine di questa tipo dovra calcolare il risultato piuttosto che cercarIo. Guardiamo piu attentamente i caratteri da convertire. Questi caratteri saranno compresi nell'intervallo da $30 a $39 0 da $41 a $46. Un input nell'intervallo $30-$39 sara un carattere ASCII compreso tra 0 e 9 e, sottraendo $30 da questa input, otterremo la conversione. Un input nell'intervallo $41-$46 un carattere ASCII compreso tra A e F e, sottraendo $37 da questa input otterremo la conversione. Per esempio, $41 (A in ASCII) meno $36 dara $OA (A in binario). Ogni altro valore esterno a questi intervalli e illegale e ven-a convert ito in $FF. Tenendo presente queste relazioni, la subroutine BINA dovra solo stabilire se il carattere contenuto nell'accumulatore appart iene a uno degli intervalli legali e, se _cosi, eseguire l'approprtata sottraaione. Qui di seguito viene presentata una subroutine BINA che non richiede l'uso di tabelle:

BINA

SEC SBC #$30 BCC NOK

CMP #$OA BCCOK SBC #7 CMP#$IO BCSNOK

Si prepara alia sottrazione Sottrae $30 Se il carattere era minore di $30 non andava bene, quindi converte in $FF Era nell'intervallo $30-$39? Se st. andava bene e quindi gia stata effettuata la conversione Sottrae 7 Era nell'intervallo $41-$46? Se SI, non andava bene

IL MONITOR VISIBILE

95

NOK OK

SEC CMP #$OA BCSOK LDA #$FF RTS LDX #0 RTS

Le utility del Monitor Visibile


II Monitor BINA Visibile me He a disposizione Ie seguenti subroutine:

CALLSL [Link] LEGKEY LEGBYT GO [Link] [Link] VISMON

Determina se I'accumulatore contiene l'equivalente di un carattere esadecimale. Se 51, esegue la conversione binaria, se no, converte nel valore $FF Chiama I'indirizzo attualmente selezionato come una subroutine Seleziona l'Indi rizzo precedente decrementando il puntatore SELEZ Legge il valore del tasto premuto richiamando la routine della ROM Legge il byte contenuto nell'indirizzo selezionato Carica i registri con i valori visualizzat i Seleziona il byte successivo incrementando i! puntalore SELEZ Memorizza il contenuto dell'accumulatore nell'indirizzo selezionato Permette all'utente di dare comandi al Monitor Visibile finche I'utente non preme il tasto Q (fine) delle routine piu avanti. del Monitor Visibile, alcu-

La Figura 6.6 mostra la gerarchia ne delle quali saranno presentate

Uso del Monitor Visibile


II Capitolo 13 mostra come possibile memorizzare il cod ice oggetto del Monitor Visibile. Per usare questo programma con tutte Ie caratteristiche qui descritte e necessario usare il programma BASIC di caricamento del Capitolo 13 che ci permettera di caricare Ie routine presentate nelle seguenti appendici:

96

IL MONITOR VISIBlLE

Appendlcl El E2 E3 El2 El3

Contenuto Utility della schermo Monitor Visibile prime livello Monitor Visibile subroutine AGGIOR Tabella dati di sistema del VIC-20 Tabella dati di sistema del C-64

VIC-20 C-64

Concatenando i programrni oggetto contenuti in queste appendici otterrete un monitor perfettamente funzionante. Ma questa solo l'Inizio. Ci sono molte funzioni che possono essere aggiunte ed quello che faremo nei pros simi capitoli.

Monitor Visibile

LINE.'

lINE.2

TVTQXY

PULXY

TVTOXY

TVTQXY

VEOBYT

TVPIU

LIT
TVTOXY ROMKEY

FIgura 6.6 La gerarchia delle routine del Monitor Visibile

Caplwlo

Utility di stampa

II Monitor Visibile di grande aiuto per esaminare e modificare il contenuto della memoria. rna, COSI come e stato sviluppato fino ad ora, emuto, non puc cloe "par-larcl" se non attraverso la limitata visualizzazione dei campi. Potremo quindi inserire i caratteri in memoria rna non saferna in grado di listarli. Quindi a questa punto dovremo sviluppare delle routine che ci permettano di indirizzare messaggi, testi 0 stringhe qualsiasi di caratteri ad una qualsiasi periferica di output. Questa capitola esaminera in dettaglio una serie di routine di stampa. Net sistema operativo del vostro computer sana presenti delle routine che controllano la visualizzazione. II C-64 e iI VIC-20 posseggono alcune routine in ROM che perrnettono di indirizzare l'uscita al video, sirnulando quello che viene cornunernente chiarnato un TVT (Tele Vision Typewriter - macchina da scrivere video), oppure alia perifer-ica connessa alia porta seriale, generalrnente una stampante. Poiche queste routine sono gia presenti nel sistema operativo del vostro computer, non ci sara bisogno di reinventarIe, rna piuttosto cercheremo di sviluppare un softw -vre che indirizzi i dati da visualizzare all'appropriata routine del sisten. ~ operativo. Siccome ci apprestiamo a scr ivere del software che richiama Ie due routine standard di output, perche non prevedere un aggancio con una routine di output specificatamente scritta dall'utente ? Una possibilita del genere rendera estremamente semplice indirizzare I'output (messaggi, dump esadecimali, listati, ecc.) allo schermo. alia stampante 0 a qualsiasi per iferica speciale che potreste avere connesso al vostro sistema.

98

UTIUTY 01 STAMPA

Selezione della periferica di output


Qualsiasi programma dovrebbe essere in grado di indirizzare i dati allo schermo, e/o alia stampante, elo a una subroutine-utente. Ouello che ci
occorre quindi sono alcune subroutine cbe permettano di selezionare sin-

golarmente 0 globalmente Ie periferiche. Chiameremo queste subroutine [Link], TVTOFF, [Link], [Link], [Link], USROFF, [Link] e AL· LOFF. Con queste subroutine il programma principale sara in grado di
attivare
0

disattivare

Ie periferiche

singolarmente

global mente.

La linea che selezionera iI video per I'output JSR [Link]

sara:

mentre la disattivazione avver'ra per mezzo di: JSR TVTOFF Le subroutine dl selezione 0 esclusione faranno uso di tre flag: TVT, PRINTR, USR. 11 flag TVT indichera se 10 schermo e selezionato come periferica di uscita; PRINTR avra la stessa funzione per la stampante e USR per la subroutine definita dall'utente. Per convenienza useremo byte differenti per ogni flag e definiremo i flag in OFF quando il valore e zero e in ON quando il valore e diverso da zero. Usando questa convenzione potremo selezionare una periferica semplicemente inserendo un valore diverso da zero nel flag di quella perlfertca e, per escluderla, dovremo inserire uno zero nel flag. Le definizioni dei flag e il Iistato delle subroutine di selezione 0 esclustone sana riportati qui di seguito: Flag delle perlferlche OFF=O ON=$FF TVT PRINTR USR .BYTEON .BYTEOFF .BYTE OFF Quando un flag ha valore zero la rispettiva periferica non e attiva Quando un flag ha valore $FF la rispettiva periferica e attiva Questo flag e zero quando iI video e escluso. Per default it video e attivo Questo flag e zero quando la stampante e esclusa. Per default la stampante e esc1usa Questo flag e zero quando la subroutine utente e esclusa. Per default la subroutine e esclusa

UTILITY DI STAMPA

99

Subroutine [Link]

di selezlone/escluslone LDA STA RTS LDA STA RTS LDA STA RTS LDA STA RTS LDA STA RTS LDA STA RTS JSR JSR JSR RTS JSR JSR JSR RTS NON TVT NOFF TVT NON PRINTR NOFF PRINTR NON USR NOFF USR [Link] [Link] [Link] TVTOFF [Link] USROFF Attiva il video come periferica di ouput settando iI flag con iI valore $FF Disattiva iI video azzerando il flag

TVTOFF

[Link]

Attiva Ia stampante con iI valore $FF Disattiva flag la stampante

settando

il flag

[Link]

azzerando

il it

[Link]

Attiva la routine flag a $FF

utente

settando

USROFF

Disattiva la routine do il flag Attiva tutte

utente

azzeran-

[Link]

Ie periferiche

ALLOFF

Disattiva

tutte

Ie periferiche

Una routine di stampa dei caratteri


Ora che iI programma principale puc atttvare 0 disattivare qualsiasi combinazione di periferiche, ci occorre una routine che invii i caratteri alia periferica selezionata. Chiameremo questa routine INVCAR, vista la sua funzione di inviare caratteri aile perifertche. Tutto il software presentato fara uso di questa routine per inviare i caratteri e in nessun caso usera Ie routine del sistema operativo direttamente. Questa fatto rendera il software pili facile da aggiornare. Se, per esempio svilupperete differenti routine di output, il programma principale continuera ad usare INVCAR evitandovi di dover adattare la routine. Quando INVCAR viene richiamata, ven-a eseguito un test sui flag TVT e

------

------

------

--------

100

UTILITY DI STAMPA

se questa flag senate ver-t-a richiamata la routine di stampa sui video. Lo stesso test vert-a eseguito sia per il flag PRINTR che per il flag USR e se anche questi S0l10 settati, i caratteri verranuo inviati anche aile r-ispetlive routine. La Figura 7. t mostra il diagramma di flusso della routine INVCAR.

Figura 7.1 Diagramma di flusso della routine te le perifcrtche selezionate

INVCAR, pel" inviare dati a tut-

Vettori di output
Se Ie routine di output sono situate in diverse posizioni della memoria corne sara possibile far sapere a INVCAR gli indirizzi delle routine che dovra chiamare? Non sara possibile direttamente, rna solo indirettamente per mezzo di alcuni puntatori che avremo opportunamente predisposto. Occorrono per questo scopo tre puntatori, 0 vettori di output, che chtamino Ie routine di output del sistema operative. II primo puntatore che chiamererno ROMTVT indir'izzera alia routine di output per il video; il secondo, ROMPRT. indir izzera alia routine di output della porta seriale; iI terzo. USROUT, dovra indirizzare alia routine di output scritta

UTILITY DI STAMPA

101

dall'utente per scapi particolari (se non avete necessita di quest'ultima routine, USROUT indir'izzera una routine fittizia consistente in una singola istruzione: RTS). Se dovesse capitare per un motivo qualsiasi di dover rilocare in memoria queste routine, sara sufficiente modificare solo il vettore riguardante la routine interessata. I punta tori ROMTVT, ROMPRT e US ROUT non dovranno necessariamente risiedere vicino a INVCAR, il che significa che potremo memorizzare tutti i vettori e i punta tori riguardanti it nostro sistema in una determinata area di memoria che chiameremo per comodita dati di sistema. Per ulteriori informazioni riguardo a questa blocco di memoria bastera fare riferimento aile Appendici Bl 0 B2. Riportiamo qui di seguito il listato della routine INVCAR:

INVCAR INVCAR STA CAR BEQFINE LDATVT [Link] LDACAR JSR VAl. I LDAPRINTR [Link] LDACAR JSR VAL 2 LDA USR BEQFINE LDACAR JSRVAl.3 RTS .BYTE 0 Salva it earattere Se non ce n'e ritorna senza stampare E attivo iI video? Se no, controlla la periferica suecessiva Se 51, indirizza indirettamente il carattere alia routine video E attiva la stampante? Se no, controlla la periferica suecess iva Se st. indirizza indirettamente il carattere alia routine stampante E attiva la routine utente? Se no, salta alia label FINE Se 51, indirizza indirettamente it carattere alia routine utente Ritorna al programma principale Questo byte contiene l'ultimo carattere inviato

[Link]

[Link]

FINE CAR

Chlamate VAI.l VAl. 2 VAl. 3

aile routine JMP (ROMTVT) JMP (ROMPRT) JMP (USROUT)

102

UTILITY DI STAMPA

Routine di output per caratteri speciali


INVCAR una routine di output generale; cerchiamo adesso di sviluppare una routine di output che ci permetta di svolgere Ie funzioni che sono richieste piu spesso. Per esempio, si presenta frequentemente la necessita di inviare un a capo (LF-Line Feed) e un ritorno carello (CR-Carriage Return) per posizionarsi sulla riga successive, oppure di lasciare spazi bianchi 0 di dover visualizzare byte in forma esadecimale. Quello che ci prefiggiarno e sviluppare alcune routine dedicate proprio a queste funzioni. Poiche ognuna di queste subroutine chiamera INVCAR, i caratteri potranno essere inviati a tutte Ie periferiche selezionate. Di seguito sono riportati i listati di queste tre routine:

CR·LF CR=$OD LF=$OA [Link] LDA #CR JSRINVCAR LDA #LF JSRINVCAR RTS Codice Codice ASCII ASCII di CR di LF Ie perife-

Invia un CR e LF a tutte che selezionate

SPAZIO SPAZIO LDA #$20 JSRINVCAR RTS BYTE [Link] PHA LSRA LSRA LSRA LSRA JSR ASCII JSRINVCAR Salva il byte Determina I'ASCII corrispondente ai 4 bit pili significativi Carica nell'accumulatore it codice ASCII corrispondente allo spazio e 10 invia aile periferiche attive

Invia attive

il carattere

aile

periferiche

UTILITY DI STAMPAI03

PLA JSR ASCII JSRINVCAR RTS

Determina

i'ASCII

dei 4 bit meno

significativi
Invia att ive

iI carattere

aile

periferiche

Invio ripetitivo
Poiche alcuni programmi potrebbero avere la necesaita di inviare piu di uno spazio 0 CRILF 0 altro carattere, perche non sviluppare alcune utility che permettano di inviare 10 stesso carattere ripetitivamente aile periferiche? In qualunque caso sara necessaria memorizzare nel registro X iI numero di r-ipetizioni richieste e poi chiamare la routine SPAll per inviare X spazi, oppure la routine CRLFX per inviare X a capo, oppure aneora la routine CARX per inviare X volte il carattere contenuto nell'accumulatore. Se iI valore del registro X zero, non verdi inviato alcun carattere. Per inviare sette spazi quindi sara necessario includere Ie seguenti linee di programma:

LDX #7 JSR SPAZI Per inviare quattro a capo:

LDX #4 JSR CRLFX Per

inviare dieci asterischi


LDX # 10 LDA #'. JSRCARX

(*):

Per poter utilizzare queste SPAZI, CRLFX e CARX. SPAZI·CARX SPAZI CARX LDA #$20 STXRIPETE

istruzioni

ci occorrono

tre piccole

subroutine:

Carica I'accumulatore zio Inizializza il contatore

con uno spadi ripetizione

104

UTILITY DI STAMP A

RPLOOP

PHA LDXRIPETE BEQ FINERI DEC RIPETE JSR INVCAR PLA CLC BCCRPLOOP PLA RTS

Salva it carattere da r-ipetere E stato inviato l'ulnmo carattere? Se st, esce dal loop, altrimenti decrementa il contatore Invia il carattere aile periferiche attive

FINERI

Ripete Pulisce

it

carattere 10 stack

se necessaria

CRLFX CRLFX CRLOOP STX RIPETE LDXRIPETE BEQ FINECR DEC RIPETE JSR [Link] CLC BCCCRLOOP RTS .BYTE [Link]

iI contatore

Se ha finito ritorna Decrementa il contatore Invia un a capo Contralla se era I'ultimo Se ha finite Questa byte

FINECR RIPETE

e usato

ritorna

come contatore

Come stampare un messaggio


Si potra presentare 1a necessita di visualizzare (0 stampare) un messaggio contenuto in una arbitraria locazione di memoria. A questa scopo svilupperemo una routine, che chiameremo [Link]. Per mezzo di questa routine potremo inviare un messaggio a tutte Ie un ita periferiche attive. Per pater funzionare sara necessaria prelevare tutti i caratteri che compongana it messaggio ad uno ad uno in maniera sequenziale e passarli alta routine. Anche in questa caso davremo far sapere alia routine in che locazioni di memoria presente iI messaggia e, come abbiama operata in precedenza, potremmo fare usa di un puntatore che sia inizializzato volta per volta con la locazione di partenza del messaggio da inviare. Questa soluzione pen) richiede due ulteriori byte per il puntatore. Potrerno usare un registro per specificare la locazione del puntatore che punta all'inizio del messaggio. Presumibilmente it programma principale in grade di trovare 2 byte in un'opportuna locaziane della pagina zero, an-

Potrebbero piacerti anche