Skip to content

Instantly share code, notes, and snippets.

@danoneata
Created March 3, 2017 09:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danoneata/74010f07342c7f605c38da2233fd1bcb to your computer and use it in GitHub Desktop.
Save danoneata/74010f07342c7f605c38da2233fd1bcb to your computer and use it in GitHub Desktop.
Digital circuit simulator
/**
* 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
}
}
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