Lesson 2. 16×4 memory: sixteen rows and picking one

In pictures

After this lesson you will have real memory: RAM16x4 — 16 words of 4 bits. Set the address and the data on the switches, press WE — the word is written; change the address — the display shows what is stored in that cell. Inside are 16 WORD4 rows from lesson 1 and the DEC16 decoder from the processor kit.


2.1. The idea: pick one row out of sixteen

A 4-bit address is a number from 0 to 15, the row number. The DEC16 decoder turns it into "one lit wire out of sixteen" — the same decoder that picked the instruction in the processor kit. From there the wires r0–r15 do all the work:

  • "give": wire rN goes straight to R of its row — the selected row opens its "tap", the others give zeros;
  • "write": AND(rN, WE) → W of the row — only the selected row can write, and only while WE is pressed;
  • output: for each bit the 16 row outputs meet in a 16-input OR (4 × OR4 → OR4). The zeros of the rows that aren't selected change nothing — the output is the word of the selected row.
A0–A3address = 2DEC161 of 16WEr0RWWORD4c0 = 0r1RWWORD4c1 = 0r2RWWORD4c2 = 5r15RWWORD4c15 = 0⋮⋮OR16 → 1Q = 5D0–D3 go to every row at once (not drawn)
The 16×4 memory. The decoder lights exactly one row (r2): it gets "give" R, and with WE = 1 also "write" W (through the AND). The other 15 rows output zeros, and the OR on each bit leaves the selected row's word at the output.

The data D0–D3 goes to all 16 rows at once: only the row with W = 1 writes it anyway.

Just like real static memory: while WE is pressed, writing is going on; change the address only with WE released, otherwise the word will also be written wherever the address has moved to.

2.2. Why reading uses gates and not a shared wire

In real memory chips the row outputs are not collected through OR: all the cells of one bit sit on a shared wire (a "bit line") through switch transistors, and the selected row connects its cell to that wire. That takes fewer parts. It won't work for us:

a shared data wire — as in real chipsQ0row 1 leavingpulls to VCCswitch onrow 2 arrivingpulls to GNDswitch onfor an instant both switches are on: VCC ↔ GND
Why not a shared wire. When the address changes, the new row connects an instant before the old one disconnects: one pulls the wire to power, the other to ground — a short circuit. Real chips are saved by analog circuitry (precharging the wire, sense amplifiers); our switches are ideal — so we build reading from AND-OR gates.

AND-OR costs more parts, but in it every wire is always driven by exactly one gate — there is nothing to short.

2.3. Building

The same project as in lesson 1: lesson 1's test bench doesn't get in the way (it has its own labels wD, wO). You need WORD4 (lesson 1), DEC16 and OR4 (the processor kit).

Step 1. The RAM16x4 chip

What we build. A decoder, 16 "write" gates (AND), 16 rows and an OR tree.

INPUT PORTS: A0, A1, A2, A3, D0, D1, D2, D3, WE · OUTPUT PORTS: Q0, Q1, Q2, Q3

ElementPinDirectionLabel
DEC16I0inA0
DEC16I1inA1
DEC16I2inA2
DEC16I3inA3
DEC16Y0outr0
DEC16Y1outr1
DEC16Y2outr2
DEC16Y3outr3
DEC16Y4outr4
DEC16Y5outr5
DEC16Y6outr6
DEC16Y7outr7
DEC16Y8outr8
DEC16Y9outr9
DEC16Y10outr10
DEC16Y11outr11
DEC16Y12outr12
DEC16Y13outr13
DEC16Y14outr14
DEC16Y15outr15
ANDI0inr0
ANDI1inWE
ANDO0outw0
ANDI0inr1
ANDI1inWE
ANDO0outw1
ANDI0inr2
ANDI1inWE
ANDO0outw2
ANDI0inr3
ANDI1inWE
ANDO0outw3
ANDI0inr4
ANDI1inWE
ANDO0outw4
ANDI0inr5
ANDI1inWE
ANDO0outw5
ANDI0inr6
ANDI1inWE
ANDO0outw6
ANDI0inr7
ANDI1inWE
ANDO0outw7
ANDI0inr8
ANDI1inWE
ANDO0outw8
ANDI0inr9
ANDI1inWE
ANDO0outw9
ANDI0inr10
ANDI1inWE
ANDO0outw10
ANDI0inr11
ANDI1inWE
ANDO0outw11
ANDI0inr12
ANDI1inWE
ANDO0outw12
ANDI0inr13
ANDI1inWE
ANDO0outw13
ANDI0inr14
ANDI1inWE
ANDO0outw14
ANDI0inr15
ANDI1inWE
ANDO0outw15
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw0
WORD4Rinr0
WORD4O0outc0_0
WORD4O1inc0_1
WORD4O2inc0_2
WORD4O3inc0_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw1
WORD4Rinr1
WORD4O0outc1_0
WORD4O1inc1_1
WORD4O2inc1_2
WORD4O3inc1_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw2
WORD4Rinr2
WORD4O0outc2_0
WORD4O1inc2_1
WORD4O2inc2_2
WORD4O3inc2_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw3
WORD4Rinr3
WORD4O0outc3_0
WORD4O1inc3_1
WORD4O2inc3_2
WORD4O3inc3_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw4
WORD4Rinr4
WORD4O0outc4_0
WORD4O1inc4_1
WORD4O2inc4_2
WORD4O3inc4_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw5
WORD4Rinr5
WORD4O0outc5_0
WORD4O1inc5_1
WORD4O2inc5_2
WORD4O3inc5_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw6
WORD4Rinr6
WORD4O0outc6_0
WORD4O1inc6_1
WORD4O2inc6_2
WORD4O3inc6_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw7
WORD4Rinr7
WORD4O0outc7_0
WORD4O1inc7_1
WORD4O2inc7_2
WORD4O3inc7_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw8
WORD4Rinr8
WORD4O0outc8_0
WORD4O1inc8_1
WORD4O2inc8_2
WORD4O3inc8_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw9
WORD4Rinr9
WORD4O0outc9_0
WORD4O1inc9_1
WORD4O2inc9_2
WORD4O3inc9_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw10
WORD4Rinr10
WORD4O0outc10_0
WORD4O1inc10_1
WORD4O2inc10_2
WORD4O3inc10_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw11
WORD4Rinr11
WORD4O0outc11_0
WORD4O1inc11_1
WORD4O2inc11_2
WORD4O3inc11_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw12
WORD4Rinr12
WORD4O0outc12_0
WORD4O1inc12_1
WORD4O2inc12_2
WORD4O3inc12_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw13
WORD4Rinr13
WORD4O0outc13_0
WORD4O1inc13_1
WORD4O2inc13_2
WORD4O3inc13_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw14
WORD4Rinr14
WORD4O0outc14_0
WORD4O1inc14_1
WORD4O2inc14_2
WORD4O3inc14_3
WORD4D0inD0
WORD4D1inD1
WORD4D2inD2
WORD4D3inD3
WORD4Winw15
WORD4Rinr15
WORD4O0outc15_0
WORD4O1inc15_1
WORD4O2inc15_2
WORD4O3inc15_3
OR4Ainc0_0
OR4Binc1_0
OR4Cinc2_0
OR4Dinc3_0
OR4Youtg0_0
OR4Ainc4_0
OR4Binc5_0
OR4Cinc6_0
OR4Dinc7_0
OR4Youtg1_0
OR4Ainc8_0
OR4Binc9_0
OR4Cinc10_0
OR4Dinc11_0
OR4Youtg2_0
OR4Ainc12_0
OR4Binc13_0
OR4Cinc14_0
OR4Dinc15_0
OR4Youtg3_0
OR4Aing0_0
OR4Bing1_0
OR4Cing2_0
OR4Ding3_0
OR4YoutQ0
OR4Ainc0_1
OR4Binc1_1
OR4Cinc2_1
OR4Dinc3_1
OR4Youtg0_1
OR4Ainc4_1
OR4Binc5_1
OR4Cinc6_1
OR4Dinc7_1
OR4Youtg1_1
OR4Ainc8_1
OR4Binc9_1
OR4Cinc10_1
OR4Dinc11_1
OR4Youtg2_1
OR4Ainc12_1
OR4Binc13_1
OR4Cinc14_1
OR4Dinc15_1
OR4Youtg3_1
OR4Aing0_1
OR4Bing1_1
OR4Cing2_1
OR4Ding3_1
OR4YoutQ1
OR4Ainc0_2
OR4Binc1_2
OR4Cinc2_2
OR4Dinc3_2
OR4Youtg0_2
OR4Ainc4_2
OR4Binc5_2
OR4Cinc6_2
OR4Dinc7_2
OR4Youtg1_2
OR4Ainc8_2
OR4Binc9_2
OR4Cinc10_2
OR4Dinc11_2
OR4Youtg2_2
OR4Ainc12_2
OR4Binc13_2
OR4Cinc14_2
OR4Dinc15_2
OR4Youtg3_2
OR4Aing0_2
OR4Bing1_2
OR4Cing2_2
OR4Ding3_2
OR4YoutQ2
OR4Ainc0_3
OR4Binc1_3
OR4Cinc2_3
OR4Dinc3_3
OR4Youtg0_3
OR4Ainc4_3
OR4Binc5_3
OR4Cinc6_3
OR4Dinc7_3
OR4Youtg1_3
OR4Ainc8_3
OR4Binc9_3
OR4Cinc10_3
OR4Dinc11_3
OR4Youtg2_3
OR4Ainc12_3
OR4Binc13_3
OR4Cinc14_3
OR4Dinc15_3
OR4Youtg3_3
OR4Aing0_3
OR4Bing1_3
OR4Cing2_3
OR4Ding3_3
OR4YoutQ3

Select all → Ctrl+G → in the Library double-click the chip name → RAM16x4.

Step 2. The test bench

What we build. Four address switches, four data switches, a WE button and three displays: the address, what we write, what is stored in memory.

ElementPinDirectionLabel
poweroutoutVCC
groundoutoutGND
inputOutoutmA0
inputOutoutmA1
inputOutoutmA2
inputOutoutmA3
inputOutoutmD0
inputOutoutmD1
inputOutoutmD2
inputOutoutmD3
buttonoutoutmWE
RAM16x4A0inmA0
RAM16x4A1inmA1
RAM16x4A2inmA2
RAM16x4A3inmA3
RAM16x4D0inmD0
RAM16x4D1inmD1
RAM16x4D2inmD2
RAM16x4D3inmD3
RAM16x4WEinmWE
RAM16x4Q0outmQ0
RAM16x4Q1outmQ1
RAM16x4Q2outmQ2
RAM16x4Q3outmQ3

Three displays: each one ⚙ — width 4, view HEX; source — bus mA (address), mD (what we write), mQ (what is in memory). Don't group the test bench into a chip.

2.4. Check

The address and the data are binary numbers on the switches, low bit on the right (mA0, mD0).

#What you doAddress mADataDisplay: address / data / memory
1address 0000000000000 / 0 / empty — nothing written yet
2set 1000000010 / 1 / empty — only set it
3press and release WE000000010 / 1 / 1 — written
4address 0001000100011 / 1 / empty
5set 2, press and release WE000100101 / 2 / 2 — written
6address 0000000000100 / 2 / 1 ← what is in cell 0
7address 0001000100101 / 2 / 2 ← what is in cell 1

The key one is step 6: the data switches are set to 2, but memory at address 0 shows 1. The memory display shows not the switches but what the cell remembered. You don't need to press anything to read: change the address and you see the contents right away.

Cells that were never written are empty or orange (in Fast — F); that's how it should be. While WE is pressed, the memory display follows the data switches — the latches of the selected row are open.

If not:

You seeWhere to look
writing goes into all cells at onceW of the rows: each has its own wN = AND(rN, WE), not a shared WE
the wrong cell is readDEC16: I0–I3 = A0–A3 in order; rN → R of row N
one bit is always 0the OR tree of that bit: 4 × OR4 → OR4 → QN

Lesson 2 paste (Cmd+I)

On top of lesson 1.

chip RAM16x4 {  portIn(A0)  portIn(A1)  portIn(A2)  portIn(A3)  portIn(D0)  portIn(D1)  portIn(D2)  portIn(D3)  portIn(WE)  portOut(Q0)  portOut(Q1)  portOut(Q2)  portOut(Q3)  DEC16(I0=A0, I1=A1, I2=A2, I3=A3, Y0=r0, Y1=r1, Y2=r2, Y3=r3, Y4=r4, Y5=r5, Y6=r6, Y7=r7, Y8=r8, Y9=r9, Y10=r10, Y11=r11, Y12=r12, Y13=r13, Y14=r14, Y15=r15)  AND(r0, WE, w0)  AND(r1, WE, w1)  AND(r2, WE, w2)  AND(r3, WE, w3)  AND(r4, WE, w4)  AND(r5, WE, w5)  AND(r6, WE, w6)  AND(r7, WE, w7)  AND(r8, WE, w8)  AND(r9, WE, w9)  AND(r10, WE, w10)  AND(r11, WE, w11)  AND(r12, WE, w12)  AND(r13, WE, w13)  AND(r14, WE, w14)  AND(r15, WE, w15)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w0, R=r0, O0=c0_0, O1=c0_1, O2=c0_2, O3=c0_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w1, R=r1, O0=c1_0, O1=c1_1, O2=c1_2, O3=c1_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w2, R=r2, O0=c2_0, O1=c2_1, O2=c2_2, O3=c2_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w3, R=r3, O0=c3_0, O1=c3_1, O2=c3_2, O3=c3_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w4, R=r4, O0=c4_0, O1=c4_1, O2=c4_2, O3=c4_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w5, R=r5, O0=c5_0, O1=c5_1, O2=c5_2, O3=c5_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w6, R=r6, O0=c6_0, O1=c6_1, O2=c6_2, O3=c6_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w7, R=r7, O0=c7_0, O1=c7_1, O2=c7_2, O3=c7_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w8, R=r8, O0=c8_0, O1=c8_1, O2=c8_2, O3=c8_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w9, R=r9, O0=c9_0, O1=c9_1, O2=c9_2, O3=c9_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w10, R=r10, O0=c10_0, O1=c10_1, O2=c10_2, O3=c10_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w11, R=r11, O0=c11_0, O1=c11_1, O2=c11_2, O3=c11_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w12, R=r12, O0=c12_0, O1=c12_1, O2=c12_2, O3=c12_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w13, R=r13, O0=c13_0, O1=c13_1, O2=c13_2, O3=c13_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w14, R=r14, O0=c14_0, O1=c14_1, O2=c14_2, O3=c14_3)  WORD4(D0=D0, D1=D1, D2=D2, D3=D3, W=w15, R=r15, O0=c15_0, O1=c15_1, O2=c15_2, O3=c15_3)  OR4(A=c0_0, B=c1_0, C=c2_0, D=c3_0, Y=g0_0)  OR4(A=c4_0, B=c5_0, C=c6_0, D=c7_0, Y=g1_0)  OR4(A=c8_0, B=c9_0, C=c10_0, D=c11_0, Y=g2_0)  OR4(A=c12_0, B=c13_0, C=c14_0, D=c15_0, Y=g3_0)  OR4(A=g0_0, B=g1_0, C=g2_0, D=g3_0, Y=Q0)  OR4(A=c0_1, B=c1_1, C=c2_1, D=c3_1, Y=g0_1)  OR4(A=c4_1, B=c5_1, C=c6_1, D=c7_1, Y=g1_1)  OR4(A=c8_1, B=c9_1, C=c10_1, D=c11_1, Y=g2_1)  OR4(A=c12_1, B=c13_1, C=c14_1, D=c15_1, Y=g3_1)  OR4(A=g0_1, B=g1_1, C=g2_1, D=g3_1, Y=Q1)  OR4(A=c0_2, B=c1_2, C=c2_2, D=c3_2, Y=g0_2)  OR4(A=c4_2, B=c5_2, C=c6_2, D=c7_2, Y=g1_2)  OR4(A=c8_2, B=c9_2, C=c10_2, D=c11_2, Y=g2_2)  OR4(A=c12_2, B=c13_2, C=c14_2, D=c15_2, Y=g3_2)  OR4(A=g0_2, B=g1_2, C=g2_2, D=g3_2, Y=Q2)  OR4(A=c0_3, B=c1_3, C=c2_3, D=c3_3, Y=g0_3)  OR4(A=c4_3, B=c5_3, C=c6_3, D=c7_3, Y=g1_3)  OR4(A=c8_3, B=c9_3, C=c10_3, D=c11_3, Y=g2_3)  OR4(A=c12_3, B=c13_3, C=c14_3, D=c15_3, Y=g3_3)  OR4(A=g0_3, B=g1_3, C=g2_3, D=g3_3, Y=Q3)} power(VCC)ground(GND)input(Out=mA0)input(Out=mA1)input(Out=mA2)input(Out=mA3)input(Out=mD0)input(Out=mD1)input(Out=mD2)input(Out=mD3)button{label="WE", hostKey="KeyW"}(mWE)RAM16x4(A0=mA0, A1=mA1, A2=mA2, A3=mA3, D0=mD0, D1=mD1, D2=mD2, D3=mD3, WE=mWE, Q0=mQ0, Q1=mQ1, Q2=mQ2, Q3=mQ3)display{bits=4, base="HEX", busSource="mA"}()display{bits=4, base="HEX", busSource="mD"}()display{bits=4, base="HEX", busSource="mQ"}()

Stuck? Something doesn't work →