home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
ddjmag
/
ddj8912.arc
/
AYERS.LST
next >
Wrap
File List
|
1989-10-30
|
29KB
|
905 lines
_AN OBJECT-ORIENTED LOGIC SIMULATOR_
by Kenneth E. Ayers
[LISTIN╟ ONE]
Object subclass: #LogicLab
instanceVariableNames:
'devices signals switches clashes changed topPane analyzer breadboard
listSelector currentComponent '
classVariableNames: ''
poolDictionaries:
'FunctionKeys CharacterConstants ' !
!LogicLab class methods !
description
"Answer a String describing the
application and version."
^'LogicLab (Version 1.0 -- 06/26/88)'.!
new
"Answer an initialized LogicLab application."
| logicLab |
logicLab := super new.
logicLab initialize.
^logicLab.! !
!LogicLab methods !
addComponent: aComponent
"Add aComponent to the circuit description.
If there is an error, answer nil; otherwise
answer aComponent."
| name |
name := aComponent name.
name size == 0
ifTrue: [
"
User is installing -- get a name.
"
name := self getNewName.
name isNil
ifTrue: [^nil].
aComponent name: name]
ifFalse: [
"
A name has been supplied -- this implies
that the component is being installed from
a file. Need to check for a clash with
an existing name.
"
((self componentNamed: name) isNil)
ifFalse: [
"
Had a name clash -- get a synonym
from the user and stash both of them
away in the clashes table. Then
rename the component.
"
name := self getNewName.
name isNilè ifTrue: [^nil].
clashes
at: aComponent name
put: name.
aComponent name: name]].
changed := true.
aComponent isDevice
ifTrue: [devices add: aComponent]
ifFalse: [
aComponent isSignal
ifTrue: [signals add: aComponent]
ifFalse: [
switches add: aComponent.
analyzer isNil
ifFalse: [analyzer addSwitch: aComponent]]].
^aComponent.!
allNames
"Answer an array of all of the
names of installed components."
^((self deviceNames), (self signalNames), (self switchNames)).!
analyzer: aModel
"Set the LogicAnalyzer Application model
to aModel."
analyzer := aModel.!
breadboardList
"Answer an array of strings according to the
current list selector."
listSelector isNil
ifTrue: [listSelector := #listDevices].
^(self perform: listSelector).!
breadboardMenu
"Private -- answer the menu that processes
breadboard functions."
MenuPosition := Cursor position.
^(Menu
labels: ('Load\Save\Erase\List\',
'Install\Connect\Remove\Disconnect\',
'Simulate\',
'Quit') withCrs
lines: #(4 8 9)
selectors: #(load save erase list
install connect remove disconnect
run
quit)).!
changed
"Answer true if the circuit has changed."
^changed.!
changed: aBoolean
"Set the circuit-changed flag to aBoolean."
changed := aBoolean.!
close
"Close the LogicLab breadboarding window."
topPane dispatcher deactivateWindow closeWindow.!
closeIt
"Close the breadboard application window."è self close.!
componentNamed: aName
"Answer the component (device, signal, or switch)
whose name is aName. If no component can be found
answer nil."
| realName |
realName := aName.
clashes isNil
ifFalse: [
(clashes includesKey: aName)
ifTrue: [realName := clashes at: aName]].
devices do: [:aDevice|
(aDevice name = realName)
ifTrue: [^aDevice]].
signals do: [:aSignal|
(aSignal name = realName)
ifTrue: [^aSignal]].
switches do: [:aSwitch|
(aSwitch name = realName)
ifTrue: [^aSwitch]].
^nil.!
componentTypeMenu: selectorArray
"Answer a user-selected action for a
component type."
^((Menu
labels: 'Device\Signal\Switch' withCrs
lines: #()
selectors: selectorArray) popUpAt: MenuPosition).!
connect
"Make a user-specified connection."
| from to |
from := self getNode.
from isNil
ifTrue: [^nil].
to := self getNode.
to isNil
ifTrue: [^nil].
from connect: to.
changed := true.
currentComponent := from model.
listSelector := #listComponentConnections.
breadboard update.!
description
"Answer a string with a description of the receiver."
^(self class description).!
deviceNames
"Answer a collection of all of the
names of installed devices."
| list |
list := OrderedCollection new: (devices size).
devices do: [:aDevice| list add: aDevice name].
^list.!
devices
"Answer the list of installed devices."
^devices.!èdisconnect
"Remove a user-specified connection."
| node |
node := self getNode.
node isNil
ifTrue: [^nil].
node disconnect.
changed := true.
currentComponent := node model.
listSelector := #listComponentConnections.
breadboard update.!
erase
"After user-verification, erase
the circuit description."
Cursor offset: MenuPosition.
(self verify: 'Erase circuit description?')
ifFalse: [^nil].
self eraseCircuit.
listSelector := #listDevices.
changed := true.
breadboard update.!
eraseCircuit
"Erase the circuit description."
devices do: [:aDevice|
self removeComponent: aDevice].
signals do: [:aSignal|
self removeComponent: aSignal].
switches do: [:aSwitch|
self removeComponent: aSwitch].
self initialize.!
getExistingComponent
"Answer a user-specified component."
| name component reply list |
name := self getName.
name isNil
ifTrue: [^nil].
component := self componentNamed: name.
component isNil
ifFalse: [^component].
Cursor offset: MenuPosition.
(Menu message:
(name, ' not installed -- select from list?')) isNil
ifTrue: [^nil].
Cursor offset: MenuPosition.
reply := self componentTypeMenu:
#(deviceNames signalNames switchNames).
Cursor offset: MenuPosition.
reply isNil
ifTrue: [^nil].
list := self perform: reply.
(list size == 0)
ifTrue: [
Menu message: 'None installed'.
Cursor offset: MenuPosition.
^nil].è name := VariableMenu selectFrom: list.
name isNil
ifTrue: [^nil].
name := list at: name.
^(self componentNamed: name).!
getExistingName
"Answer a user-specified name of
an existing component."
| component |
component := self getExistingComponent.
component isNil
ifTrue: [^nil].
^(component name).!
getFile
"Answer a FileStream for a
user-specified filename."
| name |
name := self getFilename.
name isNil
ifTrue: [^nil].
^(File pathName: name).!
getFilename
"Answer a user-specified filename."
| name |
Cursor offset: MenuPosition.
name :=
Prompter
prompt: 'Enter filename'
default: ''.
Cursor offset: MenuPosition.
^name.!
getName
"Answer a user-specified name."
| name |
Cursor offset: MenuPosition.
name :=
Prompter
prompt: 'Enter component name'
default: ''.
Cursor offset: MenuPosition.
^name.!
getNewName
"Answer a user-specified name for
a new component."
| name |
Cursor offset: MenuPosition.
name :=
Prompter
prompt: 'Enter name for new component'
default: ''.
Cursor offset: MenuPosition.
name isNil
ifTrue: [^nil].
[(self componentNamed: name) isNil]
whileFalse: [è name :=
Prompter
prompt: 'Name exists -- enter NEW name'
default: name.
Cursor offset: MenuPosition.
name isNil
ifTrue: [^nil]].
^name.!
getNode
"Answer a user-specified LogicNode."
| component |
component := self getExistingComponent.
component isNil
ifTrue: [^nil].
^(component getNode).!
initialize
"Private -- initialize a new
LogicLab application."
devices := OrderedCollection new.
signals := OrderedCollection new.
switches := OrderedCollection new.
changed := true.!
install
"Install a user-specified component."
| component |
component := LogicComponent install.
component isNil
ifTrue: [^nil].
self addComponent: component.
listSelector := self listSelectorFor: component.
breadboard update.
^component.!
installClassFrom: aStream
"Install a LogicComponent subclass
whose name is the next word on aStream."
| className |
className := aStream nextWord.
(Smalltalk includesKey: className asSymbol)
ifFalse: [
self error: ('Class: ', className, ' not installed')].!
installComponentFrom: aStream
"Install a LogicComponent instance
whose name is the next word on aStream."
| className class component |
className := aStream nextWord.
class := LogicComponent classNamed: className.
class isNil
ifTrue: [
self error: ('Unknown class: ', className).
^nil].
component := class new installFrom: aStream.
component isNil
ifTrue: [^nil].
^(self addComponent: component).!
installConnectionFrom: aStreamè "Install a connection from aStream."
| fromName from toName to fromNode toNode |
fromName := aStream nextWord.
from := self componentNamed: fromName.
from isNil
ifTrue: [
self error: ('Unknown component: ', fromName).
^nil].
fromNode := from getNodeFrom: aStream.
fromNode isNil
ifTrue: [
self error: ('Unknown node on: ', fromName).
^nil].
toName := aStream nextWord.
to := self componentNamed: toName.
to isNil
ifTrue: [
self error: ('Unknown component: ', toName).
^nil].
toNode := to getNodeFrom: aStream.
toNode isNil
ifTrue: [
self error: ('Unknown node on: ', toName).
^nil].
^(fromNode connect: toNode).!
installFrom: aStream
"Load a circuit from the description
on aStream."
| keyWord |
clashes := Dictionary new.
[(aStream atEnd)
or: [(keyWord := aStream nextWord) isNil]]
whileFalse: [
keyWord = 'LOAD'
ifTrue: [
self installClassFrom: aStream]
ifFalse: [
keyWord = 'INSTALL'
ifTrue: [
self installComponentFrom: aStream]
ifFalse: [
keyWord = 'CONNECT'
ifTrue: [
self installConnectionFrom: aStream]
ifFalse: [
self error:
('Unknown command: ',
keyWord)]]]].
clashes release.
clashes := nil.!
list
"Process a user-specified list request."
| selection |
selection :=
(Menuè labels: ('Components\Connections\',
'Circuit Description') withCrs
lines: #()
selectors: #(listComponents
listConnections
listCircuit))
popUpAt: MenuPosition.
selection isNil
ifTrue: [^nil].
listSelector := selection.
breadboard update.!
listCircuit
"Answer a collection of strings with
the circuit description."
| name stream list |
CursorManager execute change.
name := 'logiclab.tmp'.
stream := File pathName: name.
list := OrderedCollection new.
stream
nextPutAll: '**** Circuit Description ****';
cr;
cr.
self storeOn: stream.
stream flush.
stream position: 0.
[stream atEnd]
whileFalse: [list add: stream nextLine].
stream close.
File remove: name.
CursorManager normal change.
^list.!
listComponentConnections
"Answer a collection of strings listing
the connection chain(s) for the
'currentComponent'."
currentComponent isNil
ifTrue: [^#()]
ifFalse: [
^(#('**** Connection List ****' ' '),
currentComponent connectionList)].!
listComponents
"Answer a collection of strings containing
a list of installed components."
| selection |
selection :=
self componentTypeMenu:
#(listDevices listSignals listSwitches).
selection isNil
ifTrue: [^#()].
^(self perform: selection).!
listConnections
"Answer a collection of strings listing
the connection chain(s) for a
user-specified component."è | component |
component := self getExistingComponent.
component isNil
ifTrue: [^#()].
currentComponent := component.
^self listComponentConnections.!
listContaining: aComponent
"Answer the list (devices, signals, or switches)
that includes aComponent."
(devices includes: aComponent)
ifTrue: [^devices].
(signals includes: aComponent)
ifTrue: [^signals].
^switches.!
listDevices
"Answer a collection of strings containing
a list of all the installed devices."
| size list |
size := devices size.
size == 0
ifTrue: [^#('No devices installed')].
size := size + 1.
list := OrderedCollection new: size.
list add: 'DEVICES'.
devices do: [:aDevice| list add: (' ', (aDevice identify))].
^list.!
listSelectorFor: aComponent
"Answer the list selector method used
to produce the list for aComponent's type."
aComponent isDevice
ifTrue: [^#listDevices].
aComponent isSignal
ifTrue: [^#listSignals].
^#listSwitches.!
listSignals
"Answer a collection of strings containing
a list of all the installed input signals."
| size list |
size := signals size.
size == 0
ifTrue: [^#('No signals installed')].
size := size + 1.
list := OrderedCollection new: size.
list add: 'SIGNALS'.
signals do: [:aSignal| list add: (' ', (aSignal identify))].
^list.!
listSwitches
"Answer a collection of strings containing
a list of all the installed swithces."
| size list |
size := switches size.
size == 0
ifTrue: [^#('No switches installed')].
size := size + 1.
list := OrderedCollection new: size.è list add: 'SWITHCES'.
switches do: [:aSwitch| list add: (' ', (aSwitch identify))].
^list.!
load
"Load a circuit description from
a user-specified file."
| file |
file := self getFile.
file isNil
ifTrue: [^nil].
self installFrom: file.
listSelector := #listDevices.
breadboard update.!
noDelay
"Setup all components to ignore
propagation delays."
signals do: [:signal| signal noDelay].
switches do: [:switch| switch noDelay].
devices do: [:device| device noDelay].!
noMenu
"Private -- answer an empty menu."
^(EmptyMenu new).!
open
"Open the Breadboard and Analyzer windows."
| size position |
size := (Display boundingBox extent * 3) // 4.
position := Display boundingBox center - (size // 2).
topPane :=
TopPane new
label: ((self class description),
' -- Breadboard');
model: self;
menu: #noMenu;
yourself.
topPane addSubpane:
(breadboard := ListPane new
name: #breadboardList;
model: self;
menu: #breadboardMenu;
change: #doNothing:;
framingRatio: (0 @ 0 extent: 1 @ 1)).
topPane reframe: (position extent: size).
topPane dispatcher openWindow scheduleWindow.!
quit
"Quit this LogicLab."
(self verify: 'Quit this LogicLab?')
ifFalse: [^nil].
self eraseCircuit.
signals := switches := devices := nil.
analyzer isNil
ifFalse: [
analyzer closeWindow.
analyzer := nil].
breadboard dispatcher deactivateWindow closeWindow.
Scheduler systemDispatcher redraw.è Scheduler resume.!
remove
"Remove a user-specified component."
| component |
component := self getExistingComponent.
component isNil
ifTrue: [^nil].
changed := true.
listSelector := self listSelectorFor: component.
self removeComponent: component.
breadboard update.!
removeComponent: aComponent
"Remove aComponent from the circuit."
analyzer isNil
ifFalse: [analyzer removeComponent: aComponent].
(self listContaining: aComponent) remove: aComponent.
aComponent remove.!
reset
"Reset all components."
signals do: [:signal| signal reset].
switches do: [:switch| switch reset].
devices do: [:device| device reset].!
restoreDelay
"Setup all components to use
propagation delays."
signals do: [:signal| signal restoreDelay].
switches do: [:switch| switch restoreDelay].
devices do: [:device| device restoreDelay].!
resume
"Resume the breadboarding application
after running the simulation."
Cursor offset: breadboard frame center.
topPane dispatcher scheduleWindow.!
run
"Invoke the LogicAnalyzer to run the simulation."
analyzer isNil
ifTrue: [
analyzer := LogicAnalyzer new.
analyzer openOn: self]
ifFalse: [analyzer activate].!
save
"Store the circuit description in
a user-specified file."
| file |
file := self getFile.
file isNil
ifTrue: [^nil].
CursorManager execute change.
self storeOn: file.
file
flush;
close.
CursorManager normal change.!
selectName
"Answer a user-selected name from a listè of the names of installed components."
| names index |
names := self allNames.
(names size == 0)
ifTrue: [^nil].
index := VariableMenu selectFrom: names.
index isNil
ifTrue: [^nil].
^(names at: index).!
signalNames
"Answer a collection of all of the
names of installed signals."
| list |
list := OrderedCollection new: (signals size).
signals do: [:aSignal| list add: aSignal name].
^list.!
signals
"Answer the list of installed signals."
^signals.!
simulate
"Simulate one pseudo-time interval."
signals do: [:signal| signal simulate].
switches do: [:switch| switch simulate].
devices do: [:device| device simulate].!
storeClassesOn: aStream
"Write a record of each component class
used by the circuit on aStream."
| classes |
classes := Set new.
devices do: [:aDevice| classes add: aDevice class].
signals do: [:aSignal| classes add: aSignal class].
switches do: [:aSwitch| classes add: aSwitch class].
classes do: [:aClass|
aStream
nextPutAll: ('LOAD ', (aClass name));
cr].!
storeComponentsFrom: aCollection on: aStream
"Write a record of each logic component from
aCollection installed in the circuit on aStream."
aCollection do: [:aComponent|
aStream nextPutAll: 'INSTALL '.
aComponent storeOn: aStream.
aStream cr].!
storeConnectionsOn: aStream
"Write a record of each connection
in the circuit on aStream."
devices do: [:aDevice| aDevice storeConnectionsOn: aStream].
signals do: [:aSignal| aSignal storeConnectionsOn: aStream].
switches do: [:aSwitch| aSwitch storeConnectionsOn: aStream].
devices do: [:aDevice| aDevice unMark].
signals do: [:aSignal| aSignal unMark].
switches do: [:aSwitch| aSwitch unMark].!
storeDevicesOn: aStream
"Write a record of each logic device
installed in the circuit on aStream."è self storeComponentsFrom: devices on: aStream.!
storeOn: aStream
"Write a description of the circuit on
aStream in a form that can be recovered
by the 'installOn:' method."
self
storeClassesOn: aStream;
storeDevicesOn: aStream;
storeSignalsOn: aStream;
storeSwitchesOn: aStream;
storeConnectionsOn: aStream.!
storeSignalsOn: aStream
"Write a record of each logic signal
installed in the circuit on aStream."
self storeComponentsFrom: signals on: aStream.!
storeSwitchesOn: aStream
"Write a record of each logic switch
installed in the circuit on aStream."
self storeComponentsFrom: switches on: aStream.!
switches
"Answer the list of installed switches."
^switches.!
switchNames
"Answer a collection of all of the
names of installed swithces."
| list |
list := OrderedCollection new: (switches size).
switches do: [:aSwitch| list add: aSwitch name].
^list.!
verify: aPrompt
"Ask the user to verify some condition."
Cursor offset: MenuPosition.
^((Menu message: aPrompt) notNil).! !
ì
[LISTIN╟ TWO]
LogicSwitch subclass: #ToggleSwitch
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: '' !
!ToggleSwitch class methods !
type
"Answer a string with the receiver's type."
^'Toggle Switch'.! !
!ToggleSwitch methods !
identify
"Answer a string identifying the receiver."
^((self name),
' (', (self type), ')').!
push: aButton
"Simulate pushing a toggle switch by
inverting its state."
node invert.
node isHigh
ifTrue: [aButton lampOn]
ifFalse: [aButton lampOff].
(model isNil or: [changeSelector isNil])
ifFalse: [model perform: changeSelector].!
reset
"Reset the receiver."
button isNil
ifFalse: [
node isHigh
ifTrue: [button lampOn]
ifFalse: [button lampOff]].!
simulate
"Simulate a toggle switch."
node output.! !
[LISTIN╟ THREE]
LogicSwitch subclass: #PulserSwitch
instanceVariableNames:
'rest time timer '
classVariableNames: ''
poolDictionaries: '' !
!PulserSwitch class methods !
type
"Answer a string with the receiver's type."
^'Pulser'.! !
!PulserSwitch methods !
identify
"Answer a string identifying the receiver."
^((self name),
' (', (self type), ' -- ',
(LogicNode
statePrintString: (LogicNode not: rest)), ': ',
(TimeInterval timePrintString: time), ')').!
initialize
"Initialize a new PulserSwitch."
super initialize.
rest := false.
time := timer := 0.!
install
"Answer the receiver with user-specified
rest state and pulse time."
rest := LogicNode getState. "User will select pulse state"
rest isNil
ifTrue: [^super release].
rest := LogicNode not: rest.
time := TimeInterval getTimeFor: 'pulse'.
time isNil
ifTrue: [^super release].
^self.!
installFrom: aStream
"Answer a new PulserSwitch initialized with
parameters read from aStream."
super installFrom: aStream.
rest := LogicNode stateNamed: aStream nextWord.
node state: rest.
time := aStream nextWord asInteger.
^self.!
push: aButton
"Simulate pushing a Pulser Switch."
timer == 0
ifTrue: [node state: (LogicNode not: rest)].
timer := time.
node isHigh
ifTrue: [aButton lampOn]
ifFalse: [aButton lampOff].
(model isNil or: [changeSelector isNil])è ifFalse: [model perform: changeSelector].!
reset
"Reset the receiver's state to its resting
state and its timer to zero."
node state: rest.
timer := 0.
button isNil
ifFalse: [
node isHigh
ifTrue: [button lampOn]
ifFalse: [button lampOff]].!
simulate
"Simulate a Pulser Switch."
timer == 0
ifTrue: [
node state: rest.
button isNil
ifFalse: [
node isHigh
ifTrue: [button lampOn]
ifFalse: [button lampOff]]]
ifFalse: [timer := timer - 1].
node output.!
storeOn: aStream
"Store a record of the receiver on aStream."
super storeOn: aStream.
aStream
nextPutAll: (' ',
(LogicNode statePrintString: rest), ' ',
(time printString)).! !
[LISTIN╟ FOUR]
LogicDevice subclass: #N74LS00
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: '' !
!N74LS00 class methods !
description
"Answer a string with a description
of the receiver's function."
^'Quad 2-input NAND gate'.!
type
"Answer a string with the receiver's type."
^'74LS00'.! !
!N74LS00 methods !
initialize
"Private -- initialize the propagation delays
for a new 74LS00 LogicDevice."
super
initialize;
initializeDelays:
#( 5 5 10 5 5 10 0
10 5 5 10 5 5 0 ).!
simulate
"Simulate a 74LS00 device."
((pins at: 1) isHigh and: [(pins at: 2) isHigh])
ifTrue: [(pins at: 3) output: false]
ifFalse: [(pins at: 3) output: true].
((pins at: 4) isHigh and: [(pins at: 5) isHigh])
ifTrue: [(pins at: 6) output: false]
ifFalse: [(pins at: 6) output: true].
((pins at: 10) isHigh and: [(pins at: 9) isHigh])
ifTrue: [(pins at: 8) output: false]
ifFalse: [(pins at: 8) output: true].
((pins at: 13) isHigh and: [(pins at: 12) isHigh])
ifTrue: [(pins at: 11) output: false]
ifFalse: [(pins at: 11) output: true].! !
[LISTIN╟ FIVE]
output: aState ì
"Generate aState as an output from the node." ì
old := int. ì
int := aState. ì
int == ext ì
ifTrue: [ ì
"State is stable" ì
timer := 0. ì
^self outputToConnections]. ì
"State has changed" ì
timer == 0 ì
ifTrue: [ ì
"No delay in progress -- initiate prop delay" ì
delay == 0 ì
ifTrue: [ ì
"No delay -- just change state" ì
ext := int] ì
ifFalse: [ ì
"Arm delay timer" ì
timer := delay]. ì
^self outputToConnections]. ì
"Propagation delay in progress" ì
timer := timer - 1. ì
timer == 0 ì
ifTrue: [ ì
"Timer has expired -- update state" ì
ext := int]. ì
self outputToConnections. ì
[LISTIN╟ SIX]
simulate ì
"Simulate a 74LS00 device." ì
((pins at: 1) isHigh and: [(pins at: 2) isHigh]) ì
ifTrue: [(pins at: 3) output: false] ì
ifFalse: [(pins at: 3) output: true]. ì
((pins at: 4) isHigh and: [(pins at: 5) isHigh]) ì
ifTrue: [(pins at: 6) output: false] ì
ifFalse: [(pins at: 6) output: true]. ì
((pins at: 10) isHigh and: [(pins at: 9) isHigh]) ì
ifTrue: [(pins at: 8) output: false] ì
ifFalse: [(pins at: 8) output: true]. ì
((pins at: 13) isHigh and: [(pins at: 12) isHigh]) ì
ifTrue: [(pins at: 11) output: false] ì
ifFalse: [(pins at: 11) output: true]. ì
ì