I built my own 16-Bit CPU in Excel

Inkbox
27 Jan 202416:27

Summary

TLDRThe video details the speaker's project of building a fully functional 16-bit CPU inside a regular Excel spreadsheet, using only native Excel formulas and features. It walks through the design and implementation of the CPU components like the control unit, registers, ALU, memory, and an instruction set architecture. A custom assembly language, compiler, and sample programs are created to demonstrate running code on the Excel CPU. Despite slow speeds, it serves as an interactive tool to visualize a basic CPU's inner workings one cycle at a time.

Takeaways

  • 😀 Built a fully functioning 16-bit CPU in Microsoft Excel using only formulas
  • 💡 Designed a custom 16-bit instruction set architecture with 25 opcodes and 23 instructions
  • 🤯 Compiled programs written in a custom assembly language EXCEL-ASM16 using a Python compiler
  • 📊 Fetched, decoded and executed instructions using an ALU and control unit formulas
  • 🖥️ Included general purpose registers, flags, program counter and 128KB RAM in the spreadsheet
  • 👨‍💻 Wrote programs to draw graphics, play music and run algorithms on the Excel CPU
  • ⏱️ Ran the CPU at only 2-3 Hz by manually advancing the clock signal making it very slow
  • 📺 Built a 128x128 pixel display with 16 color options using 4KB of the RAM
  • 🔌 Added handy buttons for resetting, running in manual mode and reading compiled programs
  • 🆕 Made the CPU design, compiler and sample programs available for download to try yourself

Q & A

  • What is the CPU built in this project based on?

    -The CPU is built in Excel based on a custom 16-bit instruction set architecture designed specifically for this project.

  • How much RAM does the system have?

    -The system has 128 KB of RAM.

  • What is the purpose of the Control Unit?

    -The Control Unit decodes the opcode and operands from the instruction and produces the necessary signals to control other parts of the CPU.

  • How are system flags like carry, zero, sign, and overflow set?

    -The carry flag is set when the ALU result exceeds 16 bits. The zero flag checks if the ALU result is 0. The sign flag checks the top bit of the ALU result. The overflow flag checks for overflow conditions.

  • What is the purpose of the Program Counter?

    -The Program Counter contains the address of the next instruction to execute. It handles sequencing through a program.

  • How is video output achieved?

    -The last 4KB of RAM is used as video RAM, representing a 128x128 pixel display with 16 colors. Conditional formatting simulates pixels.

  • What programming language is used for compilation?

    -A custom assembly language called EXCEL-ASM16 was designed for the instruction set. Compilation is handled externally in Python.

  • How are compiled programs loaded into the system?

    -Compiled code is saved to a separate Excel spreadsheet acting as ROM. A switch allows the CPU to read from this ROM.

  • What is the purpose of the manual override?

    -A manual override mode allows instructions to be directly specified, useful for testing during development.

  • How fast can the CPU run?

    -The purely formula-based Excel implementation allows a speed of only 2-3 Hz, requiring manual advancement of the clock signal.

Outlines

00:00

😄 Introducing the Amazing Excel CPU

The paragraph introduces the concept of building a fully functioning 16-bit CPU entirely within a regular Excel spreadsheet, without using any plugins or scripts. It explains the basic computing capabilities already present in spreadsheets. It then outlines the key components of a typical computer that will be emulated, including the CPU, RAM, registers, and display.

05:05

👨‍💻 Programming the Fundamentals

The paragraph discusses low-level digital logic gates like decoders and flip flops that can be built using Excel formulas. It then explains the need for a custom 16-bit Instruction Set Architecture (ISA) that defines all CPU operations. The ISA includes 25 opcodes and 23 instructions for arithmetic, logic, data movement etc. The basic functioning of a CPU is described - fetching instructions from memory, decoding them, execution by the ALU, and writing back registers.

10:09

⚙️ Assembling the Main Units

The paragraph explains the key CPU units - the Fetch unit, Control Unit, ALU, Register File, and Program Counter. Formulas for the ALU operations are shown. Other critical components like the clock, registers, flags, and program flow control using the PC are covered. Key multiplexers and data paths tying together the main units are also depicted.

15:13

📟 Building the Memory Subsystem

The paragraph discusses memory organization with 128KB RAM and a 4KB display, along with access logic. Formulas for memory read/write are shown. The clock and reset options are enhanced. A manual instruction override capability is introduced. The complex video memory mapping and pixel color encoding using conditional formatting is depicted.

Mindmap

Keywords

💡CPU

CPU stands for Central Processing Unit. It is the main component of a computer that interprets instructions and performs calculations and operations. The video focuses on building a 16-bit CPU entirely within an Excel spreadsheet, with features like registers, an arithmetic logic unit, program counter, etc. The CPU is the core of the computer system created in Excel.

💡RAM

RAM stands for Random Access Memory. It is the memory or storage space in a computer where data and programs are stored when the computer is running. The video's Excel computer system has 128KB of RAM, implemented through Excel formulas and cells. RAM provides space for users to run programs on the custom CPU.

💡Registers

Registers are small units of high speed storage within a CPU used to store and manipulate data. The video's CPU design has 16 general purpose 16-bit registers inside the register file component. Registers provide quick access to data for processing instructions.

💡ALU

ALU stands for Arithmetic Logic Unit. It is the component of a CPU that carries out arithmetic and logical operations. The video shows an ALU built in Excel that can do 16 different functions on two operands. The ALU is called the heart of the CPU.

💡Control Unit

The Control Unit is part of the CPU that interprets opcodes in instructions and generates control signals for other components. The video's Control Unit decodes instructions and produces output signals that operate the ALU, Registers, Program Counter, etc.

💡Instruction Set

An instruction set is the collection of instructions supported by a CPU. The video designs a custom 16-bit instruction set called EXCEL-ASM16 for the Excel CPU, with instructions like load, store, add, multiply, etc. The instruction set allows programs to be written for the CPU.

💡Clock

A clock signal synchronizes all the operations in a digital circuit like a CPU. The video shows a clock built in Excel that alternates between 0 and 1 to trigger each step of the fetch-decode-execute cycle. The clock coordinates the entire spreadsheet CPU system.

💡Compiler

A compiler is a program that converts code written in a high level language into binary machine code for a CPU. The video uses a Python compiler to compile EXCEL-ASM16 code into binary instructions to load into the Excel CPU's memory.

💡Memory

Memory refers to the total address space in a computer system used to store data and programs. The Excel CPU has a 128KB memory map, with RAM, space for programs, and a 4KB display section. Memory holds all information needed for running programs.

💡Machine Code

Machine code refers to the low level binary instructions executed directly by a CPU. The video's compiler converts EXCEL-ASM16 code to 16-bit Excel machine code that can be loaded into the CPU's memory and run by the processor.

Highlights

Spreadsheets are just fancy calculators that can be used to emulate a CPU

Uses binary logic and integer conversion in formulas to create basic logic gates like decoders in Excel

Had to flip circuit diagrams 90 degrees for them to work properly due to how Excel calculates formulas

Designed a custom 16-bit CPU instruction set architecture with 25 opcodes and 23 instructions

Built main CPU components like fetch, control, ALU, register file, and program counter units in Excel

128KB RAM represented as 256x256 table, uses formulas to read/write to cells based on 16-bit addresses

4K display created using conditional formatting for 16 colors on 128x128 pixel sheet area

Wrote EXCEL-ASM16 assembly language and Python compiler to generate programs for the Excel CPU

Programs load into separate ROM sheet, CPU reads from it into memory before executing

Built functioning CPU, memory, display fully within Excel with no plugins or scripts

Able to create graphics demos, games, calculations but limited to 2-3Hz even when manually stepping

Useful for visualizing processor components and instructions one cycle at a time

Entire project including CPU sheet, compiler, programs available to download and experiment with

Very slow but impressive feat of engineering everything in plain Excel formulas

Could help beginners understand low-level CPU functionality interactively

Transcripts

play00:00

A 16-bit CPU, 128 Kilobytes of RAM, a 4K  monitor, all in one Excel file? No Visual  

play00:05

Basic Scripts, no plugins, just a regular  spreadsheet. Is it even possible? It's the  

play00:09

best kind of possible, theoretically possible. This video brought to you in part by Brilliant.  

play00:13

Spreadsheets are just fancy calculators. Data in  data out. And if we go by the literal definition  

play00:18

of "something that computes" then Excel  is already a very competent computer. But  

play00:22

a computer like your PC or other device is a bit  more complex. That has a Central Processing Unit,  

play00:27

Gigabytes of Random Access Memory, and some  kind of pixel based display. But essentially,  

play00:32

it's still just a calculator, with the CPU  being made of different components that do  

play00:35

a more advanced version of data in data out. And at a low level, it isn’t hard to emulate that  

play00:40

in Excel. For example, this is a 3-bit to 8-bit  decoder chip, it takes in a 3-bit binary signal,  

play00:46

representing 0 to 7, and gives the one  corresponding output signal. The magic,  

play00:50

or should I say the logic, of everything happens  here, in the formula bar. If you think Excel is  

play00:55

boring it's because you've never known about  the power of Excel formulas. The formula for  

play00:59

each output pin cell uses a combination  of binary logic and integer conversion to  

play01:03

correctly compute the output. And I can also  reference other cells in this formula as well,  

play01:07

say on a 8-bit to 3-bit encoder, where the input  here is referencing the output of the first chip,  

play01:12

that's like virtually wiring these pins together.  Then with three more functions for the output pins  

play01:17

here, I have two chips that have the opposite  function, operating in plain old Excel.  

play01:22

But before we take a deep dive into spreadsheets,  a word from this video's returning sponsor  

play01:25

Brilliant. If you, like me, love learning, but  don't have the time or sometimes motivation to  

play01:30

dedicate as you'd like, then Brilliant may be  just the thing for you. Brilliant has thousands  

play01:34

of interactive lessons for beginners and experts  alike. You can learn about Computer Science, Math,  

play01:39

and Data Analysis, with only 15 minutes  of interactive problem solving a day,  

play01:43

through bite-sized lessons that make learning fun  again. That’s the thing about Brilliant, I enjoy  

play01:47

going through the lessons, and I’m learning at  the same time. Try Brilliant for free for thirty  

play01:52

days by clicking on the link in the description  below or by visiting www.brilliant.org/Inkbox.  

play01:57

And if you're one of the first 200 people  to sign up you'll even get 20% off an annual  

play02:01

subscription. That's www.brilliant.org/Inkbox Now the medium of Excel is a bit different  

play02:06

from the typical resistors and transistors of a  physical computer, and so there are a few quirks  

play02:11

I have to deal with. Some things have simple  fixes, like in building a clock signal. This  

play02:15

runs off a simple formula that sets itself  to 0 if it's 1 and 1 if it's 0. Now, Excel  

play02:20

is smart enough to not just run this calculation  in a loop forever, but it's also smart enough to  

play02:24

let you do that if you want to anyways. By going  to options I can turn on iterative calculation,  

play02:29

and set it to update only one cycle at a time.  Then by pressing F9 or updating any cell, the  

play02:34

sheet recalculates and the clock signal updates. There are going to be lots of alternatives to what  

play02:39

I’m doing here by using scripts and stuff,  but if I stoop to that level then I’m not  

play02:43

actually using the full potential of Excel,  I’d just be writing a Visual Basic Program.  

play02:47

Anyways, to test this clock signal  out further I built a JK flip flop,  

play02:51

one of the fundamental components in low level  digital logic. But it didn't work. I know it  

play02:55

should work though because Wikipedia said it  would. But eventually I figured out what the  

play02:58

problem was. Excel updates from left to right,  top to bottom, so the physical alignment of the  

play03:03

values in the chip are critical to it working  properly. So, for the most part formulas should  

play03:07

only reference cells above, not below. Hopefully  it doesn't get any more complicated than that.  

play03:13

So, this is the new design for the JK flip  flop after I flipped it 90 degrees, and it  

play03:17

now works as intended. I’ve wired up four of  them together with a couple of binary AND gates,  

play03:22

and now I've got a working 4-bit counter that  counts based off the universal clock signal.  

play03:27

Now I could design the whole CPU at this level,  but there's one thing hodling me back from that,  

play03:32

my sanity. It'll be much easier to design the  CPU on a higher level based off of a custom  

play03:37

Instruction Set Architecture. An ISA describes  how a CPU should work, it's the rule book for the  

play03:42

data in data out process. It defines a list of CPU  instructions, and other features of the processor  

play03:47

including a set of registers, units of memory  used to store and manipulate data within the CPU,  

play03:52

mainly located within what's called the register  file. The main registers in a 64-bit CPU are,  

play03:57

you'll never guess, 64-bits long. My registers  will be 16-bits long, making this a 16-bit CPU.  

play04:04

While a typical CPU based on the x86-64  architecture has 981 instruction mnemonics  

play04:10

like MOV, ADD, and OR, there are actually  3,684 total variants. Meaning that ADD for  

play04:16

example has 6 unique opcodes used for working  with different parts of registers or memory.  

play04:21

Writing high level Assembly code, the programmer  doesn't have to worry about these differences,  

play04:25

but both the assembling process and  the CPU clearly distinguish the two.  

play04:29

But since the most common instructions are used  an order of magnitude more often than instructions  

play04:33

like PAVGB, I decided to not include several  thousand of them in my ISA, instead I boiled  

play04:38

everything down to a list of 25 opcodes, and 23  instruction mnemonics. Including loading, storing,  

play04:45

transferring from one register to another,  arithmetic operations, bitwise operations,  

play04:49

rolling, comparing, jumping, setting flags, and  NOP. I'm even including things like multiplication  

play04:54

and division, which aren't strictly necessary, but  it'll make programming things much easier later.  

play04:59

Speaking of programming, a program is a list of  instructions stored in memory. Each instruction  

play05:04

is carried out by fetching it from memory,  decoding it and producing necessary signals,  

play05:09

executing the operation, and storing the  output either back in the register file  

play05:13

or in the computer's memory. I can keep track  of the location of the next instruction using  

play05:18

a special register called the Program Counter,  and that's more or less the basic CPU design.  

play05:23

Following that cycle, the first thing to build  is the Fetch Unit, which reads the memory at  

play05:27

the address pointed to by the PC register.  The Instructions in my ISA are not a fixed  

play05:32

length. Some are 16 bits long, and others are  32 bit long, but the Fetch Unit here always  

play05:38

retrieves a full 32-bit value, both the PC and  the PC+1 value. But since both the PC Unit and  

play05:45

the Memory Unit haven't been built yet, I'll  have to skip most of that logic here for now.  

play05:49

After getting the instruction, it's passed on to  the Control Unit. Here the instruction is broken  

play05:53

into the specified opcode, the first register  operand, the 2nd register operand, and the  

play05:58

16-bit immediate attached value. So even though  a full 32-bit value was retrieved from memory,  

play06:03

the second 16 bits won’t affect anything for  most instructions. Each of this unit’s output  

play06:08

pins has a unique formula that, based on the  opcode, sets these signals according to this  

play06:12

chart here. These signals get carried off to  different parts of the CPU like the Arithmetic  

play06:17

Logic Unit, the beating heart of the CPU. The ALU preforms some kind of operation with  

play06:22

the two operands. The ALU operation and operand 1  come directly from the Control Unit, but operand 2  

play06:29

actually comes from an above multiplexer, since  it can be one of 6 different values, either 0,  

play06:34

the value of the second register, the memory value  of the address in the second register, the 4-bit  

play06:39

immediate value, the 16-bit immediate value,  or the memory value of that 16-bit immediate  

play06:44

address. Again, the Memory Unit isn't built yet,  so I’ll fill things in by hand temporarily.  

play06:49

The ALU operation is itself a 4-bit value, so  there are 16 different functions it can run,  

play06:55

including some non-arithmetic  actions, that result in a  

play06:58

32-bit output, 16 high bits and 16 low bits. These are the most important formulas in the whole  

play07:05

spreadsheet as it determines what the output of  the processor will be. Most of the operations are  

play07:10

straight forward and don’t affect the high 16-bits  at all, but the MULT instruction does result in a  

play07:16

full 32-bit result, so the low 16 bits will be  stored in the first specified register and the  

play07:21

high 16 bits in the second. Division will cause  the result to be stored in the first register,  

play07:26

with the modulus result in the second register. Rolling the bits left or right was a bit tricky  

play07:32

to figure out. The second operand here is the  4-bit immediate value, meaning that the bits can  

play07:37

roll left or right up to 15 times. Thankfully  Excel has a BITLSHIFT and BITRSHIFT function,  

play07:43

and with a little more algebra I figured it out. Before the next unit, I need to pass the two  

play07:49

results here through another multiplexer, one  that selects between the high result and the low  

play07:53

result, this also gives me an excuse to break  down each result into binary, just for flare,  

play07:57

I think it's cool to look at. This output is wired  to the input for Register 1 in the Register File,  

play08:03

where the 16 General Purpose Registers are kept.  Register 2 input is always the high 16-bit output  

play08:08

from the ALU and the REG1, REG2, and the two  Write signals come straight from the Control Unit,  

play08:14

if either write signal is set to true, then the  specified register is changed based on the input.  

play08:19

Inside of the Register File I've kept  the four system flags, the carry flag,  

play08:23

zero flag, sign flag, and the overflow flag.  The carry flag is set when the ALU low 16-bit  

play08:29

result is greater than 2^16. Here's the trick  through, remember that all important ALU formula,  

play08:35

what if I told you, it wasn't the final output  formula? Sneakily I've put that long formula  

play08:40

one cell above and hid the text by setting the  color to be the same value as the background,  

play08:44

then I use modulus division to get a result  that fits within 16 bits for the final result,  

play08:50

if the result of this above cell is greater than  2^16, it'll set the carry flag to true. The other  

play08:55

flags are simpler, ZF is set if the result of that  low 16-bit value is equal to 0, SF is equivalent  

play09:01

to the top bit in the low-16 result, and OF  is set through the conditions of overflow.  

play09:07

The last unit in the CPU is the Program Counter.  When the clock signal is high, the PC checks if it  

play09:12

needs to reset to 0, take a two-byte or four-byte  step (which is equal to one or two memory units),  

play09:18

or if the PC Set Immediate Flag is set, then,  based on whether the jump conditions are met,  

play09:23

it will be set the PC to the 16-bit  Immediate value as specified in the  

play09:27

instruction. These are typically used after the  CMP instruction, and help with creating loops  

play09:31

and other branches in programs, this will make  more sense when I get to writing some code.  

play09:36

And that's the whole CPU, not too bad and  it comes in a reasonable package. But that's  

play09:40

about to change when I start building  the RAM unit. With a 16-bit address bus,  

play09:44

there are 65,536 addressable 16-bit memory  units, that’s 128KB of RAM in total. I've fit  

play09:53

them into a 256x256 table, and installed  a Memory Management Unit on top. The key  

play09:59

signals here are Memory Write from the Control  Unit, the Address from the first multiplexer,  

play10:03

and the value that comes from the ALU. This  address is converted into an X and Y coordinate,  

play10:09

based off the Excel Space, if the Memory Write  signal is set to high, then the cell at this  

play10:13

coordinate is updated to hold this new value.  Of course, one cell can't dictate that another  

play10:18

cell be written to. Each cell has to have its own  defined formula, but again I'm not crazy, I didn't  

play10:23

write 65,000 different equations, I wrote one  equation that would work for every single cell,  

play10:29

highlighted everything then after writing the  function in the formula bar hit Ctrl-Enter and  

play10:33

it was automatically applied to every cell. To read from the RAM table based off of a single  

play10:38

16-bit address, I've used two Excel functions,  Address, to specify the row and column of the  

play10:44

desired cell in digits, and Indirect, which  grabs the value of the specified address.  

play10:49

Going back to the Fetch Unit, I can finally finish  it to grab two units of memory from the address in  

play10:54

the PC register. And now I've also added two  buttons on top next to the clock. One of them  

play10:59

is Reset, which resets the PC and RAM all back  to 0, and the other is Manual. In manual Mode,  

play11:05

the instruction is specified by the user in  the override slot in the Fetch Unit. I found  

play11:09

this came in handy when designing and testing  things for the CPU, so I've included it as a  

play11:14

feature now. The first multiplexer also reads  from two different spots in memory, from the  

play11:19

address in the second specified register, and the  address in the 16-bit immediate value. Though,  

play11:24

I did make one mistake here, I realized that I  didn't have an instruction that used this 3rd  

play11:28

option, so I had to add a 26th instruction.  It’s another LOAD instruction, but this could  

play11:33

be useful for indirect addressing in programs. Now the only thing missing is the 4K screen. And  

play11:39

by that I of course mean it uses 4KB of memory.  Looking at the memory map here, it will use the  

play11:44

last 4KB of the 128KB of RAM, with the rest being  free for you to do whatever you want with it,  

play11:50

it’s your RAM. The screen is 128x128 cells with  each cell representing one pixel, but I've resized  

play11:57

these cells to be square rather than rectangle.  The screen will have a 16-color display,  

play12:02

that's 4-bits per pixel, or one word in memory  controlling four pixels. That added another layer  

play12:08

of complexity to the Excel formula, as I'm reading  data from a 256x16 table onto a 128x128 table,  

play12:16

and again I'm only writing the one formula to be  applied to the whole table here, because I find  

play12:22

it much more fun to spend three hours writing and  testing one complex function that does everything,  

play12:27

than spend one hour mindlessly applying simpler  functions to each cell. After I have that worked  

play12:32

out, to add color all I have to do is something  I've been doing this whole time already, apply  

play12:36

conditional formatting. I've added 16 different  rules for the 16 different colors, and with the  

play12:41

text color being the same as the background,  the cells look and act like regular pixels.  

play12:46

So, this is it now, it’s not a system on a chip,  it’s a system on a spreadsheet. And it all comes  

play12:51

down to this. Here's a real simple program  that I wrote that should change the first  

play12:55

four pixels of the screen to red, blue, green,  and yellow. First, set register 0 to $F000,  

play13:03

alright. Then set register 1 to $48C7, okay. Now  this should be it right here, store register 1 to  

play13:12

the address in register 0. Three, two, one…

play13:28

This is so cool. This is a working CPU in a  

play13:31

regular Excel spreadsheet. But I’m not done  yet because right now I’m only running this  

play13:35

in manual mode. But I want to run much larger  programs from memory now. And for that I'll need  

play13:41

a compiler. Remember when I said my sanity stood  in the way? I’ve designed a new Assembly Language  

play13:46

based on my ISA and I'm calling it EXCEL-ASM16, it  features not only 23 different instructions, but  

play13:53

also the ability to define variables in the data  segment, for numbers to be defined using decimal,  

play13:57

hexadecimal, or for certain instructions,  with @ to signify the memory location,  

play14:02

it has support for labels, comments, and  an additional ORG instruction which sets  

play14:06

the address for the next instruction, and the  ability to include binary files directly into  

play14:11

the program. Now this is all pretty basic for an  Assembly language, and certainly there are more  

play14:16

bells and whistles I could have added, but it's  good enough for a made up Excel CPU language.  

play14:21

I wrote the entire compiler in EXCEL-ASM16 and  it runs inside this Excel CPU. No, it doesn’t  

play14:28

actually, I’m not insane. I wrote it in Python  so that it'd be cross platform compatible. But,  

play14:33

how do I get compiled programs into memory?  Because if I just try to write directly to  

play14:37

the cell, that overwrites the cell's formula.  So instead let me tweak a few things. I'm going  

play14:43

to come up top and add a few more buttons, a  separate button for reset memory, and a read  

play14:48

ROM button. I can't actually keep the ROM in this  file though, because Excel doesn't like formulas  

play14:53

with iterative calculations to be saved by an  outside program. So, my many attempts to keep  

play14:58

the ROM below the RAM only resulted in many,  many broken spreadsheets. Kids, remember never  

play15:03

to run experimental tests in your main file. When you run the compiler, first specify your  

play15:08

program file, then you can specify that you  want the compiled result saved in an Excel  

play15:12

spreadsheet called ROM, which will look like  this after it compiles. Then go back to the  

play15:17

Excel CPU file and flip the Read ROM switch.  I've already adjusted the memory function to  

play15:22

read from the ROM file when this is turned  on, then flip it off before you start your  

play15:26

program. Reset the PC to 0, and let her rip.

play15:35

This is amazing, and I'm able to make all kinds of  

play15:38

super cool programs with this, and the best part  is that this is still just a regular spreadsheet,  

play15:43

but the worst part is that it’s also super slow.  I'm updating the clock cycle by hand by pressing  

play15:49

the F9 key, and it takes such a long time to run  each program. The CPU working its hardest isn't  

play15:54

running any faster than 2 or 3 Hz, the footage of  all these programs I’ve been showing you has been  

play16:00

very much sped up. But still, I think this could  be a useful tool to show the inner workings of  

play16:04

a processor one clock cycle at a time, and maybe  it'll run faster on your machine. Everything, the  

play16:09

CPU, the compiler, the ROM, my sample programs,  and all the documentation I wrote is available  

play16:14

to download, so hit that subscribe button if you  want to see more projects like this. And thanks  

play16:19

once again to Brilliant for sponsoring this video,  check them out down below, and until next time…