0:00

For the rest of this week,

we'll do a lot of example on Discrete Event Simulation.

The central idea is that we will use mutable variables to

simulate changing quantities in the real world.

As a side effect, so to speak,

you will also learn how to structure a system into a sequence of layers.

And, some of these layers will be domain specific languages.

Concretely, we will construct a digital circuit simulator and that simulator

itself is based on a general framework for discrete event simulation.

Simulation and digital circuits by themselves,

could probably take up a complete course.

But, with the right tools at our disposal we are going to

see that we can simplify it enough to compress it into less than one hour.

So, let's get started.

Let's start with a small description language for digital circuits.

A digital circuit is composed of wires and functional components.

The wires transport signals that are transformed by the components.

Because, we are dealing with digital circuits are not analog ones we represent

the signals between simply using the booleans true and false.

The base components are also called Gates.

And, they are the inverter whose output is the inverse of its input,

the andGate that forms the conjunction of

its two inputs and the orGate that forms the disjunction of its two inputs.

From these basic components,

we can construct others by combining them using wires to connect them.

Another thing, that's important is that the components have a reaction time.

That's called delay.

That means that outputs don't change immediately after a change to

their inputs there's a delay until that change takes place.

Digital circuits are usually described by diagrams.

And, the basic components of these diagrams that Gates drawn as follows.

Let's start with the inverter.

So, the inverter is simply a triangle with a dot at the end that transforms

its input here on the left hand side to its output on the right hand side.

It's called an inverter.

The second basic gate is the andGate.

So, that's written like this,

it takes two inputs and transforms them,

takes the conjunction of the two inputs and the outputs.

So, the output is true if both inputs are true.

And finally, we have the orGate which takes

two inputs and converts them to an output which is true.

If either of the two inputs is true.

From these basic Gates we can now construct more interesting circuits.

So, we are going to show how to construct a halfAdder,

that takes two inputs and converts them into a sum in the carry.

So, let's take the two inputs call them a and b,

what we would do is we would form first the AND of the a and b is written like this.

And, at the same time form the OR of the two inputs.

That's written like this.

Then, we place an inverter after the AND,

and finally another andGate here and that gives us the sum,

on this wire and to carry on this one.

So, if you do the math then we will see that the sum is computed

by- they can be a or b.

And we have AND here.

AND not a and b.

So the sum is set.

It's either a and b are set or not both and both of them are set.

Whereas, the carry is a and b.

So, if both a and b are set then the carry is one but the sum is zero.

If either a and b are set then the sum is one and the carry is zero.

So let's wrap this up.

Draw a box around it.

And, call it a halfAdder or I'm going to abbreviate that too HA.

You've seen the circuit diagrams.

What we are now after is a textural language that describes these circuits.

So, the idea is that we would have wires and the wires are here name.

So, they have names. What we are going to do also is name the internal wires.

So, there would be a wire here and a wire here.

And, those wires we can create using a class wire.

So, we can create new wires by writing val a equals new wire,

then b equals new wires,

c equals new wire that would create between new wires a,b and c. Or,

equivalently we can abbreviate to that to just writing vowel a,b,

c equals new wire.

And, that way we can create all the wires in our circuit diagram that you see here.

And finally, we can place the gates between the wires.

So, one thing that's important here is that

a wire is just not just a single straight line.

But, everything that's connected until it hits a gate.

So, the b wire for instance would- could consist of this line but also this line here.

But, not that line here because,

there is the orGate between that line and that line.

So, that's why we have renamed that wire to be d and that wire to e. So,

once we have wires,

we still need to place the gates.

And, that we do with the following functions.

We have an inverter function that takes as inputs two wires,

the input and output wire and places so to

speak the inverter as a side effect onto the circuit board.

And, the andGate will do the same thing.

It gets two inputs a1 and a2.

And an output places the andGate between those wires and the orGate

analogously for two inputs and one output.

So, let's see how we would express our halfAdder using this language.

So, a halfAdder then is a circuit that takes four wires,

the two inputs a and b and the outputs s and c. What we

need to create them is two internal wires so that's a d and e let's stand here.

And then we place an orGate between a,

b and d that circuit here.

We place the andGate between a,

b and c that circuit here.

You place the inverter between c and e. You will see it.

And finally, replace the andGate between d,e and s. And that together wrapped up,

gives us a component which we call a halfAdder.

Which is, its own function and therefore can be used as another component.

Just, in the same way we can use orGates, andGates and inverter.

So, we can use that to have other than to place between input and output wires.

So here, you see a full adder that can be constructed from two halfAdders and an orGate.

To understand that, let's draw the diagram first.

The full adder takes three inputs the a and the b and, an input carry.

And, it works by placing a halfAdder between the b and the input carry.

Then placing another halfAdder between the a and the sum of the first one.

That some result would give us the final sum.

And as to the carries,

they be produced them by taking the OR of the two carries of the halfAdder.

So, here we get sum.

And here we get the output carry.

Let's name the internal wires.

So, we would have the internal sum of the first halfAdder

and the two carries called and see c1 and c2.

So, that would give us a full Adder of one bit.

Now, to put that in text.

You see the function here,

full Adder takes the three inputs and the two outputs.

There are three internal wires s, c1 and c2.

And, there's a halfAdder between b,

c and s and c1.

There's a half adder between a,

the sum of the first one s sum and c2 and an orGate between c1,

c2 and c out.

And now, we have a full one bit Adder which in turn of course we could use to produce

a eight bit Adder or 16 bit adder or any other circuit you like.

So, here's an exercise for you.

I have a mystery function call it f that connects three wires a and b.

The way you see it here.

And, I want you to answer what logical function does

this circuit produce on the output wire c. Is it a and not b?

Or a and not b and a,

or maybe b and not a,

or a equals b,

or a not equals b,

or a multiplied with b.

So, to figure out what the circuit computes.

A good way to proceed is to look at

the internal wires and see what logical function they would produce.

So, if we look at the f for instance.

So, as it says that would be the AND between the a and e. And the e

itself is the inverter of the b.

So, that that the b and a and not b.

Likewise the g would be b and not a.

And, then we have as a final result f or g. So,

that means that either a is true and b is false.

Or b is true and a is false and

that those are the two possibilities that turn the result true.

So, that means the result is true whenever a and b are different.

So, the right solution is this one here.