-
Notifications
You must be signed in to change notification settings - Fork 36
/
Simulation.scala
153 lines (130 loc) · 3.99 KB
/
Simulation.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package week3
/** Class Hierarchy: Simulation > Gates (Wire, AND, OR, NOT) >
* Circuits (HalfAdder, FullAdder) > MySimulation and Param trait.
*/
trait Simulation {
type Action = () => Unit
case class Event(time: Int, action: Action)
private type Agenda = List[Event]
private var agenda: Agenda = List()
//to handle time
private var curtime = 0
def currentTime: Int = curtime
def afterDelay(delay: Int)(block: => Unit): Unit = {
val item = Event(currentTime + delay, () => block)
agenda = insert(agenda, item)
}
//Ensures the agenda is time-sorted
private def insert(agenda: List[Event], item: Event): List[Event] = agenda match {
case first :: rest if(first.time <= item.time) => first :: insert(rest, item)
case _ => item :: agenda
}
def run(): Unit = {
afterDelay(0) {
println("*** simulation started, time = "+currentTime+" ***")
}
loop()
}
//The event handling loop remove successive elements from the agenda and performs
//the associated actions
private def loop(): Unit = agenda match {
case first :: rest =>
agenda = rest
curtime = first.time
first.action()
loop()
case Nil =>
}
}
abstract class Gates extends Simulation {
//abstract methods
def InverterDelay: Int
def AndGateDelay: Int
def OrGateDelay: Int
class Wire {
//represents the current val of the signal
private var sigVal = false
//represents the actions attached to the current signal
private var actions: List[Action] = List()
//returns the current value of signal transported by the wire
def getSignal: Boolean = sigVal
def setSignal(s: Boolean): Unit = {
if(s!=sigVal) {
sigVal = s
actions foreach (_()) //same as for (a <- actions) a()
}
}
//Attaches the specific procedures to the actions of the wire
def addAction(a: Action): Unit = {
actions = a :: actions
a()
}
}
//The Logic Gates
def inverter(input: Wire, output: Wire): Unit = {
def inverterAction(): Unit = {
val inputSig = input.getSignal
afterDelay(InverterDelay) { output setSignal !inputSig }
}
input addAction inverterAction
}
def andGate(in1: Wire, in2: Wire, output: Wire): Unit = {
def andAction(): Unit = {
val in1Sig = in1.getSignal
val in2Sig = in2.getSignal
//perform whenever one of the two signal changes
afterDelay(AndGateDelay) { output setSignal (in1Sig & in2Sig) }
}
in1 addAction andAction
in2 addAction andAction
}
def orGate(in1: Wire, in2: Wire, output: Wire): Unit = {
def orAction(): Unit = {
val in1Sig = in1.getSignal
val in2Sig = in2.getSignal
//perform whenever one of the two signal changes
afterDelay(OrGateDelay) { output setSignal (in1Sig | in2Sig) }
}
in1 addAction orAction
in2 addAction orAction
}
/* In this alternative orGate, the time to stabilize event is longer */
//a | b == !(!a & !b)
def orGateAlt(in1: Wire, in2: Wire, output: Wire): Unit = {
val notIn1, notIn2, notOut = new Wire
inverter(in1, notIn1)
inverter(in2, notIn2)
andGate(notIn1, notIn2, notOut)
inverter(notOut, output)
}
/* Probe is attached to a wire */
def probe(name: String, wire: Wire): Unit = {
def probeAction(): Unit = {
println(s"$name $currentTime new-value = ${wire.getSignal}")
}
wire addAction probeAction
}
}
abstract class Circuits extends Gates {
//half adder
def halfAdder(a: Wire, b: Wire, s: Wire, c: Wire): Unit = {
val d, e = new Wire
orGate(a, b, d)
andGate(a, b, c)
inverter(c, e)
andGate(d, e, s)
}
//A full bit adder
def fullAdder(a: Wire, b: Wire, cin: Wire, sum: Wire, cout: Wire): Unit = {
val s, c1, c2 = new Wire
halfAdder(b, cin, s, c1)
halfAdder(a, s, sum, c2)
orGate(c1, c2, cout)
}
}
//fixes the technology specific constants
trait Parameters {
def InverterDelay = 2
def AndGateDelay = 3
def OrGateDelay = 5
}