Relazione su DigiChip 1.0
Transcript
Relazione su DigiChip 1.0
Loris Bindoni 1999 DigiChip 1.0 Relazione in lingua italiana Indice 1 Introduzione 2 Requisiti ed Implementazione 2.1 Analisi e specifica informale dei requisiti 2.2 Scelte implementative 3 L’algoritmo di Simulazione 3.1 L’algoritmo di Ford-Moore-Bellman 3.2 Da Ford-Moore-Bellman a DigiChip 1.0 3.3 L’algoritmo di simulazione di DigiChip 1.0 4 Architettura Statica 5 Interfacce di Classe 6 Scenari e Diagrammi Dinamici 6.1 Scenari 6.2 Diagrammi dinamici 7 Osservazioni Conclusive 7.1 Carenze, limitazioni ed errori 7.2 Sviluppi futuri 1 1 Introduzione. Alla base di DigiChip 1.0 c’è una constatazione pratica della difficoltà da parte di un hobbista o di uno studente di un corso di elettronica, di realizzare un prototipo di un circuito digitale. Chi ha sperimentato in prima persona quanto tediosa risulti la costruzione di questo tipo di circuiti, si sarà di certo accorto anche di come molto spesso ci sia il rischio di rompere i componenti stessi durante la prova dei circuiti e la necessità di un alimentatore, di una breadboard e di strumenti di misura faccia considerevolmente aumentare le spese iniziali. DigiChip 1.0 viene incontro a tutte queste necessità in modo completo, semplice ed intuitivo. Utilizzando una interfaccia grafica comune a molte altre applicazioni Windows 9x, l’utente può con facilità ed in poco tempo costruire e testare i propri circuiti elettronici digitali in standard TTL. La possibilità di salvare e caricare i circuiti su disco permette di distribuire le proprie creazioni anche ad altre persone o di mantenerle memorizzate per una successiva modifica o estensione. Il programma non è rivolto ai professionisti in quanto mette a disposizione un assortimento di componenti elettronici di base (alcuni dei quali non più in commercio) ma considerati comunque come ‘tipici’ e come tali oggetto ancora oggi di trattazioni teoriche. E’ invece chiaramente rivolto agli hobbisti ed ai corsi di elettronica e sistemi negli istituti tecnici superiori. DigiChip 1.0 è stato realizzato in ambiente elj-win32 v0.4, una distribuzione di GNU-SmallEiffel per Microsoft Windows 9x ed NT curata da Geoff Eldridge e che mette a disposizione la libreria grafica GRAPE ampiamente utilizzata per l’applicazione. Le immagini sono state realizzate con Paint-Shop-Pro 4. NOTA: Questo testo non si propone di sostituire il contenuto dei file readme.txt e manual.txt contenuti nella distribuzione ed il manuale online reperibile al sito http://www.geocities.com/~lbindoni/digichip.html ma ne è la diretta continuazione, occupandosi di descrivere in modo adeguato la struttura e l’implementazione del programma a partire dalle scelte effettuate. 2 2 Requisiti ed Implementazione. In questa sezione verranno elencati in modo informale i requisiti del programma. Verranno analizzate dapprima tutte le funzionalità richieste e successivamente verranno discusse le scelte implementative. Non tutte le scelte sono state fatte sulla base dell’efficienza e della semplicità, molte scelte sono state invece dovute all’uso intensivo fatto della grafica ed ai tempi limitati a disposizione per lo sviluppo dell’applicazione. In particolare va sottolineato fin da ora come la libreria GRAPE abbia notevolmente esteso le possibilità di sviluppo del programma anche grazie alla sua perfetta integrazione con Eiffel. E’ infatti notevole lo sforzo effettuato dai suoi sviluppatori allo scopo di realizzare una libreria grafica semplice e potente basata su classi, tale che la pregevole struttura di un linguaggio puro ad oggetti come Eiffel non venisse distrutta dall’introduzione di funzionalità grafiche. Ciò nonostante va comunque ricordato come GRAPE introduca i principi della programmazione ad eventi, tipica delle librerie grafiche per Windows, all’interno del programma, modellandone alcune caratteristiche. Nel seguito dell’analisi non verranno comunque prese in considerazione le classi e i metodi grafici utilizzati in quanto considerabili comunque come ‘aggiuntivi’ rispetto le funzionalità del programma. Molte delle scelte fatte saranno poi discusse anche nel capitolo 8. 3 2.1 Analisi e specifica informale dei requisiti. Il progetto prevede la costruzione di una applicazione in grado di permettere la costruzione ed il successivo test di funzionamento di prototipi di circuiti elettronici digitali secondo lo standard TTL su breadboard di montaggio. Saranno forniti strumenti grafici in grado di accelerare il processo di costruzione e di analisi del circuito. Il programma dovrà essere in grado di fornire principalmente le seguenti funzioni: 1. Creazione di un circuito mediante l’uso di fili elettrici (wires) e di componenti elettronici integrati (chips) su una breadboard con formato commerciale di 63 pit di larghezza. 2. Disponibilità di strumenti di verifica e di uso integrati (alimentatore, clock, switch, 8 segnali di ingresso ed 8 di uscita). 3. Possibilità di costruire circuiti sia di tipo combinatorio che sequenziale. 4. Possibilità di creare (ex-novo) un circuito, ma anche di caricarlo e di salvarlo su una qualunque unità di memorizzazione riconosciuta da windows. 5. Modifica di un circuito mediante aggiunta e rimozione di uno o più componenti. 6. Possibilità di definire il colore dei fili e di modellarne la forma in modo da migliorare la chiarezza e la leggibilità dei circuiti. 7. Simulazione di funzionamento del circuito. 8. Help online su Internet accessibile mediante browser. 9. Architettura del programma estendibile, cioè ampliabile con l’aggiunta di nuovi componenti elettronici a disposizione senza sconvolgere l’attuale struttura. Analizziamo ora i punti in dettaglio: 1. Sarà fornita una rappresentazione grafica fotorealistica di una breadboard di 63 fori di larghezza. Sulla breadboard sarà possibile inserire fili elettrici e componenti elettronici mediante l’uso del mouse. In particolare sarà disponibile un menù ed una speedbar (che sostituisce le voci di menù più frequentemente utilizzate) attraverso la quale sarà possibile selezionare il tipo di componente e il colore del filo da aggiungere. 2. Saranno disposti nell’area sottostante alla rappresentazione grafica della breadboard gli strumenti di verifica e di uso. In particolare sarà inserito un alimentatore per circuiti digitali provvisto di due pit (fori) di uscita: VCC e GND; un generatore di clock digitale (ad onda quadra con duty-cycle del 50%) a frequenza selezionabile mediante due piccoli pulsanti e provvisto di un unico pit di uscita: GND; 8 canali di ingresso digitali, ognuno con il proprio pit di uscita ed ognuno con il proprio livello selezionabile mediante pulsante; uno switch digitale a due posizioni, con il quale è possibile selezionare tra due ingressi distinti, quale trasferire in uscita; 8 canali di uscita, ognuno provvisto di un proprio indicatore di livello digitale. 3. Saranno forniti sia componenti elettronici (chip) basati su logica combinatoria (cioè per i quali le uscite dipendono solamente dagli ingressi), sia chip basati su logica sequenziale (cioè per i quali le uscite dipendono dagli ingressi e da uno stato interno). Per la prima categoria saranno forniti: porte logiche, codificatori, multiplexers, demultiplexers, comparatori, unità aritmetico-logiche e display; per la seconda categoria saranno invece forniti: flip-flops, registri e contatori. 4. Sarà data la possibilità di caricare e salvare i propri circuiti su qualunque unità di memorizzazione riconosciuta da Windows. Saranno offerte le consuete scelte di save, save_as e open accessibili anche da speedbar. 5. Sarà possibile operare delle modifiche su un circuito rimuovendo componenti (fili o chip) mediante l’operazione di remove, accessibile anche da speedbar. Sarà possibile altresì aggiungere o rimuovere componenti da un file caricato da disco. 6. Sarà fornita una lista di colori da assegnare ai fili elettrici di connessione che verranno creati da quel momento in poi. Sarà inoltre possibile modellare (shaping) i fili elettrici sulla breadboard in modo da ottimizzare la disposizione e migliorare la leggibilità dei circuiti realizzati, mediante l’inserimento del filo nel circuito in tre fasi distinte: collocazione dell’origine, collocazione del punto di flesso, collocazione della destinazione. 7. Sarà possibile avviare ed arrestare la simulazione del funzionamento del circuito mediante le selezioni di menù start e stop o mediante la pressione degli omonimi pulsanti sulla speedbar. Durante l’esecuzione della simulazione sarà possibile intervenire attivamente sulla simulazione agendo sui segnali di ingresso e sulla frequenza di clock. 4 8. Sarà prodotto un manuale online accessibile mediante connessione ad Internet. Il manuale sarà pubblicato alla pagina http://www.geocities.com/~lbindoni/digichip.html e, se nel proprio computer è installato Internet Explorer, l’accesso sarà automatico alla selezione di help online da menù. 9. Sarà possibile estendere notevolmente il programma aggiungendo nuovi chip all’elenco di quelli già esistenti, senza violare l’architettura attuale. DigiChip è stato infatti pensato con l’intento di fornire una base di partenza alla definizione dei componenti voluti, e la sua struttura è versatile e flessibile. 5 2.2 Scelte implementative. Una volta analizzato il problema si è cominciato a progettarne l’implementazione effettiva. Uno dei principali nodi da risolvere riguardava il modo in cui i fili elettrici di collegamento dovevano essere realizzati. Allo scopo di semplificare la realizzazione dell’algoritmo di simulazione si è preferito rappresentare i fili elettrici come fossero dei componenti elettronici e cioè componenti provvisti di un ingresso ed una uscita. Questo significa che in DigiChip i fili sono direzionali e cioè trasportano un segnale da un ingresso ad una uscita e durante la costruzione del circuito quale dei due capi sia di ingresso e quale di uscita deve essere dichiaratamente espresso (vedi manuale). A questo scopo è bene distinguere sin da ora il significato di due termini: Un filo elettrico di connessione è un componente elettronico inserito dall’utente durante la costruzione del circuito, viceversa una connessione elettronica (o elettrica) è un collegamento tra più pit implementato all’interno della breadboard e che si occupa di mantenere allo stesso valore elettrico i suoi pit (vedi struttura di una breadboard nel manuale). Un altro problema era relativo alla possibilità di inserire più segnali su di un’unica connessione. Questa possibilità in un circuito elettronico reale è quasi sempre sintomo di un errore commesso durante la progettazione. Raramente infatti si incontrano i cosiddetti and cablati (wired-and) cioè punti in cui sono collegate in un unico punto le uscite di più componenti elettronici. Si è perciò preferito escludere subito questa possibilità mediante un controllo statico sulle uscite (vedi manuale). Anche l’implementazione della breadboard influisce notevolmente sulla struttura del programma. Si è preferito implementarla nel modo più intuitivo e spontaneo, e cioè come un array bidimensionale. Ad ogni cella dell’array può essere collegato un componente elettronico: questo facilità l’accesso (posizione -> componente) e si è scelto di demandare al componente stesso le operazioni di recupero delle informazioni riguardo la posizione di ogni singolo pin del chip. Questo significa che possiamo accedere al livello elettrico di un foro (pit) della breadboard nel seguente modo: (posizione -> componente -> livello_pin), grazie al fatto che ogni componente possiede informazioni sulla propria struttura e sulla propria collocazione sulla breadboard. Un metodo di breadboard si occupa di gestire le connessioni elettriche tra i vari pit. E pit è una classe utilizzata più o meno come verrebbe utilizzata una struttura di dati in un linguaggio non ad oggetti: ha lo scopo di racchiudere in un unico oggetto quella che è la struttura base durante il processo di simulazione, e cioè il trasferimento di un segnale attraverso un grafo. Covered_pit è invece una classe dalla quale viene istanziato un oggetto che rappresenta un pit inaccessibile della breadboard. Una breadboard, infatti, non celle utilizzabili per tutti gli elementi di una matrice, ma alcune posizioni sono coperte da un rivestimento di plastica. I componenti elettronici sono inseriti anche in liste, in modo da accelerare notevolmente le operazioni di visualizzazione e ridisegno richieste dalla grafica. Proprio il ridisegno viene implementato in un’unica procedura allo scopo di accelerarne l’esecuzione: questo va certamente a scapito dell’eleganza dell’architettura del programma, ma l’aumento di prestazioni è risultato notevole. L’uso di due array (old_val e new) che mantengano traccia dei valori dei pin di ogni chip precedentemente e successivamente all’esecuzione di operation (il metodo che “fa funzionare il chip sugli ingressi”) ha permesso di implementare agevolmente tutti quei chip che “reagiscono” in funzione di variazioni dei segnali di ingresso anziché sulla base dei valori degli ingressi. E’ il caso, in particolare, dei circuiti in logica sequenziale che commutano sul fronte di salita (o di discesa) del clock. L’ultimo problema era costituito dalla necessità di gestire files su disco. A causa della possibilità da parte di SmallEiffel di gestire unicamente files di tipo testo si è provveduto a progettare un formato che risultasse di dimensioni compatte (in modo che i files rimangano di piccole dimensioni) ma comprensibile. In questo modo una limitazione di SmallEiffel si è tradotta in un miglioramento per il programma poiché i files risultano essere manualmente editabili. 6 3 L’algoritmo di Simulazione. La simulazione è l’operazione più importante e più complessa svolta da DigiChip. A questo scopo era necessario realizzare un algoritmo che ne implementasse in modo efficace ed efficiente le funzionalità. Si è dunque preferito procedere non inventando un nuovo algoritmo ad-hoc ma adattandone uno esistente (l’algoritmo di Ford-Moore-Bellman per la ricerca del cammino minimo in un grafo) al nostro caso. In 3.1, dopo avere esaminato in breve cos’è un grafo, verrà descritto l’algoritmo di Ford-Moore-Bellman ed analizzate le sue caratteristiche. In 3.2 verranno elencate tutte le operazioni di raffronto e di derivazione utilizzate per generare l’algoritmo di DigiChip 1.0. In 3.3 verrà compiutamente descritto l’algoritmo di simulazione di DigiChip 1.0. 7 3.1 L’algoritmo di Ford-Moore-Bellman. Prima di passare ad analizzare l’algoritmo è necessario fornire delle definizioni preliminari di teoria dei grafi. Un grafo orientato (in inglese directed-graph) G è costituito da un insieme N≠∅ di nodi e da un insieme A di archi, dove A⊆N×N è un insieme di coppie ordinate. Informalmente ciascun arco è orientato e va dal suo nodo iniziale al nodo finale. Due archi aventi un nodo in comune sono detti adiacenti. Un archi si dicono consecutivi quando il suo nodo iniziale di uno coincide con il nodo finale dell’altro. Un grafo si dice valutato se a ciascun arco del grafo è associato un numero reale detto valutazione (che può avere il significato di lunghezza, o costo o capacità o altro ancora...). Un cammino (in inglese path) P è una successione di archi α1, α2, ..., αk tale che ciascun arco αi è consecutivo ad αi-1 (i=2, 3, .., k). Si consideri un grafo orientato e valutato G = (N, A) e si denoti con l(α) o con d(i, j) la valutazione associata al generico arco α = (i, j). Tale valutazione, nel seguito detta anche lunghezza dell’arco (i, j), può essere positiva, negativa o nulla. Dato un cammino P = (α1, α2, ..., αk) si definisce come lunghezza del cammino stesso la somma delle lunghezze degli archi che compongono il cammino. L’algoritmo di Ford-Moore-Bellman viene utilizzato per la ricerca del cammino minimo da un nodo a tutti gli altri nodi di un grafo e può essere utilizzato anche in grafi orientati in cui qualche arco ha lunghezza negativa a condizione però che non esista alcun circuito di lunghezza negativa. Se un circuito del genere esistesse, allora inserendolo un numero arbitrariamente grande di volte in un cammino fra due nodi, si otterrebbe una lunghezza di segno negativo arbitrariamente grande e quindi il cammino minimo non sarebbe definito. Descrizione dell’algoritmo: Ad ogni nodo v si associano l’etichetta l(v) che rappresenta la lunghezza del miglior cammino da s a v correntemente trovato, e p(v) che rappresenta il predecessore di v nel suddetto cammino. Se non si è ancora trovato un cammino tra s e v, si pone: l(v) = ∞, p(v) = 0. • • • PASSO 1. (Inizializzazione) Si pone: l(s) := 0, p(s) := s l(v) := ∞, p(v) := 0 ∀ v ≠ s PASSO 2. (Criterio di arresto) Si seleziona un arco (u, v) in base ad un particolare criterio. Se l(u) + d(u, v) < l(v), allora si va al passo 3. Se invece l(u) + d(u, v) ≥ l(v), ∀ (u, v) ∈ A, allora l’algoritmo ha termine. PASSO 3. (Assegnamento) Si pone: l(v) := l(u)+ d(u, v) p(v) := u Si torna al passo 2. Ai fini dell’implementazione, e quindi dell’efficienza dell’algoritmo, l’ordine determinato dal criterio con cui vengono esaminati gli archi al Passo 2 ha notevole rilevanza. I due criteri più diffusi fanno uso di una lista dei nodi Q. Inizialmente si pone Q = {s}. L’ordine con cui esaminare al Passo 2 gli archi (u, v) viene stabilito in base al seguente criterio. Si prende il primo vertice di Q, cioè, se Q = {q1, q2, ..., qk} allora si cancella q1 dalla lista Q: Q := Q \ {q1}, si pone u = q1 e si considerano gli archi che escono da u. 8 Si opera il confronto l(u) + d(u, v) < l(v) per tutti i nodi v adiacenti ad u. Se esiste un vertice v’ tale che l(u) + d(u, v’) < l(v’), allora, oltre a cambiare l’etichetta del nodo v’ si inserisce il nodo v’ nella lista stessa (sempre che esso non vi sia già presente): Q := Q ∪ {v’} L’inserimento di v’ in Q può avvenire nei due modi: 1- Per il criterio FIFO, v’ viene inserito in coda alla lista stessa. 2- Per il criterio di PAPE, se è la prima volta che v’ viene inserito, esso deve essere posto in coda alla lista; se invece v’ era già stato inserito in precedenza, allora si pone all’inizio della lista stessa. Nel caso esista nel grafo un circuito di lunghezza negativa l’algoritmo non terminerà, è perciò sufficiente contare quante volte un nodo verrà esaminato per riconoscere la presenza di questo tipo di circuiti. Osservazioni sulla complessità computazionale: Posto n := |N| ed m := |A| è facile verificare che la versione FIFO dell’algoritmo ha complessità computazionale O(nm). La versione PAPE presenta invece complessità esponenziale pur se nella pratica si comporta in maniera particolarmente veloce soprattutto per grafi sparsi (cioè con pochi archi) nel caso medio. 9 3.2 Da Ford-Moore-Bellman a DigiChip 1.0. Un’analisi anche sommaria dell’algoritmo di Ford-Moore-Bellman può facilmente far intuire come vi siano parecchie analogie con il caso di simulazione di funzionamento di un circuito elettronico. Innanzitutto è necessario raffrontare la definizione di grafo con quella di circuito elettronico digitale, modellando quest’ultimo in modo da poterlo inserire nell’algoritmo opportuno. Un circuito elettronico (in inglese electronic-circuit) E è costituito da un insieme C≠∅ di componenti elettronici (chip e fili elettrici) e da un insieme L di connessioni di breadboard (utilizzate, cioè sulle quali è inserito un pin di output ed almeno un pin di input), dove L⊆Co×Ci è un insieme di coppie ordinate di pin tale che Co è l’insieme di tutti i pin di uscita di tutti i componenti elettronici e Ci è l’insieme di tutti i pin di ingresso di tutti i componenti elettronici. Informalmente, ogni componente elettronico c∈C è rappresentato da un nodo provvisto di un insieme Ci di pin di ingresso e da un insieme Co di pin di uscita tale che ogni connessione l∈L è orientata e cioè connette un pin di uscita di un componente elettronico con un pin di ingresso di un altro componente elettronico. Da ogni pin di uscita può partire un numero qualunque (anche nullo) di connessioni, ad ogni pin di ingresso può arrivare al più una sola connessione. La rappresentazione di un componente elettronico (chip e wire) risulta essere cioè la seguente: Ci C Co 1 2 3 4 5 7 9 Ci C Co S WIRE E 6 CHIP LS7400 8 10 12 11 13 14 Un circuito elettronico si dice digitale se a ciascuna connessione di breadboard del circuito è associato un valore booleano a sua volta associato ad un livello elettrico. A partire da questa definizione si può ora iniziare a progettare il simulatore. L’idea è quella di eseguire l’algoritmo in modo che le variazioni dei livelli di ingresso si ripercuotano sulle uscite, cioè a partire da un ingresso (vertice di origine) il cui valore è variato si calcolano le variazioni prodotte su tutti gli altri vertici: questo può essere facilmente assimilato al problema della ricerca del cammino minimo da un nodo a tutti gli altri, infatti il concetto di propagazione del miglioramento di una soluzione è pressoché identico al concetto di propagazione della variazione di un segnale: in entrambi i casi se un nodo (componente) ha migliorato (modificato) la propria distanza (il proprio valore), allora è possibile che il miglioramento (la variazione) si propaghi ai successivi nodi (componenti). Analizzando l’algoritmo di Ford-Moore-Bellman è anche facile intuire come un’altra caratteristica risulti necessario definire: Il procedimento di esplorazione delle distanze viene inizialmente eseguito con tutti i nodi impostati al valore di infinito (∞), questa distanza viene utilizzata nella pratica come indicatore di ‘nodo irraggiungibile’ in modo che con qualunque valore parziale si pervenga al nodo il percorso trovato costituisca comunque un miglioramento della soluzione. E’ dunque necessario definire un valore aggiuntivo ai due valori digitali. Per raggiungere questo obiettivo verrà utilizzato il tipo integer in sostituzione del tipo boolean come indicativo dei livelli logici nei circuiti. Al valore 0 verrà associato il valore logico FALSE e il livello elettrico di GND, al valore 1 verrà associato il valore logico TRUE e il livello elettrico di VCC mentre al valore –1 verrà associato il valore logico di indefinito e perciò un livello elettrico inconsistente (riconosciuto come GND o VCC a seconda dei casi). 10 Questo può essere in qualche modo paragonato al caso reale in cui un ingresso scollegato (cioè flottante) di un chip viene riconosciuto dal chip talvolta come livello alto (VCC) e altre volte come livello basso (GND). L’introduzione di questo nuovo valore non risolve unicamente il problema legato all’interpretazione del livello logico di ingressi flottanti, ma anche il problema del controllo dell’alimentazione. Inizialmente tutte le connessioni si trovano a questo stato di inconsistenza, e la prima fase dell’algoritmo si occupa di impostare viceversa ad uno stato di consistenza e coerenza tutto il circuito. Per raggiungere lo scopo viene eseguito l’algoritmo calcolando la variazione dei segnali come conseguenza dello stato iniziale degli ingressi: i primi due ingressi sono ovviamente gli ingressi di alimentazione, gli altri ingressi sono dati dal clock e dalla posizione dei selettori digitali. Abbiamo analizzato come l’algoritmo di Ford-Moore-Bellman non possa essere utilizzato in grafi in cui siano presenti cicli di lunghezza negativa. Nella versione modificata questo limite si rispecchia nell’impossibilità di simulare con pieno successo circuiti astabili (talvolta definiti anche oscillatori), cioè circuiti che non raggiungano (in assenza di variazioni nei segnali di ingresso) uno stato stabile entro un certo tempo. Poiché il circuito viene realizzato inserendo i componenti su di una breadboard di dimensioni limitate è stato possibile evitare che l’applicazione perdesse il controllo sull’algoritmo imponendo un limite al numero di passi (nel programma indicati come ministeps) ed al numero di elementi nella lista Q di supporto. Se non si fosse imposto questo limite non si sarebbe potuto mantenere il controllo sullo svolgimento della simulazione (con la possibilità di arrestarla da programma). Giunto a questo limite, il programma segnala con un opportuno messaggio di errore che il circuito è astabile (cioè oscillante) o troppo complesso. In realtà non è possibile con i componenti disponibili costruire un circuito stabile che raggiunga questo limite di complessità, ma sarebbe possibile definire dei nuovi componenti provvisti di più stati e con questi costruire circuiti che raggiungano questo livello, e perciò è stato deciso di includere questa informazione nel messaggio di errore. Il dato relativo al predecessore, visto in Ford-Moore-Bellman, non ha invece nessuna rilevanza per DigiChip dato che non è nel nostro interesse sapere in che direzione si propaghino le variazioni ma solo a quali valori portino. Per quanto riguarda la scelta di quale delle due versioni dell’algoritmo andare ad implementare (FIFO o PAPE) è stata preferita la prima possibilità. Difatti, da una prova pratica, è emerso come il comportamento secondo PAPE, male si adatta ad un circuito elettronico dove il grafo relativo è tutt’altro che sparso, inoltre, anche se l’algoritmo secondo PAPE offre risultati migliori nel caso medio, tale proprietà è vanificata dal fatto che in particolari condizioni la complessità può diventare inaccettabile: queste profonde oscillazioni di prestazioni degradano la qualità di un programma che simula il comportamento di un circuito in conseguenza (anche) alla temporizzazione di un clock e cioè quando si richiede una qualche uniformità nelle prestazioni. 11 3.3 L’algoritmo di simulazione di DigiChip 1.0. Dato un circuito elettronico digitale E = (C, L) dove C≠∅ ed L⊆Co×Ci. Ad ogni pin p (o pit, cioè foro sulla basetta, dato che ad ogni pin può essere associato il pit sul quale è stato collocato) si associa l’etichetta l(p) che rappresenta il valore elettrico corrente del pin (0, 1 o –1). Q è una lista di pin (o pit) gestita come FIFO. I è l’insieme dei pin relativi agli ingressi dell’applicazione (cioè i due ingressi di alimentazione, l’ingresso di clock e gli 8 ingressi numerati). • • • • PASSO 1. (Inizializzazione) Si pone: l(s) := valore_iniziale_di_s, ∀ s∈I l(v) := −1, ∀ v ∉ I Q := I contatore := 1 PASSO 2. (Criterio di arresto) Se Q = ∅, allora l’algoritmo si arresta (rimane in attesa di un passo di aggiornamento). Se Q ha più di max elementi o contatore>max allora arresta l’algoritmo e segnala che il circuito è instabile o troppo complesso. Altrimenti: q := first(Q) /* L’elemento pin q viene letto dalla lista Q */ q := remove_first(Q) /* L’elemento pin q viene rimosso dalla lista Q */ contatore := contatore + 1 PASSO 3. (Assegnamento) Sia c il componente elettronico al quale q appartiene: c.operation() /* Viene fatto “funzionare” il componente elettronico sui nuovi ingressi */ Sia H una lista FIFO di supporto formata da tutti i pin di uscita di c il cui valore è stato modificato dall’esecuzione di operation. ∀ h ∈ H e ∀ k ∈ Ci tale che (h, k) ∈ L: l(k) := l(h) /* Assegna al pin k il livello del pin h */ Q := add_last(k) /* Accoda il pin k alla lista Q */ Torna al passo 2 PASSO DI AGGIORAMENTO Ad ogni modifica di un valore di ingresso associato ad un nodo s ∈ I: Q := add_last(s) /* Accoda il pin s alla lista Q */ contatore := 1 Vai al passo 2 12 4 Architettura Statica Nello schema seguente viene riportata l’architettura statica essenziale del programma secondo la notazione BON. Per motivi tecnici il simbolo di doppia linea continua è stato sostituito da una linea singolo tratteggiata ed il simbolo di parentesi graffa è stato sostituito da un simbolo a tridente. ABOUT SELECT _ DLG INPUTS CLOCK MAIN WORKBENCH SWITCH PIT LS.../HD... BREADBOARD CHIP * WIRE COVERED_PIT E_COMPONENT * Ecco una breve descrizione delle classi coinvolte: MAIN: Classe principale che si occupa della gestione della finestra di windows e degli eventi generati durante il funzionamento dell’applicazione. Possiede le classi di about, dialog e workbench. ABOUT: Implementa la finestra di visualizzazione delle informazioni sull’autore e sul programma. SELECT_DLG: Implementa la finestra di selezione del chip da aggiungere quando si preme il pulsante di add-chip sulla speedbar. WORKBENCH: La classe worbench è senza dubbio la classe più importante dell’intera applicazione. Possiede e si occupa di gestire le classi inputs, clock, switch e breadboard. Essa rappresenta il vero e proprio banco di lavoro, in quanto implementa sia le funzioni di costruzione del circuito (aggiunta e rimozione di componenti) che di modifica (cancellazione di componenti) come pure le operazioni di lettura e scrittura sui file e, soprattutto, implementa l’algoritmo di simulazione. INPUTS: Gestisce e rappresenta gli 8 ingressi digitali. CLOCK: Gestisce e rappresenta il generatore di clock. SWITCH: Gestisce e rappresenta lo switch digitale. BREADBOARD: Rappresenta la breadboard sulla quale vengono inseriti i componenti e ne gestisce le connessioni elettriche. E_COMPONENT: E’ la classe dalla quale ereditano chip, wire e covered_pit. In essa sono implementate tutte quelle funzionalità comuni ad un chip, ad un filo elettrico di connessione e ad un foro non accessibile della breadboard. 13 CHIP: E’ la classe dalla quale ereditano tutti i tipi di chip e fornisce tutte le funzionalità di base comuni ad essi. Eredita da e_component. LS.../HD...: Classi che ereditano da chip ed implementano le caratteristiche specifiche ed il funzionamento corretto di ogni modello di circuito elettronico o display. WIRE: Implementa un filo elettrico di connessione ereditando da e_component. COVERED_PIT: Implementa una posizione della breadboard non accessibile (cioè una posizione ove la breadboard non è forata). Eredita da e_component. PIT: Viene utilizzata come struttura di base durante l’operazione di simulazione ed è altresì utilizzata per lo scambio di informazioni tra la classe breadboard e la classe workbench. Associa ad una posizione sulla breadboard il suo valore digitale. In realtà la struttura statica del programma è molto più complessa (sempre escludendo le classi relative alla grafica) e cioè: WBCONST COMMANDS INPUTS SELECT _ DLG SBAR_RESPONDER CLOCK ABOUT MAIN WORKBENCH SWITCH RESCONST PIT LS.../HD... BREADBOARD COVERED_PIT CHIP * WIRE E_COMPONENT * Ecco una breve descrizione delle classi aggiunte: COMMANDS: Dichiarazione delle costanti relative ai codici di comando ricevuti dal programma al verificarsi di specifici eventi. RESCONST: Dichiarazione delle costanti relative alle risorse (immagini, icone e cursori) caricate dal programma. WBCONST: Dichiarazione delle costanti relative ad operazioni specifiche della classe workbench. SBAR_RESPONDER: Si occupa di visualizzare le hints quando il cursore del mouse viene sovrapposto ad un pulsante della speedbar. Come si può facilmente vedere, più complessa risulta essere anche la relazione che intercorre tra le classi. In realtà molte relazioni sono state introdotte per ovviare a problemi dovuti alle funzionalità grafiche del programma. Tutto ciò, per quanto funzionale ed inevitabile, ha prodotto una qualche perdita di eleganza nell’architettura generale dell’applicazione. 14 5 Interfacce di Classe Verranno ora presentate le interfacce delle classi realizzate per DigiChip 1.0. In realtà non tutte le classi vengono presentate in questa sezione. Si è scelto di evitare di inserire in questa sezione la classe CURSOR che ha il solo scopo di fornire un costruttore aggiuntivo alla classe della libreria GRAPE “GRAPHIC CURSOR”. Questo nuovo costruttore risulta essere infatti indispensabile per l’uso di cursori grafici caricati da files e verrà per questo incluso nelle prossime release di elj-win32. Si è inoltre scelto di non includere le interfacce di tutti i modelli di chip disponibili nel programma, ma solo di alcuni. Per l’esattezza di: • Un chip basato su logica combinatoria (LS7400). • Un chip basato su logica sequenziale (LS7474). • Un display a 7-segmenti (HD1107). Le classi vengono presentate in ordine alfabetico. 15 -- The ABOUT window (information about the program) class interface ABOUT inherit DIALOG rename make as dlg_make redefine on_clicked, on_paint, set_default_style end COMMANDS RESCONST creation make feature {ANY} make (This_app : STRING) set_default_style -- set the style of the window to modal on_paint : INTEGER -- callback: draw the content of the window on_clicked (element : TILE) : INTEGER -- callback: close the about window when the button is clicked end interface -- class ABOUT BREVE DESCRIZIONE: La classe about si occupa di implementare la finestra di about con le informazioni sull’autore e sul programma. Il costruttore riceve in ingresso il nome dell’applicazione (cioè il nome completo del file eseguibile) dal quale caricherà il logo dell’applicazione. Set_default_style è stata ridefinita affinché la finestra di about sia di tipo modale (cioè sempre in primo piano e tale da mantenere il controllo dell’applicazione finché non verrà chiusa). 16 -- The breadboard is used to represent and to manage pits and electronic components class interface BREADBOARD creation make feature {ANY} make (parent : WORKBENCH) add_chip (chip : CHIP; x, y : INTEGER) : BOOLEAN -- add a chip to the breadboard with up-left pin in (x, y) position add_wire (wire : WIRE; x, y : INTEGER) : BOOLEAN -- add a wire to the breadboard with source point placed in (x, y) get_node_list (pit : PIT) : LINKED_LIST[PIT] -- get list of non-output pits (nodes) electronically linked by the breadboard has_output (x, y : INTEGER) : BOOLEAN -- has the current position an output electronically linked by the breadboard? is_empty (x, y : INTEGER) : BOOLEAN -- is the pit in the current position empty? is_in_board (x, y : INTEGER) : BOOLEAN -- is the pit in the current position inside the breadboard area? remove (x, y : INTEGER) : BOOLEAN -- has been removed the e-component placed in (x, y) position? chips_list : TWO_WAY_LINKED_LIST[CHIP] -- list of all chips placed in the breadboard wires_list : TWO_WAY_LINKED_LIST[WIRE] -- list of all wires placed in the breadboard board_scheme : FIXED_ARRAY2[E_COMPONENT] -- the matrix representation of all pit cells feature {NONE} covered_pit : COVERED_PIT -- the e_component that covers inaccessible pits workbench : WORKBENCH -- the workbench that manage the breadboard end interface -- class BREADBOARD BREVE DESCRIZIONE: La classe breadboard rappresenta l’implementazione della breadboard ed in particolare delle connessioni elettriche su di questa presenti. Sono presenti metodi per l’aggiunta e la rimozione di componenti elettronici e metodi per il controllo di pit sulla breadboard. Particolarmente importante è il metodo get_node_list che, dato un pit sulla breadboard, restituisce una lista di pit collegati elettricamente sulla breadboard che siano pit di ingresso per altri componenti elettronici. Get_node_list viene utilizzato ampiamente durante lo svolgimento delle operazioni di simulazione. 17 -- A chip is a monolithic integrated circuit, of the TTL family, in a dual in-line package (DIP) deferred class interface CHIP inherit E_COMPONENT creation make feature {ANY} is_output (x, y : INTEGER) : BOOLEAN is_chip : BOOLEAN is TRUE paint (dgc : DISPLAY_GRAPHICS_CONTEXT; x, y : REAL) -- paint chip inside the package draw (wbc : WORKBENCH ; x, y : REAL) is -- paint self-redrawing chips insertion (x, y : INTEGER) -- insert the up-left pin of the chip in x, y position remove (breadboard : BREADBOARD) set_input (wbc : WORKBENCH; pit : PIT) : LINKED_LIST[PIT] reset reset_state -- reset the state of sequential-logic chips operation -- all operations performed by the chip when an input is changed chip_type : INTEGER is deferred end -- univocal code of the chip type chip_width : INTEGER is deferred end -- the width (in pins per side) of the chip output_pins : ARRAY[INTEGER] is deferred end -- list of chip pins defined as output name : STRING is deferred end -- the name of the chip type x_pos, y_pos : INTEGER -- the position where the up-left pin has been inserted feature {NONE} new, old_val : ARRAY[INTEGER] -- the pins' logical level before and after "operation" end interface -- class CHIP BREVE DESCRIZIONE: La classe chip è una classe astratta e fornisce un’interfaccia per tutti i tipi di chip utilizzati dall’applicazione (sia di tipo combinatorio che sequenziale) come pure per il display HD1107. In particolare new ed old_val sono i due array che mantengono traccia dei livelli elettrici dei pin del chip prima e dopo l’esecuzione del metodo operation. Il confronto tra i valori assunti dai due diversi array è utilizzato durante il processo di simulazione. 18 -- Clock controls the speed of the clock pulse generator class interface CLOCK creation make feature {ANY} make (container : WORKBENCH) on_clicked (element : TILE; x_orig, y_orig : REAL) : BOOLEAN -- operations to do when clock buttons are pressed on_size (x_orig, y_orig : REAL) -- move buttons according to window resizing speed : INTEGER -- returns the clock speed (in hertz) pulse -- toggle the clock level (generate a pulse edge) value : INTEGER -- returns the current pulse level (0 or 1) feature {NONE} workbench : WORKBENCH -- the workbench that contains the clock inc_freq : TEXT_BUTTON -- increase-frequency button dec_freq : TEXT_BUTTON -- decrease-frequency button clock_speed : INTEGER -- the current clock speed in hertz val_pulse : INTEGER -- the current level of the pulse initial_clock_speed : INTEGER is 3 -- the clock speed when application starts max_clock_speed : INTEGER is 50 -- the maximal clock speed step_clock_speed : INTEGER is 1 -- the clock speed step when increasing or decreasing end interface -- class CLOCK BREVE DESCRIZIONE: La classe clock gestisce i pulsanti e le operazioni del clock durante tutta l’esecuzione del programma. Sono inoltre impostati dei limiti alla selezione della frequenza del clock. 19 -- Commands code used by the application class interface COMMANDS feature {ANY} Idm_quit, Idm_new, Idm_open, Idm_save, Idm_saveas, Idm_start, Idm_stop, Idm_help, Idm_about, Idm_add_chip, Idm_add_wire, Idm_remove, Idm_def_col, Idm_yellow, Idm_red, Idm_green, Idm_blue, Idm_magenta, Idm_cyan, Idm_brown, Ctx_start, Ctx_stop : INTEGER is unique Idm_7400 : INTEGER is 400 Idm_7402 : INTEGER is 402 Idm_7404 : INTEGER is 404 Idm_7408 : INTEGER is 408 Idm_7410 : INTEGER is 410 Idm_7420 : INTEGER is 420 Idm_7427 : INTEGER is 427 Idm_7432 : INTEGER is 432 Idm_7486 : INTEGER is 486 Idm_74266 : INTEGER is 4266 Idm_7442 : INTEGER is 442 Idm_7448 : INTEGER is 448 Idm_74151 : INTEGER is 4151 Idm_74138 : INTEGER is 4138 Idm_7485 : INTEGER is 485 Idm_74181 : INTEGER is 4181 Idm_7474 : INTEGER is 474 Idm_74112 : INTEGER is 4112 Idm_74194 : INTEGER is 4194 Idm_74190 : INTEGER is 4190 Idm_1107 : INTEGER is 107 end interface -- class COMMANDS BREVE DESCRIZIONE: La classe commands definisce costanti utilizzate dal programma, ed in particolare dalla classe main e dalla classe workbench. 20 -- A covered-pit is a cell of the breadboard closed by the plastic cover class interface COVERED_PIT inherit E_COMPONENT creation make feature {ANY} is_output (x, y : INTEGER) : BOOLEAN is_chip : BOOLEAN is FALSE remove (breadboard : BREADBOARD) set_input (wbc : WORKBENCH; pit : PIT) : LINKED_LIST[PIT] reset end interface -- class COVERED_PIT BREVE DESCRIZIONE: La classe covered_pit, derivata da e_component, è una classe della quale verrà istanziato un unico oggetto. Questo oggetto rappresenterà la copertura plastica presente sopra alcuni fori (pits) della breadboard e che ha lo scopo di evitarne l’uso per l’inserimento di altri componenti. Sebbene l’uso di questa classe si sarebbe potuto agevolmente evitare, la sua introduzione ha migliorato l’efficienza di alcuni metodi chiave utilizzati durante il processo di simulazione aumentandone significativamente la velocità di esecuzione. 21 -- An e_component is a chip or a wire or a covered pit deferred class interface E_COMPONENT feature {ANY} is_output (x, y : INTEGER) : BOOLEAN -- is the pin placed in (x, y) an output pin for the e_component? is_chip : BOOLEAN -- is the e_component a chip? set_input (wbc : WORKBENCH; pit : PIT) : LINKED_LIST[PIT] -- set a pit of the e_component, an return a list of pit consequently varied reset -- reset the logical level of all e_components pins remove (breadboard : BREADBOARD) -- remove the e_component from the breaboard end interface -- class E_COMPONENT BREVE DESCRIZIONE: La classe e_component è una classe astratta da cui derivano le classi chip, wire e covered_pit. 22 class interface HD1107 inherit CHIP redefine paint, draw end creation make feature {ANY} chip_type : INTEGER is 107 chip_width : INTEGER is 5 output_pins : ARRAY[INTEGER] paint (dgc : DISPLAY_GRAPHICS_CONTEXT; x, y : REAL) -- is used for window redrawing draw (wbc : WORKBENCH ; x, y : REAL) -- used to paint the display content everytime an input changes name : STRING is "1107" end interface -- class HD1107 BREVE DESCRIZIONE: La classe HD1107 implementa il display grafico a 7 segmenti disponibile ed utilizzabile nella costruzione dei circuiti elettronici. Il metodo paint viene utilizzato durante il processo di redrawing della finestra, mentre il metodo draw svolge la funzione duale di operation per gli altri chip e cioè quella di effettuare un aggiornamento delle proprie uscite (in questo caso l’aspetto grafico) in conseguenza alla variazione di un suo segnale di ingresso. 23 -- Inputs controls the level of the input channels class interface INPUTS creation make feature {ANY} make (container : WORKBENCH) on_clicked (element : TILE; x_orig, y_orig : REAL) : BOOLEAN -- operations to do when input buttons are pressed on_size (x_orig, y_orig : REAL) -- move buttons according to window resizing feature {NONE} workbench : WORKBENCH -- the workbench that contains the inputs buttons : FIXED_ARRAY[TEXT_BUTTON] -- the input buttons buttons_state : FIXED_ARRAY[BOOLEAN] -- the logical level of the inputs end interface -- class INPUTS BREVE DESCRIZIONE: La classe inputs gestisce gli otto pulsanti relativi ai canali di ingresso del workbench e dei relativi livelli elettrici. 24 class interface LS7400 inherit CHIP redefine operation end creation make feature {ANY} chip_type : INTEGER is 400 chip_width : INTEGER is 7 output_pins : ARRAY[INTEGER] operation name : STRING is "7400" end interface -- class LS7400 BREVE DESCRIZIONE: La classe LS7400 rappresenta l’implementazione di un chip basato su logica combinatoria. Si tratta di un chip contenente 4 porte logiche integrate (nand). 25 class interface LS7474 inherit CHIP redefine operation, reset_state end creation make feature {ANY} chip_type : INTEGER is 474 chip_width : INTEGER is 7 output_pins : ARRAY[INTEGER] operation state1, state2 : INTEGER – the internal state of the two flip-flops reset_state name : STRING is "7474" end interface -- class LS7474 BREVE DESCRIZIONE: La classe 7474 rappresenta l’implementazione di un chip basato su logica sequenziale. Si tratta di due flip-flops di tipo D in un unico chip. Da notare la presenza di due variabili contenenti lo stato interno di ciascun flip-flop e la ridefinizione del metodo reset_state per effettuarne l’azzeramento iniziale. 26 -- Main class class interface MAIN inherit APPLICATION rename make as app_make redefine on_create, make_menu, make_speedbar, can_destroy, on_command, make_desktop end COMMANDS RESCONST creation make feature {ANY} can_destroy : INTEGER -- callback: when exiting from application on_create : INTEGER -- executed when the main window is made up filter_table : ARRAY[STRING] -- generate the array of file formats on_command (cmd : INTEGER) : INTEGER -- callback: called when the window receives a command from menu or speedbar make_menu : MENU -- create the menu items make_speedbar : SPEEDBAR -- make the speedbar buttons and add the speedbar responder make_desktop : DESKTOP -- make the desktop as a void desktop set_need_save -- set the need_save flag to true feature {NONE} remove_color_mark -- remove the v-mark from all color menu items feature {ANY} This_app : STRING -- name of current application file wire_color : COLOR -- color used for painting new wires file_name : STRING -- the name of the circuit file currently open feature {NONE} need_save : BOOLEAN -- the file on the breadboard need to be saved win : WORKBENCH -- the workbench of the application rsp : SBAR_RESPONDER -- the speedbar responder open_dlg : FILE_DIALOG -- dialog window used to open files save_dlg : FILE_DIALOG -- dialog window used to save files color_yellow : MENU_ITEM -- the color_yellow item of the menu 27 color_red : MENU_ITEM -- the color_red item of the menu color_green : MENU_ITEM -- the color_green item of the menu color_blue : MENU_ITEM -- the color_blue item of the menu color_magenta : MENU_ITEM -- the color_magenta item of the menu color_cyan : MENU_ITEM -- the color_cyan item of the menu color_brown : MENU_ITEM -- the color_brown item of the menu color_other : MENU_ITEM -- the color definable item of the menu end interface -- class MAIN BREVE DESCRIZIONE: La classe main si occupa di gestire l’aspetto complessivo del programma. In particolare possiede e gestisce le singole finestre, come pure l’intero menù e la speedbar. 28 -- A pit is a cell of the breadboard with a digital level class interface PIT creation make feature {ANY} make (val, ax, ay : INTEGER) value, x, y : INTEGER end interface -- class PIT BREVE DESCRIZIONE: La classe pit è utilizzata per lo scambio di dati tra le classi workbench e breadboard. Ogni oggetto di tipo pit fornirà l’associazione tra una posizione sulla breadboard ed il suo livello elettrico. E’ ampiamente utilizzata durante il processo di sumulazione. 29 -- Resource constants class interface RESCONST feature {ANY} Icon_app : INTEGER is 20001 Butt_new : INTEGER is 20002 Butt_open : INTEGER is 20003 Butt_save : INTEGER is 20004 Butt_chip : INTEGER is 20005 Butt_wire : INTEGER is 20006 Butt_remv : INTEGER is 20007 Butt_start : INTEGER is 20008 Butt_stop : INTEGER is 20009 Breadboard : INTEGER is 20010 Chip : INTEGER is 20011 Wire_in : INTEGER is 20012 Wire_out : INTEGER is 20013 Wire_through : INTEGER is 20014 Comp_remv : INTEGER is 20015 Logo : INTEGER is 20016 Chip_left : INTEGER is 20017 Chip_right : INTEGER is 20018 end interface -- class RESCONST BREVE DESCRIZIONE: La classe resconst definisce le costanti utilizzate per l’indirizzamento delle risorse (immagini, cursori e icone) che verranno collegate all’applicazione durante la fase di linking del programma. 30 -- The speedbar responder displays hints when the mouse cursor is over a speedbar button class interface SBAR_RESPONDER inherit SPEEDBAR_RESPONDER redefine on_hint_string_request end COMMANDS creation make feature {ANY} on_hint_string_request (tile : TILE) : STRING -- return a string according to the button under the mouse cursor end interface -- class SBAR_RESPONDER BREVE DESCRIZIONE: La classe speedbar (ridefinita da speedbar_responder) si occupa di fornire le stringhe di informazione (hints) che verranno visualizzate ogniqualvolta il cursore del mouse sarà sovrapposto ad un pulsante della speedbar. 31 -- The SELECT_DLG is the chip selection dialog class interface SELECT_DLG inherit DIALOG rename make as dlg_make redefine on_clicked, set_default_style end COMMANDS creation make feature {ANY} set_default_style -- set the windows style to modal on_clicked (element : TILE) : INTEGER -- when the button is pressed, close window returning the selection code feature {NONE} list_box : LIST_BOX -- the list of selectable chips end interface -- class SELECT_DLG BREVE DESCRIZIONE: La classe select_dlg implementa la finestra di selezione del tipo di chip e viene visualizzata quando viene selezionato il pulsante di add-chip della speedbar. La finestra è definita come modale, non è perciò possibile accedere ad altre funzionalità del programma finché la finestra non è stata chiusa. 32 -- Switch controls the position of the switch class interface SWITCH creation make feature {ANY} make (container : WORKBENCH) on_clicked (element : TILE; x_orig, y_orig : REAL) : BOOLEAN -- operations to do when switch button is pressed on_size (x_orig, y_orig : REAL) -- move button according to window resizing level_of : BOOLEAN -- returns the position of the switch feature {NONE} workbench : WORKBENCH -- the workbench that contains the switch button : TEXT_BUTTON -- the switch button button_state : BOOLEAN -- the position of the switch end interface -- class SWITCH BREVE DESCRIZIONE: La classe switch gestisce lo switch digitale presente sul workbench. Lo switch permette di selezionare un’uscita tra due diversi ingressi ed il suo funzionamento è bloccato durante l’esecuzione della simulazione. 33 -- Constants used by the workbench class interface WBCONST feature {ANY} Null_state, Component, Start_wire, End_wire, Through_wire, Remove : INTEGER is unique end interface -- class WBCONST BREVE DESCRIZIONE: La classe wbconst definisce costanti aggiuntive che verranno utilizzate dalla classe workbench. 34 -- A wire is an unidirectional link between two cells class interface WIRE inherit E_COMPONENT creation make feature {ANY} make (wire_color : COLOR) is_output (x, y : INTEGER) : BOOLEAN is_chip : BOOLEAN is FALSE set_origin (x, y : INTEGER) -- set the origin point of the wire set_flex (x, y : INTEGER) -- set the flex point of the wire set_destination (x, y : INTEGER) -- set the destination point of the wire remove (breadboard : BREADBOARD) reset set_input (wbc : WORKBENCH; pit : PIT) : LINKED_LIST[PIT] from_x, from_y : INTEGER -- pit position of the origin point of the wire to_x, to_y : INTEGER -- pit position of the destination point of the wire flex_x, flex_y : INTEGER -- pit position of the flex point of the wire color : COLOR -- the color used to draw the wire feature {NONE} output : INTEGER -- the logical level of the output end interface -- class WIRE BREVE DESCRIZIONE: La classe wire eredita dalla classe e-component e implementa le caratteristiche di un filo elettrico di connessione utilizzato durante la costruzione di un circuito elettronico. Da notare la presenza dei tre metodi set_origin, set_flex e set_destination che rappresentano chiaramente la politica di disposizione di un filo elettrico in 3 fasi distinte. 35 -- The workbench is the place where circuit is built and tested class interface WORKBENCH inherit SIZABLE_WINDOW rename make as sw_make redefine on_create, on_paint, on_size, on_clicked, on_lbutton_down, on_command, on_timer end RESCONST COMMANDS WBCONST creation make feature {ANY} make (container : MAIN; filen : STRING) on_create : INTEGER -- callback: called when the window is built on_paint : INTEGER -- callback: called when the window need repainting on_size (w, h : INTEGER) : INTEGER -- callback: called when window is resized on_clicked (elemento : TILE) : INTEGER -- callback: called when a button on the workbench is pressed on_lbutton_down (x, y : INTEGER) : INTEGER -- callback: called when the mouse left button is pressed on_command (cmd : INTEGER) : INTEGER -- callback: called when the window receives a command create_chip (type : INTEGER) -- create a new chip of type as selected reset_simulation -- resets all components used for the simulation simulation -- execute the simulation for a pit only (ministep) start_simulation -- start the simulation step_simulation -- execute the simulation for a new input signal (step) add_to_simulation (pit : PIT) -- add a new pit to the simulation (pit which value is changed) stop_simulation -- stop the simulation paint_outputs 36 -- repaint the outputs on_timer : INTEGER -- callback: called every n-milliseconds during simulation play_simulation : BOOLEAN -- the simulation is running? output_leds : ARRAY[BOOLEAN] -- value of output leds switch : SWITCH -- the switch manager x_orig, y_orig : REAL -- position of the up-left corner of the breadboard inside window feature {NONE} state : INTEGER -- actual state of the workbench cursor : CURSOR -- cursor used pict, img_chip_l, img_chip_r : PICTURE -- images inputs : INPUTS -- the digital inputs manager clock : CLOCK -- the clock manager desktop : MAIN -- the main (application) window breadboard : BREADBOARD -- the breadboard manager chip_to_insert : CHIP -- chip to insert to the breadboard wire_to_insert : WIRE -- wire to insert to the table global_pits : LINKED_LIST[PIT] -- list of pits involved in the simulation Max_capacity : INTEGER is 2000 -- value used to distinguish between stable and unstable circuits end interface -- class WORKBENCH BREVE DESCRIZIONE: La classe workbench è il cuore del programma ed implementa le funzionalità di gestione di breadboard, switch, inputs e clock. Da notare, in questo senso, la presenza le funzioni del timer utilizzate per il clock. Workbench si occupa anche della creazione dei fili elettrici di connessione e dei chip che successivamente andranno collocati sulla breadboard. In workbench è implementato il simulatore ed il suo algoritmo è stato suddiviso nei seguenti metodi: • • • • • • Reset_simulation: tutti i componenti del grafo coinvolti nella simulazione vengono azzerati. Simulation: viene eseguita la simulazione per un unico pit (viene analizzato come la variazione di un pit ha influito sugli altri). Start_simulation: viene eseguita la prima fase della simulazione: a partire dai valori iniziali dell’alimentazione, clock ed ingressi viene portato il circuito ad un livello di consistenza. Step_simulation: viene eseguito un nuovo passo di simulazione, cioè la simulazione viene eseguita finché le variazioni non si sono rese stabili. Add_to_simulation: viene aggiunto un pit il cui livello è mutato alla simulazione. Stop_simulation: arresta l’algoritmo di simulazione. 37 6 Scenari e Diagrammi Dinamici In questa sezione verranno analizzati tre scenari relativi alle tre operazioni fondamentali nell’uso di DigiChip. Si tratta delle operazioni di: • Inserimento di un chip nel circuito. • Rimozione di un componente dal circuito. • Simulazione di funzionamento del circuito. Si è preferito illustrare l’operazione di inserimento su di un chip piuttosto che su un filo elettrico di connessione principalmente per ragioni di semplicità. Ad ogni modo una volta che si è compreso il funzionamento dell’operazione su di un chip risulta molto semplice capire il comportamento per un filo. Le operazioni di inserimento e rimozione verranno rappresentate in modo completo senza però scendere troppo nei particolari dell’implementazione. La simulazione di funzionamento sarà invece semplificata per ovvi motivi, sarà comunque possibile comprendere il comportamento più generale dei componenti durante questa fase dell’applicazione. 38 6.1 Scenari Nella realizzazione degli scenari sono state aggiunte due entità che non fanno parte dell’applicazione ma che hanno notevole importanza allo scopo di comprendere il funzionamento del programma. La prima delle due è l’utente che ha diretto contatto con l’interfaccia dell’applicazione. L’altra entità è il sistema di gestione degli eventi di Windows e risiede nel sistema operativo. Ha il compito di passare le richieste dell’utente alla giusta “sezione” dell’applicazione. Queste entità aggiuntive saranno indicate in maiuscolo nei diagrammi dinamici. Il primo scenario si riferisce all’operazione di aggiunta di un chip al circuito. L’entità indicata con LS..../HD.... nel diagramma dinamico è il chip da aggiungere al circuito. Il chip viene creato dal workbench dopo aver ricevuto il messaggio 3 dal main (vedi diagramma). Chips_list è la lista dei chip inseriti sulla breadboard ed è stata inclusa nel diagramma solamente per motivi di completezza. Il secondo scenario si riferisce alla rimozione di un componente dalla breadboard. E’ interessante notare come questo scenario differisca solo lievemente dal precedente. Ancora più interessante è il motivo che porta alla differenza: nel primo caso il trattamento con due metodi differenziati per l’aggiunta di chip e fili elettrici di connessione permetteva alla breadboard di sapere a quale delle due liste il componente andava aggiunto (chips_list o wires_list). Viceversa, in questo caso, l’esistenza di un’unico metodo di rimozione componenti (chip o fili) non permette alla breadboard di sapere se si sta rimuovendo un chip o un filo. E’ dunque il componente stesso che si occupa, dopo la sua rimozione dalla breadboard, di farsi eliminare dalla lista opportuna. Il terzo scenario semplifica il procedimento di simulazione di funzionamento di un circuito. Da notare è il comportamento della breadboard in questo caso. Essa è infatti ora utilizzata un po’ come fosse una cartina geografica. La gestione dei chip e dei fili di collegamento è interamente a carico di workbench, che però invia continue richieste anche a breadboard. Questa fase può essere infatti vista nel seguente modo: workbench esegue il proprio algoritmo di simulazione su un grafo mantenendo il proprio diretto controllo sui due insiemi che lo definiscono: l’insieme dei nodi (Wire e LS..../HD....) e l’insieme degli archi (breadboard). 39 6.2 Diagrammi dinamici 1 2 3 4 5 6 7 8 1° Scenario Box Aggiunta di un chip al circuito L’utente richiede l’inserimento nel circuito di un particolare tipo di chip tramite la selezione dal menù principale Il sistema di gestione degli eventi di Windows invia la richiesta al main del programma Il main del programma trasferisce la richiesta (con il codice del tipo di chip da inserire) al workbench L’utente seleziona mediante mouse la posizione in cui inserire il chip Il sistema di gestione degli eventi di Windows codifica la richiesta e la invia a workbench Workbench chiede a breadboard di inserire il chip nella data posizione Se la collocazione è ammissibile la breadboard notifica al chip l’inserimento in una certa posizione della breadboard La breadboard inserisce in chips_list il chip appena inserito UTENTE Chips_list 1, 4 SISTEMA DI GESTIONE DEGLI EVENTI DI WINDOWS 5 LS..../HD.... 2 Main 7 3 Workbench 6 40 Breadboard 8 1 2 3 4 5 6 7 8 9 2° Scenario Box Rimozione di un componente dal circuito L’utente richiede la rimozione dal circuito di un componente tramite la selezione dal menù principale Il sistema di gestione degli eventi di Windows invia la richiesta al main del programma Il main del programma trasferisce la richiesta al workbench L’utente seleziona mediante mouse la posizione in cui è presente il componente da rimuovere Il sistema di gestione degli eventi di Windows codifica la richiesta e la invia a workbench Workbench chiede a breadboard di rimuovere il componente nella data posizione Se nella posizione è presente un componente rimovibile allora la breadboard notifica al componente di rimuoversi dalla breadboard Il componente richiede alla breadboard di eliminare dalla lista chips_list o wire_list il proprio riferimento La breadboard elimina il componente dall’opportuna lista chips_list o wires_list Chips_list or Wires_list UTENTE 1, 4 SISTEMA DI GESTIONE DEGLI EVENTI DI WINDOWS 5 E_component 2 Main 8 3 Workbench 6 41 7 Breadboard 9 1 2 3 4 5 6 7 3° Scenario Box Simulazione del funzionamento del circuito L’utente richiede l’avvio o l’arresto della simulazione mediante la selezione delle apposite voci di menu Il sistema di gestione degli eventi di Windows invia la richiesta al main del programma Il main del programma trasferisce la richiesta al workbench L’utente modifica una selezione degli input Il sistema di gestione degli eventi di Windows codifica la richiesta e la invia a workbench Workbench richiede l’esecuzione di una operazione ad un chip, ad un filo elettrico di connessione o ad una connessione elettrica di breadboard L’oggetto notifica il risultato dell’operazione a workbench UTENTE 1, 4 SISTEMA DI GESTIONE DEGLI EVENTI DI WINDOWS 5 6 LS..../HD.... 2 7 Main 3 Workbench 7 7 6 6 Wire Breadboard 42 7 Osservazioni Conclusive In questa sezione verranno analizzati gli errori, le limitazioni e le carenze che sono state riscontrate dopo un uso intensivo del programma. Verranno analizzate le limitazioni e loro possibili soluzioni nonché le conseguenze prodotte da queste limitazioni sul piano pratico. Verranno analizzati gli errori e le loro conseguenze, discutendoli anche secondo la politica del “Si poteva fare meglio?”. Verranno discusse le carenze e le possibili estensioni. Sarà poi data un’occhiata al futuro, studiando possibili estensioni e migliorie del programma e loro conseguenti benefici. 43 7.1 Carenze, limitazioni ed errori Il programma ha senza dubbio parecchie carenze. Innanzitutto mancano altri strumenti di test per i circuiti, inoltre non esiste la possibilità di far ruotare i chip al loro inserimento di 180°, un pulsante di rotazione ed un miglioramento al metodo di inserimento dei chip nella breadboard avrebbe risolto il problema. Non è inoltre possibile spostare un componente già inserito (bisogna eliminarlo e reinserirlo). I componenti a disposizione sono pochi e questo limita la creatività dell’utente. Ma le limitazioni riguardano soprattutto le dimensioni del circuito realizzabile e la possibilità di costruire circuiti astabili (come oscillatori). Inoltre non ci sono altri componenti utilizzabili come visualizzatori o dispositivi di input. L’aggiunta di altri componenti di questo tipo sarebbe possibile e non particolarmente difficile grazie all’architettura di tipo sostanzialmente aperta del programma. Una grossa limitazione che sarebbe bene eliminare sarebbe la necessità di definire la direzione di un filo elettrico di collegamento, tralasciando il compito al programma di ricavarla, problema che è comunque di non facile soluzione. Per quanto riguarda gli errori, invece, dopo parecchie modifiche e riscritture di parti del codice non ne sono più stati segnalati nell’uso pratico e tutti i circuiti realizzati hanno funzionato in maniera corretta. Non è comunque da escludere che uno stress-testing condotto in modo più accurato possa mettere in evidenza errori tutt’ora presenti. Dalle conoscenze del programma si può infatti affermare con certezza che il tentativo di aprire un file di un formato non proprio di DigiChip potrebbe avere come conseguenza un crash del programma. Nonostante l’introduzione di un header al formato dei files di DigiChip 1.0 (*.dgc) abbia permesso di ridurre notevolmente questa eventualità, la possibilità che un file editato manualmente dall’utente possa portare ancora ad errori di questo tipo, permane. Si poteva fare meglio rendendo più robusta la funzionalità di caricamento di un file da disco, controllando di volta in volta i dati relativi al formato del file. 7.2 Sviluppi futuri Come testimonia anche il nome completo dell’applicazione (DigiChip 1.0) l’idea è quella di proseguire lo sviluppo dell’applicazione, a partire dalle indicazioni date nelle osservazioni delle limitazioni e degli errori. L’idea sarebbe quella di avere in un’unica applicazione anche le funzionalità di progettazione e testing dei circuiti elettronici analogici, sebbene questo richieda di rivedere un po’ tutta l’architettura del sistema. Ad ogni modo, il progetto presenta una quantità incredibile di direzioni verso le quali proseguire la sua crescita. 44