 Hi, I'll start by describing what the stock is and what it is not about. This is my second stock here at the Cultural Council. I was here last year also, and last year too I have spoken about something I've been doing in Berlin, whereas last year's stock was about something I was trying at work. This is something I'm trying on my own time. This is an experience report. How many of you here have not computer science trained? How many? Okay, enough to get a sense of what I'm going to do. So I'm a programmer by profession. I've been programming for a while now, about 15 years or more. But I was trained as a Mechanical Engineering. Programming is okay. It's my own. And while I haven't recently reasoned about it, computer science is not something which I've learned from. So every now and then I could be computer science books and I'd make an attempt to go through them with many pieces. And this time I decided to program my way through it. And so I was also dabbling in online. I chose to do so in an online. So this is an experience report of what I have tried in online. And my journey of learning computer science while trying to implement some of the stuff, computer architecture, while trying to implement some of the things. So this is not an introduction to online. We're not familiar with online. This is not an introduction. This is definitely not an introduction to functional programming. It is not meant to be an introduction to computer architecture. I'll still walk you through some of the stuff so that you can see some context about what I have done. Okay, I work. My grandiose section is director of engineering here. I'm a programmer. I manage the product for instance. So at work I use mostly Java and Scala with the world Python and some Erlang. If you were here in 2016, you probably would have heard my story about how that bit of Erlang came into my work. What I found in the intervening years since 2015 is that Erlang is very hard to find for a decent time. And it is hardest to convince people. For instance, let's say you're using Java. You pick up Intlizia idea and that's about all your tools in one. Whereas you start with Erlang, while the language holds great promise, you have to look around somebody to this rebar, to this unit, then how do you deploy it, and so on. While the tools are there, there is no one single package for everything I see. In fact, starting with editing, there are decent plugins for Intlizia and so on. But many people still prefer the unit. Not that it might be bad. These are the challenges. A bit about my employer, Rofia. We have a product, we have a suite of products which are in the financial space. We started off as a mint clone for Intlizia. Mint for Intlizia, where you can track your person. That was about seven, eight years ago. And then we've grown to offer a suite of products. I'll tell you a bit about the product. I am Henish. How many of you here have applied for a loan from Intlizia? There you go. We submit a bunch of documents. I'm meant to prove who you are. And then assess your creditworthiness or income. Perfeurs has largely automated this product. We submit bank documents. This is a bank statement. A company bank statement. In case you are in-situ fuel and stuff. We process it, analyze it, then give you a report. We have about 120 customers. Most of India's private banks are our customers. So if you apply for a loan from, let's say, Goat & Bank, Bajaj fits HTSC and so on. A good chance that your application goes to our office. We process about 100,000 customers. Enough about Perfeurs. Let's come to computer architecture. I started my quest using one of the classic books of computer architecture. Andrew S. Tannenbaum, Structured Computer Organization. In my case, I used the fourth edition because that's what I had. Later editions have come out. Computer architecture, Tannenbaum defines it as consisting of multiple levels. These are the six levels and classic levels. There is some interlap between levels. These are not set in stone. Even though the first three more or less seems to be stable, whereas the fourth, five and six, you have a great amount of variance. I worked through the first level, completed the second level also, and I'm in the process of completing the third level. I'm yet to complete the third level. The top will largely focus on the first level as well as the code that I'm going to show you. Any questions? Let's start with the digital logic level. Digital logic is the simplest level. It is effectively one level above the electronic one. You have these gates. I'm sure that all of you would have heard of the almighty NAND group. These devices are essentially linear or rather they are not digital. Using them, you can reliably... A gate is not a digital, a non-digital. But using it, you can reliably... The common gates are... I'm sure that most of you have seen these big gates. So the NAND gate is... The NAND gate is particularly considered the mother gate. There are simple reasons that it needs to be fabricated and that all the other gates can be made of. This is again computer architecture 101. So that's the digital level. Everything consists of a bunch of gates. You put them together in different combinations to get combinative circuit. And then you add more and more on top of the circuit until you get to the next level. So let us look at the next level. This is micro-architecture. Once you reach micro-architecture, things become a bit more interesting. At micro-architecture level, you have local... Starting with one bit all the way up to your 32-bit register, 64-bit register, and so on. Then you have the heart of your computer. And as a political logic processing unit, you can again start with a one-bit ALU and go all the way up to 32-bit, 64-bit, or any number of bits and pieces. Then you have registers and then you have the ALU. These are connected together in what is called the data path. In fact, that's going to be one of the key things that we'll talk about. The data path is essentially what goes into the ALU and what goes into it. Where does it come from and where does it get stored That is the GIST property. The typical operation is something like this. An ALU has two inputs and one output. There are other bits and pieces that come into it. But for most practical cases, there are two inputs and one output. You can load these two inputs from a variety of registers and then you can perform an operation and the output of that operation can be stored in the variety of registers. Any operation is typically, the process is something like identify which registers do the operands come from, send them through the ALU, let it finish the computation. Look at the outcome. Decide which register should the outcome be stored in to perform that operation. That is the GIST of data path operation. The operations are controlled by what is called a micro program. Now micro programs, these days are emitted directly in the hardware but from a student's perspective it makes sense to look at them not as an abstraction but rather look at them in detail so that you actually understand them. So if you buy a modern machine, chances are that your micro program is already there late into the hardware. But for my experience process, I tried to go in and look at how the micro program was done in a classic fashion. For example, Tanon Bomb, he actually sells out his program and then he builds a subset of the JVN, the integer for the JVN on top. What are micro programs? It's effectively an interpreter for the level above. In fact, that is a pattern that you see throughout the computer. Every level acts as an interpreter or maybe a translator for the level above. In some cases there are interpreters, in some cases there are translators or compilers. But effectively, each level talks to the level below and then we can talk that language. In this case, the micro program essentially understands what is being said in every level above and it talks to the level below and it does less than one. Let's take an app. In fact, you fetch the instructions. You find out the operating. You load them into registers. When you fetch operating instruction, it comes from a particular part of the main memory called the microphone. It comes from the memory. You load them into the app. The sum is computed by daily view and the result is routed to a register from memory. This is the data path in all its glory. The quick question, how many can recall the names of all the... I keep forgetting. CCVN, I'm picking three classes. No, that's not what it is. It's a constant good point. LVE is not last made. So how... This is the data path. What trips up some people, it tripped me up is that you forget that this is not a combinatory circuit. Whereas while these things are built up of combinatory circuits, it is not a combinatory circuit where you apply the values and your output is ready like that. These things, it's more like an orchestra where somebody has to chord area off. You have a beginning and then you have an end and you have several things distinct happening. These different steps are formed by combinatory circuits. But there is a definite gap in between. Things don't get over like in... The moment you get the values or rather if you try to make it instantaneous then you get corrupted by the order. It has to be sequenced. Loading the registers and into the bus. That has to be step one. You ask the ALU to do its job. When you wait for the output to stabilize in the output, then you push the output maybe into the same region. So that there is a sequence in order. And that kind of trips people up. It tripped me up. This classic picture, we'll come back to this. So effectively you have a conductor or an orchestrator who is responsible for making sure that these things happen. The clock is nothing but an entity which goes... effectively it gives a tick which is what is happening here. And then it goes stuck again. Between the tick and the clock several things happen. How do you model that? The faster your ticks and clocks the more things can be accomplished in a given period of time. So over 40 years your tick clocks have gone from 1 MHz all the way to 3.4 to 5 MHz. You have that and it continues to... between your machines are capable of achieving more and more with time. Keep these things in mind. We'll come back to this. When it comes down to programming when you try to program this these things become relevant, particularly in order. This is the gore pair of the whole thing being orchestrated. So you have a control store there. It sends out a particular signal. It's like some 40 bits or so tells you each part of what. For example, there are 6 plus 2 8 controls which tell you ALU which options to perform and any additions that need to be performed after the ALU. Like shifting it... There are other... For example, there is a bus control at the far right B. It controls what goes into the B bus. So these are the names. Don't remember that. Interestingly, OPC he said it's a scratch there was no definitive name about what do these feel like. Old program counter seems favored but there is a very categorical name that I'd like to... Now how does the ALU know what to do? The ALU gets 6 bits in and 2 out as dub control. Those 6 bits control what it does. For example, 6 bits represents a function of the A. Let's take the first one, just for example. You have... The first 2 bits are effectively a classic decoder where it tells you what to do. Then each of the inputs is the input A enabled is the second input enabled should the input be inverted is there an increment or a carry. If this is the particular sequence then all it does is take the A and then out to the A. Don't worry about what... Why would you do that? Never mind that. But that is what it can do. It can do an A plus 1, B plus 1, A plus 1, so on. A or B. You can form 4 different functions. A and B, A or B, not B and then A plus 1. These are the options that you can do and with a little jugglery you can do a bunch of things around. There are about 16 functions. Now on top of this comes the instructions of architecture which is effectively if you buy a chip and you get a manual with it whatever it says in there typically is the spacing. And this is these 8 instructions which are carried out interpretively by the microphone or in these days by the hardware but for our for this session we'll consider that these are interpretable. This is the iJVM it's a very modern subject called iJVM. These are the might level 2 instructions don't worry too much about it. But let's just give you an idea of what is available and what is possible. So everything is identified by a hex code and then you have a name third level is called the OS machine level. Now I'm a bit confused here because this is traditionally the OS level but it's not the OS as we know this is not probably the OS this is like one level below. We understand this as a Windows and Linux but this is not the OS. So you have the ability to run two or more programs concurrently because that's out there. We're not there in the early era yet but we can do stuff. And then you have more variation in design whereas the chip level and the OS level doesn't matter which CPU you're looking at it is broadly the same from level 2 or level 3 onwards the number of variations increases drastically. So level 4 and higher level 4 and higher are intended for application. So if you're writing Assettingly or if you're writing C or any of these modern languages in your fifth level. Level 4 is typically Assettingly. Level 5 is all these high level programming languages. Tannenbottom doesn't mention Erlang in the basic C and C classes but Erlang fits into the language. Whereas level 1, 2 and 3 rely on numeric languages level 4 and 5 usually have the word and phrases which make more sense in humans. Level 4 is an assembly language it's again all these things cascade down level 5 is converted to level 4 which gets interpreted at level 2 and 2. High level languages hundreds of them exist and the programs are translated into level 3 and 4 and these translators are they are a level 5 language which do use interpreters. This is all for the problem. Let's come to the crux of the problem. How do we go about implementing this in our language? Let's start at the simplest level. How do you implement a gate? Any thoughts? How do you implement a gate in the language I just want an AND gate. You write a function. In fact, I did it. I started with a function. Once you have a function then you can compose them and do a bunch of stuff with them. Next comes the level 1. Data path, microcontroller and then we'll come back. Let's start with gates. When I started with Erlang my first thing was to use the atoms 2 and 4 which are the primary values in our language. It has certain advantages. First of all, a bank is not strictly tied but if you use 2 and 4 then you get an additional degree of type safety. Otherwise you have to we'll see why. 2 and 4 makes it very clear you are only accessing 2 atoms and your guards become easier. The problem with 2 and 4 is that they do not map to the domains. I couldn't find a single textbook where 2 and 4 make use. Maybe when I was explaining Boolean, I would talk in terms of 2 and 4 but very quickly things would convert to go into 0 and 1. So to match the domain and to remove that additional overhead of thinking in terms of 2 and 4 then converting to 0 and 1. I switched to 0 and 1. So my question had 0 and 1. So 0 and 1 gives you 8 and friendly. However, you cannot use the built-in operator. If you want to do an and of 0 and 1 you can't do that. Whereas an and of 2 and 4 there are built-in operators in a line that you do. So 0 and 1 you have to invent your own writing function and your guards become a bit more complex. I'll show you a snippet of 4 which we'll illustrate more. Then I went ahead and said fine I'll write one function per gate with an and and xor and so on. The second approach is to write an and then use an and to build an. So let's take a look at some code. So I have written 5 gates here. These are the classic gates. I have an and gate, I have an and gate and not gate or gate and xor. Let's start with the and gate since it's the mother gate. I've chosen to implement the gates separate rather than using a This is my proof tape. Thanks to pattern matching and function heads, I can write it pretty much as though I'm writing the proof tape. So writing them, testing them is very straightforward. I haven't used any guards because this is pretty much even though there is no static typing this pretty much makes sure that at run time things will be caught and then it will crash. This will not always hold true as we've seen. This is a more defined approach where I define the gates in terms of an and gate. Now here I have a problem. I don't want to spell out 4 heads for the and gate because I'm going to invoke an and gate which means I'm obliged to use various, I can't do what I'm doing otherwise I have to repeat the whole whereas body of the function remains. And the guards are cumbersome. A and B are integral. Well they are integral. But they are very specific. This is not a Haskell where I can say A is either 0 or 1. So I have to put all these very cumbersome guards to make sure that the client code which calls this passes through. Once I do that, I can go to the and gate and the and gate will take care of it. And here are the other gates implemented in terms of. Okay that was easy. Let's I mean let's get deeper in how do you are true you can my point is to illustrate that I have to write an instance rather than relying on a type system. That was my point. In fact what I've seen is that I looked at code out in the while. Maybe at the top of the API lower down guards are non-existent. I used to spec later on which I'll come in. Now comes the crux or rather get into more interesting therapy. I have a combinator circuit. How do I represent connection? If the circuit is simple enough I can compose functions like I did with the NANDP. But as a circuit becomes more complex I'm obliged to have connections. These wires that lead in one part this is a half adder and that's a full adder. You can see the individual gates but do you see these the same input is shared by a bunch of gates and then there one of the output goes another gate. When you're composing functions this is not easy to cool off. Whereas the outputs naturally map it's okay but the moment an output is shared between two different gates you have to store it in a variable. Plus function construction works with combinator circuits. But how do you represent memory by its nature? It means there's an element to find. How do you represent that in a function? A function by nature cannot hold state. I mean for it to be a pure function. I mean Java of course may disagree but the function cannot hold state. That is one problem. Another problem is that many gates as I mentioned they have different inputs. How do you connect those inputs? A-L-U to find the picture this is your one bit A-L-U look at this argument. It's not two inputs, it's four inputs. In fact there are cases where you have n number of inputs which are odd together and then you have another. How do you represent that? Let's go ahead and run another course. So here is my one bit A-L-U. Can you see that? This is my one bit A-L-U represented as a pure function. It gets these many inputs it uses variables to compute various things and then it gives you the output and the layout. You can combine n number of these to build a ripple carry. You can have 16 bit A-L-U we won't be doing that we directly jump to 32 bit but this is your function at one bit this works because an A-L-U still is a common total it doesn't hold any memory there is no time bound temperance so I can pull this off. I am not going to explain this in detail but effectively you have whatever I showed you in the last picture you have a decoder you have a logical unit you have a full adder and then finally you use an OR gate So now come to the data part Why do we need clocks? How do we represent clocks? Now how do you represent clocks? And how do you represent all these temperatures? My solution was to use a process holding a state to represent some of the clock so your bus is effectively a process its state is a name not really needed but you can use some other variable also for a human from a human perspective I have said I thought name made more sense it has a width, it could be a 32 bit bus it could be 8 bit controlled bus and so on and it holds a name a register similarly you have a name, you have some buses attached to it an ALU which is a 32 bit ALU it does not really need state but it needs state in this case because it needs to keep track of which buses are doing it and then clock signals are modeled at this effectively we have a tick and a clock it is slightly more complicated than a tick and a clock but that is what happens so let us take a quick look at bus clock so this is my bus I have used the gen server behavior of all I to make it easy to create processes which holds state so I have a bus I can initiate a bus which will call gen server keep track of the name and width of the bus I have a get name, I have a get value a get width and a set value these are all synchronous calls because you need to know that the bus output is stable before you initiate another operation you cannot do it as simple at that low level there is no as simple it has to be simple I have some callback functions here I hope people understand gen server but effectively it is a think of it as a generic way of handling processes which holds state so I have get name, get value, get width set and stuff like that and finally there is a terminal which makes sure that the buses terminate I like to test things out as I go so I decided to start with a one bit a right test run right test for a full ladder and so on this is where I come into some of the things of our life so let's take a look at some of the tests how many here are familiar with our life how many have used eunit I come from or rather I use testng and junit that work and coming from those two eunit was a root server eunit swallows your debug it just swallows so if you want to have a debug output you have to use one of the macros that eunit has which means your source code will be populated with macros which comes from the testing I find that unaccept that's like hello they are supposed to be this part the setup and tear down put me a better part of who I was to figure out because you have test generators and testing functions and blah blah blah and while the online documentation is sparse I was able to find some good help from learny from online it's also a book so let's look at a test for ALU when you start an ALU you create all the wires wires are essentially one bit you create the wires they have names and then you create an ALU and you tell the ALU that these are the connections that are there these are the wires when it comes to a 32 bit ALU after that you run it through a bunch of operations these are the operations that are permitted and you have the results so you ensure that you have an INV, AAV and blah blah blah and you ensure that for each operation the ALU is returning ok so somebody suggested using expected equal to active that is your pattern matching but that works but the problem is that in the absence of assert the tests are not counted so if I want to know if I have written 700 or 800 tests or whatever I can't unless I use a question mark so if anybody knows the author of the unit or if anybody is willing to come to me this is an area which would make the programmers much easier second observation as you move on to higher bits 32 bit whatever online makes binary and bits reading very easy bitwise operations are active you get bitwise operators provided you are willing to work with integers you don't get any for bits string than binaries so if I want to flip all the bits of a binary sorry you write a function not that I think a function is difficult but I was surprised to find that given that the language originate with the telecom domain works with binary expressions this would be the problem these are some of the things I had to write a custom function I actually wrote a small mini library called bitslib this is my mini hl library for bits so effectively you have adding two bits you have adding individual bits, adding bit strings how do you do a two-sufarm treatment of a series of bits how do you invert the bits practically everything is implemented in terms of because of functions this works, it's no harm in and it's a good exercise to go through but when you come to serious bit-munging you probably don't want to go through a bunch you want to have an operator which will do it more efficiently at the beam level I use spec in leostatic type one of my hascular friends looked at it and very secretive but this is all I had to go over so I wrote a bit of typing I'm sure that part these are my types they are incomplete so interesting part you have you have a binary value this is 0 or 1 a bus can only be modeled as a process my width is one of these numbers I have a connection and I have a list of connections that's essentially all of it it works for some value it works but it's not particularly pleasant dialyzer is low for my likelihood I would like my type system to be checked with every build, every test and so on but if I attach dialyzer to my build process I can't run it like every two minutes as I want in the data path we get into some more interesting parts these are things which happen in the sequence but if you send a tick to every component you can't ensure the sequence initially I started with the naive idea that I'll have a tick and a clock but no you have to break it up the first signal will set up whatever the second signal will tell the buses to get loaded and the third signal will tell the ALU you cannot have a single signal it's interpreted in a different way otherwise your code handling becomes very rough and you lose all you've got so these are the ALU functions interestingly I found a bug in pan and bombs listing in edition 4 so let's come to the bulk of the code yeah this is my 32 bit ALU or rather test for the same to write all the 16 functions listed there so you have the first function which computes A can you see here the first one is compute A, compute B A plus B these are my test cases the data for the test cases this is a 32 bit ALU modeled as a process in essence it gets all these signals these are the control signals it has a list of connections and effectively it's a list of 3 buses plus the control bus you have an A bus, you have a B bus and the control bus it tells you what to do you break it down shift, left, right, etc I have chosen to model the ALU and the shifter as a single unit because to me it made more sense so this is an ALU also it also has a built-in shifter it can shift the results to those two now this is brilliant I don't have to worry about finding out which bit does what I can just unpack it so based on the decoder combinations I do A and B, A or B, not B or A of every bus here it's called out let's look at A and B A and B there is no zip width for bit strings so I had to write my own because you have to take one bit at a time for two bit strings and compare them so this part is out for the A and B or A or B now let's go back this is the micro-instruction format it has about 36 bits what happens now unpacking this in Erlang was a cinch you probably saw something similar to this in Francisco's speech so that's my micro-instruction I can break it down in any fashion I want then send these signals to other components so this part is very easy setting up a process it's easy bit mangy, not so easy I wanted to cover a bit more but there are time constraints so this is what I want to do I want to complete the ISI level architecture it's still a working process I would like to complete up to assembly level I want to have a Daemon PUI to actually visualise the data part so if you have other ideas or questions here and we are hiring if you know Erlang I have chosen not to model them at the moment but in my notes what I have done is you have effectively a way to delay delivering a message or you have ways to delay acting on the message so when you initiate a component you can very well give it as a property of the component because it's a process to tell it that delay your responses where those units are propagation but strictly speaking what I see is that propagation delay it makes sense to model it from a learning perspective but otherwise I'll just skip it and go through because I have a finite delay in terms of execution I have to wait for the signals to propagate I need to get a signal back from the bus saying that the value is taken that itself is not going to work yeah this is my thought I would like to put a delay built into the component which you can configure a component okay delay sending or responding to your message oh yeah I went through that too in fact I looked at their HDL format and I started passing it then I came with my own equivalent I'll show you a thing I wrote so this is my poor man's version of a full adder which I have written out I have a simple passer for it so you have wires you declare all the wires then you declare the internal wires then you connect these this has evolved it's still evolving ideally I'd like to reach a point where I can pass their HDL files in fact that's where I started I looked at that, I liked their idea I looked at the java code but then in java you have all these difficulties they actually jump through hoops to accomplish several things it's a nice beginner's product