Created
March 3, 2017 09:57
-
-
Save danoneata/74010f07342c7f605c38da2233fd1bcb to your computer and use it in GitHub Desktop.
Digital circuit simulator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by eurus on 28/02/2017. | |
*/ | |
package components | |
import collection.immutable.Queue | |
import ActionType._ | |
sealed trait SignalValue | |
object `0` extends SignalValue { | |
override def toString: String = "0" | |
} | |
object `1` extends SignalValue { | |
override def toString: String = "1" | |
} | |
object ActionType { | |
type Action = () => Agenda | |
type ActionProcedure = Agenda => Agenda | |
} | |
class Wire(var signalValue: SignalValue = `0`, var actionProcedures: List[ActionProcedure] = Nil) { | |
def addActionProcedure(agenda: Agenda, actionProcedure: ActionProcedure): Agenda = { | |
actionProcedures = actionProcedure :: actionProcedures | |
actionProcedure.apply(agenda) | |
} | |
def getSignal: SignalValue = signalValue | |
def setSignal(agenda: Agenda, v: SignalValue): Agenda = { | |
if (v != signalValue) { | |
signalValue = v | |
callEach(agenda, actionProcedures) | |
} else { | |
agenda | |
} | |
} | |
private def callEach(agenda: Agenda, procedures: List[ActionProcedure]): Agenda = | |
procedures.foldLeft(agenda)((a, actionProcedure) => actionProcedure.apply(a)) | |
} | |
case class Segment(time: Int, queue: Queue[Action]) | |
case class Agenda(currentTime: Int = 0, segments: List[Segment] = Nil) { | |
def add(time: Int, action: Action): Agenda = { | |
def makeNewSegment(time: Int, action: Action): Segment = { | |
var q = new Queue[Action] | |
Segment(time, q.enqueue(action)) | |
} | |
val newSegment = segments.find(s => s.time == time) match { | |
case None => makeNewSegment(time, action) | |
case Some(segment) => Segment(segment.time, segment.queue.enqueue(action)) | |
} | |
val beforeSegments = segments.filter(s => s.time < time) | |
val afterSegments = segments.filter(s => s.time > time) | |
val newSegments = beforeSegments ++ List(newSegment) ++ afterSegments | |
Agenda(currentTime, newSegments) | |
} | |
def afterDelay(delay: Int, action: Action): Agenda = { | |
add(currentTime + delay, action) | |
} | |
def propagate(): Agenda = { | |
var time = currentTime | |
segments.foreach { segment => | |
time = segment.time | |
segment.queue.foreach { action => action.apply() } | |
} | |
Agenda(time, List.empty[Segment]) | |
} | |
} | |
class Gates { | |
def not(agenda0: Agenda, input: Wire, output: Wire): Agenda = { | |
def logicalNot(s: SignalValue) = s match { | |
case `0` => `1` | |
case `1` => `0` | |
} | |
def notActionProcedure(agenda: Agenda): Agenda = { | |
val DELAY = 3 | |
val v = logicalNot(input.getSignal) | |
val f = () => output.setSignal(agenda, v) | |
agenda.afterDelay(DELAY, f) | |
} | |
val agenda1 = input.addActionProcedure(agenda0, notActionProcedure) | |
agenda1 | |
} | |
def and(agenda0: Agenda, a1: Wire, a2: Wire, output: Wire): Agenda = { | |
def logicalAnd(s: SignalValue, t: SignalValue) = (s, t) match { | |
case (`0`, `0`) => `0` | |
case (`0`, `1`) => `0` | |
case (`1`, `0`) => `0` | |
case (`1`, `1`) => `1` | |
} | |
def andActionProcedure(agenda: Agenda): Agenda = { | |
val DELAY = 5 | |
val v = logicalAnd(a1.getSignal, a2.getSignal) | |
val f = () => output.setSignal(agenda, v) | |
agenda.afterDelay(DELAY, f) | |
} | |
val agenda1 = a1.addActionProcedure(agenda0, andActionProcedure) | |
val agenda2 = a2.addActionProcedure(agenda1, andActionProcedure) | |
agenda2 | |
} | |
def or(agenda0: Agenda, a1: Wire, a2: Wire, output: Wire): Agenda = { | |
def logicalOr(s: SignalValue, t: SignalValue) = (s, t) match { | |
case (`0`, `0`) => `0` | |
case (`0`, `1`) => `1` | |
case (`1`, `0`) => `1` | |
case (`1`, `1`) => `1` | |
} | |
def orActionProcedure(agenda: Agenda): Agenda = { | |
val DELAY = 5 | |
val v = logicalOr(a1.getSignal, a2.getSignal) | |
val f = () => output.setSignal(agenda, v) | |
agenda.afterDelay(DELAY, f) | |
} | |
val agenda1 = a1.addActionProcedure(agenda0, orActionProcedure) | |
val agenda2 = a2.addActionProcedure(agenda1, orActionProcedure) | |
agenda2 | |
} | |
def halfAdder(agenda0: Agenda, a: Wire, b: Wire, s: Wire, c: Wire): Agenda = { | |
val d = new Wire | |
val e = new Wire | |
val agenda1 = or(agenda0, a, b, d) | |
val agenda2 = and(agenda1, a, b, c) | |
val agenda3 = not(agenda2, c, e) | |
val agenda4 = and(agenda3, d, e, s) | |
agenda4 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import components._ | |
object Main extends App { | |
def probe(agenda: Agenda, name: String, wire: Wire): Agenda = { | |
wire.addActionProcedure(agenda, (agenda: Agenda) => { | |
println("Wire: " + name) | |
println("Time: " + agenda.currentTime.toString) | |
println("Signal: " + wire.getSignal.toString) | |
println() | |
agenda | |
}) | |
} | |
override def main(args: Array[String]): Unit = { | |
val agenda0 = new Agenda | |
val gates = new Gates | |
val i = new Wire | |
val o = new Wire | |
val agenda1 = gates.not(agenda0, i, o) | |
val agenda2 = probe(agenda1, "output", o) | |
val agenda3 = agenda2.propagate() | |
val agenda4 = i.setSignal(agenda3, `1`) | |
val agenda5 = agenda4.propagate() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment