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