From Nand To Lambda

Ryan Moore

Engineer at MX.com

Volunteer Teaching Refugees to Code

Musician!

Lover of Haskell!

InSPiRAtion

Haskell Programming

From Nand To Tetris

From First Principles

Build a Modern Computer

From First Principles

From First Principles!

  • Boolean Combinatory Circuits in Haskell & HDL
  • Arithmetic Combinatory Circuits in Haskell & HDL
  • Arithmetic Logic Unit in Haskell & HDL
  • Sequential Circuits IN Haskell & HDL
  • RAM in Haskell & HDL

INstaLl Some Biz

1. Exercise & Tools Repo: https://gitlab.com/paniclater/nand-to-lambda-workshop

2. Haskell: https://www.haskell.org/platform/

3. Hardware Simulation: http://www.nand2tetris.org/software.php

Haskell

&

Hardware Description Language

Similarities?

  • Function input & output
  • Function Composition
  • Declarative, not imperative
  • Achieves side effects through types

Haskell Syntax Foundation

  • Function declaration
  • Let ... in
  • Where
  • Tuple
  • Type & Data Constructors
  • Pattern Matching
CHIP MyChip {
    IN a, b;  // can be many ins
    OUT out;  // can be many outs

    PARTS:
    //Here we connect inputs and outputs using other chips!
    //Wire the inputs a & b to BuiltInChip inputs,
    //assign its output to a variable
    BuiltInChip(aInput=a, bInput=b, out=myVar)

    //Wire in the variable myVar (output of other chip) to BuiltInChips input,
    //wire its output to the output of MyChip
    BuiltInChip(a=myVar, b=myVar, out=out)
}

HDL

What's Up With NAND?

Input A Input B Output
High High Low
High Low High
Low High High
Low Low High

NAND in Haskell

NOT

Input A Input B
High Low
Low High

Not IN HAskell

Not in HDL

Now Implement:

  • and
  • or
  • xor
  • mux
  • dmux
  • not16
  • and16
  • or16
  • mux16
  • mux4Way
  • dmux4Way
  • or8Way
  • dmux8Way
  • mux4Way16
  • mux8Way16

Arithmetic Combinatory circuits

Operand Operand Sum Carry
1 1 0 1
1 0 1 0
0 1 1 0
0 0 0 0

Half Adder

Operand Operand Operand Sum Carry
1 1 1 1 1
1 1 0 0 1
1 0 0 1 0
0 0 0 0 0

Full Adder

What's A Monoid, Precious?

  • Algebraic Structure
  • Associative Binary Operation
  • Identity Element
  • Monoid a
  • mappend :: a -> a -> a
  • mempty :: a

Monoid OR

Monoid SUM

What About A Monoidal Nand?

Nand does not have an identity value!

What About A Semigroup Nand?

Nand is not associative!

Now Implement:

  • halfAdder
  • fullAdder
  • add16
  • increment16

Extra stars if you use monoid instances in your haskell implementation!

Arithmetic Logic Unit

single Combinatory Logic Chip For All Computation!

What About Negative Numbers?

What About Subtraction?

Two's Compliment Principle

-x = 2^n - x

where x is a positive integer

n is the total binary digits availiable

In a 5 bit binary system n is 5

2^5 - 2 = 30

"two" x would be 00010

"thirty" is 11110

11110 + 00010 = 100000

Since there are only 5 bits, we trim off the 1 and get 00000

Two's Compliment Principle

The system can code a total of 2^n signed numbers

Max and min numbers are (2^n) - 1 and -2^ (n-1)

All negative numbers begin with 1

All positive numbers begin with 0

To get (-x) from x one can leave all the trailing 0s, keep the least significant 1 intact, then flip all the remaining bits

0001

No trailing zeros, keep 1.

1

Flip the other bits

lets try with 1

1111

0110

Keep the trailing zero and the first 1.

10

Flip the other bits

lets try with 6

1010

Shortcut

Flip all the bits and add 1

0110

lets try with 6

flip bits

1001

add 1

1010

Two's Compliment Principle

We've already implemented increment by 1 gates!

We've already implemented bit flipping gates!

We've already solved negative numbers and subtraction!

ALU SPEC

Inputs:

16 bit bus x[16]

16 bit bus y[16]

Control bit zx

Control bit nx

Control bit zy

Control bit ny

Control bit f

Control bit no

ALU SPEC

Outputs:

Control bit zr

Control bit ng

16 bit bus z[16]

ALU SPEC

Rules:

  1. Zero x input if zx
  2. Negate x input if nx
  3. Zero y input if zy
  4. Negate the y input with ny
  5. Concatenate with Add if f
  6. Concatenate with And if not f
  7. Negate the output if no

ALU TRUTH TABLE

Implement ALU in Haskell and HDL!

Parser Combinators Turning Assembly To Machine Code

INtro To Hack ASsembly

INtro To Hack ASsembly

// Computes R0 = 2 + 3  (R0 refers to RAM[0])

@2
D=A
@3
D=D+A
@0
M=D

INtro To Hack ASsembly

/***
Predefined Symbols

    A: Address Register.
    D: Data Register.
    M: Refers to the register in Main Memory whose address is currently stored in A.
    SP: RAM address 0.
    LCL: RAM address 1.
    ARG: RAM address 2.
    THIS: RAM address 3.
    THAT: RAM address 4.
    R0-R15: Addresses of 16 RAM Registers, mapped from 0 to 15.
    SCREEN: Base address of the Screen Map in Main Memory, which is equal to 16384.
    KBD: Keyboard Register address in Main Memory, which is equal to 24576.
**/

rEgisters

A, D, M

INStructions

  • A-Instruction
    • Concrete Address
    • Symbolic Address
  • C-Instruction
  • Loop

A INStructions

  • Concrete Address: @1010101010101010
  • Symbolic Address: @Counter, @15

If the address is concrete, store that address in the A register.

If the address is symbolic, look up the symbol's address and then store that address in the A register.

C INStructions

Destination + Computation + Jump

//Destination can be A, D, M or some combination
A
D
M
AD
ADM

//Computation with operators +,-,|,!,& and arguments A,D,M,1,0
A+D
D-M
!A
A&M

//Jump can be:
JMP
JEQ
JNE
JLT
JGE
JGT
JLE 

C INStructions

Computation Is RequireD

Destination and Jump Optional

//Computation only
D + M 
//Computation and Destination
D=0 
//Computation and Jump
D-1;JEQ
//All Three
M=A&D;JGT 

Predefined Symbols

/***
Predefined Symbols

    A: Address Register.
    D: Data Register.
    M: Refers to the register in Main Memory whose address is currently stored in A.
    SP: RAM address 0.
    LCL: RAM address 1.
    ARG: RAM address 2.
    THIS: RAM address 3.
    THAT: RAM address 4.
    R0-R15: Addresses of 16 RAM Registers, mapped from 0 to 15.
    SCREEN: Base address of the Screen Map in Main Memory, which is equal to 16384.
    KBD: Keyboard Register address in Main Memory, which is equal to 24576.
**/

INtro To AppLicative And Alternative

Pure

wraps a value into an applicative

(<*>)

applies a function contained by an applicative to a value held in another

(<|>)

the (<*>) that keeps trying!

Let's Parse Some Assembly!

Resources

Stephen Diel: Parsing

http://dev.stephendiehl.com/fun/002_parsers.html

Allele Dev: Applicatives and Alternatives

https://queertypes.com/posts/59-applicatives-alternatives.html

Allele Dev: Applicatives and Alternatives

https://queertypes.com/posts/59-applicatives-alternatives.html

Haskell Programming From First Principles: Chapter 14

http://haskellbook.com/

From Nand To Lambda

By Ryan Moore

From Nand To Lambda

Slides for workshop version of my journey through learning physical computing and functional programming side by side from the course Nand2Tetris: Build A Computer from First Principles and the book Haskell Programming from Foundational Principles.

  • 739