diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 15f8df3..e2a4253 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -7,3 +7,4 @@
- [L1 - Electronics Refresher](./lecture_electrical_basics.md)
- [L2 - The NOP Computer](./lecture_nop_computer.md)
+- [L3 - Program Storage](./lecture_program_storage.md)
diff --git a/src/images/eprom_diagram.png b/src/images/eprom_diagram.png
new file mode 100644
index 0000000..b277ed0
Binary files /dev/null and b/src/images/eprom_diagram.png differ
diff --git a/src/images/eprom_picture.png b/src/images/eprom_picture.png
new file mode 100644
index 0000000..0ce970f
Binary files /dev/null and b/src/images/eprom_picture.png differ
diff --git a/src/images/mask_rom.png b/src/images/mask_rom.png
new file mode 100644
index 0000000..47a79ca
Binary files /dev/null and b/src/images/mask_rom.png differ
diff --git a/src/images/sst39sf010a.png b/src/images/sst39sf010a.png
new file mode 100644
index 0000000..c68df57
Binary files /dev/null and b/src/images/sst39sf010a.png differ
diff --git a/src/lecture_electrical_basics.md b/src/lecture_electrical_basics.md
index 66c84c5..c8c6b14 100644
--- a/src/lecture_electrical_basics.md
+++ b/src/lecture_electrical_basics.md
@@ -1,4 +1,4 @@
-# Electronics Refresher
+# L1 - Electronics Refresher
## Lecture
diff --git a/src/lecture_nop_computer.md b/src/lecture_nop_computer.md
index d8df424..1598dd3 100644
--- a/src/lecture_nop_computer.md
+++ b/src/lecture_nop_computer.md
@@ -1,4 +1,4 @@
-# The NOP Computer
+# L2 - The NOP Computer
### Notation
diff --git a/src/lecture_program_storage.md b/src/lecture_program_storage.md
new file mode 100644
index 0000000..5029827
--- /dev/null
+++ b/src/lecture_program_storage.md
@@ -0,0 +1,276 @@
+# L3 - Program Storage
+
+## Lecture
+
+### NOP Computer Recap
+
+TODO:
+
+### Today's Goal
+
+Currently, our computer has only a single byte of program storage:
+the eight wires we connected directly to the data bus are the only byte that will ever run.
+
+Most interesting programs consist of more than a single byte though,
+and in order to store those bytes we need another IC.
+
+### Storage Technologies
+
+There are a few key characteristics of programs
+that dictate the way in which we store them:
+- Most programs are not changed often (or changed at all).
+- We typically want programs to persist even when power is turned off.
+
+If we look back through history, these requirements were met in a number of ways (to name a few):
+- Solid State Drives
+- Hard Drives
+- Installation CDs
+- Floppy Disks
+- Magnetic Tapes
+- Punch Cards
+
+Unfortunately, these methods all suffer from a significant drawback: they're complicated.
+Our CPU expects to be able to just put an address in and get data out,
+which simply isn't an efficient (or reasonable) way to use any of the above media.
+
+This complexity problem is why computers new and old always have some form of much simpler storage
+that *does* simply work like `address in -> data out`,
+and we usually call this a **ROM**, for **R**ead **O**nly **M**emory.
+For extremely simple systems, like microcontrollers, this ROM might be the only storage available.
+For desktop computers, this ROM is located directly on the motherboard and will hold just enough code
+to be able to set up and access e.g. a hard drive,
+which will contain the rest of the operating system and your files.
+
+#### Mask ROM
+
+Read Only Memory has taken various forms throughout history.
+The simplest approach is actually very similar to what we already did to our computer's data bus,
+where we hard-wired specific bits to represent our data in an unmodifiable way.
+A ROM in which the data is stored in the physical shape of the metal and silicon
+is known as a **"mask ROM"**, because the data is encoded in the masks used to fabricate the device.
+A picture of the insides of a mask ROM is shown below;
+the pattern of metal connections is what stores the data.
+
+![Mask ROM die shot](images/mask_rom.png)
+
+#### PROM
+
+The downside of a mask ROM is that making an updated version of the ROM is *extremely* difficult:
+changing the layout of an IC can cost millions of dollars and require several months of time.
+This is obviously not ideal if a company ships a product containing a mask ROM
+that is later found to have a bug.
+
+Often a more convenient form of ROM is **OTP**, or **O**ne **T**ime **P**rogrammable ROM,
+typically just **PROM** for short.
+
+The inside of a PROM looks much like a mask ROM, but with one key difference:
+every possible bit starts connected.
+To program the PROM, a high current is passed through the bits we would like to clear.
+The heat of this current actually melts the very thin wire, disconnecting it permanently.
+By selectively melting specific wires, we can permanently store a pattern of bits in our PROM
+without needing to change the design at the factory.
+
+#### EPROM
+
+While a PROM allows us to permanently store data once,
+this does mean that if we ever want to "update" the data,
+our only option is to buy a second PROM and use it to replace the first one.
+While much cheaper than remanufacturing the ROM,
+this still isn't ideal if we'd like to make changes either for testing or for updates.
+
+Thus, we need what is called an **E**rasable Programmable Read Only Memory, or EPROM.
+An EPROM works by forcing electrons into an area they cannot escape from,
+shown as the "float gate" area in the diagram below.
+The charge (or lack thereof) on the floating gate then either allows or prevents a transistor from turning on–
+effectively allowing us to "connect" or "disconnect" wires just like in the ROM and PROM.
+
+![Diagram of EPROM cell](images/eprom_diagram.png)
+
+In order to erase the EPROM so that we can reprogram it,
+we need to get the electrons back out of the floating gate.
+To do this, we actually leverage the power of the sun:
+High-energy UV rays from sunlight strike the electrons and knock them out of the floating gate,
+eventually discharging the gate and allowing us to store new data.
+You can recognize an EPROM by looking for a window that allows the sunlight in, as shown below.
+
+![Picture of EPROM](images/eprom_picture.png)
+
+#### EEPROM
+
+While the EPROM is very close to ideal,
+unfortunately there are many engineers and developers that are allergic to sunlight and grass.
+Also, the UV erasing process can take a few hours.
+
+To finally arrive at our ideal stage medium, we have the
+**E**lectrically Erasable Programmable Read Only Memory, or **EEPROM**.
+
+The internal structure is very similar to an EPROM, but with one key difference:
+Instead of needing sunlight to pull the electrons out of the floating gate,
+we use quantum mechanics.
+As I do not understand quantum mechanics, unfortunately I cannot elaborate further.
+The upside is that both programming and erasing can both be done quickly and electronically,
+making EEPROMs a very useful storage medium indeed.
+
+#### Flash Memory
+
+In fact, EEPROMs are so useful, that the same technology that is inside EEPROMs
+is what is used for **flash storage**.
+Yes, the very same "flash" as in "flash drive" and in solid state drives:
+the disk that is likely in your computer can trace its roots all the way back to improvements on the mask ROM.
+
+The differences between EEPROM and flash memory
+are really just in terms of layout, density, and the exact encoding scheme used for the bits.
+The primary thing one might notice when comparing EEPROM and flash
+is that flash storage is larger and faster for the same price,
+but it must be erased in large (often 4096 byte) blocks at a time,
+unlike an EEPROM in which each individual byte can be erased and reprogrammed.
+
+For our purposes, these differences are mostly superficial,
+and flash memory is both much cheaper and has more storage.
+Thus, we will be using the **SST39SF010A** 128KiB flash IC to store our programs.
+
+### The SST39SF010A
+
+The flash memory our computer will use is the SST39SF010A, whose
+[datasheet is available on Microchip's website](https://ww1.microchip.com/downloads/aemDocuments/documents/MPD/ProductDocuments/DataSheets/SST39SF010A-SST39SF020A-SST39SF040-Data-Sheet-DS20005022.pdf).
+The pinout diagram is shown below for convenience, with some annotations.
+
+![Pinout of the SST39SF010A](images/sst39sf010a.png)
+
+Most of the pins should be familiar:
+
+- VDD should be connected to 5V
+- VSS should be connected to 0V/GND
+- A0 through A16 are the address bus
+- DQ0 through DQ7 are the data bus
+
+Reading data from the flash is very simple:
+If you (the CPU) drive an address, the flash will return a stored byte driven on the data lines,
+exactly as we want.
+Note that we will need to do a little bit with those WE#, OE#, and CE# pins,
+which we'll discuss shortly.
+
+The NC pins on the flash stand for **No Connect**,
+i.e. you shouldn't connect anything to those pins.
+Usually NC just means the pins are unused,
+but sometimes a no-connect pin activates some factory test functionality,
+which we definitely don't want to use by accident.
+
+Note that, because this is a 128KiB flash (i.e. there are 2^17 bytes) there are 17 address lines.
+Our CPU only has 16 address lines,
+which means that the last address line on the flash can't be (easily) used,
+and so we can't use the whole storage of the device.
+However, storage space will almost certainly not be a problem:
+the entirety of Super Mario Bros on the NES could fit in just 32KiB!
+Unless you're writing some *very* large programs you don't need to worry about space.
+
+### Active Low Pins
+
+In an earlier section we decided to read voltages as "HIGH" or "LOW"
+rather than on/off or 1/0. It's now time to talk about why that's helpful.
+
+*Usually*, holding a pin on a device HIGH causes that pin to activate,
+where what "activate" means depends on the device–
+typically something gets turned on, a counter counts up, outputs are driven, etc.
+As such, we call most pins **active high**, because a HIGH signal means the pin is active.
+
+However, active high pins are merely a *convention*.
+It would also be perfectly reasonable to design ICs in such a way
+that applying a LOW signal to a pin causes something to be active.
+Such a pin would be called **active low**, because a LOW signal means the pin is active.
+
+As it turns out, due to historical and physics reasons,
+active low pins are fairly common.
+Both the CPU and the flash IC have active low pins, though we haven't discussed them yet.
+
+Different manufacturers use different notation for active low pins, but the common ones are:
+
+- An **overbar** (e.g. FOO)
+- A **B** suffix (e.g. FOOB)
+- A **#** suffix (e.g. FOO#)
+
+The overbar notation is borrowed from boolean algebra,
+where it denotes inverting a signal.
+The alternative notations exist for a very simple reason: trying to type an overbar is difficult!
+The "B" suffix actually stands for "**B**ar" while being very easy to type.
+The "#" suffix is more mysterious, but it illustrates a general rule:
+if you ever see a weird symbol next to a symbol name, it probably means active low!
+
+If we take a look at the pins on the flash IC we didn't discuss,
+we can see that they all end with a #, which means that they're all active low.
+Similarly, if you look at the pinout of the 6502, you'll find several pins that all end with a B,
+and those too are active low.
+
+To accompany our HIGH/LOW terminology,
+let's adopt another pair of words to better communicate when a pin is active or inactive.
+If a pin is active, we say it is **asserted**, and if a pin is not active, we say it is **deasserted**.
+
+### Flash Control Pins
+
+Now that we know about the meaning of active HIGH and LOW pins,
+we can talk about what exactly the CE#, WE#, and OE# pins do on the flash.
+
+CE# stands for **Chip Enable**,
+which is the overall enable/disable for the flash chip.
+If the chip enable signal is deasserted (HIGH),
+the flash will do absolutely nothing: it cannot be erased or programmed and it will not drive any data outputs.
+If the chip enable signal is asserted (LOW),
+the flash will behave normally according to the other two pins (WE# and OE#).
+
+WE# stands for **Write Enable**,
+which is what allows us to erase and program the flash chip.
+The procedure for using the WE# signal is a little complicated to discuss right now,
+and programming procedure is handled completely by the debugger, so you don't need to worry about it.
+For now, we can know that during normal operation the WE# pin should be deasserted (HIGH)
+so that we don't accidentally erase any code.
+
+OE# stands for **Output Enable**,
+which activates or deactivates the data bus connection.
+If the output enable signal is deasserted (HIGH),
+the data outputs will not actually drive the bus and are effectively disconnected.
+Note that "disconnected" explicitly means we aren't driving anything–it is neither HIGH nor LOW.
+Right now that would leave our data bus floating, but this property will come in handy later.
+If the output enable signal is asserted (LOW),
+the data outputs will drive a byte and we can read data.
+
+So, to summarize, if we just wanted our CPU to be constantly reading from the flash,
+we would drive the flash's control pins as follows:
+
+- CE# LOW to enable the whole chip
+- WE# HIGH to prevent any erasing or programming
+- OE# LOW to enable the data lines
+
+### Connecting the Flash
+
+If you look at the debugger PCB closely, there are two pins at the end of the "T"
+labeled WE and PROG.
+These two signals aren't part of the 6502:
+they're an additional feature of the debugger be able to program the flash.
+
+The debugger's WE# pin can go directly into the EEPROM's WE# pin.
+The PROG# pin will be asserted whenever the debugger is busy doing erase and program operations,
+and it's needed to shut off the OE# pin in order to avoid trying to read and write at the same time.
+
+In other words, if PROG# is asserted (LOW), we need OE# to be deasserted (HIGH).
+This allows us to do our erasing and programming without accidentally reading at the same time.
+
+If PROG# is deasserted (HIGH), we need OE# to be asserted (LOW).
+This allows our computer to function normally and read data from the flash.
+
+This setup naturally calls for a NOT gate–which, as previously mentioned, can be done with a NAND gate instead.
+
+As for the CE# pin, there's never really a reason we need to use it (since the OE# pin already works just fine),
+so we can just leave the CE# pin always asserted (tied LOW).
+
+To summarize:
+
+- The address/data lines on the 6502 and the flash can be directly connected
+- The WE# pin should be directly connected to the debugger's WE#
+- The CE# pin should be tied LOW
+- The OE# pin should be connected with some logic (shown in schematic)
+
+## Hands-On
+
+### Schematic
+
+### Using the Debugger
\ No newline at end of file